--- trunk/Src/wptKeyCache.cpp 2006/01/13 14:21:16 147 +++ trunk/Src/wptKeyCache.cpp 2006/03/22 11:04:20 187 @@ -36,6 +36,7 @@ #include "wptErrors.h" #include "wptW32API.h" #include "wptGPG.h" +#include "wptTypes.h" /* Attribute list which holds the image data. */ @@ -49,6 +50,7 @@ typedef struct attr_list_s *attr_list_t; +/* Free attribute list @ctx. */ void free_attr_list (attr_list_t ctx) { @@ -81,6 +83,8 @@ buffer = buf+9+10; pos = 0; c = (attr_list_t)calloc (1, sizeof *c); + if (!c) + BUG (0); p = strtok (buffer, " "); while (p != NULL) { switch (pos) { @@ -102,7 +106,6 @@ pos++; p = strtok (NULL, " "); } - /*printf ("id=%s octets=%d flags=%d\n", c->fpr, c->octets, c->flags);*/ if (!*ctx) *ctx = c; else { @@ -111,6 +114,8 @@ t->next = c; } c->d = (unsigned char*)malloc (c->octets); + if (!c->d) + BUG (0); memcpy (c->d, data, c->octets); data += c->octets; datlen -= c->octets; @@ -125,23 +130,25 @@ parse_attr_data (const char *keyid, attr_list_t *list) { gpgme_error_t err; - FILE *tmp; - char *status; + FILE *tmp; BYTE *data; - DWORD ndata; + char *status, tmpnam[MAX_PATH+1]; + DWORD ndata = 0; err = gpg_get_photoid_data (keyid, &status, &data, &ndata); if (err) return err; - if (ndata > 0) { - tmp = tmpfile (); + get_temp_name (tmpnam, MAX_PATH, NULL); + tmp = fopen (tmpnam, "w+b"); + if (ndata > 0 && tmp != NULL) { fwrite (status, 1, strlen (status), tmp); fflush (tmp); rewind (tmp); ndata = parse_attr_list (tmp, data, ndata, list); fclose (tmp); + DeleteFile (tmpnam); } else *list = NULL; @@ -171,6 +178,8 @@ gpg_iobuf_ioctl (inp, 3, 1, NULL); pkt = (PACKET*)calloc (1, sizeof *pkt); + if (!pkt) + BUG (0); gpg_init_packet (pkt); while (gpg_parse_packet (inp, pkt) != -1) { if (pkt->pkttype == PKT_SECRET_KEY) { @@ -214,6 +223,8 @@ fnd->attrib.flags = dat->flags; fnd->attrib.len = dat->octets; fnd->attrib.d = (unsigned char*)malloc (dat->octets); + if (!fnd->attrib.d) + BUG (0); memcpy (fnd->attrib.d, dat->d, dat->octets); return 0; } @@ -265,6 +276,8 @@ gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */ pkt = (PACKET*)calloc (1, sizeof * pkt); + if (!pkt) + BUG (0); gpg_init_packet (pkt); while (gpg_parse_packet (inp, pkt) != -1) { if (pkt->pkttype == PKT_PUBLIC_KEY) { @@ -300,7 +313,7 @@ else if (nsym > 0) { c->sym_prefs = (unsigned char*)calloc (1, nsym+1); if (!c->sym_prefs) - return gpg_error (GPG_ERR_ENOMEM); + BUG (0); memcpy (c->sym_prefs, sym_prefs, nsym); } } @@ -342,7 +355,7 @@ return gpg_error (GPG_ERR_INV_ARG); ctx = (gpg_keycache_t)calloc (1, sizeof *ctx); if (!ctx) - return gpg_error (GPG_ERR_ENOMEM); + BUG (0); ctx->secret = 0; ctx->pos = 0; *r_ctx = ctx; @@ -363,6 +376,7 @@ c2 = c->next; gpgme_key_release (c->key); c->key = NULL; + safe_free (c->pref_keyserver); safe_free (c->sym_prefs); safe_free (c->attrib.d); safe_free (c->card_type); @@ -402,7 +416,7 @@ c = (struct keycache_s*)calloc (1, sizeof *c); if (!c) - return gpg_error (GPG_ERR_ENOMEM); + BUG (0); c->gloflags.is_protected = 1; /*default: assume protection. */ c->key = key; if (!ctx->item) @@ -503,17 +517,20 @@ /* Return the next key which was updated. Before it is returned the update flag is cleared. + @r_status is 1 for a new key and 2 for an updated key. Return value: 0 on success. */ gpgme_error_t gpg_keycache_next_updated_key (gpg_keycache_t ctx, - struct keycache_s **r_obj) + struct keycache_s **r_obj, + int *r_status) { struct keycache_s *c; for (c = ctx->item; c; c = c->next) { - if (c->flags == 1) { - c->flags = 0; + if (c->flags != 0) { + *r_status = c->flags; *r_obj = c; + c->flags = 0; return 0; } } @@ -535,6 +552,7 @@ err = gpgme_new (&gctx); if (err) return err; + gpgme_set_keylist_mode (gctx, GPGME_KEYLIST_MODE_SIGS); err = gpgme_get_key (gctx, keyid, &key, is_sec); gpgme_release (gctx); if (err) @@ -544,7 +562,7 @@ log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub); gpgme_key_release (fndkey); c->key = key; - c->flags = 1; + c->flags = KC_FLAG_UPD; if (is_sec && pub != NULL && !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) { log_debug ("keycache update: set public part %p\r\n", fndkey); @@ -568,7 +586,7 @@ } } if (c) - c->flags = 1; + c->flags = KC_FLAG_ADD; } return 0; } @@ -592,17 +610,18 @@ c = ctx->item; if (c->next == NULL) { gpgme_key_release (itm->key); - if (itm) - free (itm); + safe_free (itm); ctx->item = NULL; } else { - while (c && c->next != itm) - c = c->next; + for (; c != NULL; c = c->next) { + if (c->next == itm) + break; + } + assert (c != NULL); /* XXX: sometimes access violation. */ c->next = c->next->next; gpgme_key_release (itm->key); - if (itm) - free (itm); + safe_free (itm); } return 0; } @@ -676,7 +695,7 @@ pos++; p = (unsigned char*)calloc (1, pos+1); if (!p) - abort (); + BUG (0); memcpy (p, prefs, pos); return p; } @@ -697,7 +716,8 @@ c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card; if (!c->gloflags.divert_to_card) c->gloflags.divert_to_card = key_divert_to_card (key); - c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs); + if (c_sec->sym_prefs) + c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs); c->pubpart = c_sec; c->pubpart->key = key; } @@ -746,7 +766,11 @@ *r_key = NULL; return gpg_error (GPG_ERR_EOF); } - + if (ctx->tmp->flags != 0) + ctx->tmp->flags = 0; /* reset the 'updated' status. */ + /* it might be possible there is no public key. */ + if (flags && ctx->tmp->pubpart == NULL) + flags = 0; *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key; *c = ctx->tmp = ctx->tmp->next; ctx->pos++; @@ -767,3 +791,142 @@ err = keycache_next_key (ctx, flags, &c, r_key); return err; } + + +/* Search for a key with the pattern @pattern and mark + this key as the default signing key if found. + Return value: 0 on success. */ +gpgme_error_t +gpg_keycache_set_default_key (gpg_keycache_t ctx, + const char *pattern) +{ + gpgme_error_t err; + gpgme_key_t key; + struct keycache_s *itm; + + err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm); + if (err) + return err; + + if (itm) + itm->default_key = 1; + return 0; +} + +/* Return the default key from the cache. If no was + marked before, NULL is returned in @r_key. + Return value: 0 on success. */ +gpgme_error_t +gpg_keycache_get_default_key (gpg_keycache_t ctx, + gpgme_key_t *r_key) +{ + struct keycache_s *itm; + + *r_key = NULL; + for (itm = ctx->item; itm; itm = itm->next) { + if (itm->default_key) { + *r_key = itm->key; + break; + } + } + if (!*r_key) + return gpgme_error (GPG_ERR_NOT_FOUND); + return 0; +} + + +static gpgme_error_t +decode_subpacket (const char *subpkt_data, int *type, + char **out, WORD *outlen) +{ + char tmp[128], *p = tmp, *val; + char *enc = NULL; + size_t pos = 0, i=0; + + /* example: spk:24:1:21:http%3A//subkeys.pgp.de */ + *outlen = 0; + *out = NULL; + + if (strncmp (subpkt_data, "spk:", 4)) + return gpg_error (GPG_ERR_NO_DATA); + + strncpy (tmp, subpkt_data, 62); + val = strtok (tmp, ":"); + while (val != NULL) { + switch (pos++) { + case 0: + break; + + case 1: + if (type) + *type = atoi (val); + break; + + case 2: + break; + + case 3: + *outlen = atoi (val); + break; + + case 4: + enc = strdup (val); + break; + } + val = strtok (NULL, ":"); + } + if (!enc) + return gpg_error (GPG_ERR_NO_DATA);; + *out = (char*)calloc (1, strlen (enc)+1); + for (pos = 0; pos < strlen (enc); pos++) { + if (enc[pos] == '%' && enc[pos+1] == '%') + (*out)[i++] = '%'; + else if (enc[pos] == '%') { + char tmp[3]; + tmp[0] = enc[++pos]; + tmp[1] = enc[++pos]; + tmp[2] = 0; + (*out)[i++] = (char)strtoul (tmp, NULL, 16); + } + else + (*out)[i++] = enc[pos]; + } + (*out)[i] = 0; + free (enc); + return 0; +} + + +/* If the attribute given in @attr is not set in the + key cache object, try to update it. */ +gpgme_error_t +gpg_keycache_update_attr (struct keycache_s *item, + int attr, int force) +{ + gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR); + char *val = NULL; + WORD n = 0; + + switch (attr) { + case KC_ATTR_PREFSYM: + if (!force && item->sym_prefs) + break; + safe_free (item->sym_prefs); + err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val); + if (!err && val != NULL) + err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n); + break; + + case KC_ATTR_PREFKSERV: + if (!force && item->pref_keyserver) + break; + safe_free (item->pref_keyserver); + err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val); + if (!err && val != NULL) + err = decode_subpacket (val, NULL, &item->pref_keyserver, &n); + break; + } + safe_free (val); + return err; +} +