/[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 123 by twoaday, Wed Dec 14 09:01:45 2005 UTC revision 260 by twoaday, Wed Aug 16 10:01:30 2006 UTC
# Line 1  Line 1 
1  /* wptKeyCache.cpp- Caching for the pub- and the secring  /* wptKeyCache.cpp- Caching for the pub- and the secring
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2006 Timo Schulz
3   *   *
4   * This file is part of MyGPGME.   * This file is part of WinPT.
5   *   *
6   * MyGPGME is free software; you can redistribute it and/or modify   * WinPT is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * MyGPGME is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
# Line 25  Line 25 
25  #include <windows.h>  #include <windows.h>
26  #include <stdio.h>  #include <stdio.h>
27  #include <string.h>  #include <string.h>
 #include <malloc.h>  
28  #include <ctype.h>  #include <ctype.h>
29  #include <assert.h>  #include <assert.h>
30  #include <gpgme.h>  #include <gpgme.h>
# Line 35  Line 34 
34  #include "wptNLS.h"  #include "wptNLS.h"
35  #include "wptErrors.h"  #include "wptErrors.h"
36  #include "wptW32API.h"  #include "wptW32API.h"
37    #include "wptGPG.h"
38    #include "wptTypes.h"
39    #include "wptCommonCtl.h"
40    #include "wptContext.h"
41    #include "wptKeyEdit.h"
42    #include "wptUTF8.h"
43    
44    
45    gpgme_error_t parse_keyserver_url (char **r_keyserver, unsigned short *r_port);
46    
47    /* Attribute list which holds the image data. */
48    struct attr_list_s {
49        struct attr_list_s *next;
50        char *fpr;                   /* fingerprint of the key */
51        unsigned char *d;            /* actual JPEG data. */
52        unsigned long octets;        /* length of the data. */
53        unsigned int flags;          /* status of the attribute. */
54    };
55    typedef struct attr_list_s *attr_list_t;
56    
57    
58  #if 0  /* XXX: convert it to an inline function and place it in a header file. */
59  /* convert a binary buffer into its hex representation. */  static unsigned char*
60  static void  safe_uchar_alloc (size_t n)
 buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)  
