Fix problem when using the fallback dirmngr.
[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 static assuan_context_t dirmngr_ctx = NULL;
48 static int force_pipe_server = 0;
49
50 struct inq_certificate_parm_s {
51   assuan_context_t ctx;
52   ksba_cert_t cert;
53   ksba_cert_t issuer_cert;
54 };
55
56 struct isvalid_status_parm_s {
57   ctrl_t ctrl;
58   int seen;
59   unsigned char fpr[20];
60 };
61
62
63 struct lookup_parm_s {
64   ctrl_t ctrl;
65   assuan_context_t ctx;
66   void (*cb)(void *, ksba_cert_t);
67   void *cb_value;
68   struct membuf data;
69   int error;
70 };
71
72 struct run_command_parm_s {
73   assuan_context_t ctx;
74 };
75
76
77 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
78    create a buffer, put_membuf to append bytes and get_membuf to
79    release and return the buffer.  Allocation errors are detected but
80    only returned at the final get_membuf(), this helps not to clutter
81    the code with out of core checks.  */
82
83 static void
84 init_membuf (struct membuf *mb, int initiallen)
85 {
86   mb->len = 0;
87   mb->size = initiallen;
88   mb->out_of_core = 0;
89   mb->buf = xtrymalloc (initiallen);
90   if (!mb->buf)
91       mb->out_of_core = 1;
92 }
93
94 static void
95 put_membuf (struct membuf *mb, const void *buf, size_t len)
96 {
97   if (mb->out_of_core)
98     return;
99
100   if (mb->len + len >= mb->size)
101     {
102       char *p;
103       
104       mb->size += len + 1024;
105       p = xtryrealloc (mb->buf, mb->size);
106       if (!p)
107         {
108           mb->out_of_core = 1;
109           return;
110         }
111       mb->buf = p;
112     }
113   memcpy (mb->buf + mb->len, buf, len);
114   mb->len += len;
115 }
116
117 static void *
118 get_membuf (struct membuf *mb, size_t *len)
119 {
120   char *p;
121
122   if (mb->out_of_core)
123     {
124       xfree (mb->buf);
125       mb->buf = NULL;
126       return NULL;
127     }
128
129   p = mb->buf;
130   *len = mb->len;
131   mb->buf = NULL;
132   mb->out_of_core = 1; /* don't allow a reuse */
133   return p;
134 }
135
136
137 /* This fucntion prepares the dirmngr for a new session.  The
138    audit-events option is used so that other dirmngr clients won't get
139    disturbed by such events.  */
140 static void
141 prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
142 {
143   if (!ctrl->dirmngr_seen)
144     {
145       ctrl->dirmngr_seen = 1;
146       if (!err)
147         {
148           err = assuan_transact (ctx, "OPTION audit-events=1",
149                                  NULL, NULL, NULL, NULL, NULL, NULL);
150           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
151             err = 0;  /* Allow the use of old dirmngr versions.  */
152         }
153       audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
154     }
155 }
156
157
158 \f
159 /* Try to connect to the agent via socket or fork it off and work by
160    pipes.  Handle the server's initial greeting */
161 static int
162 start_dirmngr (ctrl_t ctrl)
163 {
164   int rc;
165   char *infostr, *p;
166   assuan_context_t ctx;
167   int try_default = 0;
168
169   if (opt.disable_dirmngr)
170     return gpg_error (GPG_ERR_NO_DIRMNGR);
171
172   if (dirmngr_ctx)
173     {
174       prepare_dirmngr (ctrl, dirmngr_ctx, 0);
175       return 0; /* fixme: We need a context for each thread or serialize
176                    the access to the dirmngr */
177     }
178   /* Note: if you change this to multiple connections, you also need
179      to take care of the implicit option sending caching. */
180
181 #ifdef HAVE_W32_SYSTEM
182   infostr = NULL;
183   opt.prefer_system_dirmngr = 1;
184 #else
185   infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
186 #endif /*HAVE_W32_SYSTEM*/
187   if (infostr && !*infostr)
188     infostr = NULL;
189   else if (infostr)
190     infostr = xstrdup (infostr);
191
192   if (opt.prefer_system_dirmngr && !force_pipe_server && !infostr)
193     {
194       infostr = xstrdup (dirmngr_socket_name ());
195       try_default = 1;
196     }
197   if (!infostr)
198     {
199       const char *pgmname;
200       const char *argv[3];
201       int no_close_list[3];
202       int i;
203
204       if (!opt.dirmngr_program || !*opt.dirmngr_program)
205         opt.dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
206       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
207         pgmname = opt.dirmngr_program;
208       else
209         pgmname++;
210
211       if (opt.verbose)
212         log_info (_("no running dirmngr - starting `%s'\n"),
213                   opt.dirmngr_program);
214       
215       if (fflush (NULL))
216         {
217           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
218           log_error ("error flushing pending output: %s\n", strerror (errno));
219           return tmperr;
220         }
221
222       argv[0] = pgmname;
223       argv[1] = "--server";
224       argv[2] = NULL;
225
226       i=0;
227       if (log_get_fd () != -1)
228         no_close_list[i++] = log_get_fd ();
229       no_close_list[i++] = fileno (stderr);
230       no_close_list[i] = -1;
231
232       /* connect to the agent and perform initial handshaking */
233       rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, argv,
234                                 no_close_list);
235     }
236   else
237     {
238       int prot;
239       int pid;
240
241       if (!try_default)
242         {
243           if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
244             {
245               log_error (_("malformed DIRMNGR_INFO environment variable\n"));
246               xfree (infostr);
247               force_pipe_server = 1;
248               return start_dirmngr (ctrl);
249             }
250           *p++ = 0;
251           pid = atoi (p);
252           while (*p && *p != PATHSEP_C)
253             p++;
254           prot = *p? atoi (p+1) : 0;
255           if (prot != 1)
256             {
257               log_error (_("dirmngr protocol version %d is not supported\n"),
258                          prot);
259               xfree (infostr);
260               force_pipe_server = 1;
261               return start_dirmngr (ctrl);
262             }
263         }
264       else
265         pid = -1;
266
267       rc = assuan_socket_connect (&ctx, infostr, pid);
268 #ifdef HAVE_W32_SYSTEM
269       if (rc)
270         log_debug ("connecting dirmngr at `%s' failed\n", infostr);
271 #endif
272
273       xfree (infostr);
274 #ifndef HAVE_W32_SYSTEM
275       if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
276         {
277           log_info (_("can't connect to the dirmngr - trying fall back\n"));
278           force_pipe_server = 1;
279           return start_dirmngr (ctrl);
280         }
281 #endif /*!HAVE_W32_SYSTEM*/
282     }
283
284   prepare_dirmngr (ctrl, ctx, rc);
285
286   if (rc)
287     {
288       log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc));
289       return gpg_error (GPG_ERR_NO_DIRMNGR);
290     }
291   dirmngr_ctx = ctx;
292
293   if (DBG_ASSUAN)
294     log_debug ("connection to dirmngr established\n");
295   return 0;
296 }
297
298
299 \f
300 /* Handle a SENDCERT inquiry. */
301 static int
302 inq_certificate (void *opaque, const char *line)
303 {
304   struct inq_certificate_parm_s *parm = opaque;
305   int rc;
306   const unsigned char *der;
307   size_t derlen;
308   int issuer_mode = 0;
309   ksba_sexp_t ski = NULL;
310
311   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
312     {
313       line += 8;
314     }
315   else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
316     {
317       size_t n;
318
319       /* Send a certificate where a sourceKeyIdentifier is included. */
320       line += 12;
321       while (*line == ' ')
322         line++;
323       ski = make_simple_sexp_from_hexstr (line, &n);
324       line += n;
325       while (*line == ' ')
326         line++;
327     }
328   else if (!strncmp (line, "SENDISSUERCERT", 14)
329            && (line[14] == ' ' || !line[14]))
330     {
331       line += 14;
332       issuer_mode = 1;
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 assuan_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           return gpg_error (GPG_ERR_GENERAL);
468         }
469     }
470
471   if (opt.verbose > 1)
472     {
473       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
474       log_info ("asking dirmngr about %s%s\n", fpr,
475                 use_ocsp? " (using OCSP)":"");
476       xfree (fpr);
477     }
478
479   parm.ctx = dirmngr_ctx;
480   parm.cert = cert;
481   parm.issuer_cert = issuer_cert;
482
483   stparm.ctrl = ctrl;
484   stparm.seen = 0;
485   memset (stparm.fpr, 0, 20);
486
487   /* FIXME: If --disable-crl-checks has been set, we should pass an
488      option to dirmngr, so that no fallback CRL check is done after an
489      ocsp check.  It is not a problem right now as dirmngr does not
490      fallback to CRL checking.  */
491
492   /* It is sufficient to send the options only once because we have
493      one connection per process only. */
494   if (!did_options)
495     {
496       if (opt.force_crl_refresh)
497         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
498                          NULL, NULL, NULL, NULL, NULL, NULL);
499       did_options = 1;
500     }
501   snprintf (line, DIM(line)-1, "ISVALID%s %s", 
502             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
503             certid);
504   line[DIM(line)-1] = 0;
505   xfree (certid);
506
507   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
508                         inq_certificate, &parm,
509                         isvalid_status_cb, &stparm);
510   if (opt.verbose > 1)
511     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
512   rc = rc;
513
514   if (!rc && stparm.seen)
515     {
516       /* Need to also check the certificate validity. */
517       if (stparm.seen != 1)
518         {
519           log_error ("communication problem with dirmngr detected\n");
520           rc = gpg_error (GPG_ERR_INV_CRL);
521         }
522       else
523         {
524           KEYDB_HANDLE kh;
525           ksba_cert_t rspcert = NULL;
526
527           /* Fixme: First try to get the certificate from the
528              dirmngr's cache - it should be there. */
529           kh = keydb_new (0);
530           if (!kh)
531             rc = gpg_error (GPG_ERR_ENOMEM);
532           if (!rc)
533             rc = keydb_search_fpr (kh, stparm.fpr);
534           if (!rc)
535             rc = keydb_get_cert (kh, &rspcert);
536           if (rc)
537             {
538               log_error ("unable to find the certificate used "
539                          "by the dirmngr: %s\n", gpg_strerror (rc));
540               rc = gpg_error (GPG_ERR_INV_CRL);
541             }
542           keydb_release (kh);
543
544           if (!rc)
545             {
546               rc = gpgsm_cert_use_ocsp_p (rspcert);
547               if (rc)
548                 rc = gpg_error (GPG_ERR_INV_CRL);
549               else
550                 {
551                   /* Note the no_dirmngr flag: This avoids checking
552                      this certificate over and over again. */
553                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL, 
554                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
555                   if (rc)
556                     {
557                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
558                                  gpg_strerror (rc));
559                       rc = gpg_error (GPG_ERR_INV_CRL);
560                     }
561                 }
562             }
563           ksba_cert_release (rspcert);
564         }
565     }
566   return rc;
567 }
568
569
570 \f
571 /* Lookup helpers*/
572 static int
573 lookup_cb (void *opaque, const void *buffer, size_t length)
574 {
575   struct lookup_parm_s *parm = opaque;
576   size_t len;
577   char *buf;
578   ksba_cert_t cert;
579   int rc;
580
581   if (parm->error)
582     return 0;
583
584   if (buffer)
585     {
586       put_membuf (&parm->data, buffer, length);
587       return 0;
588     }
589   /* END encountered - process what we have */
590   buf = get_membuf (&parm->data, &len);
591   if (!buf)
592     {
593       parm->error = gpg_error (GPG_ERR_ENOMEM);
594       return 0;
595     }
596
597   rc = ksba_cert_new (&cert);
598   if (rc)
599     {
600       parm->error = rc;
601       return 0;
602     }
603   rc = ksba_cert_init_from_mem (cert, buf, len);
604   if (rc)
605     {
606       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
607     }
608   else
609     {
610       parm->cb (parm->cb_value, cert);
611     }
612
613   ksba_cert_release (cert);
614   init_membuf (&parm->data, 4096);
615   return 0;
616 }
617
618 /* Return a properly escaped pattern from NAMES.  The only error
619    return is NULL to indicate a malloc failure. */
620 static char *
621 pattern_from_strlist (strlist_t names)
622 {
623   strlist_t sl;
624   int n;
625   const char *s;
626   char *pattern, *p;
627
628   for (n=0, sl=names; sl; sl = sl->next)
629     {
630       for (s=sl->d; *s; s++, n++)
631         {
632           if (*s == '%' || *s == ' ' || *s == '+')
633             n += 2;
634         }
635       n++;
636     }
637
638   p = pattern = xtrymalloc (n+1);
639   if (!pattern)
640     return NULL;
641
642   for (n=0, sl=names; sl; sl = sl->next)
643     {
644       for (s=sl->d; *s; s++)
645         {
646           switch (*s)
647             {
648             case '%':
649               *p++ = '%';
650               *p++ = '2';
651               *p++ = '5';
652               break;
653             case ' ':
654               *p++ = '%';
655               *p++ = '2';
656               *p++ = '0';
657               break;
658             case '+':
659               *p++ = '%';
660               *p++ = '2';
661               *p++ = 'B';
662               break;
663             default:
664               *p++ = *s;
665               break;
666             }
667         }
668       *p++ = ' ';
669     }
670   if (p == pattern)
671     *pattern = 0; /* is empty */
672   else
673     p[-1] = '\0'; /* remove trailing blank */
674   
675   return pattern;
676 }
677
678 static int
679 lookup_status_cb (void *opaque, const char *line)
680 {
681   struct lookup_parm_s *parm = opaque;
682
683   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
684     {
685       if (parm->ctrl)
686         {
687           for (line += 8; *line == ' '; line++)
688             ;
689           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
690             return gpg_error (GPG_ERR_ASS_CANCELED);
691         }
692     }
693   else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
694     {
695       if (parm->ctrl)
696         {
697           for (line +=9; *line == ' '; line++)
698             ;
699           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
700         }
701     }
702   return 0;
703 }
704
705
706 /* Run the Directroy Managers lookup command using the pattern
707    compiled from the strings given in NAMES.  The caller must provide
708    the callback CB which will be passed cert by cert.  Note that CTRL
709    is optional.  With CACHE_ONLY the dirmngr will search only its own
710    key cache. */
711 int 
712 gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
713                       void (*cb)(void*, ksba_cert_t), void *cb_value)
714
715   int rc;
716   char *pattern;
717   char line[ASSUAN_LINELENGTH];
718   struct lookup_parm_s parm;
719   size_t len;
720
721   rc = start_dirmngr (ctrl);
722   if (rc)
723     return rc;
724
725   pattern = pattern_from_strlist (names);
726   if (!pattern)
727     return out_of_core ();
728   snprintf (line, DIM(line)-1, "LOOKUP%s %s", 
729             cache_only? " --cache-only":"", pattern);
730   line[DIM(line)-1] = 0;
731   xfree (pattern);
732
733   parm.ctrl = ctrl;
734   parm.ctx = dirmngr_ctx;
735   parm.cb = cb;
736   parm.cb_value = cb_value;
737   parm.error = 0;
738   init_membuf (&parm.data, 4096);
739
740   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
741                         NULL, NULL, lookup_status_cb, &parm);
742   xfree (get_membuf (&parm.data, &len));
743   if (rc)
744     return rc;
745   return parm.error;
746 }
747
748
749 \f
750 /* Run Command helpers*/
751
752 /* Fairly simple callback to write all output of dirmngr to stdout. */
753 static int
754 run_command_cb (void *opaque, const void *buffer, size_t length)
755 {
756   if (buffer)
757     {
758       if ( fwrite (buffer, length, 1, stdout) != 1 )
759         log_error ("error writing to stdout: %s\n", strerror (errno));
760     }
761   return 0;
762 }
763
764 /* Handle inquiries from the dirmngr COMMAND. */
765 static int
766 run_command_inq_cb (void *opaque, const char *line)
767 {
768   struct run_command_parm_s *parm = opaque;
769   int rc = 0;
770
771   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
772     { /* send the given certificate */
773       int err;
774       ksba_cert_t cert;
775       const unsigned char *der;
776       size_t derlen;
777
778       line += 8;
779       if (!*line)
780         return gpg_error (GPG_ERR_ASS_PARAMETER);
781
782       err = gpgsm_find_cert (line, NULL, &cert);
783       if (err)
784         {
785           log_error ("certificate not found: %s\n", gpg_strerror (err));
786           rc = gpg_error (GPG_ERR_NOT_FOUND);
787         }
788       else
789         {
790           der = ksba_cert_get_image (cert, &derlen);
791           if (!der)
792             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
793           else
794             rc = assuan_send_data (parm->ctx, der, derlen);
795           ksba_cert_release (cert);
796         }
797     }
798   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
799     { /* Simply show the message given in the argument. */
800       line += 9;
801       log_info ("dirmngr: %s\n", line);
802     }
803   else
804     {
805       log_error ("unsupported inquiry `%s'\n", line);
806       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
807     }
808
809   return rc; 
810 }
811
812 static int
813 run_command_status_cb (void *opaque, const char *line)
814 {
815   ctrl_t ctrl = opaque;
816
817   if (opt.verbose)
818     {
819       log_info ("dirmngr status: %s\n", line);
820     }
821   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
822     {
823       if (ctrl)
824         {
825           for (line += 8; *line == ' '; line++)
826             ;
827           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
828             return gpg_error (GPG_ERR_ASS_CANCELED);
829         }
830     }
831   return 0;
832 }
833
834
835
836 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
837    to stdout.  A couple of inquiries are defined (see above).  ARGC
838    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
839    percent characters within the argument strings are percent escaped
840    so that blanks can act as delimiters. */
841 int
842 gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
843                            int argc, char **argv)
844
845   int rc;
846   int i;
847   const char *s;
848   char *line, *p;
849   size_t len;
850   struct run_command_parm_s parm;
851
852   rc = start_dirmngr (ctrl);
853   if (rc)
854     return rc;
855
856   parm.ctx = dirmngr_ctx;
857
858   len = strlen (command) + 1;
859   for (i=0; i < argc; i++)
860     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
861   line = xtrymalloc (len);
862   if (!line)
863     return out_of_core ();
864
865   p = stpcpy (line, command);
866   for (i=0; i < argc; i++)
867     {
868       *p++ = ' ';
869       for (s=argv[i]; *s; s++)
870         {
871           if (!isascii (*s))
872             *p++ = *s;
873           else if (*s == ' ')
874             *p++ = '+';
875           else if (!isprint (*s) || *s == '+')
876             {
877               sprintf (p, "%%%02X", *(const unsigned char *)s);
878               p += 3;
879             }
880           else
881             *p++ = *s;
882         }
883     }
884   *p = 0;
885
886   rc = assuan_transact (dirmngr_ctx, line,
887                         run_command_cb, NULL,
888                         run_command_inq_cb, &parm,
889                         run_command_status_cb, ctrl);
890   xfree (line);
891   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
892   return rc;
893 }