* engine-gpgsm.c (_gpgme_gpgsm_op_keylist): Implement secret only mode.
[gpgme.git] / gpgme / keylist.c
1 /* keylist.c -  key listing
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME 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  * GPGME 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 <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32 #include "key.h"
33
34 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
35
36 static void finish_key ( GpgmeCtx ctx );
37
38
39 static void
40 keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
41 {
42     if ( ctx->out_of_core )
43         return;
44
45     switch (code) {
46       case STATUS_EOF:
47         finish_key (ctx);
48         break;
49
50       default:
51         /* ignore all other codes */
52         break;
53     }
54 }
55
56
57 static time_t
58 parse_timestamp ( char *p )
59 {
60     if (!*p )
61         return 0;
62
63     return (time_t)strtoul (p, NULL, 10);
64 }
65
66
67 static void
68 set_mainkey_trust_info ( GpgmeKey key, const char *s )
69 {
70     /* look at letters and stop at the first digit */
71     for (; *s && !my_isdigit (*s); s++ ) {
72         switch (*s) {
73           case 'e': key->keys.flags.expired = 1; break;
74           case 'r': key->keys.flags.revoked = 1; break;
75           case 'd': key->keys.flags.disabled = 1; break;
76           case 'i': key->keys.flags.invalid = 1; break;
77         }
78     }
79 }
80
81
82 static void
83 set_userid_flags ( GpgmeKey key, const char *s )
84 {
85     /* look at letters and stop at the first digit */
86     for (; *s && !my_isdigit (*s); s++ ) {
87         switch (*s) {
88           case 'r': key->uids->revoked  = 1; break;
89           case 'i': key->uids->invalid  = 1; break;
90
91           case 'n': key->uids->validity = GPGME_VALIDITY_NEVER; break;
92           case 'm': key->uids->validity = GPGME_VALIDITY_MARGINAL; break;
93           case 'f': key->uids->validity = GPGME_VALIDITY_FULL; break;
94           case 'u': key->uids->validity = GPGME_VALIDITY_ULTIMATE; break;
95         }
96     }
97 }
98
99 static void
100 set_subkey_trust_info ( struct subkey_s *k, const char *s )
101 {
102     /* look at letters and stop at the first digit */
103     for (; *s && !my_isdigit (*s); s++ ) {
104         switch (*s) {
105           case 'e': k->flags.expired = 1; break;
106           case 'r': k->flags.revoked = 1; break;
107           case 'd': k->flags.disabled = 1; break;
108           case 'i': k->flags.invalid = 1; break;
109         }
110     }
111 }
112
113 static void
114 set_mainkey_capability ( GpgmeKey key, const char *s )
115 {
116     for (; *s ; s++ ) {
117         switch (*s) {
118           case 'e': key->keys.flags.can_encrypt = 1; break;
119           case 's': key->keys.flags.can_sign = 1; break;
120           case 'c': key->keys.flags.can_certify = 1; break;
121           case 'E': key->gloflags.can_encrypt = 1; break;
122           case 'S': key->gloflags.can_sign = 1; break;
123           case 'C': key->gloflags.can_certify = 1; break;
124         }
125     }
126 }
127
128 static void
129 set_subkey_capability ( struct subkey_s *k, const char *s )
130 {
131     for (; *s; s++ ) {
132         switch (*s) {
133           case 'e': k->flags.can_encrypt = 1; break;
134           case 's': k->flags.can_sign = 1; break;
135           case 'c': k->flags.can_certify = 1; break;
136         }
137     }
138 }
139
140
141
142 /* Note: we are allowed to modify line */
143 static void
144 keylist_colon_handler ( GpgmeCtx ctx, char *line )
145 {
146     char *p, *pend;
147     int field = 0;
148     enum {
149       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
150       RT_CRT, RT_CRS
151     } rectype = RT_NONE;
152     GpgmeKey key = ctx->tmp_key;
153     int i;
154     const char *trust_info = NULL;
155     struct subkey_s *sk = NULL;
156
157     if ( ctx->out_of_core )
158         return;
159     if (!line) { /* EOF */
160         finish_key (ctx);
161         return; 
162     }
163
164     for (p = line; p; p = pend) {
165         field++;
166         pend = strchr (p, ':');
167         if (pend) 
168             *pend++ = 0;
169
170         if ( field == 1 ) {
171             if ( !strcmp ( p, "sig" ) )
172                 rectype = RT_SIG;
173             else if ( !strcmp ( p, "uid" ) && key ) {
174                 rectype = RT_UID;
175                 key = ctx->tmp_key;
176             }
177             else if ( !strcmp (p, "sub") && key ) {
178                 /* start a new subkey */
179                 rectype = RT_SUB;
180                 if ( !(sk = _gpgme_key_add_subkey (key)) ) {
181                     ctx->out_of_core=1;
182                     return;
183                 }
184             }
185             else if ( !strcmp (p, "ssb") && key ) {
186                 /* start a new secret subkey */
187                 rectype = RT_SSB;
188                 if ( !(sk = _gpgme_key_add_secret_subkey (key)) ) {
189                     ctx->out_of_core=1;
190                     return;
191                 }
192             }
193             else if ( !strcmp (p, "pub") ) {
194                 /* start a new keyblock */
195                 if ( _gpgme_key_new ( &key ) ) {
196                     ctx->out_of_core=1; /* the only kind of error we can get*/
197                     return;
198                 }
199                 rectype = RT_PUB;
200                 finish_key ( ctx );
201                 assert ( !ctx->tmp_key );
202                 ctx->tmp_key = key;
203             }
204             else if ( !strcmp (p, "sec") ) {
205                 /* start a new keyblock */
206                 if ( _gpgme_key_new_secret ( &key ) ) {
207                     ctx->out_of_core=1; /*the only kind of error we can get*/
208                     return;
209                 }
210                 rectype = RT_SEC;
211                 finish_key ( ctx );
212                 assert ( !ctx->tmp_key );
213                 ctx->tmp_key = key;
214             }
215             else if ( !strcmp (p, "crt") ) {
216                 /* start a new certificate */
217                 if ( _gpgme_key_new ( &key ) ) {
218                     ctx->out_of_core=1; /* the only kind of error we can get*/
219                     return;
220                 }
221                 key->x509 = 1;
222                 rectype = RT_CRT;
223                 finish_key ( ctx );
224                 assert ( !ctx->tmp_key );
225                 ctx->tmp_key = key;
226             }
227             else if ( !strcmp (p, "crs") ) {
228                 /* start a new certificate */
229                 if ( _gpgme_key_new_secret ( &key ) ) {
230                     ctx->out_of_core=1; /* the only kind of error we can get*/
231                     return;
232                 }
233                 key->x509 = 1;
234                 rectype = RT_CRS;
235                 finish_key ( ctx );
236                 assert ( !ctx->tmp_key );
237                 ctx->tmp_key = key;
238             }
239             else if ( !strcmp ( p, "fpr" ) && key ) 
240                 rectype = RT_FPR;
241             else 
242                 rectype = RT_NONE;
243             
244         }
245         else if ( rectype == RT_PUB || rectype == RT_SEC
246                   || rectype == RT_CRT || rectype == RT_CRS)
247           {
248             switch (field) {
249               case 2: /* trust info */
250                 trust_info = p; 
251                 set_mainkey_trust_info (key, trust_info);
252                 break;
253               case 3: /* key length */
254                 i = atoi (p); 
255                 if ( i > 1 ) /* ignore invalid values */
256                     key->keys.key_len = i; 
257                 break;
258               case 4: /* pubkey algo */
259                 i = atoi (p);
260                 if ( i > 1 && i < 128 )
261                     key->keys.key_algo = i;
262                 break;
263               case 5: /* long keyid */
264                 if ( strlen (p) == DIM(key->keys.keyid)-1 )
265                     strcpy (key->keys.keyid, p);
266                 break;
267               case 6: /* timestamp (seconds) */
268                 key->keys.timestamp = parse_timestamp (p);
269                 break;
270               case 7: /* valid for n days */
271                 break;
272               case 8: /* X.509 serial number */
273                 /* fixme: store it */
274                 break;
275               case 9: /* ownertrust */
276                 break;
277               case 10: /* not used for gpg due to --fixed-list-mode option 
278                           but gpgsm stores the issuer name */
279                 /* fixme: store issuer name */
280                 break;
281               case 11: /* signature class  */
282                 break;
283               case 12: /* capabilities */
284                 set_mainkey_capability (key, p );
285                 break;
286               case 13:
287                 pend = NULL;  /* we can stop here */
288                 break;
289             }
290           }
291         else if ( (rectype == RT_SUB || rectype== RT_SSB) && sk ) {
292             switch (field) {
293               case 2: /* trust info */
294                 set_subkey_trust_info ( sk, p);
295                 break;
296               case 3: /* key length */
297                 i = atoi (p); 
298                 if ( i > 1 ) /* ignore invalid values */
299                     sk->key_len = i; 
300                 break;
301               case 4: /* pubkey algo */
302                 i = atoi (p);
303                 if ( i > 1 && i < 128 )
304                     sk->key_algo = i;
305                 break;
306               case 5: /* long keyid */
307                 if ( strlen (p) == DIM(sk->keyid)-1 )
308                     strcpy (sk->keyid, p);
309                 break;
310               case 6: /* timestamp (seconds) */
311                 sk->timestamp = parse_timestamp (p);
312                 break;
313               case 7: /* valid for n days */
314                 break;
315               case 8: /* reserved (LID) */
316                 break;
317               case 9: /* ownertrust */
318                 break;
319               case 10:/* user ID n/a for a subkey */
320                 break;
321               case 11:  /* signature class  */
322                 break;
323               case 12: /* capability */
324                 set_subkey_capability ( sk, p );
325                 break;
326               case 13:
327                 pend = NULL;  /* we can stop here */
328                 break;
329             }
330         }
331         else if ( rectype == RT_UID ) {
332             switch (field) {
333               case 2: /* trust info */
334                 trust_info = p;  /*save for later */
335                 break;
336               case 10: /* user ID */
337                 if ( _gpgme_key_append_name ( key, p) )
338                     ctx->out_of_core = 1;
339                 else {
340                     if (trust_info)
341                         set_userid_flags (key, trust_info);
342                 }
343                 pend = NULL;  /* we can stop here */
344                 break;
345             }
346         }
347         else if ( rectype == RT_FPR ) {
348             switch (field) {
349               case 10: /* fingerprint (take only the first one)*/
350                 if ( !key->keys.fingerprint && *p ) {
351                     key->keys.fingerprint = xtrystrdup (p);
352                     if ( !key->keys.fingerprint )
353                         ctx->out_of_core = 1;
354                 }
355                 pend = NULL; /* that is all we want */
356                 break;
357             }
358         }
359     }
360     
361 }
362
363
364 /*
365  * We have read an entire key into ctx->tmp_key and should now finish
366  * it.  It is assumed that this releases ctx->tmp_key.
367  */
368 static void
369 finish_key ( GpgmeCtx ctx )
370 {
371     GpgmeKey key = ctx->tmp_key;
372     struct key_queue_item_s *q, *q2;
373
374     if (key) {
375         ctx->tmp_key = NULL;
376         
377         _gpgme_key_cache_add (key);
378         
379         q = xtrymalloc ( sizeof *q );
380         if ( !q ) {
381             gpgme_key_release (key);
382             ctx->out_of_core = 1;
383             return;
384         }
385         q->key = key;
386         q->next = NULL;
387         /* fixme: lock queue. Use a tail pointer? */
388         if ( !(q2 = ctx->key_queue) )
389             ctx->key_queue = q;
390         else {
391             for ( ; q2->next; q2 = q2->next )
392                 ;
393             q2->next = q;
394         }
395         ctx->key_cond = 1;
396         /* fixme: unlock queue */
397     }
398 }
399
400 /**
401  * gpgme_op_keylist_start:
402  * @c: context 
403  * @pattern: a GnuPG user ID or NULL for all
404  * @secret_only: List only keys where the secret part is available
405  * 
406  * Note that this function also cancels a pending key listing
407  * operaton. To actually retrieve the key, use
408  * gpgme_op_keylist_next().
409  * 
410  * Return value:  0 on success or an errorcode. 
411  **/
412 GpgmeError
413 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
414 {
415   GpgmeError err = 0;
416
417   if (!ctx)
418     return mk_error (Invalid_Value);
419   ctx->pending = 1;
420
421   _gpgme_release_result (ctx);
422   ctx->out_of_core = 0;
423
424   if (ctx->engine)
425     {
426       _gpgme_engine_release (ctx->engine); 
427       ctx->engine = NULL;
428     }
429   gpgme_key_release (ctx->tmp_key);
430   ctx->tmp_key = NULL;
431   /* Fixme: Release key_queue.  */
432     
433   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
434                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
435   if (err)
436     goto leave;
437
438   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
439   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
440                                               keylist_colon_handler, ctx);
441   if (err)
442     goto leave;
443   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
444
445   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, ctx->keylist_mode);
446
447   if (!err)     /* And kick off the process.  */
448     err = _gpgme_engine_start (ctx->engine, ctx);
449
450  leave:
451   if (err)
452     {
453       ctx->pending = 0; 
454       _gpgme_engine_release (ctx->engine);
455       ctx->engine = NULL;
456     }
457   return err;
458 }
459
460 /**
461  * gpgme_op_keylist_next:
462  * @c: Context
463  * @r_key: Returned key object
464  * 
465  * Return the next key from the key listing started with
466  * gpgme_op_keylist_start().  The caller must free the key using
467  * gpgme_key_release().  If the last key has already been returned the
468  * last time the function was called, %GPGME_EOF is returned and the
469  * operation is finished.
470  * 
471  * Return value: 0 on success, %GPGME_EOF or another error code.
472  **/
473 GpgmeError
474 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
475 {
476   struct key_queue_item_s *queue_item;
477
478   if (!r_key)
479     return mk_error (Invalid_Value);
480   *r_key = NULL;
481   if (!ctx)
482     return mk_error (Invalid_Value);
483   if (!ctx->pending)
484     return mk_error (No_Request);
485   if (ctx->out_of_core)
486     return mk_error (Out_Of_Core);
487
488   if (!ctx->key_queue)
489     {
490       _gpgme_wait_on_condition (ctx, 1, &ctx->key_cond);
491       if (ctx->out_of_core)
492         return mk_error (Out_Of_Core);
493       if (!ctx->key_cond)
494         {
495           ctx->pending = 0;
496           return mk_error (EOF);
497         }
498       ctx->key_cond = 0; 
499       assert (ctx->key_queue);
500     }
501   queue_item = ctx->key_queue;
502   ctx->key_queue = queue_item->next;
503   if (!ctx->key_queue)
504     ctx->key_cond = 0;
505   
506   *r_key = queue_item->key;
507   xfree (queue_item);
508   return 0;
509 }
510
511 /**
512  * gpgme_op_keylist_end:
513  * @c: Context
514  * 
515  * Ends the keylist operation and allows to use the context for some
516  * other operation next.
517  **/
518 GpgmeError
519 gpgme_op_keylist_end (GpgmeCtx ctx)
520 {
521   if (!ctx)
522     return mk_error (Invalid_Value);
523   if (!ctx->pending)
524     return mk_error (No_Request);
525   if (ctx->out_of_core)
526     return mk_error (Out_Of_Core);
527
528   ctx->pending = 0;
529   return 0;
530 }