61  {  {
62      char dig[3];      unsigned char *p = new unsigned char[n];
63      size_t i;      if (!p)
64            BUG (0);
65        return p;
66    }
67    
68    
69      memset (dst, 0, dlen);  /* Free attribute list @ctx. */
70      for (i = 0; i < nbytes && dlen > 0; i++) {  void
71          sprintf (dig, "%02X", buf[i]);  free_attr_list (attr_list_t ctx)
72          strcat (dst, dig);  {
73          dlen -= 2;      attr_list_t n;
74    
75        while (ctx) {
76            n = ctx->next;
77            free_if_alloc (ctx->fpr);
78            free_if_alloc (ctx->d);
79            free_if_alloc (ctx);
80            ctx = n;
81      }      }
82  }  }
83  #endif          
84    /* Parse the attribute list in @fp and store it into @ctx.
85       Return value: number of parsed items. */
86    int
87    parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
88    {
89        attr_list_t c, t;
90        char buf[512], *p, *buffer;
91        int pos, n=0;
92        
93        *ctx = NULL;
94        while (fgets (buf, 511, fp)) {
95            if (strstr (buf, "\r\n"))
96                buf[strlen (buf)-2]=0;
97            if (strstr (buf, "\n"))
98                buf[strlen (buf)-1]=0;
99            if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
100                continue;
101            buffer = buf+9+10;
102            pos = 0;
103            c = new attr_list_s;
104            if (!c)
105                BUG (0);
106            memset (c, 0, sizeof *c);
107    
108            p = strtok (buffer, " ");
109            while (p != NULL) {
110                switch (pos) {
111                case 0:
112                    c->fpr = m_strdup (p);
113                    break;
114                    
115                case 1:
116                    c->octets = strtoul (p, NULL, 10);
117                    break;
118                    
119                case 7:
120                    c->flags = strtoul (p, NULL, 10);
121                    break;
122                    
123                default:
124                    break;
125                }
126                pos++;
127                p = strtok (NULL, " ");
128            }
129            if (!*ctx)
130                *ctx = c;
131            else {
132                for (t = *ctx; t->next; t=t->next)
133                    ;
134                t->next = c;
135            }
136            c->d = safe_uchar_alloc (c->octets);
137            memcpy (c->d, data, c->octets);
138            data += c->octets;
139            datlen -= c->octets;
140            n++;
141        }
142        /*assert (datlen == 0); */
143        return n;
144    }
145    
146    
147    static int
148    parse_attr_data (const char *keyid, attr_list_t *list)
149    {
150        gpgme_error_t err;
151        FILE *tmp;    
152        BYTE *data;
153        char *status, tmpnam[MAX_PATH+1];
154        DWORD ndata = 0;
155    
156        err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
157        if (err)
158            return err;
159    
160        get_temp_name (tmpnam, MAX_PATH, NULL);
161        tmp = fopen (tmpnam, "w+b");
162        if (ndata > 0 && tmp != NULL) {
163            fwrite (status, 1, strlen (status), tmp);
164            fflush (tmp);
165            rewind (tmp);
166    
167            ndata = parse_attr_list (tmp, data, ndata, list);
168            fclose (tmp);
169            DeleteFile (tmpnam);
170        }
171        else
172            *list = NULL;
173    
174        safe_free (status);
175        safe_free (data);
176        return ndata;
177    }
178    
179    
180  /* Parse the secret keyring and retrieve some additional information  /* Parse the secret keyring and retrieve some additional information
# Line 60  buffer_to_string (char *dst, size_t dlen Line 182  buffer_to_string (char *dst, size_t dlen
182  static void  static void
183  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
184  {      {    
185      PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);      PACKET *pkt;
186      PKT_secret_key *sk;      PKT_secret_key *sk;
187      gpg_iobuf_t inp;      gpg_iobuf_t inp;
188      gpgme_error_t err;      gpgme_error_t err;
# Line 69  parse_secring (gpg_keycache_t cache, con Line 191  parse_secring (gpg_keycache_t cache, con
191      char keyid[16+1];      char keyid[16+1];
192    
193      inp = gpg_iobuf_open (secring);      inp = gpg_iobuf_open (secring);
194      if (!inp) {      if (!inp)
         safe_free (pkt);  
195          return;          return;
196      }  
197      gpg_iobuf_ioctl (inp, 3, 1, NULL);      gpg_iobuf_ioctl (inp, 3, 1, NULL);
198        pkt = (PACKET*)calloc (1, sizeof *pkt);
199        if (!pkt)
200            BUG (0);
201      gpg_init_packet (pkt);      gpg_init_packet (pkt);
202      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
203          if (pkt->pkttype == PKT_SECRET_KEY) {          if (pkt->pkttype == PKT_SECRET_KEY) {
# Line 88  parse_secring (gpg_keycache_t cache, con Line 212  parse_secring (gpg_keycache_t cache, con
212                  goto next;                  goto next;
213              c->gloflags.is_protected = sk->is_protected;              c->gloflags.is_protected = sk->is_protected;
214              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
215              if (c->pubpart != NULL) {                  if (c->pubpart != NULL) {
216                  c->pubpart->gloflags.is_protected = sk->is_protected;                      c->pubpart->gloflags.is_protected = sk->is_protected;
217                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
218              }              }
219          }          }
# Line 102  next: Line 226  next:
226  }  }
227    
228    
229    /* Update the photo image of a single key with the fingerprint
230       @fpr. The @dat struct contains the new item data. */
231    static gpgme_error_t
232    keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
233    {
234        struct keycache_s *fnd = NULL;
235        gpgme_key_t key;
236        
237        gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
238        if (!fnd)
239            return gpg_error (GPG_ERR_NOT_FOUND);
240        free_if_alloc (fnd->attrib.d);
241        fnd->attrib.flags = dat->flags;
242        fnd->attrib.len = dat->octets;
243        fnd->attrib.d = safe_uchar_alloc (dat->octets);
244        memcpy (fnd->attrib.d, dat->d, dat->octets);
245        return 0;
246    }
247    
248    
249    /* Update all photo images in the cache. */
250    static gpgme_error_t
251    keycache_update_photos (gpg_keycache_t ctx)
252    {
253        attr_list_t list=NULL, n;
254        DWORD ndata;
255    
256        ndata = parse_attr_data (NULL, &list);
257        if (ndata < 1) {
258            free_attr_list (list);
259            return 0;
260        }
261    
262        for (n=list; n; n=n->next)
263            keycache_update_photo (ctx, n->fpr, n);
264        free_attr_list (list);
265        return 0;
266    }
267    
268    
269    void
270    keycache_decode_uid (struct keycache_s *ctx)
271    {
272        gpgme_user_id_t u;
273        struct native_uid_s *n, *t;
274    
275        for (u = ctx->key->uids; u; u = u->next) {
276            n = new native_uid_s;
277            if (!n)
278                BUG (0);
279            memset (n, 0, sizeof *n);
280            if (is_8bit_string (u->uid)) {
281                n->malloced = 1;
282                n->uid = utf8_to_native (u->uid);
283                if (u->name != NULL)
284                    n->name = utf8_to_native (u->name);
285                if (u->email != NULL)
286                    n->email = m_strdup (u->email);
287                if (u->comment != NULL)
288                    n->comment = utf8_to_native (u->comment);
289            }
290            else {
291                n->malloced = 0;
292                n->uid = u->uid;
293                n->name = u->name;
294                n->comment = u->comment;
295                n->email = u->email;
296            }
297            n->signatures = u->signatures;
298            n->validity = u->validity;
299            n->revoked = u->revoked;
300            if (!ctx->uids)
301                ctx->uids = n;
302            else {
303                for (t = ctx->uids; t->next; t=t->next)
304                    ;
305                t->next = n;          
306            }
307        }
308    }
309    
310    
311    /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
312    static void
313    keycache_decode_uids (gpg_keycache_t ctx)
314    {
315        struct keycache_s *c;
316    
317        for (c = ctx->item; c; c = c->next)
318            keycache_decode_uid (c);
319    }
320    
321    
322    static void
323    free_native_uids (struct native_uid_s **r_n)
324    {
325        struct native_uid_s *t;
326        struct native_uid_s *n = *r_n;
327    
328        while (n != NULL) {
329            t = n->next;
330            if (n->malloced) {
331                free_if_alloc (n->uid);
332                free_if_alloc (n->name);
333                free_if_alloc (n->comment);
334                free_if_alloc (n->email);
335            }
336            free_if_alloc (n);
337            n = t;
338        }
339        *r_n = NULL;
340    }
341    
342    
343    
344  /* Merge the information from the keyrings into the key cache structure. */  /* Merge the information from the keyrings into the key cache structure. */
345  gpgme_error_t  static gpgme_error_t
346  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
347                     const char *pubring, const char *secring)                     const char *pubring, const char *secring)
348  {  {
349      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
350      gpgme_key_t key = NULL;      gpgme_key_t key = NULL;
351      gpg_iobuf_t inp;      gpg_iobuf_t inp;
352      PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);      PACKET *pkt;
353      struct keycache_s *c;      struct keycache_s *c;
354      const byte *sym_prefs;      const BYTE *sym_prefs;
355      char keyid[16+1], *id = NULL;      char keyid[16+1];
356      int key_seen = 0;      int key_seen = 0;
357      size_t nsym =0;      size_t nsym =0;
358    
359      if (secring) {      if (secring) {
360          parse_secring (ctx, kid, secring);          parse_secring (ctx, kid, secring);
361          if (!pubring) {          if (!pubring)
             safe_free (pkt);  
362              return 0;              return 0;
         }  
363      }      }
364      inp = gpg_iobuf_open (pubring);      inp = gpg_iobuf_open (pubring);
365      if (!inp) {      if (!inp)
         safe_free (pkt);  
366          return gpg_error (GPG_ERR_KEYRING_OPEN);          return gpg_error (GPG_ERR_KEYRING_OPEN);
     }  
367      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
368    
369        pkt = (PACKET*)calloc (1, sizeof * pkt);
370        if (!pkt)
371            BUG (0);
372      gpg_init_packet (pkt);      gpg_init_packet (pkt);
373      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
374          if (pkt->pkttype == PKT_PUBLIC_KEY) {          if (pkt->pkttype == PKT_PUBLIC_KEY) {
375              strcpy (keyid, "");              strcpy (keyid, "");
376              key_seen = 1;              key_seen = 1;
377          }          }
378            if (pkt->pkttype == PKT_SIGNATURE &&
379          if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {              pkt->pkt.signature->sig_class == 0x1F) {
380              if (pkt->pkt.signature->numrevkeys == 0)              if (pkt->pkt.signature->numrevkeys == 0)
381                  goto next;                  goto next;
382              _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);              _snprintf (keyid, sizeof (keyid) -1, "%08X",
383                            pkt->pkt.signature->keyid[1]);
384              if (kid && strcmp (kid, keyid) != 0)              if (kid && strcmp (kid, keyid) != 0)
385                  goto next;                  goto next;
386              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
# Line 149  keycache_prepare2 (gpg_keycache_t ctx, c Line 388  keycache_prepare2 (gpg_keycache_t ctx, c
388                  goto next;                  goto next;
389              c->gloflags.has_desig_rev = 1;              c->gloflags.has_desig_rev = 1;
390          }          }
391          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 && c != NULL) {
392              sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
393                                              SIGSUBPKT_PREF_SYM, &nsym);                                                SIGSUBPKT_PREF_SYM, &nsym);
394              if (sym_prefs == NULL)              if (!sym_prefs)
395                  goto next;                  goto next;
396              _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);              _snprintf (keyid, sizeof (keyid) - 1, "%08X",
397                            pkt->pkt.signature->keyid[1]);
398              if (kid && strcmp (kid, keyid) != 0)              if (kid && strcmp (kid, keyid) != 0)
399                  goto next;                  goto next;
400              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
401              if (err)              if (err || !c)
402                    goto next;
403                if (c->sym_prefs) // only use the prefs from the primary uid.
404                  goto next;                  goto next;
405              else if (nsym > 0) {              else if (nsym > 0) {
406                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);                  c->sym_prefs = safe_uchar_alloc (nsym+1);
407                  if (!c->sym_prefs)                  memset (c->sym_prefs, 0, nsym+1);
                     return gpg_error (GPG_ERR_ENOMEM);  
408                  memcpy (c->sym_prefs, sym_prefs, nsym);                  memcpy (c->sym_prefs, sym_prefs, nsym);
409              }              }
410          }          }
         if (pkt->pkttype == PKT_USER_ID) {  
             if (id)  
                 free (id);  
             id = strdup (pkt->pkt.user_id->name);  
             if (!id) {  
                 err = gpg_error (GPG_ERR_ENOMEM);  
                 goto fail;  
             }  
         }  
         if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)  
             && pkt->pkt.user_id->attrib_data && key) {  
             PKT_user_id *uid = pkt->pkt.user_id;  
             c->attrib.used = 1;  
             c->attrib.len = uid->attrib_len;  
             c->attrib.d = (unsigned char*)calloc (1, uid->attrib_len + 1);  
             if (!c->attrib.d) {  
                 err = gpg_error (GPG_ERR_ENOMEM);  
                 goto fail;  
             }  
             memcpy (c->attrib.d, uid->attrib_data, uid->attrib_len);  
             key = NULL;  
             c = NULL;  
         }  
