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

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 209 - (show annotations)
Wed May 3 14:34:08 2006 UTC (18 years, 10 months ago) by twoaday
File size: 24618 byte(s)
2006-05-02  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptFileManagerDlg.cpp (file_encrypt_dlg_proc): Use a
        caption for the radio button group.
        * wptKeyserverDlg.cpp (keyserver_recv_key): Use new code.
        * wptKeyserver.cpp (kserver_recvkey, finger_recvkey,
        ldap_recvkey): Avoid fixed buffers.
        (do_spawn_ldap_helper): New.
        (ldap_recvkey): Factor out code into helper function.
        * wptPassphraseCBDlg.cpp (passphrase_callback_proc):
        Increase width of the list box to make sure even large
        user IDs will be completly displayed.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26