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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 214 - (show annotations)
Sun May 14 18:40:36 2006 UTC (18 years, 9 months ago) by twoaday
File size: 24823 byte(s)
2006-05-14  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeyCache.cpp (gpg_keycache_update_attr): Parse
        preferred keyserver URL.
        * wptHTTP.cpp (extractHostInfo): Fix segv.
        * wptGPGUtil.cpp (gpg_find_key_subpacket): Ignore default
        gpg.conf.
        * wptKeyserverSearchDlg.cpp (search_hkp_keys): Do not
        assume an existing user id.
        * wptPassphraseCB.cpp (passphrase_cb): Automatic cancel
        if no passphrase is available.

(for complete list of changes, see Src/ChangeLog)

About to release 0.12.1


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26