411  next:  next:
412          gpg_free_packet (pkt);          gpg_free_packet (pkt);
413          gpg_init_packet(pkt);          gpg_init_packet(pkt);
414      }      }
415    
 fail:  
     safe_free (id);  
416      safe_free (pkt);      safe_free (pkt);
417      gpg_iobuf_close (inp);      gpg_iobuf_close (inp);
418      return err;      return err;
# Line 228  gpg_keycache_new (gpg_keycache_t *r_ctx) Line 444  gpg_keycache_new (gpg_keycache_t *r_ctx)
444            
445      if (!r_ctx)      if (!r_ctx)
446          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
447      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);      ctx = new gpg_keycache_s;    
448      if (!ctx)      if (!ctx)
449          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
450        memset (ctx, 0, sizeof *ctx);
451      ctx->secret = 0;      ctx->secret = 0;
452      ctx->pos = 0;      ctx->pos = 0;
453      *r_ctx = ctx;      *r_ctx = ctx;
# Line 238  gpg_keycache_new (gpg_keycache_t *r_ctx) Line 455  gpg_keycache_new (gpg_keycache_t *r_ctx)
455  }  }
456    
457    
458    void
459    gpg_keycache_item_release (struct keycache_s *c)
460    {
461        if (c->key)
462            gpgme_key_release (c->key);    
463        c->key = NULL;      
464        if (c->rev != NULL)    
465            gpg_desig_rev_release (c->rev);
466        c->rev = NULL;
467        free_if_alloc (c->pref_keyserver);
468        free_if_alloc (c->sym_prefs);
469        free_if_alloc (c->attrib.d);
470        free_if_alloc (c->card_type);
471        free_native_uids (&c->uids);
472        free_if_alloc (c);
473    }
474    
475    
476  /* Release keycache object @ctx. */  /* Release keycache object @ctx. */
477  void  void
478  gpg_keycache_release (gpg_keycache_t ctx)  gpg_keycache_release (gpg_keycache_t ctx)
# Line 249  gpg_keycache_release (gpg_keycache_t ctx Line 484  gpg_keycache_release (gpg_keycache_t ctx
484    
485      for (c = ctx->item; c; c = c2) {      for (c = ctx->item; c; c = c2) {
486          c2 = c->next;          c2 = c->next;
487          gpgme_key_release (c->key);          gpg_keycache_item_release (c);
         c->key = NULL;  
         if (c->sym_prefs)  
             free (c->sym_prefs);  
         c->sym_prefs = NULL;  
         if (c->attrib.d)  
             free (c->attrib.d);  
         c->attrib.d = NULL;  
         if (c->card_type)  
             free (c->card_type);  
         free (c);  
488      }      }
489      if (ctx)      free_if_alloc (ctx);
         free (ctx);  
