Reset the context lock flag after a failed dirmngr start which may happend
[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   if (!dirmngr_ctx_locked)
343     log_error ("WARNING: trying to release a non-locked dirmngr ctx\n");
344   dirmngr_ctx_locked = 0;
345 }
346
347
348 static int
349 start_dirmngr2 (ctrl_t ctrl)
350 {
351   gpg_error_t err;
352
353   assert (! dirmngr2_ctx_locked);
354   dirmngr2_ctx_locked = 1;
355
356   err = start_dirmngr_ext (ctrl, &dirmngr2_ctx);
357   if (!dirmngr2_ctx)
358     dirmngr2_ctx_locked = 0;
359   return err;
360 }
361
362
363 static void
364 release_dirmngr2 (ctrl_t ctrl)
365 {
366   if (!dirmngr2_ctx_locked)
367     log_error ("WARNING: trying to release a non-locked dirmngr2 ctx\n");
368   dirmngr2_ctx_locked = 0;
369 }
370
371
372 \f
373 /* Handle a SENDCERT inquiry. */
374 static int
375 inq_certificate (void *opaque, const char *line)
376 {
377   struct inq_certificate_parm_s *parm = opaque;
378   int rc;
379   const unsigned char *der;
380   size_t derlen;
381   int issuer_mode = 0;
382   ksba_sexp_t ski = NULL;
383
384   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
385     {
386       line += 8;
387     }
388   else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
389     {
390       size_t n;
391
392       /* Send a certificate where a sourceKeyIdentifier is included. */
393       line += 12;
394       while (*line == ' ')
395         line++;
396       ski = make_simple_sexp_from_hexstr (line, &n);
397       line += n;
398       while (*line == ' ')
399         line++;
400     }
401   else if (!strncmp (line, "SENDISSUERCERT", 14)
402            && (line[14] == ' ' || !line[14]))
403     {
404       line += 14;
405       issuer_mode = 1;
406     }
407   else
408     {
409       log_error ("unsupported inquiry `%s'\n", line);
410       return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
411     }
412
413   if (!*line)
414     { /* Send the current certificate. */
415       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
416                                  &derlen);
417       if (!der)
418         rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
419       else
420         rc = assuan_send_data (parm->ctx, der, derlen);
421     }
422   else if (issuer_mode)
423     {
424       log_error ("sending specific issuer certificate back "
425                  "is not yet implemented\n");
426       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
427     }
428   else 
429     { /* Send the given certificate. */
430       int err;
431       ksba_cert_t cert;
432
433
434       err = gpgsm_find_cert (line, ski, &cert);
435       if (err)
436         {
437           log_error ("certificate not found: %s\n", gpg_strerror (err));
438           rc = gpg_error (GPG_ERR_NOT_FOUND);
439         }
440       else
441         {
442           der = ksba_cert_get_image (cert, &derlen);
443           if (!der)
444             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
445           else
446             rc = assuan_send_data (parm->ctx, der, derlen);
447           ksba_cert_release (cert);
448         }
449     }
450
451   xfree (ski);
452   return rc; 
453 }
454
455
456 /* Take a 20 byte hexencoded string and put it into the the provided
457    20 byte buffer FPR in binary format. */
458 static int
459 unhexify_fpr (const char *hexstr, unsigned char *fpr)
460 {
461   const char *s;
462   int n;
463
464   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
465     ;
466   if (*s || (n != 40))
467     return 0; /* no fingerprint (invalid or wrong length). */
468   n /= 2;
469   for (s=hexstr, n=0; *s; s += 2, n++)
470     fpr[n] = xtoi_2 (s);
471   return 1; /* okay */
472 }
473
474
475 static assuan_error_t
476 isvalid_status_cb (void *opaque, const char *line)
477 {
478   struct isvalid_status_parm_s *parm = opaque;
479
480   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
481     {
482       if (parm->ctrl)
483         {
484           for (line += 8; *line == ' '; line++)
485             ;
486           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
487             return gpg_error (GPG_ERR_ASS_CANCELED);
488         }
489     }
490   else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
491       && (line[24]==' ' || !line[24]))
492     {
493       parm->seen++;
494       if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
495         parm->seen++; /* Bumb it to indicate an error. */
496     }
497   return 0;
498 }
499
500
501
502 \f
503 /* Call the directory manager to check whether the certificate is valid
504    Returns 0 for valid or usually one of the errors:
505
506   GPG_ERR_CERTIFICATE_REVOKED
507   GPG_ERR_NO_CRL_KNOWN
508   GPG_ERR_CRL_TOO_OLD
509
510   Values for USE_OCSP:
511      0 = Do CRL check.
512      1 = Do an OCSP check.
513      2 = Do an OCSP check using only the default responder.
514  */
515 int
516 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
517                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
518 {
519   static int did_options;
520   int rc;
521   char *certid;
522   char line[ASSUAN_LINELENGTH];
523   struct inq_certificate_parm_s parm;
524   struct isvalid_status_parm_s stparm;
525
526   rc = start_dirmngr (ctrl);
527   if (rc)
528     return rc;
529
530   if (use_ocsp)
531     {
532       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
533     }
534   else
535     {
536       certid = gpgsm_get_certid (cert);
537       if (!certid)
538         {
539           log_error ("error getting the certificate ID\n");
540           release_dirmngr (ctrl);
541           return gpg_error (GPG_ERR_GENERAL);
542         }
543     }
544
545   if (opt.verbose > 1)
546     {
547       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
548       log_info ("asking dirmngr about %s%s\n", fpr,
549                 use_ocsp? " (using OCSP)":"");
550       xfree (fpr);
551     }
552
553   parm.ctx = dirmngr_ctx;
554   parm.cert = cert;
555   parm.issuer_cert = issuer_cert;
556
557   stparm.ctrl = ctrl;
558   stparm.seen = 0;
559   memset (stparm.fpr, 0, 20);
560
561   /* FIXME: If --disable-crl-checks has been set, we should pass an
562      option to dirmngr, so that no fallback CRL check is done after an
563      ocsp check.  It is not a problem right now as dirmngr does not
564      fallback to CRL checking.  */
565
566   /* It is sufficient to send the options only once because we have
567      one connection per process only. */
568   if (!did_options)
569     {
570       if (opt.force_crl_refresh)
571         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
572                          NULL, NULL, NULL, NULL, NULL, NULL);
573       did_options = 1;
574     }
575   snprintf (line, DIM(line)-1, "ISVALID%s %s", 
576             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
577             certid);
578   line[DIM(line)-1] = 0;
579   xfree (certid);
580
581   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
582                         inq_certificate, &parm,
583                         isvalid_status_cb, &stparm);
584   if (opt.verbose > 1)
585     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
586   rc = rc;
587
588   if (!rc && stparm.seen)
589     {
590       /* Need to also check the certificate validity. */
591       if (stparm.seen != 1)
592         {
593           log_error ("communication problem with dirmngr detected\n");
594           rc = gpg_error (GPG_ERR_INV_CRL);
595         }
596       else
597         {
598           KEYDB_HANDLE kh;
599           ksba_cert_t rspcert = NULL;
600
601           /* Fixme: First try to get the certificate from the
602              dirmngr's cache - it should be there. */
603           kh = keydb_new (0);
604           if (!kh)
605             rc = gpg_error (GPG_ERR_ENOMEM);
606           if (!rc)
607             rc = keydb_search_fpr (kh, stparm.fpr);
608           if (!rc)
609             rc = keydb_get_cert (kh, &rspcert);
610           if (rc)
611             {
612               log_error ("unable to find the certificate used "
613                          "by the dirmngr: %s\n", gpg_strerror (rc));
614               rc = gpg_error (GPG_ERR_INV_CRL);
615             }
616           keydb_release (kh);
617
618           if (!rc)
619             {
620               rc = gpgsm_cert_use_ocsp_p (rspcert);
621               if (rc)
622                 rc = gpg_error (GPG_ERR_INV_CRL);
623               else
624                 {
625                   /* Note the no_dirmngr flag: This avoids checking
626                      this certificate over and over again. */
627                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL, 
628                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
629                   if (rc)
630                     {
631                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
632                                  gpg_strerror (rc));
633                       rc = gpg_error (GPG_ERR_INV_CRL);
634                     }
635                 }
636             }
637           ksba_cert_release (rspcert);
638         }
639     }
640   release_dirmngr (ctrl);
641   return rc;
642 }
643
644
645 \f
646 /* Lookup helpers*/
647 static int
648 lookup_cb (void *opaque, const void *buffer, size_t length)
649 {
650   struct lookup_parm_s *parm = opaque;
651   size_t len;
652   char *buf;
653   ksba_cert_t cert;
654   int rc;
655
656   if (parm->error)
657     return 0;
658
659   if (buffer)
660     {
661       put_membuf (&parm->data, buffer, length);
662       return 0;
663     }
664   /* END encountered - process what we have */
665   buf = get_membuf (&parm->data, &len);
666   if (!buf)
667     {
668       parm->error = gpg_error (GPG_ERR_ENOMEM);
669       return 0;
670     }
671
672   rc = ksba_cert_new (&cert);
673   if (rc)
674     {
675       parm->error = rc;
676       return 0;
677     }
678   rc = ksba_cert_init_from_mem (cert, buf, len);
679   if (rc)
680     {
681       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
682     }
683   else
684     {
685       parm->cb (parm->cb_value, cert);
686     }
687
688   ksba_cert_release (cert);
689   init_membuf (&parm->data, 4096);
690   return 0;
691 }
692
693 /* Return a properly escaped pattern from NAMES.  The only error
694    return is NULL to indicate a malloc failure. */
695 static char *
696 pattern_from_strlist (strlist_t names)
697 {
698   strlist_t sl;
699   int n;
700   const char *s;
701   char *pattern, *p;
702
703   for (n=0, sl=names; sl; sl = sl->next)
704     {
705       for (s=sl->d; *s; s++, n++)
706         {
707           if (*s == '%' || *s == ' ' || *s == '+')
708             n += 2;
709         }
710       n++;
711     }
712
713   p = pattern = xtrymalloc (n+1);
714   if (!pattern)
715     return NULL;
716
717   for (n=0, sl=names; sl; sl = sl->next)
718     {
719       for (s=sl->d; *s; s++)
720         {
721           switch (*s)
722             {
723             case '%':
724               *p++ = '%';
725               *p++ = '2';
726               *p++ = '5';
727               break;
728             case ' ':
729               *p++ = '%';
730               *p++ = '2';
731               *p++ = '0';
732               break;
733             case '+':
734               *p++ = '%';
735               *p++ = '2';
736               *p++ = 'B';
737               break;
738             default:
739               *p++ = *s;
740               break;
741             }
742         }
743       *p++ = ' ';
744     }
745   if (p == pattern)
746     *pattern = 0; /* is empty */
747   else
748     p[-1] = '\0'; /* remove trailing blank */
749   
750   return pattern;
751 }
752
753 static int
754 lookup_status_cb (void *opaque, const char *line)
755 {
756   struct lookup_parm_s *parm = opaque;
757
758   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
759     {
760       if (parm->ctrl)
761         {
762           for (line += 8; *line == ' '; line++)
763             ;
764           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
765             return gpg_error (GPG_ERR_ASS_CANCELED);
766         }
767     }
768   else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
769     {
770       if (parm->ctrl)
771         {
772           for (line +=9; *line == ' '; line++)
773             ;
774           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
775         }
776     }
777   return 0;
778 }
779
780
781 /* Run the Directory Manager's lookup command using the pattern
782    compiled from the strings given in NAMES.  The caller must provide
783    the callback CB which will be passed cert by cert.  Note that CTRL
784    is optional.  With CACHE_ONLY the dirmngr will search only its own
785    key cache. */
786 int 
787 gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
788                       void (*cb)(void*, ksba_cert_t), void *cb_value)
789
790   int rc;
791   char *pattern;
792   char line[ASSUAN_LINELENGTH];
793   struct lookup_parm_s parm;
794   size_t len;
795   assuan_context_t ctx;
796
797   /* The lookup function can be invoked from the callback of a lookup
798      function, for example to walk the chain.  */
799   if (!dirmngr_ctx_locked)
800     {
801       rc = start_dirmngr (ctrl);
802       if (rc)
803         return rc;
804       ctx = dirmngr_ctx;
805     }
806   else if (!dirmngr2_ctx_locked)
807     {
808       rc = start_dirmngr2 (ctrl);
809       if (rc)
810         return rc;
811       ctx = dirmngr2_ctx;
812     }
813   else
814     {
815       log_fatal ("both dirmngr contexts are in use\n");
816     }
817
818   pattern = pattern_from_strlist (names);
819   if (!pattern)
820     {
821       if (ctx == dirmngr_ctx)
822         release_dirmngr (ctrl);
823       else
824         release_dirmngr2 (ctrl);
825
826       return out_of_core ();
827     }
828   snprintf (line, DIM(line)-1, "LOOKUP%s %s", 
829             cache_only? " --cache-only":"", pattern);
830   line[DIM(line)-1] = 0;
831   xfree (pattern);
832
833   parm.ctrl = ctrl;
834   parm.ctx = ctx;
835   parm.cb = cb;
836   parm.cb_value = cb_value;
837   parm.error = 0;
838   init_membuf (&parm.data, 4096);
839
840   rc = assuan_transact (ctx, line, lookup_cb, &parm,
841                         NULL, NULL, lookup_status_cb, &parm);
842   xfree (get_membuf (&parm.data, &len));
843
844   if (ctx == dirmngr_ctx)
845     release_dirmngr (ctrl);
846   else
847     release_dirmngr2 (ctrl);
848
849   if (rc)
850       return rc;
851   return parm.error;
852 }
853
854
855 \f
856 /* Run Command helpers*/
857
858 /* Fairly simple callback to write all output of dirmngr to stdout. */
859 static int
860 run_command_cb (void *opaque, const void *buffer, size_t length)
861 {
862   if (buffer)
863     {
864       if ( fwrite (buffer, length, 1, stdout) != 1 )
865         log_error ("error writing to stdout: %s\n", strerror (errno));
866     }
867   return 0;
868 }
869
870 /* Handle inquiries from the dirmngr COMMAND. */
871 static int
872 run_command_inq_cb (void *opaque, const char *line)
873 {
874   struct run_command_parm_s *parm = opaque;
875   int rc = 0;
876
877   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
878     { /* send the given certificate */
879       int err;
880       ksba_cert_t cert;
881       const unsigned char *der;
882       size_t derlen;
883
884       line += 8;
885       if (!*line)
886         return gpg_error (GPG_ERR_ASS_PARAMETER);
887
888       err = gpgsm_find_cert (line, NULL, &cert);
889       if (err)
890         {
891           log_error ("certificate not found: %s\n", gpg_strerror (err));
892           rc = gpg_error (GPG_ERR_NOT_FOUND);
893         }
894       else
895         {
896           der = ksba_cert_get_image (cert, &derlen);
897           if (!der)
898             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
899           else
900             rc = assuan_send_data (parm->ctx, der, derlen);
901           ksba_cert_release (cert);
902         }
903     }
904   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
905     { /* Simply show the message given in the argument. */
906       line += 9;
907       log_info ("dirmngr: %s\n", line);
908     }
909   else
910     {
911       log_error ("unsupported inquiry `%s'\n", line);
912       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
913     }
914
915   return rc; 
916 }
917
918 static int
919 run_command_status_cb (void *opaque, const char *line)
920 {
921   ctrl_t ctrl = opaque;
922
923   if (opt.verbose)
924     {
925       log_info ("dirmngr status: %s\n", line);
926     }
927   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
928     {
929       if (ctrl)
930         {
931           for (line += 8; *line == ' '; line++)
932             ;
933           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
934             return gpg_error (GPG_ERR_ASS_CANCELED);
935         }
936     }
937   return 0;
938 }
939
940
941
942 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
943    to stdout.  A couple of inquiries are defined (see above).  ARGC
944    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
945    percent characters within the argument strings are percent escaped
946    so that blanks can act as delimiters. */
947 int
948 gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
949                            int argc, char **argv)
950
951   int rc;
952   int i;
953   const char *s;
954   char *line, *p;
955   size_t len;
956   struct run_command_parm_s parm;
957
958   rc = start_dirmngr (ctrl);
959   if (rc)
960     return rc;
961
962   parm.ctx = dirmngr_ctx;
963
964   len = strlen (command) + 1;
965   for (i=0; i < argc; i++)
966     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
967   line = xtrymalloc (len);
968   if (!line)
969     {
970       release_dirmngr (ctrl);
971       return out_of_core ();
972     }
973
974   p = stpcpy (line, command);
975   for (i=0; i < argc; i++)
976     {
977       *p++ = ' ';
978       for (s=argv[i]; *s; s++)
979         {
980           if (!isascii (*s))
981             *p++ = *s;
982           else if (*s == ' ')
983             *p++ = '+';
984           else if (!isprint (*s) || *s == '+')
985             {
986               sprintf (p, "%%%02X", *(const unsigned char *)s);
987               p += 3;
988             }
989           else
990             *p++ = *s;
991         }
992     }
993   *p = 0;
994
995   rc = assuan_transact (dirmngr_ctx, line,
996                         run_command_cb, NULL,
997                         run_command_inq_cb, &parm,
998                         run_command_status_cb, ctrl);
999   xfree (line);
1000   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
1001   release_dirmngr (ctrl);
1002   return rc;
1003 }