dirmngr: Improve assuan error comment for cmd keyserver.
[gnupg.git] / dirmngr / server.c
1 /* server.c - LDAP and Keyserver access server
2  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011, 2015 g10 Code GmbH
4  * Copyright (C) 2014, 2015, 2016 Werner Koch
5  * Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
6  *
7  * This file is part of GnuPG.
8  *
9  * GnuPG is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * GnuPG is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <https://www.gnu.org/licenses/>.
21  *
22  * SPDX-License-Identifier: GPL-3.0+
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 #include "dirmngr.h"
37 #include <assuan.h>
38
39 #include "crlcache.h"
40 #include "crlfetch.h"
41 #if USE_LDAP
42 # include "ldapserver.h"
43 #endif
44 #include "ocsp.h"
45 #include "certcache.h"
46 #include "validate.h"
47 #include "misc.h"
48 #if USE_LDAP
49 # include "ldap-wrapper.h"
50 #endif
51 #include "ks-action.h"
52 #include "ks-engine.h"  /* (ks_hkp_print_hosttable) */
53 #if USE_LDAP
54 # include "ldap-parse-uri.h"
55 #endif
56 #include "dns-stuff.h"
57 #include "../common/mbox-util.h"
58 #include "../common/zb32.h"
59 #include "../common/server-help.h"
60
61 /* To avoid DoS attacks we limit the size of a certificate to
62    something reasonable.  The DoS was actually only an issue back when
63    Dirmngr was a system service and not a user service. */
64 #define MAX_CERT_LENGTH (16*1024)
65
66 /* The limit for the CERTLIST inquiry.  We allow for up to 20
67  * certificates but also take PEM encoding into account.  */
68 #define MAX_CERTLIST_LENGTH ((MAX_CERT_LENGTH * 20 * 4)/3)
69
70 /* The same goes for OpenPGP keyblocks, but here we need to allow for
71    much longer blocks; a 200k keyblock is not too unusual for keys
72    with a lot of signatures (e.g. 0x5b0358a2).  9C31503C6D866396 even
73    has 770 KiB as of 2015-08-23.  To avoid adding a runtime option we
74    now use 20MiB which should really be enough.  Well, a key with
75    several pictures could be larger (the parser as a 18MiB limit for
76    attribute packets) but it won't be nice to the keyservers to send
77    them such large blobs.  */
78 #define MAX_KEYBLOCK_LENGTH (20*1024*1024)
79
80
81 #define PARM_ERROR(t) assuan_set_error (ctx, \
82                                         gpg_error (GPG_ERR_ASS_PARAMETER), (t))
83 #define set_error(e,t) (ctx ? assuan_set_error (ctx, gpg_error (e), (t)) \
84                         /**/: gpg_error (e))
85
86
87
88 /* Control structure per connection. */
89 struct server_local_s
90 {
91   /* Data used to associate an Assuan context with local server data */
92   assuan_context_t assuan_ctx;
93
94   /* The session id (a counter).  */
95   unsigned int session_id;
96
97   /* Per-session LDAP servers.  */
98   ldap_server_t ldapservers;
99
100   /* Per-session list of keyservers.  */
101   uri_item_t keyservers;
102
103   /* If this flag is set to true this dirmngr process will be
104      terminated after the end of this session.  */
105   int stopme;
106
107   /* State variable private to is_tor_running.  */
108   int tor_state;
109
110   /* If the first both flags are set the assuan logging of data lines
111    * is suppressed.  The count variable is used to show the number of
112    * non-logged bytes.  */
113   size_t inhibit_data_logging_count;
114   unsigned int inhibit_data_logging : 1;
115   unsigned int inhibit_data_logging_now : 1;
116 };
117
118
119 /* Cookie definition for assuan data line output.  */
120 static gpgrt_ssize_t data_line_cookie_write (void *cookie,
121                                              const void *buffer, size_t size);
122 static int data_line_cookie_close (void *cookie);
123 static es_cookie_io_functions_t data_line_cookie_functions =
124   {
125     NULL,
126     data_line_cookie_write,
127     NULL,
128     data_line_cookie_close
129   };
130
131
132 /* Local prototypes */
133 static const char *task_check_wkd_support (ctrl_t ctrl, const char *domain);
134
135
136
137 \f
138 /* Accessor for the local ldapservers variable. */
139 ldap_server_t
140 get_ldapservers_from_ctrl (ctrl_t ctrl)
141 {
142   if (ctrl && ctrl->server_local)
143     return ctrl->server_local->ldapservers;
144   else
145     return NULL;
146 }
147
148 /* Release an uri_item_t list.  */
149 static void
150 release_uri_item_list (uri_item_t list)
151 {
152   while (list)
153     {
154       uri_item_t tmp = list->next;
155       http_release_parsed_uri (list->parsed_uri);
156       xfree (list);
157       list = tmp;
158     }
159 }
160
161 /* Release all configured keyserver info from CTRL.  */
162 void
163 release_ctrl_keyservers (ctrl_t ctrl)
164 {
165   if (! ctrl->server_local)
166     return;
167
168   release_uri_item_list (ctrl->server_local->keyservers);
169   ctrl->server_local->keyservers = NULL;
170 }
171
172
173
174 /* Helper to print a message while leaving a command.  */
175 static gpg_error_t
176 leave_cmd (assuan_context_t ctx, gpg_error_t err)
177 {
178   if (err)
179     {
180       const char *name = assuan_get_command_name (ctx);
181       if (!name)
182         name = "?";
183       if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
184         log_error ("command '%s' failed: %s\n", name,
185                    gpg_strerror (err));
186       else
187         log_error ("command '%s' failed: %s <%s>\n", name,
188                    gpg_strerror (err), gpg_strsource (err));
189     }
190   return err;
191 }
192
193
194 /* This is a wrapper around assuan_send_data which makes debugging the
195    output in verbose mode easier.  */
196 static gpg_error_t
197 data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size)
198 {
199   ctrl_t ctrl = assuan_get_pointer (ctx);
200   const char *buffer = buffer_arg;
201   gpg_error_t err;
202
203   /* If we do not want logging, enable it here.  */
204   if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
205     ctrl->server_local->inhibit_data_logging_now = 1;
206
207   if (opt.verbose && buffer && size)
208     {
209       /* Ease reading of output by sending a physical line at each LF.  */
210       const char *p;
211       size_t n, nbytes;
212
213       nbytes = size;
214       do
215         {
216           p = memchr (buffer, '\n', nbytes);
217           n = p ? (p - buffer) + 1 : nbytes;
218           err = assuan_send_data (ctx, buffer, n);
219           if (err)
220             {
221               gpg_err_set_errno (EIO);
222               goto leave;
223             }
224           buffer += n;
225           nbytes -= n;
226           if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
227             {
228               gpg_err_set_errno (EIO);
229               goto leave;
230             }
231         }
232       while (nbytes);
233     }
234   else
235     {
236       err = assuan_send_data (ctx, buffer, size);
237       if (err)
238         {
239           gpg_err_set_errno (EIO);  /* For use by data_line_cookie_write.  */
240           goto leave;
241         }
242     }
243
244  leave:
245   if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
246     {
247       ctrl->server_local->inhibit_data_logging_now = 0;
248       ctrl->server_local->inhibit_data_logging_count += size;
249     }
250
251   return err;
252 }
253
254
255 /* A write handler used by es_fopencookie to write assuan data
256    lines.  */
257 static gpgrt_ssize_t
258 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
259 {
260   assuan_context_t ctx = cookie;
261
262   if (data_line_write (ctx, buffer, size))
263     return -1;
264   return (gpgrt_ssize_t)size;
265 }
266
267
268 static int
269 data_line_cookie_close (void *cookie)
270 {
271   assuan_context_t ctx = cookie;
272
273   if (DBG_IPC)
274     {
275       ctrl_t ctrl = assuan_get_pointer (ctx);
276
277       if (ctrl && ctrl->server_local
278           && ctrl->server_local->inhibit_data_logging
279           && ctrl->server_local->inhibit_data_logging_count)
280         log_debug ("(%zu bytes sent via D lines not shown)\n",
281                    ctrl->server_local->inhibit_data_logging_count);
282     }
283   if (assuan_send_data (ctx, NULL, 0))
284     {
285       gpg_err_set_errno (EIO);
286       return -1;
287     }
288
289   return 0;
290 }
291
292
293 /* Copy the % and + escaped string S into the buffer D and replace the
294    escape sequences.  Note, that it is sufficient to allocate the
295    target string D as long as the source string S, i.e.: strlen(s)+1.
296    Note further that if S contains an escaped binary Nul the resulting
297    string D will contain the 0 as well as all other characters but it
298    will be impossible to know whether this is the original EOS or a
299    copied Nul. */
300 static void
301 strcpy_escaped_plus (char *d, const unsigned char *s)
302 {
303   while (*s)
304     {
305       if (*s == '%' && s[1] && s[2])
306         {
307           s++;
308           *d++ = xtoi_2 ( s);
309           s += 2;
310         }
311       else if (*s == '+')
312         *d++ = ' ', s++;
313       else
314         *d++ = *s++;
315     }
316   *d = 0;
317 }
318
319
320 /* This function returns true if a Tor server is running.  The status
321  * is cached for the current connection.  */
322 static int
323 is_tor_running (ctrl_t ctrl)
324 {
325   /* Check whether we can connect to the proxy.  */
326
327   if (!ctrl || !ctrl->server_local)
328     return 0; /* Ooops.  */
329
330   if (!ctrl->server_local->tor_state)
331     {
332       assuan_fd_t sock;
333
334       sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
335       if (sock == ASSUAN_INVALID_FD)
336         ctrl->server_local->tor_state = -1; /* Not running.  */
337       else
338         {
339           assuan_sock_close (sock);
340           ctrl->server_local->tor_state = 1; /* Running.  */
341         }
342     }
343   return (ctrl->server_local->tor_state > 0);
344 }
345
346
347 /* Return an error if the assuan context does not belong to the owner
348    of the process or to root.  On error FAILTEXT is set as Assuan
349    error string.  */
350 static gpg_error_t
351 check_owner_permission (assuan_context_t ctx, const char *failtext)
352 {
353 #ifdef HAVE_W32_SYSTEM
354   /* Under Windows the dirmngr is always run under the control of the
355      user.  */
356   (void)ctx;
357   (void)failtext;
358 #else
359   gpg_err_code_t ec;
360   assuan_peercred_t cred;
361
362   ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
363   if (!ec && cred->uid && cred->uid != getuid ())
364     ec = GPG_ERR_EPERM;
365   if (ec)
366     return set_error (ec, failtext);
367 #endif
368   return 0;
369 }
370
371
372
373 /* Common code for get_cert_local and get_issuer_cert_local. */
374 static ksba_cert_t
375 do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
376 {
377   unsigned char *value;
378   size_t valuelen;
379   int rc;
380   char *buf;
381   ksba_cert_t cert;
382
383   buf = name? strconcat (command, " ", name, NULL) : xtrystrdup (command);
384   if (!buf)
385     rc = gpg_error_from_syserror ();
386   else
387     {
388       rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
389                            &value, &valuelen, MAX_CERT_LENGTH);
390       xfree (buf);
391     }
392   if (rc)
393     {
394       log_error (_("assuan_inquire(%s) failed: %s\n"),
395                  command, gpg_strerror (rc));
396       return NULL;
397     }
398
399   if (!valuelen)
400     {
401       xfree (value);
402       return NULL;
403     }
404
405   rc = ksba_cert_new (&cert);
406   if (!rc)
407     {
408       rc = ksba_cert_init_from_mem (cert, value, valuelen);
409       if (rc)
410         {
411           ksba_cert_release (cert);
412           cert = NULL;
413         }
414     }
415   xfree (value);
416   return cert;
417 }
418
419
420
421 /* Ask back to return a certificate for NAME, given as a regular gpgsm
422  * certificate identifier (e.g. fingerprint or one of the other
423  * methods).  Alternatively, NULL may be used for NAME to return the
424  * current target certificate.  Either return the certificate in a
425  * KSBA object or NULL if it is not available.  */
426 ksba_cert_t
427 get_cert_local (ctrl_t ctrl, const char *name)
428 {
429   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
430     {
431       if (opt.debug)
432         log_debug ("get_cert_local called w/o context\n");
433       return NULL;
434     }
435   return do_get_cert_local (ctrl, name, "SENDCERT");
436
437 }
438
439
440 /* Ask back to return the issuing certificate for NAME, given as a
441  * regular gpgsm certificate identifier (e.g. fingerprint or one
442  * of the other methods).  Alternatively, NULL may be used for NAME to
443  * return the current target certificate. Either return the certificate
444  * in a KSBA object or NULL if it is not available.  */
445 ksba_cert_t
446 get_issuing_cert_local (ctrl_t ctrl, const char *name)
447 {
448   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
449     {
450       if (opt.debug)
451         log_debug ("get_issuing_cert_local called w/o context\n");
452       return NULL;
453     }
454   return do_get_cert_local (ctrl, name, "SENDISSUERCERT");
455 }
456
457
458 /* Ask back to return a certificate with subject NAME and a
459  * subjectKeyIdentifier of KEYID. */
460 ksba_cert_t
461 get_cert_local_ski (ctrl_t ctrl, const char *name, ksba_sexp_t keyid)
462 {
463   unsigned char *value;
464   size_t valuelen;
465   int rc;
466   char *buf;
467   ksba_cert_t cert;
468   char *hexkeyid;
469
470   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
471     {
472       if (opt.debug)
473         log_debug ("get_cert_local_ski called w/o context\n");
474       return NULL;
475     }
476   if (!name || !keyid)
477     {
478       log_debug ("get_cert_local_ski called with insufficient arguments\n");
479       return NULL;
480     }
481
482   hexkeyid = serial_hex (keyid);
483   if (!hexkeyid)
484     {
485       log_debug ("serial_hex() failed\n");
486       return NULL;
487     }
488
489   buf = strconcat ("SENDCERT_SKI ", hexkeyid, " /", name, NULL);
490   if (!buf)
491     {
492       log_error ("can't allocate enough memory: %s\n", strerror (errno));
493       xfree (hexkeyid);
494       return NULL;
495     }
496   xfree (hexkeyid);
497
498   rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
499                        &value, &valuelen, MAX_CERT_LENGTH);
500   xfree (buf);
501   if (rc)
502     {
503       log_error (_("assuan_inquire(%s) failed: %s\n"), "SENDCERT_SKI",
504                  gpg_strerror (rc));
505       return NULL;
506     }
507
508   if (!valuelen)
509     {
510       xfree (value);
511       return NULL;
512     }
513
514   rc = ksba_cert_new (&cert);
515   if (!rc)
516     {
517       rc = ksba_cert_init_from_mem (cert, value, valuelen);
518       if (rc)
519         {
520           ksba_cert_release (cert);
521           cert = NULL;
522         }
523     }
524   xfree (value);
525   return cert;
526 }
527
528
529 /* Ask the client via an inquiry to check the istrusted status of the
530    certificate specified by the hexified fingerprint HEXFPR.  Returns
531    0 if the certificate is trusted by the client or an error code.  */
532 gpg_error_t
533 get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr)
534 {
535   unsigned char *value;
536   size_t valuelen;
537   int rc;
538   char request[100];
539
540   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx
541       || !hexfpr)
542     return gpg_error (GPG_ERR_INV_ARG);
543
544   snprintf (request, sizeof request, "ISTRUSTED %s", hexfpr);
545   rc = assuan_inquire (ctrl->server_local->assuan_ctx, request,
546                        &value, &valuelen, 100);
547   if (rc)
548     {
549       log_error (_("assuan_inquire(%s) failed: %s\n"),
550                  request, gpg_strerror (rc));
551       return rc;
552     }
553   /* The expected data is: "1" or "1 cruft" (not a C-string).  */
554   if (valuelen && *value == '1' && (valuelen == 1 || spacep (value+1)))
555     rc = 0;
556   else
557     rc = gpg_error (GPG_ERR_NOT_TRUSTED);
558   xfree (value);
559   return rc;
560 }
561
562
563
564
565 /* Ask the client to return the certificate associated with the
566    current command. This is sometimes needed because the client usually
567    sends us just the cert ID, assuming that the request can be
568    satisfied from the cache, where the cert ID is used as key. */
569 static int
570 inquire_cert_and_load_crl (assuan_context_t ctx)
571 {
572   ctrl_t ctrl = assuan_get_pointer (ctx);
573   gpg_error_t err;
574   unsigned char *value = NULL;
575   size_t valuelen;
576   ksba_cert_t cert = NULL;
577
578   err = assuan_inquire( ctx, "SENDCERT", &value, &valuelen, 0);
579   if (err)
580     return err;
581
582 /*   { */
583 /*     FILE *fp = fopen ("foo.der", "r"); */
584 /*     value = xmalloc (2000); */
585 /*     valuelen = fread (value, 1, 2000, fp); */
586 /*     fclose (fp); */
587 /*   } */
588
589   if (!valuelen) /* No data returned; return a comprehensible error. */
590     return gpg_error (GPG_ERR_MISSING_CERT);
591
592   err = ksba_cert_new (&cert);
593   if (err)
594     goto leave;
595   err = ksba_cert_init_from_mem (cert, value, valuelen);
596   if(err)
597     goto leave;
598   xfree (value); value = NULL;
599
600   err = crl_cache_reload_crl (ctrl, cert);
601
602  leave:
603   ksba_cert_release (cert);
604   xfree (value);
605   return err;
606 }
607
608
609 /* Handle OPTION commands. */
610 static gpg_error_t
611 option_handler (assuan_context_t ctx, const char *key, const char *value)
612 {
613   ctrl_t ctrl = assuan_get_pointer (ctx);
614   gpg_error_t err = 0;
615
616   if (!strcmp (key, "force-crl-refresh"))
617     {
618       int i = *value? atoi (value) : 0;
619       ctrl->force_crl_refresh = i;
620     }
621   else if (!strcmp (key, "audit-events"))
622     {
623       int i = *value? atoi (value) : 0;
624       ctrl->audit_events = i;
625     }
626   else if (!strcmp (key, "http-proxy"))
627     {
628       xfree (ctrl->http_proxy);
629       if (!*value || !strcmp (value, "none"))
630         ctrl->http_proxy = NULL;
631       else if (!(ctrl->http_proxy = xtrystrdup (value)))
632         err = gpg_error_from_syserror ();
633     }
634   else if (!strcmp (key, "honor-keyserver-url-used"))
635     {
636       /* Return an error if we are running in Tor mode.  */
637       if (dirmngr_use_tor ())
638         err = gpg_error (GPG_ERR_FORBIDDEN);
639     }
640   else if (!strcmp (key, "http-crl"))
641     {
642       int i = *value? atoi (value) : 0;
643       ctrl->http_no_crl = !i;
644     }
645   else
646     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
647
648   return err;
649 }
650
651
652 \f
653 static const char hlp_dns_cert[] =
654   "DNS_CERT <subtype> <name>\n"
655   "DNS_CERT --pka <user_id>\n"
656   "DNS_CERT --dane <user_id>\n"
657   "\n"
658   "Return the CERT record for <name>.  <subtype> is one of\n"
659   "  *     Return the first record of any supported subtype\n"
660   "  PGP   Return the first record of subtype PGP (3)\n"
661   "  IPGP  Return the first record of subtype IPGP (6)\n"
662   "If the content of a certificate is available (PGP) it is returned\n"
663   "by data lines.  Fingerprints and URLs are returned via status lines.\n"
664   "In --pka mode the fingerprint and if available an URL is returned.\n"
665   "In --dane mode the key is returned from RR type 61";
666 static gpg_error_t
667 cmd_dns_cert (assuan_context_t ctx, char *line)
668 {
669   /* ctrl_t ctrl = assuan_get_pointer (ctx); */
670   gpg_error_t err = 0;
671   int pka_mode, dane_mode;
672   char *mbox = NULL;
673   char *namebuf = NULL;
674   char *encodedhash = NULL;
675   const char *name;
676   int certtype;
677   char *p;
678   void *key = NULL;
679   size_t keylen;
680   unsigned char *fpr = NULL;
681   size_t fprlen;
682   char *url = NULL;
683
684   pka_mode = has_option (line, "--pka");
685   dane_mode = has_option (line, "--dane");
686   line = skip_options (line);
687
688   if (pka_mode && dane_mode)
689     {
690       err = PARM_ERROR ("either --pka or --dane may be given");
691       goto leave;
692     }
693
694   if (pka_mode || dane_mode)
695     ; /* No need to parse here - we do this later.  */
696   else
697     {
698       p = strchr (line, ' ');
699       if (!p)
700         {
701           err = PARM_ERROR ("missing arguments");
702           goto leave;
703         }
704       *p++ = 0;
705       if (!strcmp (line, "*"))
706         certtype = DNS_CERTTYPE_ANY;
707       else if (!strcmp (line, "IPGP"))
708         certtype = DNS_CERTTYPE_IPGP;
709       else if (!strcmp (line, "PGP"))
710         certtype = DNS_CERTTYPE_PGP;
711       else
712         {
713           err = PARM_ERROR ("unknown subtype");
714           goto leave;
715         }
716       while (spacep (p))
717         p++;
718       line = p;
719       if (!*line)
720         {
721           err = PARM_ERROR ("name missing");
722           goto leave;
723         }
724     }
725
726   if (pka_mode || dane_mode)
727     {
728       char *domain;     /* Points to mbox.  */
729       char hashbuf[32]; /* For SHA-1 and SHA-256. */
730
731       /* We lowercase ascii characters but the DANE I-D does not allow
732          this.  FIXME: Check after the release of the RFC whether to
733          change this.  */
734       mbox = mailbox_from_userid (line);
735       if (!mbox || !(domain = strchr (mbox, '@')))
736         {
737           err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
738           goto leave;
739         }
740       *domain++ = 0;
741
742       if (pka_mode)
743         {
744           gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
745           encodedhash = zb32_encode (hashbuf, 8*20);
746           if (!encodedhash)
747             {
748               err = gpg_error_from_syserror ();
749               goto leave;
750             }
751           namebuf = strconcat (encodedhash, "._pka.", domain, NULL);
752           if (!namebuf)
753             {
754               err = gpg_error_from_syserror ();
755               goto leave;
756             }
757           name = namebuf;
758           certtype = DNS_CERTTYPE_IPGP;
759         }
760       else
761         {
762           /* Note: The hash is truncated to 28 bytes and we lowercase
763              the result only for aesthetic reasons.  */
764           gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
765           encodedhash = bin2hex (hashbuf, 28, NULL);
766           if (!encodedhash)
767             {
768               err = gpg_error_from_syserror ();
769               goto leave;
770             }
771           ascii_strlwr (encodedhash);
772           namebuf = strconcat (encodedhash, "._openpgpkey.", domain, NULL);
773           if (!namebuf)
774             {
775               err = gpg_error_from_syserror ();
776               goto leave;
777             }
778           name = namebuf;
779           certtype = DNS_CERTTYPE_RR61;
780         }
781     }
782   else
783     name = line;
784
785   err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url);
786   if (err)
787     goto leave;
788
789   if (key)
790     {
791       err = data_line_write (ctx, key, keylen);
792       if (err)
793         goto leave;
794     }
795
796   if (fpr)
797     {
798       char *tmpstr;
799
800       tmpstr = bin2hex (fpr, fprlen, NULL);
801       if (!tmpstr)
802         err = gpg_error_from_syserror ();
803       else
804         {
805           err = assuan_write_status (ctx, "FPR", tmpstr);
806           xfree (tmpstr);
807         }
808       if (err)
809         goto leave;
810     }
811
812   if (url)
813     {
814       err = assuan_write_status (ctx, "URL", url);
815       if (err)
816         goto leave;
817     }
818
819
820  leave:
821   xfree (key);
822   xfree (fpr);
823   xfree (url);
824   xfree (mbox);
825   xfree (namebuf);
826   xfree (encodedhash);
827   return leave_cmd (ctx, err);
828 }
829
830
831 \f
832 /* Core of cmd_wkd_get and task_check_wkd_support.  If CTX is NULL
833  * this function will not write anything to the assuan output.  */
834 static gpg_error_t
835 proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
836 {
837   gpg_error_t err = 0;
838   char *mbox = NULL;
839   char *domainbuf = NULL;
840   char *domain;     /* Points to mbox or domainbuf.  */
841   char *domain_orig;/* Points to mbox.  */
842   char sha1buf[20];
843   char *uri = NULL;
844   char *encodedhash = NULL;
845   int opt_submission_addr;
846   int opt_policy_flags;
847   int is_wkd_query;   /* True if this is a real WKD query.  */
848   int no_log = 0;
849   char portstr[20] = { 0 };
850
851   opt_submission_addr = has_option (line, "--submission-address");
852   opt_policy_flags = has_option (line, "--policy-flags");
853   if (has_option (line, "--quick"))
854     ctrl->timeout = opt.connect_quick_timeout;
855   line = skip_options (line);
856   is_wkd_query = !(opt_policy_flags || opt_submission_addr);
857
858   mbox = mailbox_from_userid (line);
859   if (!mbox || !(domain = strchr (mbox, '@')))
860     {
861       err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
862       goto leave;
863     }
864   *domain++ = 0;
865   domain_orig = domain;
866
867   /* First check whether we already know that the domain does not
868    * support WKD.  */
869   if (is_wkd_query)
870     {
871       if (domaininfo_is_wkd_not_supported (domain_orig))
872         {
873           err = gpg_error (GPG_ERR_NO_DATA);
874           goto leave;
875         }
876     }
877
878   /* Check for SRV records.  */
879   if (1)
880     {
881       struct srventry *srvs;
882       unsigned int srvscount;
883       size_t domainlen, targetlen;
884       int i;
885
886       err = get_dns_srv (domain, "openpgpkey", NULL, &srvs, &srvscount);
887       if (err)
888         goto leave;
889
890       /* Find the first target which also ends in DOMAIN or is equal
891        * to DOMAIN.  */
892       domainlen = strlen (domain);
893       for (i = 0; i < srvscount; i++)
894         {
895           if (DBG_DNS)
896             log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port);
897           targetlen = strlen (srvs[i].target);
898           if ((targetlen > domainlen + 1
899                && srvs[i].target[targetlen - domainlen - 1] == '.'
900                && !ascii_strcasecmp (srvs[i].target + targetlen - domainlen,
901                                      domain))
902               || (targetlen == domainlen
903                   && !ascii_strcasecmp (srvs[i].target, domain)))
904             {
905               /* found.  */
906               domainbuf = xtrystrdup (srvs[i].target);
907               if (!domainbuf)
908                 {
909                   err = gpg_error_from_syserror ();
910                   xfree (srvs);
911                   goto leave;
912                 }
913               domain = domainbuf;
914               if (srvs[i].port)
915                 snprintf (portstr, sizeof portstr, ":%hu", srvs[i].port);
916               break;
917             }
918         }
919       xfree (srvs);
920     }
921
922   gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
923   encodedhash = zb32_encode (sha1buf, 8*20);
924   if (!encodedhash)
925     {
926       err = gpg_error_from_syserror ();
927       goto leave;
928     }
929
930   if (opt_submission_addr)
931     {
932       uri = strconcat ("https://",
933                        domain,
934                        portstr,
935                        "/.well-known/openpgpkey/submission-address",
936                        NULL);
937     }
938   else if (opt_policy_flags)
939     {
940       uri = strconcat ("https://",
941                        domain,
942                        portstr,
943                        "/.well-known/openpgpkey/policy",
944                        NULL);
945     }
946   else
947     {
948       uri = strconcat ("https://",
949                        domain,
950                        portstr,
951                        "/.well-known/openpgpkey/hu/",
952                        encodedhash,
953                        NULL);
954       no_log = 1;
955       if (uri)
956         {
957           err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
958                                        domain, portstr);
959           if (err)
960             goto leave;
961         }
962     }
963   if (!uri)
964     {
965       err = gpg_error_from_syserror ();
966       goto leave;
967     }
968
969   /* Setup an output stream and perform the get.  */
970   {
971     estream_t outfp;
972
973     outfp = ctx? es_fopencookie (ctx, "w", data_line_cookie_functions) : NULL;
974     if (!outfp && ctx)
975       err = set_error (GPG_ERR_ASS_GENERAL,
976                        "error setting up a data stream");
977     else
978       {
979         if (ctrl->server_local)
980           {
981             if (no_log)
982               ctrl->server_local->inhibit_data_logging = 1;
983             ctrl->server_local->inhibit_data_logging_now = 0;
984             ctrl->server_local->inhibit_data_logging_count = 0;
985           }
986         err = ks_action_fetch (ctrl, uri, outfp);
987         es_fclose (outfp);
988         if (ctrl->server_local)
989           ctrl->server_local->inhibit_data_logging = 0;
990
991         /* Register the result under the domain name of MBOX. */
992         switch (gpg_err_code (err))
993           {
994           case 0:
995             domaininfo_set_wkd_supported (domain_orig);
996             break;
997
998           case GPG_ERR_NO_NAME:
999             /* There is no such domain.  */
1000             domaininfo_set_no_name (domain_orig);
1001             break;
1002
1003           case GPG_ERR_NO_DATA:
1004             if (is_wkd_query && ctrl->server_local)
1005               {
1006                 /* Mark that and schedule a check.  */
1007                 domaininfo_set_wkd_not_found (domain_orig);
1008                 workqueue_add_task (task_check_wkd_support, domain_orig,
1009                                     ctrl->server_local->session_id, 1);
1010               }
1011             else if (opt_policy_flags) /* No policy file - no support.  */
1012               domaininfo_set_wkd_not_supported (domain_orig);
1013             break;
1014
1015           default:
1016             /* Don't register other errors.  */
1017             break;
1018           }
1019       }
1020   }
1021
1022  leave:
1023   xfree (uri);
1024   xfree (encodedhash);
1025   xfree (mbox);
1026   xfree (domainbuf);
1027   return err;
1028 }
1029
1030
1031 static const char hlp_wkd_get[] =
1032   "WKD_GET [--submission-address|--policy-flags] <user_id>\n"
1033   "\n"
1034   "Return the key or other info for <user_id>\n"
1035   "from the Web Key Directory.";
1036 static gpg_error_t
1037 cmd_wkd_get (assuan_context_t ctx, char *line)
1038 {
1039   ctrl_t ctrl = assuan_get_pointer (ctx);
1040   gpg_error_t err;
1041
1042   err = proc_wkd_get (ctrl, ctx, line);
1043
1044   return leave_cmd (ctx, err);
1045 }
1046
1047
1048 /* A task to check whether DOMAIN supports WKD.  This is done by
1049  * checking whether the policy flags file can be read.  */
1050 static const char *
1051 task_check_wkd_support (ctrl_t ctrl, const char *domain)
1052 {
1053   char *string;
1054
1055   if (!ctrl || !domain)
1056     return "check_wkd_support";
1057
1058   string = strconcat ("--policy-flags foo@", domain, NULL);
1059   if (!string)
1060     log_error ("%s: %s\n", __func__, gpg_strerror (gpg_error_from_syserror ()));
1061   else
1062     {
1063       proc_wkd_get (ctrl, NULL, string);
1064       xfree (string);
1065     }
1066
1067   return NULL;
1068 }
1069
1070
1071 \f
1072 static const char hlp_ldapserver[] =
1073   "LDAPSERVER <data>\n"
1074   "\n"
1075   "Add a new LDAP server to the list of configured LDAP servers.\n"
1076   "DATA is in the same format as expected in the configure file.";
1077 static gpg_error_t
1078 cmd_ldapserver (assuan_context_t ctx, char *line)
1079 {
1080 #if USE_LDAP
1081   ctrl_t ctrl = assuan_get_pointer (ctx);
1082   ldap_server_t server;
1083   ldap_server_t *last_next_p;
1084
1085   while (spacep (line))
1086     line++;
1087   if (*line == '\0')
1088     return leave_cmd (ctx, PARM_ERROR (_("ldapserver missing")));
1089
1090   server = ldapserver_parse_one (line, "", 0);
1091   if (! server)
1092     return leave_cmd (ctx, gpg_error (GPG_ERR_INV_ARG));
1093
1094   last_next_p = &ctrl->server_local->ldapservers;
1095   while (*last_next_p)
1096     last_next_p = &(*last_next_p)->next;
1097   *last_next_p = server;
1098   return leave_cmd (ctx, 0);
1099 #else
1100   (void)line;
1101   return leave_cmd (ctx, gpg_error (GPG_ERR_NOT_IMPLEMENTED));
1102 #endif
1103 }
1104
1105
1106 static const char hlp_isvalid[] =
1107   "ISVALID [--only-ocsp] [--force-default-responder]"
1108   " <certificate_id>|<certificate_fpr>\n"
1109   "\n"
1110   "This command checks whether the certificate identified by the\n"
1111   "certificate_id is valid.  This is done by consulting CRLs or\n"
1112   "whatever has been configured.  Note, that the returned error codes\n"
1113   "are from gpg-error.h.  The command may callback using the inquire\n"
1114   "function.  See the manual for details.\n"
1115   "\n"
1116   "The CERTIFICATE_ID is a hex encoded string consisting of two parts,\n"
1117   "delimited by a single dot.  The first part is the SHA-1 hash of the\n"
1118   "issuer name and the second part the serial number.\n"
1119   "\n"
1120   "Alternatively the certificate's fingerprint may be given in which\n"
1121   "case an OCSP request is done before consulting the CRL.\n"
1122   "\n"
1123   "If the option --only-ocsp is given, no fallback to a CRL check will\n"
1124   "be used.\n"
1125   "\n"
1126   "If the option --force-default-responder is given, only the default\n"
1127   "OCSP responder will be used and any other methods of obtaining an\n"
1128   "OCSP responder URL won't be used.";
1129 static gpg_error_t
1130 cmd_isvalid (assuan_context_t ctx, char *line)
1131 {
1132   ctrl_t ctrl = assuan_get_pointer (ctx);
1133   char *issuerhash, *serialno;
1134   gpg_error_t err;
1135   int did_inquire = 0;
1136   int ocsp_mode = 0;
1137   int only_ocsp;
1138   int force_default_responder;
1139
1140   only_ocsp = has_option (line, "--only-ocsp");
1141   force_default_responder = has_option (line, "--force-default-responder");
1142   line = skip_options (line);
1143
1144   issuerhash = xstrdup (line); /* We need to work on a copy of the
1145                                   line because that same Assuan
1146                                   context may be used for an inquiry.
1147                                   That is because Assuan reuses its
1148                                   line buffer.
1149                                    */
1150
1151   serialno = strchr (issuerhash, '.');
1152   if (serialno)
1153     *serialno++ = 0;
1154   else
1155     {
1156       char *endp = strchr (issuerhash, ' ');
1157       if (endp)
1158         *endp = 0;
1159       if (strlen (issuerhash) != 40)
1160         {
1161           xfree (issuerhash);
1162           return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID")));
1163         }
1164       ocsp_mode = 1;
1165     }
1166
1167
1168  again:
1169   if (ocsp_mode)
1170     {
1171       /* Note, that we ignore the given issuer hash and instead rely
1172          on the current certificate semantics used with this
1173          command. */
1174       if (!opt.allow_ocsp)
1175         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1176       else
1177         err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
1178       /* Fixme: If we got no ocsp response and --only-ocsp is not used
1179          we should fall back to CRL mode.  Thus we need to clear
1180          OCSP_MODE, get the issuerhash and the serialno from the
1181          current certificate and jump to again. */
1182     }
1183   else if (only_ocsp)
1184     err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1185   else
1186     {
1187       switch (crl_cache_isvalid (ctrl,
1188                                  issuerhash, serialno,
1189                                  ctrl->force_crl_refresh))
1190         {
1191         case CRL_CACHE_VALID:
1192           err = 0;
1193           break;
1194         case CRL_CACHE_INVALID:
1195           err = gpg_error (GPG_ERR_CERT_REVOKED);
1196           break;
1197         case CRL_CACHE_DONTKNOW:
1198           if (did_inquire)
1199             err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1200           else if (!(err = inquire_cert_and_load_crl (ctx)))
1201             {
1202               did_inquire = 1;
1203               goto again;
1204             }
1205           break;
1206         case CRL_CACHE_CANTUSE:
1207           err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1208           break;
1209         default:
1210           log_fatal ("crl_cache_isvalid returned invalid code\n");
1211         }
1212     }
1213
1214   xfree (issuerhash);
1215   return leave_cmd (ctx, err);
1216 }
1217
1218
1219 /* If the line contains a SHA-1 fingerprint as the first argument,
1220    return the FPR vuffer on success.  The function checks that the
1221    fingerprint consists of valid characters and prints and error
1222    message if it does not and returns NULL.  Fingerprints are
1223    considered optional and thus no explicit error is returned. NULL is
1224    also returned if there is no fingerprint at all available.
1225    FPR must be a caller provided buffer of at least 20 bytes.
1226
1227    Note that colons within the fingerprint are allowed to separate 2
1228    hex digits; this allows for easier cutting and pasting using the
1229    usual fingerprint rendering.
1230 */
1231 static unsigned char *
1232 get_fingerprint_from_line (const char *line, unsigned char *fpr)
1233 {
1234   const char *s;
1235   int i;
1236
1237   for (s=line, i=0; *s && *s != ' '; s++ )
1238     {
1239       if ( hexdigitp (s) && hexdigitp (s+1) )
1240         {
1241           if ( i >= 20 )
1242             return NULL;  /* Fingerprint too long.  */
1243           fpr[i++] = xtoi_2 (s);
1244           s++;
1245         }
1246       else if ( *s != ':' )
1247         return NULL; /* Invalid.  */
1248     }
1249   if ( i != 20 )
1250     return NULL; /* Fingerprint to short.  */
1251   return fpr;
1252 }
1253
1254
1255
1256 static const char hlp_checkcrl[] =
1257   "CHECKCRL [<fingerprint>]\n"
1258   "\n"
1259   "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1260   "entire X.509 certificate blob) is valid or not by consulting the\n"
1261   "CRL responsible for this certificate.  If the fingerprint has not\n"
1262   "been given or the certificate is not known, the function \n"
1263   "inquires the certificate using an\n"
1264   "\n"
1265   "  INQUIRE TARGETCERT\n"
1266   "\n"
1267   "and the caller is expected to return the certificate for the\n"
1268   "request (which should match FINGERPRINT) as a binary blob.\n"
1269   "Processing then takes place without further interaction; in\n"
1270   "particular dirmngr tries to locate other required certificate by\n"
1271   "its own mechanism which includes a local certificate store as well\n"
1272   "as a list of trusted root certificates.\n"
1273   "\n"
1274   "The return value is the usual gpg-error code or 0 for ducesss;\n"
1275   "i.e. the certificate validity has been confirmed by a valid CRL.";
1276 static gpg_error_t
1277 cmd_checkcrl (assuan_context_t ctx, char *line)
1278 {
1279   ctrl_t ctrl = assuan_get_pointer (ctx);
1280   gpg_error_t err;
1281   unsigned char fprbuffer[20], *fpr;
1282   ksba_cert_t cert;
1283
1284   fpr = get_fingerprint_from_line (line, fprbuffer);
1285   cert = fpr? get_cert_byfpr (fpr) : NULL;
1286
1287   if (!cert)
1288     {
1289       /* We do not have this certificate yet or the fingerprint has
1290          not been given.  Inquire it from the client.  */
1291       unsigned char *value = NULL;
1292       size_t valuelen;
1293
1294       err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1295                            &value, &valuelen, MAX_CERT_LENGTH);
1296       if (err)
1297         {
1298           log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1299           goto leave;
1300         }
1301
1302       if (!valuelen) /* No data returned; return a comprehensible error. */
1303         err = gpg_error (GPG_ERR_MISSING_CERT);
1304       else
1305         {
1306           err = ksba_cert_new (&cert);
1307           if (!err)
1308             err = ksba_cert_init_from_mem (cert, value, valuelen);
1309         }
1310       xfree (value);
1311       if(err)
1312         goto leave;
1313     }
1314
1315   assert (cert);
1316
1317   err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
1318   if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
1319     {
1320       err = crl_cache_reload_crl (ctrl, cert);
1321       if (!err)
1322         err = crl_cache_cert_isvalid (ctrl, cert, 0);
1323     }
1324
1325  leave:
1326   ksba_cert_release (cert);
1327   return leave_cmd (ctx, err);
1328 }
1329
1330
1331 static const char hlp_checkocsp[] =
1332   "CHECKOCSP [--force-default-responder] [<fingerprint>]\n"
1333   "\n"
1334   "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1335   "entire X.509 certificate blob) is valid or not by asking an OCSP\n"
1336   "responder responsible for this certificate.  The optional\n"
1337   "fingerprint may be used for a quick check in case an OCSP check has\n"
1338   "been done for this certificate recently (we always cache OCSP\n"
1339   "responses for a couple of minutes). If the fingerprint has not been\n"
1340   "given or there is no cached result, the function inquires the\n"
1341   "certificate using an\n"
1342   "\n"
1343   "   INQUIRE TARGETCERT\n"
1344   "\n"
1345   "and the caller is expected to return the certificate for the\n"
1346   "request (which should match FINGERPRINT) as a binary blob.\n"
1347   "Processing then takes place without further interaction; in\n"
1348   "particular dirmngr tries to locate other required certificates by\n"
1349   "its own mechanism which includes a local certificate store as well\n"
1350   "as a list of trusted root certificates.\n"
1351   "\n"
1352   "If the option --force-default-responder is given, only the default\n"
1353   "OCSP responder will be used and any other methods of obtaining an\n"
1354   "OCSP responder URL won't be used.\n"
1355   "\n"
1356   "The return value is the usual gpg-error code or 0 for ducesss;\n"
1357   "i.e. the certificate validity has been confirmed by a valid CRL.";
1358 static gpg_error_t
1359 cmd_checkocsp (assuan_context_t ctx, char *line)
1360 {
1361   ctrl_t ctrl = assuan_get_pointer (ctx);
1362   gpg_error_t err;
1363   unsigned char fprbuffer[20], *fpr;
1364   ksba_cert_t cert;
1365   int force_default_responder;
1366
1367   force_default_responder = has_option (line, "--force-default-responder");
1368   line = skip_options (line);
1369
1370   fpr = get_fingerprint_from_line (line, fprbuffer);
1371   cert = fpr? get_cert_byfpr (fpr) : NULL;
1372
1373   if (!cert)
1374     {
1375       /* We do not have this certificate yet or the fingerprint has
1376          not been given.  Inquire it from the client.  */
1377       unsigned char *value = NULL;
1378       size_t valuelen;
1379
1380       err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1381                            &value, &valuelen, MAX_CERT_LENGTH);
1382       if (err)
1383         {
1384           log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1385           goto leave;
1386         }
1387
1388       if (!valuelen) /* No data returned; return a comprehensible error. */
1389         err = gpg_error (GPG_ERR_MISSING_CERT);
1390       else
1391         {
1392           err = ksba_cert_new (&cert);
1393           if (!err)
1394             err = ksba_cert_init_from_mem (cert, value, valuelen);
1395         }
1396       xfree (value);
1397       if(err)
1398         goto leave;
1399     }
1400
1401   assert (cert);
1402
1403   if (!opt.allow_ocsp)
1404     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1405   else
1406     err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder);
1407
1408  leave:
1409   ksba_cert_release (cert);
1410   return leave_cmd (ctx, err);
1411 }
1412
1413
1414
1415 static int
1416 lookup_cert_by_url (assuan_context_t ctx, const char *url)
1417 {
1418   ctrl_t ctrl = assuan_get_pointer (ctx);
1419   gpg_error_t err = 0;
1420   unsigned char *value = NULL;
1421   size_t valuelen;
1422
1423   /* Fetch single certificate given it's URL.  */
1424   err = fetch_cert_by_url (ctrl, url, &value, &valuelen);
1425   if (err)
1426     {
1427       log_error (_("fetch_cert_by_url failed: %s\n"), gpg_strerror (err));
1428       goto leave;
1429     }
1430
1431   /* Send the data, flush the buffer and then send an END. */
1432   err = assuan_send_data (ctx, value, valuelen);
1433   if (!err)
1434     err = assuan_send_data (ctx, NULL, 0);
1435   if (!err)
1436     err = assuan_write_line (ctx, "END");
1437   if (err)
1438     {
1439       log_error (_("error sending data: %s\n"), gpg_strerror (err));
1440       goto leave;
1441     }
1442
1443  leave:
1444
1445   return err;
1446 }
1447
1448
1449 /* Send the certificate, flush the buffer and then send an END. */
1450 static gpg_error_t
1451 return_one_cert (void *opaque, ksba_cert_t cert)
1452 {
1453   assuan_context_t ctx = opaque;
1454   gpg_error_t err;
1455   const unsigned char *der;
1456   size_t derlen;
1457
1458   der = ksba_cert_get_image (cert, &derlen);
1459   if (!der)
1460     err = gpg_error (GPG_ERR_INV_CERT_OBJ);
1461   else
1462     {
1463       err = assuan_send_data (ctx, der, derlen);
1464       if (!err)
1465         err = assuan_send_data (ctx, NULL, 0);
1466       if (!err)
1467         err = assuan_write_line (ctx, "END");
1468     }
1469   if (err)
1470     log_error (_("error sending data: %s\n"), gpg_strerror (err));
1471   return err;
1472 }
1473
1474
1475 /* Lookup certificates from the internal cache or using the ldap
1476    servers. */
1477 static int
1478 lookup_cert_by_pattern (assuan_context_t ctx, char *line,
1479                         int single, int cache_only)
1480 {
1481   gpg_error_t err = 0;
1482   char *p;
1483   strlist_t sl, list = NULL;
1484   int truncated = 0, truncation_forced = 0;
1485   int count = 0;
1486   int local_count = 0;
1487 #if USE_LDAP
1488   ctrl_t ctrl = assuan_get_pointer (ctx);
1489   unsigned char *value = NULL;
1490   size_t valuelen;
1491   struct ldapserver_iter ldapserver_iter;
1492   cert_fetch_context_t fetch_context;
1493 #endif /*USE_LDAP*/
1494   int any_no_data = 0;
1495
1496   /* Break the line down into an STRLIST */
1497   for (p=line; *p; line = p)
1498     {
1499       while (*p && *p != ' ')
1500         p++;
1501       if (*p)
1502         *p++ = 0;
1503
1504       if (*line)
1505         {
1506           sl = xtrymalloc (sizeof *sl + strlen (line));
1507           if (!sl)
1508             {
1509               err = gpg_error_from_errno (errno);
1510               goto leave;
1511             }
1512           memset (sl, 0, sizeof *sl);
1513           strcpy_escaped_plus (sl->d, line);
1514           sl->next = list;
1515           list = sl;
1516         }
1517     }
1518
1519   /* First look through the internal cache.  The certificates returned
1520      here are not counted towards the truncation limit.  */
1521   if (single && !cache_only)
1522     ; /* Do not read from the local cache in this case.  */
1523   else
1524     {
1525       for (sl=list; sl; sl = sl->next)
1526         {
1527           err = get_certs_bypattern (sl->d, return_one_cert, ctx);
1528           if (!err)
1529             local_count++;
1530           if (!err && single)
1531             goto ready;
1532
1533           if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1534             {
1535               err = 0;
1536               if (cache_only)
1537                 any_no_data = 1;
1538             }
1539           else if (gpg_err_code (err) == GPG_ERR_INV_NAME && !cache_only)
1540             {
1541               /* No real fault because the internal pattern lookup
1542                  can't yet cope with all types of pattern.  */
1543               err = 0;
1544             }
1545           if (err)
1546             goto ready;
1547         }
1548     }
1549
1550   /* Loop over all configured servers unless we want only the
1551      certificates from the cache.  */
1552 #if USE_LDAP
1553   for (ldapserver_iter_begin (&ldapserver_iter, ctrl);
1554        !cache_only && !ldapserver_iter_end_p (&ldapserver_iter)
1555          && ldapserver_iter.server->host && !truncation_forced;
1556        ldapserver_iter_next (&ldapserver_iter))
1557     {
1558       ldap_server_t ldapserver = ldapserver_iter.server;
1559
1560       if (DBG_LOOKUP)
1561         log_debug ("cmd_lookup: trying %s:%d base=%s\n",
1562                    ldapserver->host, ldapserver->port,
1563                    ldapserver->base?ldapserver->base : "[default]");
1564
1565       /* Fetch certificates matching pattern */
1566       err = start_cert_fetch (ctrl, &fetch_context, list, ldapserver);
1567       if ( gpg_err_code (err) == GPG_ERR_NO_DATA )
1568         {
1569           if (DBG_LOOKUP)
1570             log_debug ("cmd_lookup: no data\n");
1571           err = 0;
1572           any_no_data = 1;
1573           continue;
1574         }
1575       if (err)
1576         {
1577           log_error (_("start_cert_fetch failed: %s\n"), gpg_strerror (err));
1578           goto leave;
1579         }
1580
1581       /* Fetch the certificates for this query. */
1582       while (!truncation_forced)
1583         {
1584           xfree (value); value = NULL;
1585           err = fetch_next_cert (fetch_context, &value, &valuelen);
1586           if (gpg_err_code (err) == GPG_ERR_NO_DATA )
1587             {
1588               err = 0;
1589               any_no_data = 1;
1590               break; /* Ready. */
1591             }
1592           if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
1593             {
1594               truncated = 1;
1595               err = 0;
1596               break;  /* Ready.  */
1597             }
1598           if (gpg_err_code (err) == GPG_ERR_EOF)
1599             {
1600               err = 0;
1601               break; /* Ready. */
1602             }
1603           if (!err && !value)
1604             {
1605               err = gpg_error (GPG_ERR_BUG);
1606               goto leave;
1607             }
1608           if (err)
1609             {
1610               log_error (_("fetch_next_cert failed: %s\n"),
1611                          gpg_strerror (err));
1612               end_cert_fetch (fetch_context);
1613               goto leave;
1614             }
1615
1616           if (DBG_LOOKUP)
1617             log_debug ("cmd_lookup: returning one cert%s\n",
1618                        truncated? " (truncated)":"");
1619
1620           /* Send the data, flush the buffer and then send an END line
1621              as a certificate delimiter. */
1622           err = assuan_send_data (ctx, value, valuelen);
1623           if (!err)
1624             err = assuan_send_data (ctx, NULL, 0);
1625           if (!err)
1626             err = assuan_write_line (ctx, "END");
1627           if (err)
1628             {
1629               log_error (_("error sending data: %s\n"), gpg_strerror (err));
1630               end_cert_fetch (fetch_context);
1631               goto leave;
1632             }
1633
1634           if (++count >= opt.max_replies )
1635             {
1636               truncation_forced = 1;
1637               log_info (_("max_replies %d exceeded\n"), opt.max_replies );
1638             }
1639           if (single)
1640             break;
1641         }
1642
1643       end_cert_fetch (fetch_context);
1644     }
1645 #endif /*USE_LDAP*/
1646
1647  ready:
1648   if (truncated || truncation_forced)
1649     {
1650       char str[50];
1651
1652       sprintf (str, "%d", count);
1653       assuan_write_status (ctx, "TRUNCATED", str);
1654     }
1655
1656   if (!err && !count && !local_count && any_no_data)
1657     err = gpg_error (GPG_ERR_NO_DATA);
1658
1659  leave:
1660   free_strlist (list);
1661   return err;
1662 }
1663
1664
1665 static const char hlp_lookup[] =
1666   "LOOKUP [--url] [--single] [--cache-only] <pattern>\n"
1667   "\n"
1668   "Lookup certificates matching PATTERN. With --url the pattern is\n"
1669   "expected to be one URL.\n"
1670   "\n"
1671   "If --url is not given:  To allow for multiple patterns (which are ORed)\n"
1672   "quoting is required: Spaces are translated to \"+\" or \"%20\";\n"
1673   "obviously this requires that the usual escape quoting rules are applied.\n"
1674   "\n"
1675   "If --url is given no special escaping is required because URLs are\n"
1676   "already escaped this way.\n"
1677   "\n"
1678   "If --single is given the first and only the first match will be\n"
1679   "returned.  If --cache-only is _not_ given, no local query will be\n"
1680   "done.\n"
1681   "\n"
1682   "If --cache-only is given no external lookup is done so that only\n"
1683   "certificates from the cache may get returned.";
1684 static gpg_error_t
1685 cmd_lookup (assuan_context_t ctx, char *line)
1686 {
1687   gpg_error_t err;
1688   int lookup_url, single, cache_only;
1689
1690   lookup_url = has_leading_option (line, "--url");
1691   single = has_leading_option (line, "--single");
1692   cache_only = has_leading_option (line, "--cache-only");
1693   line = skip_options (line);
1694
1695   if (lookup_url && cache_only)
1696     err = gpg_error (GPG_ERR_NOT_FOUND);
1697   else if (lookup_url && single)
1698     err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1699   else if (lookup_url)
1700     err = lookup_cert_by_url (ctx, line);
1701   else
1702     err = lookup_cert_by_pattern (ctx, line, single, cache_only);
1703
1704   return leave_cmd (ctx, err);
1705 }
1706
1707
1708 static const char hlp_loadcrl[] =
1709   "LOADCRL [--url] <filename|url>\n"
1710   "\n"
1711   "Load the CRL in the file with name FILENAME into our cache.  Note\n"
1712   "that FILENAME should be given with an absolute path because\n"
1713   "Dirmngrs cwd is not known.  With --url the CRL is directly loaded\n"
1714   "from the given URL.\n"
1715   "\n"
1716   "This command is usually used by gpgsm using the invocation \"gpgsm\n"
1717   "--call-dirmngr loadcrl <filename>\".  A direct invocation of Dirmngr\n"
1718   "is not useful because gpgsm might need to callback gpgsm to ask for\n"
1719   "the CA's certificate.";
1720 static gpg_error_t
1721 cmd_loadcrl (assuan_context_t ctx, char *line)
1722 {
1723   ctrl_t ctrl = assuan_get_pointer (ctx);
1724   gpg_error_t err = 0;
1725   int use_url = has_leading_option (line, "--url");
1726
1727   line = skip_options (line);
1728
1729   if (use_url)
1730     {
1731       ksba_reader_t reader;
1732
1733       err = crl_fetch (ctrl, line, &reader);
1734       if (err)
1735         log_error (_("fetching CRL from '%s' failed: %s\n"),
1736                    line, gpg_strerror (err));
1737       else
1738         {
1739           err = crl_cache_insert (ctrl, line, reader);
1740           if (err)
1741             log_error (_("processing CRL from '%s' failed: %s\n"),
1742                        line, gpg_strerror (err));
1743           crl_close_reader (reader);
1744         }
1745     }
1746   else
1747     {
1748       char *buf;
1749
1750       buf = xtrymalloc (strlen (line)+1);
1751       if (!buf)
1752         err = gpg_error_from_syserror ();
1753       else
1754         {
1755           strcpy_escaped_plus (buf, line);
1756           err = crl_cache_load (ctrl, buf);
1757           xfree (buf);
1758         }
1759     }
1760
1761   return leave_cmd (ctx, err);
1762 }
1763
1764
1765 static const char hlp_listcrls[] =
1766   "LISTCRLS\n"
1767   "\n"
1768   "List the content of all CRLs in a readable format.  This command is\n"
1769   "usually used by gpgsm using the invocation \"gpgsm --call-dirmngr\n"
1770   "listcrls\".  It may also be used directly using \"dirmngr\n"
1771   "--list-crls\".";
1772 static gpg_error_t
1773 cmd_listcrls (assuan_context_t ctx, char *line)
1774 {
1775   gpg_error_t err;
1776   estream_t fp;
1777
1778   (void)line;
1779
1780   fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
1781   if (!fp)
1782     err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
1783   else
1784     {
1785       err = crl_cache_list (fp);
1786       es_fclose (fp);
1787     }
1788   return leave_cmd (ctx, err);
1789 }
1790
1791
1792 static const char hlp_cachecert[] =
1793   "CACHECERT\n"
1794   "\n"
1795   "Put a certificate into the internal cache.  This command might be\n"
1796   "useful if a client knows in advance certificates required for a\n"
1797   "test and wants to make sure they get added to the internal cache.\n"
1798   "It is also helpful for debugging.  To get the actual certificate,\n"
1799   "this command immediately inquires it using\n"
1800   "\n"
1801   "  INQUIRE TARGETCERT\n"
1802   "\n"
1803   "and the caller is expected to return the certificate for the\n"
1804   "request as a binary blob.";
1805 static gpg_error_t
1806 cmd_cachecert (assuan_context_t ctx, char *line)
1807 {
1808   ctrl_t ctrl = assuan_get_pointer (ctx);
1809   gpg_error_t err;
1810   ksba_cert_t cert = NULL;
1811   unsigned char *value = NULL;
1812   size_t valuelen;
1813
1814   (void)line;
1815
1816   err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1817                        &value, &valuelen, MAX_CERT_LENGTH);
1818   if (err)
1819     {
1820       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1821       goto leave;
1822     }
1823
1824   if (!valuelen) /* No data returned; return a comprehensible error. */
1825     err = gpg_error (GPG_ERR_MISSING_CERT);
1826   else
1827     {
1828       err = ksba_cert_new (&cert);
1829       if (!err)
1830         err = ksba_cert_init_from_mem (cert, value, valuelen);
1831     }
1832   xfree (value);
1833   if(err)
1834     goto leave;
1835
1836   err = cache_cert (cert);
1837
1838  leave:
1839   ksba_cert_release (cert);
1840   return leave_cmd (ctx, err);
1841 }
1842
1843
1844 static const char hlp_validate[] =
1845   "VALIDATE [--systrust] [--tls] [--no-crl]\n"
1846   "\n"
1847   "Validate a certificate using the certificate validation function\n"
1848   "used internally by dirmngr.  This command is only useful for\n"
1849   "debugging.  To get the actual certificate, this command immediately\n"
1850   "inquires it using\n"
1851   "\n"
1852   "  INQUIRE TARGETCERT\n"
1853   "\n"
1854   "and the caller is expected to return the certificate for the\n"
1855   "request as a binary blob.  The option --tls modifies this by asking\n"
1856   "for list of certificates with\n"
1857   "\n"
1858   "  INQUIRE CERTLIST\n"
1859   "\n"
1860   "Here the first certificate is the target certificate, the remaining\n"
1861   "certificates are suggested intermediary certificates.  All certifciates\n"
1862   "need to be PEM encoded.\n"
1863   "\n"
1864   "The option --systrust changes the behaviour to include the system\n"
1865   "provided root certificates as trust anchors.  The option --no-crl\n"
1866   "skips CRL checks";
1867 static gpg_error_t
1868 cmd_validate (assuan_context_t ctx, char *line)
1869 {
1870   ctrl_t ctrl = assuan_get_pointer (ctx);
1871   gpg_error_t err;
1872   ksba_cert_t cert = NULL;
1873   certlist_t certlist = NULL;
1874   unsigned char *value = NULL;
1875   size_t valuelen;
1876   int systrust_mode, tls_mode, no_crl;
1877
1878   systrust_mode = has_option (line, "--systrust");
1879   tls_mode = has_option (line, "--tls");
1880   no_crl = has_option (line, "--no-crl");
1881   line = skip_options (line);
1882
1883   if (tls_mode)
1884     err = assuan_inquire (ctrl->server_local->assuan_ctx, "CERTLIST",
1885                           &value, &valuelen, MAX_CERTLIST_LENGTH);
1886   else
1887     err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1888                           &value, &valuelen, MAX_CERT_LENGTH);
1889   if (err)
1890     {
1891       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1892       goto leave;
1893     }
1894
1895   if (!valuelen) /* No data returned; return a comprehensible error. */
1896     err = gpg_error (GPG_ERR_MISSING_CERT);
1897   else if (tls_mode)
1898     {
1899       estream_t fp;
1900
1901       fp = es_fopenmem_init (0, "rb", value, valuelen);
1902       if (!fp)
1903         err = gpg_error_from_syserror ();
1904       else
1905         {
1906           err = read_certlist_from_stream (&certlist, fp);
1907           es_fclose (fp);
1908           if (!err && !certlist)
1909             err = gpg_error (GPG_ERR_MISSING_CERT);
1910           if (!err)
1911             {
1912               /* Extraxt the first certificate from the list.  */
1913               cert = certlist->cert;
1914               ksba_cert_ref (cert);
1915             }
1916         }
1917     }
1918   else
1919     {
1920       err = ksba_cert_new (&cert);
1921       if (!err)
1922         err = ksba_cert_init_from_mem (cert, value, valuelen);
1923     }
1924   xfree (value);
1925   if(err)
1926     goto leave;
1927
1928   if (!tls_mode)
1929     {
1930       /* If we have this certificate already in our cache, use the
1931        * cached version for validation because this will take care of
1932        * any cached results.  We don't need to do this in tls mode
1933        * because this has already been done for certificate in a
1934        * certlist_t. */
1935       unsigned char fpr[20];
1936       ksba_cert_t tmpcert;
1937
1938       cert_compute_fpr (cert, fpr);
1939       tmpcert = get_cert_byfpr (fpr);
1940       if (tmpcert)
1941         {
1942           ksba_cert_release (cert);
1943           cert = tmpcert;
1944         }
1945     }
1946
1947   /* Quick hack to make verification work by inserting the supplied
1948    * certs into the cache.  */
1949   if (tls_mode && certlist)
1950     {
1951       certlist_t cl;
1952
1953       for (cl = certlist->next; cl; cl = cl->next)
1954         cache_cert (cl->cert);
1955     }
1956
1957   err = validate_cert_chain (ctrl, cert, NULL,
1958                              (VALIDATE_FLAG_TRUST_CONFIG
1959                               | (tls_mode ? VALIDATE_FLAG_TLS : 0)
1960                               | (systrust_mode ? VALIDATE_FLAG_TRUST_SYSTEM : 0)
1961                               | (no_crl ? VALIDATE_FLAG_NOCRLCHECK : 0)),
1962                              NULL);
1963
1964  leave:
1965   ksba_cert_release (cert);
1966   release_certlist (certlist);
1967   return leave_cmd (ctx, err);
1968 }
1969
1970
1971 \f
1972 /* Parse an keyserver URI and store it in a new uri item which is
1973    returned at R_ITEM.  On error return an error code.  */
1974 static gpg_error_t
1975 make_keyserver_item (const char *uri, uri_item_t *r_item)
1976 {
1977   gpg_error_t err;
1978   uri_item_t item;
1979
1980   *r_item = NULL;
1981   item = xtrymalloc (sizeof *item + strlen (uri));
1982   if (!item)
1983     return gpg_error_from_syserror ();
1984
1985   item->next = NULL;
1986   item->parsed_uri = NULL;
1987   strcpy (item->uri, uri);
1988
1989 #if USE_LDAP
1990   if (ldap_uri_p (item->uri))
1991     err = ldap_parse_uri (&item->parsed_uri, uri);
1992   else
1993 #endif
1994     {
1995       err = http_parse_uri (&item->parsed_uri, uri, 1);
1996     }
1997
1998   if (err)
1999     xfree (item);
2000   else
2001     *r_item = item;
2002   return err;
2003 }
2004
2005
2006 /* If no keyserver is stored in CTRL but a global keyserver has been
2007    set, put that global keyserver into CTRL.  We need use this
2008    function to help migrate from the old gpg based keyserver
2009    configuration to the new dirmngr based configuration.  */
2010 static gpg_error_t
2011 ensure_keyserver (ctrl_t ctrl)
2012 {
2013   gpg_error_t err;
2014   uri_item_t item;
2015   uri_item_t onion_items = NULL;
2016   uri_item_t plain_items = NULL;
2017   uri_item_t ui;
2018   strlist_t sl;
2019
2020   if (ctrl->server_local->keyservers)
2021     return 0; /* Already set for this session.  */
2022   if (!opt.keyserver)
2023     {
2024       /* No global option set.  Fall back to default:  */
2025       return make_keyserver_item (DIRMNGR_DEFAULT_KEYSERVER,
2026                                   &ctrl->server_local->keyservers);
2027     }
2028
2029   for (sl = opt.keyserver; sl; sl = sl->next)
2030     {
2031       err = make_keyserver_item (sl->d, &item);
2032       if (err)
2033         goto leave;
2034       if (item->parsed_uri->onion)
2035         {
2036           item->next = onion_items;
2037           onion_items = item;
2038         }
2039       else
2040         {
2041           item->next = plain_items;
2042           plain_items = item;
2043         }
2044     }
2045
2046   /* Decide which to use.  Note that the session has no keyservers
2047      yet set. */
2048   if (onion_items && !onion_items->next && plain_items && !plain_items->next)
2049     {
2050       /* If there is just one onion and one plain keyserver given, we take
2051          only one depending on whether Tor is running or not.  */
2052       if (is_tor_running (ctrl))
2053         {
2054           ctrl->server_local->keyservers = onion_items;
2055           onion_items = NULL;
2056         }
2057       else
2058         {
2059           ctrl->server_local->keyservers = plain_items;
2060           plain_items = NULL;
2061         }
2062     }
2063   else if (!is_tor_running (ctrl))
2064     {
2065       /* Tor is not running.  It does not make sense to add Onion
2066          addresses.  */
2067       ctrl->server_local->keyservers = plain_items;
2068       plain_items = NULL;
2069     }
2070   else
2071     {
2072       /* In all other cases add all keyservers.  */
2073       ctrl->server_local->keyservers = onion_items;
2074       onion_items = NULL;
2075       for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next)
2076         ;
2077       if (ui)
2078         ui->next = plain_items;
2079       else
2080         ctrl->server_local->keyservers = plain_items;
2081       plain_items = NULL;
2082     }
2083
2084  leave:
2085   release_uri_item_list (onion_items);
2086   release_uri_item_list (plain_items);
2087
2088   return err;
2089 }
2090
2091
2092 static const char hlp_keyserver[] =
2093   "KEYSERVER [<options>] [<uri>|<host>]\n"
2094   "Options are:\n"
2095   "  --help\n"
2096   "  --clear      Remove all configured keyservers\n"
2097   "  --resolve    Resolve HKP host names and rotate\n"
2098   "  --hosttable  Print table of known hosts and pools\n"
2099   "  --dead       Mark <host> as dead\n"
2100   "  --alive      Mark <host> as alive\n"
2101   "\n"
2102   "If called without arguments list all configured keyserver URLs.\n"
2103   "If called with an URI add this as keyserver.  Note that keyservers\n"
2104   "are configured on a per-session base.  A default keyserver may already be\n"
2105   "present, thus the \"--clear\" option must be used to get full control.\n"
2106   "If \"--clear\" and an URI are used together the clear command is\n"
2107   "obviously executed first.  A RESET command does not change the list\n"
2108   "of configured keyservers.";
2109 static gpg_error_t
2110 cmd_keyserver (assuan_context_t ctx, char *line)
2111 {
2112   ctrl_t ctrl = assuan_get_pointer (ctx);
2113   gpg_error_t err = 0;
2114   int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
2115   int dead_flag, alive_flag;
2116   uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
2117                              is always initialized.  */
2118
2119   clear_flag = has_option (line, "--clear");
2120   help_flag = has_option (line, "--help");
2121   resolve_flag = has_option (line, "--resolve");
2122   host_flag = has_option (line, "--hosttable");
2123   dead_flag = has_option (line, "--dead");
2124   alive_flag = has_option (line, "--alive");
2125   line = skip_options (line);
2126   add_flag = !!*line;
2127
2128   if (help_flag)
2129     {
2130       err = ks_action_help (ctrl, line);
2131       goto leave;
2132     }
2133
2134   if (resolve_flag)
2135     {
2136       err = ensure_keyserver (ctrl);
2137       if (err)
2138         {
2139           assuan_set_error (ctx, err,
2140                             "Bad keyserver configuration in dirmngr.conf");
2141           goto leave;
2142         }
2143       err = ks_action_resolve (ctrl, ctrl->server_local->keyservers);
2144       if (err)
2145         goto leave;
2146     }
2147
2148   if (alive_flag && dead_flag)
2149     {
2150       err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies");
2151       goto leave;
2152     }
2153   if (dead_flag)
2154     {
2155       err = check_owner_permission (ctx, "no permission to use --dead");
2156       if (err)
2157         goto leave;
2158     }
2159   if (alive_flag || dead_flag)
2160     {
2161       if (!*line)
2162         {
2163           err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing");
2164           goto leave;
2165         }
2166
2167       err = ks_hkp_mark_host (ctrl, line, alive_flag);
2168       if (err)
2169         goto leave;
2170     }
2171
2172   if (host_flag)
2173     {
2174       err = ks_hkp_print_hosttable (ctrl);
2175       if (err)
2176         goto leave;
2177     }
2178   if (resolve_flag || host_flag || alive_flag || dead_flag)
2179     goto leave;
2180
2181   if (add_flag)
2182     {
2183       err = make_keyserver_item (line, &item);
2184       if (err)
2185         goto leave;
2186     }
2187   if (clear_flag)
2188     release_ctrl_keyservers (ctrl);
2189   if (add_flag)
2190     {
2191       item->next = ctrl->server_local->keyservers;
2192       ctrl->server_local->keyservers = item;
2193     }
2194
2195   if (!add_flag && !clear_flag && !help_flag)
2196     {
2197       /* List configured keyservers.  However, we first add a global
2198          keyserver. */
2199       uri_item_t u;
2200
2201       err = ensure_keyserver (ctrl);
2202       if (err)
2203         {
2204           assuan_set_error (ctx, err,
2205                             "Bad keyserver configuration in dirmngr.conf");
2206           goto leave;
2207         }
2208
2209       for (u=ctrl->server_local->keyservers; u; u = u->next)
2210         dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
2211     }
2212   err = 0;
2213
2214  leave:
2215   return leave_cmd (ctx, err);
2216 }
2217
2218
2219 \f
2220 static const char hlp_ks_search[] =
2221   "KS_SEARCH {<pattern>}\n"
2222   "\n"
2223   "Search the configured OpenPGP keyservers (see command KEYSERVER)\n"
2224   "for keys matching PATTERN";
2225 static gpg_error_t
2226 cmd_ks_search (assuan_context_t ctx, char *line)
2227 {
2228   ctrl_t ctrl = assuan_get_pointer (ctx);
2229   gpg_error_t err;
2230   strlist_t list, sl;
2231   char *p;
2232   estream_t outfp;
2233
2234   if (has_option (line, "--quick"))
2235     ctrl->timeout = opt.connect_quick_timeout;
2236   line = skip_options (line);
2237
2238   /* Break the line down into an strlist.  Each pattern is
2239      percent-plus escaped. */
2240   list = NULL;
2241   for (p=line; *p; line = p)
2242     {
2243       while (*p && *p != ' ')
2244         p++;
2245       if (*p)
2246         *p++ = 0;
2247       if (*line)
2248         {
2249           sl = xtrymalloc (sizeof *sl + strlen (line));
2250           if (!sl)
2251             {
2252               err = gpg_error_from_syserror ();
2253               goto leave;
2254             }
2255           sl->flags = 0;
2256           strcpy_escaped_plus (sl->d, line);
2257           sl->next = list;
2258           list = sl;
2259         }
2260     }
2261
2262   err = ensure_keyserver (ctrl);
2263   if (err)
2264     goto leave;
2265
2266   /* Setup an output stream and perform the search.  */
2267   outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2268   if (!outfp)
2269     err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2270   else
2271     {
2272       err = ks_action_search (ctrl, ctrl->server_local->keyservers,
2273                               list, outfp);
2274       es_fclose (outfp);
2275     }
2276
2277  leave:
2278   free_strlist (list);
2279   return leave_cmd (ctx, err);
2280 }
2281
2282
2283 \f
2284 static const char hlp_ks_get[] =
2285   "KS_GET {<pattern>}\n"
2286   "\n"
2287   "Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
2288   "(see command KEYSERVER).  Each pattern should be a keyid, a fingerprint,\n"
2289   "or an exact name indicated by the '=' prefix.";
2290 static gpg_error_t
2291 cmd_ks_get (assuan_context_t ctx, char *line)
2292 {
2293   ctrl_t ctrl = assuan_get_pointer (ctx);
2294   gpg_error_t err;
2295   strlist_t list, sl;
2296   char *p;
2297   estream_t outfp;
2298
2299   if (has_option (line, "--quick"))
2300     ctrl->timeout = opt.connect_quick_timeout;
2301   line = skip_options (line);
2302
2303   /* Break the line into a strlist.  Each pattern is by
2304      definition percent-plus escaped.  However we only support keyids
2305      and fingerprints and thus the client has no need to apply the
2306      escaping.  */
2307   list = NULL;
2308   for (p=line; *p; line = p)
2309     {
2310       while (*p && *p != ' ')
2311         p++;
2312       if (*p)
2313         *p++ = 0;
2314       if (*line)
2315         {
2316           sl = xtrymalloc (sizeof *sl + strlen (line));
2317           if (!sl)
2318             {
2319               err = gpg_error_from_syserror ();
2320               goto leave;
2321             }
2322           sl->flags = 0;
2323           strcpy_escaped_plus (sl->d, line);
2324           sl->next = list;
2325           list = sl;
2326         }
2327     }
2328
2329   err = ensure_keyserver (ctrl);
2330   if (err)
2331     goto leave;
2332
2333   /* Setup an output stream and perform the get.  */
2334   outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2335   if (!outfp)
2336     err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2337   else
2338     {
2339       ctrl->server_local->inhibit_data_logging = 1;
2340       ctrl->server_local->inhibit_data_logging_now = 0;
2341       ctrl->server_local->inhibit_data_logging_count = 0;
2342       err = ks_action_get (ctrl, ctrl->server_local->keyservers, list, outfp);
2343       es_fclose (outfp);
2344       ctrl->server_local->inhibit_data_logging = 0;
2345     }
2346
2347  leave:
2348   free_strlist (list);
2349   return leave_cmd (ctx, err);
2350 }
2351
2352
2353 static const char hlp_ks_fetch[] =
2354   "KS_FETCH <URL>\n"
2355   "\n"
2356   "Get the key(s) from URL.";
2357 static gpg_error_t
2358 cmd_ks_fetch (assuan_context_t ctx, char *line)
2359 {
2360   ctrl_t ctrl = assuan_get_pointer (ctx);
2361   gpg_error_t err;
2362   estream_t outfp;
2363
2364   if (has_option (line, "--quick"))
2365     ctrl->timeout = opt.connect_quick_timeout;
2366   line = skip_options (line);
2367
2368   err = ensure_keyserver (ctrl);  /* FIXME: Why do we needs this here?  */
2369   if (err)
2370     goto leave;
2371
2372   /* Setup an output stream and perform the get.  */
2373   outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2374   if (!outfp)
2375     err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2376   else
2377     {
2378       ctrl->server_local->inhibit_data_logging = 1;
2379       ctrl->server_local->inhibit_data_logging_now = 0;
2380       ctrl->server_local->inhibit_data_logging_count = 0;
2381       err = ks_action_fetch (ctrl, line, outfp);
2382       es_fclose (outfp);
2383       ctrl->server_local->inhibit_data_logging = 0;
2384     }
2385
2386  leave:
2387   return leave_cmd (ctx, err);
2388 }
2389
2390
2391 \f
2392 static const char hlp_ks_put[] =
2393   "KS_PUT\n"
2394   "\n"
2395   "Send a key to the configured OpenPGP keyservers.  The actual key material\n"
2396   "is then requested by Dirmngr using\n"
2397   "\n"
2398   "  INQUIRE KEYBLOCK\n"
2399   "\n"
2400   "The client shall respond with a binary version of the keyblock (e.g.,\n"
2401   "the output of `gpg --export KEYID').  For LDAP\n"
2402   "keyservers Dirmngr may ask for meta information of the provided keyblock\n"
2403   "using:\n"
2404   "\n"
2405   "  INQUIRE KEYBLOCK_INFO\n"
2406   "\n"
2407   "The client shall respond with a colon delimited info lines (the output\n"
2408   "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n";
2409 static gpg_error_t
2410 cmd_ks_put (assuan_context_t ctx, char *line)
2411 {
2412   ctrl_t ctrl = assuan_get_pointer (ctx);
2413   gpg_error_t err;
2414   unsigned char *value = NULL;
2415   size_t valuelen;
2416   unsigned char *info = NULL;
2417   size_t infolen;
2418
2419   /* No options for now.  */
2420   line = skip_options (line);
2421
2422   err = ensure_keyserver (ctrl);
2423   if (err)
2424     goto leave;
2425
2426   /* Ask for the key material.  */
2427   err = assuan_inquire (ctx, "KEYBLOCK",
2428                         &value, &valuelen, MAX_KEYBLOCK_LENGTH);
2429   if (err)
2430     {
2431       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2432       goto leave;
2433     }
2434
2435   if (!valuelen) /* No data returned; return a comprehensible error. */
2436     {
2437       err = gpg_error (GPG_ERR_MISSING_CERT);
2438       goto leave;
2439     }
2440
2441   /* Ask for the key meta data. Not actually needed for HKP servers
2442      but we do it anyway to test the client implementation.  */
2443   err = assuan_inquire (ctx, "KEYBLOCK_INFO",
2444                         &info, &infolen, MAX_KEYBLOCK_LENGTH);
2445   if (err)
2446     {
2447       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2448       goto leave;
2449     }
2450
2451   /* Send the key.  */
2452   err = ks_action_put (ctrl, ctrl->server_local->keyservers,
2453                        value, valuelen, info, infolen);
2454
2455  leave:
2456   xfree (info);
2457   xfree (value);
2458   return leave_cmd (ctx, err);
2459 }
2460
2461
2462 \f
2463 static const char hlp_loadswdb[] =
2464   "LOADSWDB [--force]\n"
2465   "\n"
2466   "Load and verify the swdb.lst from the Net.";
2467 static gpg_error_t
2468 cmd_loadswdb (assuan_context_t ctx, char *line)
2469 {
2470   ctrl_t ctrl = assuan_get_pointer (ctx);
2471   gpg_error_t err;
2472
2473   err = dirmngr_load_swdb (ctrl, has_option (line, "--force"));
2474
2475   return leave_cmd (ctx, err);
2476 }
2477
2478
2479 \f
2480 static const char hlp_getinfo[] =
2481   "GETINFO <what>\n"
2482   "\n"
2483   "Multi purpose command to return certain information.  \n"
2484   "Supported values of WHAT are:\n"
2485   "\n"
2486   "version     - Return the version of the program.\n"
2487   "pid         - Return the process id of the server.\n"
2488   "tor         - Return OK if running in Tor mode\n"
2489   "dnsinfo     - Return info about the DNS resolver\n"
2490   "socket_name - Return the name of the socket.\n"
2491   "session_id  - Return the current session_id.\n"
2492   "workqueue   - Inspect the work queue\n";
2493 static gpg_error_t
2494 cmd_getinfo (assuan_context_t ctx, char *line)
2495 {
2496   ctrl_t ctrl = assuan_get_pointer (ctx);
2497   gpg_error_t err;
2498   char numbuf[50];
2499
2500   if (!strcmp (line, "version"))
2501     {
2502       const char *s = VERSION;
2503       err = assuan_send_data (ctx, s, strlen (s));
2504     }
2505   else if (!strcmp (line, "pid"))
2506     {
2507       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
2508       err = assuan_send_data (ctx, numbuf, strlen (numbuf));
2509     }
2510   else if (!strcmp (line, "socket_name"))
2511     {
2512       const char *s = dirmngr_get_current_socket_name ();
2513       err = assuan_send_data (ctx, s, strlen (s));
2514     }
2515   else if (!strcmp (line, "session_id"))
2516     {
2517       snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id);
2518       err = assuan_send_data (ctx, numbuf, strlen (numbuf));
2519     }
2520   else if (!strcmp (line, "tor"))
2521     {
2522       int use_tor;
2523
2524       use_tor = dirmngr_use_tor ();
2525       if (use_tor)
2526         {
2527           if (!is_tor_running (ctrl))
2528             err = assuan_write_status (ctx, "NO_TOR", "Tor not running");
2529           else
2530             err = 0;
2531           if (!err)
2532             assuan_set_okay_line (ctx, use_tor == 1 ? "- Tor mode is enabled"
2533                                   /**/              : "- Tor mode is enforced");
2534         }
2535       else
2536         err = set_error (GPG_ERR_FALSE, "Tor mode is NOT enabled");
2537     }
2538   else if (!strcmp (line, "dnsinfo"))
2539     {
2540       if (standard_resolver_p ())
2541         assuan_set_okay_line
2542           (ctx, "- Forced use of System resolver (w/o Tor support)");
2543       else
2544         {
2545 #ifdef USE_LIBDNS
2546           assuan_set_okay_line (ctx, (recursive_resolver_p ()
2547                                       ? "- Libdns recursive resolver"
2548                                       : "- Libdns stub resolver"));
2549 #else
2550           assuan_set_okay_line (ctx, "- System resolver (w/o Tor support)");
2551 #endif
2552         }
2553       err = 0;
2554     }
2555   else if (!strcmp (line, "workqueue"))
2556     {
2557       workqueue_dump_queue (ctrl);
2558       err = 0;
2559     }
2560   else
2561     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
2562
2563   return leave_cmd (ctx, err);
2564 }
2565
2566
2567 \f
2568 static const char hlp_killdirmngr[] =
2569   "KILLDIRMNGR\n"
2570   "\n"
2571   "This command allows a user - given sufficient permissions -\n"
2572   "to kill this dirmngr process.\n";
2573 static gpg_error_t
2574 cmd_killdirmngr (assuan_context_t ctx, char *line)
2575 {
2576   ctrl_t ctrl = assuan_get_pointer (ctx);
2577
2578   (void)line;
2579
2580   ctrl->server_local->stopme = 1;
2581   assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
2582   return gpg_error (GPG_ERR_EOF);
2583 }
2584
2585
2586 static const char hlp_reloaddirmngr[] =
2587   "RELOADDIRMNGR\n"
2588   "\n"
2589   "This command is an alternative to SIGHUP\n"
2590   "to reload the configuration.";
2591 static gpg_error_t
2592 cmd_reloaddirmngr (assuan_context_t ctx, char *line)
2593 {
2594   (void)ctx;
2595   (void)line;
2596
2597   dirmngr_sighup_action ();
2598   return 0;
2599 }
2600
2601
2602 \f
2603 /* Tell the assuan library about our commands. */
2604 static int
2605 register_commands (assuan_context_t ctx)
2606 {
2607   static struct {
2608     const char *name;
2609     assuan_handler_t handler;
2610     const char * const help;
2611   } table[] = {
2612     { "DNS_CERT",   cmd_dns_cert,   hlp_dns_cert },
2613     { "WKD_GET",    cmd_wkd_get,    hlp_wkd_get },
2614     { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
2615     { "ISVALID",    cmd_isvalid,    hlp_isvalid },
2616     { "CHECKCRL",   cmd_checkcrl,   hlp_checkcrl },
2617     { "CHECKOCSP",  cmd_checkocsp,  hlp_checkocsp },
2618     { "LOOKUP",     cmd_lookup,     hlp_lookup },
2619     { "LOADCRL",    cmd_loadcrl,    hlp_loadcrl },
2620     { "LISTCRLS",   cmd_listcrls,   hlp_listcrls },
2621     { "CACHECERT",  cmd_cachecert,  hlp_cachecert },
2622     { "VALIDATE",   cmd_validate,   hlp_validate },
2623     { "KEYSERVER",  cmd_keyserver,  hlp_keyserver },
2624     { "KS_SEARCH",  cmd_ks_search,  hlp_ks_search },
2625     { "KS_GET",     cmd_ks_get,     hlp_ks_get },
2626     { "KS_FETCH",   cmd_ks_fetch,   hlp_ks_fetch },
2627     { "KS_PUT",     cmd_ks_put,     hlp_ks_put },
2628     { "GETINFO",    cmd_getinfo,    hlp_getinfo },
2629     { "LOADSWDB",   cmd_loadswdb,   hlp_loadswdb },
2630     { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
2631     { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
2632     { NULL, NULL }
2633   };
2634   int i, j, rc;
2635
2636   for (i=j=0; table[i].name; i++)
2637     {
2638       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
2639                                     table[i].help);
2640       if (rc)
2641         return rc;
2642     }
2643   return 0;
2644 }
2645
2646
2647 /* Note that we do not reset the list of configured keyservers.  */
2648 static gpg_error_t
2649 reset_notify (assuan_context_t ctx, char *line)
2650 {
2651   ctrl_t ctrl = assuan_get_pointer (ctx);
2652   (void)line;
2653
2654 #if USE_LDAP
2655   ldapserver_list_free (ctrl->server_local->ldapservers);
2656 #endif /*USE_LDAP*/
2657   ctrl->server_local->ldapservers = NULL;
2658   return 0;
2659 }
2660
2661
2662 /* This function is called by our assuan log handler to test whether a
2663  * log message shall really be printed.  The function must return
2664  * false to inhibit the logging of MSG.  CAT gives the requested log
2665  * category.  MSG might be NULL. */
2666 int
2667 dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
2668                             const char *msg)
2669 {
2670   ctrl_t ctrl = assuan_get_pointer (ctx);
2671
2672   (void)cat;
2673   (void)msg;
2674
2675   if (!ctrl || !ctrl->server_local)
2676     return 1; /* Can't decide - allow logging.  */
2677
2678   if (!ctrl->server_local->inhibit_data_logging)
2679     return 1; /* Not requested - allow logging.  */
2680
2681   /* Disallow logging if *_now is true.  */
2682   return !ctrl->server_local->inhibit_data_logging_now;
2683 }
2684
2685
2686 /* Startup the server and run the main command loop.  With FD = -1,
2687  * use stdin/stdout.  SESSION_ID is either 0 or a unique number
2688  * identifying a session.  */
2689 void
2690 start_command_handler (assuan_fd_t fd, unsigned int session_id)
2691 {
2692   static const char hello[] = "Dirmngr " VERSION " at your service";
2693   static char *hello_line;
2694   int rc;
2695   assuan_context_t ctx;
2696   ctrl_t ctrl;
2697
2698   ctrl = xtrycalloc (1, sizeof *ctrl);
2699   if (ctrl)
2700     ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
2701   if (!ctrl || !ctrl->server_local)
2702     {
2703       log_error (_("can't allocate control structure: %s\n"),
2704                  strerror (errno));
2705       xfree (ctrl);
2706       return;
2707     }
2708
2709   dirmngr_init_default_ctrl (ctrl);
2710
2711   rc = assuan_new (&ctx);
2712   if (rc)
2713     {
2714       log_error (_("failed to allocate assuan context: %s\n"),
2715                  gpg_strerror (rc));
2716       dirmngr_exit (2);
2717     }
2718
2719   if (fd == ASSUAN_INVALID_FD)
2720     {
2721       assuan_fd_t filedes[2];
2722
2723       filedes[0] = assuan_fdopen (0);
2724       filedes[1] = assuan_fdopen (1);
2725       rc = assuan_init_pipe_server (ctx, filedes);
2726     }
2727   else
2728     {
2729       rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
2730     }
2731
2732   if (rc)
2733     {
2734       assuan_release (ctx);
2735       log_error (_("failed to initialize the server: %s\n"),
2736                  gpg_strerror(rc));
2737       dirmngr_exit (2);
2738     }
2739
2740   rc = register_commands (ctx);
2741   if (rc)
2742     {
2743       log_error (_("failed to the register commands with Assuan: %s\n"),
2744                  gpg_strerror(rc));
2745       dirmngr_exit (2);
2746     }
2747
2748
2749   if (!hello_line)
2750     {
2751       hello_line = xtryasprintf
2752         ("Home: %s\n"
2753          "Config: %s\n"
2754          "%s",
2755          gnupg_homedir (),
2756          opt.config_filename? opt.config_filename : "[none]",
2757          hello);
2758     }
2759
2760   ctrl->server_local->assuan_ctx = ctx;
2761   assuan_set_pointer (ctx, ctrl);
2762
2763   assuan_set_hello_line (ctx, hello_line);
2764   assuan_register_option_handler (ctx, option_handler);
2765   assuan_register_reset_notify (ctx, reset_notify);
2766
2767   ctrl->server_local->session_id = session_id;
2768
2769   for (;;)
2770     {
2771       rc = assuan_accept (ctx);
2772       if (rc == -1)
2773         break;
2774       if (rc)
2775         {
2776           log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
2777           break;
2778         }
2779
2780 #ifndef HAVE_W32_SYSTEM
2781       if (opt.verbose)
2782         {
2783           assuan_peercred_t peercred;
2784
2785           if (!assuan_get_peercred (ctx, &peercred))
2786             log_info ("connection from process %ld (%ld:%ld)\n",
2787                       (long)peercred->pid, (long)peercred->uid,
2788                       (long)peercred->gid);
2789         }
2790 #endif
2791
2792       rc = assuan_process (ctx);
2793       if (rc)
2794         {
2795           log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
2796           continue;
2797         }
2798     }
2799
2800
2801 #if USE_LDAP
2802   ldap_wrapper_connection_cleanup (ctrl);
2803
2804   ldapserver_list_free (ctrl->server_local->ldapservers);
2805 #endif /*USE_LDAP*/
2806   ctrl->server_local->ldapservers = NULL;
2807
2808   release_ctrl_keyservers (ctrl);
2809
2810   ctrl->server_local->assuan_ctx = NULL;
2811   assuan_release (ctx);
2812
2813   if (ctrl->server_local->stopme)
2814     dirmngr_exit (0);
2815
2816   if (ctrl->refcount)
2817     log_error ("oops: connection control structure still referenced (%d)\n",
2818                ctrl->refcount);
2819   else
2820     {
2821       release_ctrl_ocsp_certs (ctrl);
2822       xfree (ctrl->server_local);
2823       dirmngr_deinit_default_ctrl (ctrl);
2824       xfree (ctrl);
2825     }
2826 }
2827
2828
2829 /* Send a status line back to the client.  KEYWORD is the status
2830    keyword, the optional string arguments are blank separated added to
2831    the line, the last argument must be a NULL. */
2832 gpg_error_t
2833 dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
2834 {
2835   gpg_error_t err = 0;
2836   va_list arg_ptr;
2837   const char *text;
2838   assuan_context_t ctx;
2839
2840   va_start (arg_ptr, keyword);
2841
2842   if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
2843     {
2844       char buf[950], *p;
2845       size_t n;
2846
2847       p = buf;
2848       n = 0;
2849       while ( (text = va_arg (arg_ptr, const char *)) )
2850         {
2851           if (n)
2852             {
2853               *p++ = ' ';
2854               n++;
2855             }
2856           for ( ; *text && n < DIM (buf)-2; n++)
2857             *p++ = *text++;
2858         }
2859       *p = 0;
2860       err = assuan_write_status (ctx, keyword, buf);
2861     }
2862
2863   va_end (arg_ptr);
2864   return err;
2865 }
2866
2867
2868 /* Print a help status line.  The function splits text at LFs.  */
2869 gpg_error_t
2870 dirmngr_status_help (ctrl_t ctrl, const char *text)
2871 {
2872   gpg_error_t err = 0;
2873   assuan_context_t ctx;
2874
2875   if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
2876     {
2877       char buf[950], *p;
2878       size_t n;
2879
2880       do
2881         {
2882           p = buf;
2883           n = 0;
2884           for ( ; *text && *text != '\n' && n < DIM (buf)-2; n++)
2885             *p++ = *text++;
2886           if (*text == '\n')
2887             text++;
2888           *p = 0;
2889           err = assuan_write_status (ctx, "#", buf);
2890         }
2891       while (!err && *text);
2892     }
2893
2894   return err;
2895 }
2896
2897
2898 /* Print a help status line using a printf like format.  The function
2899  * splits text at LFs.  */
2900 gpg_error_t
2901 dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
2902 {
2903   va_list arg_ptr;
2904   gpg_error_t err;
2905   char *buf;
2906
2907   va_start (arg_ptr, format);
2908   buf = es_vbsprintf (format, arg_ptr);
2909   err = buf? 0 : gpg_error_from_syserror ();
2910   va_end (arg_ptr);
2911   if (!err)
2912     err = dirmngr_status_help (ctrl, buf);
2913   es_free (buf);
2914   return err;
2915 }
2916
2917
2918 /* This function is similar to print_assuan_status but takes a CTRL
2919  * arg instead of an assuan context as first argument.  */
2920 gpg_error_t
2921 dirmngr_status_printf (ctrl_t ctrl, const char *keyword,
2922                        const char *format, ...)
2923 {
2924   gpg_error_t err;
2925   va_list arg_ptr;
2926   assuan_context_t ctx;
2927
2928   if (!ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
2929     return 0;
2930
2931   va_start (arg_ptr, format);
2932   err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
2933   va_end (arg_ptr);
2934   return err;
2935 }
2936
2937
2938 /* Send a tick progress indicator back.  Fixme: This is only done for
2939    the currently active channel.  */
2940 gpg_error_t
2941 dirmngr_tick (ctrl_t ctrl)
2942 {
2943   static time_t next_tick = 0;
2944   gpg_error_t err = 0;
2945   time_t now = time (NULL);
2946
2947   if (!next_tick)
2948     {
2949       next_tick = now + 1;
2950     }
2951   else if ( now > next_tick )
2952     {
2953       if (ctrl)
2954         {
2955           err = dirmngr_status (ctrl, "PROGRESS", "tick", "? 0 0", NULL);
2956           if (err)
2957             {
2958               /* Take this as in indication for a cancel request.  */
2959               err = gpg_error (GPG_ERR_CANCELED);
2960             }
2961           now = time (NULL);
2962         }
2963
2964       next_tick = now + 1;
2965     }
2966   return err;
2967 }