/[winpt]/trunk/Src/wptKeyCache.cpp
ViewVC logotype

Diff of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 32 by twoaday, Mon Oct 24 08:03:48 2005 UTC revision 260 by twoaday, Wed Aug 16 10:01:30 2006 UTC
# Line 1  Line 1 
1  /* wptKeyCache.cpp- Caching for the pub- and the secring  /* wptKeyCache.cpp- Caching for the pub- and the secring
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2006 Timo Schulz
3   *   *
4   * This file is part of MyGPGME.   * This file is part of WinPT.
5   *   *
6   * MyGPGME is free software; you can redistribute it and/or modify   * WinPT is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * MyGPGME is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20  #include <windows.h>  
21  #include <stdio.h>  #ifdef HAVE_CONFIG_H
22  #include <string.h>  #include <config.h>
23  #include <malloc.h>  #endif
24  #include <ctype.h>  
25  #include <assert.h>  #include <windows.h>
26    #include <stdio.h>
27  #include "w32gpgme.h"  #include <string.h>
28  #include "wptKeyCache.h"  #include <ctype.h>
29  #include "openpgp.h"  #include <assert.h>
30  #include "wptNLS.h"  #include <gpgme.h>
31  #include "wptErrors.h"  
32  #include "wptW32API.h"  #include "wptKeyCache.h"
33    #include "openpgp.h"
34    #include "wptNLS.h"
35  /* convert a binary buffer into its hex representation. */  #include "wptErrors.h"
36  static void  #include "wptW32API.h"
37  buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)  #include "wptGPG.h"
38  {  #include "wptTypes.h"
39      char dig[3];  #include "wptCommonCtl.h"
40      size_t i;  #include "wptContext.h"
41    #include "wptKeyEdit.h"
42      memset (dst, 0, dlen);  #include "wptUTF8.h"
43      for (i = 0; i < nbytes && dlen > 0; i++) {  
44          sprintf (dig, "%02X", buf[i]);  
45          strcat (dst, dig);  gpgme_error_t parse_keyserver_url (char **r_keyserver, unsigned short *r_port);
46          dlen -= 2;  
47      }  /* Attribute list which holds the image data. */
48  }  struct attr_list_s {
49        struct attr_list_s *next;
50        char *fpr;                   /* fingerprint of the key */
51  /* Parse the secret keyring and retrieve some additional information      unsigned char *d;            /* actual JPEG data. */
52     for each key which was found. */      unsigned long octets;        /* length of the data. */
53  static void      unsigned int flags;          /* status of the attribute. */
54  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)  };
55  {      typedef struct attr_list_s *attr_list_t;
56      PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);  
57      PKT_secret_key *sk;  
58      gpg_iobuf_t inp;  /* XXX: convert it to an inline function and place it in a header file. */
59      gpgme_error_t err;  static unsigned char*
60      gpgme_key_t key;  safe_uchar_alloc (size_t n)
61      struct keycache_s *c=NULL;  {
62      char keyid[16+1];      unsigned char *p = new unsigned char[n];
63        if (!p)
64      inp = gpg_iobuf_open (secring);          BUG (0);
65      if (!inp) {      return p;
66          safe_free (pkt);  }
67          return;  
68      }  
69      gpg_iobuf_ioctl (inp, 3, 1, NULL);  /* Free attribute list @ctx. */
70      gpg_init_packet (pkt);  void
71      while (gpg_parse_packet (inp, pkt) != -1) {  free_attr_list (attr_list_t ctx)
72          if (pkt->pkttype == PKT_SECRET_KEY) {  {
73              sk = pkt->pkt.secret_key;      attr_list_t n;
74              /* XXX: key IDs of card public keys are wrong! */  
75              _snprintf (keyid, sizeof (keyid)-1, "%08lX",      while (ctx) {
76                         gpg_keyid_from_sk (sk, NULL));          n = ctx->next;
77              if (kid && strcmp (kid, keyid) != 0)          free_if_alloc (ctx->fpr);
78                  goto next;          free_if_alloc (ctx->d);
79              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);          free_if_alloc (ctx);
80              if (err)          ctx = n;
81                  goto next;      }
82              c->gloflags.is_protected = sk->is_protected;  }
83              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;          
84              if (c->pubpart != NULL) {      /* Parse the attribute list in @fp and store it into @ctx.
85                  c->pubpart->gloflags.is_protected = sk->is_protected;         Return value: number of parsed items. */
86                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;  int
87              }  parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
88          }  {
89  next:      attr_list_t c, t;
90          gpg_free_packet (pkt);      char buf[512], *p, *buffer;
91          gpg_init_packet (pkt);      int pos, n=0;
92      }      
93      safe_free (pkt);      *ctx = NULL;
94      gpg_iobuf_close (inp);      while (fgets (buf, 511, fp)) {
95  }          if (strstr (buf, "\r\n"))
96                buf[strlen (buf)-2]=0;
97            if (strstr (buf, "\n"))
98  /* Merge the information from the keyrings into the key cache structure. */              buf[strlen (buf)-1]=0;
99  gpgme_error_t          if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
100  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,              continue;
101                     const char *pubring, const char *secring)          buffer = buf+9+10;
102  {          pos = 0;
103      gpgme_error_t err;          c = new attr_list_s;
104      gpgme_key_t key = NULL;          if (!c)
105      gpg_iobuf_t inp;              BUG (0);
106      PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);          memset (c, 0, sizeof *c);
107      struct keycache_s *c;  
108      const byte *sym_prefs;          p = strtok (buffer, " ");
109      char keyid[16+1], *id = NULL;          while (p != NULL) {
110      int key_seen = 0;              switch (pos) {
111      size_t nbytes = 0, nsym =0;              case 0:
112                    c->fpr = m_strdup (p);
113      if (secring) {                  break;
114          parse_secring (ctx, kid, secring);                  
115          if (!pubring) {              case 1:
116              safe_free(pkt);                  c->octets = strtoul (p, NULL, 10);
117              return 0;                  break;
118          }                  
119      }              case 7:
120      inp = gpg_iobuf_open (pubring);                  c->flags = strtoul (p, NULL, 10);
121      if (!inp) {                  break;
122          safe_free( pkt );                  
123          return gpg_error (GPG_ERR_KEYRING_OPEN);              default:
124      }                  break;
125      gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */              }
126                pos++;
127      gpg_init_packet( pkt );              p = strtok (NULL, " ");
128      while (gpg_parse_packet (inp, pkt) != -1) {          }
129          if (pkt->pkttype == PKT_PUBLIC_KEY) {          if (!*ctx)
130              strcpy (keyid, "");              *ctx = c;
131              key_seen = 1;          else {
132          }              for (t = *ctx; t->next; t=t->next)
133                    ;
134          if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {              t->next = c;
135              if (pkt->pkt.signature->numrevkeys == 0)          }
136                  goto next;          c->d = safe_uchar_alloc (c->octets);
137              _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);          memcpy (c->d, data, c->octets);
138              if (kid && strcmp (kid, keyid) != 0)          data += c->octets;
139                  goto next;          datlen -= c->octets;
140              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);          n++;
141              if (err)      }
142                  goto next;      /*assert (datlen == 0); */
143              c->gloflags.has_desig_rev = 1;      return n;
144          }  }
145          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {  
146              sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,  
147                                              SIGSUBPKT_PREF_SYM, &nsym);  static int
148              if (sym_prefs == NULL)  parse_attr_data (const char *keyid, attr_list_t *list)
149                  goto next;  {
150              _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);      gpgme_error_t err;
151              if (kid && strcmp (kid, keyid) != 0)      FILE *tmp;    
152                  goto next;      BYTE *data;
153              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);      char *status, tmpnam[MAX_PATH+1];
154              if (err)      DWORD ndata = 0;
155                  goto next;  
156              else if (nsym > 0) {      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
157                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);      if (err)
158                  if (!c->sym_prefs)          return err;
159                      return gpg_error (GPG_ERR_ENOMEM);  
160                  memcpy (c->sym_prefs, sym_prefs, nsym);      get_temp_name (tmpnam, MAX_PATH, NULL);
161              }      tmp = fopen (tmpnam, "w+b");
162          }      if (ndata > 0 && tmp != NULL) {
163          if (pkt->pkttype == PKT_USER_ID) {          fwrite (status, 1, strlen (status), tmp);
164              if (id)          fflush (tmp);
165                  free (id);          rewind (tmp);
166              id = strdup (pkt->pkt.user_id->name);  
167              if (!id) {          ndata = parse_attr_list (tmp, data, ndata, list);
168                  err = gpg_error (GPG_ERR_ENOMEM);          fclose (tmp);
169                  goto fail;          DeleteFile (tmpnam);
170              }      }
171          }      else
172          if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)          *list = NULL;
173              && pkt->pkt.user_id->attrib_data && key) {  
174              PKT_user_id *id = pkt->pkt.user_id;      safe_free (status);
175              c->attrib.used = 1;      safe_free (data);
176              c->attrib.len = id->attrib_len;      return ndata;
177              c->attrib.d = (unsigned char*)calloc (1, id->attrib_len + 1);  }
178              if (!c->attrib.d) {  
179                  err = gpg_error (GPG_ERR_ENOMEM);  
180                  goto fail;  /* Parse the secret keyring and retrieve some additional information
181              }     for each key which was found. */
182              memcpy (c->attrib.d, id->attrib_data, id->attrib_len);  static void
183              key = NULL;  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
184              c = NULL;  {    
185          }      PACKET *pkt;
186  next:      PKT_secret_key *sk;
187          gpg_free_packet (pkt);      gpg_iobuf_t inp;
188          gpg_init_packet(pkt);      gpgme_error_t err;
189      }      gpgme_key_t key;
190        struct keycache_s *c=NULL;
191  fail:      char keyid[16+1];
192      safe_free (id);  
193      safe_free (pkt);      inp = gpg_iobuf_open (secring);
194      gpg_iobuf_close (inp);      if (!inp)
195      return err;          return;
196  }  
197        gpg_iobuf_ioctl (inp, 3, 1, NULL);
198        pkt = (PACKET*)calloc (1, sizeof *pkt);
199  gpgme_error_t      if (!pkt)
200  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)          BUG (0);
201  {      gpg_init_packet (pkt);
202      return keycache_prepare2 (ctx, NULL, pubr, secr);      while (gpg_parse_packet (inp, pkt) != -1) {
203  }          if (pkt->pkttype == PKT_SECRET_KEY) {
204                sk = pkt->pkt.secret_key;
205  gpgme_error_t              /* XXX: key IDs of card public keys are wrong! */
206  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,              _snprintf (keyid, sizeof (keyid)-1, "%08lX",
207                                 const char *pubr, const char *secr)                         gpg_keyid_from_sk (sk, NULL));
208  {              if (kid && strcmp (kid, keyid) != 0)
209      if (!strncmp (keyid, "0x", 2))                  goto next;
210          keyid += 2;                err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
211      return keycache_prepare2 (ctx, keyid, pubr, secr);              if (err)
212  }                  goto next;
213                c->gloflags.is_protected = sk->is_protected;
214                c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
215  /* Create new keycache object and return it in @r_ctx.              if (c->pubpart != NULL) {
216     Return value: 0 on success. */                  c->pubpart->gloflags.is_protected = sk->is_protected;
217  gpgme_error_t                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
218  gpg_keycache_new (gpg_keycache_t *r_ctx)              }
219  {          }
220      gpg_keycache_t ctx;  next:
221                gpg_free_packet (pkt);
222      if (!r_ctx)          gpg_init_packet (pkt);
223          return gpg_error (GPG_ERR_INV_ARG);      }
224      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);      safe_free (pkt);
225      if (!ctx)      gpg_iobuf_close (inp);
226          return gpg_error (GPG_ERR_ENOMEM);  }
227      ctx->secret = 0;  
228      ctx->pos = 0;  
229      *r_ctx = ctx;  /* Update the photo image of a single key with the fingerprint
230      return 0;     @fpr. The @dat struct contains the new item data. */
231  }  static gpgme_error_t
232    keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
233    {
234  /* Release keycache object @ctx. */      struct keycache_s *fnd = NULL;
235  void      gpgme_key_t key;
236  gpg_keycache_release (gpg_keycache_t ctx)      
237  {      gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
238      struct keycache_s *c, *c2;      if (!fnd)
239                return gpg_error (GPG_ERR_NOT_FOUND);
240      if (!ctx)      free_if_alloc (fnd->attrib.d);
241          return;      fnd->attrib.flags = dat->flags;
242        fnd->attrib.len = dat->octets;
243      for (c = ctx->item; c; c = c2) {      fnd->attrib.d = safe_uchar_alloc (dat->octets);
244          c2 = c->next;      memcpy (fnd->attrib.d, dat->d, dat->octets);
245          gpgme_key_release (c->key);      return 0;
246          c->key = NULL;  }
247          if (c->sym_prefs)  
248              free (c->sym_prefs);  
249          c->sym_prefs = NULL;  /* Update all photo images in the cache. */
250          if (c->attrib.d)  static gpgme_error_t
251              free (c->attrib.d);  keycache_update_photos (gpg_keycache_t ctx)
252          c->attrib.d = NULL;  {
253          if (c->card_type)      attr_list_t list=NULL, n;
254              free (c->card_type);      DWORD ndata;
255          free (c);  
256      }      ndata = parse_attr_data (NULL, &list);
257      if (ctx)      if (ndata < 1) {
258          free (ctx);          free_attr_list (list);
259  }          return 0;
260        }
261    
262  /* Set (progress) callback for the given keycache object.      for (n=list; n; n=n->next)
263     @ctx the keycache          keycache_update_photo (ctx, n->fpr, n);
264     @cb  the callback function      free_attr_list (list);
265     @cb_value1 opaque value which is passed to the callback.      return 0;
266     @cb_value2 see @cb_value1. */  }
267  void  
268  gpg_keycache_set_cb (gpg_keycache_t ctx,  
269                       void (*cb)(void *, const char *, int, int, int),  void
270                       void * cb_value1, int cb_value2)  keycache_decode_uid (struct keycache_s *ctx)
271  {  {
272      if (!ctx)      gpgme_user_id_t u;
273          return;      struct native_uid_s *n, *t;
274      ctx->cb = cb;  
275      ctx->cb_value = cb_value1;      for (u = ctx->key->uids; u; u = u->next) {
276      ctx->cb_value2 = cb_value2;          n = new native_uid_s;
277  }          if (!n)
278                BUG (0);
279            memset (n, 0, sizeof *n);
280  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.          if (is_8bit_string (u->uid)) {
281     Return value: 0 on success. */              n->malloced = 1;
282  gpgme_error_t              n->uid = utf8_to_native (u->uid);
283  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)              if (u->name != NULL)
284  {                  n->name = utf8_to_native (u->name);
285      struct keycache_s * c, * n1;              if (u->email != NULL)
286                        n->email = m_strdup (u->email);
287      if (!ctx)              if (u->comment != NULL)
288          return gpg_error (GPG_ERR_INV_ARG);                  n->comment = utf8_to_native (u->comment);
289                }
290      c = (struct keycache_s*)calloc (1, sizeof *c);          else {
291      if (!c)              n->malloced = 0;
292          return gpg_error (GPG_ERR_ENOMEM);              n->uid = u->uid;
293      c->gloflags.is_protected = 1; /*default: assume protection. */              n->name = u->name;
294      c->key = key;              n->comment = u->comment;
295      if (!ctx->item)              n->email = u->email;
296          ctx->item = c;          }
297      else {          n->signatures = u->signatures;
298          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)          n->validity = u->validity;
299              ;          n->revoked = u->revoked;
300          n1->next = c;          if (!ctx->uids)
301      }              ctx->uids = n;
302      if (opaque)          else {
303          *opaque = c;              for (t = ctx->uids; t->next; t=t->next)
304      return 0;                  ;
305  }              t->next = n;          
306            }
307        }
308    }
309  #define has_keyid_len(pattern) (\  
310      strlen (pattern) == 8  || strlen (pattern) == 10 || \  
311      strlen (pattern) == 16 || strlen (pattern) == 18)  /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
312    static void
313    keycache_decode_uids (gpg_keycache_t ctx)
314  gpgme_error_t  {
315  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,      struct keycache_s *c;
316                          gpgme_key_t *r_key, struct keycache_s **r_item)  
317  {      for (c = ctx->item; c; c = c->next)
318      struct keycache_s *c;          keycache_decode_uid (c);
319      gpgme_subkey_t s;  }
320      gpgme_user_id_t u;  
321      gpgme_key_t key;  
322      const char *kid;  static void
323        free_native_uids (struct native_uid_s **r_n)
324      if (!ctx || !r_key)  {
325          return gpg_error (GPG_ERR_INV_ARG);      struct native_uid_s *t;
326            struct native_uid_s *n = *r_n;
327      if (strstr (pattern, "0x"))  
328          pattern += 2;      while (n != NULL) {
329            t = n->next;
330      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4          if (n->malloced) {
331         fingerprints into the 64-bit keyid. */              free_if_alloc (n->uid);
332      if (strlen (pattern) == 40 && isxdigit (*pattern))              free_if_alloc (n->name);
333          pattern += 32;              free_if_alloc (n->comment);
334                free_if_alloc (n->email);
335      /* XXX: this code is very slow, revamp it and use hash tables whenever          }
336              it is possible. */          free_if_alloc (n);
337      for (c = ctx->item; c; c = c->next) {          n = t;
338          key = c->key;      }
339          assert (key->_refs >= 1);      *r_n = NULL;
340          for (s = key->subkeys; s; s = s->next) {  }
341              for (u = key->uids; u; u = u->next) {  
342                  if (u->name && stristr (u->name, pattern)) {  
343                      if (r_item)  
344                          *r_item = c;  /* Merge the information from the keyrings into the key cache structure. */
345                      *r_key = flags? c->pubpart->key : c->key;  static gpgme_error_t
346                      return 0;  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
347                  }                     const char *pubring, const char *secring)
348              }  {
349              if (has_keyid_len (pattern))      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
350                  kid = s->keyid;      gpgme_key_t key = NULL;
351              else      gpg_iobuf_t inp;
352                  kid = s->fpr;      PACKET *pkt;
353              if (kid && stristr (kid, pattern)) {      struct keycache_s *c;
354                  if (r_item)      const BYTE *sym_prefs;
355                      *r_item = c;      char keyid[16+1];
356                  *r_key = flags? c->pubpart->key : c->key;      int key_seen = 0;
357                  return 0;      size_t nsym =0;
358              }  
359          }      if (secring) {
360      }          parse_secring (ctx, kid, secring);
361      *r_key = NULL;          if (!pubring)
362      return gpg_error (GPG_ERR_INTERNAL);              return 0;
363  } /* keycache_find_key */      }
364        inp = gpg_iobuf_open (pubring);
365        if (!inp)
366  gpgme_error_t          return gpg_error (GPG_ERR_KEYRING_OPEN);
367  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
368                         int flags, gpgme_key_t *r_key)  
369  {      pkt = (PACKET*)calloc (1, sizeof * pkt);
370      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);      if (!pkt)
371  }          BUG (0);
372        gpg_init_packet (pkt);
373        while (gpg_parse_packet (inp, pkt) != -1) {
374  gpgme_error_t          if (pkt->pkttype == PKT_PUBLIC_KEY) {
375  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,              strcpy (keyid, "");
376                           void *opaque, const char *keyid)              key_seen = 1;
377  {          }
378      struct keycache_s *c = NULL, *c_new=NULL;          if (pkt->pkttype == PKT_SIGNATURE &&
379      gpgme_key_t key=NULL, fndkey=NULL;              pkt->pkt.signature->sig_class == 0x1F) {
380      gpgme_error_t err;              if (pkt->pkt.signature->numrevkeys == 0)
381      gpgme_ctx_t gctx;                  goto next;
382      gpg_keycache_t pub = (gpg_keycache_t)opaque;              _snprintf (keyid, sizeof (keyid) -1, "%08X",
383                            pkt->pkt.signature->keyid[1]);
384      err = gpgme_new (&gctx);              if (kid && strcmp (kid, keyid) != 0)
385      if (err)                  goto next;
386          return err;              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
387      err = gpgme_get_key (gctx, keyid, &key, is_sec);              if (err)
388      gpgme_release (gctx);                  goto next;
389      if (err)              c->gloflags.has_desig_rev = 1;
390          return err;          }
391      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 && c != NULL) {
392      if (!err && c != NULL) {              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
393          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);                                                SIGSUBPKT_PREF_SYM, &nsym);
394          gpgme_key_release (fndkey);              if (!sym_prefs)
395          c->key = key;                  goto next;
396          c->flags = 0;              _snprintf (keyid, sizeof (keyid) - 1, "%08X",
397          if (is_sec && pub != NULL &&                          pkt->pkt.signature->keyid[1]);
398              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {              if (kid && strcmp (kid, keyid) != 0)
399              log_debug ("keycache update: set public part %p\r\n", fndkey);                  goto next;
400              c->pubpart->key = fndkey;              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
401          }              if (err || !c)
402      }                  goto next;
403      else {              if (c->sym_prefs) // only use the prefs from the primary uid.
404          log_debug ("keycache add: sync public part\r\n");                  goto next;
405          if (is_sec)              else if (nsym > 0) {
406              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);                  c->sym_prefs = safe_uchar_alloc (nsym+1);
407          gpg_keycache_add_key (ctx, key, (void **)&c);                  memset (c->sym_prefs, 0, nsym+1);
408          if (c != NULL && is_sec) {                  memcpy (c->sym_prefs, sym_prefs, nsym);
409              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);              }
410              c->pubpart = c_new;          }
411              if (c_new != NULL) {  next:
412                  c->pubpart->key = fndkey;          gpg_free_packet (pkt);
413                  c->gloflags.is_protected = c_new->gloflags.is_protected;          gpg_init_packet(pkt);
414                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;      }
415              }  
416          }      safe_free (pkt);
417      }      gpg_iobuf_close (inp);
418      return 0;      return err;
419  }  }
420    
421    
422  /* Delete a key from the cache @ctx with the pattern @pattern.  gpgme_error_t
423     Return value: 0 on success. */  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
424  gpgme_error_t  {
425  gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)      return keycache_prepare2 (ctx, NULL, pubr, secr);
426  {  }
427      struct keycache_s *itm = NULL, *c;  
428      gpgme_key_t key;  gpgme_error_t
429      gpgme_error_t rc;  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
430                                   const char *pubr, const char *secr)
431      if (!ctx)  {
432          return gpg_error (GPG_ERR_INV_ARG);      if (!strncmp (keyid, "0x", 2))
433      rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);          keyid += 2;  
434      if (rc)      return keycache_prepare2 (ctx, keyid, pubr, secr);
435          return rc;  }
436        
437      c = ctx->item;  
438      if (c->next == NULL) {  /* Create new keycache object and return it in @r_ctx.
439          gpgme_key_release (itm->key);     Return value: 0 on success. */
440          if (itm)  gpgme_error_t
441              free (itm);  gpg_keycache_new (gpg_keycache_t *r_ctx)
442          ctx->item = NULL;  {
443      }      gpg_keycache_t ctx;
444      else {      
445          while (c && c->next != itm)      if (!r_ctx)
446              c = c->next;          return gpg_error (GPG_ERR_INV_ARG);
447          c->next = c->next->next;      ctx = new gpg_keycache_s;    
448          gpgme_key_release (itm->key);      if (!ctx)
449          if (itm)          BUG (0);
450              free (itm);      memset (ctx, 0, sizeof *ctx);
451      }      ctx->secret = 0;
452      return 0;      ctx->pos = 0;
453  }      *r_ctx = ctx;
454        return 0;
455    }
456  /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring  
457     will be added to the cache. @secret is 1 if the source is the secret keyring.  
458     Return value: 0 on success. */  void
459  gpgme_error_t  gpg_keycache_item_release (struct keycache_s *c)
460  gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)  {
461  {      if (c->key)
462      gpgme_error_t err;          gpgme_key_release (c->key);    
463      gpgme_ctx_t c;      c->key = NULL;      
464      gpgme_key_t key;      if (c->rev != NULL)    
465      int count = 0;          gpg_desig_rev_release (c->rev);
466            c->rev = NULL;
467      if (!ctx)      free_if_alloc (c->pref_keyserver);
468          return gpg_error (GPG_ERR_INV_ARG);      free_if_alloc (c->sym_prefs);
469            free_if_alloc (c->attrib.d);
470      err = gpgme_new (&c);      free_if_alloc (c->card_type);
471      if (err)      free_native_uids (&c->uids);
472          return err;      free_if_alloc (c);
473    }
474      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);  
475      err = gpgme_op_keylist_start (c, pattern, secret);  
476      while(!err) {  /* Release keycache object @ctx. */
477          err = gpgme_op_keylist_next (c, &key);  void
478          if (!err)  gpg_keycache_release (gpg_keycache_t ctx)
479              err = gpg_keycache_add_key (ctx, key, NULL);  {
480          if (ctx->cb)      struct keycache_s *c, *c2;
481              ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,      
482                       count++, ctx->cb_value2);      if (!ctx)
483      }          return;
484      if (gpgme_err_code (err) == GPG_ERR_EOF)  
485          err = gpg_error (GPG_ERR_NO_ERROR);      for (c = ctx->item; c; c = c2) {
486      /* XXX: make sure the progress dialog is closed. */          c2 = c->next;
487      gpgme_op_keylist_end (c);          gpg_keycache_item_release (c);
488      gpgme_release (c);      }
489      return err;      free_if_alloc (ctx);
490  }  }
491    
492    
493  /* XXX: kludge to see if the key is stored on a card. */  /* Set (progress) callback for the given keycache object.
494  static int     @ctx the keycache
495  key_divert_to_card (gpgme_key_t key)     @cb  the callback function
496  {     @cb_value1 opaque value which is passed to the callback.
497      gpgme_subkey_t k;     @cb_value2 see @cb_value1. */
498      int n=0, n_alg=0, can_auth = 0;  void
499    gpg_keycache_set_cb (gpg_keycache_t ctx,
500      for (k = key->subkeys; k; k = k->next) {                       void (*cb)(void *, const char *, int, int, int),
501          n++;                       void * cb_value1, int cb_value2)
502          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)  {
503              n_alg++;      if (!ctx)
504          if (k->can_authenticate)          return;
505              can_auth++;      ctx->cb = cb;
506      }      ctx->cb_value = cb_value1;
507      if (n == 3 && n_alg == 3 && can_auth == 1)      ctx->cb_value2 = cb_value2;
508          return 1;  }
509      return 0;  
510  }  
511    /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
512       Return value: 0 on success. */
513  gpgme_error_t  gpgme_error_t
514  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
515  {  {
516      struct keycache_s *c, *c_sec;      struct keycache_s *c, *n1;
517      gpgme_key_t key;      
518        if (!ctx)
519      if (!pub || !sec)          return gpg_error (GPG_ERR_INV_ARG);
520          return gpg_error (GPG_ERR_INV_ARG);      
521            c = new keycache_s;
522      for (c=sec->item; c; c=c->next) {        if (!c)
523          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {          BUG (0);
524              c_sec->gloflags.is_protected = c->gloflags.is_protected;      memset (c, 0, sizeof *c);
525              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;      c->gloflags.is_protected = 1; /*default: assume protection. */
526              if (!c->gloflags.divert_to_card)      c->key = key;
527                  c->gloflags.divert_to_card = key_divert_to_card (key);      if (!ctx->item)
528              c->pubpart = c_sec;          ctx->item = c;
529              c->pubpart->key = key;      else {
530          }          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
531      }              ;
532      return 0;          n1->next = c;
533  }      }
534        if (opaque)
535            *opaque = c;
536  /* Rewind the given cache @ctx to the begin. */      return 0;
537  void  }
538  gpg_keycache_rewind (gpg_keycache_t ctx)  
539  {  
540      if (ctx)  
541          ctx->pos = 0;  #define has_keyid_len(pattern) (\
542  }      strlen (pattern) == 8  || strlen (pattern) == 10 || \
543        strlen (pattern) == 16 || strlen (pattern) == 18)
544    
545    
546  /* Return the number of elements in the cache @ctx. */  gpgme_error_t
547  int  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
548  gpg_keycache_get_size (gpg_keycache_t ctx)                          gpgme_key_t *r_key, struct keycache_s **r_item)
549  {  {
550      struct keycache_s *c;      struct keycache_s *c;
551      int count = 0;      gpgme_subkey_t s;
552            gpgme_user_id_t u;
553      if (!ctx)      gpgme_key_t key;
554          return 0;      const char *kid;
555      for (c = ctx->item; c; c = c->next)      
556          count++;      if (!ctx || !r_key)
557      return count;          return gpg_error (GPG_ERR_INV_ARG);
558  }      
559        if (strstr (pattern, "0x"))
560            pattern += 2;
561  static gpgme_error_t  
562  keycache_next_key (gpg_keycache_t ctx, int flags,      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
563                     struct keycache_s **c, gpgme_key_t *r_key)         fingerprints into the 64-bit keyid. */
564  {            if (strlen (pattern) == 40 && isxdigit (*pattern))
565      if (!ctx || !r_key)          pattern += 32;
566          return gpg_error (GPG_ERR_INV_ARG);  
567        /* XXX: this code is very slow, revamp it and use hash tables whenever
568      if (!ctx->pos)              it is possible. */
569          ctx->tmp = ctx->item;      for (c = ctx->item; c; c = c->next) {
570                key = c->key;
571      if (!ctx->tmp || !ctx->tmp->key) {          assert (key->_refs >= 1);
572          ctx->pos = 0;          for (s = key->subkeys; s; s = s->next) {
573          *r_key = NULL;              for (u = key->uids; u; u = u->next) {
574          return gpg_error (GPG_ERR_EOF);                  if (u->name && stristr (u->name, pattern)) {
575      }                      if (r_item)
576                                *r_item = c;
577      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;                      *r_key = flags? c->pubpart->key : c->key;
578      *c = ctx->tmp = ctx->tmp->next;                      return 0;
579      ctx->pos++;                  }
580                }
581      return 0;              if (has_keyid_len (pattern))
582  }                  kid = s->keyid;
583                else
584                    kid = s->fpr;
585  /* Return the next key from the cache @ctx. The key will be returned              if (kid && stristr (kid, pattern)) {
586     in @r_key. @flags can contain additional flags.                  if (r_item)
587     Return value: 0 on success. */                      *r_item = c;
588  gpgme_error_t                  *r_key = flags? c->pubpart->key : c->key;
589  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)                  return 0;
590  {              }
591      struct keycache_s *c=NULL;          }
592      gpgme_error_t err = 0;      }
593        *r_key = NULL;
594      err = keycache_next_key (ctx, flags, &c, r_key);      return gpg_error (GPG_ERR_INTERNAL);
595      return err;  }
596  }  
597    
598    gpgme_error_t
599    gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
600                           int flags, gpgme_key_t *r_key)
601    {
602        return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
603    }
604    
605    
606    /* Reload a photo image of a single key with the keyid @keyid.
607       Return value: 0 on success. */
608    static gpgme_error_t
609    keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
610    {
611        attr_list_t list;
612    
613        if (parse_attr_data (keyid, &list) < 1) {
614            free_attr_list (list);
615            return 0;
616        }
617        keycache_update_photo (ctx, list->fpr, list);
618        free_attr_list (list);
619        return 0;
620    }
621    
622    
623    /* Return the next key which was updated. Before it is
624       returned the update flag is cleared.
625       @r_status is 1 for a new key and 2 for an updated key.
626       Return value: 0 on success. */
627    gpgme_error_t
628    gpg_keycache_next_updated_key (gpg_keycache_t ctx,
629                                   struct keycache_s **r_obj,
630                                   int *r_status)
631    {
632        struct keycache_s *c;
633    
634        for (c = ctx->item; c; c = c->next) {
635            if (c->flags != 0) {
636                *r_status = c->flags;
637                *r_obj = c;
638                c->flags = 0; /* reset update flag. */
639                return 0;
640            }
641        }
642        return gpg_error (GPG_ERR_NOT_FOUND);
643    }
644    
645    
646    /* Helper to retrieve a GPG key. */
647    static gpgme_error_t
648    get_gpg_key (const char *keyid, int is_sec, gpgme_key_t *r_key)
649    {
650        gpgme_ctx_t ctx;
651        gpgme_error_t err;
652    
653        err = gpgme_new (&ctx);
654        if (err)
655            return err;
656        gpgme_set_keylist_mode  (ctx, GPGME_KEYLIST_MODE_SIGS);
657        err = gpgme_get_key (ctx, keyid, r_key, is_sec);
658        gpgme_release (ctx);
659        return err;
660    }
661    
662    
663    /* Fetch a key directly from gpg but without adding
664       it to the key cache. Caller must free @r_ctx. */
665    gpgme_error_t
666    gpg_keycache_fetch_key (const char *keyid, int is_sec,
667                            gpgme_key_t *r_key, struct keycache_s **r_c)
668    {
669        gpgme_error_t err;
670        gpgme_key_t key;
671        struct keycache_s *c;
672    
673        *r_key = NULL;
674        *r_c = NULL;
675        err = get_gpg_key (keyid, is_sec, &key);
676        if (err)
677            return err;
678    
679        c = new keycache_s;
680        if (!c)
681            BUG (0);
682        memset (c, 0, sizeof *c);
683        c->gloflags.is_protected = 1; /*default: assume protection. */
684        c->key = key;    
685        keycache_decode_uid (c);
686        *r_key = key;
687        *r_c = c;
688        return 0;
689    }
690    
691    
692    /* Update the key with the keyid @key in the key cache.
693       If the key does not exist, it is added otherwise all
694       parts are first freed and then replaced with the updated data. */
695    gpgme_error_t
696    gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
697                             void *opaque, const char *keyid)
698    {    
699        gpgme_key_t key=NULL, fndkey=NULL;
700        gpgme_error_t err;
701        struct keycache_s *c = NULL, *c_new=NULL;
702        gpg_keycache_t pub = (gpg_keycache_t)opaque;
703    
704        err = get_gpg_key (keyid, is_sec, &key);
705        if (err)
706            return err;
707        err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
708        if (!err && c != NULL) {
709            log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
710            gpgme_key_release (fndkey);
711            c->key = key;
712            c->flags = KC_FLAG_UPD;
713            if (is_sec && pub != NULL &&
714                !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
715                log_debug ("keycache update: set public part %p\r\n", fndkey);
716                c->pubpart->key = fndkey;
717            }
718            /* XXX: this is also called for keys without a photo-id. */
719            keycache_reload_photo (ctx, keyid);
720        }
721        else {
722            log_debug ("keycache add: sync public part\r\n");
723            if (is_sec)
724                gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
725            gpg_keycache_add_key (ctx, key, (void **)&c);
726            if (c != NULL && is_sec) {
727                log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
728                c->pubpart = c_new;
729                if (c_new != NULL) {
730                    c->pubpart->key = fndkey;
731                    c->gloflags.is_protected = c_new->gloflags.is_protected;
732                    c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
733                }
734            }
735            if (c != NULL)
736                c->flags = KC_FLAG_ADD;
737        }
738    
739        /* refresh utf8 user ID list. */
740        if (c != NULL && c->key) {
741            free_native_uids (&c->uids);
742            keycache_decode_uid (c);
743        }
744    
745        return 0;
746    }
747    
748    
749    /* Delete a key from the cache @ctx with the pattern @pattern.
750       Return value: 0 on success. */
751    gpgme_error_t
752    gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
753    {
754        struct keycache_s *itm = NULL, *c;
755        gpgme_key_t key;
756        gpgme_error_t rc;
757    
758        if (!ctx)
759            return gpg_error (GPG_ERR_INV_ARG);
760        rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
761        if (rc)
762            return rc;
763        
764        c = ctx->item;
765        if (!c) /* empty */
766            return 0;
767        else if (c->next == NULL) {
768            if (itm->key)
769                gpgme_key_release (itm->key);
770            itm->key = NULL;
771            free_if_alloc (itm);
772            /* the cache has no other items, so we set the context to NULL
773               to indicate that the entire cache is empty. */
774            ctx->item = NULL;
775        }
776        else {
777            for (; c != NULL; c = c->next) {
778                if (c->next == itm)
779                    break;
780            }
781            assert (c != NULL); /* XXX: sometimes access violation. */
782            c->next = c->next->next;
783            if (itm->key)
784                gpgme_key_release (itm->key);
785            itm->key = NULL;
786            free_if_alloc (itm);
787        }
788        return 0;
789    }
790    
791    
792    /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
793       will be added to the cache. @secret is 1 if the source is the secret keyring.
794       Return value: 0 on success. */
795    gpgme_error_t
796    gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
797    {
798        gpgme_error_t err;
799        gpgme_ctx_t c;
800        gpgme_key_t key;
801        int count = 0;
802        
803        if (!ctx)
804            return gpg_error (GPG_ERR_INV_ARG);
805        
806        err = gpgme_new (&c);
807        if (err)
808            return err;
809    
810        /* XXX: GPGME_KEYLIST_MODE_SIG_NOTATIONS causes an internal error! */
811        gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
812        err = gpgme_op_keylist_start (c, pattern, secret);
813        while(!err) {
814            err = gpgme_op_keylist_next (c, &key);
815            if (!err)
816                err = gpg_keycache_add_key (ctx, key, NULL);
817            if (ctx->cb)
818                ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
819                         count++, ctx->cb_value2);
820        }
821        if (gpgme_err_code (err) == GPG_ERR_EOF)
822            err = gpg_error (GPG_ERR_NO_ERROR);
823        keycache_update_photos (ctx);
824        keycache_decode_uids (ctx);
825        gpgme_op_keylist_end (c);
826        gpgme_release (c);
827        return err;
828    }
829    
830    
831    /* Return 1 if we can assume that the actual private key is
832       stored on a smart card. This is not bullet proof, but the
833       card provides 3 keys (RSA) and each key for a different purpose. */
834    static int
835    key_divert_to_card (gpgme_key_t key)
836    {
837        gpgme_subkey_t k;
838        int n=0;
839        int can_auth = 0, can_encr = 0;
840    
841        for (k = key->subkeys; k; k = k->next) {
842            n++;
843            if (k->pubkey_algo != GPGME_PK_RSA || k->length != 1024) {
844                return 0;
845                break;
846            }
847            if (k->can_authenticate)
848                can_auth++;
849            if (k->can_encrypt)
850                can_encr++;
851        }
852        if (n >= 3 && can_auth >= 1 && can_encr >= 1)
853            return 1;
854        return 0;
855    }
856    
857    
858    static unsigned char*
859    copy_uid_prefs (const unsigned char *prefs)
860    {
861        unsigned char *p;
862        size_t pos=0;
863    
864        while (prefs[pos] != 0)
865            pos++;
866        p = safe_uchar_alloc (pos+1);
867        memset (p, 0, pos+1);
868        memcpy (p, prefs, pos);
869        return p;
870    }
871    
872    
873    /* Sync the secret and the public key cache information. */
874    gpgme_error_t
875    gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
876    {
877        struct keycache_s *c, *c_sec;
878        gpgme_key_t key;
879    
880        if (!pub || !sec)
881            return gpg_error (GPG_ERR_INV_ARG);
882        
883        for (c=sec->item; c; c=c->next) {
884            if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0,
885                                         &key, &c_sec)) {
886                c_sec->gloflags.is_protected = c->gloflags.is_protected;
887                c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
888                if (!c->gloflags.divert_to_card)
889                    c->gloflags.divert_to_card = key_divert_to_card (key);
890                if (c_sec->sym_prefs)
891                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
892                c->pubpart = c_sec;
893                c->pubpart->key = key;
894            }
895        }
896        return 0;
897    }
898    
899    
900    /* Rewind the given cache @ctx to the begin. */
901    void
902    gpg_keycache_rewind (gpg_keycache_t ctx)
903    {
904        if (ctx)
905            ctx->pos = 0;
906    }
907    
908    
909    
910    /* Return the number of elements in the cache @ctx. */
911    int
912    gpg_keycache_get_size (gpg_keycache_t ctx)
913    {
914        struct keycache_s *c;
915        int count = 0;
916        
917        if (!ctx)
918            return 0;
919        for (c = ctx->item; c; c = c->next)
920            count++;
921        return count;
922    }
923    
924    
925    static gpgme_error_t
926    keycache_next_key (gpg_keycache_t ctx, int flags,
927                       struct keycache_s **c, gpgme_key_t *r_key)
928    {      
929        if (!ctx || !r_key)
930            return gpg_error (GPG_ERR_INV_ARG);
931    
932        if (!ctx->pos)
933            ctx->tmp = ctx->item;
934        
935        if (!ctx->tmp || !ctx->tmp->key) {
936            ctx->pos = 0;
937            *r_key = NULL;
938            return gpg_error (GPG_ERR_EOF);
939        }
940        if (ctx->tmp->flags != 0)
941            ctx->tmp->flags = 0; /* reset the 'updated' status. */
942    
943        /* it might be possible there is no public key. */
944        if (flags && ctx->tmp->pubpart == NULL)
945            flags = 0;
946        *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
947        *c = ctx->tmp;
948        ctx->tmp = ctx->tmp->next;
949        ctx->pos++;
950    
951        return 0;
952    }
953    
954    
955    /* Return the next key from the cache @ctx. The key will be returned
956       in @r_key. @flags can contain additional flags.
957       Return value: 0 on success. */
958    gpgme_error_t
959    gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
960    {
961        struct keycache_s *c=NULL;
962        gpgme_error_t err;
963    
964        err = keycache_next_key (ctx, flags, &c, r_key);
965        return err;
966    }
967    
968    
969    gpgme_error_t
970    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
971                            struct keycache_s **c, gpgme_key_t *r_key)
972    {
973        return keycache_next_key (ctx, flags, c, r_key);
974    }
975    
976    
977    /* Search for a key with the pattern @pattern and mark
978       this key as the default signing key if found.
979       Return value: 0 on success. */
980    gpgme_error_t
981    gpg_keycache_set_default_key (gpg_keycache_t ctx,
982                                  const char *pattern)
983    {
984        gpgme_error_t err;
985        gpgme_key_t key;
986        struct keycache_s *itm;
987    
988        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
989        if (err)
990            return err;
991    
992        if (itm)
993            itm->default_key = 1;
994        return 0;
995    }
996    
997    /* Return the default key from the cache. If no was
998       marked before, NULL is returned in @r_key.
999       Return value: 0 on success. */
1000    gpgme_error_t
1001    gpg_keycache_get_default_key (gpg_keycache_t ctx,
1002                                  gpgme_key_t *r_key)
1003    {
1004        struct keycache_s *itm;
1005    
1006        *r_key = NULL;
1007        for (itm = ctx->item; itm; itm = itm->next) {
1008            if (itm->default_key) {
1009                *r_key = itm->key;
1010                break;
1011            }
1012        }
1013        if (!*r_key)
1014            return gpgme_error (GPG_ERR_NOT_FOUND);
1015        return 0;
1016    }
1017    
1018    
1019    static gpgme_error_t
1020    decode_subpacket (const char *subpkt_data, int *type,
1021                      char **out, WORD *outlen)
1022    {
1023        char tmp[128], *val;
1024        char *enc = NULL;      
1025        size_t pos = 0;
1026    
1027        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
1028        *outlen = 0;
1029        *out = NULL;
1030        
1031        if (strncmp (subpkt_data, "spk:", 4))
1032            return gpg_error (GPG_ERR_NO_DATA);
1033    
1034        /* XXX: do not use static buffer sizes. */
1035        strncpy (tmp, subpkt_data, DIM (tmp)-4);
1036        val = strtok (tmp, ":");
1037        while (val != NULL) {
1038            switch (pos++) {
1039            case 0:
1040                break;
1041    
1042            case 1:
1043                if (type)
1044                    *type = atoi (val);
1045                break;
1046    
1047            case 2:
1048                break;
1049    
1050            case 3:
1051                *outlen = atoi (val);
1052                break;
1053    
1054            case 4:
1055                enc = m_strdup (val);
1056                break;
1057            }
1058            val = strtok (NULL, ":");
1059        }
1060        if (!enc)
1061            return gpg_error (GPG_ERR_NO_DATA);
1062        unhexify_buffer (enc, out);
1063        free_if_alloc (enc);
1064        return 0;
1065    }
1066    
1067    
1068    /* If the attribute given in @attr is not set in the
1069       key cache object, try to update it. */
1070    gpgme_error_t
1071    gpg_keycache_update_attr (struct keycache_s *item,
1072                              int attr, int force)
1073    {
1074        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
1075        char *val = NULL;
1076        WORD n = 0;    
1077    
1078        switch (attr) {
1079        case KC_ATTR_PREFSYM:
1080            if (!force && item->sym_prefs)
1081                break;
1082            free_if_alloc (item->sym_prefs);
1083            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1084            if (!err && val != NULL)
1085                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
1086            break;
1087    
1088        case KC_ATTR_PREFKSERV:
1089            if (!force && item->pref_keyserver)
1090                break;
1091            free_if_alloc (item->pref_keyserver);
1092            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1093            if (!err && val != NULL)
1094                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1095            if (!err && item->pref_keyserver)
1096                err = parse_keyserver_url (&item->pref_keyserver,
1097                                           &item->pref_keyserver_port);
1098            break;
1099        }
1100        safe_free (val);
1101        return err;
1102    }

Legend:
Removed from v.32  
changed lines
  Added in v.260

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26