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

Legend:
Removed from v.32  
changed lines
  Added in v.168

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26