/[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 150 by twoaday, Wed Jan 18 11:52:45 2006 UTC revision 340 by twoaday, Sun Nov 27 13:15:07 2011 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-2006 Timo Schulz   *      Copyright (C) 2001-2006, 2009 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.
  *  
  * You should have received a copy of the GNU General Public License  
  * along with this program; if not, write to the Free Software  
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA  
15   */   */
16    
17  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
# Line 25  Line 21 
21  #include <windows.h>  #include <windows.h>
22  #include <stdio.h>  #include <stdio.h>
23  #include <string.h>  #include <string.h>
 #include <malloc.h>  
24  #include <ctype.h>  #include <ctype.h>
25  #include <assert.h>  #include <assert.h>
26  #include <gpgme.h>  #include <gpgme.h>
# Line 36  Line 31 
31  #include "wptErrors.h"  #include "wptErrors.h"
32  #include "wptW32API.h"  #include "wptW32API.h"
33  #include "wptGPG.h"  #include "wptGPG.h"
34    #include "wptTypes.h"
35    #include "wptCommonCtl.h"
36    #include "wptContext.h"
37    #include "wptKeyEdit.h"
38    #include "wptUTF8.h"
39    
40    
41    gpgme_error_t parse_keyserver_url (char **r_keyserver, unsigned short *r_port);
42    
43  /* Attribute list which holds the image data. */  /* Attribute list which holds the image data. */
44  struct attr_list_s {  struct attr_list_s {
# Line 49  struct attr_list_s { Line 51  struct attr_list_s {
51  typedef struct attr_list_s *attr_list_t;  typedef struct attr_list_s *attr_list_t;
52    
53    
54  void  static unsigned char*
55    safe_uchar_alloc (size_t n)
56    {
57        unsigned char *p = new unsigned char[n];
58        if (!p)
59            BUG (0);
60        return p;
61    }
62    
63    
64    /* Free attribute list @ctx. */
65    static void
66  free_attr_list (attr_list_t ctx)  free_attr_list (attr_list_t ctx)
67  {  {
68      attr_list_t n;      attr_list_t n;
69    
70      while (ctx) {      while (ctx) {
71          n = ctx->next;          n = ctx->next;
72          free (ctx->fpr);          free_if_alloc (ctx->fpr);
73          free (ctx->d);          free_if_alloc (ctx->d);
74            free_if_alloc (ctx);
75          ctx = n;          ctx = n;
76      }      }
77  }  }
# Line 80  parse_attr_list (FILE *fp, const BYTE *d Line 95  parse_attr_list (FILE *fp, const BYTE *d
95              continue;              continue;
96          buffer = buf+9+10;          buffer = buf+9+10;
97          pos = 0;          pos = 0;
98          c = (attr_list_t)calloc (1, sizeof *c);          c = new attr_list_s;
99            if (!c)
100                BUG (0);
101            memset (c, 0, sizeof *c);
102    
103          p = strtok (buffer, " ");          p = strtok (buffer, " ");
104          while (p != NULL) {          while (p != NULL) {
105              switch (pos) {              switch (pos) {
106              case 0:              case 0:
107                  c->fpr = strdup (p);                  c->fpr = m_strdup (p);
108                  break;                  break;
109                                    
110              case 1:              case 1:
# Line 102  parse_attr_list (FILE *fp, const BYTE *d Line 121  parse_attr_list (FILE *fp, const BYTE *d
121              pos++;              pos++;
122              p = strtok (NULL, " ");              p = strtok (NULL, " ");
123          }          }
         /*printf ("id=%s octets=%d flags=%d\n", c->fpr, c->octets, c->flags);*/  
124          if (!*ctx)          if (!*ctx)
125              *ctx = c;              *ctx = c;
126          else {          else {
# Line 110  parse_attr_list (FILE *fp, const BYTE *d Line 128  parse_attr_list (FILE *fp, const BYTE *d
128                  ;                  ;
129              t->next = c;              t->next = c;
130          }          }
131          c->d = (unsigned char*)malloc (c->octets);          c->d = safe_uchar_alloc (c->octets);
132          memcpy (c->d, data, c->octets);          memcpy (c->d, data, c->octets);
133          data += c->octets;          data += c->octets;
134          datlen -= c->octets;          datlen -= c->octets;
# Line 125  static int Line 143  static int
143  parse_attr_data (const char *keyid, attr_list_t *list)  parse_attr_data (const char *keyid, attr_list_t *list)
144  {  {
145      gpgme_error_t err;      gpgme_error_t err;
146      FILE *tmp;      FILE *tmp;    
     char *status;  
147      BYTE *data;      BYTE *data;
148      DWORD ndata;      char *status, tmpnam[MAX_PATH+1];
149        DWORD ndata = 0;
150    
151      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
152      if (err)      if (err)
153          return err;          return err;
154    
155      if (ndata > 0) {      get_temp_name (tmpnam, MAX_PATH, NULL);
156          tmp = tmpfile ();      tmp = fopen (tmpnam, "w+b");
157        if (ndata > 0 && tmp != NULL) {
158          fwrite (status, 1, strlen (status), tmp);          fwrite (status, 1, strlen (status), tmp);
159          fflush (tmp);          fflush (tmp);
160          rewind (tmp);          rewind (tmp);
   
161          ndata = parse_attr_list (tmp, data, ndata, list);          ndata = parse_attr_list (tmp, data, ndata, list);
         fclose (tmp);  
162      }      }
163      else      else
164          *list = NULL;          *list = NULL;
165        if (tmp != NULL) {
166            fclose (tmp);
167            DeleteFile (tmpnam);
168        }
169    
170      safe_free (status);      safe_free (status);
171      safe_free (data);      safe_free (data);
# Line 171  parse_secring (gpg_keycache_t cache, con Line 192  parse_secring (gpg_keycache_t cache, con
192    
193      gpg_iobuf_ioctl (inp, 3, 1, NULL);      gpg_iobuf_ioctl (inp, 3, 1, NULL);
194      pkt = (PACKET*)calloc (1, sizeof *pkt);      pkt = (PACKET*)calloc (1, sizeof *pkt);
195        if (!pkt)
196            BUG (0);
197      gpg_init_packet (pkt);      gpg_init_packet (pkt);
198      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
199          if (pkt->pkttype == PKT_SECRET_KEY) {          if (pkt->pkttype == PKT_SECRET_KEY) {
# Line 185  parse_secring (gpg_keycache_t cache, con Line 208  parse_secring (gpg_keycache_t cache, con
208                  goto next;                  goto next;
209              c->gloflags.is_protected = sk->is_protected;              c->gloflags.is_protected = sk->is_protected;
210              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
211              if (c->pubpart != NULL) {                  if (c->pubpart != NULL) {
212                  c->pubpart->gloflags.is_protected = sk->is_protected;                      c->pubpart->gloflags.is_protected = sk->is_protected;
213                  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;
214              }              }
215          }          }
# Line 210  keycache_update_photo (gpg_keycache_t ct Line 233  keycache_update_photo (gpg_keycache_t ct
233      gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);      gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
234      if (!fnd)      if (!fnd)
235          return gpg_error (GPG_ERR_NOT_FOUND);          return gpg_error (GPG_ERR_NOT_FOUND);
236      safe_free (fnd->attrib.d);      free_if_alloc (fnd->attrib.d);
237      fnd->attrib.flags = dat->flags;      fnd->attrib.flags = dat->flags;
238      fnd->attrib.len = dat->octets;      fnd->attrib.len = dat->octets;
239      fnd->attrib.d = (unsigned char*)malloc (dat->octets);      fnd->attrib.d = safe_uchar_alloc (dat->octets);
240      memcpy (fnd->attrib.d, dat->d, dat->octets);      memcpy (fnd->attrib.d, dat->d, dat->octets);
241      return 0;      return 0;
242  }  }
# Line 239  keycache_update_photos (gpg_keycache_t c Line 262  keycache_update_photos (gpg_keycache_t c
262  }  }
263    
264    
265    void
266    keycache_decode_uid (struct keycache_s *ctx)
267    {
268        gpgme_user_id_t u;
269        struct native_uid_s *n, *t;
270    
271        for (u = ctx->key->uids; u; u = u->next) {
272            n = new native_uid_s;
273            if (!n)
274                BUG (0);
275            memset (n, 0, sizeof *n);
276            if (is_8bit_string (u->uid)) {
277                n->malloced = 1;
278                n->uid = utf8_to_native (u->uid);
279                if (u->name != NULL)
280                    n->name = utf8_to_native (u->name);
281                if (u->email != NULL)
282                    n->email = m_strdup (u->email);
283                if (u->comment != NULL)
284                    n->comment = utf8_to_native (u->comment);
285            }
286            else {
287                n->malloced = 0;
288                n->uid = u->uid;
289                n->name = u->name;
290                n->comment = u->comment;
291                n->email = u->email;
292            }
293            n->signatures = u->signatures;
294            n->validity = u->validity;
295            n->revoked = u->revoked;
296            if (!ctx->uids)
297                ctx->uids = n;
298            else {
299                for (t = ctx->uids; t->next; t=t->next)
300                    ;
301                t->next = n;          
302            }
303        }
304    }
305    
306    
307    /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
308    static void
309    keycache_decode_uids (gpg_keycache_t ctx)
310    {
311        struct keycache_s *c;
312    
313        for (c = ctx->item; c; c = c->next)
314            keycache_decode_uid (c);
315    }
316    
317    
318    static void
319    free_native_uids (struct native_uid_s **r_n)
320    {
321        struct native_uid_s *t;
322        struct native_uid_s *n = *r_n;
323    
324        while (n != NULL) {
325            t = n->next;
326            if (n->malloced) {
327                free_if_alloc (n->uid);
328                free_if_alloc (n->name);
329                free_if_alloc (n->comment);
330                free_if_alloc (n->email);
331            }
332            free_if_alloc (n);
333            n = t;
334        }
335        *r_n = NULL;
336    }
337    
338    
339    
340  /* Merge the information from the keyrings into the key cache structure. */  /* Merge the information from the keyrings into the key cache structure. */
341  gpgme_error_t  static gpgme_error_t
342  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
343                     const char *pubring, const char *secring)                     const char *pubring, const char *secring)
344  {  {
# Line 249  keycache_prepare2 (gpg_keycache_t ctx, c Line 347  keycache_prepare2 (gpg_keycache_t ctx, c
347      gpg_iobuf_t inp;      gpg_iobuf_t inp;
348      PACKET *pkt;      PACKET *pkt;
349      struct keycache_s *c;      struct keycache_s *c;
350      const byte *sym_prefs;      const BYTE *sym_prefs;
351      char keyid[16+1];      char keyid[16+1];
352      int key_seen = 0;      int key_seen = 0;
353      size_t nsym =0;      size_t nsym =0;
# Line 265  keycache_prepare2 (gpg_keycache_t ctx, c Line 363  keycache_prepare2 (gpg_keycache_t ctx, c
363      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
364    
365      pkt = (PACKET*)calloc (1, sizeof * pkt);      pkt = (PACKET*)calloc (1, sizeof * pkt);
366        if (!pkt)
367            BUG (0);
368      gpg_init_packet (pkt);      gpg_init_packet (pkt);
369      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
370          if (pkt->pkttype == PKT_PUBLIC_KEY) {          if (pkt->pkttype == PKT_PUBLIC_KEY) {
371              strcpy (keyid, "");              strcpy (keyid, "");
372              key_seen = 1;              key_seen = 1;
373          }          }
   
374          if (pkt->pkttype == PKT_SIGNATURE &&          if (pkt->pkttype == PKT_SIGNATURE &&
375              pkt->pkt.signature->sig_class == 0x1F) {              pkt->pkt.signature->sig_class == 0x1F) {
376              if (pkt->pkt.signature->numrevkeys == 0)              if (pkt->pkt.signature->numrevkeys == 0)
# Line 285  keycache_prepare2 (gpg_keycache_t ctx, c Line 384  keycache_prepare2 (gpg_keycache_t ctx, c
384                  goto next;                  goto next;
385              c->gloflags.has_desig_rev = 1;              c->gloflags.has_desig_rev = 1;
386          }          }
387          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 && c != NULL) {
388              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
389                                                SIGSUBPKT_PREF_SYM, &nsym);                                                SIGSUBPKT_PREF_SYM, &nsym);
390              if (!sym_prefs)              if (!sym_prefs)
# Line 295  keycache_prepare2 (gpg_keycache_t ctx, c Line 394  keycache_prepare2 (gpg_keycache_t ctx, c
394              if (kid && strcmp (kid, keyid) != 0)              if (kid && strcmp (kid, keyid) != 0)
395                  goto next;                  goto next;
396              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
397              if (err)              if (err || !c)
398                    goto next;
399                if (c->sym_prefs) // only use the prefs from the primary uid.
400                  goto next;                  goto next;
401              else if (nsym > 0) {              else if (nsym > 0) {
402                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);                  c->sym_prefs = safe_uchar_alloc (nsym+1);
403                  if (!c->sym_prefs)                  memset (c->sym_prefs, 0, nsym+1);
                     return gpg_error (GPG_ERR_ENOMEM);  
404                  memcpy (c->sym_prefs, sym_prefs, nsym);                  memcpy (c->sym_prefs, sym_prefs, nsym);
405              }              }
406          }          }
# Line 340  gpg_keycache_new (gpg_keycache_t *r_ctx) Line 440  gpg_keycache_new (gpg_keycache_t *r_ctx)
440            
441      if (!r_ctx)      if (!r_ctx)
442          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
443      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);      ctx = new gpg_keycache_s;    
444      if (!ctx)      if (!ctx)
445          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
446        memset (ctx, 0, sizeof *ctx);
447      ctx->secret = 0;      ctx->secret = 0;
448      ctx->pos = 0;      ctx->pos = 0;
449      *r_ctx = ctx;      *r_ctx = ctx;
# Line 350  gpg_keycache_new (gpg_keycache_t *r_ctx) Line 451  gpg_keycache_new (gpg_keycache_t *r_ctx)
451  }  }
452    
453    
454    void
455    gpg_keycache_item_release (struct keycache_s *c)
456    {
457        if (c->key)
458            gpgme_key_release (c->key);    
459        c->key = NULL;      
460        if (c->rev != NULL)    
461            gpg_desig_rev_release (c->rev);
462        c->rev = NULL;
463        free_if_alloc (c->pref_keyserver);
464        free_if_alloc (c->sym_prefs);
465        free_if_alloc (c->attrib.d);
466        free_if_alloc (c->card_type);
467        free_native_uids (&c->uids);
468        free_if_alloc (c);
469    }
470    
471    
472  /* Release keycache object @ctx. */  /* Release keycache object @ctx. */
473  void  void
474  gpg_keycache_release (gpg_keycache_t ctx)  gpg_keycache_release (gpg_keycache_t ctx)
# Line 361  gpg_keycache_release (gpg_keycache_t ctx Line 480  gpg_keycache_release (gpg_keycache_t ctx
480    
481      for (c = ctx->item; c; c = c2) {      for (c = ctx->item; c; c = c2) {
482          c2 = c->next;          c2 = c->next;
483          gpgme_key_release (c->key);          gpg_keycache_item_release (c);
         c->key = NULL;  
         safe_free (c->sym_prefs);  
         safe_free (c->attrib.d);  
         safe_free (c->card_type);  
         free (c);  
484      }      }
485      safe_free (ctx);      free_if_alloc (ctx);
486  }  }
487    
488    
# Line 400  gpg_keycache_add_key (gpg_keycache_t ctx Line 514  gpg_keycache_add_key (gpg_keycache_t ctx
514      if (!ctx)      if (!ctx)
515          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
516            
517      c = (struct keycache_s*)calloc (1, sizeof *c);      c = new keycache_s;
518      if (!c)      if (!c)
519          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
520        memset (c, 0, sizeof *c);
521      c->gloflags.is_protected = 1; /*default: assume protection. */      c->gloflags.is_protected = 1; /*default: assume protection. */
522      c->key = key;      c->key = key;
523      if (!ctx->item)      if (!ctx->item)
# Line 515  gpg_keycache_next_updated_key (gpg_keyca Line 630  gpg_keycache_next_updated_key (gpg_keyca
630      for (c = ctx->item; c; c = c->next) {      for (c = ctx->item; c; c = c->next) {
631          if (c->flags != 0) {          if (c->flags != 0) {
632              *r_status = c->flags;              *r_status = c->flags;
             c->flags = 0;  
633              *r_obj = c;              *r_obj = c;
634                c->flags = 0; /* reset update flag. */
635              return 0;              return 0;
636          }          }
637      }      }
# Line 524  gpg_keycache_next_updated_key (gpg_keyca Line 639  gpg_keycache_next_updated_key (gpg_keyca
639  }  }
640    
641    
642    /* Helper to retrieve a GPG key. */
643    static gpgme_error_t
644    get_gpg_key (const char *keyid, int is_sec, gpgme_key_t *r_key)
645    {
646        gpgme_ctx_t ctx;
647        gpgme_error_t err;
648    
649        err = gpgme_new (&ctx);
650        if (err)
651            return err;
652        gpgme_set_keylist_mode  (ctx, GPGME_KEYLIST_MODE_SIGS);
653        err = gpgme_get_key (ctx, keyid, r_key, is_sec);
654        gpgme_release (ctx);
655        return err;
656    }
657    
658    
659    /* Fetch a key directly from gpg but without adding
660       it to the key cache. Caller must free @r_ctx. */
661    gpgme_error_t
662    gpg_keycache_fetch_key (const char *keyid, int is_sec,
663                            gpgme_key_t *r_key, struct keycache_s **r_c)
664    {
665        gpgme_error_t err;
666        gpgme_key_t key;
667        struct keycache_s *c;
668    
669        *r_key = NULL;
670        *r_c = NULL;
671        err = get_gpg_key (keyid, is_sec, &key);
672        if (err)
673            return err;
674    
675        c = new keycache_s;
676        if (!c)
677            BUG (0);
678        memset (c, 0, sizeof *c);
679        c->gloflags.is_protected = 1; /*default: assume protection. */
680        c->key = key;    
681        keycache_decode_uid (c);
682        *r_key = key;
683        *r_c = c;
684        return 0;
685    }
686    
687    
688    /* Update the key with the keyid @key in the key cache.
689       If the key does not exist, it is added otherwise all
690       parts are first freed and then replaced with the updated data. */
691  gpgme_error_t  gpgme_error_t
692  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
693                           void *opaque, const char *keyid)                           void *opaque, const char *keyid)
694  {  {    
     struct keycache_s *c = NULL, *c_new=NULL;  
695      gpgme_key_t key=NULL, fndkey=NULL;      gpgme_key_t key=NULL, fndkey=NULL;
696      gpgme_error_t err;      gpgme_error_t err;
697      gpgme_ctx_t gctx;      struct keycache_s *c = NULL, *c_new=NULL;
698      gpg_keycache_t pub = (gpg_keycache_t)opaque;      gpg_keycache_t pub = (gpg_keycache_t)opaque;
699    
700      err = gpgme_new (&gctx);      err = get_gpg_key (keyid, is_sec, &key);
     if (err)  
         return err;  
     gpgme_set_keylist_mode  (gctx, GPGME_KEYLIST_MODE_SIGS);  
     err = gpgme_get_key (gctx, keyid, &key, is_sec);  
     gpgme_release (gctx);  
701      if (err)      if (err)
702          return err;          return err;
703      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
# Line 571  gpg_keycache_update_key (gpg_keycache_t Line 728  gpg_keycache_update_key (gpg_keycache_t
728                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
729              }              }
730          }          }
731          if (c)          if (c != NULL)
732              c->flags = KC_FLAG_ADD;              c->flags = KC_FLAG_ADD;
733      }      }
734    
735        /* refresh utf8 user ID list. */
736        if (c != NULL && c->key) {
737            free_native_uids (&c->uids);
738            keycache_decode_uid (c);
739        }
740    
741      return 0;      return 0;
742  }  }
743    
# Line 594  gpg_keycache_delete_key (gpg_keycache_t Line 758  gpg_keycache_delete_key (gpg_keycache_t
758          return rc;          return rc;
759            
760      c = ctx->item;      c = ctx->item;
761      if (c->next == NULL) {      if (!c) /* empty */
762          gpgme_key_release (itm->key);          return 0;
763          if (itm)      else if (c->next == NULL) {
764              free (itm);          if (itm->key)
765                gpgme_key_release (itm->key);
766            itm->key = NULL;
767            free_if_alloc (itm);
768            /* the cache has no other items, so we set the context to NULL
769               to indicate that the entire cache is empty. */
770          ctx->item = NULL;          ctx->item = NULL;
771      }      }
772      else {      else {
773          while (c && c->next != itm)          for (; c != NULL; c = c->next) {
774              c = c->next;              if (c->next == itm)
775                    break;
776            }
777            assert (c != NULL); /* XXX: sometimes access violation. */
778          c->next = c->next->next;          c->next = c->next->next;
779          gpgme_key_release (itm->key);          if (itm->key)
780          if (itm)              gpgme_key_release (itm->key);
781              free (itm);          itm->key = NULL;
782            free_if_alloc (itm);
783      }      }
784      return 0;      return 0;
785  }  }
# Line 630  gpg_keycache_init (gpg_keycache_t ctx, c Line 803  gpg_keycache_init (gpg_keycache_t ctx, c
803      if (err)      if (err)
804          return err;          return err;
805    
806        /* XXX: GPGME_KEYLIST_MODE_SIG_NOTATIONS causes an internal error! */
807      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
808      err = gpgme_op_keylist_start (c, pattern, secret);      err = gpgme_op_keylist_start (c, pattern, secret);
809      while(!err) {      while(!err) {
# Line 643  gpg_keycache_init (gpg_keycache_t ctx, c Line 817  gpg_keycache_init (gpg_keycache_t ctx, c
817      if (gpgme_err_code (err) == GPG_ERR_EOF)      if (gpgme_err_code (err) == GPG_ERR_EOF)
818          err = gpg_error (GPG_ERR_NO_ERROR);          err = gpg_error (GPG_ERR_NO_ERROR);
819      keycache_update_photos (ctx);      keycache_update_photos (ctx);
820      /* XXX: make sure the progress dialog is closed. */      keycache_decode_uids (ctx);
821      gpgme_op_keylist_end (c);      gpgme_op_keylist_end (c);
822      gpgme_release (c);      gpgme_release (c);
823      return err;      return err;
824  }  }
825    
826    
827  /* XXX: kludge to see if the key is stored on a card. */  /* Return 1 if we can assume that the actual private key is
828       stored on a smart card. This is not bullet proof, but the
829       card provides 3 keys (RSA) and each key for a different purpose. */
830  static int  static int
831  key_divert_to_card (gpgme_key_t key)  key_divert_to_card (gpgme_key_t key)
832  {  {
833      gpgme_subkey_t k;      gpgme_subkey_t k;
834      int n=0, n_alg=0, can_auth = 0;      int n=0;
835        int can_auth = 0, can_encr = 0;
836    
837      for (k = key->subkeys; k; k = k->next) {      for (k = key->subkeys; k; k = k->next) {
838          n++;          n++;
839          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)          if (k->pubkey_algo != GPGME_PK_RSA || k->length != 1024) {
840              n_alg++;              return 0;
841                break;
842            }
843          if (k->can_authenticate)          if (k->can_authenticate)
844              can_auth++;              can_auth++;
845            if (k->can_encrypt)
846                can_encr++;
847      }      }
848      if (n == 3 && n_alg == 3 && can_auth == 1)      if (n >= 3 && can_auth >= 1 && can_encr >= 1)
849          return 1;          return 1;
850      return 0;      return 0;
851  }  }
# Line 678  copy_uid_prefs (const unsigned char *pre Line 859  copy_uid_prefs (const unsigned char *pre
859    
860      while (prefs[pos] != 0)      while (prefs[pos] != 0)
861          pos++;          pos++;
862      p = (unsigned char*)calloc (1, pos+1);      p = safe_uchar_alloc (pos+1);
863      if (!p)      memset (p, 0, pos+1);
         abort ();  
