2005-04-11 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / call-dirmngr.c
blob9c4a5f22f2e4bde3c461d05f0d9a1c39f506f773
1 /* call-dirmngr.c - communication with the dromngr
2 * Copyright (C) 2002, 2003 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
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>
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <assuan.h>
35 #include "i18n.h"
36 #include "keydb.h"
38 /* The name of the socket for a system daemon. */
39 #define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
41 struct membuf {
42 size_t len;
43 size_t size;
44 char *buf;
45 int out_of_core;
50 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
51 static int force_pipe_server = 0;
53 struct inq_certificate_parm_s {
54 ASSUAN_CONTEXT ctx;
55 ksba_cert_t cert;
56 ksba_cert_t issuer_cert;
59 struct isvalid_status_parm_s {
60 CTRL ctrl;
61 int seen;
62 unsigned char fpr[20];
66 struct lookup_parm_s {
67 CTRL ctrl;
68 ASSUAN_CONTEXT ctx;
69 void (*cb)(void *, ksba_cert_t);
70 void *cb_value;
71 struct membuf data;
72 int error;
75 struct run_command_parm_s {
76 ASSUAN_CONTEXT ctx;
80 /* A simple implementation of a dynamic buffer. Use init_membuf() to
81 create a buffer, put_membuf to append bytes and get_membuf to
82 release and return the buffer. Allocation errors are detected but
83 only returned at the final get_membuf(), this helps not to clutter
84 the code with out of core checks. */
86 static void
87 init_membuf (struct membuf *mb, int initiallen)
89 mb->len = 0;
90 mb->size = initiallen;
91 mb->out_of_core = 0;
92 mb->buf = xtrymalloc (initiallen);
93 if (!mb->buf)
94 mb->out_of_core = 1;
97 static void
98 put_membuf (struct membuf *mb, const void *buf, size_t len)
100 if (mb->out_of_core)
101 return;
103 if (mb->len + len >= mb->size)
105 char *p;
107 mb->size += len + 1024;
108 p = xtryrealloc (mb->buf, mb->size);
109 if (!p)
111 mb->out_of_core = 1;
112 return;
114 mb->buf = p;
116 memcpy (mb->buf + mb->len, buf, len);
117 mb->len += len;
120 static void *
121 get_membuf (struct membuf *mb, size_t *len)
123 char *p;
125 if (mb->out_of_core)
127 xfree (mb->buf);
128 mb->buf = NULL;
129 return NULL;
132 p = mb->buf;
133 *len = mb->len;
134 mb->buf = NULL;
135 mb->out_of_core = 1; /* don't allow a reuse */
136 return p;
143 /* Try to connect to the agent via socket or fork it off and work by
144 pipes. Handle the server's initial greeting */
145 static int
146 start_dirmngr (void)
148 int rc;
149 char *infostr, *p;
150 ASSUAN_CONTEXT ctx;
151 int try_default = 0;
153 if (dirmngr_ctx)
154 return 0; /* fixme: We need a context for each thread or serialize
155 the access to the dirmngr */
156 /* Note: if you change this to multiple connections, you also need
157 to take care of the implicit option sending caching. */
159 infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
160 if (opt.prefer_system_dirmngr && !force_pipe_server
161 &&(!infostr || !*infostr))
163 infostr = DEFAULT_SOCKET_NAME;
164 try_default = 1;
166 if (!infostr || !*infostr)
168 const char *pgmname;
169 const char *argv[3];
170 int no_close_list[3];
171 int i;
173 if (opt.verbose)
174 log_info (_("no running dirmngr - starting one\n"));
176 if (fflush (NULL))
178 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
179 log_error ("error flushing pending output: %s\n", strerror (errno));
180 return tmperr;
183 if (!opt.dirmngr_program || !*opt.dirmngr_program)
184 opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
185 if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
186 pgmname = opt.dirmngr_program;
187 else
188 pgmname++;
190 argv[0] = pgmname;
191 argv[1] = "--server";
192 argv[2] = NULL;
194 i=0;
195 if (log_get_fd () != -1)
196 no_close_list[i++] = log_get_fd ();
197 no_close_list[i++] = fileno (stderr);
198 no_close_list[i] = -1;
200 /* connect to the agent and perform initial handshaking */
201 rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
202 no_close_list);
204 else
206 int prot;
207 int pid;
209 infostr = xstrdup (infostr);
210 if (!try_default && *infostr)
212 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
214 log_error (_("malformed DIRMNGR_INFO environment variable\n"));
215 xfree (infostr);
216 force_pipe_server = 1;
217 return start_dirmngr ();
219 *p++ = 0;
220 pid = atoi (p);
221 while (*p && *p != ':')
222 p++;
223 prot = *p? atoi (p+1) : 0;
224 if (prot != 1)
226 log_error (_("dirmngr protocol version %d is not supported\n"),
227 prot);
228 xfree (infostr);
229 force_pipe_server = 1;
230 return start_dirmngr ();
233 else
234 pid = -1;
236 rc = assuan_socket_connect (&ctx, infostr, pid);
237 xfree (infostr);
238 if (rc == ASSUAN_Connect_Failed)
240 log_error (_("can't connect to the dirmngr - trying fall back\n"));
241 force_pipe_server = 1;
242 return start_dirmngr ();
246 if (rc)
248 log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
249 return gpg_error (GPG_ERR_NO_DIRMNGR);
251 dirmngr_ctx = ctx;
253 if (DBG_ASSUAN)
254 log_debug ("connection to dirmngr established\n");
255 return 0;
260 /* Handle a SENDCERT inquiry. */
261 static AssuanError
262 inq_certificate (void *opaque, const char *line)
264 struct inq_certificate_parm_s *parm = opaque;
265 AssuanError rc;
266 const unsigned char *der;
267 size_t derlen;
268 int issuer_mode = 0;
270 if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
272 line += 8;
274 else if (!strncmp (line, "SENDISSUERCERT", 14)
275 && (line[14] == ' ' || !line[14]))
277 line += 14;
278 issuer_mode = 1;
280 else
282 log_error ("unsupported inquiry `%s'\n", line);
283 return ASSUAN_Inquire_Unknown;
286 if (!*line)
287 { /* Send the current certificate. */
288 der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
289 &derlen);
290 if (!der)
291 rc = ASSUAN_Inquire_Error;
292 else
293 rc = assuan_send_data (parm->ctx, der, derlen);
295 else if (issuer_mode)
297 log_error ("sending specific issuer certificate back "
298 "is not yet implemented\n");
299 rc = ASSUAN_Inquire_Error;
301 else
302 { /* Send the given certificate. */
303 int err;
304 ksba_cert_t cert;
307 err = gpgsm_find_cert (line, &cert);
308 if (err)
310 log_error ("certificate not found: %s\n", gpg_strerror (err));
311 rc = ASSUAN_Inquire_Error;
313 else
315 der = ksba_cert_get_image (cert, &derlen);
316 if (!der)
317 rc = ASSUAN_Inquire_Error;
318 else
319 rc = assuan_send_data (parm->ctx, der, derlen);
320 ksba_cert_release (cert);
324 return rc;
328 /* Take a 20 byte hexencoded string and put it into the the provided
329 20 byte buffer FPR in binary format. */
330 static int
331 unhexify_fpr (const char *hexstr, unsigned char *fpr)
333 const char *s;
334 int n;
336 for (s=hexstr, n=0; hexdigitp (s); s++, n++)
338 if (*s || (n != 40))
339 return 0; /* no fingerprint (invalid or wrong length). */
340 n /= 2;
341 for (s=hexstr, n=0; *s; s += 2, n++)
342 fpr[n] = xtoi_2 (s);
343 return 1; /* okay */
347 static assuan_error_t
348 isvalid_status_cb (void *opaque, const char *line)
350 struct isvalid_status_parm_s *parm = opaque;
352 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
354 if (parm->ctrl)
356 for (line += 8; *line == ' '; line++)
358 if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
359 return ASSUAN_Canceled;
362 else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
363 && (line[24]==' ' || !line[24]))
365 parm->seen++;
366 if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
367 parm->seen++; /* Bumb it to indicate an error. */
369 return 0;
375 /* Call the directory manager to check whether the certificate is valid
376 Returns 0 for valid or usually one of the errors:
378 GPG_ERR_CERTIFICATE_REVOKED
379 GPG_ERR_NO_CRL_KNOWN
380 GPG_ERR_CRL_TOO_OLD
382 With USE_OCSP set to true, the dirmngr is asked to do an OCSP
383 request first.
386 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
387 ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
389 static int did_options;
390 int rc;
391 char *certid;
392 char line[ASSUAN_LINELENGTH];
393 struct inq_certificate_parm_s parm;
394 struct isvalid_status_parm_s stparm;
397 rc = start_dirmngr ();
398 if (rc)
399 return rc;
401 if (use_ocsp)
403 certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
405 else
407 certid = gpgsm_get_certid (cert);
408 if (!certid)
410 log_error ("error getting the certificate ID\n");
411 return gpg_error (GPG_ERR_GENERAL);
415 if (opt.verbose > 1)
417 char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
418 log_info ("asking dirmngr about %s%s\n", fpr,
419 use_ocsp? " (using OCSP)":"");
420 xfree (fpr);
423 parm.ctx = dirmngr_ctx;
424 parm.cert = cert;
425 parm.issuer_cert = issuer_cert;
427 stparm.ctrl = ctrl;
428 stparm.seen = 0;
429 memset (stparm.fpr, 0, 20);
431 /* FIXME: If --disable-crl-checks has been set, we should pass an
432 option to dirmngr, so that no fallback CRL check is done after an
433 ocsp check. */
435 /* It is sufficient to send the options only once because we have
436 one connection per process only. */
437 if (!did_options)
439 if (opt.force_crl_refresh)
440 assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
441 NULL, NULL, NULL, NULL, NULL, NULL);
442 did_options = 1;
444 snprintf (line, DIM(line)-1, "ISVALID %s", certid);
445 line[DIM(line)-1] = 0;
446 xfree (certid);
448 rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
449 inq_certificate, &parm,
450 isvalid_status_cb, &stparm);
451 if (opt.verbose > 1)
452 log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
453 rc = map_assuan_err (rc);
455 if (!rc && stparm.seen)
457 /* Need to also check the certificate validity. */
458 if (stparm.seen != 1)
460 log_error ("communication problem with dirmngr detected\n");
461 rc = gpg_error (GPG_ERR_INV_CRL);
463 else
465 KEYDB_HANDLE kh;
466 ksba_cert_t rspcert = NULL;
468 /* Fixme: First try to get the certificate from the
469 dirmngr's cache - it should be there. */
470 kh = keydb_new (0);
471 if (!kh)
472 rc = gpg_error (GPG_ERR_ENOMEM);
473 if (!rc)
474 rc = keydb_search_fpr (kh, stparm.fpr);
475 if (!rc)
476 rc = keydb_get_cert (kh, &rspcert);
477 if (rc)
479 log_error ("unable to find the certificate used "
480 "by the dirmngr: %s\n", gpg_strerror (rc));
481 rc = gpg_error (GPG_ERR_INV_CRL);
483 keydb_release (kh);
485 if (!rc)
487 rc = gpgsm_cert_use_ocsp_p (rspcert);
488 if (rc)
489 rc = gpg_error (GPG_ERR_INV_CRL);
490 else
492 /* Note, the flag = 1: This avoids checking this
493 certificate over and over again. */
494 rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
495 if (rc)
497 log_error ("invalid certificate used for CRL/OCSP: %s\n",
498 gpg_strerror (rc));
499 rc = gpg_error (GPG_ERR_INV_CRL);
503 ksba_cert_release (rspcert);
506 return rc;
511 /* Lookup helpers*/
512 static AssuanError
513 lookup_cb (void *opaque, const void *buffer, size_t length)
515 struct lookup_parm_s *parm = opaque;
516 size_t len;
517 char *buf;
518 ksba_cert_t cert;
519 int rc;
521 if (parm->error)
522 return 0;
524 if (buffer)
526 put_membuf (&parm->data, buffer, length);
527 return 0;
529 /* END encountered - process what we have */
530 buf = get_membuf (&parm->data, &len);
531 if (!buf)
533 parm->error = gpg_error (GPG_ERR_ENOMEM);
534 return 0;
537 rc = ksba_cert_new (&cert);
538 if (rc)
540 parm->error = rc;
541 return 0;
543 rc = ksba_cert_init_from_mem (cert, buf, len);
544 if (rc)
546 log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
548 else
550 parm->cb (parm->cb_value, cert);
553 ksba_cert_release (cert);
554 init_membuf (&parm->data, 4096);
555 return 0;
558 /* Return a properly escaped pattern from NAMES. The only error
559 return is NULL to indicate a malloc failure. */
560 static char *
561 pattern_from_strlist (STRLIST names)
563 STRLIST sl;
564 int n;
565 const char *s;
566 char *pattern, *p;
568 for (n=0, sl=names; sl; sl = sl->next)
570 for (s=sl->d; *s; s++, n++)
572 if (*s == '%' || *s == ' ' || *s == '+')
573 n += 2;
575 n++;
578 p = pattern = xtrymalloc (n+1);
579 if (!pattern)
580 return NULL;
582 for (n=0, sl=names; sl; sl = sl->next)
584 for (s=sl->d; *s; s++)
586 switch (*s)
588 case '%':
589 *p++ = '%';
590 *p++ = '2';
591 *p++ = '5';
592 break;
593 case ' ':
594 *p++ = '%';
595 *p++ = '2';
596 *p++ = '0';
597 break;
598 case '+':
599 *p++ = '%';
600 *p++ = '2';
601 *p++ = 'B';
602 break;
603 default:
604 *p++ = *s;
605 break;
608 *p++ = ' ';
610 if (p == pattern)
611 *pattern = 0; /* is empty */
612 else
613 p[-1] = '\0'; /* remove trailing blank */
615 return pattern;
618 static AssuanError
619 lookup_status_cb (void *opaque, const char *line)
621 struct lookup_parm_s *parm = opaque;
623 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
625 if (parm->ctrl)
627 for (line += 8; *line == ' '; line++)
629 if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
630 return ASSUAN_Canceled;
633 else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
635 if (parm->ctrl)
637 for (line +=9; *line == ' '; line++)
639 gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
642 return 0;
646 /* Run the Directroy Managers lookup command using the pattern
647 compiled from the strings given in NAMES. The caller must provide
648 the callback CB which will be passed cert by cert. Note that CTRL
649 is optional. */
650 int
651 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
652 void (*cb)(void*, ksba_cert_t), void *cb_value)
654 int rc;
655 char *pattern;
656 char line[ASSUAN_LINELENGTH];
657 struct lookup_parm_s parm;
658 size_t len;
660 rc = start_dirmngr ();
661 if (rc)
662 return rc;
664 pattern = pattern_from_strlist (names);
665 if (!pattern)
666 return OUT_OF_CORE (errno);
667 snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
668 line[DIM(line)-1] = 0;
669 xfree (pattern);
671 parm.ctrl = ctrl;
672 parm.ctx = dirmngr_ctx;
673 parm.cb = cb;
674 parm.cb_value = cb_value;
675 parm.error = 0;
676 init_membuf (&parm.data, 4096);
678 rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
679 NULL, NULL, lookup_status_cb, &parm);
680 xfree (get_membuf (&parm.data, &len));
681 if (rc)
682 return map_assuan_err (rc);
683 return parm.error;
688 /* Run Command helpers*/
690 /* Fairly simple callback to write all output of dirmngr to stdout. */
691 static AssuanError
692 run_command_cb (void *opaque, const void *buffer, size_t length)
694 if (buffer)
696 if ( fwrite (buffer, length, 1, stdout) != 1 )
697 log_error ("error writing to stdout: %s\n", strerror (errno));
699 return 0;
702 /* Handle inquiries from the dirmngr COMMAND. */
703 static AssuanError
704 run_command_inq_cb (void *opaque, const char *line)
706 struct run_command_parm_s *parm = opaque;
707 AssuanError rc = 0;
709 if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
710 { /* send the given certificate */
711 int err;
712 ksba_cert_t cert;
713 const unsigned char *der;
714 size_t derlen;
716 line += 8;
717 if (!*line)
718 return ASSUAN_Inquire_Error;
720 err = gpgsm_find_cert (line, &cert);
721 if (err)
723 log_error ("certificate not found: %s\n", gpg_strerror (err));
724 rc = ASSUAN_Inquire_Error;
726 else
728 der = ksba_cert_get_image (cert, &derlen);
729 if (!der)
730 rc = ASSUAN_Inquire_Error;
731 else
732 rc = assuan_send_data (parm->ctx, der, derlen);
733 ksba_cert_release (cert);
736 else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
737 { /* Simply show the message given in the argument. */
738 line += 9;
739 log_info ("dirmngr: %s\n", line);
741 else
743 log_error ("unsupported inquiry `%s'\n", line);
744 rc = ASSUAN_Inquire_Unknown;
747 return rc;
750 static AssuanError
751 run_command_status_cb (void *opaque, const char *line)
753 ctrl_t ctrl = opaque;
755 if (opt.verbose)
757 log_info ("dirmngr status: %s\n", line);
759 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
761 if (ctrl)
763 for (line += 8; *line == ' '; line++)
765 if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
766 return ASSUAN_Canceled;
769 return 0;
774 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
775 to stdout. A couple of inquiries are defined (see above). ARGC
776 arguments in ARGV are given to the Dirmngr. Spaces, plus and
777 percent characters within the argument strings are percent escaped
778 so that blanks can act as delimiters. */
780 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
781 int argc, char **argv)
783 int rc;
784 int i;
785 const char *s;
786 char *line, *p;
787 size_t len;
788 struct run_command_parm_s parm;
790 rc = start_dirmngr ();
791 if (rc)
792 return rc;
794 parm.ctx = dirmngr_ctx;
796 len = strlen (command) + 1;
797 for (i=0; i < argc; i++)
798 len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
799 line = xtrymalloc (len);
800 if (!line)
801 return OUT_OF_CORE (errno);
803 p = stpcpy (line, command);
804 for (i=0; i < argc; i++)
806 *p++ = ' ';
807 for (s=argv[i]; *s; s++)
809 if (!isascii (*s))
810 *p++ = *s;
811 else if (*s == ' ')
812 *p++ = '+';
813 else if (!isprint (*s) || *s == '+')
815 sprintf (p, "%%%02X", *s);
816 p += 3;
818 else
819 *p++ = *s;
822 *p = 0;
824 rc = assuan_transact (dirmngr_ctx, line,
825 run_command_cb, NULL,
826 run_command_inq_cb, &parm,
827 run_command_status_cb, ctrl);
828 xfree (line);
829 log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
830 return map_assuan_err (rc);