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