Line data Source code
1 : /* keylist.c - Listing keys.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007,
4 : 2008, 2009 g10 Code GmbH
5 :
6 : This file is part of GPGME.
7 :
8 : GPGME is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as
10 : published by the Free Software Foundation; either version 2.1 of
11 : the License, or (at your option) any later version.
12 :
13 : GPGME is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public
19 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #ifdef HAVE_SYS_TYPES_H
29 : /* Solaris 8 needs sys/types.h before time.h. */
30 : # include <sys/types.h>
31 : #endif
32 : #include <time.h>
33 : #include <assert.h>
34 : #include <ctype.h>
35 : #include <errno.h>
36 :
37 : /* Suppress warning for accessing deprecated member "class". */
38 : #define _GPGME_IN_GPGME
39 : #include "gpgme.h"
40 : #include "util.h"
41 : #include "context.h"
42 : #include "ops.h"
43 : #include "debug.h"
44 :
45 :
46 : struct key_queue_item_s
47 : {
48 : struct key_queue_item_s *next;
49 : gpgme_key_t key;
50 : };
51 :
52 : typedef struct
53 : {
54 : struct _gpgme_op_keylist_result result;
55 :
56 : gpgme_key_t tmp_key;
57 :
58 : /* This points to the last uid in tmp_key. */
59 : gpgme_user_id_t tmp_uid;
60 :
61 : /* This points to the last sig in tmp_uid. */
62 : gpgme_key_sig_t tmp_keysig;
63 :
64 : /* Something new is available. */
65 : int key_cond;
66 : struct key_queue_item_s *key_queue;
67 : } *op_data_t;
68 :
69 :
70 : static void
71 57 : release_op_data (void *hook)
72 : {
73 57 : op_data_t opd = (op_data_t) hook;
74 57 : struct key_queue_item_s *key = opd->key_queue;
75 :
76 57 : if (opd->tmp_key)
77 0 : gpgme_key_unref (opd->tmp_key);
78 :
79 : /* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key,
80 : so we do not need to release them here. */
81 :
82 114 : while (key)
83 : {
84 0 : struct key_queue_item_s *next = key->next;
85 :
86 0 : gpgme_key_unref (key->key);
87 0 : key = next;
88 : }
89 57 : }
90 :
91 :
92 : gpgme_keylist_result_t
93 3 : gpgme_op_keylist_result (gpgme_ctx_t ctx)
94 : {
95 : void *hook;
96 : op_data_t opd;
97 : gpgme_error_t err;
98 :
99 3 : TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_result", ctx);
100 :
101 3 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
102 3 : opd = hook;
103 3 : if (err || !opd)
104 : {
105 0 : TRACE_SUC0 ("result=(null)");
106 0 : return NULL;
107 : }
108 :
109 3 : TRACE_LOG1 ("truncated = %i", opd->result.truncated);
110 :
111 3 : TRACE_SUC1 ("result=%p", &opd->result);
112 3 : return &opd->result;
113 : }
114 :
115 :
116 : static gpgme_error_t
117 58 : keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
118 : {
119 58 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
120 : gpgme_error_t err;
121 : void *hook;
122 : op_data_t opd;
123 :
124 58 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
125 58 : opd = hook;
126 58 : if (err)
127 0 : return err;
128 :
129 58 : switch (code)
130 : {
131 : case GPGME_STATUS_TRUNCATED:
132 0 : opd->result.truncated = 1;
133 0 : break;
134 :
135 : default:
136 58 : break;
137 : }
138 58 : return 0;
139 : }
140 :
141 :
142 : static void
143 172 : set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
144 : {
145 515 : while (*src && !isdigit (*src))
146 : {
147 171 : switch (*src)
148 : {
149 : case 'e':
150 2 : subkey->expired = 1;
151 2 : break;
152 :
153 : case 'r':
154 0 : subkey->revoked = 1;
155 0 : break;
156 :
157 : case 'd':
158 : /* Note that gpg 1.3 won't print that anymore but only uses
159 : the capabilities field. */
160 0 : subkey->disabled = 1;
161 0 : break;
162 :
163 : case 'i':
164 0 : subkey->invalid = 1;
165 0 : break;
166 : }
167 171 : src++;
168 : }
169 172 : }
170 :
171 :
172 : static void
173 88 : set_mainkey_trust_info (gpgme_key_t key, const char *src)
174 : {
175 : /* First set the trust info of the main key (the first subkey). */
176 88 : set_subkey_trust_info (key->subkeys, src);
177 :
178 : /* Now set the summarized trust info. */
179 263 : while (*src && !isdigit (*src))
180 : {
181 87 : switch (*src)
182 : {
183 : case 'e':
184 0 : key->expired = 1;
185 0 : break;
186 :
187 : case 'r':
188 0 : key->revoked = 1;
189 0 : break;
190 :
191 : case 'd':
192 : /* Note that gpg 1.3 won't print that anymore but only uses
193 : the capabilities field. However, it is still used for
194 : external key listings. */
195 0 : key->disabled = 1;
196 0 : break;
197 :
198 : case 'i':
199 0 : key->invalid = 1;
200 0 : break;
201 : }
202 87 : src++;
203 : }
204 88 : }
205 :
206 :
207 : static void
208 180 : set_userid_flags (gpgme_key_t key, const char *src)
209 : {
210 180 : gpgme_user_id_t uid = key->_last_uid;
211 :
212 180 : assert (uid);
213 : /* Look at letters and stop at the first digit. */
214 538 : while (*src && !isdigit (*src))
215 : {
216 178 : switch (*src)
217 : {
218 : case 'r':
219 0 : uid->revoked = 1;
220 0 : break;
221 :
222 : case 'i':
223 0 : uid->invalid = 1;
224 0 : break;
225 :
226 : case 'n':
227 4 : uid->validity = GPGME_VALIDITY_NEVER;
228 4 : break;
229 :
230 : case 'm':
231 0 : uid->validity = GPGME_VALIDITY_MARGINAL;
232 0 : break;
233 :
234 : case 'f':
235 0 : uid->validity = GPGME_VALIDITY_FULL;
236 0 : break;
237 :
238 : case 'u':
239 2 : uid->validity = GPGME_VALIDITY_ULTIMATE;
240 2 : break;
241 : }
242 178 : src++;
243 : }
244 180 : }
245 :
246 :
247 : static void
248 172 : set_subkey_capability (gpgme_subkey_t subkey, const char *src)
249 : {
250 1026 : while (*src)
251 : {
252 682 : switch (*src)
253 : {
254 : case 'e':
255 86 : subkey->can_encrypt = 1;
256 86 : break;
257 :
258 : case 's':
259 86 : subkey->can_sign = 1;
260 86 : break;
261 :
262 : case 'c':
263 88 : subkey->can_certify = 1;
264 88 : break;
265 :
266 : case 'a':
267 82 : subkey->can_authenticate = 1;
268 82 : break;
269 :
270 : case 'q':
271 0 : subkey->is_qualified = 1;
272 0 : break;
273 :
274 : case 'd':
275 0 : subkey->disabled = 1;
276 0 : break;
277 : }
278 682 : src++;
279 : }
280 172 : }
281 :
282 :
283 : static void
284 88 : set_mainkey_capability (gpgme_key_t key, const char *src)
285 : {
286 : /* First set the capabilities of the main key (the first subkey). */
287 88 : set_subkey_capability (key->subkeys, src);
288 :
289 774 : while (*src)
290 : {
291 598 : switch (*src)
292 : {
293 : case 'd':
294 : case 'D':
295 : /* Note, that this flag is also set using the key validity
296 : field for backward compatibility with gpg 1.2. We use d
297 : and D, so that a future gpg version will be able to
298 : disable certain subkeys. Currently it is expected that
299 : gpg sets this for the primary key. */
300 0 : key->disabled = 1;
301 0 : break;
302 :
303 : case 'e':
304 : case 'E':
305 88 : key->can_encrypt = 1;
306 88 : break;
307 :
308 : case 's':
309 : case 'S':
310 170 : key->can_sign = 1;
311 170 : break;
312 :
313 : case 'c':
314 : case 'C':
315 176 : key->can_certify = 1;
316 176 : break;
317 :
318 : case 'a':
319 : case 'A':
320 164 : key->can_authenticate = 1;
321 164 : break;
322 :
323 : case 'q':
324 : case 'Q':
325 0 : key->is_qualified = 1;
326 0 : break;
327 : }
328 598 : src++;
329 : }
330 88 : }
331 :
332 :
333 : static void
334 88 : set_ownertrust (gpgme_key_t key, const char *src)
335 : {
336 : /* Look at letters and stop at the first digit. */
337 258 : while (*src && !isdigit (*src))
338 : {
339 82 : switch (*src)
340 : {
341 : case 'n':
342 0 : key->owner_trust = GPGME_VALIDITY_NEVER;
343 0 : break;
344 :
345 : case 'm':
346 0 : key->owner_trust = GPGME_VALIDITY_MARGINAL;
347 0 : break;
348 :
349 : case 'f':
350 0 : key->owner_trust = GPGME_VALIDITY_FULL;
351 0 : break;
352 :
353 : case 'u':
354 0 : key->owner_trust = GPGME_VALIDITY_ULTIMATE;
355 0 : break;
356 :
357 : default:
358 82 : key->owner_trust = GPGME_VALIDITY_UNKNOWN;
359 82 : break;
360 : }
361 82 : src++;
362 : }
363 88 : }
364 :
365 :
366 : /* Parse field 15 of a secret key or subkey. This fields holds a
367 : reference to smartcards. FIELD is the content of the field and we
368 : are allowed to modify it. */
369 : static gpg_error_t
370 4 : parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field)
371 : {
372 4 : if (!*field)
373 : ; /* Empty. */
374 4 : else if (*field == '#')
375 : {
376 : /* This is a stub for an offline key. We reset the SECRET flag
377 : of the subkey here. Note that the secret flag of the entire
378 : key will be true even then. We even explicitly set
379 : key->secret to make it works for GPGME_KEYLIST_MODE_WITH_SECRET. */
380 0 : subkey->secret = 0;
381 0 : key->secret = 1;
382 : }
383 4 : else if (strchr ("01234567890ABCDEFabcdef", *field))
384 : {
385 : /* Fields starts with a hex digit; thus it is a serial number. */
386 0 : key->secret = 1;
387 0 : subkey->is_cardkey = 1;
388 0 : subkey->card_number = strdup (field);
389 0 : if (!subkey->card_number)
390 0 : return gpg_error_from_syserror ();
391 : }
392 4 : else if (*field == '+')
393 : {
394 4 : key->secret = 1;
395 4 : subkey->secret = 1;
396 : }
397 : else
398 : {
399 : /* RFU. */
400 : }
401 :
402 4 : return 0;
403 : }
404 :
405 :
406 : /* We have read an entire key into tmp_key and should now finish it.
407 : It is assumed that this releases tmp_key. */
408 : static void
409 145 : finish_key (gpgme_ctx_t ctx, op_data_t opd)
410 : {
411 145 : gpgme_key_t key = opd->tmp_key;
412 :
413 145 : opd->tmp_key = NULL;
414 145 : opd->tmp_uid = NULL;
415 145 : opd->tmp_keysig = NULL;
416 :
417 145 : if (key)
418 88 : _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
419 145 : }
420 :
421 :
422 : /* Note: We are allowed to modify LINE. */
423 : static gpgme_error_t
424 640 : keylist_colon_handler (void *priv, char *line)
425 : {
426 640 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
427 : enum
428 : {
429 : RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
430 : RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
431 : }
432 640 : rectype = RT_NONE;
433 : #define NR_FIELDS 17
434 : char *field[NR_FIELDS];
435 640 : int fields = 0;
436 : void *hook;
437 : op_data_t opd;
438 : gpgme_error_t err;
439 : gpgme_key_t key;
440 640 : gpgme_subkey_t subkey = NULL;
441 640 : gpgme_key_sig_t keysig = NULL;
442 :
443 640 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
444 640 : opd = hook;
445 640 : if (err)
446 0 : return err;
447 :
448 640 : key = opd->tmp_key;
449 :
450 640 : TRACE2 (DEBUG_CTX, "gpgme:keylist_colon_handler", ctx,
451 : "key = %p, line = %s", key, line ? line : "(null)");
452 :
453 640 : if (!line)
454 : {
455 : /* End Of File. */
456 57 : finish_key (ctx, opd);
457 57 : return 0;
458 : }
459 :
460 9517 : while (line && fields < NR_FIELDS)
461 : {
462 8351 : field[fields++] = line;
463 8351 : line = strchr (line, ':');
464 8351 : if (line)
465 8105 : *(line++) = '\0';
466 : }
467 :
468 583 : if (!strcmp (field[0], "sig"))
469 5 : rectype = RT_SIG;
470 578 : else if (!strcmp (field[0], "rev"))
471 0 : rectype = RT_REV;
472 578 : else if (!strcmp (field[0], "pub"))
473 80 : rectype = RT_PUB;
474 498 : else if (!strcmp (field[0], "sec"))
475 2 : rectype = RT_SEC;
476 496 : else if (!strcmp (field[0], "crt"))
477 4 : rectype = RT_CRT;
478 492 : else if (!strcmp (field[0], "crs"))
479 2 : rectype = RT_CRS;
480 490 : else if (!strcmp (field[0], "fpr") && key)
481 172 : rectype = RT_FPR;
482 318 : else if (!strcmp (field[0], "uid") && key)
483 180 : rectype = RT_UID;
484 138 : else if (!strcmp (field[0], "sub") && key)
485 82 : rectype = RT_SUB;
486 56 : else if (!strcmp (field[0], "ssb") && key)
487 2 : rectype = RT_SSB;
488 54 : else if (!strcmp (field[0], "spk") && key)
489 0 : rectype = RT_SPK;
490 : else
491 54 : rectype = RT_NONE;
492 :
493 : /* Only look at signatures immediately following a user ID. For
494 : this, clear the user ID pointer when encountering anything but a
495 : signature. */
496 583 : if (rectype != RT_SIG && rectype != RT_REV)
497 578 : opd->tmp_uid = NULL;
498 :
499 : /* Only look at subpackets immediately following a signature. For
500 : this, clear the signature pointer when encountering anything but
501 : a subpacket. */
502 583 : if (rectype != RT_SPK)
503 583 : opd->tmp_keysig = NULL;
504 :
505 583 : switch (rectype)
506 : {
507 : case RT_PUB:
508 : case RT_SEC:
509 : case RT_CRT:
510 : case RT_CRS:
511 : /* Start a new keyblock. */
512 88 : err = _gpgme_key_new (&key);
513 88 : if (err)
514 0 : return err;
515 88 : key->keylist_mode = ctx->keylist_mode;
516 88 : err = _gpgme_key_add_subkey (key, &subkey);
517 88 : if (err)
518 : {
519 0 : gpgme_key_unref (key);
520 0 : return err;
521 : }
522 :
523 88 : if (rectype == RT_SEC || rectype == RT_CRS)
524 4 : key->secret = subkey->secret = 1;
525 88 : if (rectype == RT_CRT || rectype == RT_CRS)
526 6 : key->protocol = GPGME_PROTOCOL_CMS;
527 88 : finish_key (ctx, opd);
528 88 : opd->tmp_key = key;
529 :
530 : /* Field 2 has the trust info. */
531 88 : if (fields >= 2)
532 88 : set_mainkey_trust_info (key, field[1]);
533 :
534 : /* Field 3 has the key length. */
535 88 : if (fields >= 3)
536 : {
537 88 : int i = atoi (field[2]);
538 : /* Ignore invalid values. */
539 88 : if (i > 1)
540 88 : subkey->length = i;
541 : }
542 :
543 : /* Field 4 has the public key algorithm. */
544 88 : if (fields >= 4)
545 : {
546 88 : int i = atoi (field[3]);
547 88 : if (i >= 1 && i < 128)
548 88 : subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
549 : }
550 :
551 : /* Field 5 has the long keyid. Allow short key IDs for the
552 : output of an external keyserver listing. */
553 88 : if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1)
554 88 : strcpy (subkey->_keyid, field[4]);
555 :
556 : /* Field 6 has the timestamp (seconds). */
557 88 : if (fields >= 6)
558 88 : subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
559 :
560 : /* Field 7 has the expiration time (seconds). */
561 88 : if (fields >= 7)
562 88 : subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
563 :
564 : /* Field 8 has the X.509 serial number. */
565 88 : if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
566 : {
567 6 : key->issuer_serial = strdup (field[7]);
568 6 : if (!key->issuer_serial)
569 0 : return gpg_error_from_syserror ();
570 : }
571 :
572 : /* Field 9 has the ownertrust. */
573 88 : if (fields >= 9)
574 88 : set_ownertrust (key, field[8]);
575 :
576 : /* Field 10 is not used for gpg due to --fixed-list-mode option
577 : but GPGSM stores the issuer name. */
578 88 : if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
579 6 : if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
580 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
581 :
582 : /* Field 11 has the signature class. */
583 :
584 : /* Field 12 has the capabilities. */
585 88 : if (fields >= 12)
586 88 : set_mainkey_capability (key, field[11]);
587 :
588 : /* Field 15 carries special flags of a secret key. */
589 88 : if (fields >= 15
590 85 : && (key->secret
591 83 : || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
592 : {
593 2 : err = parse_sec_field15 (key, subkey, field[14]);
594 2 : if (err)
595 0 : return err;
596 : }
597 :
598 : /* Field 17 has the curve name for ECC. */
599 88 : if (fields >= 17 && *field[16])
600 : {
601 0 : subkey->curve = strdup (field[16]);
602 0 : if (!subkey->curve)
603 0 : return gpg_error_from_syserror ();
604 : }
605 :
606 88 : break;
607 :
608 : case RT_SUB:
609 : case RT_SSB:
610 : /* Start a new subkey. */
611 84 : err = _gpgme_key_add_subkey (key, &subkey);
612 84 : if (err)
613 0 : return err;
614 :
615 84 : if (rectype == RT_SSB)
616 2 : subkey->secret = 1;
617 :
618 : /* Field 2 has the trust info. */
619 84 : if (fields >= 2)
620 84 : set_subkey_trust_info (subkey, field[1]);
621 :
622 : /* Field 3 has the key length. */
623 84 : if (fields >= 3)
624 : {
625 84 : int i = atoi (field[2]);
626 : /* Ignore invalid values. */
627 84 : if (i > 1)
628 84 : subkey->length = i;
629 : }
630 :
631 : /* Field 4 has the public key algorithm. */
632 84 : if (fields >= 4)
633 : {
634 84 : int i = atoi (field[3]);
635 84 : if (i >= 1 && i < 128)
636 84 : subkey->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
637 : }
638 :
639 : /* Field 5 has the long keyid. */
640 84 : if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
641 84 : strcpy (subkey->_keyid, field[4]);
642 :
643 : /* Field 6 has the timestamp (seconds). */
644 84 : if (fields >= 6)
645 84 : subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
646 :
647 : /* Field 7 has the expiration time (seconds). */
648 84 : if (fields >= 7)
649 84 : subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
650 :
651 : /* Field 8 is reserved (LID). */
652 : /* Field 9 has the ownertrust. */
653 : /* Field 10, the user ID, is n/a for a subkey. */
654 :
655 : /* Field 11 has the signature class. */
656 :
657 : /* Field 12 has the capabilities. */
658 84 : if (fields >= 12)
659 84 : set_subkey_capability (subkey, field[11]);
660 :
661 : /* Field 15 carries special flags of a secret key. */
662 84 : if (fields >= 15
663 84 : && (key->secret
664 82 : || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET)))
665 : {
666 2 : err = parse_sec_field15 (key, subkey, field[14]);
667 2 : if (err)
668 0 : return err;
669 : }
670 :
671 : /* Field 17 has the curve name for ECC. */
672 84 : if (fields >= 17 && *field[16])
673 : {
674 0 : subkey->curve = strdup (field[16]);
675 0 : if (!subkey->curve)
676 0 : return gpg_error_from_syserror ();
677 : }
678 :
679 84 : break;
680 :
681 : case RT_UID:
682 : /* Field 2 has the trust info, and field 10 has the user ID. */
683 180 : if (fields >= 10)
684 : {
685 180 : if (_gpgme_key_append_name (key, field[9], 1))
686 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
687 : else
688 : {
689 180 : if (field[1])
690 180 : set_userid_flags (key, field[1]);
691 180 : opd->tmp_uid = key->_last_uid;
692 : }
693 : }
694 180 : break;
695 :
696 : case RT_FPR:
697 : /* Field 10 has the fingerprint (take only the first one). */
698 172 : if (fields >= 10 && field[9] && *field[9])
699 : {
700 : /* Need to apply it to the last subkey because all subkeys
701 : do have fingerprints. */
702 172 : subkey = key->_last_subkey;
703 172 : if (!subkey->fpr)
704 : {
705 172 : subkey->fpr = strdup (field[9]);
706 172 : if (!subkey->fpr)
707 0 : return gpg_error_from_syserror ();
708 : }
709 : }
710 :
711 : /* Field 13 has the gpgsm chain ID (take only the first one). */
712 172 : if (fields >= 13 && !key->chain_id && *field[12])
713 : {
714 6 : key->chain_id = strdup (field[12]);
715 6 : if (!key->chain_id)
716 0 : return gpg_error_from_syserror ();
717 : }
718 172 : break;
719 :
720 : case RT_SIG:
721 : case RT_REV:
722 5 : if (!opd->tmp_uid)
723 1 : return 0;
724 :
725 : /* Start a new (revoked) signature. */
726 4 : assert (opd->tmp_uid == key->_last_uid);
727 4 : keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
728 4 : if (!keysig)
729 0 : return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
730 :
731 : /* Field 2 has the calculated trust ('!', '-', '?', '%'). */
732 4 : if (fields >= 2)
733 4 : switch (field[1][0])
734 : {
735 : case '!':
736 4 : keysig->status = gpg_error (GPG_ERR_NO_ERROR);
737 4 : break;
738 :
739 : case '-':
740 0 : keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
741 0 : break;
742 :
743 : case '?':
744 0 : keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
745 0 : break;
746 :
747 : case '%':
748 0 : keysig->status = gpg_error (GPG_ERR_GENERAL);
749 0 : break;
750 :
751 : default:
752 0 : keysig->status = gpg_error (GPG_ERR_NO_ERROR);
753 0 : break;
754 : }
755 :
756 : /* Field 4 has the public key algorithm. */
757 4 : if (fields >= 4)
758 : {
759 4 : int i = atoi (field[3]);
760 4 : if (i >= 1 && i < 128)
761 4 : keysig->pubkey_algo = _gpgme_map_pk_algo (i, ctx->protocol);
762 : }
763 :
764 : /* Field 5 has the long keyid. */
765 4 : if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
766 4 : strcpy (keysig->_keyid, field[4]);
767 :
768 : /* Field 6 has the timestamp (seconds). */
769 4 : if (fields >= 6)
770 4 : keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
771 :
772 : /* Field 7 has the expiration time (seconds). */
773 4 : if (fields >= 7)
774 4 : keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
775 :
776 : /* Field 11 has the signature class (eg, 0x30 means revoked). */
777 4 : if (fields >= 11)
778 4 : if (field[10][0] && field[10][1])
779 : {
780 4 : int sig_class = _gpgme_hextobyte (field[10]);
781 4 : if (sig_class >= 0)
782 : {
783 4 : keysig->sig_class = sig_class;
784 4 : keysig->class = keysig->sig_class;
785 4 : if (sig_class == 0x30)
786 0 : keysig->revoked = 1;
787 : }
788 4 : if (field[10][2] == 'x')
789 4 : keysig->exportable = 1;
790 : }
791 :
792 4 : opd->tmp_keysig = keysig;
793 4 : break;
794 :
795 : case RT_SPK:
796 0 : if (!opd->tmp_keysig)
797 0 : return 0;
798 0 : assert (opd->tmp_keysig == key->_last_uid->_last_keysig);
799 :
800 0 : if (fields >= 4)
801 : {
802 : /* Field 2 has the subpacket type. */
803 0 : int type = atoi (field[1]);
804 :
805 : /* Field 3 has the flags. */
806 0 : int flags = atoi (field[2]);
807 :
808 : /* Field 4 has the length. */
809 0 : int len = atoi (field[3]);
810 :
811 : /* Field 5 has the data. */
812 0 : char *data = field[4];
813 :
814 : /* Type 20: Notation data. */
815 : /* Type 26: Policy URL. */
816 0 : if (type == 20 || type == 26)
817 : {
818 : gpgme_sig_notation_t notation;
819 :
820 0 : keysig = opd->tmp_keysig;
821 :
822 : /* At this time, any error is serious. */
823 0 : err = _gpgme_parse_notation (¬ation, type, flags, len, data);
824 0 : if (err)
825 0 : return err;
826 :
827 : /* Add a new notation. FIXME: Could be factored out. */
828 0 : if (!keysig->notations)
829 0 : keysig->notations = notation;
830 0 : if (keysig->_last_notation)
831 0 : keysig->_last_notation->next = notation;
832 0 : keysig->_last_notation = notation;
833 : }
834 : }
835 :
836 : case RT_NONE:
837 : /* Unknown record. */
838 54 : break;
839 : }
840 582 : return 0;
841 : }
842 :
843 :
844 : void
845 88 : _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
846 : {
847 : gpgme_error_t err;
848 88 : gpgme_ctx_t ctx = (gpgme_ctx_t) data;
849 88 : gpgme_key_t key = (gpgme_key_t) type_data;
850 : void *hook;
851 : op_data_t opd;
852 : struct key_queue_item_s *q, *q2;
853 :
854 88 : assert (type == GPGME_EVENT_NEXT_KEY);
855 :
856 88 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
857 88 : opd = hook;
858 88 : if (err)
859 0 : return;
860 :
861 88 : q = malloc (sizeof *q);
862 88 : if (!q)
863 : {
864 0 : gpgme_key_unref (key);
865 : /* FIXME return GPGME_Out_Of_Core; */
866 0 : return;
867 : }
868 88 : q->key = key;
869 88 : q->next = NULL;
870 : /* FIXME: Use a tail pointer? */
871 88 : if (!(q2 = opd->key_queue))
872 71 : opd->key_queue = q;
873 : else
874 : {
875 17 : for (; q2->next; q2 = q2->next)
876 : ;
877 17 : q2->next = q;
878 : }
879 88 : opd->key_cond = 1;
880 : }
881 :
882 :
883 : /* Start a keylist operation within CTX, searching for keys which
884 : match PATTERN. If SECRET_ONLY is true, only secret keys are
885 : returned. */
886 : gpgme_error_t
887 57 : gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
888 : {
889 : gpgme_error_t err;
890 : void *hook;
891 : op_data_t opd;
892 57 : int flags = 0;
893 :
894 57 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx,
895 : "pattern=%s, secret_only=%i", pattern, secret_only);
896 :
897 57 : if (!ctx)
898 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
899 :
900 57 : err = _gpgme_op_reset (ctx, 2);
901 57 : if (err)
902 0 : return TRACE_ERR (err);
903 :
904 57 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
905 : sizeof (*opd), release_op_data);
906 57 : opd = hook;
907 57 : if (err)
908 0 : return TRACE_ERR (err);
909 :
910 57 : _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
911 :
912 57 : err = _gpgme_engine_set_colon_line_handler (ctx->engine,
913 : keylist_colon_handler, ctx);
914 57 : if (err)
915 0 : return TRACE_ERR (err);
916 :
917 57 : if (ctx->offline)
918 0 : flags |= GPGME_ENGINE_FLAG_OFFLINE;
919 :
920 57 : err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
921 : ctx->keylist_mode, flags);
922 57 : return TRACE_ERR (err);
923 : }
924 :
925 :
926 : /* Start a keylist operation within CTX, searching for keys which
927 : match PATTERN. If SECRET_ONLY is true, only secret keys are
928 : returned. */
929 : gpgme_error_t
930 0 : gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
931 : int secret_only, int reserved)
932 : {
933 : gpgme_error_t err;
934 : void *hook;
935 : op_data_t opd;
936 0 : int flags = 0;
937 :
938 0 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx,
939 : "secret_only=%i, reserved=0x%x", secret_only, reserved);
940 :
941 0 : if (!ctx)
942 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
943 :
944 0 : err = _gpgme_op_reset (ctx, 2);
945 0 : if (err)
946 0 : return TRACE_ERR (err);
947 :
948 0 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
949 : sizeof (*opd), release_op_data);
950 0 : opd = hook;
951 0 : if (err)
952 0 : return TRACE_ERR (err);
953 :
954 0 : _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
955 0 : err = _gpgme_engine_set_colon_line_handler (ctx->engine,
956 : keylist_colon_handler, ctx);
957 0 : if (err)
958 0 : return TRACE_ERR (err);
959 :
960 0 : if (ctx->offline)
961 0 : flags |= GPGME_ENGINE_FLAG_OFFLINE;
962 :
963 0 : err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
964 : reserved, ctx->keylist_mode,
965 : flags);
966 0 : return TRACE_ERR (err);
967 : }
968 :
969 :
970 : /* Return the next key from the keylist in R_KEY. */
971 : gpgme_error_t
972 143 : gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
973 : {
974 : gpgme_error_t err;
975 : struct key_queue_item_s *queue_item;
976 : void *hook;
977 : op_data_t opd;
978 :
979 143 : TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_next", ctx);
980 :
981 143 : if (!ctx || !r_key)
982 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
983 143 : *r_key = NULL;
984 143 : if (!ctx)
985 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
986 :
987 143 : err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
988 143 : opd = hook;
989 143 : if (err)
990 0 : return TRACE_ERR (err);
991 143 : if (opd == NULL)
992 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
993 :
994 143 : if (!opd->key_queue)
995 : {
996 126 : err = _gpgme_wait_on_condition (ctx, &opd->key_cond, NULL);
997 126 : if (err)
998 0 : return TRACE_ERR (err);
999 :
1000 126 : if (!opd->key_cond)
1001 55 : return TRACE_ERR (gpg_error (GPG_ERR_EOF));
1002 :
1003 71 : opd->key_cond = 0;
1004 71 : assert (opd->key_queue);
1005 : }
1006 88 : queue_item = opd->key_queue;
1007 88 : opd->key_queue = queue_item->next;
1008 88 : if (!opd->key_queue)
1009 71 : opd->key_cond = 0;
1010 :
1011 88 : *r_key = queue_item->key;
1012 88 : free (queue_item);
1013 :
1014 88 : return TRACE_SUC2 ("key=%p (%s)", *r_key,
1015 : ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1016 : (*r_key)->subkeys->fpr : "invalid");
1017 : }
1018 :
1019 :
1020 : /* Terminate a pending keylist operation within CTX. */
1021 : gpgme_error_t
1022 5 : gpgme_op_keylist_end (gpgme_ctx_t ctx)
1023 : {
1024 5 : TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx);
1025 :
1026 5 : if (!ctx)
1027 0 : return gpg_error (GPG_ERR_INV_VALUE);
1028 :
1029 5 : return 0;
1030 : }
1031 :
1032 :
1033 : /* Get the key with the fingerprint FPR from the crypto backend. If
1034 : SECRET is true, get the secret key. */
1035 : gpgme_error_t
1036 52 : gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
1037 : int secret)
1038 : {
1039 : gpgme_ctx_t listctx;
1040 : gpgme_error_t err;
1041 : gpgme_key_t key;
1042 :
1043 52 : TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
1044 : "fpr=%s, secret=%i", fpr, secret);
1045 :
1046 52 : if (!ctx || !r_key || !fpr)
1047 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1048 :
1049 52 : if (strlen (fpr) < 8) /* We have at least a key ID. */
1050 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1051 :
1052 : /* FIXME: We use our own context because we have to avoid the user's
1053 : I/O callback handlers. */
1054 52 : err = gpgme_new (&listctx);
1055 52 : if (err)
1056 0 : return TRACE_ERR (err);
1057 : {
1058 : gpgme_protocol_t proto;
1059 : gpgme_engine_info_t info;
1060 :
1061 : /* Clone the relevant state. */
1062 52 : proto = gpgme_get_protocol (ctx);
1063 52 : gpgme_set_protocol (listctx, proto);
1064 52 : gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1065 52 : info = gpgme_ctx_get_engine_info (ctx);
1066 105 : while (info && info->protocol != proto)
1067 1 : info = info->next;
1068 52 : if (info)
1069 52 : gpgme_ctx_set_engine_info (listctx, proto,
1070 52 : info->file_name, info->home_dir);
1071 : }
1072 :
1073 52 : err = gpgme_op_keylist_start (listctx, fpr, secret);
1074 52 : if (!err)
1075 52 : err = gpgme_op_keylist_next (listctx, r_key);
1076 52 : if (!err)
1077 : {
1078 : try_next_key:
1079 52 : err = gpgme_op_keylist_next (listctx, &key);
1080 52 : if (gpgme_err_code (err) == GPG_ERR_EOF)
1081 52 : err = 0;
1082 : else
1083 : {
1084 0 : if (!err
1085 0 : && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1086 0 : && key && key->subkeys && key->subkeys->fpr
1087 0 : && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1088 : {
1089 : /* The fingerprint is identical. We assume that this is
1090 : the same key and don't mark it as an ambiguous. This
1091 : problem may occur with corrupted keyrings and has
1092 : been noticed often with gpgsm. In fact gpgsm uses a
1093 : similar hack to sort out such duplicates but it can't
1094 : do that while listing keys. */
1095 0 : gpgme_key_unref (key);
1096 0 : goto try_next_key;
1097 : }
1098 0 : if (!err)
1099 : {
1100 0 : gpgme_key_unref (key);
1101 0 : err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1102 : }
1103 0 : gpgme_key_unref (*r_key);
1104 : }
1105 : }
1106 52 : gpgme_release (listctx);
1107 52 : if (! err)
1108 : {
1109 52 : TRACE_LOG2 ("key=%p (%s)", *r_key,
1110 : ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1111 : (*r_key)->subkeys->fpr : "invalid");
1112 : }
1113 52 : return TRACE_ERR (err);
1114 : }
|