864      memcpy (p, prefs, pos);      memcpy (p, prefs, pos);
865      return p;      return p;
866  }  }
867    
868    
869    /* Sync the secret and the public key cache information. */
870  gpgme_error_t  gpgme_error_t
871  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
872  {  {
# Line 695  gpg_keycache_sync (gpg_keycache_t pub, g Line 876  gpg_keycache_sync (gpg_keycache_t pub, g
876      if (!pub || !sec)      if (!pub || !sec)
877          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
878            
879      for (c=sec->item; c; c=c->next) {        for (c=sec->item; c; c=c->next) {
880          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,
881                                         &key, &c_sec)) {
882              c_sec->gloflags.is_protected = c->gloflags.is_protected;              c_sec->gloflags.is_protected = c->gloflags.is_protected;
883              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
884              if (!c->gloflags.divert_to_card)              if (!c->gloflags.divert_to_card)
885                  c->gloflags.divert_to_card = key_divert_to_card (key);                  c->gloflags.divert_to_card = key_divert_to_card (key);
886              c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);              if (c_sec->sym_prefs)
887                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
888              c->pubpart = c_sec;              c->pubpart = c_sec;
889              c->pubpart->key = key;              c->pubpart->key = key;
890          }          }
# Line 752  keycache_next_key (gpg_keycache_t ctx, i Line 935  keycache_next_key (gpg_keycache_t ctx, i
935      }      }
936      if (ctx->tmp->flags != 0)      if (ctx->tmp->flags != 0)
937          ctx->tmp->flags = 0; /* reset the 'updated' status. */          ctx->tmp->flags = 0; /* reset the 'updated' status. */
938    
939        /* it might be possible there is no public key. */
940        if (flags && ctx->tmp->pubpart == NULL)
941            flags = 0;
942      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
943      *c = ctx->tmp = ctx->tmp->next;      *c = ctx->tmp;
944        ctx->tmp = ctx->tmp->next;
945      ctx->pos++;      ctx->pos++;
946    
947      return 0;      return 0;
# Line 767  gpgme_error_t Line 955  gpgme_error_t
955  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)
956  {  {
957      struct keycache_s *c=NULL;      struct keycache_s *c=NULL;
958      gpgme_error_t err = 0;      gpgme_error_t err;
959    
960      err = keycache_next_key (ctx, flags, &c, r_key);      err = keycache_next_key (ctx, flags, &c, r_key);
961      return err;      return err;
962  }  }
963    
964    
965    gpgme_error_t
966    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
967                            struct keycache_s **c, gpgme_key_t *r_key)
968    {
969        return keycache_next_key (ctx, flags, c, r_key);
970    }
971    
972    
973    /* Search for a key with the pattern @pattern and mark
974       this key as the default signing key if found.
975       Return value: 0 on success. */
976    gpgme_error_t
977    gpg_keycache_set_default_key (gpg_keycache_t ctx,
978                                  const char *pattern)
979    {
980        gpgme_error_t err;
981        gpgme_key_t key;
982        struct keycache_s *itm;
983    
984        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
985        if (err)
986            return err;
987    
988        if (itm)
989            itm->default_key = 1;
990        return 0;
991    }
992    
993    /* Return the default key from the cache. If no was
994       marked before, NULL is returned in @r_key.
995       Return value: 0 on success. */
996    gpgme_error_t
997    gpg_keycache_get_default_key (gpg_keycache_t ctx,
998                                  gpgme_key_t *r_key)
999    {
1000        struct keycache_s *itm;
1001    
1002        *r_key = NULL;
1003        for (itm = ctx->item; itm; itm = itm->next) {
1004            if (itm->default_key) {
1005                *r_key = itm->key;
1006                break;
1007            }
1008        }
1009        if (!*r_key)
1010            return gpgme_error (GPG_ERR_NOT_FOUND);
1011        return 0;
1012    }
1013    
1014    
1015    /* FIXME: rewrite the subpacket part */
1016    void unhexify_buffer (const char *in, char **r_out);
1017    
1018    static gpgme_error_t
1019    decode_subpacket (const char *subpkt_data, int *type,
1020                      char **out, WORD *outlen)
1021    {
1022        char tmp[128], *val;
1023        char *enc = NULL;      
1024        size_t pos = 0;
1025    
1026        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
1027        *outlen = 0;
1028        *out = NULL;
1029        
1030        if (strncmp (subpkt_data, "spk:", 4))
1031            return gpg_error (GPG_ERR_NO_DATA);
1032    
1033        /* XXX: do not use static buffer sizes. */
1034        strncpy (tmp, subpkt_data, DIM (tmp)-4);
1035        val = strtok (tmp, ":");
1036        while (val != NULL) {
1037            switch (pos++) {
1038            case 0:
1039                break;
1040    
1041            case 1:
1042                if (type)
1043                    *type = atoi (val);
1044                break;
1045    
1046            case 2:
1047                break;
1048    
1049            case 3:
1050                *outlen = atoi (val);
1051                break;
1052    
1053            case 4:
1054                enc = m_strdup (val);
1055                break;
1056            }
1057            val = strtok (NULL, ":");
1058        }
1059        if (!enc)
1060            return gpg_error (GPG_ERR_NO_DATA);
1061        unhexify_buffer (enc, out);
1062        free_if_alloc (enc);
1063        return 0;
1064    }
1065    
1066    
1067    /* If the attribute given in @attr is not set in the
1068       key cache object, try to update it. */
1069    gpgme_error_t
1070    gpg_keycache_update_attr (struct keycache_s *item,
1071                              int attr, int force)
1072    {
1073        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
1074        char *val = NULL;
1075        WORD n = 0;    
1076    
1077        switch (attr) {
1078        case KC_ATTR_PREFSYM:
1079            if (!force && item->sym_prefs)
1080                break;
1081            free_if_alloc (item->sym_prefs);
1082            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1083            if (!err && val != NULL)
1084                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
1085            break;
1086    
1087        case KC_ATTR_PREFKSERV:
1088            if (!force && item->pref_keyserver)
1089                break;
1090            free_if_alloc (item->pref_keyserver);
1091            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1092            if (!err && val != NULL)
1093                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1094            if (!err && item->pref_keyserver)
1095                err = parse_keyserver_url (&item->pref_keyserver,
1096                                           &item->pref_keyserver_port);
1097            break;
1098        }
1099        safe_free (val);
1100        return err;
1101    }

Legend:
Removed from v.150  
changed lines
  Added in v.340

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26