490  }  }
491    
492    
# Line 294  gpg_keycache_add_key (gpg_keycache_t ctx Line 518  gpg_keycache_add_key (gpg_keycache_t ctx
518      if (!ctx)      if (!ctx)
519          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
520            
521      c = (struct keycache_s*)calloc (1, sizeof *c);      c = new keycache_s;
522      if (!c)      if (!c)
523          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
524        memset (c, 0, sizeof *c);
525      c->gloflags.is_protected = 1; /*default: assume protection. */      c->gloflags.is_protected = 1; /*default: assume protection. */
526      c->key = key;      c->key = key;
527      if (!ctx->item)      if (!ctx->item)
# Line 367  gpg_keycache_find_key2 (gpg_keycache_t c Line 592  gpg_keycache_find_key2 (gpg_keycache_t c
592      }      }
593      *r_key = NULL;      *r_key = NULL;
594      return gpg_error (GPG_ERR_INTERNAL);      return gpg_error (GPG_ERR_INTERNAL);
595  } /* keycache_find_key */  }
596    
597    
598  gpgme_error_t  gpgme_error_t
# Line 378  gpg_keycache_find_key (gpg_keycache_t ct Line 603  gpg_keycache_find_key (gpg_keycache_t ct
603  }  }
604    
605    
606    /* Reload a photo image of a single key with the keyid @keyid.
607       Return value: 0 on success. */
608    static gpgme_error_t
609    keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
610    {
611        attr_list_t list;
612    
613        if (parse_attr_data (keyid, &list) < 1) {
614            free_attr_list (list);
615            return 0;
616        }
617        keycache_update_photo (ctx, list->fpr, list);
618        free_attr_list (list);
619        return 0;
620    }
621    
622    
623    /* Return the next key which was updated. Before it is
624       returned the update flag is cleared.
625       @r_status is 1 for a new key and 2 for an updated key.
626       Return value: 0 on success. */
627    gpgme_error_t
628    gpg_keycache_next_updated_key (gpg_keycache_t ctx,
629                                   struct keycache_s **r_obj,
630                                   int *r_status)
631    {
632        struct keycache_s *c;
633    
634        for (c = ctx->item; c; c = c->next) {
635            if (c->flags != 0) {
636                *r_status = c->flags;
637                *r_obj = c;
638                c->flags = 0; /* reset update flag. */
639                return 0;
640            }
641        }
642        return gpg_error (GPG_ERR_NOT_FOUND);
643    }
644    
645    
646    /* Helper to retrieve a GPG key. */
647    static gpgme_error_t
648    get_gpg_key (const char *keyid, int is_sec, gpgme_key_t *r_key)
649    {
650        gpgme_ctx_t ctx;
651        gpgme_error_t err;
652    
653        err = gpgme_new (&ctx);
654        if (err)
655            return err;
656        gpgme_set_keylist_mode  (ctx, GPGME_KEYLIST_MODE_SIGS);
657        err = gpgme_get_key (ctx, keyid, r_key, is_sec);
658        gpgme_release (ctx);
659        return err;
660    }
661    
662    
663    /* Fetch a key directly from gpg but without adding
664       it to the key cache. Caller must free @r_ctx. */
665    gpgme_error_t
666    gpg_keycache_fetch_key (const char *keyid, int is_sec,
667                            gpgme_key_t *r_key, struct keycache_s **r_c)
668    {
669        gpgme_error_t err;
670        gpgme_key_t key;
671        struct keycache_s *c;
672    
673        *r_key = NULL;
674        *r_c = NULL;
675        err = get_gpg_key (keyid, is_sec, &key);
676        if (err)
677            return err;
678    
679        c = new keycache_s;
680        if (!c)
681            BUG (0);
682        memset (c, 0, sizeof *c);
683        c->gloflags.is_protected = 1; /*default: assume protection. */
684        c->key = key;    
685        keycache_decode_uid (c);
686        *r_key = key;
687        *r_c = c;
688        return 0;
689    }
690    
691    
692    /* Update the key with the keyid @key in the key cache.
693       If the key does not exist, it is added otherwise all
694       parts are first freed and then replaced with the updated data. */
695  gpgme_error_t  gpgme_error_t
696  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
697                           void *opaque, const char *keyid)                           void *opaque, const char *keyid)
698  {  {    
     struct keycache_s *c = NULL, *c_new=NULL;  
699      gpgme_key_t key=NULL, fndkey=NULL;      gpgme_key_t key=NULL, fndkey=NULL;
700      gpgme_error_t err;      gpgme_error_t err;
701      gpgme_ctx_t gctx;      struct keycache_s *c = NULL, *c_new=NULL;
702      gpg_keycache_t pub = (gpg_keycache_t)opaque;      gpg_keycache_t pub = (gpg_keycache_t)opaque;
703    
704      err = gpgme_new (&gctx);      err = get_gpg_key (keyid, is_sec, &key);
     if (err)  
         return err;  
     err = gpgme_get_key (gctx, keyid, &key, is_sec);  
     gpgme_release (gctx);  
705      if (err)      if (err)
706          return err;          return err;
707      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
# Line 400  gpg_keycache_update_key (gpg_keycache_t Line 709  gpg_keycache_update_key (gpg_keycache_t
709          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
710          gpgme_key_release (fndkey);          gpgme_key_release (fndkey);
711          c->key = key;          c->key = key;
712          c->flags = 0;          c->flags = KC_FLAG_UPD;
713          if (is_sec && pub != NULL &&          if (is_sec && pub != NULL &&
714              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
715              log_debug ("keycache update: set public part %p\r\n", fndkey);              log_debug ("keycache update: set public part %p\r\n", fndkey);
716              c->pubpart->key = fndkey;              c->pubpart->key = fndkey;
717          }          }
718            /* XXX: this is also called for keys without a photo-id. */
719            keycache_reload_photo (ctx, keyid);
720      }      }
721      else {      else {
722          log_debug ("keycache add: sync public part\r\n");          log_debug ("keycache add: sync public part\r\n");
# Line 421  gpg_keycache_update_key (gpg_keycache_t Line 732  gpg_keycache_update_key (gpg_keycache_t
732                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
733              }              }
734          }          }
735            if (c != NULL)
736                c->flags = KC_FLAG_ADD;
737        }
738    
739        /* refresh utf8 user ID list. */
740        if (c != NULL && c->key) {
741            free_native_uids (&c->uids);
742            keycache_decode_uid (c);
743      }      }
744    
745      return 0;      return 0;
746  }  }
747    
# Line 442  gpg_keycache_delete_key (gpg_keycache_t Line 762  gpg_keycache_delete_key (gpg_keycache_t
762          return rc;          return rc;
763            
764      c = ctx->item;      c = ctx->item;
765      if (c->next == NULL) {      if (!c) /* empty */
766          gpgme_key_release (itm->key);          return 0;
767          if (itm)      else if (c->next == NULL) {
768              free (itm);          if (itm->key)
769                gpgme_key_release (itm->key);
770            itm->key = NULL;
771            free_if_alloc (itm);
772            /* the cache has no other items, so we set the context to NULL
773               to indicate that the entire cache is empty. */
774          ctx->item = NULL;          ctx->item = NULL;
775      }      }
776      else {      else {
777          while (c && c->next != itm)          for (; c != NULL; c = c->next) {
778              c = c->next;              if (c->next == itm)
779                    break;
780            }
781            assert (c != NULL); /* XXX: sometimes access violation. */
782          c->next = c->next->next;          c->next = c->next->next;
783          gpgme_key_release (itm->key);          if (itm->key)
784          if (itm)              gpgme_key_release (itm->key);
785              free (itm);          itm->key = NULL;
786            free_if_alloc (itm);
787      }      }
788      return 0;      return 0;
789  }  }
# Line 478  gpg_keycache_init (gpg_keycache_t ctx, c Line 807  gpg_keycache_init (gpg_keycache_t ctx, c
807      if (err)      if (err)
808          return err;          return err;
809    
810        /* XXX: GPGME_KEYLIST_MODE_SIG_NOTATIONS causes an internal error! */
811      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
812      err = gpgme_op_keylist_start (c, pattern, secret);      err = gpgme_op_keylist_start (c, pattern, secret);
813      while(!err) {      while(!err) {
# Line 490  gpg_keycache_init (gpg_keycache_t ctx, c Line 820  gpg_keycache_init (gpg_keycache_t ctx, c
820      }      }
821      if (gpgme_err_code (err) == GPG_ERR_EOF)      if (gpgme_err_code (err) == GPG_ERR_EOF)
822          err = gpg_error (GPG_ERR_NO_ERROR);          err = gpg_error (GPG_ERR_NO_ERROR);
823      /* XXX: make sure the progress dialog is closed. */      keycache_update_photos (ctx);
824        keycache_decode_uids (ctx);
825      gpgme_op_keylist_end (c);      gpgme_op_keylist_end (c);
826      gpgme_release (c);      gpgme_release (c);
827      return err;      return err;
828  }  }
829    
830    
831  /* XXX: kludge to see if the key is stored on a card. */  /* Return 1 if we can assume that the actual private key is
832       stored on a smart card. This is not bullet proof, but the
833       card provides 3 keys (RSA) and each key for a different purpose. */
834  static int  static int
835  key_divert_to_card (gpgme_key_t key)  key_divert_to_card (gpgme_key_t key)
836  {  {
837      gpgme_subkey_t k;      gpgme_subkey_t k;
838      int n=0, n_alg=0, can_auth = 0;      int n=0;
839        int can_auth = 0, can_encr = 0;
840    
841      for (k = key->subkeys; k; k = k->next) {      for (k = key->subkeys; k; k = k->next) {
842          n++;          n++;
843          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)          if (k->pubkey_algo != GPGME_PK_RSA || k->length != 1024) {
844              n_alg++;              return 0;
845                break;
846            }
847          if (k->can_authenticate)          if (k->can_authenticate)
848              can_auth++;              can_auth++;
849            if (k->can_encrypt)
850                can_encr++;
851      }      }
852      if (n == 3 && n_alg == 3 && can_auth == 1)      if (n >= 3 && can_auth >= 1 && can_encr >= 1)
853          return 1;          return 1;
854      return 0;      return 0;
855  }  }
# Line 525  copy_uid_prefs (const unsigned char *pre Line 863  copy_uid_prefs (const unsigned char *pre
863    
864      while (prefs[pos] != 0)      while (prefs[pos] != 0)
865          pos++;          pos++;
866      p = (unsigned char*)calloc (1, pos+1);      p = safe_uchar_alloc (pos+1);
867      if (!p)      memset (p, 0, pos+1);
         abort ();  
