/[winpt]/trunk/MyGPGME/keylist.c
ViewVC logotype

Contents of /trunk/MyGPGME/keylist.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 21 - (show annotations)
Wed Jul 27 11:17:44 2005 UTC (19 years, 7 months ago) by twoaday
File MIME type: text/plain
File size: 19810 byte(s)
2005-07-22  Timo Schulz  <twoaday@freakmail.de>
 
        * gpgme.c (_gpgme_add_comment): Forgot to alloc an extra
        byte for the '0'. This fixes a lot of crashes related to
        file operations.
        * keylist.c (gpgme_op_keylist_getkey): Use the param for
        'pub' or 'sec' mode.
        * keycache.c (gpgme_keycache_update_key): If the key is
        not in the cache, add it and if the cache contain secret
        key, sync it with the pub cache.
        * editkey.c (edit_key_colon_handler): Allocate 1 byte for
        the NUL-char.  This also fixes a lot of reported crashes
        related to the showpref feature.
 


1 /* keylist.c - key listing
2 * Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH
3 * Copyright (C) 2002-2005 Timo Schulz
4 *
5 * This file is part of MyGPGME.
6 *
7 * MyGPGME is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * MyGPGME is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <windows.h>
29
30 #include "util.h"
31 #include "context.h"
32 #include "ops.h"
33 #include "key.h"
34
35 static void finish_key ( gpgme_ctx_t ctx );
36
37
38 static void
39 keylist_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args )
40 {
41 if( ctx->out_of_core )
42 return;
43
44 switch( code ) {
45 case STATUS_EOF:
46 if( ctx->tmp_key )
47 finish_key( ctx );
48 break;
49
50 default: /* ignore all other codes */
51 break;
52 }
53 }
54
55
56
57 static time_t
58 parse_timestamp( char * p )
59 {
60 return *p ? (time_t)strtoul( p, NULL, 10 ) : 0;
61 }
62
63
64 static void
65 set_mainkey_trust_info( gpgme_key_t key, const char * s )
66 {
67 /* look at letters and stop at the first digit */
68 for( ; *s && !isdigit( *s ); s++ ) {
69 switch( *s ) {
70 case 'u': key->gloflags.ultimate = 1;
71 key->validity = GPGME_VALIDITY_ULTIMATE; break;
72 case '-':
73 case 'q': key->validity = GPGME_VALIDITY_UNDEFINED; break;
74 case 'm': key->validity = GPGME_VALIDITY_MARGINAL; break;
75 case 'f': key->validity = GPGME_VALIDITY_FULL; break;
76 case 'e': key->keys.flags.expired = 1; break;
77 case 'r': key->keys.flags.revoked = 1;
78 key->validity = GPGME_VALIDITY_REVOKED; break;
79 case 'd': key->keys.flags.disabled = 1; break;
80 case 'i': key->keys.flags.invalid = 1; break;
81 }
82 }
83 }
84
85
86 static void
87 set_userid_flags (struct user_id_s * u, const char * s)
88 {
89 /* look at letters and stop at the first digit */
90 for (; *s && !isdigit (*s); s++) {
91 switch( *s ) {
92 case 'r': u->flags.revoked = 1;
93 u->validity = GPGME_VALIDITY_REVOKED; break;
94 case 'i': u->flags.invalid = 1;
95 u->validity = GPGME_VALIDITY_UNDEFINED; break;
96 case 'n': u->validity = GPGME_VALIDITY_NEVER; break;
97 case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break;
98 case 'f': u->validity = GPGME_VALIDITY_FULL; break;
99 case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break;
100 }
101 }
102 }
103
104 static void
105 set_subkey_trust_info( struct subkey_s * k, const char * s )
106 {
107 /* look at letters and stop at the first digit */
108 for( ; *s && !isdigit (*s); s++ ) {
109 switch( *s ) {
110 case 'e': k->flags.expired = 1; break;
111 case 'r': k->flags.revoked = 1; break;
112 case 'd': k->flags.disabled = 1; break;
113 case 'i': k->flags.invalid = 1; break;
114 }
115 }
116 }
117
118 static void
119 set_mainkey_capability( gpgme_key_t key, const char * s )
120 {
121 for( ; *s ; s++ ) {
122 switch( *s ) {
123 case 'a': key->keys.flags.can_auth = 1; break;
124 case 'e': key->keys.flags.can_encrypt = 1; break;
125 case 's': key->keys.flags.can_sign = 1; break;
126 case 'c': key->keys.flags.can_certify = 1; break;
127 case 'E': key->gloflags.can_encrypt = 1; break;
128 case 'S': key->gloflags.can_sign = 1; break;
129 case 'C': key->gloflags.can_certify = 1; break;
130 case 'D': key->gloflags.disabled = 1; break;
131 }
132 }
133 }
134
135 static void
136 set_subkey_capability (struct subkey_s * k, const char * s)
137 {
138 for (; *s; s++) {
139 switch (*s) {
140 case 'a': k->flags.can_auth = 1; break;
141 case 'e': k->flags.can_encrypt = 1; break;
142 case 's': k->flags.can_sign = 1; break;
143 case 'c': k->flags.can_certify = 1; break;
144 }
145 }
146 }
147
148 static void
149 set_mainkey_ownertrust( gpgme_key_t key, const char * s )
150 {
151 switch( *s ) {
152 case '-': key->otrust = GPGME_TRUST_UNKNOWN; break;
153 case 'e': key->otrust = GPGME_TRUST_EXPIRED; break;
154 case 'q': key->otrust = GPGME_TRUST_UNDEFINED; break;
155 case 'n': key->otrust = GPGME_TRUST_NEVER; break;
156 case 'm': key->otrust = GPGME_TRUST_MARGINAL; break;
157 case 'f': key->otrust = GPGME_TRUST_FULLY; break;
158 case 'u': key->otrust = GPGME_TRUST_ULTIMATE; break;
159 default: key->otrust = GPGME_TRUST_UNKNOWN; break;
160 }
161 }
162
163
164 /* Note: we are allowed to modify line */
165 static void
166 keylist_colon_handler( gpgme_ctx_t ctx, char * line )
167 {
168 enum {
169 RT_NONE,
170 RT_SIG,
171 RT_UID,
172 RT_SUB,
173 RT_PUB,
174 RT_FPR,
175 RT_SSB,
176 RT_SEC,
177 RT_PKD,
178 } rectype = RT_NONE;
179 gpgme_key_t key = ctx->tmp_key;
180 struct subkey_s * sk = NULL;
181 struct signature_s * sig = NULL;
182 struct subkey_s * s = NULL;
183 struct user_id_s * u = NULL;
184 struct mpi_s * m = NULL, * mt = NULL;
185 const char * trust_info = NULL;
186 char * p, * pend;
187 int field = 0;
188 unsigned long val=0;
189 int i;
190
191 if( ctx->out_of_core )
192 return;
193 if( !line ) { /* EOF */
194 if( ctx->tmp_key )
195 finish_key( ctx );
196 return;
197 }
198
199 for( p = line; p; p = pend ) {
200 field++;
201 pend = strchr( p, ':' );
202 if( pend )
203 *pend++ = 0;
204
205 if( field == 1 ) {
206 if( !strcmp( p, "sig" ) && key ) {
207 rectype = RT_SIG;
208 sig = _gpgme_key_add_signature( key );
209 if( !sig ) {
210 ctx->out_of_core = 1;
211 break;
212 }
213 }
214 else if( !strcmp( p, "uid" ) && key ) {
215 rectype = RT_UID;
216 key = ctx->tmp_key;
217 sig = _gpgme_key_add_signature( key );
218 if( !sig ) {
219 ctx->out_of_core = 1;
220 break;
221 }
222 }
223 else if( !strcmp( p, "sub" ) && key ) {
224 /* start a new subkey */
225 rectype = RT_SUB;
226 sk = _gpgme_key_add_subkey( key );
227 if( !sk ) {
228 ctx->out_of_core = 1;
229 return;
230 }
231 }
232 else if( !strcmp( p, "ssb" ) && key ) {
233 /* start a new secret subkey */
234 rectype = RT_SSB;
235 sk = _gpgme_key_add_secret_subkey( key );
236 if( !sk ) {
237 ctx->out_of_core = 1;
238 return;
239 }
240 }
241 else if( !strcmp( p, "pub" ) ) {
242 /* start a new keyblock */
243 if( _gpgme_key_new ( &key ) ) {
244 ctx->out_of_core = 1; /* the only kind of error we can get*/
245 return;
246 }
247 rectype = RT_PUB;
248 if ( ctx->tmp_key )
249 finish_key ( ctx );
250 assert ( !ctx->tmp_key );
251 ctx->tmp_key = key;
252 ctx->tmp_i = 0;
253 if (ctx->cb.progress)
254 ctx->cb.progress (ctx->cb.progress_value, "keylist", 0,
255 ctx->cb.progess_tmp,
256 ctx->cb.progress_value_int);
257 ctx->cb.progess_tmp++;
258 }
259 else if( !strcmp ( p, "sec" ) ) {
260 /* start a new keyblock */
261 if ( _gpgme_key_new_secret( &key ) ) {
262 ctx->out_of_core = 1; /* the only kind of error we can get */
263 return;
264 }
265 rectype = RT_SEC;
266 if( ctx->tmp_key )
267 finish_key ( ctx );
268 assert ( !ctx->tmp_key );
269 ctx->tmp_key = key;
270 }
271 else if( !strcmp( p, "fpr" ) && key )
272 rectype = RT_FPR;
273 else if( !strcmp( p, "pkd" ) && key )
274 rectype = RT_PKD;
275 else
276 rectype = RT_NONE;
277 }
278 else if( rectype == RT_PUB || rectype == RT_SEC )
279 {
280 switch( field ) {
281 case 2: /* trust info */
282 trust_info = p;
283 set_mainkey_trust_info( key, trust_info );
284 break;
285 case 3: /* key length */
286 i = atoi( p );
287 if( i > 1 ) /* ignore invalid values */
288 key->keys.key_len = i;
289 break;
290 case 4: /* pubkey algo */
291 i = atoi ( p );
292 if( i > 0 && i < 128 )
293 key->keys.key_algo = i;
294 break;
295 case 5: /* long keyid */
296 memset (key->keys.keyid, 0, sizeof key->keys.keyid);
297 strncpy (key->keys.keyid, p, DIM (key->keys.keyid)-1);
298 break;
299 case 6: /* timestamp (1998-02-28) */
300 key->keys.timestamp = parse_timestamp( p );
301 break;
302 case 7: /* valid for n days */
303 key->keys.expires = parse_timestamp( p );
304 break;
305 case 8: /* reserved (LID) */
306 break;
307 case 9: /* ownertrust */
308 set_mainkey_ownertrust( key, p );
309 break;
310 case 10: /* not used due to --fixed-list-mode option */
311 break;
312 case 11: /* signature class */
313 break;
314 case 12: /* capabilities */
315 set_mainkey_capability( key, p );
316 break;
317 case 15:
318 if (p && * p)
319 {
320 key->gloflags.divert_to_card = 1;
321 memset (key->keys.cardno, 0, sizeof key->keys.cardno);
322 strncpy (key->keys.cardno, p, DIM (key->keys.cardno));
323 }
324 pend = NULL; /* we can stop here */
325 break;
326 }
327 }
328 else if( (rectype == RT_SUB || rectype== RT_SSB) && sk ) {
329 switch( field ) {
330 case 2: /* trust info */
331 set_subkey_trust_info( sk, p );
332 break;
333 case 3: /* key length */
334 i = atoi( p );
335 if ( i > 1 ) /* ignore invalid values */
336 sk->key_len = i;
337 break;
338 case 4: /* pubkey algo */
339 i = atoi( p );
340 if( i > 0 && i < 128 )
341 sk->key_algo = i;
342 break;
343 case 5: /* long keyid */
344 memset (sk->keyid, 0, sizeof sk->keyid);
345 strncpy (sk->keyid, p, DIM (sk->keyid)-1);
346 break;
347 case 6: /* timestamp (1998-02-28) */
348 sk->timestamp = parse_timestamp( p );
349 break;
350 case 7: /* valid for n days */
351 sk->expires = parse_timestamp( p );
352 break;
353 case 8: /* reserved (LID) */
354 break;
355 case 9: /* ownertrust */
356 break;
357 case 10:/* user ID n/a for a subkey */
358 break;
359 case 11: /* signature class */
360 break;
361 case 12: /* capability */
362 set_subkey_capability ( sk, p );
363 break;
364 case 15:
365 memset (sk->cardno, 0, sizeof sk->cardno);
366 strncpy (sk->cardno, p, DIM (sk->cardno)-1);
367 pend = NULL; /* we can stop here */
368 break;
369 }
370 }
371 else if (rectype == RT_UID)
372 {
373 switch (field)
374 {
375 case 2: /* trust info */
376 trust_info = p; /* save for later use */
377 break;
378 case 6: /* creation date */
379 if (p)
380 val = parse_timestamp (p);
381 break;
382
383 case 8: /* hash over name */
384 break;
385
386 case 10: /* user ID */
387 safe_free (ctx->tmp_id);
388 ctx->tmp_id = strdup (p);
389 if (!ctx->tmp_id) {
390 ctx->out_of_core = 1;
391 break;
392 }
393 if (_gpgme_key_append_name (key, p, &u))
394 ctx->out_of_core = 1;
395 else if (trust_info)
396 set_userid_flags (u, trust_info);
397 if (sig) {
398 safe_free (sig->issuer);
399 sig->issuer = calloc (1, strlen (p) + 1);
400 if (!sig->issuer) {
401 ctx->out_of_core = 1;
402 break;
403 }
404 _gpgme_decode_c_string (p, &sig->issuer, strlen (p)+ 1);
405 }
406 u->created = val;
407 pend = NULL; /* we can stop here */
408 break;
409 }
410 }
411 else if( rectype == RT_FPR ) {
412 int nfpr = ctx->tmp_i;
413 switch( field ) {
414 case 10:
415 for( s = &key->keys; s && nfpr; s = s->next, nfpr-- )
416 ;
417 if( s ) {
418 s->fingerprint = strdup( p );
419 if( !s->fingerprint ) {
420 ctx->out_of_core = 1;
421 break;
422 }
423 }
424 pend = NULL; /* that is all we want */
425 ctx->tmp_i++;
426 break;
427 }
428 }
429 else if( rectype == RT_SIG ) {
430 switch( field ) {
431 case 2: /* signature state */
432 switch( *p ) {
433 case '!': sig->stat = GPGME_SIG_STAT_GOOD; break;
434 case '-': sig->stat = GPGME_SIG_STAT_BAD; break;
435 case '?': sig->stat = GPGME_SIG_STAT_NOKEY; break;
436 case '%': sig->stat = GPGME_SIG_STAT_ERROR; break;
437 default : sig->stat = GPGME_SIG_STAT_NONE; break;
438 }
439 break;
440
441 case 4: /* pk algorithm */
442 sig->algo = atol (p);
443 break;
444
445 case 5: /* long keyid */
446 memset (sig->keyid, 0, sizeof sig->keyid);
447 strncpy (sig->keyid, p, DIM (sig->keyid)-1);
448 break;
449
450 case 6: /* created */
451 sig->created = parse_timestamp( p );
452 break;
453
454 case 7: /* expires */
455 sig->expires = parse_timestamp( p );
456 break;
457
458 case 10:
459 if( p ) {
460 sig->issuer = calloc( 1, strlen( p ) + 1 );
461 if( !sig->issuer ) {
462 ctx->out_of_core = 1;
463 break;
464 }
465 _gpgme_decode_c_string( p, &sig->issuer, strlen( p ) + 1 );
466 }
467 break;
468
469 case 11:
470 sig->sigclass = strtoul( p, NULL, 16 );
471 if (strchr (p, 'l'))
472 sig->is_local = 1;
473 /*if (strchr (p, ' '))
474 sig->is_nonrev = 1;*/
475 if (sig->sigclass < 0x10 || sig->sigclass > 0x13) {
476 /* we only want certificates and no key signatures */
477 pend = NULL;
478 break;
479 }
480 if( ctx->tmp_id ) {
481 sig->user_id = calloc( 1, strlen( ctx->tmp_id ) + 1 );
482 if( !sig->user_id ) {
483 ctx->out_of_core = 1;
484 break;
485 }
486 _gpgme_decode_c_string( ctx->tmp_id, &sig->user_id, strlen( ctx->tmp_id ) +1 );
487 }
488 pend = NULL; /* we can stop here */
489 break;
490 }
491 }
492 else if( rectype == RT_PKD ) {
493 switch( field ) {
494 case 1:
495 m = calloc( 1, sizeof * m );
496 if( !m ) {
497 ctx->out_of_core = 1;
498 return;
499 }
500 for( mt=key->pkey; mt->next; mt=mt->next )
501 ;
502 mt->next = m;
503 break;
504
505 case 2:
506 if( m )
507 m->bits = atol( p );
508 break;
509
510 case 3:
511 if( m ) {
512 m->hexval = strdup( p );
513 if( !m->hexval )
514 ctx->out_of_core=1;
515 }
516 break;
517 }
518 }
519 }
520
521 }
522
523
524 /*
525 * We have read an entire key into ctx->tmp_key and should now finish
526 * it. It is assumed that this releases ctx->tmp_key.
527 */
528 static void
529 finish_key( gpgme_ctx_t ctx )
530 {
531 gpgme_key_t key = ctx->tmp_key;
532 struct key_queue_item_s * q, * q2;
533
534 assert( key );
535 ctx->tmp_key = NULL;
536
537 q = malloc( sizeof *q );
538 if( !q ) {
539 gpgme_key_release( key );
540 ctx->out_of_core = 1;
541 return;
542 }
543 q->key = key;
544 q->next = NULL;
545 /* fixme: lock queue. Use a tail pointer? */
546 q2 = ctx->key_queue;
547 if( !q2 )
548 ctx->key_queue = q;
549 else {
550 for( ; q2->next; q2 = q2->next )
551 ;
552 q2->next = q;
553 }
554 ctx->key_cond = 1;
555 /* fixme: unlock queue */
556 }
557
558
559
560 /**
561 * gpgme_op_keylist_start:
562 * @c: context
563 * @pattern: a GnuPg user ID or NULL for all
564 * @secret_only: List only keys where the secret part is available
565 *
566 * Note that this function also cancels a pending key listing operaton..
567 *
568 * Return value: 0 on success or an errorcode.
569 **/
570 gpgme_error_t
571 gpgme_op_keylist_start( gpgme_ctx_t ctx, const char *pattern, int secret_only )
572 {
573 gpgme_error_t rc = 0;
574
575 if( !ctx )
576 return mk_error( Invalid_Value );
577 ctx->pending = 1;
578
579 _gpgme_release_result( ctx );
580 ctx->out_of_core = 0;
581 ctx->cb.progess_tmp = 0;
582
583 _gpgme_gpg_release( &ctx->gpg );
584 gpgme_key_release( ctx->tmp_key );
585 ctx->tmp_key = NULL;
586 /* Fixme: release key_queue */
587
588 rc = _gpgme_gpg_new( &ctx->gpg );
589 if( rc )
590 goto leave;
591
592 _gpgme_gpg_set_status_handler( ctx->gpg, keylist_status_handler, ctx );
593 rc = _gpgme_gpg_set_colon_line_handler( ctx->gpg, keylist_colon_handler, ctx );
594 if ( rc )
595 goto leave;
596
597 /* build the commandline */
598 if (ctx->use_logging)
599 _gpgme_gpg_set_logging_handler (ctx->gpg, ctx);
600 _gpgme_gpg_set_list_options (ctx->gpg, ctx->list_opts);
601 _gpgme_gpg_add_arg( ctx->gpg, "--with-colons" );
602 _gpgme_gpg_add_arg( ctx->gpg, "--fixed-list-mode" );
603 _gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" );
604 _gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" ); /* for the subkey */
605 if( ctx->keylist_mode & 1 )
606 _gpgme_gpg_add_arg( ctx->gpg, "--no-expensive-trust-checks" );
607 if( ctx->keylist_mode & 2 )
608 _gpgme_gpg_add_arg( ctx->gpg, "--with-key-data" );
609 if( ctx->keylist_mode & 4 )
610 _gpgme_gpg_add_arg( ctx->gpg, "--fast-list-mode" );
611 if( 1 || !ctx->keylist_mode ) /* XXX: do all combinations make sense? */
612 _gpgme_gpg_add_arg( ctx->gpg, "-vvv" ); /* to list and check sigs */
613 _gpgme_gpg_add_arg ( ctx->gpg, secret_only?
614 "--list-secret-keys": /*"--list-keys"*/ "-k" );
615
616 /* Tell the gpg object about the data */
617 _gpgme_gpg_add_arg ( ctx->gpg, "--" );
618 if( pattern && *pattern )
619 _gpgme_gpg_add_arg ( ctx->gpg, pattern );
620
621 /* and kick off the process */
622 rc = _gpgme_gpg_spawn ( ctx->gpg, ctx );
623
624 leave:
625 if( rc ) {
626 ctx->pending = 0;
627 _gpgme_gpg_release ( &ctx->gpg );
628 }
629 return rc;
630 }
631
632
633 gpgme_error_t
634 gpgme_op_keylist_next( gpgme_ctx_t ctx, gpgme_key_t * r_key )
635 {
636 struct key_queue_item_s * q;
637
638 if( !r_key )
639 return mk_error( Invalid_Value );
640 *r_key = NULL;
641 if( !ctx )
642 return mk_error( Invalid_Value );
643 if( !ctx->pending )
644 return mk_error( No_Request );
645 if( ctx->out_of_core )
646 return mk_error( Out_Of_Core );
647
648 if( !ctx->key_queue ) {
649 _gpgme_wait_on_condition( ctx, 1, &ctx->key_cond );
650 if ( ctx->out_of_core )
651 return mk_error( Out_Of_Core );
652 if( !ctx->key_cond )
653 return mk_error( EOF );
654 ctx->key_cond = 0;
655 assert ( ctx->key_queue );
656 }
657 q = ctx->key_queue;
658 ctx->key_queue = q->next;
659
660 *r_key = q->key;
661 safe_free (q);
662 return 0;
663 }
664
665
666 gpgme_error_t
667 gpgme_op_keylist_getkey (int is_sec, const char *pattern, gpgme_key_t *r_key)
668 {
669 gpgme_ctx_t listctx;
670 gpgme_error_t err;
671
672 err = gpgme_new (&listctx);
673 if (err)
674 return err;
675 err = gpgme_op_keylist_start (listctx, pattern, is_sec);
676 if (!err)
677 err = gpgme_op_keylist_next (listctx, r_key);
678 gpgme_release (listctx);
679 return err;
680 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26