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
46 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
47 static int force_pipe_server = 0;
49 struct inq_certificate_parm_s {
54 struct lookup_parm_s {
57 void (*cb)(void *, KsbaCert);
63 struct run_command_parm_s {
68 /* A simple implementation of a dynamic buffer. Use init_membuf() to
69 create a buffer, put_membuf to append bytes and get_membuf to
70 release and return the buffer. Allocation errors are detected but
71 only returned at the final get_membuf(), this helps not to clutter
72 the code with out of core checks. */
75 init_membuf (struct membuf *mb, int initiallen)
78 mb->size = initiallen;
80 mb->buf = xtrymalloc (initiallen);
86 put_membuf (struct membuf *mb, const void *buf, size_t len)
91 if (mb->len + len >= mb->size)
95 mb->size += len + 1024;
96 p = xtryrealloc (mb->buf, mb->size);
104 memcpy (mb->buf + mb->len, buf, len);
109 get_membuf (struct membuf *mb, size_t *len)
123 mb->out_of_core = 1; /* don't allow a reuse */
131 /* Try to connect to the agent via socket or fork it off and work by
132 pipes. Handle the server's initial greeting */
141 return 0; /* fixme: We need a context for each thread or serialize
142 the access to the dirmngr */
144 infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
149 int no_close_list[3];
153 log_info (_("no running dirmngr - starting one\n"));
157 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
158 log_error ("error flushing pending output: %s\n", strerror (errno));
162 if (!opt.dirmngr_program || !*opt.dirmngr_program)
163 opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
164 if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
165 pgmname = opt.dirmngr_program;
170 argv[1] = "--server";
174 if (log_get_fd () != -1)
175 no_close_list[i++] = log_get_fd ();
176 no_close_list[i++] = fileno (stderr);
177 no_close_list[i] = -1;
179 /* connect to the agent and perform initial handshaking */
180 rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
188 infostr = xstrdup (infostr);
189 if ( !(p = strchr (infostr, ':')) || p == infostr)
191 log_error (_("malformed DIRMNGR_INFO environment variable\n"));
193 force_pipe_server = 1;
194 return start_dirmngr ();
198 while (*p && *p != ':')
200 prot = *p? atoi (p+1) : 0;
203 log_error (_("dirmngr protocol version %d is not supported\n"),
206 force_pipe_server = 1;
207 return start_dirmngr ();
210 rc = assuan_socket_connect (&ctx, infostr, pid);
212 if (rc == ASSUAN_Connect_Failed)
214 log_error (_("can't connect to the dirmngr - trying fall back\n"));
215 force_pipe_server = 1;
216 return start_dirmngr ();
222 log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
223 return gpg_error (GPG_ERR_NO_DIRMNGR);
228 log_debug ("connection to dirmngr established\n");
234 /* Handle a SENDCERT inquiry. */
236 inq_certificate (void *opaque, const char *line)
238 struct inq_certificate_parm_s *parm = opaque;
240 const unsigned char *der;
243 if (!(!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8])))
245 log_error ("unsupported inquiry `%s'\n", line);
246 return ASSUAN_Inquire_Unknown;
251 { /* send the current certificate */
252 der = ksba_cert_get_image (parm->cert, &derlen);
254 rc = ASSUAN_Inquire_Error;
256 rc = assuan_send_data (parm->ctx, der, derlen);
259 { /* send the given certificate */
263 err = gpgsm_find_cert (line, &cert);
266 log_error ("certificate not found: %s\n", gpg_strerror (err));
267 rc = ASSUAN_Inquire_Error;
271 der = ksba_cert_get_image (cert, &derlen);
273 rc = ASSUAN_Inquire_Error;
275 rc = assuan_send_data (parm->ctx, der, derlen);
276 ksba_cert_release (cert);
285 /* Call the directory manager to check whether the certificate is valid
286 Returns 0 for valid or usually one of the errors:
288 GPG_ERR_CERTIFICATE_REVOKED
292 With USE_OCSP set to true, the dirmngr is asked to do an OCSP
296 gpgsm_dirmngr_isvalid (ksba_cert_t cert, int use_ocsp)
300 char line[ASSUAN_LINELENGTH];
301 struct inq_certificate_parm_s parm;
303 rc = start_dirmngr ();
309 certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
313 certid = gpgsm_get_certid (cert);
316 log_error ("error getting the certificate ID\n");
317 return gpg_error (GPG_ERR_GENERAL);
323 char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
324 log_info ("asking dirmngr about %s%s\n", fpr,
325 use_ocsp? " (using OCSP)":"");
329 parm.ctx = dirmngr_ctx;
332 /* FIXME: If --disable-crl-checks has been set, we should pass an
333 option to dirmngr, so that no fallback CRL check is done after an
336 snprintf (line, DIM(line)-1, "ISVALID %s", certid);
337 line[DIM(line)-1] = 0;
340 rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
341 inq_certificate, &parm, NULL, NULL);
343 log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
344 return map_assuan_err (rc);
351 lookup_cb (void *opaque, const void *buffer, size_t length)
353 struct lookup_parm_s *parm = opaque;
364 put_membuf (&parm->data, buffer, length);
367 /* END encountered - process what we have */
368 buf = get_membuf (&parm->data, &len);
371 parm->error = gpg_error (GPG_ERR_ENOMEM);
375 rc = ksba_cert_new (&cert);
381 rc = ksba_cert_init_from_mem (cert, buf, len);
384 log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
388 parm->cb (parm->cb_value, cert);
391 ksba_cert_release (cert);
392 init_membuf (&parm->data, 4096);
396 /* Return a properly escaped pattern from NAMES. The only error
397 return is NULL to indicate a malloc failure. */
399 pattern_from_strlist (STRLIST names)
406 for (n=0, sl=names; sl; sl = sl->next)
408 for (s=sl->d; *s; s++, n++)
410 if (*s == '%' || *s == ' ' || *s == '+')
416 p = pattern = xtrymalloc (n+1);
420 for (n=0, sl=names; sl; sl = sl->next)
422 for (s=sl->d; *s; s++)
449 *pattern = 0; /* is empty */
451 p[-1] = '\0'; /* remove trailing blank */
457 lookup_status_cb (void *opaque, const char *line)
459 struct lookup_parm_s *parm = opaque;
461 if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
465 for (line +=9; *line == ' '; line++)
467 gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
474 /* Run the Directroy Managers lookup command using the pattern
475 compiled from the strings given in NAMES. The caller must provide
476 the callback CB which will be passed cert by cert. Note that CTRL
479 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
480 void (*cb)(void*, KsbaCert), void *cb_value)
484 char line[ASSUAN_LINELENGTH];
485 struct lookup_parm_s parm;
488 rc = start_dirmngr ();
492 pattern = pattern_from_strlist (names);
494 return OUT_OF_CORE (errno);
495 snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
496 line[DIM(line)-1] = 0;
500 parm.ctx = dirmngr_ctx;
502 parm.cb_value = cb_value;
504 init_membuf (&parm.data, 4096);
506 rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
507 NULL, NULL, lookup_status_cb, &parm);
508 xfree (get_membuf (&parm.data, &len));
510 return map_assuan_err (rc);
516 /* Run Command helpers*/
518 /* Fairly simple callback to write all output of dirmngr to stdout. */
520 run_command_cb (void *opaque, const void *buffer, size_t length)
524 if ( fwrite (buffer, length, 1, stdout) != 1 )
525 log_error ("error writing to stdout: %s\n", strerror (errno));
530 /* Handle inquiries from the dirmngr COMMAND. */
532 run_command_inq_cb (void *opaque, const char *line)
534 struct run_command_parm_s *parm = opaque;
537 if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
538 { /* send the given certificate */
541 const unsigned char *der;
546 return ASSUAN_Inquire_Error;
548 err = gpgsm_find_cert (line, &cert);
551 log_error ("certificate not found: %s\n", gpg_strerror (err));
552 rc = ASSUAN_Inquire_Error;
556 der = ksba_cert_get_image (cert, &derlen);
558 rc = ASSUAN_Inquire_Error;
560 rc = assuan_send_data (parm->ctx, der, derlen);
561 ksba_cert_release (cert);
564 else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
565 { /* Simply show the message given in the argument. */
567 log_info ("dirmngr: %s\n", line);
571 log_error ("unsupported inquiry `%s'\n", line);
572 rc = ASSUAN_Inquire_Unknown;
579 run_command_status_cb (void *opaque, const char *line)
583 log_info ("dirmngr status: %s\n", line);
590 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
591 to stdout. A couple of inquiries are defined (see above). ARGC
592 arguments in ARGV are given to the Dirmngr. Spaces, plus and
593 percent characters within the argument strings are percent escaped
594 so that blanks can act as delimiters. */
596 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
597 int argc, char **argv)
604 struct run_command_parm_s parm;
606 rc = start_dirmngr ();
610 parm.ctx = dirmngr_ctx;
612 len = strlen (command) + 1;
613 for (i=0; i < argc; i++)
614 len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
615 line = xtrymalloc (len);
617 return OUT_OF_CORE (errno);
619 p = stpcpy (line, command);
620 for (i=0; i < argc; i++)
623 for (s=argv[i]; *s; s++)
629 else if (!isprint (*s) || *s == '+')
631 sprintf (p, "%%%02X", *s);
640 rc = assuan_transact (dirmngr_ctx, line,
641 run_command_cb, NULL,
642 run_command_inq_cb, &parm,
643 run_command_status_cb, NULL);
645 log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
646 return map_assuan_err (rc);