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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 207 - (hide annotations)
Fri Apr 28 10:28:24 2006 UTC (18 years, 10 months ago) by twoaday
File size: 24167 byte(s)
Bug fixes and cleanups.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26