/[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 28 by twoaday, Thu Oct 20 12:35:59 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 "openpgp.h"  #include <ctype.h>
29  #include "wptNLS.h"  #include <assert.h>
30  #include "wptErrors.h"  #include <gpgme.h>
31    
32    #include "wptKeyCache.h"
33  /* convert a binary buffer into its hex representation. */  #include "openpgp.h"
34  static void  #include "wptNLS.h"
35  buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)  #include "wptErrors.h"
36  {  #include "wptW32API.h"
37      char dig[3];  #include "wptGPG.h"
38      size_t i;  #include "wptTypes.h"
39    #include "wptCommonCtl.h"
40      memset (dst, 0, dlen);  #include "wptContext.h"
41      for (i = 0; i < nbytes && dlen > 0; i++) {  #include "wptKeyEdit.h"
42          sprintf (dig, "%02X", buf[i]);  #include "wptUTF8.h"
43          strcat (dst, dig);  
44          dlen -= 2;  
45      }  gpgme_error_t parse_keyserver_url (char **r_keyserver, unsigned short *r_port);
46  }  
47    /* Attribute list which holds the image data. */
48    struct attr_list_s {
49  /* Parse the secret keyring and retrieve some additional information      struct attr_list_s *next;
50     for each key which was found. */      char *fpr;                   /* fingerprint of the key */
51  static void      unsigned char *d;            /* actual JPEG data. */
52  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)      unsigned long octets;        /* length of the data. */
53  {          unsigned int flags;          /* status of the attribute. */
54      PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);  };
55      PKT_secret_key *sk;  typedef struct attr_list_s *attr_list_t;
56      gpg_iobuf_t inp;  
57      gpgme_error_t err;  
58      gpgme_key_t key;  /* XXX: convert it to an inline function and place it in a header file. */
59      struct keycache_s *c=NULL;  static unsigned char*
60      char keyid[16+1];  safe_uchar_alloc (size_t n)
61    {
62      inp = gpg_iobuf_open (secring);      unsigned char *p = new unsigned char[n];
63      if (!inp) {      if (!p)
64          safe_free (pkt);          BUG (0);
65          return;      return p;
66      }  }
67      gpg_iobuf_ioctl (inp, 3, 1, NULL);  
68      gpg_init_packet (pkt);  
69      while (gpg_parse_packet (inp, pkt) != -1) {  /* Free attribute list @ctx. */
70          if (pkt->pkttype == PKT_SECRET_KEY) {  void
71              sk = pkt->pkt.secret_key;  free_attr_list (attr_list_t ctx)
72              /* XXX: key IDs of card public keys are wrong! */  {
73              _snprintf (keyid, sizeof (keyid)-1, "%08lX",      attr_list_t n;
74                         gpg_keyid_from_sk (sk, NULL));  
75              if (kid && strcmp (kid, keyid) != 0)      while (ctx) {
76                  goto next;          n = ctx->next;
77              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);          free_if_alloc (ctx->fpr);
78              if (err)          free_if_alloc (ctx->d);
79                  goto next;          free_if_alloc (ctx);
80              c->gloflags.is_protected = sk->is_protected;          ctx = n;
81              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;      }
82              if (c->pubpart != NULL) {      }
83                  c->pubpart->gloflags.is_protected = sk->is_protected;              
84                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;  /* Parse the attribute list in @fp and store it into @ctx.
85              }     Return value: number of parsed items. */
86          }  int
87  next:  parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
88          gpg_free_packet (pkt);  {
89          gpg_init_packet (pkt);      attr_list_t c, t;
90      }      char buf[512], *p, *buffer;
91      safe_free (pkt);      int pos, n=0;
92      gpg_iobuf_close (inp);      
93  }      *ctx = NULL;
94        while (fgets (buf, 511, fp)) {
95            if (strstr (buf, "\r\n"))
96  /* Merge the information from the keyrings into the key cache structure. */              buf[strlen (buf)-2]=0;
97  gpgme_error_t          if (strstr (buf, "\n"))
98  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,              buf[strlen (buf)-1]=0;
99                     const char *pubring, const char *secring)          if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
100  {              continue;
101      gpgme_error_t err;          buffer = buf+9+10;
102      gpgme_key_t key = NULL;          pos = 0;
103      gpg_iobuf_t inp;          c = new attr_list_s;
104      PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);          if (!c)
105      struct keycache_s *c;              BUG (0);
106      const byte *sym_prefs;          memset (c, 0, sizeof *c);
107      char keyid[16+1], *id = NULL;  
108      int key_seen = 0;          p = strtok (buffer, " ");
109      size_t nbytes = 0, nsym =0;          while (p != NULL) {
110                switch (pos) {
111      if (secring) {              case 0:
112          parse_secring (ctx, kid, secring);                  c->fpr = m_strdup (p);
113          if (!pubring) {                  break;
114              safe_free(pkt);                  
115              return 0;              case 1:
116          }                  c->octets = strtoul (p, NULL, 10);
117      }                  break;
118      inp = gpg_iobuf_open (pubring);                  
119      if (!inp) {              case 7:
120          safe_free( pkt );                  c->flags = strtoul (p, NULL, 10);
121          return gpg_error (GPG_ERR_KEYRING_OPEN);                  break;
122      }                  
123      gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */              default:
124                    break;
125      gpg_init_packet( pkt );              }
126      while (gpg_parse_packet (inp, pkt) != -1) {              pos++;
127          if (pkt->pkttype == PKT_PUBLIC_KEY) {              p = strtok (NULL, " ");
128              strcpy (keyid, "");          }
129              key_seen = 1;          if (!*ctx)
130          }              *ctx = c;
131            else {
132          if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {              for (t = *ctx; t->next; t=t->next)
133              if (pkt->pkt.signature->numrevkeys == 0)                  ;
134                  goto next;              t->next = c;
135              _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);          }
136              if (kid && strcmp (kid, keyid) != 0)          c->d = safe_uchar_alloc (c->octets);
137                  goto next;          memcpy (c->d, data, c->octets);
138              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);          data += c->octets;
139              if (err)          datlen -= c->octets;
140                  goto next;          n++;
141              c->gloflags.has_desig_rev = 1;      }
142          }      /*assert (datlen == 0); */
143          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {      return n;
144              sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,  }
145                                              SIGSUBPKT_PREF_SYM, &nsym);  
146              if (sym_prefs == NULL)  
147                  goto next;  static int
148              _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);  parse_attr_data (const char *keyid, attr_list_t *list)
149              if (kid && strcmp (kid, keyid) != 0)  {
150                  goto next;      gpgme_error_t err;
151              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);      FILE *tmp;    
152              if (err)      BYTE *data;
153                  goto next;      char *status, tmpnam[MAX_PATH+1];
154              else if (nsym > 0) {      DWORD ndata = 0;
155                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);  
156                  if (!c->sym_prefs)      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
157                      return gpg_error (GPG_ERR_ENOMEM);      if (err)
158                  memcpy (c->sym_prefs, sym_prefs, nsym);          return err;
159              }  
160          }      get_temp_name (tmpnam, MAX_PATH, NULL);
161          if (pkt->pkttype == PKT_USER_ID) {      tmp = fopen (tmpnam, "w+b");
162              if (id)      if (ndata > 0 && tmp != NULL) {
163                  free (id);          fwrite (status, 1, strlen (status), tmp);
164              id = strdup (pkt->pkt.user_id->name);          fflush (tmp);
165              if (!id) {          rewind (tmp);
166                  err = gpg_error (GPG_ERR_ENOMEM);  
167                  goto fail;          ndata = parse_attr_list (tmp, data, ndata, list);
168              }          fclose (tmp);
169          }          DeleteFile (tmpnam);
170          if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)      }
171              && pkt->pkt.user_id->attrib_data && key) {      else
172              PKT_user_id *id = pkt->pkt.user_id;          *list = NULL;
173              c->attrib.used = 1;  
174              c->attrib.len = id->attrib_len;      safe_free (status);
175              c->attrib.d = (unsigned char*)calloc (1, id->attrib_len + 1);      safe_free (data);
176              if (!c->attrib.d) {      return ndata;
177                  err = gpg_error (GPG_ERR_ENOMEM);  }
178                  goto fail;  
179              }  
180              memcpy (c->attrib.d, id->attrib_data, id->attrib_len);  /* Parse the secret keyring and retrieve some additional information
181              key = NULL;     for each key which was found. */
182              c = NULL;  static void
183          }  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
184  next:  {    
185          gpg_free_packet (pkt);      PACKET *pkt;
186          gpg_init_packet(pkt);      PKT_secret_key *sk;
187      }      gpg_iobuf_t inp;
188        gpgme_error_t err;
189  fail:      gpgme_key_t key;
190      safe_free (id);      struct keycache_s *c=NULL;
191      safe_free (pkt);      char keyid[16+1];
192      gpg_iobuf_close (inp);  
193      return err;      inp = gpg_iobuf_open (secring);
194  }      if (!inp)
195            return;
196    
197  gpgme_error_t      gpg_iobuf_ioctl (inp, 3, 1, NULL);
198  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)      pkt = (PACKET*)calloc (1, sizeof *pkt);
199  {      if (!pkt)
200      return keycache_prepare2 (ctx, NULL, pubr, secr);          BUG (0);
201  }      gpg_init_packet (pkt);
202        while (gpg_parse_packet (inp, pkt) != -1) {
203  gpgme_error_t          if (pkt->pkttype == PKT_SECRET_KEY) {
204  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,              sk = pkt->pkt.secret_key;
205                                 const char *pubr, const char *secr)              /* XXX: key IDs of card public keys are wrong! */
206  {              _snprintf (keyid, sizeof (keyid)-1, "%08lX",
207      if (!strncmp (keyid, "0x", 2))                         gpg_keyid_from_sk (sk, NULL));
208          keyid += 2;                if (kid && strcmp (kid, keyid) != 0)
209      return keycache_prepare2 (ctx, keyid, pubr, secr);                  goto next;
210  }              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
211                if (err)
212                    goto next;
213  /* Create new keycache object and return it in @r_ctx.              c->gloflags.is_protected = sk->is_protected;
214     Return value: 0 on success. */              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
215  gpgme_error_t              if (c->pubpart != NULL) {
216  gpg_keycache_new (gpg_keycache_t *r_ctx)                  c->pubpart->gloflags.is_protected = sk->is_protected;
217  {                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
218      gpg_keycache_t ctx;              }
219                }
220      if (!r_ctx)  next:
221          return gpg_error (GPG_ERR_INV_ARG);          gpg_free_packet (pkt);
222      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);          gpg_init_packet (pkt);
223      if (!ctx)      }
224          return gpg_error (GPG_ERR_ENOMEM);      safe_free (pkt);
225      ctx->secret = 0;      gpg_iobuf_close (inp);
226      ctx->pos = 0;  }
227      *r_ctx = ctx;  
228      return 0;  
229  }  /* Update the photo image of a single key with the fingerprint
230       @fpr. The @dat struct contains the new item data. */
231    static gpgme_error_t
232  /* Release keycache object @ctx. */  keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
233  void  {
234  gpg_keycache_release (gpg_keycache_t ctx)      struct keycache_s *fnd = NULL;
235  {      gpgme_key_t key;
236      struct keycache_s *c, *c2;      
237            gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
238      if (!ctx)      if (!fnd)
239          return;          return gpg_error (GPG_ERR_NOT_FOUND);
240        free_if_alloc (fnd->attrib.d);
241      for (c = ctx->item; c; c = c2) {      fnd->attrib.flags = dat->flags;
242          c2 = c->next;      fnd->attrib.len = dat->octets;
243          gpgme_key_release (c->key);      fnd->attrib.d = safe_uchar_alloc (dat->octets);
244          c->key = NULL;      memcpy (fnd->attrib.d, dat->d, dat->octets);
245          if (c->sym_prefs)      return 0;
246              free (c->sym_prefs);  }
247          c->sym_prefs = NULL;  
248          if (c->attrib.d)  
249              free (c->attrib.d);  /* Update all photo images in the cache. */
250          c->attrib.d = NULL;  static gpgme_error_t
251          if (c->card_type)  keycache_update_photos (gpg_keycache_t ctx)
252              free (c->card_type);  {
253          free (c);      attr_list_t list=NULL, n;
254      }      DWORD ndata;
255      if (ctx)  
256          free (ctx);      ndata = parse_attr_data (NULL, &list);
257  }      if (ndata < 1) {
258            free_attr_list (list);
259            return 0;
260  /* Set (progress) callback for the given keycache object.      }
261     @ctx the keycache  
262     @cb  the callback function      for (n=list; n; n=n->next)
263     @cb_value1 opaque value which is passed to the callback.          keycache_update_photo (ctx, n->fpr, n);
264     @cb_value2 see @cb_value1. */      free_attr_list (list);
265  void      return 0;
266  gpg_keycache_set_cb (gpg_keycache_t ctx,  }
267                       void (*cb)(void *, const char *, int, int, int),  
268                       void * cb_value1, int cb_value2)  
269  {  void
270      if (!ctx)  keycache_decode_uid (struct keycache_s *ctx)
271          return;  {
272      ctx->cb = cb;      gpgme_user_id_t u;
273      ctx->cb_value = cb_value1;      struct native_uid_s *n, *t;
274      ctx->cb_value2 = cb_value2;  
275  }      for (u = ctx->key->uids; u; u = u->next) {
276            n = new native_uid_s;
277            if (!n)
278  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.              BUG (0);
279     Return value: 0 on success. */          memset (n, 0, sizeof *n);
280  gpgme_error_t          if (is_8bit_string (u->uid)) {
281  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)              n->malloced = 1;
282  {              n->uid = utf8_to_native (u->uid);
283      struct keycache_s * c, * n1;              if (u->name != NULL)
284                        n->name = utf8_to_native (u->name);
285      if (!ctx)              if (u->email != NULL)
286          return gpg_error (GPG_ERR_INV_ARG);                  n->email = m_strdup (u->email);
287                    if (u->comment != NULL)
288      c = (struct keycache_s*)calloc (1, sizeof *c);                  n->comment = utf8_to_native (u->comment);
289      if (!c)          }
290          return gpg_error (GPG_ERR_ENOMEM);          else {
291      c->gloflags.is_protected = 1; /*default: assume protection. */              n->malloced = 0;
292      c->key = key;              n->uid = u->uid;
293      if (!ctx->item)              n->name = u->name;
294          ctx->item = c;              n->comment = u->comment;
295      else {              n->email = u->email;
296          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)          }
297              ;          n->signatures = u->signatures;
298          n1->next = c;          n->validity = u->validity;
299      }          n->revoked = u->revoked;
300      if (opaque)          if (!ctx->uids)
301          *opaque = c;              ctx->uids = n;
302      return 0;          else {
303  }              for (t = ctx->uids; t->next; t=t->next)
304                    ;
305                t->next = n;          
306            }
307  #define has_keyid_len(pattern) (\      }
308      strlen (pattern) == 8  || strlen (pattern) == 10 || \  }
309      strlen (pattern) == 16 || strlen (pattern) == 18)  
310    
311    /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
312  gpgme_error_t  static void
313  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,  keycache_decode_uids (gpg_keycache_t ctx)
314                          gpgme_key_t *r_key, struct keycache_s **r_item)  {
315  {      struct keycache_s *c;
316      struct keycache_s *c;  
317      gpgme_subkey_t s;      for (c = ctx->item; c; c = c->next)
318      gpgme_user_id_t u;          keycache_decode_uid (c);
319      gpgme_key_t key;  }
320      const char *kid;  
321        
322      if (!ctx || !r_key)  static void
323          return gpg_error (GPG_ERR_INV_ARG);  free_native_uids (struct native_uid_s **r_n)
324        {
325      if (strstr (pattern, "0x"))      struct native_uid_s *t;
326          pattern += 2;      struct native_uid_s *n = *r_n;
327    
328      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4      while (n != NULL) {
329         fingerprints into the 64-bit keyid. */          t = n->next;
330      if (strlen (pattern) == 40 && isxdigit (*pattern))          if (n->malloced) {
331          pattern += 32;              free_if_alloc (n->uid);
332                free_if_alloc (n->name);
333      /* XXX: this code is very slow, revamp it and use hash tables whenever              free_if_alloc (n->comment);
334              it is possible. */              free_if_alloc (n->email);
335      for (c = ctx->item; c; c = c->next) {          }
336          key = c->key;          free_if_alloc (n);
337          assert (key->_refs >= 1);          n = t;
338          for (s = key->subkeys; s; s = s->next) {      }
339              for (u = key->uids; u; u = u->next) {      *r_n = NULL;
340                  if (u->name && stristr (u->name, pattern)) {  }
341                      if (r_item)  
342                          *r_item = c;  
343                      *r_key = flags? c->pubpart->key : c->key;  
344                      return 0;  /* Merge the information from the keyrings into the key cache structure. */
345                  }  static gpgme_error_t
346              }  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
347              if (has_keyid_len (pattern))                     const char *pubring, const char *secring)
348                  kid = s->keyid;  {
349              else      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
350                  kid = s->fpr;      gpgme_key_t key = NULL;
351              if (kid && stristr (kid, pattern)) {      gpg_iobuf_t inp;
352                  if (r_item)      PACKET *pkt;
353                      *r_item = c;      struct keycache_s *c;
354                  *r_key = flags? c->pubpart->key : c->key;      const BYTE *sym_prefs;
355                  return 0;      char keyid[16+1];
356              }      int key_seen = 0;
357          }      size_t nsym =0;
358      }  
359      *r_key = NULL;      if (secring) {
360      return gpg_error (GPG_ERR_INTERNAL);          parse_secring (ctx, kid, secring);
361  } /* keycache_find_key */          if (!pubring)
362                return 0;
363        }
364  gpgme_error_t      inp = gpg_iobuf_open (pubring);
365  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,      if (!inp)
366                         int flags, gpgme_key_t *r_key)          return gpg_error (GPG_ERR_KEYRING_OPEN);
367  {      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
368      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);  
369  }      pkt = (PACKET*)calloc (1, sizeof * pkt);
370        if (!pkt)
371            BUG (0);
372  gpgme_error_t      gpg_init_packet (pkt);
373  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,      while (gpg_parse_packet (inp, pkt) != -1) {
374                           void *opaque, const char *keyid)          if (pkt->pkttype == PKT_PUBLIC_KEY) {
375  {              strcpy (keyid, "");
376      struct keycache_s *c = NULL, *c_new=NULL;              key_seen = 1;
377      gpgme_key_t key=NULL, fndkey=NULL;          }
378      gpgme_error_t err;          if (pkt->pkttype == PKT_SIGNATURE &&
379      gpgme_ctx_t gctx;              pkt->pkt.signature->sig_class == 0x1F) {
380      gpg_keycache_t pub = (gpg_keycache_t)opaque;              if (pkt->pkt.signature->numrevkeys == 0)
381                    goto next;
382      err = gpgme_new (&gctx);              _snprintf (keyid, sizeof (keyid) -1, "%08X",
383      if (err)                          pkt->pkt.signature->keyid[1]);
384          return err;              if (kid && strcmp (kid, keyid) != 0)
385      err = gpgme_get_key (gctx, keyid, &key, is_sec);                  goto next;
386      gpgme_release (gctx);              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
387      if (err)              if (err)
388          return err;                  goto next;
389      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);              c->gloflags.has_desig_rev = 1;
390      if (!err && c != NULL) {          }
391          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 && c != NULL) {
392          gpgme_key_release (fndkey);              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
393          c->key = key;                                                SIGSUBPKT_PREF_SYM, &nsym);
394          c->flags = 0;              if (!sym_prefs)
395          if (is_sec && pub != NULL &&                  goto next;
396              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {              _snprintf (keyid, sizeof (keyid) - 1, "%08X",
397              log_debug ("keycache update: set public part %p\r\n", fndkey);                          pkt->pkt.signature->keyid[1]);
398              c->pubpart->key = fndkey;              if (kid && strcmp (kid, keyid) != 0)
399          }                  goto next;
400      }              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
401      else {              if (err || !c)
402          log_debug ("keycache add: sync public part\r\n");                  goto next;
403          if (is_sec)              if (c->sym_prefs) // only use the prefs from the primary uid.
404              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);                  goto next;
405          gpg_keycache_add_key (ctx, key, (void **)&c);              else if (nsym > 0) {
406          if (c != NULL && is_sec) {                  c->sym_prefs = safe_uchar_alloc (nsym+1);
407              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);                  memset (c->sym_prefs, 0, nsym+1);
408              c->pubpart = c_new;                  memcpy (c->sym_prefs, sym_prefs, nsym);
409              if (c_new != NULL) {              }
410                  c->pubpart->key = fndkey;          }
411                  c->gloflags.is_protected = c_new->gloflags.is_protected;  next:
412                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;          gpg_free_packet (pkt);
413              }          gpg_init_packet(pkt);
414          }      }
415      }  
416      return 0;      safe_free (pkt);
417  }      gpg_iobuf_close (inp);
418        return err;
419    }
420  /* Delete a key from the cache @ctx with the pattern @pattern.  
421     Return value: 0 on success. */  
422  gpgme_error_t  gpgme_error_t
423  gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
424  {  {
425      struct keycache_s *itm = NULL, *c;      return keycache_prepare2 (ctx, NULL, pubr, secr);
426      gpgme_key_t key;  }
427      gpgme_error_t rc;  
428    gpgme_error_t
429      if (!ctx)  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
430          return gpg_error (GPG_ERR_INV_ARG);                                 const char *pubr, const char *secr)
431      rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);  {
432      if (rc)      if (!strncmp (keyid, "0x", 2))
433          return rc;          keyid += 2;  
434            return keycache_prepare2 (ctx, keyid, pubr, secr);
435      c = ctx->item;  }
436      if (c->next == NULL) {  
437          gpgme_key_release (itm->key);  
438          if (itm)  /* Create new keycache object and return it in @r_ctx.
439              free (itm);     Return value: 0 on success. */
440          ctx->item = NULL;  gpgme_error_t
441      }  gpg_keycache_new (gpg_keycache_t *r_ctx)
442      else {  {
443          while (c && c->next != itm)      gpg_keycache_t ctx;
444              c = c->next;      
445          c->next = c->next->next;      if (!r_ctx)
446          gpgme_key_release (itm->key);          return gpg_error (GPG_ERR_INV_ARG);
447          if (itm)      ctx = new gpg_keycache_s;    
448              free (itm);      if (!ctx)
449      }          BUG (0);
450      return 0;      memset (ctx, 0, sizeof *ctx);
451  }      ctx->secret = 0;
452        ctx->pos = 0;
453        *r_ctx = ctx;
454  /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring      return 0;
455     will be added to the cache. @secret is 1 if the source is the secret keyring.  }
456     Return value: 0 on success. */  
457  gpgme_error_t  
458  gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)  void
459  {  gpg_keycache_item_release (struct keycache_s *c)
460      gpgme_error_t err;  {
461      gpgme_ctx_t c;      if (c->key)
462      gpgme_key_t key;          gpgme_key_release (c->key);    
463      int count = 0;      c->key = NULL;      
464            if (c->rev != NULL)    
465      if (!ctx)          gpg_desig_rev_release (c->rev);
466          return gpg_error (GPG_ERR_INV_ARG);      c->rev = NULL;
467            free_if_alloc (c->pref_keyserver);
468      err = gpgme_new (&c);      free_if_alloc (c->sym_prefs);
469      if (err)      free_if_alloc (c->attrib.d);
470          return err;      free_if_alloc (c->card_type);
471        free_native_uids (&c->uids);
472      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);      free_if_alloc (c);
473      err = gpgme_op_keylist_start (c, pattern, secret);  }
474      while(!err) {  
475          err = gpgme_op_keylist_next (c, &key);  
476          if (!err)  /* Release keycache object @ctx. */
477              err = gpg_keycache_add_key (ctx, key, NULL);  void
478          if (ctx->cb)  gpg_keycache_release (gpg_keycache_t ctx)
479              ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,  {
480                       count++, ctx->cb_value2);      struct keycache_s *c, *c2;
481      }      
482      if (gpgme_err_code (err) == GPG_ERR_EOF)      if (!ctx)
483          err = gpg_error (GPG_ERR_NO_ERROR);          return;
484      /* XXX: make sure the progress dialog is closed. */  
485      gpgme_op_keylist_end (c);      for (c = ctx->item; c; c = c2) {
486      gpgme_release (c);          c2 = c->next;
487      return err;          gpg_keycache_item_release (c);
488  }      }
489        free_if_alloc (ctx);
490    }
491  /* XXX: kludge to see if the key is stored on a card. */  
492  static int  
493  key_divert_to_card (gpgme_key_t key)  /* Set (progress) callback for the given keycache object.
494  {     @ctx the keycache
495      gpgme_subkey_t k;     @cb  the callback function
496      int n=0, n_alg=0, can_auth = 0;     @cb_value1 opaque value which is passed to the callback.
497       @cb_value2 see @cb_value1. */
498      for (k = key->subkeys; k; k = k->next) {  void
499          n++;  gpg_keycache_set_cb (gpg_keycache_t ctx,
500          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)                       void (*cb)(void *, const char *, int, int, int),
501              n_alg++;                       void * cb_value1, int cb_value2)
502          if (k->can_authenticate)  {
503              can_auth++;      if (!ctx)
504      }          return;
505      if (n == 3 && n_alg == 3 && can_auth == 1)      ctx->cb = cb;
506          return 1;      ctx->cb_value = cb_value1;
507      return 0;      ctx->cb_value2 = cb_value2;
508  }  }
509    
510    
511  gpgme_error_t  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
512  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)     Return value: 0 on success. */
513  {  gpgme_error_t
514      struct keycache_s *c, *c_sec;  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
515      gpgme_key_t key;  {
516        struct keycache_s *c, *n1;
517      if (!pub || !sec)      
518          return gpg_error (GPG_ERR_INV_ARG);      if (!ctx)
519                return gpg_error (GPG_ERR_INV_ARG);
520      for (c=sec->item; c; c=c->next) {        
521          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {      c = new keycache_s;
522              c_sec->gloflags.is_protected = c->gloflags.is_protected;      if (!c)
523              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;          BUG (0);
524              if (!c->gloflags.divert_to_card)      memset (c, 0, sizeof *c);
525                  c->gloflags.divert_to_card = key_divert_to_card (key);      c->gloflags.is_protected = 1; /*default: assume protection. */
526              c->pubpart = c_sec;      c->key = key;
527              c->pubpart->key = key;      if (!ctx->item)
528          }          ctx->item = c;
529      }      else {
530      return 0;          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
531  }              ;
532            n1->next = c;
533        }
534  /* Rewind the given cache @ctx to the begin. */      if (opaque)
535  void          *opaque = c;
536  gpg_keycache_rewind (gpg_keycache_t ctx)      return 0;
537  {  }
538      if (ctx)  
539          ctx->pos = 0;  
540  }  
541    #define has_keyid_len(pattern) (\
542        strlen (pattern) == 8  || strlen (pattern) == 10 || \
543        strlen (pattern) == 16 || strlen (pattern) == 18)
544  /* Return the number of elements in the cache @ctx. */  
545  int  
546  gpg_keycache_get_size (gpg_keycache_t ctx)  gpgme_error_t
547  {  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
548      struct keycache_s *c;                          gpgme_key_t *r_key, struct keycache_s **r_item)
549      int count = 0;  {
550            struct keycache_s *c;
551      if (!ctx)      gpgme_subkey_t s;
552          return 0;      gpgme_user_id_t u;
553      for (c = ctx->item; c; c = c->next)      gpgme_key_t key;
554          count++;      const char *kid;
555      return count;      
556  }      if (!ctx || !r_key)
557            return gpg_error (GPG_ERR_INV_ARG);
558        
559  static gpgme_error_t      if (strstr (pattern, "0x"))
560  keycache_next_key (gpg_keycache_t ctx, int flags,          pattern += 2;
561                     struct keycache_s **c, gpgme_key_t *r_key)  
562  {            /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
563      if (!ctx || !r_key)         fingerprints into the 64-bit keyid. */
564          return gpg_error (GPG_ERR_INV_ARG);      if (strlen (pattern) == 40 && isxdigit (*pattern))
565            pattern += 32;
566      if (!ctx->pos)  
567          ctx->tmp = ctx->item;      /* XXX: this code is very slow, revamp it and use hash tables whenever
568                    it is possible. */
569      if (!ctx->tmp || !ctx->tmp->key) {      for (c = ctx->item; c; c = c->next) {
570          ctx->pos = 0;          key = c->key;
571          *r_key = NULL;          assert (key->_refs >= 1);
572          return gpg_error (GPG_ERR_EOF);          for (s = key->subkeys; s; s = s->next) {
573      }              for (u = key->uids; u; u = u->next) {
574                        if (u->name && stristr (u->name, pattern)) {
575      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;                      if (r_item)
576      *c = ctx->tmp = ctx->tmp->next;                          *r_item = c;
577      ctx->pos++;                      *r_key = flags? c->pubpart->key : c->key;
578                        return 0;
579      return 0;                  }
580  }              }
581                if (has_keyid_len (pattern))
582                    kid = s->keyid;
583  /* Return the next key from the cache @ctx. The key will be returned              else
584     in @r_key. @flags can contain additional flags.                  kid = s->fpr;
585     Return value: 0 on success. */              if (kid && stristr (kid, pattern)) {
586  gpgme_error_t                  if (r_item)
587  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)                      *r_item = c;
588  {                  *r_key = flags? c->pubpart->key : c->key;
589      struct keycache_s *c=NULL;                  return 0;
590      gpgme_error_t err = 0;              }
591            }
592      err = keycache_next_key (ctx, flags, &c, r_key);      }
593      return err;      *r_key = NULL;
594  }      return gpg_error (GPG_ERR_INTERNAL);
595    }
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.28  
changed lines
  Added in v.260

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26