(gpgsm_sign): Include a short list of capabilities.
[gnupg.git] / sm / call-dirmngr.c
1 /* call-dirmngr.c - communication with the dromngr 
2  *      Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29 #include <ctype.h>
30
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <assuan.h>
34
35 #include "i18n.h"
36
37 struct membuf {
38   size_t len;
39   size_t size;
40   char *buf;
41   int out_of_core;
42 };
43
44
45
46 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
47 static int force_pipe_server = 0;
48
49 struct inq_certificate_parm_s {
50   ASSUAN_CONTEXT ctx;
51   ksba_cert_t cert;
52   ksba_cert_t issuer_cert;
53 };
54
55 struct lookup_parm_s {
56   CTRL ctrl;
57   ASSUAN_CONTEXT ctx;
58   void (*cb)(void *, ksba_cert_t);
59   void *cb_value;
60   struct membuf data;
61   int error;
62 };
63
64 struct run_command_parm_s {
65   ASSUAN_CONTEXT ctx;
66 };
67
68
69 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
70    create a buffer, put_membuf to append bytes and get_membuf to
71    release and return the buffer.  Allocation errors are detected but
72    only returned at the final get_membuf(), this helps not to clutter
73    the code with out of core checks.  */
74
75 static void
76 init_membuf (struct membuf *mb, int initiallen)
77 {
78   mb->len = 0;
79   mb->size = initiallen;
80   mb->out_of_core = 0;
81   mb->buf = xtrymalloc (initiallen);
82   if (!mb->buf)
83       mb->out_of_core = 1;
84 }
85
86 static void
87 put_membuf (struct membuf *mb, const void *buf, size_t len)
88 {
89   if (mb->out_of_core)
90     return;
91
92   if (mb->len + len >= mb->size)
93     {
94       char *p;
95       
96       mb->size += len + 1024;
97       p = xtryrealloc (mb->buf, mb->size);
98       if (!p)
99         {
100           mb->out_of_core = 1;
101           return;
102         }
103       mb->buf = p;
104     }
105   memcpy (mb->buf + mb->len, buf, len);
106   mb->len += len;
107 }
108
109 static void *
110 get_membuf (struct membuf *mb, size_t *len)
111 {
112   char *p;
113
114   if (mb->out_of_core)
115     {
116       xfree (mb->buf);
117       mb->buf = NULL;
118       return NULL;
119     }
120
121   p = mb->buf;
122   *len = mb->len;
123   mb->buf = NULL;
124   mb->out_of_core = 1; /* don't allow a reuse */
125   return p;
126 }
127
128
129
130
131 \f
132 /* Try to connect to the agent via socket or fork it off and work by
133    pipes.  Handle the server's initial greeting */
134 static int
135 start_dirmngr (void)
136 {
137   int rc;
138   char *infostr, *p;
139   ASSUAN_CONTEXT ctx;
140
141   if (dirmngr_ctx)
142     return 0; /* fixme: We need a context for each thread or serialize
143                  the access to the dirmngr */
144
145   infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
146   if (!infostr || !*infostr)
147     {
148       const char *pgmname;
149       const char *argv[3];
150       int no_close_list[3];
151       int i;
152
153       if (opt.verbose)
154         log_info (_("no running dirmngr - starting one\n"));
155       
156       if (fflush (NULL))
157         {
158           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
159           log_error ("error flushing pending output: %s\n", strerror (errno));
160           return tmperr;
161         }
162
163       if (!opt.dirmngr_program || !*opt.dirmngr_program)
164         opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
165       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
166         pgmname = opt.dirmngr_program;
167       else
168         pgmname++;
169
170       argv[0] = pgmname;
171       argv[1] = "--server";
172       argv[2] = NULL;
173
174       i=0;
175       if (log_get_fd () != -1)
176         no_close_list[i++] = log_get_fd ();
177       no_close_list[i++] = fileno (stderr);
178       no_close_list[i] = -1;
179
180       /* connect to the agent and perform initial handshaking */
181       rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
182                                 no_close_list);
183     }
184   else
185     {
186       int prot;
187       int pid;
188
189       infostr = xstrdup (infostr);
190       if ( !(p = strchr (infostr, ':')) || p == infostr)
191         {
192           log_error (_("malformed DIRMNGR_INFO environment variable\n"));
193           xfree (infostr);
194           force_pipe_server = 1;
195           return start_dirmngr ();
196         }
197       *p++ = 0;
198       pid = atoi (p);
199       while (*p && *p != ':')
200         p++;
201       prot = *p? atoi (p+1) : 0;
202       if (prot != 1)
203         {
204           log_error (_("dirmngr protocol version %d is not supported\n"),
205                      prot);
206           xfree (infostr);
207           force_pipe_server = 1;
208           return start_dirmngr ();
209         }
210
211       rc = assuan_socket_connect (&ctx, infostr, pid);
212       xfree (infostr);
213       if (rc == ASSUAN_Connect_Failed)
214         {
215           log_error (_("can't connect to the dirmngr - trying fall back\n"));
216           force_pipe_server = 1;
217           return start_dirmngr ();
218         }
219     }
220
221   if (rc)
222     {
223       log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
224       return gpg_error (GPG_ERR_NO_DIRMNGR);
225     }
226   dirmngr_ctx = ctx;
227
228   if (DBG_ASSUAN)
229     log_debug ("connection to dirmngr established\n");
230   return 0;
231 }
232
233
234 \f
235 /* Handle a SENDCERT inquiry. */
236 static AssuanError
237 inq_certificate (void *opaque, const char *line)
238 {
239   struct inq_certificate_parm_s *parm = opaque;
240   AssuanError rc;
241   const unsigned char *der;
242   size_t derlen;
243   int issuer_mode = 0;
244
245   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
246     {
247       line += 8;
248     }
249   else if (!strncmp (line, "SENDISSUERCERT", 14)
250            && (line[14] == ' ' || !line[14]))
251     {
252       line += 14;
253       issuer_mode = 1;
254     }
255   else
256     {
257       log_error ("unsupported inquiry `%s'\n", line);
258       return ASSUAN_Inquire_Unknown;
259     }
260
261   if (!*line)
262     { /* Send the current certificate. */
263       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
264                                  &derlen);
265       if (!der)
266         rc = ASSUAN_Inquire_Error;
267       else
268         rc = assuan_send_data (parm->ctx, der, derlen);
269     }
270   else if (issuer_mode)
271     {
272       log_error ("sending specific issuer certificate back "
273                  "is not yet implemented\n");
274       rc = ASSUAN_Inquire_Error;
275     }
276   else 
277     { /* Send the given certificate. */
278       int err;
279       ksba_cert_t cert;
280
281
282       err = gpgsm_find_cert (line, &cert);
283       if (err)
284         {
285           log_error ("certificate not found: %s\n", gpg_strerror (err));
286           rc = ASSUAN_Inquire_Error;
287         }
288       else
289         {
290           der = ksba_cert_get_image (cert, &derlen);
291           if (!der)
292             rc = ASSUAN_Inquire_Error;
293           else
294             rc = assuan_send_data (parm->ctx, der, derlen);
295           ksba_cert_release (cert);
296         }
297     }
298
299   return rc; 
300 }
301
302
303 \f
304 /* Call the directory manager to check whether the certificate is valid
305    Returns 0 for valid or usually one of the errors:
306
307   GPG_ERR_CERTIFICATE_REVOKED
308   GPG_ERR_NO_CRL_KNOWN
309   GPG_ERR_CRL_TOO_OLD
310
311   With USE_OCSP set to true, the dirmngr is asked to do an OCSP
312   request first.
313  */
314 int
315 gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
316 {
317   int rc;
318   char *certid;
319   char line[ASSUAN_LINELENGTH];
320   struct inq_certificate_parm_s parm;
321
322   rc = start_dirmngr ();
323   if (rc)
324     return rc;
325
326   if (use_ocsp)
327     {
328       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
329     }
330   else
331     {
332       certid = gpgsm_get_certid (cert);
333       if (!certid)
334         {
335           log_error ("error getting the certificate ID\n");
336           return gpg_error (GPG_ERR_GENERAL);
337         }
338     }
339
340   if (opt.verbose > 1)
341     {
342       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
343       log_info ("asking dirmngr about %s%s\n", fpr,
344                 use_ocsp? " (using OCSP)":"");
345       xfree (fpr);
346     }
347
348   parm.ctx = dirmngr_ctx;
349   parm.cert = cert;
350   parm.issuer_cert = issuer_cert;
351
352   /* FIXME: If --disable-crl-checks has been set, we should pass an
353      option to dirmngr, so that no fallback CRL check is done after an
354      ocsp check. */
355
356   snprintf (line, DIM(line)-1, "ISVALID %s", certid);
357   line[DIM(line)-1] = 0;
358   xfree (certid);
359
360   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
361                         inq_certificate, &parm, NULL, NULL);
362   if (opt.verbose > 1)
363     log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
364   return map_assuan_err (rc);
365 }
366
367
368 \f
369 /* Lookup helpers*/
370 static AssuanError
371 lookup_cb (void *opaque, const void *buffer, size_t length)
372 {
373   struct lookup_parm_s *parm = opaque;
374   size_t len;
375   char *buf;
376   ksba_cert_t cert;
377   int rc;
378
379   if (parm->error)
380     return 0;
381
382   if (buffer)
383     {
384       put_membuf (&parm->data, buffer, length);
385       return 0;
386     }
387   /* END encountered - process what we have */
388   buf = get_membuf (&parm->data, &len);
389   if (!buf)
390     {
391       parm->error = gpg_error (GPG_ERR_ENOMEM);
392       return 0;
393     }
394
395   rc = ksba_cert_new (&cert);
396   if (rc)
397     {
398       parm->error = rc;
399       return 0;
400     }
401   rc = ksba_cert_init_from_mem (cert, buf, len);
402   if (rc)
403     {
404       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
405     }
406   else
407     {
408       parm->cb (parm->cb_value, cert);
409     }
410
411   ksba_cert_release (cert);
412   init_membuf (&parm->data, 4096);
413   return 0;
414 }
415
416 /* Return a properly escaped pattern from NAMES.  The only error
417    return is NULL to indicate a malloc failure. */
418 static char *
419 pattern_from_strlist (STRLIST names)
420 {
421   STRLIST sl;
422   int n;
423   const char *s;
424   char *pattern, *p;
425
426   for (n=0, sl=names; sl; sl = sl->next)
427     {
428       for (s=sl->d; *s; s++, n++)
429         {
430           if (*s == '%' || *s == ' ' || *s == '+')
431             n += 2;
432         }
433       n++;
434     }
435
436   p = pattern = xtrymalloc (n+1);
437   if (!pattern)
438     return NULL;
439
440   for (n=0, sl=names; sl; sl = sl->next)
441     {
442       for (s=sl->d; *s; s++)
443         {
444           switch (*s)
445             {
446             case '%':
447               *p++ = '%';
448               *p++ = '2';
449               *p++ = '5';
450               break;
451             case ' ':
452               *p++ = '%';
453               *p++ = '2';
454               *p++ = '0';
455               break;
456             case '+':
457               *p++ = '%';
458               *p++ = '2';
459               *p++ = 'B';
460               break;
461             default:
462               *p++ = *s;
463               break;
464             }
465         }
466       *p++ = ' ';
467     }
468   if (p == pattern)
469     *pattern = 0; /* is empty */
470   else
471     p[-1] = '\0'; /* remove trailing blank */
472   
473   return pattern;
474 }
475
476 static AssuanError
477 lookup_status_cb (void *opaque, const char *line)
478 {
479   struct lookup_parm_s *parm = opaque;
480
481   if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
482     {
483       if (parm->ctrl)
484         {
485           for (line +=9; *line == ' '; line++)
486             ;
487           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
488         }
489     }
490   return 0;
491 }
492
493
494 /* Run the Directroy Managers lookup command using the pattern
495    compiled from the strings given in NAMES.  The caller must provide
496    the callback CB which will be passed cert by cert.  Note that CTRL
497    is optional. */
498 int 
499 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
500                       void (*cb)(void*, ksba_cert_t), void *cb_value)
501
502   int rc;
503   char *pattern;
504   char line[ASSUAN_LINELENGTH];
505   struct lookup_parm_s parm;
506   size_t len;
507
508   rc = start_dirmngr ();
509   if (rc)
510     return rc;
511
512   pattern = pattern_from_strlist (names);
513   if (!pattern)
514     return OUT_OF_CORE (errno);
515   snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
516   line[DIM(line)-1] = 0;
517   xfree (pattern);
518
519   parm.ctrl = ctrl;
520   parm.ctx = dirmngr_ctx;
521   parm.cb = cb;
522   parm.cb_value = cb_value;
523   parm.error = 0;
524   init_membuf (&parm.data, 4096);
525
526   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
527                         NULL, NULL, lookup_status_cb, &parm);
528   xfree (get_membuf (&parm.data, &len));
529   if (rc)
530     return map_assuan_err (rc);
531   return parm.error;
532 }
533
534
535 \f
536 /* Run Command helpers*/
537
538 /* Fairly simple callback to write all output of dirmngr to stdout. */
539 static AssuanError
540 run_command_cb (void *opaque, const void *buffer, size_t length)
541 {
542   if (buffer)
543     {
544       if ( fwrite (buffer, length, 1, stdout) != 1 )
545         log_error ("error writing to stdout: %s\n", strerror (errno));
546     }
547   return 0;
548 }
549
550 /* Handle inquiries from the dirmngr COMMAND. */
551 static AssuanError
552 run_command_inq_cb (void *opaque, const char *line)
553 {
554   struct run_command_parm_s *parm = opaque;
555   AssuanError rc = 0;
556
557   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
558     { /* send the given certificate */
559       int err;
560       ksba_cert_t cert;
561       const unsigned char *der;
562       size_t derlen;
563
564       line += 8;
565       if (!*line)
566         return ASSUAN_Inquire_Error;
567
568       err = gpgsm_find_cert (line, &cert);
569       if (err)
570         {
571           log_error ("certificate not found: %s\n", gpg_strerror (err));
572           rc = ASSUAN_Inquire_Error;
573         }
574       else
575         {
576           der = ksba_cert_get_image (cert, &derlen);
577           if (!der)
578             rc = ASSUAN_Inquire_Error;
579           else
580             rc = assuan_send_data (parm->ctx, der, derlen);
581           ksba_cert_release (cert);
582         }
583     }
584   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
585     { /* Simply show the message given in the argument. */
586       line += 9;
587       log_info ("dirmngr: %s\n", line);
588     }
589   else
590     {
591       log_error ("unsupported inquiry `%s'\n", line);
592       rc = ASSUAN_Inquire_Unknown;
593     }
594
595   return rc; 
596 }
597
598 static AssuanError
599 run_command_status_cb (void *opaque, const char *line)
600 {
601   if (opt.verbose)
602     {
603       log_info ("dirmngr status: %s\n", line);
604     }
605   return 0;
606 }
607
608
609
610 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
611    to stdout.  A couple of inquiries are defined (see above).  ARGC
612    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
613    percent characters within the argument strings are percent escaped
614    so that blanks can act as delimiters. */
615 int
616 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
617                            int argc, char **argv)
618
619   int rc;
620   int i;
621   const char *s;
622   char *line, *p;
623   size_t len;
624   struct run_command_parm_s parm;
625
626   rc = start_dirmngr ();
627   if (rc)
628     return rc;
629
630   parm.ctx = dirmngr_ctx;
631
632   len = strlen (command) + 1;
633   for (i=0; i < argc; i++)
634     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
635   line = xtrymalloc (len);
636   if (!line)
637     return OUT_OF_CORE (errno);
638
639   p = stpcpy (line, command);
640   for (i=0; i < argc; i++)
641     {
642       *p++ = ' ';
643       for (s=argv[i]; *s; s++)
644         {
645           if (!isascii (*s))
646             *p++ = *s;
647           else if (*s == ' ')
648             *p++ = '+';
649           else if (!isprint (*s) || *s == '+')
650             {
651               sprintf (p, "%%%02X", *s);
652               p += 3;
653             }
654           else
655             *p++ = *s;
656         }
657     }
658   *p = 0;
659
660   rc = assuan_transact (dirmngr_ctx, line,
661                         run_command_cb, NULL,
662                         run_command_inq_cb, &parm,
663                         run_command_status_cb, NULL);
664   xfree (line);
665   log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
666   return map_assuan_err (rc);
667 }