/[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 181 by twoaday, Tue Mar 14 11:01:22 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    #include "wptTypes.h"
40      memset (dst, 0, dlen);  
41      for (i = 0; i < nbytes && dlen > 0; i++) {  
42          sprintf (dig, "%02X", buf[i]);  /* Attribute list which holds the image data. */
43          strcat (dst, dig);  struct attr_list_s {
44          dlen -= 2;      struct attr_list_s *next;
45      }      char *fpr;                   /* fingerprint of the key */
46  }      unsigned char *d;            /* actual JPEG data. */
47        unsigned long octets;        /* length of the data. */
48        unsigned int flags;          /* status of the attribute. */
49  /* Parse the secret keyring and retrieve some additional information  };
50     for each key which was found. */  typedef struct attr_list_s *attr_list_t;
51  static void  
52  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)  
53  {      /* Free attribute list @ctx. */
54      PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);  void
55      PKT_secret_key *sk;  free_attr_list (attr_list_t ctx)
56      gpg_iobuf_t inp;  {
57      gpgme_error_t err;      attr_list_t n;
58      gpgme_key_t key;      while (ctx) {
59      struct keycache_s *c=NULL;          n = ctx->next;
60      char keyid[16+1];          free (ctx->fpr);
61            free (ctx->d);
62      inp = gpg_iobuf_open (secring);          ctx = n;
63      if (!inp) {      }
64          safe_free (pkt);  }
65          return;          
66      }  /* Parse the attribute list in @fp and store it into @ctx.
67      gpg_iobuf_ioctl (inp, 3, 1, NULL);     Return value: number of parsed items. */
68      gpg_init_packet (pkt);  int
69      while (gpg_parse_packet (inp, pkt) != -1) {  parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
70          if (pkt->pkttype == PKT_SECRET_KEY) {  {
71              sk = pkt->pkt.secret_key;      attr_list_t c, t;
72              /* XXX: key IDs of card public keys are wrong! */      char buf[512], *p, *buffer;
73              _snprintf (keyid, sizeof (keyid)-1, "%08lX",      int pos, n=0;
74                         gpg_keyid_from_sk (sk, NULL));      
75              if (kid && strcmp (kid, keyid) != 0)      *ctx = NULL;
76                  goto next;      while (fgets (buf, 511, fp)) {
77              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);          if (strstr (buf, "\r\n"))
78              if (err)              buf[strlen (buf)-2]=0;
79                  goto next;          if (strstr (buf, "\n"))
80              c->gloflags.is_protected = sk->is_protected;              buf[strlen (buf)-1]=0;
81              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;          if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
82              if (c->pubpart != NULL) {                  continue;
83                  c->pubpart->gloflags.is_protected = sk->is_protected;              buffer = buf+9+10;
84                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;          pos = 0;
85              }          c = (attr_list_t)calloc (1, sizeof *c);
86          }          if (!c)
87  next:              BUG (0);
88          gpg_free_packet (pkt);          p = strtok (buffer, " ");
89          gpg_init_packet (pkt);          while (p != NULL) {
90      }              switch (pos) {
91      safe_free (pkt);              case 0:
92      gpg_iobuf_close (inp);                  c->fpr = strdup (p);
93  }                  break;
94                    
95                case 1:
96  /* Merge the information from the keyrings into the key cache structure. */                  c->octets = 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)              case 7:
100  {                  c->flags = strtoul (p, NULL, 10);
101      gpgme_error_t err;                  break;
102      gpgme_key_t key = NULL;                  
103      gpg_iobuf_t inp;              default:
104      PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);                  break;
105      struct keycache_s *c;              }
106      const byte *sym_prefs;              pos++;
107      char keyid[16+1], *id = NULL;              p = strtok (NULL, " ");
108      int key_seen = 0;          }
109      size_t nbytes = 0, nsym =0;          if (!*ctx)
110                *ctx = c;
111      if (secring) {          else {
112          parse_secring (ctx, kid, secring);              for (t = *ctx; t->next; t=t->next)
113          if (!pubring) {                  ;
114              safe_free(pkt);              t->next = c;
115              return 0;          }
116          }          c->d = (unsigned char*)malloc (c->octets);
117      }          if (!c->d)
118      inp = gpg_iobuf_open (pubring);              BUG (0);
119      if (!inp) {          memcpy (c->d, data, c->octets);
120          safe_free( pkt );          data += c->octets;
121          return gpg_error (GPG_ERR_KEYRING_OPEN);          datlen -= c->octets;
122      }          n++;
123      gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */      }
124        /*assert (datlen == 0); */
125      gpg_init_packet( pkt );      return n;
126      while (gpg_parse_packet (inp, pkt) != -1) {  }
127          if (pkt->pkttype == PKT_PUBLIC_KEY) {  
128              strcpy (keyid, "");  
129              key_seen = 1;  static int
130          }  parse_attr_data (const char *keyid, attr_list_t *list)
131    {
132          if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {      gpgme_error_t err;
133              if (pkt->pkt.signature->numrevkeys == 0)      FILE *tmp;    
134                  goto next;      BYTE *data;
135              _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);      char *status, tmpnam[MAX_PATH+1];
136              if (kid && strcmp (kid, keyid) != 0)      DWORD ndata = 0;
137                  goto next;  
138              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
139              if (err)      if (err)
140                  goto next;          return err;
141              c->gloflags.has_desig_rev = 1;  
142          }      get_temp_name (tmpnam, MAX_PATH, NULL);
143          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {      tmp = fopen (tmpnam, "w+b");
144              sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,      if (ndata > 0 && tmp != NULL) {
145                                              SIGSUBPKT_PREF_SYM, &nsym);          fwrite (status, 1, strlen (status), tmp);
146              if (sym_prefs == NULL)          fflush (tmp);
147                  goto next;          rewind (tmp);
148              _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);  
149              if (kid && strcmp (kid, keyid) != 0)          ndata = parse_attr_list (tmp, data, ndata, list);
150                  goto next;          fclose (tmp);
151              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);          DeleteFile (tmpnam);
152              if (err)      }
153                  goto next;      else
154              else if (nsym > 0) {          *list = NULL;
155                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);  
156                  if (!c->sym_prefs)      safe_free (status);
157                      return gpg_error (GPG_ERR_ENOMEM);      safe_free (data);
158                  memcpy (c->sym_prefs, sym_prefs, nsym);      return ndata;
159              }  }
160          }  
161          if (pkt->pkttype == PKT_USER_ID) {  
162              if (id)  /* Parse the secret keyring and retrieve some additional information
163                  free (id);     for each key which was found. */
164              id = strdup (pkt->pkt.user_id->name);  static void
165              if (!id) {  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
166                  err = gpg_error (GPG_ERR_ENOMEM);  {    
167                  goto fail;      PACKET *pkt;
168              }      PKT_secret_key *sk;
169          }      gpg_iobuf_t inp;
170          if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)      gpgme_error_t err;
171              && pkt->pkt.user_id->attrib_data && key) {      gpgme_key_t key;
172              PKT_user_id *id = pkt->pkt.user_id;      struct keycache_s *c=NULL;
173              c->attrib.used = 1;      char keyid[16+1];
174              c->attrib.len = id->attrib_len;  
175              c->attrib.d = (unsigned char*)calloc (1, id->attrib_len + 1);      inp = gpg_iobuf_open (secring);
176              if (!c->attrib.d) {      if (!inp)
177                  err = gpg_error (GPG_ERR_ENOMEM);          return;
178                  goto fail;  
179              }      gpg_iobuf_ioctl (inp, 3, 1, NULL);
180              memcpy (c->attrib.d, id->attrib_data, id->attrib_len);      pkt = (PACKET*)calloc (1, sizeof *pkt);
181              key = NULL;      if (!pkt)
182              c = NULL;          BUG (0);
183          }      gpg_init_packet (pkt);
184  next:      while (gpg_parse_packet (inp, pkt) != -1) {
185          gpg_free_packet (pkt);          if (pkt->pkttype == PKT_SECRET_KEY) {
186          gpg_init_packet(pkt);              sk = pkt->pkt.secret_key;
187      }              /* XXX: key IDs of card public keys are wrong! */
188                _snprintf (keyid, sizeof (keyid)-1, "%08lX",
189  fail:                         gpg_keyid_from_sk (sk, NULL));
190      safe_free (id);              if (kid && strcmp (kid, keyid) != 0)
191      safe_free (pkt);                  goto next;
192      gpg_iobuf_close (inp);              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
193      return err;              if (err)
194  }                  goto next;
195                c->gloflags.is_protected = sk->is_protected;
196                c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
197  gpgme_error_t              if (c->pubpart != NULL) {    
198  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)                  c->pubpart->gloflags.is_protected = sk->is_protected;    
199  {                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
200      return keycache_prepare2 (ctx, NULL, pubr, secr);              }
201  }          }
202    next:
203  gpgme_error_t          gpg_free_packet (pkt);
204  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,          gpg_init_packet (pkt);
205                                 const char *pubr, const char *secr)      }
206  {      safe_free (pkt);
207      if (!strncmp (keyid, "0x", 2))      gpg_iobuf_close (inp);
208          keyid += 2;    }
209      return keycache_prepare2 (ctx, keyid, pubr, secr);  
210  }  
211    /* Update the photo image of a single key with the fingerprint
212       @fpr. The @dat struct contains the new item data. */
213  /* Create new keycache object and return it in @r_ctx.  static gpgme_error_t
214     Return value: 0 on success. */  keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
215  gpgme_error_t  {
216  gpg_keycache_new (gpg_keycache_t *r_ctx)      struct keycache_s *fnd = NULL;
217  {      gpgme_key_t key;
218      gpg_keycache_t ctx;      
219            gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
220      if (!r_ctx)      if (!fnd)
221          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_NOT_FOUND);
222      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);      safe_free (fnd->attrib.d);
223      if (!ctx)      fnd->attrib.flags = dat->flags;
224          return gpg_error (GPG_ERR_ENOMEM);      fnd->attrib.len = dat->octets;
225      ctx->secret = 0;      fnd->attrib.d = (unsigned char*)malloc (dat->octets);
226      ctx->pos = 0;      if (!fnd->attrib.d)
227      *r_ctx = ctx;          BUG (0);
228      return 0;      memcpy (fnd->attrib.d, dat->d, dat->octets);
229  }      return 0;
230    }
231    
232  /* Release keycache object @ctx. */  
233  void  /* Update all photo images in the cache. */
234  gpg_keycache_release (gpg_keycache_t ctx)  static gpgme_error_t
235  {  keycache_update_photos (gpg_keycache_t ctx)
236      struct keycache_s *c, *c2;  {
237            attr_list_t list=NULL, n;
238      if (!ctx)      DWORD ndata;
239          return;  
240        ndata = parse_attr_data (NULL, &list);
241      for (c = ctx->item; c; c = c2) {      if (ndata < 1) {
242          c2 = c->next;          free_attr_list (list);
243          gpgme_key_release (c->key);          return 0;
244          c->key = NULL;      }
245          if (c->sym_prefs)  
246              free (c->sym_prefs);      for (n=list; n; n=n->next)
247          c->sym_prefs = NULL;          keycache_update_photo (ctx, n->fpr, n);
248          if (c->attrib.d)      free_attr_list (list);
249              free (c->attrib.d);      return 0;
250          c->attrib.d = NULL;  }
251          if (c->card_type)  
252              free (c->card_type);  
253          free (c);  /* Merge the information from the keyrings into the key cache structure. */
254      }  gpgme_error_t
255      if (ctx)  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
256          free (ctx);                     const char *pubring, const char *secring)
257  }  {
258        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
259        gpgme_key_t key = NULL;
260  /* Set (progress) callback for the given keycache object.      gpg_iobuf_t inp;
261     @ctx the keycache      PACKET *pkt;
262     @cb  the callback function      struct keycache_s *c;
263     @cb_value1 opaque value which is passed to the callback.      const byte *sym_prefs;
264     @cb_value2 see @cb_value1. */      char keyid[16+1];
265  void      int key_seen = 0;
266  gpg_keycache_set_cb (gpg_keycache_t ctx,      size_t nsym =0;
267                       void (*cb)(void *, const char *, int, int, int),  
268                       void * cb_value1, int cb_value2)      if (secring) {
269  {          parse_secring (ctx, kid, secring);
270      if (!ctx)          if (!pubring)
271          return;              return 0;
272      ctx->cb = cb;      }
273      ctx->cb_value = cb_value1;      inp = gpg_iobuf_open (pubring);
274      ctx->cb_value2 = cb_value2;      if (!inp)
275  }          return gpg_error (GPG_ERR_KEYRING_OPEN);
276        gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
277    
278  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.      pkt = (PACKET*)calloc (1, sizeof * pkt);
279     Return value: 0 on success. */      if (!pkt)
280  gpgme_error_t          BUG (0);
281  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)      gpg_init_packet (pkt);
282  {      while (gpg_parse_packet (inp, pkt) != -1) {
283      struct keycache_s * c, * n1;          if (pkt->pkttype == PKT_PUBLIC_KEY) {
284                    strcpy (keyid, "");
285      if (!ctx)              key_seen = 1;
286          return gpg_error (GPG_ERR_INV_ARG);          }
287        
288      c = (struct keycache_s*)calloc (1, sizeof *c);          if (pkt->pkttype == PKT_SIGNATURE &&
289      if (!c)              pkt->pkt.signature->sig_class == 0x1F) {
290          return gpg_error (GPG_ERR_ENOMEM);              if (pkt->pkt.signature->numrevkeys == 0)
291      c->gloflags.is_protected = 1; /*default: assume protection. */                  goto next;
292      c->key = key;              _snprintf (keyid, sizeof (keyid) -1, "%08X",
293      if (!ctx->item)                          pkt->pkt.signature->keyid[1]);
294          ctx->item = c;              if (kid && strcmp (kid, keyid) != 0)
295      else {                  goto next;
296          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
297              ;              if (err)
298          n1->next = c;                  goto next;
299      }              c->gloflags.has_desig_rev = 1;
300      if (opaque)          }
301          *opaque = c;          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
302      return 0;              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
303  }                                                SIGSUBPKT_PREF_SYM, &nsym);
304                if (!sym_prefs)
305                    goto next;
306                _snprintf (keyid, sizeof (keyid) - 1, "%08X",
307  #define has_keyid_len(pattern) (\                          pkt->pkt.signature->keyid[1]);
308      strlen (pattern) == 8  || strlen (pattern) == 10 || \              if (kid && strcmp (kid, keyid) != 0)
309      strlen (pattern) == 16 || strlen (pattern) == 18)                  goto next;
310                err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
311                if (err)
312  gpgme_error_t                  goto next;
313  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,              else if (nsym > 0) {
314                          gpgme_key_t *r_key, struct keycache_s **r_item)                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
315  {                  if (!c->sym_prefs)
316      struct keycache_s *c;                      BUG (0);
317      gpgme_subkey_t s;                  memcpy (c->sym_prefs, sym_prefs, nsym);
318      gpgme_user_id_t u;              }
319      gpgme_key_t key;          }
320      const char *kid;  next:
321                gpg_free_packet (pkt);
322      if (!ctx || !r_key)          gpg_init_packet(pkt);
323          return gpg_error (GPG_ERR_INV_ARG);      }
324        
325      if (strstr (pattern, "0x"))      safe_free (pkt);
326          pattern += 2;      gpg_iobuf_close (inp);
327        return err;
328      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4  }
329         fingerprints into the 64-bit keyid. */  
330      if (strlen (pattern) == 40 && isxdigit (*pattern))  
331          pattern += 32;  gpgme_error_t
332    gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
333      /* XXX: this code is very slow, revamp it and use hash tables whenever  {
334              it is possible. */      return keycache_prepare2 (ctx, NULL, pubr, secr);
335      for (c = ctx->item; c; c = c->next) {  }
336          key = c->key;  
337          assert (key->_refs >= 1);  gpgme_error_t
338          for (s = key->subkeys; s; s = s->next) {  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
339              for (u = key->uids; u; u = u->next) {                                 const char *pubr, const char *secr)
340                  if (u->name && stristr (u->name, pattern)) {  {
341                      if (r_item)      if (!strncmp (keyid, "0x", 2))
342                          *r_item = c;          keyid += 2;  
343                      *r_key = flags? c->pubpart->key : c->key;      return keycache_prepare2 (ctx, keyid, pubr, secr);
344                      return 0;  }
345                  }  
346              }  
347              if (has_keyid_len (pattern))  /* Create new keycache object and return it in @r_ctx.
348                  kid = s->keyid;     Return value: 0 on success. */
349              else  gpgme_error_t
350                  kid = s->fpr;  gpg_keycache_new (gpg_keycache_t *r_ctx)
351              if (kid && stristr (kid, pattern)) {  {
352                  if (r_item)      gpg_keycache_t ctx;
353                      *r_item = c;      
354                  *r_key = flags? c->pubpart->key : c->key;      if (!r_ctx)
355                  return 0;          return gpg_error (GPG_ERR_INV_ARG);
356              }      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
357          }      if (!ctx)
358      }          BUG (0);
359      *r_key = NULL;      ctx->secret = 0;
360      return gpg_error (GPG_ERR_INTERNAL);      ctx->pos = 0;
361  } /* keycache_find_key */      *r_ctx = ctx;
362        return 0;
363    }
364  gpgme_error_t  
365  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,  
366                         int flags, gpgme_key_t *r_key)  /* Release keycache object @ctx. */
367  {  void
368      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);  gpg_keycache_release (gpg_keycache_t ctx)
369  }  {
370        struct keycache_s *c, *c2;
371        
372  gpgme_error_t      if (!ctx)
373  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,          return;
374                           void *opaque, const char *keyid)  
375  {      for (c = ctx->item; c; c = c2) {
376      struct keycache_s *c = NULL, *c_new=NULL;          c2 = c->next;
377      gpgme_key_t key=NULL, fndkey=NULL;          gpgme_key_release (c->key);
378      gpgme_error_t err;          c->key = NULL;
379      gpgme_ctx_t gctx;          safe_free (c->pref_keyserver);
380      gpg_keycache_t pub = (gpg_keycache_t)opaque;          safe_free (c->sym_prefs);
381            safe_free (c->attrib.d);
382      err = gpgme_new (&gctx);          safe_free (c->card_type);
383      if (err)          free (c);
384          return err;      }
385      err = gpgme_get_key (gctx, keyid, &key, is_sec);      safe_free (ctx);
386      gpgme_release (gctx);  }
387      if (err)  
388          return err;  
389      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);  /* Set (progress) callback for the given keycache object.
390      if (!err && c != NULL) {     @ctx the keycache
391          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);     @cb  the callback function
392          gpgme_key_release (fndkey);     @cb_value1 opaque value which is passed to the callback.
393          c->key = key;     @cb_value2 see @cb_value1. */
394          c->flags = 0;  void
395          if (is_sec && pub != NULL &&  gpg_keycache_set_cb (gpg_keycache_t ctx,
396              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {                       void (*cb)(void *, const char *, int, int, int),
397              log_debug ("keycache update: set public part %p\r\n", fndkey);                       void * cb_value1, int cb_value2)
398              c->pubpart->key = fndkey;  {
399          }      if (!ctx)
400      }          return;
401      else {      ctx->cb = cb;
402          log_debug ("keycache add: sync public part\r\n");      ctx->cb_value = cb_value1;
403          if (is_sec)      ctx->cb_value2 = cb_value2;
404              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);  }
405          gpg_keycache_add_key (ctx, key, (void **)&c);  
406          if (c != NULL && is_sec) {  
407              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
408              c->pubpart = c_new;     Return value: 0 on success. */
409              if (c_new != NULL) {  gpgme_error_t
410                  c->pubpart->key = fndkey;  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
411                  c->gloflags.is_protected = c_new->gloflags.is_protected;  {
412                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;      struct keycache_s *c, *n1;
413              }      
414          }      if (!ctx)
415      }          return gpg_error (GPG_ERR_INV_ARG);
416      return 0;      
417  }      c = (struct keycache_s*)calloc (1, sizeof *c);
418        if (!c)
419            BUG (0);
420  /* Delete a key from the cache @ctx with the pattern @pattern.      c->gloflags.is_protected = 1; /*default: assume protection. */
421     Return value: 0 on success. */      c->key = key;
422  gpgme_error_t      if (!ctx->item)
423  gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)          ctx->item = c;
424  {      else {
425      struct keycache_s *itm = NULL, *c;          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
426      gpgme_key_t key;              ;
427      gpgme_error_t rc;          n1->next = c;
428        }
429      if (!ctx)      if (opaque)
430          return gpg_error (GPG_ERR_INV_ARG);          *opaque = c;
431      rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);      return 0;
432      if (rc)  }
433          return rc;  
434        
435      c = ctx->item;  
436      if (c->next == NULL) {  #define has_keyid_len(pattern) (\
437          gpgme_key_release (itm->key);      strlen (pattern) == 8  || strlen (pattern) == 10 || \
438          if (itm)      strlen (pattern) == 16 || strlen (pattern) == 18)
439              free (itm);  
440          ctx->item = NULL;  
441      }  gpgme_error_t
442      else {  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
443          while (c && c->next != itm)                          gpgme_key_t *r_key, struct keycache_s **r_item)
444              c = c->next;  {
445          c->next = c->next->next;      struct keycache_s *c;
446          gpgme_key_release (itm->key);      gpgme_subkey_t s;
447          if (itm)      gpgme_user_id_t u;
448              free (itm);      gpgme_key_t key;
449      }      const char *kid;
450      return 0;      
451  }      if (!ctx || !r_key)
452            return gpg_error (GPG_ERR_INV_ARG);
453        
454  /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring      if (strstr (pattern, "0x"))
455     will be added to the cache. @secret is 1 if the source is the secret keyring.          pattern += 2;
456     Return value: 0 on success. */  
457  gpgme_error_t      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
458  gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)         fingerprints into the 64-bit keyid. */
459  {      if (strlen (pattern) == 40 && isxdigit (*pattern))
460      gpgme_error_t err;          pattern += 32;
461      gpgme_ctx_t c;  
462      gpgme_key_t key;      /* XXX: this code is very slow, revamp it and use hash tables whenever
463      int count = 0;              it is possible. */
464            for (c = ctx->item; c; c = c->next) {
465      if (!ctx)          key = c->key;
466          return gpg_error (GPG_ERR_INV_ARG);          assert (key->_refs >= 1);
467                for (s = key->subkeys; s; s = s->next) {
468      err = gpgme_new (&c);              for (u = key->uids; u; u = u->next) {
469      if (err)                  if (u->name && stristr (u->name, pattern)) {
470          return err;                      if (r_item)
471                            *r_item = c;
472      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);                      *r_key = flags? c->pubpart->key : c->key;
473      err = gpgme_op_keylist_start (c, pattern, secret);                      return 0;
474      while(!err) {                  }
475          err = gpgme_op_keylist_next (c, &key);              }
476          if (!err)              if (has_keyid_len (pattern))
477              err = gpg_keycache_add_key (ctx, key, NULL);                  kid = s->keyid;
478          if (ctx->cb)              else
479              ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,                  kid = s->fpr;
480                       count++, ctx->cb_value2);              if (kid && stristr (kid, pattern)) {
481      }                  if (r_item)
482      if (gpgme_err_code (err) == GPG_ERR_EOF)                      *r_item = c;
483          err = gpg_error (GPG_ERR_NO_ERROR);                  *r_key = flags? c->pubpart->key : c->key;
484      /* XXX: make sure the progress dialog is closed. */                  return 0;
485      gpgme_op_keylist_end (c);              }
486      gpgme_release (c);          }
487      return err;      }
488  }      *r_key = NULL;
489        return gpg_error (GPG_ERR_INTERNAL);
490    }
491  /* XXX: kludge to see if the key is stored on a card. */  
492  static int  
493  key_divert_to_card (gpgme_key_t key)  gpgme_error_t
494  {  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
495      gpgme_subkey_t k;                         int flags, gpgme_key_t *r_key)
496      int n=0, n_alg=0, can_auth = 0;  {
497        return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
498      for (k = key->subkeys; k; k = k->next) {  }
499          n++;  
500          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)  
501              n_alg++;  /* Reload a photo image of a single key with the keyid @keyid.
502          if (k->can_authenticate)     Return value: 0 on success. */
503              can_auth++;  static gpgme_error_t
504      }  keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
505      if (n == 3 && n_alg == 3 && can_auth == 1)  {
506          return 1;      attr_list_t list;
507      return 0;  
508  }      if (parse_attr_data (keyid, &list) < 1) {
509            free_attr_list (list);
510            return 0;
511  gpgme_error_t      }
512  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)      keycache_update_photo (ctx, list->fpr, list);
513  {      free_attr_list (list);
514      struct keycache_s *c, *c_sec;      return 0;
515      gpgme_key_t key;  }
516    
517      if (!pub || !sec)  
518          return gpg_error (GPG_ERR_INV_ARG);  /* Return the next key which was updated. Before it is
519           returned the update flag is cleared.
520      for (c=sec->item; c; c=c->next) {       @r_status is 1 for a new key and 2 for an updated key.
521          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {     Return value: 0 on success. */
522              c_sec->gloflags.is_protected = c->gloflags.is_protected;  gpgme_error_t
523              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;  gpg_keycache_next_updated_key (gpg_keycache_t ctx,
524              if (!c->gloflags.divert_to_card)                                 struct keycache_s **r_obj,
525                  c->gloflags.divert_to_card = key_divert_to_card (key);                                 int *r_status)
526              c->pubpart = c_sec;  {
527              c->pubpart->key = key;      struct keycache_s *c;
528          }  
529      }      for (c = ctx->item; c; c = c->next) {
530      return 0;          if (c->flags != 0) {
531  }              *r_status = c->flags;
532                c->flags = 0;
533                *r_obj = c;
534  /* Rewind the given cache @ctx to the begin. */              return 0;
535  void          }
536  gpg_keycache_rewind (gpg_keycache_t ctx)      }
537  {      return gpg_error (GPG_ERR_NOT_FOUND);
538      if (ctx)  }
539          ctx->pos = 0;  
540  }  
541    
542    gpgme_error_t
543    gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
544  /* Return the number of elements in the cache @ctx. */                           void *opaque, const char *keyid)
545  int  {
546  gpg_keycache_get_size (gpg_keycache_t ctx)      struct keycache_s *c = NULL, *c_new=NULL;
547  {      gpgme_key_t key=NULL, fndkey=NULL;
548      struct keycache_s *c;      gpgme_error_t err;
549      int count = 0;      gpgme_ctx_t gctx;
550            gpg_keycache_t pub = (gpg_keycache_t)opaque;
551      if (!ctx)  
552          return 0;      err = gpgme_new (&gctx);
553      for (c = ctx->item; c; c = c->next)      if (err)
554          count++;          return err;
555      return count;      gpgme_set_keylist_mode  (gctx, GPGME_KEYLIST_MODE_SIGS);
556  }      err = gpgme_get_key (gctx, keyid, &key, is_sec);
557        gpgme_release (gctx);
558        if (err)
559  static gpgme_error_t          return err;
560  keycache_next_key (gpg_keycache_t ctx, int flags,      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
561                     struct keycache_s **c, gpgme_key_t *r_key)      if (!err && c != NULL) {
562  {                log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
563      if (!ctx || !r_key)          gpgme_key_release (fndkey);
564          return gpg_error (GPG_ERR_INV_ARG);          c->key = key;
565            c->flags = KC_FLAG_UPD;
566      if (!ctx->pos)          if (is_sec && pub != NULL &&
567          ctx->tmp = ctx->item;              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
568                    log_debug ("keycache update: set public part %p\r\n", fndkey);
569      if (!ctx->tmp || !ctx->tmp->key) {              c->pubpart->key = fndkey;
570          ctx->pos = 0;          }
571          *r_key = NULL;          /* XXX: this is also called for keys without a photo-id. */
572          return gpg_error (GPG_ERR_EOF);          keycache_reload_photo (ctx, keyid);
573      }      }
574            else {
575      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;          log_debug ("keycache add: sync public part\r\n");
576      *c = ctx->tmp = ctx->tmp->next;          if (is_sec)
577      ctx->pos++;              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
578            gpg_keycache_add_key (ctx, key, (void **)&c);
579      return 0;          if (c != NULL && is_sec) {
580  }              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
581                c->pubpart = c_new;
582                if (c_new != NULL) {
583  /* Return the next key from the cache @ctx. The key will be returned                  c->pubpart->key = fndkey;
584     in @r_key. @flags can contain additional flags.                  c->gloflags.is_protected = c_new->gloflags.is_protected;
585     Return value: 0 on success. */                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
586  gpgme_error_t              }
587  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)          }
588  {          if (c)
589      struct keycache_s *c=NULL;              c->flags = KC_FLAG_ADD;
590      gpgme_error_t err = 0;      }
591        return 0;
592      err = keycache_next_key (ctx, flags, &c, r_key);  }
593      return err;  
594  }  
595    /* Delete a key from the cache @ctx with the pattern @pattern.
596       Return value: 0 on success. */
597    gpgme_error_t
598    gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
599    {
600        struct keycache_s *itm = NULL, *c;
601        gpgme_key_t key;
602        gpgme_error_t rc;
603    
604        if (!ctx)
605            return gpg_error (GPG_ERR_INV_ARG);
606        rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
607        if (rc)
608            return rc;
609        
610        c = ctx->item;
611        if (c->next == NULL) {
612            gpgme_key_release (itm->key);
613            if (itm)
614                free (itm);
615            ctx->item = NULL;
616        }
617        else {
618            while (c && c->next != itm)
619                c = c->next;
620            c->next = c->next->next;
621            gpgme_key_release (itm->key);
622            if (itm)
623                free (itm);
624        }
625        return 0;
626    }
627    
628    
629    /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
630       will be added to the cache. @secret is 1 if the source is the secret keyring.
631       Return value: 0 on success. */
632    gpgme_error_t
633    gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
634    {
635        gpgme_error_t err;
636        gpgme_ctx_t c;
637        gpgme_key_t key;
638        int count = 0;
639        
640        if (!ctx)
641            return gpg_error (GPG_ERR_INV_ARG);
642        
643        err = gpgme_new (&c);
644        if (err)
645            return err;
646    
647        gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
648        err = gpgme_op_keylist_start (c, pattern, secret);
649        while(!err) {
650            err = gpgme_op_keylist_next (c, &key);
651            if (!err)
652                err = gpg_keycache_add_key (ctx, key, NULL);
653            if (ctx->cb)
654                ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
655                         count++, ctx->cb_value2);
656        }
657        if (gpgme_err_code (err) == GPG_ERR_EOF)
658            err = gpg_error (GPG_ERR_NO_ERROR);
659        keycache_update_photos (ctx);
660        /* XXX: make sure the progress dialog is closed. */
661        gpgme_op_keylist_end (c);
662        gpgme_release (c);
663        return err;
664    }
665    
666    
667    /* XXX: kludge to see if the key is stored on a card. */
668    static int
669    key_divert_to_card (gpgme_key_t key)
670    {
671        gpgme_subkey_t k;
672        int n=0, n_alg=0, can_auth = 0;
673    
674        for (k = key->subkeys; k; k = k->next) {
675            n++;
676            if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
677                n_alg++;
678            if (k->can_authenticate)
679                can_auth++;
680        }
681        if (n == 3 && n_alg == 3 && can_auth == 1)
682            return 1;
683        return 0;
684    }
685    
686    
687    static unsigned char*
688    copy_uid_prefs (const unsigned char *prefs)
689    {
690        unsigned char *p;
691        size_t pos=0;
692    
693        while (prefs[pos] != 0)
694            pos++;
695        p = (unsigned char*)calloc (1, pos+1);
696        if (!p)
697            BUG (0);
698        memcpy (p, prefs, pos);
699        return p;
700    }
701    
702    
703    gpgme_error_t
704    gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
705    {
706        struct keycache_s *c, *c_sec;
707        gpgme_key_t key;
708    
709        if (!pub || !sec)
710            return gpg_error (GPG_ERR_INV_ARG);
711        
712        for (c=sec->item; c; c=c->next) {  
713            if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
714                c_sec->gloflags.is_protected = c->gloflags.is_protected;
715                c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
716                if (!c->gloflags.divert_to_card)
717                    c->gloflags.divert_to_card = key_divert_to_card (key);
718                if (c_sec->sym_prefs)
719                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
720                c->pubpart = c_sec;
721                c->pubpart->key = key;
722            }
723        }
724        return 0;
725    }
726    
727    
728    /* Rewind the given cache @ctx to the begin. */
729    void
730    gpg_keycache_rewind (gpg_keycache_t ctx)
731    {
732        if (ctx)
733            ctx->pos = 0;
734    }
735    
736    
737    
738    /* Return the number of elements in the cache @ctx. */
739    int
740    gpg_keycache_get_size (gpg_keycache_t ctx)
741    {
742        struct keycache_s *c;
743        int count = 0;
744        
745        if (!ctx)
746            return 0;
747        for (c = ctx->item; c; c = c->next)
748            count++;
749        return count;
750    }
751    
752    
753    static gpgme_error_t
754    keycache_next_key (gpg_keycache_t ctx, int flags,
755                       struct keycache_s **c, gpgme_key_t *r_key)
756    {      
757        if (!ctx || !r_key)
758            return gpg_error (GPG_ERR_INV_ARG);
759    
760        if (!ctx->pos)
761            ctx->tmp = ctx->item;
762        
763        if (!ctx->tmp || !ctx->tmp->key) {
764            ctx->pos = 0;
765            *r_key = NULL;
766            return gpg_error (GPG_ERR_EOF);
767        }
768        if (ctx->tmp->flags != 0)
769            ctx->tmp->flags = 0; /* reset the 'updated' status. */
770        /* it might be possible there is no public key. */
771        if (flags && ctx->tmp->pubpart == NULL)
772            flags = 0;
773        *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
774        *c = ctx->tmp = ctx->tmp->next;
775        ctx->pos++;
776    
777        return 0;
778    }
779    
780    
781    /* Return the next key from the cache @ctx. The key will be returned
782       in @r_key. @flags can contain additional flags.
783       Return value: 0 on success. */
784    gpgme_error_t
785    gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
786    {
787        struct keycache_s *c=NULL;
788        gpgme_error_t err = 0;
789    
790        err = keycache_next_key (ctx, flags, &c, r_key);
791        return err;
792    }
793    
794    
795    /* Search for a key with the pattern @pattern and mark
796       this key as the default signing key if found.
797       Return value: 0 on success. */
798    gpgme_error_t
799    gpg_keycache_set_default_key (gpg_keycache_t ctx,
800                                  const char *pattern)
801    {
802        gpgme_error_t err;
803        gpgme_key_t key;
804        struct keycache_s *itm;
805    
806        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
807        if (err)
808            return err;
809    
810        if (itm)
811            itm->default_key = 1;
812        return 0;
813    }
814    
815    /* Return the default key from the cache. If no was
816       marked before, NULL is returned in @r_key.
817       Return value: 0 on success. */
818    gpgme_error_t
819    gpg_keycache_get_default_key (gpg_keycache_t ctx,
820                                  gpgme_key_t *r_key)
821    {
822        struct keycache_s *itm;
823    
824        *r_key = NULL;
825        for (itm = ctx->item; itm; itm = itm->next) {
826            if (itm->default_key) {
827                *r_key = itm->key;
828                break;
829            }
830        }
831        if (!*r_key)
832            return gpgme_error (GPG_ERR_NOT_FOUND);
833        return 0;
834    }
835    
836    
837    static gpgme_error_t
838    decode_subpacket (const char *subpkt_data, int *type,
839                      char **out, WORD *outlen)
840    {
841        char tmp[128], *p = tmp, *val;
842        char *enc;
843        size_t pos = 0, i=0;
844    
845        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
846        *outlen = 0;
847        *out = NULL;
848        
849        if (strncmp (subpkt_data, "spk:", 4))
850            return gpg_error (GPG_ERR_NO_DATA);
851    
852        strncpy (tmp, subpkt_data, 62);
853        val = strtok (tmp, ":");
854        while (val != NULL) {
855            switch (pos++) {
856            case 0:
857                break;
858    
859            case 1:
860                if (type)
861                    *type = atoi (val);
862                break;
863    
864            case 2:
865                break;
866    
867            case 3:
868                *outlen = atoi (val);
869                break;
870    
871            case 4:
872                enc = strdup (val);
873                break;
874            }
875            val = strtok (NULL, ":");
876        }
877        if (!enc)
878            return gpg_error (GPG_ERR_NO_DATA);;
879        *out = (char*)calloc (1, strlen (enc)+1);
880        for (pos = 0; pos < strlen (enc); pos++) {
881            if (enc[pos] == '%' && enc[pos+1] == '%')
882                (*out)[i++] = '%';
883            else if (enc[pos] == '%') {
884                char tmp[3];
885                tmp[0] = enc[++pos];
886                tmp[1] = enc[++pos];
887                tmp[2] = 0;
888                (*out)[i++] = (char)strtoul (tmp, NULL, 16);
889            }
890            else
891                (*out)[i++] = enc[pos];
892        }
893        (*out)[i] = 0;
894        free (enc);
895        return 0;
896    }
897    
898    
899    /* If the attribute given in @attr is not set in the
900       key cache object, try to update it. */
901    gpgme_error_t
902    gpg_keycache_update_attr (struct keycache_s *item,
903                              int attr, int force)
904    {
905        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
906        char *val = NULL;
907        WORD n = 0;    
908    
909        switch (attr) {
910        case KC_ATTR_PREFSYM:
911            if (!force && item->sym_prefs)
912                break;
913            safe_free (item->sym_prefs);
914            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
915            if (!err && val != NULL)
916                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
917            break;
918    
919        case KC_ATTR_PREFKSERV:
920            if (!force && item->pref_keyserver)
921                break;
922            safe_free (item->pref_keyserver);
923            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
924            if (!err && val != NULL)
925                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
926            break;
927        }
928        safe_free (val);
929        return err;
930    }
931    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26