2008-06-13 Marcus Brinkmann <marcus@ulysses.g10code.com>
[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   struct keyserver_spec *server;
144
145   if (!ctrl->dirmngr_seen)
146     {
147       ctrl->dirmngr_seen = 1;
148       if (!err)
149         {
150           err = assuan_transact (ctx, "OPTION audit-events=1",
151                                  NULL, NULL, NULL, NULL, NULL, NULL);
152           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
153             err = 0;  /* Allow the use of old dirmngr versions.  */
154         }
155       audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
156     }
157
158   server = opt.keyserver;
159   while (server)
160     {
161       char line[ASSUAN_LINELENGTH];
162       char *user = server->user ? server->user : "";
163       char *pass = server->pass ? server->pass : "";
164       char *base = server->base ? server->base : "";
165
166       snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
167                 server->host, server->port, user, pass, base);
168       line[DIM (line) - 1] = 0;
169
170       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
171       if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
172         err = 0;  /* Allow the use of old dirmngr versions.  */
173
174       server = server->next;
175     }
176 }
177
178
179 \f
180 /* Try to connect to the agent via socket or fork it off and work by
181    pipes.  Handle the server's initial greeting */
182 static int
183 start_dirmngr (ctrl_t ctrl)
184 {
185   int rc;
186   char *infostr, *p;
187   assuan_context_t ctx;
188   int try_default = 0;
189
190   if (opt.disable_dirmngr)
191     return gpg_error (GPG_ERR_NO_DIRMNGR);
192
193   if (dirmngr_ctx)
194     {
195       prepare_dirmngr (ctrl, dirmngr_ctx, 0);
196       return 0; /* fixme: We need a context for each thread or serialize
197                    the access to the dirmngr */
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 (ctrl);
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 (ctrl);
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 (ctrl);
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   dirmngr_ctx = ctx;
313
314   if (DBG_ASSUAN)
315     log_debug ("connection to dirmngr established\n");
316   return 0;
317 }
318
319
320 \f
321 /* Handle a SENDCERT inquiry. */
322 static int
323 inq_certificate (void *opaque, const char *line)
324 {
325   struct inq_certificate_parm_s *parm = opaque;
326   int rc;
327   const unsigned char *der;
328   size_t derlen;
329   int issuer_mode = 0;
330   ksba_sexp_t ski = NULL;
331
332   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
333     {
334       line += 8;
335     }
336   else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
337     {
338       size_t n;
339
340       /* Send a certificate where a sourceKeyIdentifier is included. */
341       line += 12;
342       while (*line == ' ')
343         line++;
344       ski = make_simple_sexp_from_hexstr (line, &n);
345       line += n;
346       while (*line == ' ')
347         line++;
348     }
349   else if (!strncmp (line, "SENDISSUERCERT", 14)
350            && (line[14] == ' ' || !line[14]))
351     {
352       line += 14;
353       issuer_mode = 1;
354     }
355   else
356     {
357       log_error ("unsupported inquiry `%s'\n", line);
358       return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
359     }
360
361   if (!*line)
362     { /* Send the current certificate. */
363       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
364                                  &derlen);
365       if (!der)
366         rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
367       else
368         rc = assuan_send_data (parm->ctx, der, derlen);
369     }
370   else if (issuer_mode)
371     {
372       log_error ("sending specific issuer certificate back "
373                  "is not yet implemented\n");
374       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
375     }
376   else 
377     { /* Send the given certificate. */
378       int err;
379       ksba_cert_t cert;
380
381
382       err = gpgsm_find_cert (line, ski, &cert);
383       if (err)
384         {
385           log_error ("certificate not found: %s\n", gpg_strerror (err));
386           rc = gpg_error (GPG_ERR_NOT_FOUND);
387         }
388       else
389         {
390           der = ksba_cert_get_image (cert, &derlen);
391           if (!der)
392             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
393           else
394             rc = assuan_send_data (parm->ctx, der, derlen);
395           ksba_cert_release (cert);
396         }
397     }
398
399   xfree (ski);
400   return rc; 
401 }
402
403
404 /* Take a 20 byte hexencoded string and put it into the the provided
405    20 byte buffer FPR in binary format. */
406 static int
407 unhexify_fpr (const char *hexstr, unsigned char *fpr)
408 {
409   const char *s;
410   int n;
411
412   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
413     ;
414   if (*s || (n != 40))
415     return 0; /* no fingerprint (invalid or wrong length). */
416   n /= 2;
417   for (s=hexstr, n=0; *s; s += 2, n++)
418     fpr[n] = xtoi_2 (s);
419   return 1; /* okay */
420 }
421
422
423 static assuan_error_t
424 isvalid_status_cb (void *opaque, const char *line)
425 {
426   struct isvalid_status_parm_s *parm = opaque;
427
428   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
429     {
430       if (parm->ctrl)
431         {
432           for (line += 8; *line == ' '; line++)
433             ;
434           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
435             return gpg_error (GPG_ERR_ASS_CANCELED);
436         }
437     }
438   else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
439       && (line[24]==' ' || !line[24]))
440     {
441       parm->seen++;
442       if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
443         parm->seen++; /* Bumb it to indicate an error. */
444     }
445   return 0;
446 }
447
448
449
450 \f
451 /* Call the directory manager to check whether the certificate is valid
452    Returns 0 for valid or usually one of the errors:
453
454   GPG_ERR_CERTIFICATE_REVOKED
455   GPG_ERR_NO_CRL_KNOWN
456   GPG_ERR_CRL_TOO_OLD
457
458   Values for USE_OCSP:
459      0 = Do CRL check.
460      1 = Do an OCSP check.
461      2 = Do an OCSP check using only the default responder.
462  */
463 int
464 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
465                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
466 {
467   static int did_options;
468   int rc;
469   char *certid;
470   char line[ASSUAN_LINELENGTH];
471   struct inq_certificate_parm_s parm;
472   struct isvalid_status_parm_s stparm;
473
474   rc = start_dirmngr (ctrl);
475   if (rc)
476     return rc;
477
478   if (use_ocsp)
479     {
480       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
481     }
482   else
483     {
484       certid = gpgsm_get_certid (cert);
485       if (!certid)
486         {
487           log_error ("error getting the certificate ID\n");
488           return gpg_error (GPG_ERR_GENERAL);
489         }
490     }
491
492   if (opt.verbose > 1)
493     {
494       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
495       log_info ("asking dirmngr about %s%s\n", fpr,
496                 use_ocsp? " (using OCSP)":"");
497       xfree (fpr);
498     }
499
500   parm.ctx = dirmngr_ctx;
501   parm.cert = cert;
502   parm.issuer_cert = issuer_cert;
503
504   stparm.ctrl = ctrl;
505   stparm.seen = 0;
506   memset (stparm.fpr, 0, 20);
507
508   /* FIXME: If --disable-crl-checks has been set, we should pass an
509      option to dirmngr, so that no fallback CRL check is done after an
510      ocsp check.  It is not a problem right now as dirmngr does not
511      fallback to CRL checking.  */
512
513   /* It is sufficient to send the options only once because we have
514      one connection per process only. */
515   if (!did_options)
516     {
517       if (opt.force_crl_refresh)
518         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
519                          NULL, NULL, NULL, NULL, NULL, NULL);
520       did_options = 1;
521     }
522   snprintf (line, DIM(line)-1, "ISVALID%s %s", 
523             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
524             certid);
525   line[DIM(line)-1] = 0;
526   xfree (certid);
527
528   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
529                         inq_certificate, &parm,
530                         isvalid_status_cb, &stparm);
531   if (opt.verbose > 1)
532     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
533   rc = rc;
534
535   if (!rc && stparm.seen)
536     {
537       /* Need to also check the certificate validity. */
538       if (stparm.seen != 1)
539         {
540           log_error ("communication problem with dirmngr detected\n");
541           rc = gpg_error (GPG_ERR_INV_CRL);
542         }
543       else
544         {
545           KEYDB_HANDLE kh;
546           ksba_cert_t rspcert = NULL;
547
548           /* Fixme: First try to get the certificate from the
549              dirmngr's cache - it should be there. */
550           kh = keydb_new (0);
551           if (!kh)
552             rc = gpg_error (GPG_ERR_ENOMEM);
553           if (!rc)
554             rc = keydb_search_fpr (kh, stparm.fpr);
555           if (!rc)
556             rc = keydb_get_cert (kh, &rspcert);
557           if (rc)
558             {
559               log_error ("unable to find the certificate used "
560                          "by the dirmngr: %s\n", gpg_strerror (rc));
561               rc = gpg_error (GPG_ERR_INV_CRL);
562             }
563           keydb_release (kh);
564
565           if (!rc)
566             {
567               rc = gpgsm_cert_use_ocsp_p (rspcert);
568               if (rc)
569                 rc = gpg_error (GPG_ERR_INV_CRL);
570               else
571                 {
572                   /* Note the no_dirmngr flag: This avoids checking
573                      this certificate over and over again. */
574                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL, 
575                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
576                   if (rc)
577                     {
578                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
579                                  gpg_strerror (rc));
580                       rc = gpg_error (GPG_ERR_INV_CRL);
581                     }
582                 }
583             }
584           ksba_cert_release (rspcert);
585         }
586     }
587   return rc;
588 }
589
590
591 \f
592 /* Lookup helpers*/
593 static int
594 lookup_cb (void *opaque, const void *buffer, size_t length)
595 {
596   struct lookup_parm_s *parm = opaque;
597   size_t len;
598   char *buf;
599   ksba_cert_t cert;
600   int rc;
601
602   if (parm->error)
603     return 0;
604
605   if (buffer)
606     {
607       put_membuf (&parm->data, buffer, length);
608       return 0;
609     }
610   /* END encountered - process what we have */
611   buf = get_membuf (&parm->data, &len);
612   if (!buf)
613     {
614       parm->error = gpg_error (GPG_ERR_ENOMEM);
615       return 0;
616     }
617
618   rc = ksba_cert_new (&cert);
619   if (rc)
620     {
621       parm->error = rc;
622       return 0;
623     }
624   rc = ksba_cert_init_from_mem (cert, buf, len);
625   if (rc)
626     {
627       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
628     }
629   else
630     {
631       parm->cb (parm->cb_value, cert);
632     }
633
634   ksba_cert_release (cert);
635   init_membuf (&parm->data, 4096);
636   return 0;
637 }
638
639 /* Return a properly escaped pattern from NAMES.  The only error
640    return is NULL to indicate a malloc failure. */
641 static char *
642 pattern_from_strlist (strlist_t names)
643 {
644   strlist_t sl;
645   int n;
646   const char *s;
647   char *pattern, *p;
648
649   for (n=0, sl=names; sl; sl = sl->next)
650     {
651       for (s=sl->d; *s; s++, n++)
652         {
653           if (*s == '%' || *s == ' ' || *s == '+')
654             n += 2;
655         }
656       n++;
657     }
658
659   p = pattern = xtrymalloc (n+1);
660   if (!pattern)
661     return NULL;
662
663   for (n=0, sl=names; sl; sl = sl->next)
664     {
665       for (s=sl->d; *s; s++)
666         {
667           switch (*s)
668             {
669             case '%':
670               *p++ = '%';
671               *p++ = '2';
672               *p++ = '5';
673               break;
674             case ' ':
675               *p++ = '%';
676               *p++ = '2';
677               *p++ = '0';
678               break;
679             case '+':
680               *p++ = '%';
681               *p++ = '2';
682               *p++ = 'B';
683               break;
684             default:
685               *p++ = *s;
686               break;
687             }
688         }
689       *p++ = ' ';
690     }
691   if (p == pattern)
692     *pattern = 0; /* is empty */
693   else
694     p[-1] = '\0'; /* remove trailing blank */
695   
696   return pattern;
697 }
698
699 static int
700 lookup_status_cb (void *opaque, const char *line)
701 {
702   struct lookup_parm_s *parm = opaque;
703
704   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
705     {
706       if (parm->ctrl)
707         {
708           for (line += 8; *line == ' '; line++)
709             ;
710           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
711             return gpg_error (GPG_ERR_ASS_CANCELED);
712         }
713     }
714   else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
715     {
716       if (parm->ctrl)
717         {
718           for (line +=9; *line == ' '; line++)
719             ;
720           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
721         }
722     }
723   return 0;
724 }
725
726
727 /* Run the Directory Manager's lookup command using the pattern
728    compiled from the strings given in NAMES.  The caller must provide
729    the callback CB which will be passed cert by cert.  Note that CTRL
730    is optional.  With CACHE_ONLY the dirmngr will search only its own
731    key cache. */
732 int 
733 gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
734                       void (*cb)(void*, ksba_cert_t), void *cb_value)
735
736   int rc;
737   char *pattern;
738   char line[ASSUAN_LINELENGTH];
739   struct lookup_parm_s parm;
740   size_t len;
741
742   rc = start_dirmngr (ctrl);
743   if (rc)
744     return rc;
745
746   pattern = pattern_from_strlist (names);
747   if (!pattern)
748     return out_of_core ();
749   snprintf (line, DIM(line)-1, "LOOKUP%s %s", 
750             cache_only? " --cache-only":"", pattern);
751   line[DIM(line)-1] = 0;
752   xfree (pattern);
753
754   parm.ctrl = ctrl;
755   parm.ctx = dirmngr_ctx;
756   parm.cb = cb;
757   parm.cb_value = cb_value;
758   parm.error = 0;
759   init_membuf (&parm.data, 4096);
760
761   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
762                         NULL, NULL, lookup_status_cb, &parm);
763   xfree (get_membuf (&parm.data, &len));
764   if (rc)
765     return rc;
766   return parm.error;
767 }
768
769
770 \f
771 /* Run Command helpers*/
772
773 /* Fairly simple callback to write all output of dirmngr to stdout. */
774 static int
775 run_command_cb (void *opaque, const void *buffer, size_t length)
776 {
777   if (buffer)
778     {
779       if ( fwrite (buffer, length, 1, stdout) != 1 )
780         log_error ("error writing to stdout: %s\n", strerror (errno));
781     }
782   return 0;
783 }
784
785 /* Handle inquiries from the dirmngr COMMAND. */
786 static int
787 run_command_inq_cb (void *opaque, const char *line)
788 {
789   struct run_command_parm_s *parm = opaque;
790   int rc = 0;
791
792   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
793     { /* send the given certificate */
794       int err;
795       ksba_cert_t cert;
796       const unsigned char *der;
797       size_t derlen;
798
799       line += 8;
800       if (!*line)
801         return gpg_error (GPG_ERR_ASS_PARAMETER);
802
803       err = gpgsm_find_cert (line, NULL, &cert);
804       if (err)
805         {
806           log_error ("certificate not found: %s\n", gpg_strerror (err));
807           rc = gpg_error (GPG_ERR_NOT_FOUND);
808         }
809       else
810         {
811           der = ksba_cert_get_image (cert, &derlen);
812           if (!der)
813             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
814           else
815             rc = assuan_send_data (parm->ctx, der, derlen);
816           ksba_cert_release (cert);
817         }
818     }
819   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
820     { /* Simply show the message given in the argument. */
821       line += 9;
822       log_info ("dirmngr: %s\n", line);
823     }
824   else
825     {
826       log_error ("unsupported inquiry `%s'\n", line);
827       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
828     }
829
830   return rc; 
831 }
832
833 static int
834 run_command_status_cb (void *opaque, const char *line)
835 {
836   ctrl_t ctrl = opaque;
837
838   if (opt.verbose)
839     {
840       log_info ("dirmngr status: %s\n", line);
841     }
842   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
843     {
844       if (ctrl)
845         {
846           for (line += 8; *line == ' '; line++)
847             ;
848           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
849             return gpg_error (GPG_ERR_ASS_CANCELED);
850         }
851     }
852   return 0;
853 }
854
855
856
857 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
858    to stdout.  A couple of inquiries are defined (see above).  ARGC
859    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
860    percent characters within the argument strings are percent escaped
861    so that blanks can act as delimiters. */
862 int
863 gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
864                            int argc, char **argv)
865
866   int rc;
867   int i;
868   const char *s;
869   char *line, *p;
870   size_t len;
871   struct run_command_parm_s parm;
872
873   rc = start_dirmngr (ctrl);
874   if (rc)
875     return rc;
876
877   parm.ctx = dirmngr_ctx;
878
879   len = strlen (command) + 1;
880   for (i=0; i < argc; i++)
881     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
882   line = xtrymalloc (len);
883   if (!line)
884     return out_of_core ();
885
886   p = stpcpy (line, command);
887   for (i=0; i < argc; i++)
888     {
889       *p++ = ' ';
890       for (s=argv[i]; *s; s++)
891         {
892           if (!isascii (*s))
893             *p++ = *s;
894           else if (*s == ' ')
895             *p++ = '+';
896           else if (!isprint (*s) || *s == '+')
897             {
898               sprintf (p, "%%%02X", *(const unsigned char *)s);
899               p += 3;
900             }
901           else
902             *p++ = *s;
903         }
904     }
905   *p = 0;
906
907   rc = assuan_transact (dirmngr_ctx, line,
908                         run_command_cb, NULL,
909                         run_command_inq_cb, &parm,
910                         run_command_status_cb, ctrl);
911   xfree (line);
912   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
913   return rc;
914 }