/**************** * Update a hashtable. * table gives the start of the table, key and keylen is the key, * newrecnum is the record number to insert. */ static int upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum ) { TRUSTREC lastrec, rec; ulong hashrec, item; int msb; int level=0; int rc, i; hashrec = table; next_level: msb = key[level]; hashrec += msb / ITEMS_PER_HTBL_RECORD; rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); if( rc ) { log_error("upd_hashtable: read failed: %s\n", g10_errstr(rc) ); return rc; } item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; if( !item ) { /* insert a new item into the hash table */ rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum; rc = tdbio_write_record( &rec ); if( rc ) { log_error("upd_hashtable: write htbl failed: %s\n", g10_errstr(rc) ); return rc; } } else if( item != newrecnum ) { /* must do an update */ lastrec = rec; rc = tdbio_read_record( item, &rec, 0 ); if( rc ) { log_error( "upd_hashtable: read item failed: %s\n", g10_errstr(rc) ); return rc; } if( rec.rectype == RECTYPE_HTBL ) { hashrec = item; level++; if( level >= keylen ) { log_error( "hashtable has invalid indirections.\n"); return G10ERR_TRUSTDB; } goto next_level; } else if( rec.rectype == RECTYPE_HLST ) { /* extend list */ /* see whether the key is already in this list */ for(;;) { for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { if( rec.r.hlst.rnum[i] == newrecnum ) { return 0; /* okay, already in the list */ } } if( rec.r.hlst.next ) { rc = tdbio_read_record( rec.r.hlst.next, &rec, RECTYPE_HLST); if( rc ) { log_error( "upd_hashtable: read hlst failed: %s\n", g10_errstr(rc) ); return rc; } } else break; /* not there */ } /* find the next free entry and put it in */ for(;;) { for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { if( !rec.r.hlst.rnum[i] ) { rec.r.hlst.rnum[i] = newrecnum; rc = tdbio_write_record( &rec ); if( rc ) log_error( "upd_hashtable: write hlst failed: %s\n", g10_errstr(rc) ); return rc; /* done */ } } if( rec.r.hlst.next ) { rc = tdbio_read_record( rec.r.hlst.next, &rec, RECTYPE_HLST ); if( rc ) { log_error( "upd_hashtable: read hlst failed: %s\n", g10_errstr(rc) ); return rc; } } else { /* add a new list record */ rec.r.hlst.next = item = tdbio_new_recnum(); rc = tdbio_write_record( &rec ); if( rc ) { log_error( "upd_hashtable: write hlst failed: %s\n", g10_errstr(rc) ); return rc; } memset( &rec, 0, sizeof rec ); rec.rectype = RECTYPE_HLST; rec.recnum = item; rec.r.hlst.rnum[0] = newrecnum; rc = tdbio_write_record( &rec ); if( rc ) log_error( "upd_hashtable: write ext hlst failed: %s\n", g10_errstr(rc) ); return rc; /* done */ } } /* end loop over hlst slots */ } else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */ if( rec.recnum == newrecnum ) { return 0; } item = rec.recnum; /* save number of key record */ memset( &rec, 0, sizeof rec ); rec.rectype = RECTYPE_HLST; rec.recnum = tdbio_new_recnum(); rec.r.hlst.rnum[0] = item; /* old keyrecord */ rec.r.hlst.rnum[1] = newrecnum; /* and new one */ rc = tdbio_write_record( &rec ); if( rc ) { log_error( "upd_hashtable: write new hlst failed: %s\n", g10_errstr(rc) ); return rc; } /* update the hashtable record */ lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum; rc = tdbio_write_record( &lastrec ); if( rc ) log_error( "upd_hashtable: update htbl failed: %s\n", g10_errstr(rc) ); return rc; /* ready */ } else { log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n", table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); list_trustdb(NULL); return G10ERR_TRUSTDB; } } return 0; }
void import_ownertrust (ctrl_t ctrl, const char *fname ) { estream_t fp; int is_stdin=0; char line[256]; char *p; size_t n, fprlen; unsigned int otrust; byte fpr[MAX_FINGERPRINT_LEN]; int any = 0; int rc; init_trustdb (ctrl, 0); if( iobuf_is_pipe_filename (fname) ) { fp = es_stdin; fname = "[stdin]"; is_stdin = 1; } else if( !(fp = es_fopen( fname, "r" )) ) { log_error ( _("can't open '%s': %s\n"), fname, strerror(errno) ); return; } if (is_secured_file (es_fileno (fp))) { es_fclose (fp); gpg_err_set_errno (EPERM); log_error (_("can't open '%s': %s\n"), fname, strerror(errno) ); return; } while (es_fgets (line, DIM(line)-1, fp)) { TRUSTREC rec; if( !*line || *line == '#' ) continue; n = strlen(line); if( line[n-1] != '\n' ) { log_error (_("error in '%s': %s\n"), fname, _("line too long") ); /* ... or last line does not have a LF */ break; /* can't continue */ } for(p = line; *p && *p != ':' ; p++ ) if( !hexdigitp(p) ) break; if( *p != ':' ) { log_error (_("error in '%s': %s\n"), fname, _("colon missing") ); continue; } fprlen = p - line; if( fprlen != 32 && fprlen != 40 && fprlen != 64) { log_error (_("error in '%s': %s\n"), fname, _("invalid fingerprint") ); continue; } if( sscanf(p, ":%u:", &otrust ) != 1 ) { log_error (_("error in '%s': %s\n"), fname, _("ownertrust value missing")); continue; } if( !otrust ) continue; /* no otrust defined - no need to update or insert */ /* Convert the ascii fingerprint to binary */ for(p=line, fprlen=0; fprlen < MAX_FINGERPRINT_LEN && *p != ':'; p += 2 ) fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]); while (fprlen < MAX_FINGERPRINT_LEN) fpr[fprlen++] = 0; rc = tdbio_search_trust_byfpr (fpr, &rec); if( !rc ) { /* found: update */ if (rec.r.trust.ownertrust != otrust) { if (!opt.quiet) { if( rec.r.trust.ownertrust ) log_info("changing ownertrust from %u to %u\n", rec.r.trust.ownertrust, otrust ); else log_info("setting ownertrust to %u\n", otrust ); } rec.r.trust.ownertrust = otrust; write_record (ctrl, &rec); any = 1; } } else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { /* insert */ if (!opt.quiet) log_info("inserting ownertrust of %u\n", otrust ); memset (&rec, 0, sizeof rec); rec.recnum = tdbio_new_recnum (ctrl); rec.rectype = RECTYPE_TRUST; memcpy (rec.r.trust.fingerprint, fpr, 20); rec.r.trust.ownertrust = otrust; write_record (ctrl, &rec); any = 1; } else /* error */ log_error (_("error finding trust record in '%s': %s\n"), fname, gpg_strerror (rc)); } if (es_ferror (fp)) log_error ( _("read error in '%s': %s\n"), fname, strerror(errno) ); if (!is_stdin) es_fclose (fp); if (any) { revalidation_mark (ctrl); rc = tdbio_sync (); if (rc) log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) ); } }
/* * Migrate the trustdb as just up to gpg 1.0.6 (trustdb version 2) * to the 2.1 version as used with 1.0.6b - This is pretty trivial as needs * only to scan the tdb and insert new the new trust records. The old ones are * obsolte from now on */ static void migrate_from_v2 () { TRUSTREC rec; int i, n; struct { ulong keyrecno; byte ot; byte okay; byte fpr[20]; } *ottable; int ottable_size, ottable_used; byte oldbuf[40]; ulong recno; int rc, count; ottable_size = 5; ottable = xmalloc (ottable_size * sizeof *ottable); ottable_used = 0; /* We have some restrictions here. We can't use the version record * and we can't use any of the old hashtables because we dropped the * code. So we first collect all ownertrusts and then use a second * pass fo find the associated keys. We have to do this all without using * the regular record read functions. */ /* get all the ownertrusts */ if (lseek (db_fd, 0, SEEK_SET ) == -1 ) log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno)); for (recno=0;;recno++) { do n = read (db_fd, oldbuf, 40); while (n==-1 && errno == EINTR); if (!n) break; /* eof */ if (n != 40) log_fatal ("migrate_vfrom_v2: read error or short read\n"); if (*oldbuf != 2) continue; /* v2 dir record */ if (ottable_used == ottable_size) { ottable_size += 1000; ottable = xrealloc (ottable, ottable_size * sizeof *ottable); } ottable[ottable_used].keyrecno = buftoulong (oldbuf+6); ottable[ottable_used].ot = oldbuf[18]; ottable[ottable_used].okay = 0; memset (ottable[ottable_used].fpr,0, 20); if (ottable[ottable_used].keyrecno && ottable[ottable_used].ot) ottable_used++; } log_info ("found %d ownertrust records\n", ottable_used); /* Read again and find the fingerprints */ if (lseek (db_fd, 0, SEEK_SET ) == -1 ) log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno)); for (recno=0;;recno++) { do n = read (db_fd, oldbuf, 40); while (n==-1 && errno == EINTR); if (!n) break; /* eof */ if (n != 40) log_fatal ("migrate_from_v2: read error or short read\n"); if (*oldbuf != 3) continue; /* v2 key record */ for (i=0; i < ottable_used; i++) { if (ottable[i].keyrecno == recno) { memcpy (ottable[i].fpr, oldbuf+20, 20); ottable[i].okay = 1; break; } } } /* got everything - create the v3 trustdb */ if (ftruncate (db_fd, 0)) log_fatal ("can't truncate `%s': %s\n", db_name, strerror (errno) ); if (create_version_record ()) log_fatal ("failed to recreate version record of `%s'\n", db_name); /* access the hash table, so it is store just after the version record, * this is not needed put a dump is more pretty */ get_trusthashrec (); /* And insert the old ownertrust values */ count = 0; for (i=0; i < ottable_used; i++) { if (!ottable[i].okay) continue; memset (&rec, 0, sizeof rec); rec.recnum = tdbio_new_recnum (); rec.rectype = RECTYPE_TRUST; memcpy(rec.r.trust.fingerprint, ottable[i].fpr, 20); rec.r.trust.ownertrust = ottable[i].ot; if (tdbio_write_record (&rec)) log_fatal ("failed to write trust record of `%s'\n", db_name); count++; } revalidation_mark (); rc = tdbio_sync (); if (rc) log_fatal ("failed to sync `%s'\n", db_name); log_info ("migrated %d version 2 ownertrusts\n", count); xfree (ottable); }
/* * Update a hashtable in the trustdb. TABLE gives the start of the * table, KEY and KEYLEN are the key, NEWRECNUM is the record number * to insert into the table. * * Return: 0 on success or an error code. */ static int upd_hashtable (ulong table, byte *key, int keylen, ulong newrecnum) { TRUSTREC lastrec, rec; ulong hashrec, item; int msb; int level = 0; int rc, i; hashrec = table; next_level: msb = key[level]; hashrec += msb / ITEMS_PER_HTBL_RECORD; rc = tdbio_read_record (hashrec, &rec, RECTYPE_HTBL); if (rc) { log_error ("upd_hashtable: read failed: %s\n", gpg_strerror (rc)); return rc; } item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; if (!item) /* Insert a new item into the hash table. */ { rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum; rc = tdbio_write_record (&rec); if (rc) { log_error ("upd_hashtable: write htbl failed: %s\n", gpg_strerror (rc)); return rc; } } else if (item != newrecnum) /* Must do an update. */ { lastrec = rec; rc = tdbio_read_record (item, &rec, 0); if (rc) { log_error ("upd_hashtable: read item failed: %s\n", gpg_strerror (rc)); return rc; } if (rec.rectype == RECTYPE_HTBL) { hashrec = item; level++; if (level >= keylen) { log_error ("hashtable has invalid indirections.\n"); return GPG_ERR_TRUSTDB; } goto next_level; } else if (rec.rectype == RECTYPE_HLST) /* Extend the list. */ { /* Check whether the key is already in this list. */ for (;;) { for (i=0; i < ITEMS_PER_HLST_RECORD; i++) { if (rec.r.hlst.rnum[i] == newrecnum) { return 0; /* Okay, already in the list. */ } } if (rec.r.hlst.next) { rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); if (rc) { log_error ("upd_hashtable: read hlst failed: %s\n", gpg_strerror (rc) ); return rc; } } else break; /* key is not in the list */ } /* Find the next free entry and put it in. */ for (;;) { for (i=0; i < ITEMS_PER_HLST_RECORD; i++) { if (!rec.r.hlst.rnum[i]) { /* Empty slot found. */ rec.r.hlst.rnum[i] = newrecnum; rc = tdbio_write_record (&rec); if (rc) log_error ("upd_hashtable: write hlst failed: %s\n", gpg_strerror (rc)); return rc; /* Done. */ } } if (rec.r.hlst.next) { /* read the next reord of the list. */ rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); if (rc) { log_error ("upd_hashtable: read hlst failed: %s\n", gpg_strerror (rc)); return rc; } } else { /* Append a new record to the list. */ rec.r.hlst.next = item = tdbio_new_recnum (); rc = tdbio_write_record (&rec); if (rc) { log_error ("upd_hashtable: write hlst failed: %s\n", gpg_strerror (rc)); return rc; } memset (&rec, 0, sizeof rec); rec.rectype = RECTYPE_HLST; rec.recnum = item; rec.r.hlst.rnum[0] = newrecnum; rc = tdbio_write_record (&rec); if (rc) log_error ("upd_hashtable: write ext hlst failed: %s\n", gpg_strerror (rc)); return rc; /* Done. */ } } /* end loop over list slots */ } else if (rec.rectype == RECTYPE_TRUST) /* Insert a list record. */ { if (rec.recnum == newrecnum) { return 0; } item = rec.recnum; /* Save number of key record. */ memset (&rec, 0, sizeof rec); rec.rectype = RECTYPE_HLST; rec.recnum = tdbio_new_recnum (); rec.r.hlst.rnum[0] = item; /* Old key record */ rec.r.hlst.rnum[1] = newrecnum; /* and new key record */ rc = tdbio_write_record (&rec); if (rc) { log_error( "upd_hashtable: write new hlst failed: %s\n", gpg_strerror (rc) ); return rc; } /* Update the hashtable record. */ lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum; rc = tdbio_write_record (&lastrec); if (rc) log_error ("upd_hashtable: update htbl failed: %s\n", gpg_strerror (rc)); return rc; /* Ready. */ } else { log_error ("hashtbl %lu: %lu/%d points to an invalid record %lu\n", table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); if (opt.verbose > 1) list_trustdb (es_stderr, NULL); return GPG_ERR_TRUSTDB; } } return 0; }