6666bool verbose = false;
6767static bool lint_rules = false;
6868static bool assume_yes = false;
69+ #define CLI_TRUST_DB_NAME_SIZE 64
6970
7071static int send_state_report_signal (unsigned int pid , report_intent_t intent ,
7172 char * reason , size_t reason_len )
@@ -180,6 +181,79 @@ static int do_delete_db(void)
180181 return CLI_EXIT_SUCCESS ;
181182}
182183
184+ /*
185+ * dump_parse_metadata - read the active trust DB name from metadata.
186+ * @data: NUL-terminated metadata value.
187+ * @name: Destination for the active DB name.
188+ *
189+ * Returns 0 on success, ENOMEM on allocation failure, or EINVAL when the
190+ * metadata does not contain the fields needed to select an active DB.
191+ */
192+ static int dump_parse_metadata (const char * data ,
193+ char name [CLI_TRUST_DB_NAME_SIZE ])
194+ {
195+ char * copy , * line , * save = NULL ;
196+ unsigned long ignored_generation ;
197+ int have_generation = 0 , have_name = 0 ;
198+
199+ copy = strdup (data );
200+ if (copy == NULL )
201+ return ENOMEM ;
202+
203+ name [0 ] = 0 ;
204+ for (line = strtok_r (copy , "\n" , & save ); line ;
205+ line = strtok_r (NULL , "\n" , & save )) {
206+ if (sscanf (line , "generation=%lu" , & ignored_generation ) == 1 ) {
207+ have_generation = 1 ;
208+ } else if (strncmp (line , "name=" , 5 ) == 0 ) {
209+ snprintf (name , CLI_TRUST_DB_NAME_SIZE , "%s" , line + 5 );
210+ have_name = name [0 ] != 0 ;
211+ }
212+ }
213+
214+ free (copy );
215+ return have_generation && have_name ? 0 : EINVAL ;
216+ }
217+
218+ /*
219+ * dump_active_db_name - find the named DB that fapolicyd-cli -D should read.
220+ * @txn: Read transaction for the trust DB LMDB environment.
221+ * @name: Destination for the active DB name.
222+ *
223+ * Older trust databases did not have generation metadata, so absent metadata
224+ * falls back to DB_NAME. Present but unreadable metadata is treated as an
225+ * error because otherwise the CLI may inspect a stale generation.
226+ */
227+ static int dump_active_db_name (MDB_txn * txn ,
228+ char name [CLI_TRUST_DB_NAME_SIZE ])
229+ {
230+ MDB_dbi metadata_dbi ;
231+ MDB_val meta_key , meta_value ;
232+ char data [4096 ];
233+ int rc ;
234+
235+ snprintf (name , CLI_TRUST_DB_NAME_SIZE , "%s" , DB_NAME );
236+
237+ rc = mdb_dbi_open (txn , TRUST_DB_METADATA_NAME , 0 , & metadata_dbi );
238+ if (rc == MDB_NOTFOUND )
239+ return 0 ;
240+ if (rc )
241+ return rc ;
242+
243+ meta_key .mv_data = (void * )TRUST_DB_METADATA_KEY ;
244+ meta_key .mv_size = sizeof (TRUST_DB_METADATA_KEY ) - 1 ;
245+ rc = mdb_get (txn , metadata_dbi , & meta_key , & meta_value );
246+ if (rc == MDB_NOTFOUND )
247+ return 0 ;
248+ if (rc )
249+ return rc ;
250+ if (meta_value .mv_size >= sizeof (data ))
251+ return EINVAL ;
252+
253+ memcpy (data , meta_value .mv_data , meta_value .mv_size );
254+ data [meta_value .mv_size ] = 0 ;
255+ return dump_parse_metadata (data , name );
256+ }
183257
184258// This function opens the trust db and iterates over the entries.
185259// It returns CLI_EXIT_SUCCESS on success and CLI_EXIT_DB_ERROR on failure
@@ -191,12 +265,10 @@ static int do_dump_db(void)
191265 MDB_env * env ;
192266 MDB_txn * txn ;
193267 MDB_dbi dbi ;
194- MDB_dbi metadata_dbi ;
195268 MDB_stat status ;
196269 MDB_cursor * cursor ;
197270 MDB_val key , val ;
198- const char * active_name = DB_NAME ;
199- char metadata_name [64 ];
271+ char active_name [CLI_TRUST_DB_NAME_SIZE ];
200272
201273 rc = mdb_env_create (& env );
202274 if (rc ) {
@@ -235,23 +307,12 @@ static int do_dump_db(void)
235307 * records the active name in metadata. Older databases did not have this
236308 * metadata, so fall back to DB_NAME for compatibility.
237309 */
238- rc = mdb_dbi_open (txn , TRUST_DB_METADATA_NAME , 0 , & metadata_dbi );
239- if (rc == 0 ) {
240- MDB_val meta_key , meta_value ;
241-
242- meta_key .mv_data = (void * )TRUST_DB_METADATA_KEY ;
243- meta_key .mv_size = sizeof (TRUST_DB_METADATA_KEY ) - 1 ;
244- if (mdb_get (txn , metadata_dbi , & meta_key , & meta_value ) == 0 &&
245- meta_value .mv_size < 4096 ) {
246- char data [4096 ];
247- unsigned long ignored_generation ;
248-
249- memcpy (data , meta_value .mv_data , meta_value .mv_size );
250- data [meta_value .mv_size ] = 0 ;
251- if (sscanf (data , "generation=%lu\nname=%63s" ,
252- & ignored_generation , metadata_name ) == 2 )
253- active_name = metadata_name ;
254- }
310+ rc = dump_active_db_name (txn , active_name );
311+ if (rc ) {
312+ fprintf (stderr , "trust metadata read failed, error %d %s\n" ,
313+ rc , mdb_strerror (rc ));
314+ exit_rc = CLI_EXIT_DB_ERROR ;
315+ goto txn_abort ;
255316 }
256317 rc = mdb_dbi_open (txn , active_name , MDB_DUPSORT , & dbi );
257318 if (rc ) {
@@ -260,19 +321,34 @@ static int do_dump_db(void)
260321 exit_rc = CLI_EXIT_DB_ERROR ;
261322 goto txn_abort ;
262323 }
324+ rc = mdb_stat (txn , dbi , & status );
325+ if (rc ) {
326+ fprintf (stderr , "mdb_stat failed, error %d %s\n" , rc ,
327+ mdb_strerror (rc ));
328+ exit_rc = CLI_EXIT_DB_ERROR ;
329+ goto dbi_close ;
330+ }
331+ if (status .ms_entries == 0 ) {
332+ printf ("Trust database is empty\n" );
333+ goto dbi_close ;
334+ }
263335 rc = mdb_cursor_open (txn , dbi , & cursor );
264336 if (rc ) {
265337 fprintf (stderr , "mdb_cursor_open failed, error %d %s\n" , rc ,
266338 mdb_strerror (rc ));
267339 exit_rc = CLI_EXIT_DB_ERROR ;
268- goto txn_abort ;
340+ goto dbi_close ;
269341 }
270342 rc = mdb_cursor_get (cursor , & key , & val , MDB_FIRST );
271343 if (rc ) {
344+ if (rc == MDB_NOTFOUND ) {
345+ printf ("Trust database is empty\n" );
346+ goto cursor_close ;
347+ }
272348 fprintf (stderr , "mdb_cursor_get failed, error %d %s\n" , rc ,
273349 mdb_strerror (rc ));
274350 exit_rc = CLI_EXIT_DB_ERROR ;
275- goto txn_abort ;
351+ goto cursor_close ;
276352 }
277353 do {
278354 char * path = NULL , * data = NULL , sha [FILE_DIGEST_STRING_MAX ];
@@ -311,7 +387,9 @@ static int do_dump_db(void)
311387
312388 if (rc != MDB_NOTFOUND )
313389 exit_rc = CLI_EXIT_DB_ERROR ;
390+ cursor_close :
314391 mdb_cursor_close (cursor );
392+ dbi_close :
315393 mdb_close (env , dbi );
316394txn_abort :
317395 mdb_txn_abort (txn );
0 commit comments