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