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