* srv.c (getsrv): Raise maximum packet size to 2048, as PACKETSZ is
[gnupg.git] / sm / call-dirmngr.c
blob914fdd03eef4009f1a1b8e4b8bff22220370a60d
1 /* call-dirmngr.c - communication with the dromngr
2 * Copyright (C) 2002, 2003, 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <time.h>
27 #include <assert.h>
28 #include <ctype.h>
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <assuan.h>
34 #include "i18n.h"
35 #include "keydb.h"
38 struct membuf {
39 size_t len;
40 size_t size;
41 char *buf;
42 int out_of_core;
47 /* fixme: We need a context for each thread or serialize the access to
48 the dirmngr. */
49 static assuan_context_t dirmngr_ctx = NULL;
50 static assuan_context_t dirmngr2_ctx = NULL;
52 static int dirmngr_ctx_locked;
53 static int dirmngr2_ctx_locked;
55 static int force_pipe_server = 0;
57 struct inq_certificate_parm_s {
58 ctrl_t ctrl;
59 assuan_context_t ctx;
60 ksba_cert_t cert;
61 ksba_cert_t issuer_cert;
64 struct isvalid_status_parm_s {
65 ctrl_t ctrl;
66 int seen;
67 unsigned char fpr[20];
71 struct lookup_parm_s {
72 ctrl_t ctrl;
73 assuan_context_t ctx;
74 void (*cb)(void *, ksba_cert_t);
75 void *cb_value;
76 struct membuf data;
77 int error;
80 struct run_command_parm_s {
81 assuan_context_t ctx;
85 /* A simple implementation of a dynamic buffer. Use init_membuf() to
86 create a buffer, put_membuf to append bytes and get_membuf to
87 release and return the buffer. Allocation errors are detected but
88 only returned at the final get_membuf(), this helps not to clutter
89 the code with out of core checks. */
91 static void
92 init_membuf (struct membuf *mb, int initiallen)
94 mb->len = 0;
95 mb->size = initiallen;
96 mb->out_of_core = 0;
97 mb->buf = xtrymalloc (initiallen);
98 if (!mb->buf)
99 mb->out_of_core = 1;
102 static void
103 put_membuf (struct membuf *mb, const void *buf, size_t len)
105 if (mb->out_of_core)
106 return;
108 if (mb->len + len >= mb->size)
110 char *p;
112 mb->size += len + 1024;
113 p = xtryrealloc (mb->buf, mb->size);
114 if (!p)
116 mb->out_of_core = 1;
117 return;
119 mb->buf = p;
121 memcpy (mb->buf + mb->len, buf, len);
122 mb->len += len;
125 static void *
126 get_membuf (struct membuf *mb, size_t *len)
128 char *p;
130 if (mb->out_of_core)
132 xfree (mb->buf);
133 mb->buf = NULL;
134 return NULL;
137 p = mb->buf;
138 *len = mb->len;
139 mb->buf = NULL;
140 mb->out_of_core = 1; /* don't allow a reuse */
141 return p;
145 /* This function prepares the dirmngr for a new session. The
146 audit-events option is used so that other dirmngr clients won't get
147 disturbed by such events. */
148 static void
149 prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
151 struct keyserver_spec *server;
153 if (!err)
155 err = assuan_transact (ctx, "OPTION audit-events=1",
156 NULL, NULL, NULL, NULL, NULL, NULL);
157 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
158 err = 0; /* Allow the use of old dirmngr versions. */
160 audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
162 server = opt.keyserver;
163 while (server)
165 char line[ASSUAN_LINELENGTH];
166 char *user = server->user ? server->user : "";
167 char *pass = server->pass ? server->pass : "";
168 char *base = server->base ? server->base : "";
170 snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
171 server->host, server->port, user, pass, base);
172 line[DIM (line) - 1] = 0;
174 err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
175 if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
176 err = 0; /* Allow the use of old dirmngr versions. */
178 server = server->next;
184 /* Try to connect to the agent via socket or fork it off and work by
185 pipes. Handle the server's initial greeting */
186 static int
187 start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
189 int rc;
190 char *infostr, *p;
191 assuan_context_t ctx;
192 int try_default = 0;
194 if (opt.disable_dirmngr)
195 return gpg_error (GPG_ERR_NO_DIRMNGR);
197 if (*ctx_r)
198 return 0;
200 /* Note: if you change this to multiple connections, you also need
201 to take care of the implicit option sending caching. */
203 #ifdef HAVE_W32_SYSTEM
204 infostr = NULL;
205 opt.prefer_system_dirmngr = 1;
206 #else
207 infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
208 #endif /*HAVE_W32_SYSTEM*/
209 if (infostr && !*infostr)
210 infostr = NULL;
211 else if (infostr)
212 infostr = xstrdup (infostr);
214 if (opt.prefer_system_dirmngr && !force_pipe_server && !infostr)
216 infostr = xstrdup (dirmngr_socket_name ());
217 try_default = 1;
219 if (!infostr)
221 const char *pgmname;
222 const char *argv[3];
223 int no_close_list[3];
224 int i;
226 if (!opt.dirmngr_program || !*opt.dirmngr_program)
227 opt.dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
228 if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
229 pgmname = opt.dirmngr_program;
230 else
231 pgmname++;
233 if (opt.verbose)
234 log_info (_("no running dirmngr - starting `%s'\n"),
235 opt.dirmngr_program);
237 if (fflush (NULL))
239 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
240 log_error ("error flushing pending output: %s\n", strerror (errno));
241 return tmperr;
244 argv[0] = pgmname;
245 argv[1] = "--server";
246 argv[2] = NULL;
248 i=0;
249 if (log_get_fd () != -1)
250 no_close_list[i++] = log_get_fd ();
251 no_close_list[i++] = fileno (stderr);
252 no_close_list[i] = -1;
254 /* connect to the agent and perform initial handshaking */
255 rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, argv,
256 no_close_list);
258 else
260 int prot;
261 int pid;
263 if (!try_default)
265 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
267 log_error (_("malformed DIRMNGR_INFO environment variable\n"));
268 xfree (infostr);
269 force_pipe_server = 1;
270 return start_dirmngr_ext (ctrl, ctx_r);
272 *p++ = 0;
273 pid = atoi (p);
274 while (*p && *p != PATHSEP_C)
275 p++;
276 prot = *p? atoi (p+1) : 0;
277 if (prot != 1)
279 log_error (_("dirmngr protocol version %d is not supported\n"),
280 prot);
281 xfree (infostr);
282 force_pipe_server = 1;
283 return start_dirmngr_ext (ctrl, ctx_r);
286 else
287 pid = -1;
289 rc = assuan_socket_connect (&ctx, infostr, pid);
290 #ifdef HAVE_W32_SYSTEM
291 if (rc)
292 log_debug ("connecting dirmngr at `%s' failed\n", infostr);
293 #endif
295 xfree (infostr);
296 #ifndef HAVE_W32_SYSTEM
297 if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
299 log_info (_("can't connect to the dirmngr - trying fall back\n"));
300 force_pipe_server = 1;
301 return start_dirmngr_ext (ctrl, ctx_r);
303 #endif /*!HAVE_W32_SYSTEM*/
306 prepare_dirmngr (ctrl, ctx, rc);
308 if (rc)
310 log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc));
311 return gpg_error (GPG_ERR_NO_DIRMNGR);
313 *ctx_r = ctx;
315 if (DBG_ASSUAN)
316 log_debug ("connection to dirmngr established\n");
317 return 0;
321 static int
322 start_dirmngr (ctrl_t ctrl)
324 gpg_error_t err;
326 assert (! dirmngr_ctx_locked);
327 dirmngr_ctx_locked = 1;
329 err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
330 /* We do not check ERR but the existance of a context because the
331 error might come from a failed command send to the dirmngr.
332 Fixme: Why don't we close the drimngr context if we encountered
333 an error in prepare_dirmngr? */
334 if (!dirmngr_ctx)
335 dirmngr_ctx_locked = 0;
336 return err;
340 static void
341 release_dirmngr (ctrl_t ctrl)
343 (void)ctrl;
345 if (!dirmngr_ctx_locked)
346 log_error ("WARNING: trying to release a non-locked dirmngr ctx\n");
347 dirmngr_ctx_locked = 0;
351 static int
352 start_dirmngr2 (ctrl_t ctrl)
354 gpg_error_t err;
356 assert (! dirmngr2_ctx_locked);
357 dirmngr2_ctx_locked = 1;
359 err = start_dirmngr_ext (ctrl, &dirmngr2_ctx);
360 if (!dirmngr2_ctx)
361 dirmngr2_ctx_locked = 0;
362 return err;
366 static void
367 release_dirmngr2 (ctrl_t ctrl)
369 (void)ctrl;
371 if (!dirmngr2_ctx_locked)
372 log_error ("WARNING: trying to release a non-locked dirmngr2 ctx\n");
373 dirmngr2_ctx_locked = 0;
378 /* Handle a SENDCERT inquiry. */
379 static int
380 inq_certificate (void *opaque, const char *line)
382 struct inq_certificate_parm_s *parm = opaque;
383 int rc;
384 const unsigned char *der;
385 size_t derlen;
386 int issuer_mode = 0;
387 ksba_sexp_t ski = NULL;
389 if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
391 line += 8;
393 else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
395 size_t n;
397 /* Send a certificate where a sourceKeyIdentifier is included. */
398 line += 12;
399 while (*line == ' ')
400 line++;
401 ski = make_simple_sexp_from_hexstr (line, &n);
402 line += n;
403 while (*line == ' ')
404 line++;
406 else if (!strncmp (line, "SENDISSUERCERT", 14)
407 && (line[14] == ' ' || !line[14]))
409 line += 14;
410 issuer_mode = 1;
412 else if (!strncmp (line, "ISTRUSTED", 9) && (line[9]==' ' || !line[9]))
414 /* The server is asking us whether the certificate is a trusted
415 root certificate. */
416 const char *s;
417 size_t n;
418 char fpr[41];
419 struct rootca_flags_s rootca_flags;
421 line += 9;
422 while (*line == ' ')
423 line++;
425 for (s=line,n=0; hexdigitp (s); s++, n++)
427 if (*s || n != 40)
428 return gpg_error (GPG_ERR_ASS_PARAMETER);
429 for (s=line, n=0; n < 40; s++, n++)
430 fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
431 fpr[n] = 0;
433 if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
434 rc = assuan_send_data (parm->ctx, "1", 1);
435 else
436 rc = 0;
437 return rc;
439 else
441 log_error ("unsupported inquiry `%s'\n", line);
442 return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
445 if (!*line)
446 { /* Send the current certificate. */
447 der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
448 &derlen);
449 if (!der)
450 rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
451 else
452 rc = assuan_send_data (parm->ctx, der, derlen);
454 else if (issuer_mode)
456 log_error ("sending specific issuer certificate back "
457 "is not yet implemented\n");
458 rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
460 else
461 { /* Send the given certificate. */
462 int err;
463 ksba_cert_t cert;
466 err = gpgsm_find_cert (line, ski, &cert);
467 if (err)
469 log_error ("certificate not found: %s\n", gpg_strerror (err));
470 rc = gpg_error (GPG_ERR_NOT_FOUND);
472 else
474 der = ksba_cert_get_image (cert, &derlen);
475 if (!der)
476 rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
477 else
478 rc = assuan_send_data (parm->ctx, der, derlen);
479 ksba_cert_release (cert);
483 xfree (ski);
484 return rc;
488 /* Take a 20 byte hexencoded string and put it into the the provided
489 20 byte buffer FPR in binary format. */
490 static int
491 unhexify_fpr (const char *hexstr, unsigned char *fpr)
493 const char *s;
494 int n;
496 for (s=hexstr, n=0; hexdigitp (s); s++, n++)
498 if (*s || (n != 40))
499 return 0; /* no fingerprint (invalid or wrong length). */
500 n /= 2;
501 for (s=hexstr, n=0; *s; s += 2, n++)
502 fpr[n] = xtoi_2 (s);
503 return 1; /* okay */
507 static assuan_error_t
508 isvalid_status_cb (void *opaque, const char *line)
510 struct isvalid_status_parm_s *parm = opaque;
512 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
514 if (parm->ctrl)
516 for (line += 8; *line == ' '; line++)
518 if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
519 return gpg_error (GPG_ERR_ASS_CANCELED);
522 else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
523 && (line[24]==' ' || !line[24]))
525 parm->seen++;
526 if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
527 parm->seen++; /* Bumb it to indicate an error. */
529 return 0;
535 /* Call the directory manager to check whether the certificate is valid
536 Returns 0 for valid or usually one of the errors:
538 GPG_ERR_CERTIFICATE_REVOKED
539 GPG_ERR_NO_CRL_KNOWN
540 GPG_ERR_CRL_TOO_OLD
542 Values for USE_OCSP:
543 0 = Do CRL check.
544 1 = Do an OCSP check.
545 2 = Do an OCSP check using only the default responder.
548 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
549 ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
551 static int did_options;
552 int rc;
553 char *certid;
554 char line[ASSUAN_LINELENGTH];
555 struct inq_certificate_parm_s parm;
556 struct isvalid_status_parm_s stparm;
558 rc = start_dirmngr (ctrl);
559 if (rc)
560 return rc;
562 if (use_ocsp)
564 certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
566 else
568 certid = gpgsm_get_certid (cert);
569 if (!certid)
571 log_error ("error getting the certificate ID\n");
572 release_dirmngr (ctrl);
573 return gpg_error (GPG_ERR_GENERAL);
577 if (opt.verbose > 1)
579 char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
580 log_info ("asking dirmngr about %s%s\n", fpr,
581 use_ocsp? " (using OCSP)":"");
582 xfree (fpr);
585 parm.ctx = dirmngr_ctx;
586 parm.ctrl = ctrl;
587 parm.cert = cert;
588 parm.issuer_cert = issuer_cert;
590 stparm.ctrl = ctrl;
591 stparm.seen = 0;
592 memset (stparm.fpr, 0, 20);
594 /* FIXME: If --disable-crl-checks has been set, we should pass an
595 option to dirmngr, so that no fallback CRL check is done after an
596 ocsp check. It is not a problem right now as dirmngr does not
597 fallback to CRL checking. */
599 /* It is sufficient to send the options only once because we have
600 one connection per process only. */
601 if (!did_options)
603 if (opt.force_crl_refresh)
604 assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
605 NULL, NULL, NULL, NULL, NULL, NULL);
606 did_options = 1;
608 snprintf (line, DIM(line)-1, "ISVALID%s %s",
609 use_ocsp == 2? " --only-ocsp --force-default-responder":"",
610 certid);
611 line[DIM(line)-1] = 0;
612 xfree (certid);
614 rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
615 inq_certificate, &parm,
616 isvalid_status_cb, &stparm);
617 if (opt.verbose > 1)
618 log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
619 rc = rc;
621 if (!rc && stparm.seen)
623 /* Need to also check the certificate validity. */
624 if (stparm.seen != 1)
626 log_error ("communication problem with dirmngr detected\n");
627 rc = gpg_error (GPG_ERR_INV_CRL);
629 else
631 KEYDB_HANDLE kh;
632 ksba_cert_t rspcert = NULL;
634 /* Fixme: First try to get the certificate from the
635 dirmngr's cache - it should be there. */
636 kh = keydb_new (0);
637 if (!kh)
638 rc = gpg_error (GPG_ERR_ENOMEM);
639 if (!rc)
640 rc = keydb_search_fpr (kh, stparm.fpr);
641 if (!rc)
642 rc = keydb_get_cert (kh, &rspcert);
643 if (rc)
645 log_error ("unable to find the certificate used "
646 "by the dirmngr: %s\n", gpg_strerror (rc));
647 rc = gpg_error (GPG_ERR_INV_CRL);
649 keydb_release (kh);
651 if (!rc)
653 rc = gpgsm_cert_use_ocsp_p (rspcert);
654 if (rc)
655 rc = gpg_error (GPG_ERR_INV_CRL);
656 else
658 /* Note the no_dirmngr flag: This avoids checking
659 this certificate over and over again. */
660 rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
661 VALIDATE_FLAG_NO_DIRMNGR, NULL);
662 if (rc)
664 log_error ("invalid certificate used for CRL/OCSP: %s\n",
665 gpg_strerror (rc));
666 rc = gpg_error (GPG_ERR_INV_CRL);
670 ksba_cert_release (rspcert);
673 release_dirmngr (ctrl);
674 return rc;
679 /* Lookup helpers*/
680 static int
681 lookup_cb (void *opaque, const void *buffer, size_t length)
683 struct lookup_parm_s *parm = opaque;
684 size_t len;
685 char *buf;
686 ksba_cert_t cert;
687 int rc;
689 if (parm->error)
690 return 0;
692 if (buffer)
694 put_membuf (&parm->data, buffer, length);
695 return 0;
697 /* END encountered - process what we have */
698 buf = get_membuf (&parm->data, &len);
699 if (!buf)
701 parm->error = gpg_error (GPG_ERR_ENOMEM);
702 return 0;
705 rc = ksba_cert_new (&cert);
706 if (rc)
708 parm->error = rc;
709 return 0;
711 rc = ksba_cert_init_from_mem (cert, buf, len);
712 if (rc)
714 log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
716 else
718 parm->cb (parm->cb_value, cert);
721 ksba_cert_release (cert);
722 init_membuf (&parm->data, 4096);
723 return 0;
726 /* Return a properly escaped pattern from NAMES. The only error
727 return is NULL to indicate a malloc failure. */
728 static char *
729 pattern_from_strlist (strlist_t names)
731 strlist_t sl;
732 int n;
733 const char *s;
734 char *pattern, *p;
736 for (n=0, sl=names; sl; sl = sl->next)
738 for (s=sl->d; *s; s++, n++)
740 if (*s == '%' || *s == ' ' || *s == '+')
741 n += 2;
743 n++;
746 p = pattern = xtrymalloc (n+1);
747 if (!pattern)
748 return NULL;
750 for (n=0, sl=names; sl; sl = sl->next)
752 for (s=sl->d; *s; s++)
754 switch (*s)
756 case '%':
757 *p++ = '%';
758 *p++ = '2';
759 *p++ = '5';
760 break;
761 case ' ':
762 *p++ = '%';
763 *p++ = '2';
764 *p++ = '0';
765 break;
766 case '+':
767 *p++ = '%';
768 *p++ = '2';
769 *p++ = 'B';
770 break;
771 default:
772 *p++ = *s;
773 break;
776 *p++ = ' ';
778 if (p == pattern)
779 *pattern = 0; /* is empty */
780 else
781 p[-1] = '\0'; /* remove trailing blank */
783 return pattern;
786 static int
787 lookup_status_cb (void *opaque, const char *line)
789 struct lookup_parm_s *parm = opaque;
791 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
793 if (parm->ctrl)
795 for (line += 8; *line == ' '; line++)
797 if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
798 return gpg_error (GPG_ERR_ASS_CANCELED);
801 else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
803 if (parm->ctrl)
805 for (line +=9; *line == ' '; line++)
807 gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
810 return 0;
814 /* Run the Directory Manager's lookup command using the pattern
815 compiled from the strings given in NAMES. The caller must provide
816 the callback CB which will be passed cert by cert. Note that CTRL
817 is optional. With CACHE_ONLY the dirmngr will search only its own
818 key cache. */
819 int
820 gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
821 void (*cb)(void*, ksba_cert_t), void *cb_value)
823 int rc;
824 char *pattern;
825 char line[ASSUAN_LINELENGTH];
826 struct lookup_parm_s parm;
827 size_t len;
828 assuan_context_t ctx;
830 /* The lookup function can be invoked from the callback of a lookup
831 function, for example to walk the chain. */
832 if (!dirmngr_ctx_locked)
834 rc = start_dirmngr (ctrl);
835 if (rc)
836 return rc;
837 ctx = dirmngr_ctx;
839 else if (!dirmngr2_ctx_locked)
841 rc = start_dirmngr2 (ctrl);
842 if (rc)
843 return rc;
844 ctx = dirmngr2_ctx;
846 else
848 log_fatal ("both dirmngr contexts are in use\n");
851 pattern = pattern_from_strlist (names);
852 if (!pattern)
854 if (ctx == dirmngr_ctx)
855 release_dirmngr (ctrl);
856 else
857 release_dirmngr2 (ctrl);
859 return out_of_core ();
861 snprintf (line, DIM(line)-1, "LOOKUP%s %s",
862 cache_only? " --cache-only":"", pattern);
863 line[DIM(line)-1] = 0;
864 xfree (pattern);
866 parm.ctrl = ctrl;
867 parm.ctx = ctx;
868 parm.cb = cb;
869 parm.cb_value = cb_value;
870 parm.error = 0;
871 init_membuf (&parm.data, 4096);
873 rc = assuan_transact (ctx, line, lookup_cb, &parm,
874 NULL, NULL, lookup_status_cb, &parm);
875 xfree (get_membuf (&parm.data, &len));
877 if (ctx == dirmngr_ctx)
878 release_dirmngr (ctrl);
879 else
880 release_dirmngr2 (ctrl);
882 if (rc)
883 return rc;
884 return parm.error;
889 /* Run Command helpers*/
891 /* Fairly simple callback to write all output of dirmngr to stdout. */
892 static int
893 run_command_cb (void *opaque, const void *buffer, size_t length)
895 (void)opaque;
897 if (buffer)
899 if ( fwrite (buffer, length, 1, stdout) != 1 )
900 log_error ("error writing to stdout: %s\n", strerror (errno));
902 return 0;
905 /* Handle inquiries from the dirmngr COMMAND. */
906 static int
907 run_command_inq_cb (void *opaque, const char *line)
909 struct run_command_parm_s *parm = opaque;
910 int rc = 0;
912 if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
913 { /* send the given certificate */
914 int err;
915 ksba_cert_t cert;
916 const unsigned char *der;
917 size_t derlen;
919 line += 8;
920 if (!*line)
921 return gpg_error (GPG_ERR_ASS_PARAMETER);
923 err = gpgsm_find_cert (line, NULL, &cert);
924 if (err)
926 log_error ("certificate not found: %s\n", gpg_strerror (err));
927 rc = gpg_error (GPG_ERR_NOT_FOUND);
929 else
931 der = ksba_cert_get_image (cert, &derlen);
932 if (!der)
933 rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
934 else
935 rc = assuan_send_data (parm->ctx, der, derlen);
936 ksba_cert_release (cert);
939 else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
940 { /* Simply show the message given in the argument. */
941 line += 9;
942 log_info ("dirmngr: %s\n", line);
944 else
946 log_error ("unsupported inquiry `%s'\n", line);
947 rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
950 return rc;
953 static int
954 run_command_status_cb (void *opaque, const char *line)
956 ctrl_t ctrl = opaque;
958 if (opt.verbose)
960 log_info ("dirmngr status: %s\n", line);
962 if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
964 if (ctrl)
966 for (line += 8; *line == ' '; line++)
968 if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
969 return gpg_error (GPG_ERR_ASS_CANCELED);
972 return 0;
977 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
978 to stdout. A couple of inquiries are defined (see above). ARGC
979 arguments in ARGV are given to the Dirmngr. Spaces, plus and
980 percent characters within the argument strings are percent escaped
981 so that blanks can act as delimiters. */
983 gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
984 int argc, char **argv)
986 int rc;
987 int i;
988 const char *s;
989 char *line, *p;
990 size_t len;
991 struct run_command_parm_s parm;
993 rc = start_dirmngr (ctrl);
994 if (rc)
995 return rc;
997 parm.ctx = dirmngr_ctx;
999 len = strlen (command) + 1;
1000 for (i=0; i < argc; i++)
1001 len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
1002 line = xtrymalloc (len);
1003 if (!line)
1005 release_dirmngr (ctrl);
1006 return out_of_core ();
1009 p = stpcpy (line, command);
1010 for (i=0; i < argc; i++)
1012 *p++ = ' ';
1013 for (s=argv[i]; *s; s++)
1015 if (!isascii (*s))
1016 *p++ = *s;
1017 else if (*s == ' ')
1018 *p++ = '+';
1019 else if (!isprint (*s) || *s == '+')
1021 sprintf (p, "%%%02X", *(const unsigned char *)s);
1022 p += 3;
1024 else
1025 *p++ = *s;
1028 *p = 0;
1030 rc = assuan_transact (dirmngr_ctx, line,
1031 run_command_cb, NULL,
1032 run_command_inq_cb, &parm,
1033 run_command_status_cb, ctrl);
1034 xfree (line);
1035 log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
1036 release_dirmngr (ctrl);
1037 return rc;