2  * keydb_db3.c - Routines to store and fetch keys in a DB3 database.
 
   4  * Jonathan McDowell <noodles@earth.li>
 
   6  * Copyright 2002 Project Purple
 
  21 #include "charfuncs.h"
 
  25 #include "keystructs.h"
 
  27 #include "onak-conf.h"
 
  31  *      dbconn - our connection to the key database.
 
  33 static DB *dbconn = NULL;
 
  36  *      worddb - our connection to the word database.
 
  38 static DB *worddb = NULL;
 
  41  *      makewordlist - Takes a string and splits it into a set of unique words.
 
  42  *      @wordlist: The current word list.
 
  43  *      @words: The string to split and add.
 
  45  *      We take words and split it on non alpha numeric characters. These get
 
  46  *      added to the word list if they're not already present. If the wordlist
 
  47  *      is NULL then we start a new list, otherwise it's search for already
 
  48  *      added words. Note that words is modified in the process of scanning.
 
  50  *      Returns the new word list.
 
  52 struct ll *makewordlist(struct ll *wordlist, char *word)
 
  58          * Walk through the words string, spliting on non alphanumerics and
 
  59          * then checking if the word already exists in the list. If not then
 
  63         while (end != NULL && *end != 0) {
 
  65                 while (*start != 0 && !isalnum(*start)) {
 
  69                 while (*end != 0 && isalnum(*end)) {
 
  73                 if (end - start > 1) {
 
  79                         if (llfind(wordlist, start,
 
  81                                 wordlist = lladd(wordlist,
 
  91  *      initdb - Initialize the key database.
 
  93  *      This function should be called before any of the other functions in
 
  94  *      this file are called in order to allow the DB to be initialized ready
 
 102         strcpy(buf, config.db2_dbpath);
 
 103         strcat(buf, "/keydb.db");
 
 105         ret = db_create(&dbconn, NULL, 0);
 
 107                 fprintf(stderr, "db_create: %s\n", db_strerror(ret));
 
 111         ret = dbconn->open(dbconn, buf, NULL, DB_HASH,
 
 115                 dbconn->err(dbconn, ret, "%s", buf);
 
 119         strcpy(buf, config.db2_dbpath);
 
 120         strcat(buf, "/worddb");
 
 122         ret = db_create(&worddb, NULL, 0);
 
 124                 fprintf(stderr, "db_create: %s\n", db_strerror(ret));
 
 127         ret = worddb->set_flags(worddb, DB_DUP);
 
 129         ret = worddb->open(worddb, buf, NULL, DB_BTREE,
 
 133                 worddb->err(worddb, ret, "%s", buf);
 
 141  *      cleanupdb - De-initialize the key database.
 
 143  *      This function should be called upon program exit to allow the DB to
 
 144  *      cleanup after itself.
 
 148         worddb->close(worddb, 0);
 
 150         dbconn->close(dbconn, 0);
 
 155  *      starttrans - Start a transaction.
 
 157  *      Start a transaction. Intended to be used if we're about to perform many
 
 158  *      operations on the database to help speed it all up, or if we want
 
 159  *      something to only succeed if all relevant operations are successful.
 
 161 bool starttrans(void)
 
 167  *      endtrans - End a transaction.
 
 169  *      Ends a transaction.
 
 177  *      fetch_key - Given a keyid fetch the key from storage.
 
 178  *      @keyid: The keyid to fetch.
 
 179  *      @publickey: A pointer to a structure to return the key in.
 
 180  *      @intrans: If we're already in a transaction.
 
 182  *      We use the hex representation of the keyid as the filename to fetch the
 
 183  *      key from. The key is stored in the file as a binary OpenPGP stream of
 
 184  *      packets, so we can just use read_openpgp_stream() to read the packets
 
 185  *      in and then parse_keys() to parse the packets into a publickey
 
 188 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
 
 191         struct openpgp_packet_list *packets = NULL;
 
 195         struct buffer_ctx fetchbuf;
 
 197         memset(&key, 0, sizeof(key));
 
 198         memset(&data, 0, sizeof(data));
 
 203         key.size = sizeof(keyid);
 
 207         ret = dbconn->get(dbconn,
 
 214                 fetchbuf.buffer = data.data;
 
 216                 fetchbuf.size = data.size;
 
 217                 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
 
 219                 parse_keys(packets, publickey);
 
 221         } else if (ret != DB_NOTFOUND) {
 
 222                 dbconn->err(dbconn, ret, "Problem retrieving key");
 
 229  *      fetch_key_text - Trys to find the keys that contain the supplied text.
 
 230  *      @search: The text to search for.
 
 231  *      @publickey: A pointer to a structure to return the key in.
 
 233  *      This function searches for the supplied text and returns the keys that
 
 236 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 
 247         ret = worddb->cursor(worddb,
 
 252                 memset(&key, 0, sizeof(key));
 
 253                 memset(&data, 0, sizeof(data));
 
 254                 key.data = (void *) search;
 
 255                 key.size = strlen(search);
 
 256                 ret = cursor->c_get(cursor,
 
 260                 while (ret == 0 && strcmp(key.data, search) == 0) {
 
 262                         for (i = 4; i < 12; i++) {
 
 264                                 keyid += ((unsigned char *) data.data)[i];
 
 266                         numkeys += fetch_key(keyid,
 
 269                         ret = cursor->c_get(cursor,
 
 274                 ret = cursor->c_close(cursor);
 
 282  *      store_key - Takes a key and stores it.
 
 283  *      @publickey: A pointer to the public key to store.
 
 284  *      @intrans: If we're already in a transaction.
 
 285  *      @update: If true the key exists and should be updated.
 
 287  *      Again we just use the hex representation of the keyid as the filename
 
 288  *      to store the key to. We flatten the public key to a list of OpenPGP
 
 289  *      packets and then use write_openpgp_stream() to write the stream out to
 
 290  *      the file. If update is true then we delete the old key first, otherwise
 
 291  *      we trust that it doesn't exist.
 
 293 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 
 295         struct     openpgp_packet_list *packets = NULL;
 
 296         struct     openpgp_packet_list *list_end = NULL;
 
 297         struct     openpgp_publickey *next = NULL;
 
 300         struct     buffer_ctx storebuf;
 
 305         char      *primary = NULL;
 
 306         unsigned char worddb_data[12];
 
 307         struct ll *wordlist = NULL;
 
 308         struct ll *curword  = NULL;
 
 310         keyid = get_keyid(publickey);
 
 313          * Delete the key if we already have it.
 
 315          * TODO: Can we optimize this perhaps? Possibly when other data is
 
 316          * involved as well? I suspect this is easiest and doesn't make a lot
 
 317          * of difference though - the largest chunk of data is the keydata and
 
 318          * it definitely needs updated.
 
 321                 delete_key(keyid, true);
 
 325          * Convert the key to a flat set of binary data.
 
 327         next = publickey->next;
 
 328         publickey->next = NULL;
 
 329         flatten_publickey(publickey, &packets, &list_end);
 
 330         publickey->next = next;
 
 333         storebuf.size = 8192;
 
 334         storebuf.buffer = malloc(8192);
 
 336         write_openpgp_stream(buffer_putchar, &storebuf, packets);
 
 339          * Now we have the key data store it in the DB; the keyid is the key.
 
 341         memset(&key, 0, sizeof(key));
 
 342         memset(&data, 0, sizeof(data));
 
 344         key.size = sizeof(keyid);
 
 346         data.size = storebuf.offset;
 
 347         data.data = storebuf.buffer;
 
 349         ret = dbconn->put(dbconn,
 
 355                 dbconn->err(dbconn, ret, "Problem storing key");
 
 359          * Walk through our uids storing the words into the db with the keyid.
 
 361         uids = keyuids(publickey, &primary);
 
 363                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
 
 364                         wordlist = makewordlist(wordlist, uids[i]);
 
 367                 for (curword = wordlist; curword != NULL;
 
 368                                 curword = curword->next) {
 
 369                         memset(&key, 0, sizeof(key));
 
 370                         memset(&data, 0, sizeof(data));
 
 371                         key.data = curword->object;
 
 372                         key.size = strlen(key.data);
 
 373                         data.data = worddb_data;
 
 374                         data.size = sizeof(worddb_data);
 
 377                          * Our data is the key creation time followed by the
 
 380                         worddb_data[ 0] = publickey->publickey->data[1];
 
 381                         worddb_data[ 1] = publickey->publickey->data[2];
 
 382                         worddb_data[ 2] = publickey->publickey->data[3];
 
 383                         worddb_data[ 3] = publickey->publickey->data[4];
 
 384                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
 
 385                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
 
 386                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
 
 387                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
 
 388                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
 
 389                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
 
 390                         worddb_data[10] = (keyid >>  8) & 0xFF;
 
 391                         worddb_data[11] = keyid & 0xFF; 
 
 392                         ret = worddb->put(worddb,
 
 398                                 worddb->err(worddb, ret,
 
 399                                         "Problem storing key");
 
 404                  * Free our UID and word lists.
 
 406                 llfree(wordlist, NULL);
 
 407                 for (i = 0; uids[i] != NULL; i++) {
 
 419  *      delete_key - Given a keyid delete the key from storage.
 
 420  *      @keyid: The keyid to delete.
 
 421  *      @intrans: If we're already in a transaction.
 
 423  *      This function deletes a public key from whatever storage mechanism we
 
 424  *      are using. Returns 0 if the key existed.
 
 426 int delete_key(uint64_t keyid, bool intrans)
 
 428         struct openpgp_publickey *publickey = NULL;
 
 434         char *primary = NULL;
 
 435         unsigned char worddb_data[12];
 
 436         struct ll *wordlist = NULL;
 
 437         struct ll *curword  = NULL;
 
 441         fetch_key(keyid, &publickey, intrans);
 
 444          * Walk through the uids removing the words from the worddb.
 
 446         if (publickey != NULL) {
 
 447                 uids = keyuids(publickey, &primary);
 
 450                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
 
 451                         wordlist = makewordlist(wordlist, uids[i]);
 
 454                 ret = worddb->cursor(worddb,
 
 459                 for (curword = wordlist; curword != NULL;
 
 460                                 curword = curword->next) {
 
 461                         memset(&key, 0, sizeof(key));
 
 462                         memset(&data, 0, sizeof(data));
 
 463                         key.data = curword->object;
 
 464                         key.size = strlen(key.data);
 
 465                         data.data = worddb_data;
 
 466                         data.size = sizeof(worddb_data);
 
 469                          * Our data is the key creation time followed by the
 
 472                         worddb_data[ 0] = publickey->publickey->data[1];
 
 473                         worddb_data[ 1] = publickey->publickey->data[2];
 
 474                         worddb_data[ 2] = publickey->publickey->data[3];
 
 475                         worddb_data[ 3] = publickey->publickey->data[4];
 
 476                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
 
 477                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
 
 478                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
 
 479                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
 
 480                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
 
 481                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
 
 482                         worddb_data[10] = (keyid >>  8) & 0xFF;
 
 483                         worddb_data[11] = keyid & 0xFF; 
 
 485                         ret = cursor->c_get(cursor,
 
 490                                 ret = cursor->c_del(cursor, 0);
 
 494                                 worddb->err(worddb, ret,
 
 495                                         "Problem deleting word.");
 
 498                 ret = cursor->c_close(cursor);
 
 502                  * Free our UID and word lists.
 
 504                 llfree(wordlist, NULL);
 
 505                 for (i = 0; uids[i] != NULL; i++) {
 
 511                 free_publickey(publickey);
 
 516         key.size = sizeof(keyid);
 
 523         return (ret == DB_NOTFOUND);
 
 527  * Include the basic keydb routines.
 
 529 #define NEED_GETFULLKEYID 1
 
 530 #define NEED_GETKEYSIGS 1
 
 531 #define NEED_KEYID2UID 1