chiark / gitweb /
doc: Document summary values of TOFU_STATS
[gnupg2.git] / sm / call-dirmngr.c
1 /* call-dirmngr.c - Communication with the dirmngr
2  * Copyright (C) 2002, 2003, 2005, 2007, 2008,
3  *               2010  Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
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 #include "asshelp.h"
38
39
40 struct membuf {
41   size_t len;
42   size_t size;
43   char *buf;
44   int out_of_core;
45 };
46
47
48
49 /* fixme: We need a context for each thread or serialize the access to
50    the dirmngr.  */
51 static assuan_context_t dirmngr_ctx = NULL;
52 static assuan_context_t dirmngr2_ctx = NULL;
53
54 static int dirmngr_ctx_locked;
55 static int dirmngr2_ctx_locked;
56
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;
62 };
63
64 struct isvalid_status_parm_s {
65   ctrl_t ctrl;
66   int seen;
67   unsigned char fpr[20];
68 };
69
70
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;
78 };
79
80 struct run_command_parm_s {
81   ctrl_t ctrl;
82   assuan_context_t ctx;
83 };
84
85
86
87 static gpg_error_t get_cached_cert (assuan_context_t ctx,
88                                     const unsigned char *fpr,
89                                     ksba_cert_t *r_cert);
90
91
92 \f
93 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
94    create a buffer, put_membuf to append bytes and get_membuf to
95    release and return the buffer.  Allocation errors are detected but
96    only returned at the final get_membuf(), this helps not to clutter
97    the code with out of core checks.  */
98
99 static void
100 init_membuf (struct membuf *mb, int initiallen)
101 {
102   mb->len = 0;
103   mb->size = initiallen;
104   mb->out_of_core = 0;
105   mb->buf = xtrymalloc (initiallen);
106   if (!mb->buf)
107       mb->out_of_core = 1;
108 }
109
110 static void
111 put_membuf (struct membuf *mb, const void *buf, size_t len)
112 {
113   if (mb->out_of_core)
114     return;
115
116   if (mb->len + len >= mb->size)
117     {
118       char *p;
119
120       mb->size += len + 1024;
121       p = xtryrealloc (mb->buf, mb->size);
122       if (!p)
123         {
124           mb->out_of_core = 1;
125           return;
126         }
127       mb->buf = p;
128     }
129   memcpy (mb->buf + mb->len, buf, len);
130   mb->len += len;
131 }
132
133 static void *
134 get_membuf (struct membuf *mb, size_t *len)
135 {
136   char *p;
137
138   if (mb->out_of_core)
139     {
140       xfree (mb->buf);
141       mb->buf = NULL;
142       return NULL;
143     }
144
145   p = mb->buf;
146   *len = mb->len;
147   mb->buf = NULL;
148   mb->out_of_core = 1; /* don't allow a reuse */
149   return p;
150 }
151
152
153 /* Print a warning if the server's version number is less than our
154    version number.  Returns an error code on a connection problem.  */
155 static gpg_error_t
156 warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
157                        const char *servername, int mode)
158 {
159   gpg_error_t err;
160   char *serverversion;
161   const char *myversion = strusage (13);
162
163   err = get_assuan_server_version (ctx, mode, &serverversion);
164   if (err)
165     log_error (_("error getting version from '%s': %s\n"),
166                servername, gpg_strerror (err));
167   else if (compare_version_strings (serverversion, myversion) < 0)
168     {
169       char *warn;
170
171       warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
172                            servername, serverversion, myversion);
173       if (!warn)
174         err = gpg_error_from_syserror ();
175       else
176         {
177           log_info (_("WARNING: %s\n"), warn);
178           gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
179                          warn, NULL);
180           xfree (warn);
181         }
182     }
183   xfree (serverversion);
184   return err;
185 }
186
187
188 /* This function prepares the dirmngr for a new session.  The
189    audit-events option is used so that other dirmngr clients won't get
190    disturbed by such events.  */
191 static void
192 prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
193 {
194   struct keyserver_spec *server;
195
196   if (!err)
197     err = warn_version_mismatch (ctrl, ctx, DIRMNGR_NAME, 0);
198
199   if (!err)
200     {
201       err = assuan_transact (ctx, "OPTION audit-events=1",
202                              NULL, NULL, NULL, NULL, NULL, NULL);
203       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
204         err = 0;  /* Allow the use of old dirmngr versions.  */
205     }
206   audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
207
208   if (!ctx || err)
209     return;
210
211   server = opt.keyserver;
212   while (server)
213     {
214       char line[ASSUAN_LINELENGTH];
215       char *user = server->user ? server->user : "";
216       char *pass = server->pass ? server->pass : "";
217       char *base = server->base ? server->base : "";
218
219       snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s",
220                 server->host, server->port, user, pass, base);
221
222       assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
223       /* The code below is not required because we don't return an error.  */
224       /* err = [above call]  */
225       /* if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD) */
226       /*   err = 0;  /\* Allow the use of old dirmngr versions.  *\/ */
227
228       server = server->next;
229     }
230 }
231
232
233 \f
234 /* Return a new assuan context for a Dirmngr connection.  */
235 static gpg_error_t
236 start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
237 {
238   gpg_error_t err;
239   assuan_context_t ctx;
240
241   if (opt.disable_dirmngr || ctrl->offline)
242     return gpg_error (GPG_ERR_NO_DIRMNGR);
243
244   if (*ctx_r)
245     return 0;
246
247   /* Note: if you change this to multiple connections, you also need
248      to take care of the implicit option sending caching. */
249
250   err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
251                            opt.dirmngr_program,
252                            opt.autostart, opt.verbose, DBG_IPC,
253                            gpgsm_status2, ctrl);
254   if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
255     {
256       static int shown;
257
258       if (!shown)
259         {
260           shown = 1;
261           log_info (_("no dirmngr running in this session\n"));
262         }
263     }
264   prepare_dirmngr (ctrl, ctx, err);
265   if (err)
266     return err;
267
268   *ctx_r = ctx;
269   return 0;
270 }
271
272
273 static int
274 start_dirmngr (ctrl_t ctrl)
275 {
276   gpg_error_t err;
277
278   assert (! dirmngr_ctx_locked);
279   dirmngr_ctx_locked = 1;
280
281   err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
282   /* We do not check ERR but the existence of a context because the
283      error might come from a failed command send to the dirmngr.
284      Fixme: Why don't we close the drimngr context if we encountered
285      an error in prepare_dirmngr?  */
286   if (!dirmngr_ctx)
287     dirmngr_ctx_locked = 0;
288   return err;
289 }
290
291
292 static void
293 release_dirmngr (ctrl_t ctrl)
294 {
295   (void)ctrl;
296
297   if (!dirmngr_ctx_locked)
298     log_error ("WARNING: trying to release a non-locked dirmngr ctx\n");
299   dirmngr_ctx_locked = 0;
300 }
301
302
303 static int
304 start_dirmngr2 (ctrl_t ctrl)
305 {
306   gpg_error_t err;
307
308   assert (! dirmngr2_ctx_locked);
309   dirmngr2_ctx_locked = 1;
310
311   err = start_dirmngr_ext (ctrl, &dirmngr2_ctx);
312   if (!dirmngr2_ctx)
313     dirmngr2_ctx_locked = 0;
314   return err;
315 }
316
317
318 static void
319 release_dirmngr2 (ctrl_t ctrl)
320 {
321   (void)ctrl;
322
323   if (!dirmngr2_ctx_locked)
324     log_error ("WARNING: trying to release a non-locked dirmngr2 ctx\n");
325   dirmngr2_ctx_locked = 0;
326 }
327
328
329 \f
330 /* Handle a SENDCERT inquiry. */
331 static gpg_error_t
332 inq_certificate (void *opaque, const char *line)
333 {
334   struct inq_certificate_parm_s *parm = opaque;
335   const char *s;
336   int rc;
337   size_t n;
338   const unsigned char *der;
339   size_t derlen;
340   int issuer_mode = 0;
341   ksba_sexp_t ski = NULL;
342
343   if ((s = has_leading_keyword (line, "SENDCERT")))
344     {
345       line = s;
346     }
347   else if ((s = has_leading_keyword (line, "SENDCERT_SKI")))
348     {
349       /* Send a certificate where a sourceKeyIdentifier is included. */
350       line = s;
351       ski = make_simple_sexp_from_hexstr (line, &n);
352       line += n;
353       while (*line == ' ')
354         line++;
355     }
356   else if ((s = has_leading_keyword (line, "SENDISSUERCERT")))
357     {
358       line = s;
359       issuer_mode = 1;
360     }
361   else if ((s = has_leading_keyword (line, "ISTRUSTED")))
362     {
363       /* The server is asking us whether the certificate is a trusted
364          root certificate.  */
365       char fpr[41];
366       struct rootca_flags_s rootca_flags;
367
368       line = s;
369
370       for (s=line,n=0; hexdigitp (s); s++, n++)
371         ;
372       if (*s || n != 40)
373         return gpg_error (GPG_ERR_ASS_PARAMETER);
374       for (s=line, n=0; n < 40; s++, n++)
375         fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
376       fpr[n] = 0;
377
378       if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
379         rc = assuan_send_data (parm->ctx, "1", 1);
380       else
381         rc = 0;
382       return rc;
383     }
384   else
385     {
386       log_error ("unsupported inquiry '%s'\n", line);
387       return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
388     }
389
390   if (!*line)
391     { /* Send the current certificate. */
392       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
393                                  &derlen);
394       if (!der)
395         rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
396       else
397         rc = assuan_send_data (parm->ctx, der, derlen);
398     }
399   else if (issuer_mode)
400     {
401       log_error ("sending specific issuer certificate back "
402                  "is not yet implemented\n");
403       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
404     }
405   else
406     { /* Send the given certificate. */
407       int err;
408       ksba_cert_t cert;
409
410
411       err = gpgsm_find_cert (parm->ctrl, line, ski, &cert);
412       if (err)
413         {
414           log_error ("certificate not found: %s\n", gpg_strerror (err));
415           rc = gpg_error (GPG_ERR_NOT_FOUND);
416         }
417       else
418         {
419           der = ksba_cert_get_image (cert, &derlen);
420           if (!der)
421             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
422           else
423             rc = assuan_send_data (parm->ctx, der, derlen);
424           ksba_cert_release (cert);
425         }
426     }
427
428   xfree (ski);
429   return rc;
430 }
431
432
433 /* Take a 20 byte hexencoded string and put it into the the provided
434    20 byte buffer FPR in binary format. */
435 static int
436 unhexify_fpr (const char *hexstr, unsigned char *fpr)
437 {
438   const char *s;
439   int n;
440
441   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
442     ;
443   if (*s || (n != 40))
444     return 0; /* no fingerprint (invalid or wrong length). */
445   for (s=hexstr, n=0; *s; s += 2, n++)
446     fpr[n] = xtoi_2 (s);
447   return 1; /* okay */
448 }
449
450
451 static gpg_error_t
452 isvalid_status_cb (void *opaque, const char *line)
453 {
454   struct isvalid_status_parm_s *parm = opaque;
455   const char *s;
456
457   if ((s = has_leading_keyword (line, "PROGRESS")))
458     {
459       if (parm->ctrl)
460         {
461           line = s;
462           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
463             return gpg_error (GPG_ERR_ASS_CANCELED);
464         }
465     }
466   else if ((s = has_leading_keyword (line, "ONLY_VALID_IF_CERT_VALID")))
467     {
468       parm->seen++;
469       if (!*s || !unhexify_fpr (s, parm->fpr))
470         parm->seen++; /* Bumb it to indicate an error. */
471     }
472   return 0;
473 }
474
475
476
477 \f
478 /* Call the directory manager to check whether the certificate is valid
479    Returns 0 for valid or usually one of the errors:
480
481   GPG_ERR_CERTIFICATE_REVOKED
482   GPG_ERR_NO_CRL_KNOWN
483   GPG_ERR_CRL_TOO_OLD
484
485   Values for USE_OCSP:
486      0 = Do CRL check.
487      1 = Do an OCSP check.
488      2 = Do an OCSP check using only the default responder.
489  */
490 int
491 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
492                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
493 {
494   static int did_options;
495   int rc;
496   char *certid;
497   char line[ASSUAN_LINELENGTH];
498   struct inq_certificate_parm_s parm;
499   struct isvalid_status_parm_s stparm;
500
501   rc = start_dirmngr (ctrl);
502   if (rc)
503     return rc;
504
505   if (use_ocsp)
506     {
507       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
508     }
509   else
510     {
511       certid = gpgsm_get_certid (cert);
512       if (!certid)
513         {
514           log_error ("error getting the certificate ID\n");
515           release_dirmngr (ctrl);
516           return gpg_error (GPG_ERR_GENERAL);
517         }
518     }
519
520   if (opt.verbose > 1)
521     {
522       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
523       log_info ("asking dirmngr about %s%s\n", fpr,
524                 use_ocsp? " (using OCSP)":"");
525       xfree (fpr);
526     }
527
528   parm.ctx = dirmngr_ctx;
529   parm.ctrl = ctrl;
530   parm.cert = cert;
531   parm.issuer_cert = issuer_cert;
532
533   stparm.ctrl = ctrl;
534   stparm.seen = 0;
535   memset (stparm.fpr, 0, 20);
536
537   /* FIXME: If --disable-crl-checks has been set, we should pass an
538      option to dirmngr, so that no fallback CRL check is done after an
539      ocsp check.  It is not a problem right now as dirmngr does not
540      fallback to CRL checking.  */
541
542   /* It is sufficient to send the options only once because we have
543      one connection per process only. */
544   if (!did_options)
545     {
546       if (opt.force_crl_refresh)
547         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
548                          NULL, NULL, NULL, NULL, NULL, NULL);
549       did_options = 1;
550     }
551   snprintf (line, DIM(line), "ISVALID%s %s",
552             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
553             certid);
554   xfree (certid);
555
556   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
557                         inq_certificate, &parm,
558                         isvalid_status_cb, &stparm);
559   if (opt.verbose > 1)
560     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
561
562   if (!rc && stparm.seen)
563     {
564       /* Need to also check the certificate validity. */
565       if (stparm.seen != 1)
566         {
567           log_error ("communication problem with dirmngr detected\n");
568           rc = gpg_error (GPG_ERR_INV_CRL);
569         }
570       else
571         {
572           ksba_cert_t rspcert = NULL;
573
574           if (get_cached_cert (dirmngr_ctx, stparm.fpr, &rspcert))
575             {
576               /* Ooops: Something went wrong getting the certificate
577                  from the dirmngr.  Try our own cert store now.  */
578               KEYDB_HANDLE kh;
579
580               kh = keydb_new ();
581               if (!kh)
582                 rc = gpg_error (GPG_ERR_ENOMEM);
583               if (!rc)
584                 rc = keydb_search_fpr (ctrl, kh, stparm.fpr);
585               if (!rc)
586                 rc = keydb_get_cert (kh, &rspcert);
587               if (rc)
588                 {
589                   log_error ("unable to find the certificate used "
590                              "by the dirmngr: %s\n", gpg_strerror (rc));
591                   rc = gpg_error (GPG_ERR_INV_CRL);
592                 }
593               keydb_release (kh);
594             }
595
596           if (!rc)
597             {
598               rc = gpgsm_cert_use_ocsp_p (rspcert);
599               if (rc)
600                 rc = gpg_error (GPG_ERR_INV_CRL);
601               else
602                 {
603                   /* Note the no_dirmngr flag: This avoids checking
604                      this certificate over and over again. */
605                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
606                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
607                   if (rc)
608                     {
609                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
610                                  gpg_strerror (rc));
611                       rc = gpg_error (GPG_ERR_INV_CRL);
612                     }
613                 }
614             }
615           ksba_cert_release (rspcert);
616         }
617     }
618   release_dirmngr (ctrl);
619   return rc;
620 }
621
622
623 \f
624 /* Lookup helpers*/
625 static gpg_error_t
626 lookup_cb (void *opaque, const void *buffer, size_t length)
627 {
628   struct lookup_parm_s *parm = opaque;
629   size_t len;
630   char *buf;
631   ksba_cert_t cert;
632   int rc;
633
634   if (parm->error)
635     return 0;
636
637   if (buffer)
638     {
639       put_membuf (&parm->data, buffer, length);
640       return 0;
641     }
642   /* END encountered - process what we have */
643   buf = get_membuf (&parm->data, &len);
644   if (!buf)
645     {
646       parm->error = gpg_error (GPG_ERR_ENOMEM);
647       return 0;
648     }
649
650   rc = ksba_cert_new (&cert);
651   if (rc)
652     {
653       parm->error = rc;
654       return 0;
655     }
656   rc = ksba_cert_init_from_mem (cert, buf, len);
657   if (rc)
658     {
659       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
660     }
661   else
662     {
663       parm->cb (parm->cb_value, cert);
664     }
665
666   ksba_cert_release (cert);
667   init_membuf (&parm->data, 4096);
668   return 0;
669 }
670
671 /* Return a properly escaped pattern from NAMES.  The only error
672    return is NULL to indicate a malloc failure. */
673 static char *
674 pattern_from_strlist (strlist_t names)
675 {
676   strlist_t sl;
677   int n;
678   const char *s;
679   char *pattern, *p;
680
681   for (n=0, sl=names; sl; sl = sl->next)
682     {
683       for (s=sl->d; *s; s++, n++)
684         {
685           if (*s == '%' || *s == ' ' || *s == '+')
686             n += 2;
687         }
688       n++;
689     }
690
691   p = pattern = xtrymalloc (n+1);
692   if (!pattern)
693     return NULL;
694
695   for (sl=names; sl; sl = sl->next)
696     {
697       for (s=sl->d; *s; s++)
698         {
699           switch (*s)
700             {
701             case '%':
702               *p++ = '%';
703               *p++ = '2';
704               *p++ = '5';
705               break;
706             case ' ':
707               *p++ = '%';
708               *p++ = '2';
709               *p++ = '0';
710               break;
711             case '+':
712               *p++ = '%';
713               *p++ = '2';
714               *p++ = 'B';
715               break;
716             default:
717               *p++ = *s;
718               break;
719             }
720         }
721       *p++ = ' ';
722     }
723   if (p == pattern)
724     *pattern = 0; /* is empty */
725   else
726     p[-1] = '\0'; /* remove trailing blank */
727
728   return pattern;
729 }
730
731 static gpg_error_t
732 lookup_status_cb (void *opaque, const char *line)
733 {
734   struct lookup_parm_s *parm = opaque;
735   const char *s;
736
737   if ((s = has_leading_keyword (line, "PROGRESS")))
738     {
739       if (parm->ctrl)
740         {
741           line = s;
742           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
743             return gpg_error (GPG_ERR_ASS_CANCELED);
744         }
745     }
746   else if ((s = has_leading_keyword (line, "TRUNCATED")))
747     {
748       if (parm->ctrl)
749         {
750           line = s;
751           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
752         }
753     }
754   return 0;
755 }
756
757
758 /* Run the Directory Manager's lookup command using the pattern
759    compiled from the strings given in NAMES.  The caller must provide
760    the callback CB which will be passed cert by cert.  Note that CTRL
761    is optional.  With CACHE_ONLY the dirmngr will search only its own
762    key cache. */
763 int
764 gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
765                       void (*cb)(void*, ksba_cert_t), void *cb_value)
766 {
767   int rc;
768   char *pattern;
769   char line[ASSUAN_LINELENGTH];
770   struct lookup_parm_s parm;
771   size_t len;
772   assuan_context_t ctx;
773
774   /* The lookup function can be invoked from the callback of a lookup
775      function, for example to walk the chain.  */
776   if (!dirmngr_ctx_locked)
777     {
778       rc = start_dirmngr (ctrl);
779       if (rc)
780         return rc;
781       ctx = dirmngr_ctx;
782     }
783   else if (!dirmngr2_ctx_locked)
784     {
785       rc = start_dirmngr2 (ctrl);
786       if (rc)
787         return rc;
788       ctx = dirmngr2_ctx;
789     }
790   else
791     {
792       log_fatal ("both dirmngr contexts are in use\n");
793     }
794
795   pattern = pattern_from_strlist (names);
796   if (!pattern)
797     {
798       if (ctx == dirmngr_ctx)
799         release_dirmngr (ctrl);
800       else
801         release_dirmngr2 (ctrl);
802
803       return out_of_core ();
804     }
805   snprintf (line, DIM(line), "LOOKUP%s %s",
806             cache_only? " --cache-only":"", pattern);
807   xfree (pattern);
808
809   parm.ctrl = ctrl;
810   parm.ctx = ctx;
811   parm.cb = cb;
812   parm.cb_value = cb_value;
813   parm.error = 0;
814   init_membuf (&parm.data, 4096);
815
816   rc = assuan_transact (ctx, line, lookup_cb, &parm,
817                         NULL, NULL, lookup_status_cb, &parm);
818   xfree (get_membuf (&parm.data, &len));
819
820   if (ctx == dirmngr_ctx)
821     release_dirmngr (ctrl);
822   else
823     release_dirmngr2 (ctrl);
824
825   if (rc)
826       return rc;
827   return parm.error;
828 }
829
830
831 \f
832 static gpg_error_t
833 get_cached_cert_data_cb (void *opaque, const void *buffer, size_t length)
834 {
835   struct membuf *mb = opaque;
836
837   if (buffer)
838     put_membuf (mb, buffer, length);
839   return 0;
840 }
841
842 /* Return a certificate from the Directory Manager's cache.  This
843    function only returns one certificate which must be specified using
844    the fingerprint FPR and will be stored at R_CERT.  On error NULL is
845    stored at R_CERT and an error code returned.  Note that the caller
846    must provide the locked dirmngr context CTX. */
847 static gpg_error_t
848 get_cached_cert (assuan_context_t ctx,
849                  const unsigned char *fpr, ksba_cert_t *r_cert)
850 {
851   gpg_error_t err;
852   char line[ASSUAN_LINELENGTH];
853   char hexfpr[2*20+1];
854   struct membuf mb;
855   char *buf;
856   size_t buflen = 0;
857   ksba_cert_t cert;
858
859   *r_cert = NULL;
860
861   bin2hex (fpr, 20, hexfpr);
862   snprintf (line, DIM(line), "LOOKUP --single --cache-only 0x%s", hexfpr);
863
864   init_membuf (&mb, 4096);
865   err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
866                          NULL, NULL, NULL, NULL);
867   buf = get_membuf (&mb, &buflen);
868   if (err)
869     {
870       xfree (buf);
871       return err;
872     }
873   if (!buf)
874     return gpg_error (GPG_ERR_ENOMEM);
875
876   err = ksba_cert_new (&cert);
877   if (err)
878     {
879       xfree (buf);
880       return err;
881     }
882   err = ksba_cert_init_from_mem (cert, buf, buflen);
883   xfree (buf);
884   if (err)
885     {
886       log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
887       ksba_cert_release (cert);
888       return err;
889     }
890
891   *r_cert = cert;
892   return 0;
893 }
894
895
896 \f
897 /* Run Command helpers*/
898
899 /* Fairly simple callback to write all output of dirmngr to stdout. */
900 static gpg_error_t
901 run_command_cb (void *opaque, const void *buffer, size_t length)
902 {
903   (void)opaque;
904
905   if (buffer)
906     {
907       if ( fwrite (buffer, length, 1, stdout) != 1 )
908         log_error ("error writing to stdout: %s\n", strerror (errno));
909     }
910   return 0;
911 }
912
913 /* Handle inquiries from the dirmngr COMMAND. */
914 static gpg_error_t
915 run_command_inq_cb (void *opaque, const char *line)
916 {
917   struct run_command_parm_s *parm = opaque;
918   const char *s;
919   int rc = 0;
920
921   if ((s = has_leading_keyword (line, "SENDCERT")))
922     { /* send the given certificate */
923       int err;
924       ksba_cert_t cert;
925       const unsigned char *der;
926       size_t derlen;
927
928       line = s;
929       if (!*line)
930         return gpg_error (GPG_ERR_ASS_PARAMETER);
931
932       err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert);
933       if (err)
934         {
935           log_error ("certificate not found: %s\n", gpg_strerror (err));
936           rc = gpg_error (GPG_ERR_NOT_FOUND);
937         }
938       else
939         {
940           der = ksba_cert_get_image (cert, &derlen);
941           if (!der)
942             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
943           else
944             rc = assuan_send_data (parm->ctx, der, derlen);
945           ksba_cert_release (cert);
946         }
947     }
948   else if ((s = has_leading_keyword (line, "PRINTINFO")))
949     { /* Simply show the message given in the argument. */
950       line = s;
951       log_info ("dirmngr: %s\n", line);
952     }
953   else
954     {
955       log_error ("unsupported inquiry '%s'\n", line);
956       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
957     }
958
959   return rc;
960 }
961
962 static gpg_error_t
963 run_command_status_cb (void *opaque, const char *line)
964 {
965   ctrl_t ctrl = opaque;
966   const char *s;
967
968   if (opt.verbose)
969     {
970       log_info ("dirmngr status: %s\n", line);
971     }
972   if ((s = has_leading_keyword (line, "PROGRESS")))
973     {
974       if (ctrl)
975         {
976           line = s;
977           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
978             return gpg_error (GPG_ERR_ASS_CANCELED);
979         }
980     }
981   return 0;
982 }
983
984
985
986 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
987    to stdout.  A couple of inquiries are defined (see above).  ARGC
988    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
989    percent characters within the argument strings are percent escaped
990    so that blanks can act as delimiters. */
991 int
992 gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
993                            int argc, char **argv)
994 {
995   int rc;
996   int i;
997   const char *s;
998   char *line, *p;
999   size_t len;
1000   struct run_command_parm_s parm;
1001
1002   rc = start_dirmngr (ctrl);
1003   if (rc)
1004     return rc;
1005
1006   parm.ctrl = ctrl;
1007   parm.ctx = dirmngr_ctx;
1008
1009   len = strlen (command) + 1;
1010   for (i=0; i < argc; i++)
1011     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
1012   line = xtrymalloc (len);
1013   if (!line)
1014     {
1015       release_dirmngr (ctrl);
1016       return out_of_core ();
1017     }
1018
1019   p = stpcpy (line, command);
1020   for (i=0; i < argc; i++)
1021     {
1022       *p++ = ' ';
1023       for (s=argv[i]; *s; s++)
1024         {
1025           if (!isascii (*s))
1026             *p++ = *s;
1027           else if (*s == ' ')
1028             *p++ = '+';
1029           else if (!isprint (*s) || *s == '+')
1030             {
1031               sprintf (p, "%%%02X", *(const unsigned char *)s);
1032               p += 3;
1033             }
1034           else
1035             *p++ = *s;
1036         }
1037     }
1038   *p = 0;
1039
1040   rc = assuan_transact (dirmngr_ctx, line,
1041                         run_command_cb, NULL,
1042                         run_command_inq_cb, &parm,
1043                         run_command_status_cb, ctrl);
1044   xfree (line);
1045   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
1046   release_dirmngr (ctrl);
1047   return rc;
1048 }