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
24 #include "keystructs.h"
26 #include "onak-conf.h"
30 * dbconn - our connection to the key database.
32 static DB *dbconn = NULL;
35 * worddb - our connection to the word database.
37 static DB *worddb = NULL;
40 * db3_get_ctx - Shared with CGI buffer stuff...
49 * keydb_fetchchar - Fetches a char from a file.
51 static int keydb_fetchchar(void *ctx, size_t count, unsigned char *c)
53 struct db3_get_ctx *buf = NULL;
56 buf = (struct db3_get_ctx *) ctx;
57 for (i = 0; i < count; i++) {
58 c[i] = buf->buffer[buf->offset++];
61 return (((buf->offset) == (buf->size)) ? 1 : 0);
65 * keydb_putchar - Puts a char to a file.
67 static int keydb_putchar(void *ctx, size_t count, unsigned char *c)
69 struct db3_get_ctx *buf = NULL;
73 buf = (struct db3_get_ctx *) ctx;
75 for (newsize = buf->size; newsize < (buf->offset + count);
78 if (newsize != buf->size) {
79 buf->buffer = realloc(buf->buffer, newsize);
83 for (i = 0; i < count; i++) {
84 buf->buffer[buf->offset++] = c[i];
91 * makewordlist - Takes a string and splits it into a set of unique words.
92 * @wordlist: The current word list.
93 * @words: The string to split and add.
95 * We take words and split it on non alpha numeric characters. These get
96 * added to the word list if they're not already present. If the wordlist
97 * is NULL then we start a new list, otherwise it's search for already
98 * added words. Note that words is modified in the process of scanning.
100 * Returns the new word list.
102 struct ll *makewordlist(struct ll *wordlist, char *word)
108 * Walk through the words string, spliting on non alphanumerics and
109 * then checking if the word already exists in the list. If not then
113 while (end != NULL && *end != 0) {
115 while (*start != 0 && !isalnum(*start)) {
119 while (*end != 0 && isalnum(*end)) {
120 *end = tolower(*end);
123 if (end - start > 1) {
129 if (llfind(wordlist, start,
131 wordlist = lladd(wordlist,
141 * initdb - Initialize the key database.
143 * This function should be called before any of the other functions in
144 * this file are called in order to allow the DB to be initialized ready
152 strcpy(buf, config.db2_dbpath);
153 strcat(buf, "/keydb.db");
155 ret = db_create(&dbconn, NULL, 0);
157 fprintf(stderr, "db_create: %s\n", db_strerror(ret));
161 ret = dbconn->open(dbconn, buf, NULL, DB_HASH,
165 dbconn->err(dbconn, ret, "%s", buf);
169 strcpy(buf, config.db2_dbpath);
170 strcat(buf, "/worddb");
172 ret = db_create(&worddb, NULL, 0);
174 fprintf(stderr, "db_create: %s\n", db_strerror(ret));
177 ret = worddb->set_flags(worddb, DB_DUP);
179 ret = worddb->open(worddb, buf, NULL, DB_BTREE,
183 worddb->err(worddb, ret, "%s", buf);
191 * cleanupdb - De-initialize the key database.
193 * This function should be called upon program exit to allow the DB to
194 * cleanup after itself.
198 worddb->close(worddb, 0);
200 dbconn->close(dbconn, 0);
205 * starttrans - Start a transaction.
207 * Start a transaction. Intended to be used if we're about to perform many
208 * operations on the database to help speed it all up, or if we want
209 * something to only succeed if all relevant operations are successful.
211 bool starttrans(void)
217 * endtrans - End a transaction.
219 * Ends a transaction.
227 * fetch_key - Given a keyid fetch the key from storage.
228 * @keyid: The keyid to fetch.
229 * @publickey: A pointer to a structure to return the key in.
230 * @intrans: If we're already in a transaction.
232 * We use the hex representation of the keyid as the filename to fetch the
233 * key from. The key is stored in the file as a binary OpenPGP stream of
234 * packets, so we can just use read_openpgp_stream() to read the packets
235 * in and then parse_keys() to parse the packets into a publickey
238 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
241 struct openpgp_packet_list *packets = NULL;
245 struct db3_get_ctx fetchbuf;
247 memset(&key, 0, sizeof(key));
248 memset(&data, 0, sizeof(data));
253 key.size = sizeof(keyid);
257 ret = dbconn->get(dbconn,
264 fetchbuf.buffer = data.data;
266 fetchbuf.size = data.size;
267 read_openpgp_stream(keydb_fetchchar, &fetchbuf,
269 parse_keys(packets, publickey);
271 } else if (ret != DB_NOTFOUND) {
272 dbconn->err(dbconn, ret, "Problem retrieving key");
279 * fetch_key_text - Trys to find the keys that contain the supplied text.
280 * @search: The text to search for.
281 * @publickey: A pointer to a structure to return the key in.
283 * This function searches for the supplied text and returns the keys that
286 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
297 ret = worddb->cursor(worddb,
302 memset(&key, 0, sizeof(key));
303 memset(&data, 0, sizeof(data));
304 key.data = (void *) search;
305 key.size = strlen(search);
306 ret = cursor->c_get(cursor,
310 while (ret == 0 && strcmp(key.data, search) == 0) {
312 for (i = 4; i < 12; i++) {
314 keyid += ((unsigned char *) data.data)[i];
316 numkeys += fetch_key(keyid,
319 ret = cursor->c_get(cursor,
324 ret = cursor->c_close(cursor);
332 * store_key - Takes a key and stores it.
333 * @publickey: A pointer to the public key to store.
334 * @intrans: If we're already in a transaction.
335 * @update: If true the key exists and should be updated.
337 * Again we just use the hex representation of the keyid as the filename
338 * to store the key to. We flatten the public key to a list of OpenPGP
339 * packets and then use write_openpgp_stream() to write the stream out to
340 * the file. If update is true then we delete the old key first, otherwise
341 * we trust that it doesn't exist.
343 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
345 struct openpgp_packet_list *packets = NULL;
346 struct openpgp_packet_list *list_end = NULL;
347 struct openpgp_publickey *next = NULL;
350 struct db3_get_ctx storebuf;
355 char *primary = NULL;
356 unsigned char worddb_data[12];
357 struct ll *wordlist = NULL;
358 struct ll *curword = NULL;
360 keyid = get_keyid(publickey);
363 * Delete the key if we already have it.
365 * TODO: Can we optimize this perhaps? Possibly when other data is
366 * involved as well? I suspect this is easiest and doesn't make a lot
367 * of difference though - the largest chunk of data is the keydata and
368 * it definitely needs updated.
371 delete_key(keyid, true);
375 * Convert the key to a flat set of binary data.
377 next = publickey->next;
378 publickey->next = NULL;
379 flatten_publickey(publickey, &packets, &list_end);
380 publickey->next = next;
383 storebuf.size = 8192;
384 storebuf.buffer = malloc(8192);
386 write_openpgp_stream(keydb_putchar, &storebuf, packets);
389 * Now we have the key data store it in the DB; the keyid is the key.
391 memset(&key, 0, sizeof(key));
392 memset(&data, 0, sizeof(data));
394 key.size = sizeof(keyid);
396 data.size = storebuf.offset;
397 data.data = storebuf.buffer;
399 ret = dbconn->put(dbconn,
405 dbconn->err(dbconn, ret, "Problem storing key");
409 * Walk through our uids storing the words into the db with the keyid.
411 uids = keyuids(publickey, &primary);
413 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
414 wordlist = makewordlist(wordlist, uids[i]);
417 for (curword = wordlist; curword != NULL;
418 curword = curword->next) {
419 memset(&key, 0, sizeof(key));
420 memset(&data, 0, sizeof(data));
421 key.data = curword->object;
422 key.size = strlen(key.data);
423 data.data = worddb_data;
424 data.size = sizeof(worddb_data);
427 * Our data is the key creation time followed by the
430 worddb_data[ 0] = publickey->publickey->data[1];
431 worddb_data[ 1] = publickey->publickey->data[2];
432 worddb_data[ 2] = publickey->publickey->data[3];
433 worddb_data[ 3] = publickey->publickey->data[4];
434 worddb_data[ 4] = (keyid >> 56) & 0xFF;
435 worddb_data[ 5] = (keyid >> 48) & 0xFF;
436 worddb_data[ 6] = (keyid >> 40) & 0xFF;
437 worddb_data[ 7] = (keyid >> 32) & 0xFF;
438 worddb_data[ 8] = (keyid >> 24) & 0xFF;
439 worddb_data[ 9] = (keyid >> 16) & 0xFF;
440 worddb_data[10] = (keyid >> 8) & 0xFF;
441 worddb_data[11] = keyid & 0xFF;
442 ret = worddb->put(worddb,
448 worddb->err(worddb, ret,
449 "Problem storing key");
454 * Free our UID and word lists.
456 llfree(wordlist, NULL);
457 for (i = 0; uids[i] != NULL; i++) {
469 * delete_key - Given a keyid delete the key from storage.
470 * @keyid: The keyid to delete.
471 * @intrans: If we're already in a transaction.
473 * This function deletes a public key from whatever storage mechanism we
474 * are using. Returns 0 if the key existed.
476 int delete_key(uint64_t keyid, bool intrans)
478 struct openpgp_publickey *publickey = NULL;
484 char *primary = NULL;
485 unsigned char worddb_data[12];
486 struct ll *wordlist = NULL;
487 struct ll *curword = NULL;
491 fetch_key(keyid, &publickey, intrans);
494 * Walk through the uids removing the words from the worddb.
496 if (publickey != NULL) {
497 uids = keyuids(publickey, &primary);
500 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
501 wordlist = makewordlist(wordlist, uids[i]);
504 ret = worddb->cursor(worddb,
509 for (curword = wordlist; curword != NULL;
510 curword = curword->next) {
511 memset(&key, 0, sizeof(key));
512 memset(&data, 0, sizeof(data));
513 key.data = curword->object;
514 key.size = strlen(key.data);
515 data.data = worddb_data;
516 data.size = sizeof(worddb_data);
519 * Our data is the key creation time followed by the
522 worddb_data[ 0] = publickey->publickey->data[1];
523 worddb_data[ 1] = publickey->publickey->data[2];
524 worddb_data[ 2] = publickey->publickey->data[3];
525 worddb_data[ 3] = publickey->publickey->data[4];
526 worddb_data[ 4] = (keyid >> 56) & 0xFF;
527 worddb_data[ 5] = (keyid >> 48) & 0xFF;
528 worddb_data[ 6] = (keyid >> 40) & 0xFF;
529 worddb_data[ 7] = (keyid >> 32) & 0xFF;
530 worddb_data[ 8] = (keyid >> 24) & 0xFF;
531 worddb_data[ 9] = (keyid >> 16) & 0xFF;
532 worddb_data[10] = (keyid >> 8) & 0xFF;
533 worddb_data[11] = keyid & 0xFF;
535 ret = cursor->c_get(cursor,
540 ret = cursor->c_del(cursor, 0);
544 worddb->err(worddb, ret,
545 "Problem deleting word.");
548 ret = cursor->c_close(cursor);
552 * Free our UID and word lists.
554 llfree(wordlist, NULL);
555 for (i = 0; uids[i] != NULL; i++) {
561 free_publickey(publickey);
566 key.size = sizeof(keyid);
573 return (ret == DB_NOTFOUND);
577 * Include the basic keydb routines.
579 #define NEED_GETFULLKEYID 1
580 #define NEED_GETKEYSIGS 1
581 #define NEED_KEYID2UID 1