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"
24 #include "decodekey.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.db_dir);
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.db_dir);
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);
220 free_packet_list(packets);
223 } else if (ret != DB_NOTFOUND) {
224 dbconn->err(dbconn, ret, "Problem retrieving key");
230 int worddb_cmp(const char *d1, const char *d2)
232 return memcmp(d1, d2, 12);
236 * fetch_key_text - Trys to find the keys that contain the supplied text.
237 * @search: The text to search for.
238 * @publickey: A pointer to a structure to return the key in.
240 * This function searches for the supplied text and returns the keys that
243 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
251 char *searchtext = NULL;
252 struct ll *wordlist = NULL;
253 struct ll *curword = NULL;
254 struct ll *keylist = NULL;
255 struct ll *newkeylist = NULL;
258 searchtext = strdup(search);
259 wordlist = makewordlist(wordlist, searchtext);
262 ret = worddb->cursor(worddb,
267 for (curword = wordlist; curword != NULL; curword = curword->next) {
268 memset(&key, 0, sizeof(key));
269 memset(&data, 0, sizeof(data));
270 key.data = curword->object;
271 key.size = strlen(curword->object);
272 data.flags = DB_DBT_MALLOC;
273 ret = cursor->c_get(cursor,
277 while (ret == 0 && strncmp(key.data, curword->object,
279 ((char *) curword->object)[key.size] == 0) {
281 for (i = 4; i < 12; i++) {
283 keyid += ((unsigned char *)
287 if (keylist == NULL ||
288 llfind(keylist, data.data,
289 worddb_cmp) != NULL) {
290 newkeylist = lladd(newkeylist, data.data);
296 ret = cursor->c_get(cursor,
301 llfree(keylist, free);
302 keylist = newkeylist;
304 if (data.data != NULL) {
309 llfree(wordlist, NULL);
312 for (newkeylist = keylist;
313 newkeylist != NULL && numkeys < config.maxkeys;
314 newkeylist = newkeylist->next) {
317 for (i = 4; i < 12; i++) {
319 keyid += ((unsigned char *)
320 newkeylist->object)[i];
323 numkeys += fetch_key(keyid,
327 llfree(keylist, free);
332 ret = cursor->c_close(cursor);
339 * store_key - Takes a key and stores it.
340 * @publickey: A pointer to the public key to store.
341 * @intrans: If we're already in a transaction.
342 * @update: If true the key exists and should be updated.
344 * Again we just use the hex representation of the keyid as the filename
345 * to store the key to. We flatten the public key to a list of OpenPGP
346 * packets and then use write_openpgp_stream() to write the stream out to
347 * the file. If update is true then we delete the old key first, otherwise
348 * we trust that it doesn't exist.
350 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
352 struct openpgp_packet_list *packets = NULL;
353 struct openpgp_packet_list *list_end = NULL;
354 struct openpgp_publickey *next = NULL;
357 struct buffer_ctx storebuf;
362 char *primary = NULL;
363 unsigned char worddb_data[12];
364 struct ll *wordlist = NULL;
365 struct ll *curword = NULL;
367 keyid = get_keyid(publickey);
370 * Delete the key if we already have it.
372 * TODO: Can we optimize this perhaps? Possibly when other data is
373 * involved as well? I suspect this is easiest and doesn't make a lot
374 * of difference though - the largest chunk of data is the keydata and
375 * it definitely needs updated.
378 delete_key(keyid, true);
382 * Convert the key to a flat set of binary data.
384 next = publickey->next;
385 publickey->next = NULL;
386 flatten_publickey(publickey, &packets, &list_end);
387 publickey->next = next;
390 storebuf.size = 8192;
391 storebuf.buffer = malloc(8192);
393 write_openpgp_stream(buffer_putchar, &storebuf, packets);
396 * Now we have the key data store it in the DB; the keyid is the key.
398 memset(&key, 0, sizeof(key));
399 memset(&data, 0, sizeof(data));
401 key.size = sizeof(keyid);
403 data.size = storebuf.offset;
404 data.data = storebuf.buffer;
406 ret = dbconn->put(dbconn,
412 dbconn->err(dbconn, ret, "Problem storing key");
415 free(storebuf.buffer);
416 storebuf.buffer = NULL;
420 free_packet_list(packets);
424 * Walk through our uids storing the words into the db with the keyid.
426 uids = keyuids(publickey, &primary);
428 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
429 wordlist = makewordlist(wordlist, uids[i]);
432 for (curword = wordlist; curword != NULL;
433 curword = curword->next) {
434 memset(&key, 0, sizeof(key));
435 memset(&data, 0, sizeof(data));
436 key.data = curword->object;
437 key.size = strlen(key.data);
438 data.data = worddb_data;
439 data.size = sizeof(worddb_data);
442 * Our data is the key creation time followed by the
445 worddb_data[ 0] = publickey->publickey->data[1];
446 worddb_data[ 1] = publickey->publickey->data[2];
447 worddb_data[ 2] = publickey->publickey->data[3];
448 worddb_data[ 3] = publickey->publickey->data[4];
449 worddb_data[ 4] = (keyid >> 56) & 0xFF;
450 worddb_data[ 5] = (keyid >> 48) & 0xFF;
451 worddb_data[ 6] = (keyid >> 40) & 0xFF;
452 worddb_data[ 7] = (keyid >> 32) & 0xFF;
453 worddb_data[ 8] = (keyid >> 24) & 0xFF;
454 worddb_data[ 9] = (keyid >> 16) & 0xFF;
455 worddb_data[10] = (keyid >> 8) & 0xFF;
456 worddb_data[11] = keyid & 0xFF;
457 ret = worddb->put(worddb,
463 worddb->err(worddb, ret,
464 "Problem storing key");
469 * Free our UID and word lists.
471 llfree(wordlist, NULL);
472 for (i = 0; uids[i] != NULL; i++) {
484 * delete_key - Given a keyid delete the key from storage.
485 * @keyid: The keyid to delete.
486 * @intrans: If we're already in a transaction.
488 * This function deletes a public key from whatever storage mechanism we
489 * are using. Returns 0 if the key existed.
491 int delete_key(uint64_t keyid, bool intrans)
493 struct openpgp_publickey *publickey = NULL;
499 char *primary = NULL;
500 unsigned char worddb_data[12];
501 struct ll *wordlist = NULL;
502 struct ll *curword = NULL;
506 fetch_key(keyid, &publickey, intrans);
509 * Walk through the uids removing the words from the worddb.
511 if (publickey != NULL) {
512 uids = keyuids(publickey, &primary);
515 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
516 wordlist = makewordlist(wordlist, uids[i]);
519 ret = worddb->cursor(worddb,
524 for (curword = wordlist; curword != NULL;
525 curword = curword->next) {
526 memset(&key, 0, sizeof(key));
527 memset(&data, 0, sizeof(data));
528 key.data = curword->object;
529 key.size = strlen(key.data);
530 data.data = worddb_data;
531 data.size = sizeof(worddb_data);
534 * Our data is the key creation time followed by the
537 worddb_data[ 0] = publickey->publickey->data[1];
538 worddb_data[ 1] = publickey->publickey->data[2];
539 worddb_data[ 2] = publickey->publickey->data[3];
540 worddb_data[ 3] = publickey->publickey->data[4];
541 worddb_data[ 4] = (keyid >> 56) & 0xFF;
542 worddb_data[ 5] = (keyid >> 48) & 0xFF;
543 worddb_data[ 6] = (keyid >> 40) & 0xFF;
544 worddb_data[ 7] = (keyid >> 32) & 0xFF;
545 worddb_data[ 8] = (keyid >> 24) & 0xFF;
546 worddb_data[ 9] = (keyid >> 16) & 0xFF;
547 worddb_data[10] = (keyid >> 8) & 0xFF;
548 worddb_data[11] = keyid & 0xFF;
550 ret = cursor->c_get(cursor,
555 ret = cursor->c_del(cursor, 0);
559 worddb->err(worddb, ret,
560 "Problem deleting word.");
563 ret = cursor->c_close(cursor);
567 * Free our UID and word lists.
569 llfree(wordlist, NULL);
570 for (i = 0; uids[i] != NULL; i++) {
576 free_publickey(publickey);
581 key.size = sizeof(keyid);
588 return (ret == DB_NOTFOUND);
592 * Include the basic keydb routines.
594 #define NEED_GETFULLKEYID 1
595 #define NEED_GETKEYSIGS 1
596 #define NEED_KEYID2UID 1