* key.h (struct certsig_s): New. Use it in gpgme_key_s.
[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       finish_key (ctx);
105       if (ctx->result.keylist->truncated)
106         append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, "1");
107       if (ctx->result.keylist->xmlinfo)
108         {
109           append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, NULL);
110           _gpgme_set_op_info (ctx, ctx->result.keylist->xmlinfo);
111           ctx->result.keylist->xmlinfo = NULL;
112         }
113       break;
114
115     default:
116       /* Ignore all other codes.  */
117       break;
118     }
119 }
120
121
122 static time_t
123 parse_timestamp (char *p)
124 {
125   if (!*p)
126     return 0;
127
128   return (time_t)strtoul (p, NULL, 10);
129 }
130
131
132 static void
133 set_mainkey_trust_info (GpgmeKey key, const char *s)
134 {
135   /* Look at letters and stop at the first digit.  */
136   for (; *s && !my_isdigit (*s); s++)
137     {
138       switch (*s)
139         {
140         case 'e': key->keys.flags.expired = 1; break;
141         case 'r': key->keys.flags.revoked = 1; break;
142         case 'd': key->keys.flags.disabled = 1; break;
143         case 'i': key->keys.flags.invalid = 1; break;
144         }
145     }
146 }
147
148
149 static void
150 set_userid_flags (GpgmeKey key, const char *s)
151 {
152   struct user_id_s *u = key->uids;
153
154   assert (u);
155   while (u->next)
156     u = u->next;
157
158   /* Look at letters and stop at the first digit.  */
159   for (; *s && !my_isdigit (*s); s++)
160     {
161       switch (*s)
162         {
163         case 'r': u->revoked  = 1; break;
164         case 'i': u->invalid  = 1; break;
165
166         case 'n': u->validity = GPGME_VALIDITY_NEVER; break;
167         case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break;
168         case 'f': u->validity = GPGME_VALIDITY_FULL; break;
169         case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break;
170         }
171     }
172 }
173
174
175 static void
176 set_subkey_trust_info (struct subkey_s *k, const char *s)
177 {
178   /* Look at letters and stop at the first digit.  */
179   for (; *s && !my_isdigit (*s); s++)
180     {
181       switch (*s)
182         {
183         case 'e': k->flags.expired = 1; break;
184         case 'r': k->flags.revoked = 1; break;
185         case 'd': k->flags.disabled = 1; break;
186         case 'i': k->flags.invalid = 1; break;
187         }
188     }
189 }
190
191
192 static void
193 set_mainkey_capability (GpgmeKey key, const char *s)
194 {
195   for (; *s ; s++)
196     {
197       switch (*s)
198         {
199         case 'e': key->keys.flags.can_encrypt = 1; break;
200         case 's': key->keys.flags.can_sign = 1; break;
201         case 'c': key->keys.flags.can_certify = 1; break;
202         case 'E': key->gloflags.can_encrypt = 1; break;
203         case 'S': key->gloflags.can_sign = 1; break;
204         case 'C': key->gloflags.can_certify = 1; break;
205         }
206     }
207 }
208
209
210 static void
211 set_subkey_capability ( struct subkey_s *k, const char *s)
212 {
213   for (; *s; s++)
214     {
215       switch (*s)
216         {
217         case 'e': k->flags.can_encrypt = 1; break;
218         case 's': k->flags.can_sign = 1; break;
219         case 'c': k->flags.can_certify = 1; break;
220         }
221     }
222 }
223
224 static void
225 set_ownertrust (GpgmeKey key, const char *s)
226 {
227   /* Look at letters and stop at the first digit.  */
228   for (; *s && !my_isdigit (*s); s++)
229     {
230       switch (*s)
231         {
232         case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
233         case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
234         case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
235         case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
236         default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
237         }
238     }
239 }
240
241
242 /* Note: We are allowed to modify LINE.  */
243 static void
244 keylist_colon_handler (GpgmeCtx ctx, char *line)
245 {
246   char *p, *pend;
247   int field = 0;
248   enum
249     {
250       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
251       RT_CRT, RT_CRS
252     }
253   rectype = RT_NONE;
254   GpgmeKey key = ctx->tmp_key;
255   int i;
256   const char *trust_info = NULL;
257   struct subkey_s *sk = NULL;
258
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: /* not used for gpg due to --fixed-list-mode option 
408                         but gpgsm stores the issuer name */
409               if (rectype == RT_CRT || rectype == RT_CRS)
410                 {
411                   key->issuer_name = xtrystrdup (p);
412                   if (!key->issuer_name)
413                     ctx->error = mk_error (Out_Of_Core);
414                 }
415               break;
416             case 11: /* signature class  */
417               break;
418             case 12: /* capabilities */
419               set_mainkey_capability (key, p);
420               break;
421             case 13:
422               pend = NULL;  /* we can stop here */
423               break;
424             }
425           }
426         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
427           {
428             switch (field)
429               {
430               case 2: /* trust info */
431                 set_subkey_trust_info (sk, p);
432                 break;
433               case 3: /* key length */
434                 i = atoi (p); 
435                 if (i > 1) /* ignore invalid values */
436                   sk->key_len = i; 
437                 break;
438               case 4: /* pubkey algo */
439                 i = atoi (p);
440                 if (i >= 1 && i < 128)
441                   sk->key_algo = i;
442                 break;
443               case 5: /* long keyid */
444                 if (strlen (p) == DIM(sk->keyid) - 1)
445                   strcpy (sk->keyid, p);
446                 break;
447               case 6: /* timestamp (seconds) */
448                 sk->timestamp = parse_timestamp (p);
449                 break;
450               case 7: /* expiration time (seconds) */
451                 sk->expires_at = parse_timestamp (p);
452                 break;
453               case 8: /* reserved (LID) */
454                 break;
455               case 9: /* ownertrust */
456                 break;
457               case 10:/* user ID n/a for a subkey */
458                 break;
459               case 11:  /* signature class  */
460                 break;
461               case 12: /* capability */
462                 set_subkey_capability (sk, p);
463                 break;
464               case 13:
465                 pend = NULL;  /* we can stop here */
466                 break;
467             }
468         }
469       else if (rectype == RT_UID)
470         {
471           switch (field)
472             {
473             case 2: /* trust info */
474               trust_info = p;  /*save for later */
475               break;
476             case 10: /* user ID */
477               if (_gpgme_key_append_name (key, p))
478                 /* The only kind of error we can get*/
479                 ctx->error = mk_error (Out_Of_Core);
480               else
481                 {
482                   if (trust_info)
483                     set_userid_flags (key, trust_info);
484                 }
485               pend = NULL;  /* we can stop here */
486               break;
487             }
488         }
489       else if (rectype == RT_FPR)
490         {
491           switch (field)
492             {
493             case 10: /* fingerprint (take only the first one)*/
494               if (!key->keys.fingerprint && *p)
495                 {
496                   key->keys.fingerprint = xtrystrdup (p);
497                   if (!key->keys.fingerprint)
498                     ctx->error = mk_error (Out_Of_Core);
499                 }
500               break;
501             case 13: /* gpgsm chain ID (take only the first one)*/
502               if (!key->chain_id && *p)
503                 {
504                   key->chain_id = xtrystrdup (p);
505                   if (!key->chain_id)
506                     ctx->error = mk_error (Out_Of_Core);
507                 }
508               pend = NULL; /* that is all we want */
509               break;
510             }
511         }
512     }
513 }
514
515
516 /*
517  * We have read an entire key into ctx->tmp_key and should now finish
518  * it.  It is assumed that this releases ctx->tmp_key.
519  */
520 static void
521 finish_key (GpgmeCtx ctx)
522 {
523   GpgmeKey key = ctx->tmp_key;
524
525   ctx->tmp_key = NULL;
526
527   if (key)
528     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
529 }
530
531
532 void
533 _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data)
534 {
535   GpgmeCtx ctx = (GpgmeCtx) data;
536   GpgmeKey key = (GpgmeKey) type_data;
537   struct key_queue_item_s *q, *q2;
538
539   assert (type == GPGME_EVENT_NEXT_KEY);
540
541   _gpgme_key_cache_add (key);
542
543   q = xtrymalloc (sizeof *q);
544   if (!q)
545     {
546       gpgme_key_release (key);
547       ctx->error = mk_error (Out_Of_Core);
548       return;
549     }
550   q->key = key;
551   q->next = NULL;
552   /* FIXME: Lock queue.  Use a tail pointer?  */
553   if (!(q2 = ctx->key_queue))
554     ctx->key_queue = q;
555   else
556     {
557       for (; q2->next; q2 = q2->next)
558         ;
559       q2->next = q;
560     }
561   ctx->key_cond = 1;
562   /* FIXME: Unlock queue.  */
563 }
564
565
566 /**
567  * gpgme_op_keylist_start:
568  * @c: context 
569  * @pattern: a GnuPG user ID or NULL for all
570  * @secret_only: List only keys where the secret part is available
571  * 
572  * Note that this function also cancels a pending key listing
573  * operaton. To actually retrieve the key, use
574  * gpgme_op_keylist_next().
575  * 
576  * Return value:  0 on success or an errorcode. 
577  **/
578 GpgmeError
579 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
580 {
581   GpgmeError err = 0;
582
583   err = _gpgme_op_reset (ctx, 2);
584   if (err)
585     goto leave;
586
587   gpgme_key_release (ctx->tmp_key);
588   ctx->tmp_key = NULL;
589   /* Fixme: Release key_queue.  */
590
591   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
592   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
593                                               keylist_colon_handler, ctx);
594   if (err)
595     goto leave;
596
597   /* We don't want to use the verbose mode as this will also print 
598      the key signatures which is in most cases not needed and furthermore we 
599      just ignore those lines - This should speed up things */
600   _gpgme_engine_set_verbosity (ctx->engine, 0);
601
602   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
603                                   ctx->keylist_mode);
604
605   if (!err)     /* And kick off the process.  */
606     err = _gpgme_engine_start (ctx->engine, ctx);
607
608  leave:
609   if (err)
610     {
611       ctx->pending = 0; 
612       _gpgme_engine_release (ctx->engine);
613       ctx->engine = NULL;
614     }
615   return err;
616 }
617
618
619 /**
620  * gpgme_op_keylist_ext_start:
621  * @c: context 
622  * @pattern: a NULL terminated array of search patterns
623  * @secret_only: List only keys where the secret part is available
624  * @reserved: Should be 0.
625  * 
626  * Note that this function also cancels a pending key listing
627  * operaton. To actually retrieve the key, use
628  * gpgme_op_keylist_next().
629  * 
630  * Return value:  0 on success or an errorcode. 
631  **/
632 GpgmeError
633 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
634                             int secret_only, int reserved)
635 {
636   GpgmeError err = 0;
637
638   /* Keylist operations are always "synchronous" in the sense that we
639      don't add ourself to the global FD table.  */
640   err = _gpgme_op_reset (ctx, 1);
641   if (err)
642     goto leave;
643
644   gpgme_key_release (ctx->tmp_key);
645
646   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
647   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
648                                               keylist_colon_handler, ctx);
649   if (err)
650     goto leave;
651
652   /* We don't want to use the verbose mode as this will also print 
653      the key signatures which is in most cases not needed and furthermore we 
654      just ignore those lines - This should speed up things */
655   _gpgme_engine_set_verbosity (ctx->engine, 0);
656
657   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
658                                       reserved, ctx->keylist_mode);
659
660   if (!err)     /* And kick off the process.  */
661     err = _gpgme_engine_start (ctx->engine, ctx);
662
663  leave:
664   if (err)
665     {
666       ctx->pending = 0; 
667       _gpgme_engine_release (ctx->engine);
668       ctx->engine = NULL;
669     }
670   return err;
671 }
672
673
674 /**
675  * gpgme_op_keylist_next:
676  * @c: Context
677  * @r_key: Returned key object
678  * 
679  * Return the next key from the key listing started with
680  * gpgme_op_keylist_start().  The caller must free the key using
681  * gpgme_key_release().  If the last key has already been returned the
682  * last time the function was called, %GPGME_EOF is returned and the
683  * operation is finished.
684  * 
685  * Return value: 0 on success, %GPGME_EOF or another error code.
686  **/
687 GpgmeError
688 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
689 {
690   struct key_queue_item_s *queue_item;
691
692   if (!r_key)
693     return mk_error (Invalid_Value);
694   *r_key = NULL;
695   if (!ctx)
696     return mk_error (Invalid_Value);
697   if (!ctx->pending)
698     return mk_error (No_Request);
699   if (ctx->error)
700     return ctx->error;
701
702   if (!ctx->key_queue)
703     {
704       GpgmeError err = _gpgme_wait_on_condition (ctx, &ctx->key_cond);
705       if (err)
706         {
707           ctx->pending = 0;
708           return err;
709         }
710       if (!ctx->pending)
711         {
712           /* The operation finished.  Because not all keys might have
713              been returned to the caller yet, we just reset the
714              pending flag to 1.  This will cause us to call
715              _gpgme_wait_on_condition without any active file
716              descriptors, but that is a no-op, so it is safe.  */
717           ctx->pending = 1;
718         }
719       if (!ctx->key_cond)
720         {
721           ctx->pending = 0;
722           return mk_error (EOF);
723         }
724       ctx->key_cond = 0; 
725       assert (ctx->key_queue);
726     }
727   queue_item = ctx->key_queue;
728   ctx->key_queue = queue_item->next;
729   if (!ctx->key_queue)
730     ctx->key_cond = 0;
731   
732   *r_key = queue_item->key;
733   xfree (queue_item);
734   return 0;
735 }
736
737
738 /**
739  * gpgme_op_keylist_end:
740  * @c: Context
741  * 
742  * Ends the keylist operation and allows to use the context for some
743  * other operation next.
744  **/
745 GpgmeError
746 gpgme_op_keylist_end (GpgmeCtx ctx)
747 {
748   if (!ctx)
749     return mk_error (Invalid_Value);
750   if (!ctx->pending)
751     return mk_error (No_Request);
752   if (ctx->error)
753     return ctx->error;
754
755   ctx->pending = 0;
756   return 0;
757 }