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

Legend:
Removed from v.28  
changed lines
  Added in v.271

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26