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