2002-09-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / keylist.c
1 /* keylist.c -  key listing
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 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 struct keylist_result_s
37 {
38   int truncated;
39   GpgmeData xmlinfo;
40 };
41
42 static void finish_key ( GpgmeCtx ctx );
43
44
45 void
46 _gpgme_release_keylist_result (KeylistResult result)
47 {
48   if (!result)
49     return;
50   xfree (result);
51 }
52
53 /* Append some XML info.  args is currently ignore but we might want
54    to add more information in the future (like source of the
55    keylisting.  With args of NULL the XML structure is closed.  */
56 static void
57 append_xml_keylistinfo (GpgmeData *rdh, char *args)
58 {
59   GpgmeData dh;
60
61   if (!*rdh)
62     {
63       if (gpgme_data_new (rdh))
64         return; /* FIXME: We are ignoring out-of-core.  */
65       dh = *rdh;
66       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
67     }
68   else
69     {
70       dh = *rdh;
71       _gpgme_data_append_string (dh, "  </keylisting>\n");
72     }
73
74   if (!args)
75     {
76       /* Just close the XML containter.  */
77       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
78       return;
79     }
80
81   _gpgme_data_append_string (dh,
82                              "  <keylisting>\n"
83                              "    <truncated/>\n"
84                              );
85     
86 }
87
88
89
90 static void
91 keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
92 {
93   if (ctx->error)
94     return;
95   test_and_allocate_result (ctx, keylist);
96
97    switch (code)
98     {
99     case GPGME_STATUS_TRUNCATED:
100       ctx->result.keylist->truncated = 1;
101       break;
102
103     case GPGME_STATUS_EOF:
104       if (ctx->result.keylist->truncated)
105         append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, "1");
106       if (ctx->result.keylist->xmlinfo)
107         {
108           append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, NULL);
109           _gpgme_set_op_info (ctx, ctx->result.keylist->xmlinfo);
110           ctx->result.keylist->xmlinfo = NULL;
111         }
112       break;
113
114     default:
115       /* Ignore all other codes.  */
116       break;
117     }
118 }
119
120
121 static time_t
122 parse_timestamp (char *p)
123 {
124   if (!*p)
125     return 0;
126
127   return (time_t)strtoul (p, NULL, 10);
128 }
129
130
131 static void
132 set_mainkey_trust_info (GpgmeKey key, const char *s)
133 {
134   /* Look at letters and stop at the first digit.  */
135   for (; *s && !my_isdigit (*s); s++)
136     {
137       switch (*s)
138         {
139         case 'e': key->keys.flags.expired = 1; break;
140         case 'r': key->keys.flags.revoked = 1; break;
141         case 'd': key->keys.flags.disabled = 1; break;
142         case 'i': key->keys.flags.invalid = 1; break;
143         }
144     }
145 }
146
147
148 static void
149 set_userid_flags (GpgmeKey key, const char *s)
150 {
151   struct user_id_s *u = key->uids;
152
153   assert (u);
154   while (u->next)
155     u = u->next;
156
157   /* Look at letters and stop at the first digit.  */
158   for (; *s && !my_isdigit (*s); s++)
159     {
160       switch (*s)
161         {
162         case 'r': u->revoked  = 1; break;
163         case 'i': u->invalid  = 1; break;
164
165         case 'n': u->validity = GPGME_VALIDITY_NEVER; break;
166         case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break;
167         case 'f': u->validity = GPGME_VALIDITY_FULL; break;
168         case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break;
169         }
170     }
171 }
172
173
174 static void
175 set_subkey_trust_info (struct subkey_s *k, const char *s)
176 {
177   /* Look at letters and stop at the first digit.  */
178   for (; *s && !my_isdigit (*s); s++)
179     {
180       switch (*s)
181         {
182         case 'e': k->flags.expired = 1; break;
183         case 'r': k->flags.revoked = 1; break;
184         case 'd': k->flags.disabled = 1; break;
185         case 'i': k->flags.invalid = 1; break;
186         }
187     }
188 }
189
190
191 static void
192 set_mainkey_capability (GpgmeKey key, const char *s)
193 {
194   for (; *s ; s++)
195     {
196       switch (*s)
197         {
198         case 'e': key->keys.flags.can_encrypt = 1; break;
199         case 's': key->keys.flags.can_sign = 1; break;
200         case 'c': key->keys.flags.can_certify = 1; break;
201         case 'E': key->gloflags.can_encrypt = 1; break;
202         case 'S': key->gloflags.can_sign = 1; break;
203         case 'C': key->gloflags.can_certify = 1; break;
204         }
205     }
206 }
207
208
209 static void
210 set_subkey_capability ( struct subkey_s *k, const char *s)
211 {
212   for (; *s; s++)
213     {
214       switch (*s)
215         {
216         case 'e': k->flags.can_encrypt = 1; break;
217         case 's': k->flags.can_sign = 1; break;
218         case 'c': k->flags.can_certify = 1; break;
219         }
220     }
221 }
222
223 static void
224 set_ownertrust (GpgmeKey key, const char *s)
225 {
226   /* Look at letters and stop at the first digit.  */
227   for (; *s && !my_isdigit (*s); s++)
228     {
229       switch (*s)
230         {
231         case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
232         case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
233         case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
234         case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
235         default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
236         }
237     }
238 }
239
240
241 /* Note: We are allowed to modify LINE.  */
242 static void
243 keylist_colon_handler (GpgmeCtx ctx, char *line)
244 {
245   char *p, *pend;
246   int field = 0;
247   enum
248     {
249       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
250       RT_CRT, RT_CRS
251     }
252   rectype = RT_NONE;
253   GpgmeKey key = ctx->tmp_key;
254   int i;
255   const char *trust_info = NULL;
256   struct subkey_s *sk = NULL;
257
258   DEBUG3 ("keylist_colon_handler ctx=%p, key=%p, line=%s\n", ctx, key, line);
259   if (ctx->error)
260     return;
261   if (!line)
262     {
263       /* EOF */
264       finish_key (ctx);
265       return; 
266     }
267   
268   for (p = line; p; p = pend)
269     {
270       field++;
271       pend = strchr (p, ':');
272       if (pend) 
273         *pend++ = 0;
274
275       if (field == 1)
276         {
277           if (!strcmp (p, "sig"))
278             rectype = RT_SIG;
279           else if (!strcmp (p, "uid") && key)
280             {
281               rectype = RT_UID;
282               key = ctx->tmp_key;
283             }
284           else if (!strcmp (p, "sub") && key)
285             {
286               /* Start a new subkey.  */
287               rectype = RT_SUB; 
288               if (!(sk = _gpgme_key_add_subkey (key)))
289                 {
290                   ctx->error = mk_error (Out_Of_Core);
291                   return;
292                 }
293             }
294           else if (!strcmp (p, "ssb") && key)
295             {
296               /* Start a new secret subkey.  */
297               rectype = RT_SSB;
298               if (!(sk = _gpgme_key_add_secret_subkey (key)))
299                 {
300                   ctx->error = mk_error (Out_Of_Core);
301                   return;
302                 }
303             }
304           else if (!strcmp (p, "pub"))
305             {
306               /* Start a new keyblock.  */
307               if (_gpgme_key_new (&key))
308                 {
309                   /* The only kind of error we can get.  */
310                   ctx->error = mk_error (Out_Of_Core);
311                   return;
312                 }
313               rectype = RT_PUB;
314               finish_key (ctx);
315               assert (!ctx->tmp_key);
316               ctx->tmp_key = key;
317             }
318           else if (!strcmp (p, "sec"))
319             {
320               /* Start a new keyblock,  */
321               if (_gpgme_key_new_secret (&key))
322                 {
323                   /* The only kind of error we can get.  */
324                   ctx->error = mk_error (Out_Of_Core);
325                   return;
326                 }
327               rectype = RT_SEC;
328               finish_key (ctx);
329               assert (!ctx->tmp_key);
330               ctx->tmp_key = key;
331             }
332           else if (!strcmp (p, "crt"))
333             {
334               /* Start a new certificate. */
335               if (_gpgme_key_new (&key))
336                 {
337                   /* The only kind of error we can get.  */
338                   ctx->error = mk_error (Out_Of_Core);
339                   return;
340                 }
341               key->x509 = 1;
342               rectype = RT_CRT;
343               finish_key (ctx);
344               assert (!ctx->tmp_key);
345               ctx->tmp_key = key;
346             }
347           else if (!strcmp (p, "crs"))
348             {
349               /* Start a new certificate.  */
350               if (_gpgme_key_new_secret (&key))
351                 {
352                   /* The only kind of error we can get.  */
353                   ctx->error = mk_error (Out_Of_Core);
354                   return;
355                 }
356               key->x509 = 1;
357               rectype = RT_CRS;
358               finish_key (ctx);
359               assert (!ctx->tmp_key);
360               ctx->tmp_key = key;
361             }
362           else if (!strcmp (p, "fpr") && key) 
363             rectype = RT_FPR;
364           else 
365             rectype = RT_NONE;
366         }
367       else if (rectype == RT_PUB || rectype == RT_SEC
368                || rectype == RT_CRT || rectype == RT_CRS)
369         {
370           switch (field)
371             {
372             case 2: /* trust info */
373               trust_info = p; 
374               set_mainkey_trust_info (key, trust_info);
375               break;
376             case 3: /* key length */
377               i = atoi (p); 
378               if (i > 1) /* ignore invalid values */
379                 key->keys.key_len = i; 
380                 break;
381             case 4: /* pubkey algo */
382               i = atoi (p);
383               if (i >= 1 && i < 128)
384                 key->keys.key_algo = i;
385               break;
386               case 5: /* long keyid */
387                 if (strlen (p) == DIM(key->keys.keyid) - 1)
388                   strcpy (key->keys.keyid, p);
389                 break;
390             case 6: /* timestamp (seconds) */
391               key->keys.timestamp = parse_timestamp (p);
392               break;
393             case 7: /* expiration time (seconds) */
394               key->keys.expires_at = parse_timestamp (p);
395               break;
396             case 8: /* X.509 serial number */
397               if (rectype == RT_CRT || rectype == RT_CRS)
398                 {
399                   key->issuer_serial = xtrystrdup (p);
400                   if (!key->issuer_serial)
401                     ctx->error = mk_error (Out_Of_Core);
402                 }
403               break;
404             case 9: /* ownertrust */
405               set_ownertrust (key, p);
406               break;
407             case 10:
408               /* Not used for gpg due to --fixed-list-mode option but
409                  GPGSM stores the issuer name.  */
410               if (rectype == RT_CRT || rectype == RT_CRS)
411                 if (_gpgme_decode_c_string (p, &key->issuer_name))
412                   ctx->error = mk_error (Out_Of_Core);
413               break;
414             case 11: /* signature class  */
415               break;
416             case 12: /* capabilities */
417               set_mainkey_capability (key, p);
418               break;
419             case 13:
420               pend = NULL;  /* we can stop here */
421               break;
422             }
423           }
424         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
425           {
426             switch (field)
427               {
428               case 2: /* trust info */
429                 set_subkey_trust_info (sk, p);
430                 break;
431               case 3: /* key length */
432                 i = atoi (p); 
433                 if (i > 1) /* ignore invalid values */
434                   sk->key_len = i; 
435                 break;
436               case 4: /* pubkey algo */
437                 i = atoi (p);
438                 if (i >= 1 && i < 128)
439                   sk->key_algo = i;
440                 break;
441               case 5: /* long keyid */
442                 if (strlen (p) == DIM(sk->keyid) - 1)
443                   strcpy (sk->keyid, p);
444                 break;
445               case 6: /* timestamp (seconds) */
446                 sk->timestamp = parse_timestamp (p);
447                 break;
448               case 7: /* expiration time (seconds) */
449                 sk->expires_at = parse_timestamp (p);
450                 break;
451               case 8: /* reserved (LID) */
452                 break;
453               case 9: /* ownertrust */
454                 break;
455               case 10:/* user ID n/a for a subkey */
456                 break;
457               case 11:  /* signature class  */
458                 break;
459               case 12: /* capability */
460                 set_subkey_capability (sk, p);
461                 break;
462               case 13:
463                 pend = NULL;  /* we can stop here */
464                 break;
465             }
466         }
467       else if (rectype == RT_UID)
468         {
469           switch (field)
470             {
471             case 2: /* trust info */
472               trust_info = p;  /*save for later */
473               break;
474             case 10: /* user ID */
475               if (_gpgme_key_append_name (key, p))
476                 /* The only kind of error we can get*/
477                 ctx->error = mk_error (Out_Of_Core);
478               else
479                 {
480                   if (trust_info)
481                     set_userid_flags (key, trust_info);
482                 }
483               pend = NULL;  /* we can stop here */
484               break;
485             }
486         }
487       else if (rectype == RT_FPR)
488         {
489           switch (field)
490             {
491             case 10: /* fingerprint (take only the first one)*/
492               if (!key->keys.fingerprint && *p)
493                 {
494                   key->keys.fingerprint = xtrystrdup (p);
495                   if (!key->keys.fingerprint)
496                     ctx->error = mk_error (Out_Of_Core);
497                 }
498               break;
499             case 13: /* gpgsm chain ID (take only the first one)*/
500               if (!key->chain_id && *p)
501                 {
502                   key->chain_id = xtrystrdup (p);
503                   if (!key->chain_id)
504                     ctx->error = mk_error (Out_Of_Core);
505                 }
506               pend = NULL; /* that is all we want */
507               break;
508             }
509         }
510     }
511 }
512
513
514 /*
515  * We have read an entire key into ctx->tmp_key and should now finish
516  * it.  It is assumed that this releases ctx->tmp_key.
517  */
518 static void
519 finish_key (GpgmeCtx ctx)
520 {
521   GpgmeKey key = ctx->tmp_key;
522
523   ctx->tmp_key = NULL;
524
525   if (key)
526     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
527 }
528
529
530 void
531 _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data)
532 {
533   GpgmeCtx ctx = (GpgmeCtx) data;
534   GpgmeKey key = (GpgmeKey) type_data;
535   struct key_queue_item_s *q, *q2;
536
537   assert (type == GPGME_EVENT_NEXT_KEY);
538
539   _gpgme_key_cache_add (key);
540
541   q = xtrymalloc (sizeof *q);
542   if (!q)
543     {
544       gpgme_key_release (key);
545       ctx->error = mk_error (Out_Of_Core);
546       return;
547     }
548   q->key = key;
549   q->next = NULL;
550   /* FIXME: Lock queue.  Use a tail pointer?  */
551   if (!(q2 = ctx->key_queue))
552     ctx->key_queue = q;
553   else
554     {
555       for (; q2->next; q2 = q2->next)
556         ;
557       q2->next = q;
558     }
559   ctx->key_cond = 1;
560   /* FIXME: Unlock queue.  */
561 }
562
563
564 /**
565  * gpgme_op_keylist_start:
566  * @c: context 
567  * @pattern: a GnuPG user ID or NULL for all
568  * @secret_only: List only keys where the secret part is available
569  * 
570  * Note that this function also cancels a pending key listing
571  * operaton. To actually retrieve the key, use
572  * gpgme_op_keylist_next().
573  * 
574  * Return value:  0 on success or an errorcode. 
575  **/
576 GpgmeError
577 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
578 {
579   GpgmeError err = 0;
580
581   err = _gpgme_op_reset (ctx, 2);
582   if (err)
583     goto leave;
584
585   gpgme_key_release (ctx->tmp_key);
586   ctx->tmp_key = NULL;
587   /* Fixme: Release key_queue.  */
588
589   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
590   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
591                                               keylist_colon_handler, ctx);
592   if (err)
593     goto leave;
594
595   /* We don't want to use the verbose mode as this will also print 
596      the key signatures which is in most cases not needed and furthermore we 
597      just ignore those lines - This should speed up things */
598   _gpgme_engine_set_verbosity (ctx->engine, 0);
599
600   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
601                                   ctx->keylist_mode);
602
603   if (!err)     /* And kick off the process.  */
604     err = _gpgme_engine_start (ctx->engine, ctx);
605
606  leave:
607   if (err)
608     {
609       ctx->pending = 0; 
610       _gpgme_engine_release (ctx->engine);
611       ctx->engine = NULL;
612     }
613   return err;
614 }
615
616
617 /**
618  * gpgme_op_keylist_ext_start:
619  * @c: context 
620  * @pattern: a NULL terminated array of search patterns
621  * @secret_only: List only keys where the secret part is available
622  * @reserved: Should be 0.
623  * 
624  * Note that this function also cancels a pending key listing
625  * operaton. To actually retrieve the key, use
626  * gpgme_op_keylist_next().
627  * 
628  * Return value:  0 on success or an errorcode. 
629  **/
630 GpgmeError
631 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
632                             int secret_only, int reserved)
633 {
634   GpgmeError err = 0;
635
636   err = _gpgme_op_reset (ctx, 2);
637   if (err)
638     goto leave;
639
640   gpgme_key_release (ctx->tmp_key);
641   ctx->tmp_key = NULL;
642
643   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
644   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
645                                               keylist_colon_handler, ctx);
646   if (err)
647     goto leave;
648
649   /* We don't want to use the verbose mode as this will also print 
650      the key signatures which is in most cases not needed and furthermore we 
651      just ignore those lines - This should speed up things */
652   _gpgme_engine_set_verbosity (ctx->engine, 0);
653
654   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
655                                       reserved, ctx->keylist_mode);
656
657   if (!err)     /* And kick off the process.  */
658     err = _gpgme_engine_start (ctx->engine, ctx);
659
660  leave:
661   if (err)
662     {
663       ctx->pending = 0; 
664       _gpgme_engine_release (ctx->engine);
665       ctx->engine = NULL;
666     }
667   return err;
668 }
669
670
671 /**
672  * gpgme_op_keylist_next:
673  * @c: Context
674  * @r_key: Returned key object
675  * 
676  * Return the next key from the key listing started with
677  * gpgme_op_keylist_start().  The caller must free the key using
678  * gpgme_key_release().  If the last key has already been returned the
679  * last time the function was called, %GPGME_EOF is returned and the
680  * operation is finished.
681  * 
682  * Return value: 0 on success, %GPGME_EOF or another error code.
683  **/
684 GpgmeError
685 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
686 {
687   struct key_queue_item_s *queue_item;
688
689   if (!r_key)
690     return mk_error (Invalid_Value);
691   *r_key = NULL;
692   if (!ctx)
693     return mk_error (Invalid_Value);
694   if (!ctx->pending)
695     return mk_error (No_Request);
696   if (ctx->error)
697     return ctx->error;
698
699   if (!ctx->key_queue)
700     {
701       GpgmeError err = _gpgme_wait_on_condition (ctx, &ctx->key_cond);
702       if (err)
703         {
704           ctx->pending = 0;
705           return err;
706         }
707       if (!ctx->pending)
708         {
709           /* The operation finished.  Because not all keys might have
710              been returned to the caller yet, we just reset the
711              pending flag to 1.  This will cause us to call
712              _gpgme_wait_on_condition without any active file
713              descriptors, but that is a no-op, so it is safe.  */
714           ctx->pending = 1;
715         }
716       if (!ctx->key_cond)
717         {
718           ctx->pending = 0;
719           return mk_error (EOF);
720         }
721       ctx->key_cond = 0; 
722       assert (ctx->key_queue);
723     }
724   queue_item = ctx->key_queue;
725   ctx->key_queue = queue_item->next;
726   if (!ctx->key_queue)
727     ctx->key_cond = 0;
728   
729   *r_key = queue_item->key;
730   xfree (queue_item);
731   return 0;
732 }
733
734
735 /**
736  * gpgme_op_keylist_end:
737  * @c: Context
738  * 
739  * Ends the keylist operation and allows to use the context for some
740  * other operation next.
741  **/
742 GpgmeError
743 gpgme_op_keylist_end (GpgmeCtx ctx)
744 {
745   if (!ctx)
746     return mk_error (Invalid_Value);
747   if (!ctx->pending)
748     return mk_error (No_Request);
749   if (ctx->error)
750     return ctx->error;
751
752   ctx->pending = 0;
753   return 0;
754 }