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