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