diff options
Diffstat (limited to 'g10/keyring.c')
-rw-r--r-- | g10/keyring.c | 533 |
1 files changed, 276 insertions, 257 deletions
diff --git a/g10/keyring.c b/g10/keyring.c index fae6e11ae..95f92b171 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -24,6 +24,7 @@ #include <string.h> #include <errno.h> #include <assert.h> +#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> @@ -66,7 +67,8 @@ static int kr_offtbl_ready; struct keyring_handle { - int secret; /* this is for a secret keyring */ + CONST_KR_NAME resource; + int secret; /* this is for a secret keyring */ struct { CONST_KR_NAME kr; IOBUF iobuf; @@ -191,9 +193,10 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off) /* - * Register a filename for plain keyring files - */ -void + * Register a filename for plain keyring files. Returns a pointer to + * be used to create a handles etc or NULL to indicate that it has + * already been registered */ +void * keyring_register_filename (const char *fname, int secret) { KR_NAME kr; @@ -203,7 +206,7 @@ keyring_register_filename (const char *fname, int secret) for (kr=kr_names; kr; kr = kr->next) { if ( !compare_filenames (kr->fname, fname) ) - return; /* already registered */ + return NULL; /* already registered */ } kr = m_alloc (sizeof *kr + strlen (fname)); @@ -211,27 +214,44 @@ keyring_register_filename (const char *fname, int secret) kr->secret = !!secret; kr->lockhd = NULL; kr->is_locked = 0; + /* keep a list of all issued pointers */ kr->next = kr_names; kr_names = kr; /* create the offset table the first time a function here is used */ if (!kr_offtbl) kr_offtbl = new_offset_hash_table (); -} + return kr; +} +int +keyring_is_writable (void *token) +{ + KR_NAME r = token; + return r? !access (r->fname, W_OK) : 0; +} + +/* Create a new handle for the resource associated with TOKEN. SECRET + is just just as a cross-check. + + The returned handle must be released using keyring_release (). */ KEYRING_HANDLE -keyring_new (int secret) +keyring_new (void *token, int secret) { - KEYRING_HANDLE hd; + KEYRING_HANDLE hd; + KR_NAME resource = token; - hd = m_alloc_clear (sizeof *hd); - hd->secret = !!secret; - active_handles++; - return hd; + assert (resource && !resource->secret == !secret); + + hd = m_alloc_clear (sizeof *hd); + hd->resource = resource; + hd->secret = !!secret; + active_handles++; + return hd; } void @@ -247,32 +267,13 @@ keyring_release (KEYRING_HANDLE hd) m_free (hd); } -static CONST_KR_NAME -next_kr (CONST_KR_NAME start, int secret) -{ - start = start? start->next : kr_names; - while ( start && start->secret != secret ) - start = start->next; - return start; -} const char * keyring_get_resource_name (KEYRING_HANDLE hd) { - const char *fname; - - if (!hd) - fname = NULL; - else if (hd->found.kr) - fname = hd->found.kr->fname; - else if (hd->current.kr) - fname = hd->current.kr->fname; - else { - CONST_KR_NAME kr = next_kr (NULL, hd->secret); - fname = kr? kr->fname:NULL; - } - - return fname; + if (!hd || !hd->resource) + return NULL; + return hd->resource->fname; } @@ -512,10 +513,8 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb) fname = hd->found.kr->fname; else if (hd->current.kr) fname = hd->current.kr->fname; - else { - CONST_KR_NAME kr = next_kr (NULL, hd->secret); - fname = kr? kr->fname:NULL; - } + else + fname = hd->resource? hd->resource->fname:NULL; if (!fname) return G10ERR_GENERAL; @@ -537,6 +536,7 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb) return rc; } + int keyring_delete_keyblock (KEYRING_HANDLE hd) { @@ -614,21 +614,19 @@ prepare_search (KEYRING_HANDLE hd) return -1; /* still EOF */ if (!hd->current.kr) { /* start search with first keyring */ - hd->current.kr = next_kr (NULL, hd->secret); + hd->current.kr = hd->resource; if (!hd->current.kr) { hd->current.eof = 1; - return -1; /* no keyring available */ + return -1; /* keyring not available */ } assert (!hd->current.iobuf); } - else { /* EOF on last keyring - switch to next one */ + else { /* EOF */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; - hd->current.kr = next_kr (hd->current.kr, hd->secret); - if (!hd->current.kr) { - hd->current.eof = 1; - return -1; - } + hd->current.kr = NULL; + hd->current.eof = 1; + return -1; } hd->current.eof = 0; @@ -834,244 +832,262 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen) int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc) { - int rc; - PACKET pkt; - int save_mode; - off_t offset, main_offset; - size_t n; - int need_uid, need_words, need_keyid, need_fpr, any_skip; - int pk_no, uid_no; - int initial_skip; - int use_offtbl; - PKT_user_id *uid = NULL; - PKT_public_key *pk = NULL; - PKT_secret_key *sk = NULL; - - /* figure out what information we need */ - need_uid = need_words = need_keyid = need_fpr = any_skip = 0; - for (n=0; n < ndesc; n++) { - switch (desc[n].mode) { - case KEYDB_SEARCH_MODE_EXACT: - case KEYDB_SEARCH_MODE_SUBSTR: - case KEYDB_SEARCH_MODE_MAIL: - case KEYDB_SEARCH_MODE_MAILSUB: - case KEYDB_SEARCH_MODE_MAILEND: - need_uid = 1; - break; - case KEYDB_SEARCH_MODE_WORDS: - need_uid = 1; - need_words = 1; - break; - case KEYDB_SEARCH_MODE_SHORT_KID: - case KEYDB_SEARCH_MODE_LONG_KID: - need_keyid = 1; - break; - case KEYDB_SEARCH_MODE_FPR16: - case KEYDB_SEARCH_MODE_FPR20: - case KEYDB_SEARCH_MODE_FPR: - need_fpr = 1; - break; - case KEYDB_SEARCH_MODE_FIRST: - /* always restart the search in this mode */ - keyring_search_reset (hd); - break; - default: break; + int rc; + PACKET pkt; + int save_mode; + off_t offset, main_offset; + size_t n; + int need_uid, need_words, need_keyid, need_fpr, any_skip; + int pk_no, uid_no; + int initial_skip; + int use_offtbl; + PKT_user_id *uid = NULL; + PKT_public_key *pk = NULL; + PKT_secret_key *sk = NULL; + + /* figure out what information we need */ + need_uid = need_words = need_keyid = need_fpr = any_skip = 0; + for (n=0; n < ndesc; n++) + { + switch (desc[n].mode) + { + case KEYDB_SEARCH_MODE_EXACT: + case KEYDB_SEARCH_MODE_SUBSTR: + case KEYDB_SEARCH_MODE_MAIL: + case KEYDB_SEARCH_MODE_MAILSUB: + case KEYDB_SEARCH_MODE_MAILEND: + need_uid = 1; + break; + case KEYDB_SEARCH_MODE_WORDS: + need_uid = 1; + need_words = 1; + break; + case KEYDB_SEARCH_MODE_SHORT_KID: + case KEYDB_SEARCH_MODE_LONG_KID: + need_keyid = 1; + break; + case KEYDB_SEARCH_MODE_FPR16: + case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR: + need_fpr = 1; + break; + case KEYDB_SEARCH_MODE_FIRST: + /* always restart the search in this mode */ + keyring_search_reset (hd); + break; + default: break; } - if (desc[n].skipfnc) { - any_skip = 1; - need_keyid = 1; + if (desc[n].skipfnc) + { + any_skip = 1; + need_keyid = 1; } } - rc = prepare_search (hd); - if (rc) - return rc; + rc = prepare_search (hd); + if (rc) + return rc; - use_offtbl = !hd->secret && kr_offtbl; - if (!use_offtbl) - ; - else if (!kr_offtbl_ready) - need_keyid = 1; - else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID) - { - struct off_item *oi; + use_offtbl = !hd->secret && kr_offtbl; + if (!use_offtbl) + ; + else if (!kr_offtbl_ready) + need_keyid = 1; + else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID) + { + struct off_item *oi; - oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid); - if (!oi) - { /* We know that we don't have this key */ - hd->found.kr = NULL; - hd->current.eof = 1; - return -1; - } - /* We could now create a positive search status and return. - * However the problem is that another instance of gpg may - * have changed the keyring so that the offsets are not valid - * anymore - therefore we don't do it - */ - } + oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid); + if (!oi) + { /* We know that we don't have this key */ + hd->found.kr = NULL; + hd->current.eof = 1; + return -1; + } + /* We could now create a positive search status and return. + * However the problem is that another instance of gpg may + * have changed the keyring so that the offsets are not valid + * anymore - therefore we don't do it + */ + } -#if 0 - if (need_words) { - BUG(); - if ( !hd->word_match.name || strcmp (hd->word_match.name, name) ) { - /* name changed */ - m_free (hd->word_match.name); - m_free (hd->word_match.pattern); - hd->word_match.name = m_strdup (name); - hd->word_match.pattern = prepare_word_match (name); + if (need_words) + { + const char *name = NULL; + + log_debug ("word search mode does not yet work\n"); + /* FIXME: here is a long standing bug in our function and in addition we + just use the first search description */ + for (n=0; n < ndesc && !name; n++) + { + if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS) + name = desc[n].u.name; } - name = hd->word_match.pattern; + assert (name); + if ( !hd->word_match.name || strcmp (hd->word_match.name, name) ) + { + /* name changed */ + m_free (hd->word_match.name); + m_free (hd->word_match.pattern); + hd->word_match.name = m_strdup (name); + hd->word_match.pattern = prepare_word_match (name); + } + name = hd->word_match.pattern; } -#endif - init_packet(&pkt); - save_mode = set_packet_list_mode(0); + init_packet(&pkt); + save_mode = set_packet_list_mode(0); - hd->found.kr = NULL; - main_offset = 0; - pk_no = uid_no = 0; - initial_skip = 1; /* skip until we see the start of a keyblock */ - while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid))) { - byte afp[MAX_FINGERPRINT_LEN]; - size_t an; - u32 aki[2]; - - if (pkt.pkttype == PKT_PUBLIC_KEY - || pkt.pkttype == PKT_SECRET_KEY) { - main_offset = offset; - pk_no = uid_no = 0; - initial_skip = 0; + hd->found.kr = NULL; + main_offset = 0; + pk_no = uid_no = 0; + initial_skip = 1; /* skip until we see the start of a keyblock */ + while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid))) + { + byte afp[MAX_FINGERPRINT_LEN]; + size_t an; + u32 aki[2]; + + if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY) + { + main_offset = offset; + pk_no = uid_no = 0; + initial_skip = 0; } - if (initial_skip) { - free_packet (&pkt); - continue; + if (initial_skip) + { + free_packet (&pkt); + continue; } - pk = NULL; - sk = NULL; - uid = NULL; - if ( pkt.pkttype == PKT_PUBLIC_KEY - || pkt.pkttype == PKT_PUBLIC_SUBKEY) { - pk = pkt.pkt.public_key; - ++pk_no; - - if (need_fpr) { - fingerprint_from_pk (pk, afp, &an); - while (an < 20) /* fill up to 20 bytes */ - afp[an++] = 0; - } - if (need_keyid) - keyid_from_pk (pk, aki); + pk = NULL; + sk = NULL; + uid = NULL; + if ( pkt.pkttype == PKT_PUBLIC_KEY + || pkt.pkttype == PKT_PUBLIC_SUBKEY) + { + pk = pkt.pkt.public_key; + ++pk_no; - if (use_offtbl && !kr_offtbl_ready) - update_offset_hash_table (kr_offtbl, aki, main_offset); + if (need_fpr) { + fingerprint_from_pk (pk, afp, &an); + while (an < 20) /* fill up to 20 bytes */ + afp[an++] = 0; + } + if (need_keyid) + keyid_from_pk (pk, aki); + + if (use_offtbl && !kr_offtbl_ready) + update_offset_hash_table (kr_offtbl, aki, main_offset); } - else if (pkt.pkttype == PKT_USER_ID) { - uid = pkt.pkt.user_id; - ++uid_no; + else if (pkt.pkttype == PKT_USER_ID) + { + uid = pkt.pkt.user_id; + ++uid_no; } - else if ( pkt.pkttype == PKT_SECRET_KEY - || pkt.pkttype == PKT_SECRET_SUBKEY) { - sk = pkt.pkt.secret_key; - ++pk_no; - - if (need_fpr) { - fingerprint_from_sk (sk, afp, &an); - while (an < 20) /* fill up to 20 bytes */ - afp[an++] = 0; - } - if (need_keyid) - keyid_from_sk (sk, aki); + else if ( pkt.pkttype == PKT_SECRET_KEY + || pkt.pkttype == PKT_SECRET_SUBKEY) + { + sk = pkt.pkt.secret_key; + ++pk_no; + + if (need_fpr) { + fingerprint_from_sk (sk, afp, &an); + while (an < 20) /* fill up to 20 bytes */ + afp[an++] = 0; + } + if (need_keyid) + keyid_from_sk (sk, aki); } - for (n=0; n < ndesc; n++) { - switch (desc[n].mode) { - case KEYDB_SEARCH_MODE_NONE: - BUG (); - break; - case KEYDB_SEARCH_MODE_EXACT: - case KEYDB_SEARCH_MODE_SUBSTR: - case KEYDB_SEARCH_MODE_MAIL: - case KEYDB_SEARCH_MODE_MAILSUB: - case KEYDB_SEARCH_MODE_MAILEND: - case KEYDB_SEARCH_MODE_WORDS: - if ( uid && !compare_name (desc[n].mode, - desc[n].u.name, - uid->name, uid->len)) - goto found; - break; + for (n=0; n < ndesc; n++) + { + switch (desc[n].mode) { + case KEYDB_SEARCH_MODE_NONE: + BUG (); + break; + case KEYDB_SEARCH_MODE_EXACT: + case KEYDB_SEARCH_MODE_SUBSTR: + case KEYDB_SEARCH_MODE_MAIL: + case KEYDB_SEARCH_MODE_MAILSUB: + case KEYDB_SEARCH_MODE_MAILEND: + case KEYDB_SEARCH_MODE_WORDS: + if ( uid && !compare_name (desc[n].mode, + desc[n].u.name, + uid->name, uid->len)) + goto found; + break; - case KEYDB_SEARCH_MODE_SHORT_KID: - if ((pk||sk) && desc[n].u.kid[1] == aki[1]) - goto found; - break; - case KEYDB_SEARCH_MODE_LONG_KID: - if ((pk||sk) && desc[n].u.kid[0] == aki[0] - && desc[n].u.kid[1] == aki[1]) - goto found; - break; - case KEYDB_SEARCH_MODE_FPR16: - if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16)) - goto found; - break; - case KEYDB_SEARCH_MODE_FPR20: - case KEYDB_SEARCH_MODE_FPR: - if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20)) - goto found; - break; - case KEYDB_SEARCH_MODE_FIRST: - if (pk||sk) - goto found; - break; - case KEYDB_SEARCH_MODE_NEXT: - if (pk||sk) - goto found; - break; - default: - rc = G10ERR_INV_ARG; - goto found; - } + case KEYDB_SEARCH_MODE_SHORT_KID: + if ((pk||sk) && desc[n].u.kid[1] == aki[1]) + goto found; + break; + case KEYDB_SEARCH_MODE_LONG_KID: + if ((pk||sk) && desc[n].u.kid[0] == aki[0] + && desc[n].u.kid[1] == aki[1]) + goto found; + break; + case KEYDB_SEARCH_MODE_FPR16: + if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16)) + goto found; + break; + case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR: + if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20)) + goto found; + break; + case KEYDB_SEARCH_MODE_FIRST: + if (pk||sk) + goto found; + break; + case KEYDB_SEARCH_MODE_NEXT: + if (pk||sk) + goto found; + break; + default: + rc = G10ERR_INV_ARG; + goto found; + } } - free_packet (&pkt); - continue; - found: - for (n=any_skip?0:ndesc; n < ndesc; n++) { - if (desc[n].skipfnc - && desc[n].skipfnc (desc[n].skipfncvalue, aki)) - break; + free_packet (&pkt); + continue; + found: + for (n=any_skip?0:ndesc; n < ndesc; n++) + { + if (desc[n].skipfnc + && desc[n].skipfnc (desc[n].skipfncvalue, aki)) + break; } - if (n == ndesc) - goto real_found; - free_packet (&pkt); + if (n == ndesc) + goto real_found; + free_packet (&pkt); } real_found: - if( !rc ) { - hd->found.offset = main_offset; - hd->found.kr = hd->current.kr; - hd->found.pk_no = (pk||sk)? pk_no : 0; - hd->found.uid_no = uid? uid_no : 0; + if (!rc) + { + hd->found.offset = main_offset; + hd->found.kr = hd->current.kr; + hd->found.pk_no = (pk||sk)? pk_no : 0; + hd->found.uid_no = uid? uid_no : 0; } - else if (rc == -1) - { - hd->current.eof = 1; - /* if we scanned the entire keyring, we are sure that - * all known key IDs are in our offtbl, mark that. */ - if (use_offtbl) - kr_offtbl_ready = 1; - } - else - hd->current.error = rc; - - + else if (rc == -1) + { + hd->current.eof = 1; + /* if we scanned the entire keyring, we are sure that + * all known key IDs are in our offtbl, mark that. */ + if (use_offtbl) + kr_offtbl_ready = 1; + } + else + hd->current.error = rc; - free_packet(&pkt); - set_packet_list_mode(save_mode); - return rc; + free_packet(&pkt); + set_packet_list_mode(save_mode); + return rc; } - static int create_tmp_file (const char *template, char **r_bakfname, char **r_tmpfname, IOBUF *r_fp) @@ -1236,7 +1252,7 @@ write_keyblock (IOBUF fp, KBNODE keyblock) * This is only done for the public keyrings. */ int -keyring_rebuild_cache () +keyring_rebuild_cache (void *token) { KEYRING_HANDLE hd; KEYDB_SEARCH_DESC desc; @@ -1248,7 +1264,7 @@ keyring_rebuild_cache () int rc; ulong count = 0, sigcount = 0; - hd = keyring_new (0); + hd = keyring_new (token, 0); memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_FIRST; @@ -1366,7 +1382,10 @@ do_copy (int mode, const char *fname, KBNODE root, int secret, char *bakfname = NULL; char *tmpfname = NULL; - /* open the source file */ + /* Open the source file. Because we do a rname, we have to check the + permissions of the file */ + if (access (fname, W_OK)) + return G10ERR_WRITE_FILE; fp = iobuf_open (fname); if (mode == 1 && !fp && errno == ENOENT) { /* insert mode but file does not exist: create a new file */ |