/[winpt]/trunk/Src/wptKeyCache.cpp
ViewVC logotype

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 187 - (hide annotations)
Wed Mar 22 11:04:20 2006 UTC (18 years, 11 months ago) by twoaday
File size: 22321 byte(s)
2006-03-21  Timo Schulz  <ts@g10code.de>
 
        * wptUTF8.cpp (native_to_utf8): Use directly W32 API.
        (utf8_to_native): Likewise. Remove cp850 conversion.
        * wptKeyEditDlgs.cpp (do_find_userid): Correct UTF8 handling.
        * wptKeyManager.cpp (km_delete_keys): Do not reset 'with_seckey'
        flag.

Prepare new release...


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26