diff options
Diffstat (limited to 'g10/getkey.c')
-rw-r--r-- | g10/getkey.c | 379 |
1 files changed, 139 insertions, 240 deletions
diff --git a/g10/getkey.c b/g10/getkey.c index 9dae879d2..57617a0a9 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -36,6 +36,7 @@ #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" +#include "objcache.h" #include "../common/host2net.h" #include "../common/mbox-util.h" #include "../common/status.h" @@ -112,6 +113,7 @@ static struct typedef struct keyid_list { struct keyid_list *next; + byte fprlen; char fpr[MAX_FINGERPRINT_LEN]; u32 keyid[2]; } *keyid_list_t; @@ -132,15 +134,6 @@ static int pk_cache_disabled; #if MAX_UID_CACHE_ENTRIES < 5 #error we really need the userid cache #endif -typedef struct user_id_db -{ - struct user_id_db *next; - keyid_list_t keyids; - int len; - char name[1]; -} *user_id_db_t; -static user_id_db_t user_id_db; -static int uid_cache_entries; /* Number of entries in uid cache. */ static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock); static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, @@ -262,112 +255,6 @@ user_id_not_found_utf8 (void) -/* Return the user ID from the given keyblock. - * We use the primary uid flag which has been set by the merge_selfsigs - * function. The returned value is only valid as long as the given - * keyblock is not changed. */ -static const char * -get_primary_uid (KBNODE keyblock, size_t * uidlen) -{ - KBNODE k; - const char *s; - - for (k = keyblock; k; k = k->next) - { - if (k->pkt->pkttype == PKT_USER_ID - && !k->pkt->pkt.user_id->attrib_data - && k->pkt->pkt.user_id->flags.primary) - { - *uidlen = k->pkt->pkt.user_id->len; - return k->pkt->pkt.user_id->name; - } - } - s = user_id_not_found_utf8 (); - *uidlen = strlen (s); - return s; -} - - -static void -release_keyid_list (keyid_list_t k) -{ - while (k) - { - keyid_list_t k2 = k->next; - xfree (k); - k = k2; - } -} - -/**************** - * Store the association of keyid and userid - * Feed only public keys to this function. - */ -static void -cache_user_id (KBNODE keyblock) -{ - user_id_db_t r; - const char *uid; - size_t uidlen; - keyid_list_t keyids = NULL; - KBNODE k; - - for (k = keyblock; k; k = k->next) - { - if (k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) - { - keyid_list_t a = xmalloc_clear (sizeof *a); - /* Hmmm: For a long list of keyids it might be an advantage - * to append the keys. */ - fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL); - keyid_from_pk (k->pkt->pkt.public_key, a->keyid); - /* First check for duplicates. */ - for (r = user_id_db; r; r = r->next) - { - keyid_list_t b; - - for (b = r->keyids; b; b = b->next) - { - if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN)) - { - if (DBG_CACHE) - log_debug ("cache_user_id: already in cache\n"); - release_keyid_list (keyids); - xfree (a); - return; - } - } - } - /* Now put it into the cache. */ - a->next = keyids; - keyids = a; - } - } - if (!keyids) - BUG (); /* No key no fun. */ - - - uid = get_primary_uid (keyblock, &uidlen); - - if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES) - { - /* fixme: use another algorithm to free some cache slots */ - r = user_id_db; - user_id_db = r->next; - release_keyid_list (r->keyids); - xfree (r); - uid_cache_entries--; - } - r = xmalloc (sizeof *r + uidlen - 1); - r->keyids = keyids; - r->len = uidlen; - memcpy (r->name, uid, r->len); - r->next = user_id_db; - user_id_db = r; - uid_cache_entries++; -} - /* Disable and drop the public key cache (which is filled by cache_public_key and get_pubkey). Note: there is currently no way @@ -948,11 +835,21 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, /* Find a public key identified by NAME. * - * If name appears to be a valid RFC822 mailbox (i.e., email - * address) and auto key lookup is enabled (no_akl == 0), then the - * specified auto key lookup methods (--auto-key-lookup) are used to - * import the key into the local keyring. Otherwise, just the local - * keyring is consulted. + * If name appears to be a valid RFC822 mailbox (i.e., email address) + * and auto key lookup is enabled (mode != GET_PUBKEY_NO_AKL), then + * the specified auto key lookup methods (--auto-key-lookup) are used + * to import the key into the local keyring. Otherwise, just the + * local keyring is consulted. + * + * MODE can be one of: + * GET_PUBKEY_NORMAL - The standard mode + * GET_PUBKEY_NO_AKL - The auto key locate functionality is + * disabled and only the local key ring is + * considered. Note: the local key ring is + * consulted even if local is not in the + * auto-key-locate option list! + * GET_PUBKEY_NO_LOCAL - Only the auto key locate functionaly is + * used and no local search is done. * * If RETCTX is not NULL, then the constructed context is returned in * *RETCTX so that getpubkey_next can be used to get subsequent @@ -988,18 +885,14 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, * documentation for skip_unusable for an exact definition) are * skipped unless they are looked up by key id or by fingerprint. * - * If NO_AKL is set, then the auto key locate functionality is - * disabled and only the local key ring is considered. Note: the - * local key ring is consulted even if local is not in the - * --auto-key-locate option list! - * * This function returns 0 on success. Otherwise, an error code is * returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY * (if want_secret is set) is returned if the key is not found. */ int -get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, +get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, + GETKEY_CTX * retctx, PKT_public_key * pk, const char *name, KBNODE * ret_keyblock, - KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl) + KEYDB_HANDLE * ret_kdbhd, int include_unusable) { int rc; strlist_t namelist = NULL; @@ -1035,7 +928,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, * Note: we only save the search context in RETCTX if the local * method is the first method tried (either explicitly or * implicitly). */ - if (!no_akl) + if (mode == GET_PUBKEY_NO_LOCAL) + nodefault = 1; /* Auto-key-locate but ignore "local". */ + else if (mode != GET_PUBKEY_NO_AKL) { /* auto-key-locate is enabled. */ @@ -1064,7 +959,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, anylocalfirst = 1; } - if (nodefault && is_mbox) + if (mode == GET_PUBKEY_NO_LOCAL) + { + /* Force using the AKL. If IS_MBOX is not set this is the final + * error code. */ + rc = GPG_ERR_NO_PUBKEY; + } + else if (nodefault && is_mbox) { /* Either "nodefault" or "local" (explicitly) appeared in the * auto key locate list and NAME appears to be an email address. @@ -1085,7 +986,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, /* If the requested name resembles a valid mailbox and automatic retrieval has been enabled, we try to import the key. */ - if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox) + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && mode != GET_PUBKEY_NO_AKL + && is_mbox) { /* NAME wasn't present in the local keyring (or we didn't try * the local keyring). Since the auto key locate feature is @@ -1104,22 +1007,30 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, { case AKL_NODEFAULT: /* This is a dummy mechanism. */ - mechanism_string = "None"; + mechanism_string = ""; rc = GPG_ERR_NO_PUBKEY; break; case AKL_LOCAL: - mechanism_string = "Local"; - did_akl_local = 1; - if (retctx) - { - getkey_end (ctrl, *retctx); - *retctx = NULL; - } - add_to_strlist (&namelist, name); - rc = key_byname (ctrl, anylocalfirst ? retctx : NULL, - namelist, pk, 0, - include_unusable, ret_keyblock, ret_kdbhd); + if (mode == GET_PUBKEY_NO_LOCAL) + { + mechanism_string = ""; + rc = GPG_ERR_NO_PUBKEY; + } + else + { + mechanism_string = "Local"; + did_akl_local = 1; + if (retctx) + { + getkey_end (ctrl, *retctx); + *retctx = NULL; + } + add_to_strlist (&namelist, name); + rc = key_byname (ctrl, anylocalfirst ? retctx : NULL, + namelist, pk, 0, + include_unusable, ret_keyblock, ret_kdbhd); + } break; case AKL_CERT: @@ -1246,15 +1157,14 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, name, mechanism_string); break; } - if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY - || opt.verbose || no_fingerprint) + if ((gpg_err_code (rc) != GPG_ERR_NO_PUBKEY + || opt.verbose || no_fingerprint) && *mechanism_string) log_info (_("error retrieving '%s' via %s: %s\n"), name, mechanism_string, no_fingerprint ? _("No fingerprint") : gpg_strerror (rc)); } } - if (rc && retctx) { getkey_end (ctrl, *retctx); @@ -1315,7 +1225,7 @@ subkey_is_ok (const PKT_public_key *sub) /* Return true if KEYBLOCK has only expired encryption subkyes. Note * that the function returns false if the key has no encryption - * subkeys at all or the subkecys are revoked. */ + * subkeys at all or the subkeys are revoked. */ static int only_expired_enc_subkeys (kbnode_t keyblock) { @@ -1407,7 +1317,8 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old, * resembles a mail address, the results are ranked and only the best * result is returned. */ gpg_error_t -get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, +get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode, + GETKEY_CTX *retctx, PKT_public_key *pk, const char *name, KBNODE *ret_keyblock, int include_unusable) { @@ -1430,8 +1341,9 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, getkey_end (ctrl, ctx); ctx = NULL; } - err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock, - NULL, include_unusable, 0); + err = get_pubkey_byname (ctrl, mode, + &ctx, pk, name, ret_keyblock, + NULL, include_unusable); if (err) { getkey_end (ctrl, ctx); @@ -1493,15 +1405,14 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk, /* Old key is better. */ release_public_key_parts (&new.key); free_user_id (new.uid); - new.uid = NULL; } else { /* A tie. Keep the old key. */ release_public_key_parts (&new.key); free_user_id (new.uid); - new.uid = NULL; } + new.uid = NULL; } getkey_end (ctrl, ctx); ctx = NULL; @@ -1637,7 +1548,7 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname) * * FPRINT is a byte array whose contents is the fingerprint to use as * the search term. FPRINT_LEN specifies the length of the - * fingerprint (in bytes). Currently, only 16 and 20-byte + * fingerprint (in bytes). Currently, only 16, 20, and 32-byte * fingerprints are supported. * * FIXME: We should replace this with the _byname function. This can @@ -3291,7 +3202,11 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) memcpy (&pk->revoked, &rinfo, sizeof (rinfo)); } if (main_pk->has_expired) - pk->has_expired = main_pk->has_expired; + { + pk->has_expired = main_pk->has_expired; + if (!pk->expiredate || pk->expiredate > main_pk->expiredate) + pk->expiredate = main_pk->expiredate; + } } } return; @@ -3623,7 +3538,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, xfree (tempkeystr); } - cache_user_id (keyblock); + cache_put_keyblock (keyblock); return latest_key ? latest_key : keyblock; /* Found. */ } @@ -3836,67 +3751,40 @@ get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, * this string must be freed by xfree. If R_NOUID is not NULL it is * set to true if a user id was not found; otherwise to false. */ static char * -get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, - int *r_nouid) +get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode) { - user_id_db_t r; - keyid_list_t a; - int pass = 0; + char *name; + unsigned int namelen; char *p; - if (r_nouid) - *r_nouid = 0; + log_assert (mode != 2); - /* Try it two times; second pass reads from the database. */ - do + name = cache_get_uid_bykid (keyid, &namelen); + if (!name) { - for (r = user_id_db; r; r = r->next) - { - for (a = r->keyids; a; a = a->next) - { - if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1]) - { - if (mode == 2) - { - /* An empty string as user id is possible. Make - sure that the malloc allocates one byte and - does not bail out. */ - p = xmalloc (r->len? r->len : 1); - memcpy (p, r->name, r->len); - if (r_len) - *r_len = r->len; - } - else - { - if (mode) - p = xasprintf ("%08lX%08lX %.*s", - (ulong) keyid[0], (ulong) keyid[1], - r->len, r->name); - else - p = xasprintf ("%s %.*s", keystr (keyid), - r->len, r->name); - if (r_len) - *r_len = strlen (p); - } - - return p; - } - } - } + /* Get it so that the cache will be filled. */ + if (!get_pubkey (ctrl, NULL, keyid)) + name = cache_get_uid_bykid (keyid, &namelen); } - while (++pass < 2 && !get_pubkey (ctrl, NULL, keyid)); - if (mode == 2) - p = xstrdup (user_id_not_found_utf8 ()); - else if (mode) - p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]); + if (name) + { + if (mode) + p = xasprintf ("%08lX%08lX %.*s", + (ulong) keyid[0], (ulong) keyid[1], namelen, name); + else + p = xasprintf ("%s %.*s", keystr (keyid), namelen, name); + + xfree (name); + } else - p = xasprintf ("%s [?]", keystr (keyid)); + { + if (mode) + p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]); + else + p = xasprintf ("%s [?]", keystr (keyid)); + } - if (r_nouid) - *r_nouid = 1; - if (r_len) - *r_len = strlen (p); return p; } @@ -3904,7 +3792,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, char * get_user_id_string_native (ctrl_t ctrl, u32 * keyid) { - char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL); + char *p = get_user_id_string (ctrl, keyid, 0); char *p2 = utf8_to_native (p, strlen (p), 0); xfree (p); return p2; @@ -3914,7 +3802,7 @@ get_user_id_string_native (ctrl_t ctrl, u32 * keyid) char * get_long_user_id_string (ctrl_t ctrl, u32 * keyid) { - return get_user_id_string (ctrl, keyid, 1, NULL, NULL); + return get_user_id_string (ctrl, keyid, 1); } @@ -3922,7 +3810,31 @@ get_long_user_id_string (ctrl_t ctrl, u32 * keyid) char * get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid) { - return get_user_id_string (ctrl, keyid, 2, rn, r_nouid); + char *name; + unsigned int namelen; + + if (r_nouid) + *r_nouid = 0; + + name = cache_get_uid_bykid (keyid, &namelen); + if (!name) + { + /* Get it so that the cache will be filled. */ + if (!get_pubkey (ctrl, NULL, keyid)) + name = cache_get_uid_bykid (keyid, &namelen); + } + + if (!name) + { + name = xstrdup (user_id_not_found_utf8 ()); + namelen = strlen (name); + if (r_nouid) + *r_nouid = 1; + } + + if (rn && name) + *rn = namelen; + return name; } @@ -3943,49 +3855,36 @@ get_user_id_native (ctrl_t ctrl, u32 *keyid) returned string, which must be freed using xfree, may not be NUL terminated. To determine the length of the string, you must use *RN. */ -char * -get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn) +static char * +get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t fprlen, size_t *rn) { - user_id_db_t r; - char *p; - int pass = 0; + char *name; - /* Try it two times; second pass reads from the database. */ - do + name = cache_get_uid_byfpr (fpr, fprlen, rn); + if (!name) { - for (r = user_id_db; r; r = r->next) - { - keyid_list_t a; - for (a = r->keyids; a; a = a->next) - { - if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN)) - { - /* An empty string as user id is possible. Make - sure that the malloc allocates one byte and does - not bail out. */ - p = xmalloc (r->len? r->len : 1); - memcpy (p, r->name, r->len); - *rn = r->len; - return p; - } - } - } + /* Get it so that the cache will be filled. */ + if (!get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen)) + name = cache_get_uid_byfpr (fpr, fprlen, rn); } - while (++pass < 2 - && !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, MAX_FINGERPRINT_LEN)); - p = xstrdup (user_id_not_found_utf8 ()); - *rn = strlen (p); - return p; + + if (!name) + { + name = xstrdup (user_id_not_found_utf8 ()); + *rn = strlen (name); + } + + return name; } /* Like get_user_id_byfpr, but convert the string to the native encoding. The returned string needs to be freed. Unlike get_user_id_byfpr, the returned string is NUL terminated. */ char * -get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr) +get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen) { size_t rn; - char *p = get_user_id_byfpr (ctrl, fpr, &rn); + char *p = get_user_id_byfpr (ctrl, fpr, fprlen, &rn); char *p2 = utf8_to_native (p, rn, 0); xfree (p); return p2; |