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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26