0e8f67f286557c4d0cfd1c5e542f2b1b8b05024a
[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 #include "keydb.h"
37
38
39 struct membuf {
40   size_t len;
41   size_t size;
42   char *buf;
43   int out_of_core;
44 };
45
46
47
48 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
49 static int force_pipe_server = 0;
50
51 struct inq_certificate_parm_s {
52   ASSUAN_CONTEXT ctx;
53   ksba_cert_t cert;
54   ksba_cert_t issuer_cert;
55 };
56
57 struct isvalid_status_parm_s {
58   int seen;
59   unsigned char fpr[20];
60 };
61
62
63 struct lookup_parm_s {
64   CTRL ctrl;
65   ASSUAN_CONTEXT ctx;
66   void (*cb)(void *, ksba_cert_t);
67   void *cb_value;
68   struct membuf data;
69   int error;
70 };
71
72 struct run_command_parm_s {
73   ASSUAN_CONTEXT ctx;
74 };
75
76
77 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
78    create a buffer, put_membuf to append bytes and get_membuf to
79    release and return the buffer.  Allocation errors are detected but
80    only returned at the final get_membuf(), this helps not to clutter
81    the code with out of core checks.  */
82
83 static void
84 init_membuf (struct membuf *mb, int initiallen)
85 {
86   mb->len = 0;
87   mb->size = initiallen;
88   mb->out_of_core = 0;
89   mb->buf = xtrymalloc (initiallen);
90   if (!mb->buf)
91       mb->out_of_core = 1;
92 }
93
94 static void
95 put_membuf (struct membuf *mb, const void *buf, size_t len)
96 {
97   if (mb->out_of_core)
98     return;
99
100   if (mb->len + len >= mb->size)
101     {
102       char *p;
103       
104       mb->size += len + 1024;
105       p = xtryrealloc (mb->buf, mb->size);
106       if (!p)
107         {
108           mb->out_of_core = 1;
109           return;
110         }
111       mb->buf = p;
112     }
113   memcpy (mb->buf + mb->len, buf, len);
114   mb->len += len;
115 }
116
117 static void *
118 get_membuf (struct membuf *mb, size_t *len)
119 {
120   char *p;
121
122   if (mb->out_of_core)
123     {
124       xfree (mb->buf);
125       mb->buf = NULL;
126       return NULL;
127     }
128
129   p = mb->buf;
130   *len = mb->len;
131   mb->buf = NULL;
132   mb->out_of_core = 1; /* don't allow a reuse */
133   return p;
134 }
135
136
137
138
139 \f
140 /* Try to connect to the agent via socket or fork it off and work by
141    pipes.  Handle the server's initial greeting */
142 static int
143 start_dirmngr (void)
144 {
145   int rc;
146   char *infostr, *p;
147   ASSUAN_CONTEXT ctx;
148
149   if (dirmngr_ctx)
150     return 0; /* fixme: We need a context for each thread or serialize
151                  the access to the dirmngr */
152
153   infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
154   if (!infostr || !*infostr)
155     {
156       const char *pgmname;
157       const char *argv[3];
158       int no_close_list[3];
159       int i;
160
161       if (opt.verbose)
162         log_info (_("no running dirmngr - starting one\n"));
163       
164       if (fflush (NULL))
165         {
166           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
167           log_error ("error flushing pending output: %s\n", strerror (errno));
168           return tmperr;
169         }
170
171       if (!opt.dirmngr_program || !*opt.dirmngr_program)
172         opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
173       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
174         pgmname = opt.dirmngr_program;
175       else
176         pgmname++;
177
178       argv[0] = pgmname;
179       argv[1] = "--server";
180       argv[2] = NULL;
181
182       i=0;
183       if (log_get_fd () != -1)
184         no_close_list[i++] = log_get_fd ();
185       no_close_list[i++] = fileno (stderr);
186       no_close_list[i] = -1;
187
188       /* connect to the agent and perform initial handshaking */
189       rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
190                                 no_close_list);
191     }
192   else
193     {
194       int prot;
195       int pid;
196
197       infostr = xstrdup (infostr);
198       if ( !(p = strchr (infostr, ':')) || p == infostr)
199         {
200           log_error (_("malformed DIRMNGR_INFO environment variable\n"));
201           xfree (infostr);
202           force_pipe_server = 1;
203           return start_dirmngr ();
204         }
205       *p++ = 0;
206       pid = atoi (p);
207       while (*p && *p != ':')
208         p++;
209       prot = *p? atoi (p+1) : 0;
210       if (prot != 1)
211         {
212           log_error (_("dirmngr protocol version %d is not supported\n"),
213                      prot);
214           xfree (infostr);
215           force_pipe_server = 1;
216           return start_dirmngr ();
217         }
218
219       rc = assuan_socket_connect (&ctx, infostr, pid);
220       xfree (infostr);
221       if (rc == ASSUAN_Connect_Failed)
222         {
223           log_error (_("can't connect to the dirmngr - trying fall back\n"));
224           force_pipe_server = 1;
225           return start_dirmngr ();
226         }
227     }
228
229   if (rc)
230     {
231       log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
232       return gpg_error (GPG_ERR_NO_DIRMNGR);
233     }
234   dirmngr_ctx = ctx;
235
236   if (DBG_ASSUAN)
237     log_debug ("connection to dirmngr established\n");
238   return 0;
239 }
240
241
242 \f
243 /* Handle a SENDCERT inquiry. */
244 static AssuanError
245 inq_certificate (void *opaque, const char *line)
246 {
247   struct inq_certificate_parm_s *parm = opaque;
248   AssuanError rc;
249   const unsigned char *der;
250   size_t derlen;
251   int issuer_mode = 0;
252
253   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
254     {
255       line += 8;
256     }
257   else if (!strncmp (line, "SENDISSUERCERT", 14)
258            && (line[14] == ' ' || !line[14]))
259     {
260       line += 14;
261       issuer_mode = 1;
262     }
263   else
264     {
265       log_error ("unsupported inquiry `%s'\n", line);
266       return ASSUAN_Inquire_Unknown;
267     }
268
269   if (!*line)
270     { /* Send the current certificate. */
271       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
272                                  &derlen);
273       if (!der)
274         rc = ASSUAN_Inquire_Error;
275       else
276         rc = assuan_send_data (parm->ctx, der, derlen);
277     }
278   else if (issuer_mode)
279     {
280       log_error ("sending specific issuer certificate back "
281                  "is not yet implemented\n");
282       rc = ASSUAN_Inquire_Error;
283     }
284   else 
285     { /* Send the given certificate. */
286       int err;
287       ksba_cert_t cert;
288
289
290       err = gpgsm_find_cert (line, &cert);
291       if (err)
292         {
293           log_error ("certificate not found: %s\n", gpg_strerror (err));
294           rc = ASSUAN_Inquire_Error;
295         }
296       else
297         {
298           der = ksba_cert_get_image (cert, &derlen);
299           if (!der)
300             rc = ASSUAN_Inquire_Error;
301           else
302             rc = assuan_send_data (parm->ctx, der, derlen);
303           ksba_cert_release (cert);
304         }
305     }
306
307   return rc; 
308 }
309
310
311 /* Take a 20 byte hexencoded string and put it into the the provided
312    20 byte buffer FPR in binary format. */
313 static int
314 unhexify_fpr (const char *hexstr, unsigned char *fpr)
315 {
316   const char *s;
317   int n;
318
319   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
320     ;
321   if (*s || (n != 40))
322     return 0; /* no fingerprint (invalid or wrong length). */
323   n /= 2;
324   for (s=hexstr, n=0; *s; s += 2, n++)
325     fpr[n] = xtoi_2 (s);
326   return 1; /* okay */
327 }
328
329
330 static assuan_error_t
331 isvalid_status_cb (void *opaque, const char *line)
332 {
333   struct isvalid_status_parm_s *parm = opaque;
334
335   if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
336       && (line[24]==' ' || !line[24]))
337     {
338       parm->seen++;
339       if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
340         parm->seen++; /* Bumb it to indicate an error. */
341     }
342   return 0;
343 }
344
345
346
347 \f
348 /* Call the directory manager to check whether the certificate is valid
349    Returns 0 for valid or usually one of the errors:
350
351   GPG_ERR_CERTIFICATE_REVOKED
352   GPG_ERR_NO_CRL_KNOWN
353   GPG_ERR_CRL_TOO_OLD
354
355   With USE_OCSP set to true, the dirmngr is asked to do an OCSP
356   request first.
357  */
358 int
359 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
360                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
361 {
362   int rc;
363   char *certid;
364   char line[ASSUAN_LINELENGTH];
365   struct inq_certificate_parm_s parm;
366   struct isvalid_status_parm_s stparm;
367
368   rc = start_dirmngr ();
369   if (rc)
370     return rc;
371
372   if (use_ocsp)
373     {
374       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
375     }
376   else
377     {
378       certid = gpgsm_get_certid (cert);
379       if (!certid)
380         {
381           log_error ("error getting the certificate ID\n");
382           return gpg_error (GPG_ERR_GENERAL);
383         }
384     }
385
386   if (opt.verbose > 1)
387     {
388       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
389       log_info ("asking dirmngr about %s%s\n", fpr,
390                 use_ocsp? " (using OCSP)":"");
391       xfree (fpr);
392     }
393
394   parm.ctx = dirmngr_ctx;
395   parm.cert = cert;
396   parm.issuer_cert = issuer_cert;
397
398   stparm.seen = 0;
399   memset (stparm.fpr, 0, 20);
400
401   /* FIXME: If --disable-crl-checks has been set, we should pass an
402      option to dirmngr, so that no fallback CRL check is done after an
403      ocsp check. */
404
405   snprintf (line, DIM(line)-1, "ISVALID %s", certid);
406   line[DIM(line)-1] = 0;
407   xfree (certid);
408
409   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
410                         inq_certificate, &parm,
411                         isvalid_status_cb, &stparm);
412   if (opt.verbose > 1)
413     log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
414   rc = map_assuan_err (rc);
415
416   if (!rc && stparm.seen)
417     {
418       /* Need to also check the certificate validity. */
419       if (stparm.seen != 1)
420         {
421           log_error ("communication problem with dirmngr detected\n");
422           rc = gpg_error (GPG_ERR_INV_CRL);
423         }
424       else
425         {
426           KEYDB_HANDLE kh;
427           ksba_cert_t rspcert = NULL;
428
429           /* Fixme: First try to get the certificate from the
430              dirmngr's cache - it should be there. */
431           kh = keydb_new (0);
432           if (!kh)
433             rc = gpg_error (GPG_ERR_ENOMEM);
434           if (!rc)
435             rc = keydb_search_fpr (kh, stparm.fpr);
436           if (!rc)
437             rc = keydb_get_cert (kh, &rspcert);
438           if (rc)
439             {
440               log_error ("unable to find the certificate used "
441                          "by the dirmngr: %s\n", gpg_strerror (rc));
442               rc = gpg_error (GPG_ERR_INV_CRL);
443             }
444           keydb_release (kh);
445
446           if (!rc)
447             {
448               /* fixme: We should refine the check to check for
449                  certificates allowed for CRL/OCPS. */
450               rc = gpgsm_cert_use_verify_p (rspcert);
451               if (rc)
452                 rc = gpg_error (GPG_ERR_INV_CRL);
453               else
454                 {
455                   /* Note, the flag = 1: This avoids checking this
456                      certificate over and over again. */
457                   rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
458                   if (rc)
459                     {
460                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
461                                  gpg_strerror (rc));
462                       rc = gpg_error (GPG_ERR_INV_CRL);
463                     }
464                 }
465             }
466           ksba_cert_release (rspcert);
467         }
468     }
469   return rc;
470 }
471
472
473 \f
474 /* Lookup helpers*/
475 static AssuanError
476 lookup_cb (void *opaque, const void *buffer, size_t length)
477 {
478   struct lookup_parm_s *parm = opaque;
479   size_t len;
480   char *buf;
481   ksba_cert_t cert;
482   int rc;
483
484   if (parm->error)
485     return 0;
486
487   if (buffer)
488     {
489       put_membuf (&parm->data, buffer, length);
490       return 0;
491     }
492   /* END encountered - process what we have */
493   buf = get_membuf (&parm->data, &len);
494   if (!buf)
495     {
496       parm->error = gpg_error (GPG_ERR_ENOMEM);
497       return 0;
498     }
499
500   rc = ksba_cert_new (&cert);
501   if (rc)
502     {
503       parm->error = rc;
504       return 0;
505     }
506   rc = ksba_cert_init_from_mem (cert, buf, len);
507   if (rc)
508     {
509       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
510     }
511   else
512     {
513       parm->cb (parm->cb_value, cert);
514     }
515
516   ksba_cert_release (cert);
517   init_membuf (&parm->data, 4096);
518   return 0;
519 }
520
521 /* Return a properly escaped pattern from NAMES.  The only error
522    return is NULL to indicate a malloc failure. */
523 static char *
524 pattern_from_strlist (STRLIST names)
525 {
526   STRLIST sl;
527   int n;
528   const char *s;
529   char *pattern, *p;
530
531   for (n=0, sl=names; sl; sl = sl->next)
532     {
533       for (s=sl->d; *s; s++, n++)
534         {
535           if (*s == '%' || *s == ' ' || *s == '+')
536             n += 2;
537         }
538       n++;
539     }
540
541   p = pattern = xtrymalloc (n+1);
542   if (!pattern)
543     return NULL;
544
545   for (n=0, sl=names; sl; sl = sl->next)
546     {
547       for (s=sl->d; *s; s++)
548         {
549           switch (*s)
550             {
551             case '%':
552               *p++ = '%';
553               *p++ = '2';
554               *p++ = '5';
555               break;
556             case ' ':
557               *p++ = '%';
558               *p++ = '2';
559               *p++ = '0';
560               break;
561             case '+':
562               *p++ = '%';
563               *p++ = '2';
564               *p++ = 'B';
565               break;
566             default:
567               *p++ = *s;
568               break;
569             }
570         }
571       *p++ = ' ';
572     }
573   if (p == pattern)
574     *pattern = 0; /* is empty */
575   else
576     p[-1] = '\0'; /* remove trailing blank */
577   
578   return pattern;
579 }
580
581 static AssuanError
582 lookup_status_cb (void *opaque, const char *line)
583 {
584   struct lookup_parm_s *parm = opaque;
585
586   if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
587     {
588       if (parm->ctrl)
589         {
590           for (line +=9; *line == ' '; line++)
591             ;
592           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
593         }
594     }
595   return 0;
596 }
597
598
599 /* Run the Directroy Managers lookup command using the pattern
600    compiled from the strings given in NAMES.  The caller must provide
601    the callback CB which will be passed cert by cert.  Note that CTRL
602    is optional. */
603 int 
604 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
605                       void (*cb)(void*, ksba_cert_t), void *cb_value)
606
607   int rc;
608   char *pattern;
609   char line[ASSUAN_LINELENGTH];
610   struct lookup_parm_s parm;
611   size_t len;
612
613   rc = start_dirmngr ();
614   if (rc)
615     return rc;
616
617   pattern = pattern_from_strlist (names);
618   if (!pattern)
619     return OUT_OF_CORE (errno);
620   snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
621   line[DIM(line)-1] = 0;
622   xfree (pattern);
623
624   parm.ctrl = ctrl;
625   parm.ctx = dirmngr_ctx;
626   parm.cb = cb;
627   parm.cb_value = cb_value;
628   parm.error = 0;
629   init_membuf (&parm.data, 4096);
630
631   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
632                         NULL, NULL, lookup_status_cb, &parm);
633   xfree (get_membuf (&parm.data, &len));
634   if (rc)
635     return map_assuan_err (rc);
636   return parm.error;
637 }
638
639
640 \f
641 /* Run Command helpers*/
642
643 /* Fairly simple callback to write all output of dirmngr to stdout. */
644 static AssuanError
645 run_command_cb (void *opaque, const void *buffer, size_t length)
646 {
647   if (buffer)
648     {
649       if ( fwrite (buffer, length, 1, stdout) != 1 )
650         log_error ("error writing to stdout: %s\n", strerror (errno));
651     }
652   return 0;
653 }
654
655 /* Handle inquiries from the dirmngr COMMAND. */
656 static AssuanError
657 run_command_inq_cb (void *opaque, const char *line)
658 {
659   struct run_command_parm_s *parm = opaque;
660   AssuanError rc = 0;
661
662   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
663     { /* send the given certificate */
664       int err;
665       ksba_cert_t cert;
666       const unsigned char *der;
667       size_t derlen;
668
669       line += 8;
670       if (!*line)
671         return ASSUAN_Inquire_Error;
672
673       err = gpgsm_find_cert (line, &cert);
674       if (err)
675         {
676           log_error ("certificate not found: %s\n", gpg_strerror (err));
677           rc = ASSUAN_Inquire_Error;
678         }
679       else
680         {
681           der = ksba_cert_get_image (cert, &derlen);
682           if (!der)
683             rc = ASSUAN_Inquire_Error;
684           else
685             rc = assuan_send_data (parm->ctx, der, derlen);
686           ksba_cert_release (cert);
687         }
688     }
689   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
690     { /* Simply show the message given in the argument. */
691       line += 9;
692       log_info ("dirmngr: %s\n", line);
693     }
694   else
695     {
696       log_error ("unsupported inquiry `%s'\n", line);
697       rc = ASSUAN_Inquire_Unknown;
698     }
699
700   return rc; 
701 }
702
703 static AssuanError
704 run_command_status_cb (void *opaque, const char *line)
705 {
706   if (opt.verbose)
707     {
708       log_info ("dirmngr status: %s\n", line);
709     }
710   return 0;
711 }
712
713
714
715 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
716    to stdout.  A couple of inquiries are defined (see above).  ARGC
717    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
718    percent characters within the argument strings are percent escaped
719    so that blanks can act as delimiters. */
720 int
721 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
722                            int argc, char **argv)
723
724   int rc;
725   int i;
726   const char *s;
727   char *line, *p;
728   size_t len;
729   struct run_command_parm_s parm;
730
731   rc = start_dirmngr ();
732   if (rc)
733     return rc;
734
735   parm.ctx = dirmngr_ctx;
736
737   len = strlen (command) + 1;
738   for (i=0; i < argc; i++)
739     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
740   line = xtrymalloc (len);
741   if (!line)
742     return OUT_OF_CORE (errno);
743
744   p = stpcpy (line, command);
745   for (i=0; i < argc; i++)
746     {
747       *p++ = ' ';
748       for (s=argv[i]; *s; s++)
749         {
750           if (!isascii (*s))
751             *p++ = *s;
752           else if (*s == ' ')
753             *p++ = '+';
754           else if (!isprint (*s) || *s == '+')
755             {
756               sprintf (p, "%%%02X", *s);
757               p += 3;
758             }
759           else
760             *p++ = *s;
761         }
762     }
763   *p = 0;
764
765   rc = assuan_transact (dirmngr_ctx, line,
766                         run_command_cb, NULL,
767                         run_command_inq_cb, &parm,
768                         run_command_status_cb, NULL);
769   xfree (line);
770   log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
771   return map_assuan_err (rc);
772 }