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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26