868      memcpy (p, prefs, pos);      memcpy (p, prefs, pos);
869      return p;      return p;
870  }  }
871    
872    
873    /* Sync the secret and the public key cache information. */
874  gpgme_error_t  gpgme_error_t
875  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
876  {  {
# Line 542  gpg_keycache_sync (gpg_keycache_t pub, g Line 880  gpg_keycache_sync (gpg_keycache_t pub, g
880      if (!pub || !sec)      if (!pub || !sec)
881          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
882            
883      for (c=sec->item; c; c=c->next) {        for (c=sec->item; c; c=c->next) {
884          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0,
885                                         &key, &c_sec)) {
886              c_sec->gloflags.is_protected = c->gloflags.is_protected;              c_sec->gloflags.is_protected = c->gloflags.is_protected;
887              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
888              if (!c->gloflags.divert_to_card)              if (!c->gloflags.divert_to_card)
889                  c->gloflags.divert_to_card = key_divert_to_card (key);                  c->gloflags.divert_to_card = key_divert_to_card (key);
890              c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);              if (c_sec->sym_prefs)
891                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
892              c->pubpart = c_sec;              c->pubpart = c_sec;
893              c->pubpart->key = key;              c->pubpart->key = key;
894          }          }
# Line 597  keycache_next_key (gpg_keycache_t ctx, i Line 937  keycache_next_key (gpg_keycache_t ctx, i
937          *r_key = NULL;          *r_key = NULL;
938          return gpg_error (GPG_ERR_EOF);          return gpg_error (GPG_ERR_EOF);
939      }      }
940            if (ctx->tmp->flags != 0)
941            ctx->tmp->flags = 0; /* reset the 'updated' status. */
942    
943        /* it might be possible there is no public key. */
944        if (flags && ctx->tmp->pubpart == NULL)
945            flags = 0;
946      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
947      *c = ctx->tmp = ctx->tmp->next;      *c = ctx->tmp;
948        ctx->tmp = ctx->tmp->next;
949      ctx->pos++;      ctx->pos++;
950    
951      return 0;      return 0;
# Line 613  gpgme_error_t Line 959  gpgme_error_t
959  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
960  {  {
961      struct keycache_s *c=NULL;      struct keycache_s *c=NULL;
962      gpgme_error_t err = 0;      gpgme_error_t err;
963    
964      err = keycache_next_key (ctx, flags, &c, r_key);      err = keycache_next_key (ctx, flags, &c, r_key);
965      return err;      return err;
966  }  }
967    
968    
969    gpgme_error_t
970    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
971                            struct keycache_s **c, gpgme_key_t *r_key)
972    {
973        return keycache_next_key (ctx, flags, c, r_key);
974    }
975    
976    
977    /* Search for a key with the pattern @pattern and mark
978       this key as the default signing key if found.
979       Return value: 0 on success. */
980    gpgme_error_t
981    gpg_keycache_set_default_key (gpg_keycache_t ctx,
982                                  const char *pattern)
983    {
984        gpgme_error_t err;
985        gpgme_key_t key;
986        struct keycache_s *itm;
987    
988        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
989        if (err)
990            return err;
991    
992        if (itm)
993            itm->default_key = 1;
994        return 0;
995    }
996    
997    /* Return the default key from the cache. If no was
998       marked before, NULL is returned in @r_key.
999       Return value: 0 on success. */
1000    gpgme_error_t
1001    gpg_keycache_get_default_key (gpg_keycache_t ctx,
1002                                  gpgme_key_t *r_key)
1003    {
1004        struct keycache_s *itm;
1005    
1006        *r_key = NULL;
1007        for (itm = ctx->item; itm; itm = itm->next) {
1008            if (itm->default_key) {
1009                *r_key = itm->key;
1010                break;
1011            }
1012        }
1013        if (!*r_key)
1014            return gpgme_error (GPG_ERR_NOT_FOUND);
1015        return 0;
1016    }
1017    
1018    
1019    static gpgme_error_t
1020    decode_subpacket (const char *subpkt_data, int *type,
1021                      char **out, WORD *outlen)
1022    {
1023        char tmp[128], *val;
1024        char *enc = NULL;      
1025        size_t pos = 0;
1026    
1027        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
1028        *outlen = 0;
1029        *out = NULL;
1030        
1031        if (strncmp (subpkt_data, "spk:", 4))
1032            return gpg_error (GPG_ERR_NO_DATA);
1033    
1034        /* XXX: do not use static buffer sizes. */
1035        strncpy (tmp, subpkt_data, DIM (tmp)-4);
1036        val = strtok (tmp, ":");
1037        while (val != NULL) {
1038            switch (pos++) {
1039            case 0:
1040                break;
1041    
1042            case 1:
1043                if (type)
1044                    *type = atoi (val);
1045                break;
1046    
1047            case 2:
1048                break;
1049    
1050            case 3:
1051                *outlen = atoi (val);
1052                break;
1053    
1054            case 4:
1055                enc = m_strdup (val);
1056                break;
1057            }
1058            val = strtok (NULL, ":");
1059        }
1060        if (!enc)
1061            return gpg_error (GPG_ERR_NO_DATA);
1062        unhexify_buffer (enc, out);
1063        free_if_alloc (enc);
1064        return 0;
1065    }
1066    
1067    
1068    /* If the attribute given in @attr is not set in the
1069       key cache object, try to update it. */
1070    gpgme_error_t
1071    gpg_keycache_update_attr (struct keycache_s *item,
1072                              int attr, int force)
1073    {
1074        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
1075        char *val = NULL;
1076        WORD n = 0;    
1077    
1078        switch (attr) {
1079        case KC_ATTR_PREFSYM:
1080            if (!force && item->sym_prefs)
1081                break;
1082            free_if_alloc (item->sym_prefs);
1083            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1084            if (!err && val != NULL)
1085                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
1086            break;
1087    
1088        case KC_ATTR_PREFKSERV:
1089            if (!force && item->pref_keyserver)
1090                break;
1091            free_if_alloc (item->pref_keyserver);
1092            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1093            if (!err && val != NULL)
1094                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1095            if (!err && item->pref_keyserver)
1096                err = parse_keyserver_url (&item->pref_keyserver,
1097                                           &item->pref_keyserver_port);
1098            break;
1099        }
1100        safe_free (val);
1101        return err;
1102    }

Legend:
Removed from v.123  
changed lines
  Added in v.260

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26