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
7 * This file is part of GnuPG.
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.
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.
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/>.
22 * SPDX-License-Identifier: GPL-3.0+
31 #include <sys/types.h>
42 # include "ldapserver.h"
45 #include "certcache.h"
49 # include "ldap-wrapper.h"
51 #include "ks-action.h"
52 #include "ks-engine.h" /* (ks_hkp_print_hosttable) */
54 # include "ldap-parse-uri.h"
56 #include "dns-stuff.h"
57 #include "../common/mbox-util.h"
58 #include "../common/zb32.h"
59 #include "../common/server-help.h"
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)
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)
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)
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)) \
88 /* Control structure per connection. */
91 /* Data used to associate an Assuan context with local server data */
92 assuan_context_t assuan_ctx;
94 /* The session id (a counter). */
95 unsigned int session_id;
97 /* Per-session LDAP servers. */
98 ldap_server_t ldapservers;
100 /* Per-session list of keyservers. */
101 uri_item_t keyservers;
103 /* If this flag is set to true this dirmngr process will be
104 terminated after the end of this session. */
107 /* State variable private to is_tor_running. */
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;
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 =
126 data_line_cookie_write,
128 data_line_cookie_close
132 /* Local prototypes */
133 static const char *task_check_wkd_support (ctrl_t ctrl, const char *domain);
138 /* Accessor for the local ldapservers variable. */
140 get_ldapservers_from_ctrl (ctrl_t ctrl)
142 if (ctrl && ctrl->server_local)
143 return ctrl->server_local->ldapservers;
148 /* Release an uri_item_t list. */
150 release_uri_item_list (uri_item_t list)
154 uri_item_t tmp = list->next;
155 http_release_parsed_uri (list->parsed_uri);
161 /* Release all configured keyserver info from CTRL. */
163 release_ctrl_keyservers (ctrl_t ctrl)
165 if (! ctrl->server_local)
168 release_uri_item_list (ctrl->server_local->keyservers);
169 ctrl->server_local->keyservers = NULL;
174 /* Helper to print a message while leaving a command. */
176 leave_cmd (assuan_context_t ctx, gpg_error_t err)
180 const char *name = assuan_get_command_name (ctx);
183 if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
184 log_error ("command '%s' failed: %s\n", name,
187 log_error ("command '%s' failed: %s <%s>\n", name,
188 gpg_strerror (err), gpg_strsource (err));
194 /* This is a wrapper around assuan_send_data which makes debugging the
195 output in verbose mode easier. */
197 data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size)
199 ctrl_t ctrl = assuan_get_pointer (ctx);
200 const char *buffer = buffer_arg;
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;
207 if (opt.verbose && buffer && size)
209 /* Ease reading of output by sending a physical line at each LF. */
216 p = memchr (buffer, '\n', nbytes);
217 n = p ? (p - buffer) + 1 : nbytes;
218 err = assuan_send_data (ctx, buffer, n);
221 gpg_err_set_errno (EIO);
226 if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
228 gpg_err_set_errno (EIO);
236 err = assuan_send_data (ctx, buffer, size);
239 gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */
245 if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
247 ctrl->server_local->inhibit_data_logging_now = 0;
248 ctrl->server_local->inhibit_data_logging_count += size;
255 /* A write handler used by es_fopencookie to write assuan data
258 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
260 assuan_context_t ctx = cookie;
262 if (data_line_write (ctx, buffer, size))
264 return (gpgrt_ssize_t)size;
269 data_line_cookie_close (void *cookie)
271 assuan_context_t ctx = cookie;
275 ctrl_t ctrl = assuan_get_pointer (ctx);
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);
283 if (assuan_send_data (ctx, NULL, 0))
285 gpg_err_set_errno (EIO);
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
301 strcpy_escaped_plus (char *d, const unsigned char *s)
305 if (*s == '%' && s[1] && s[2])
320 /* This function returns true if a Tor server is running. The status
321 * is cached for the current connection. */
323 is_tor_running (ctrl_t ctrl)
325 /* Check whether we can connect to the proxy. */
327 if (!ctrl || !ctrl->server_local)
328 return 0; /* Ooops. */
330 if (!ctrl->server_local->tor_state)
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. */
339 assuan_sock_close (sock);
340 ctrl->server_local->tor_state = 1; /* Running. */
343 return (ctrl->server_local->tor_state > 0);
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
351 check_owner_permission (assuan_context_t ctx, const char *failtext)
353 #ifdef HAVE_W32_SYSTEM
354 /* Under Windows the dirmngr is always run under the control of the
360 assuan_peercred_t cred;
362 ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
363 if (!ec && cred->uid && cred->uid != getuid ())
366 return set_error (ec, failtext);
373 /* Common code for get_cert_local and get_issuer_cert_local. */
375 do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
377 unsigned char *value;
383 buf = name? strconcat (command, " ", name, NULL) : xtrystrdup (command);
385 rc = gpg_error_from_syserror ();
388 rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
389 &value, &valuelen, MAX_CERT_LENGTH);
394 log_error (_("assuan_inquire(%s) failed: %s\n"),
395 command, gpg_strerror (rc));
405 rc = ksba_cert_new (&cert);
408 rc = ksba_cert_init_from_mem (cert, value, valuelen);
411 ksba_cert_release (cert);
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. */
427 get_cert_local (ctrl_t ctrl, const char *name)
429 if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
432 log_debug ("get_cert_local called w/o context\n");
435 return do_get_cert_local (ctrl, name, "SENDCERT");
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. */
446 get_issuing_cert_local (ctrl_t ctrl, const char *name)
448 if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
451 log_debug ("get_issuing_cert_local called w/o context\n");
454 return do_get_cert_local (ctrl, name, "SENDISSUERCERT");
458 /* Ask back to return a certificate with subject NAME and a
459 * subjectKeyIdentifier of KEYID. */
461 get_cert_local_ski (ctrl_t ctrl, const char *name, ksba_sexp_t keyid)
463 unsigned char *value;
470 if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
473 log_debug ("get_cert_local_ski called w/o context\n");
478 log_debug ("get_cert_local_ski called with insufficient arguments\n");
482 hexkeyid = serial_hex (keyid);
485 log_debug ("serial_hex() failed\n");
489 buf = strconcat ("SENDCERT_SKI ", hexkeyid, " /", name, NULL);
492 log_error ("can't allocate enough memory: %s\n", strerror (errno));
498 rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
499 &value, &valuelen, MAX_CERT_LENGTH);
503 log_error (_("assuan_inquire(%s) failed: %s\n"), "SENDCERT_SKI",
514 rc = ksba_cert_new (&cert);
517 rc = ksba_cert_init_from_mem (cert, value, valuelen);
520 ksba_cert_release (cert);
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. */
533 get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr)
535 unsigned char *value;
540 if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx
542 return gpg_error (GPG_ERR_INV_ARG);
544 snprintf (request, sizeof request, "ISTRUSTED %s", hexfpr);
545 rc = assuan_inquire (ctrl->server_local->assuan_ctx, request,
546 &value, &valuelen, 100);
549 log_error (_("assuan_inquire(%s) failed: %s\n"),
550 request, gpg_strerror (rc));
553 /* The expected data is: "1" or "1 cruft" (not a C-string). */
554 if (valuelen && *value == '1' && (valuelen == 1 || spacep (value+1)))
557 rc = gpg_error (GPG_ERR_NOT_TRUSTED);
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. */
570 inquire_cert_and_load_crl (assuan_context_t ctx)
572 ctrl_t ctrl = assuan_get_pointer (ctx);
574 unsigned char *value = NULL;
576 ksba_cert_t cert = NULL;
578 err = assuan_inquire( ctx, "SENDCERT", &value, &valuelen, 0);
583 /* FILE *fp = fopen ("foo.der", "r"); */
584 /* value = xmalloc (2000); */
585 /* valuelen = fread (value, 1, 2000, fp); */
589 if (!valuelen) /* No data returned; return a comprehensible error. */
590 return gpg_error (GPG_ERR_MISSING_CERT);
592 err = ksba_cert_new (&cert);
595 err = ksba_cert_init_from_mem (cert, value, valuelen);
598 xfree (value); value = NULL;
600 err = crl_cache_reload_crl (ctrl, cert);
603 ksba_cert_release (cert);
609 /* Handle OPTION commands. */
611 option_handler (assuan_context_t ctx, const char *key, const char *value)
613 ctrl_t ctrl = assuan_get_pointer (ctx);
616 if (!strcmp (key, "force-crl-refresh"))
618 int i = *value? atoi (value) : 0;
619 ctrl->force_crl_refresh = i;
621 else if (!strcmp (key, "audit-events"))
623 int i = *value? atoi (value) : 0;
624 ctrl->audit_events = i;
626 else if (!strcmp (key, "http-proxy"))
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 ();
634 else if (!strcmp (key, "honor-keyserver-url-used"))
636 /* Return an error if we are running in Tor mode. */
637 if (dirmngr_use_tor ())
638 err = gpg_error (GPG_ERR_FORBIDDEN);
640 else if (!strcmp (key, "http-crl"))
642 int i = *value? atoi (value) : 0;
643 ctrl->http_no_crl = !i;
646 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
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"
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";
667 cmd_dns_cert (assuan_context_t ctx, char *line)
669 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
671 int pka_mode, dane_mode;
673 char *namebuf = NULL;
674 char *encodedhash = NULL;
680 unsigned char *fpr = NULL;
684 pka_mode = has_option (line, "--pka");
685 dane_mode = has_option (line, "--dane");
686 line = skip_options (line);
688 if (pka_mode && dane_mode)
690 err = PARM_ERROR ("either --pka or --dane may be given");
694 if (pka_mode || dane_mode)
695 ; /* No need to parse here - we do this later. */
698 p = strchr (line, ' ');
701 err = PARM_ERROR ("missing arguments");
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;
713 err = PARM_ERROR ("unknown subtype");
721 err = PARM_ERROR ("name missing");
726 if (pka_mode || dane_mode)
728 char *domain; /* Points to mbox. */
729 char hashbuf[32]; /* For SHA-1 and SHA-256. */
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
734 mbox = mailbox_from_userid (line);
735 if (!mbox || !(domain = strchr (mbox, '@')))
737 err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
744 gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
745 encodedhash = zb32_encode (hashbuf, 8*20);
748 err = gpg_error_from_syserror ();
751 namebuf = strconcat (encodedhash, "._pka.", domain, NULL);
754 err = gpg_error_from_syserror ();
758 certtype = DNS_CERTTYPE_IPGP;
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);
768 err = gpg_error_from_syserror ();
771 ascii_strlwr (encodedhash);
772 namebuf = strconcat (encodedhash, "._openpgpkey.", domain, NULL);
775 err = gpg_error_from_syserror ();
779 certtype = DNS_CERTTYPE_RR61;
785 err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url);
791 err = data_line_write (ctx, key, keylen);
800 tmpstr = bin2hex (fpr, fprlen, NULL);
802 err = gpg_error_from_syserror ();
805 err = assuan_write_status (ctx, "FPR", tmpstr);
814 err = assuan_write_status (ctx, "URL", url);
827 return leave_cmd (ctx, err);
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. */
835 proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
839 char *domainbuf = NULL;
840 char *domain; /* Points to mbox or domainbuf. */
841 char *domain_orig;/* Points to mbox. */
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. */
849 char portstr[20] = { 0 };
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);
858 mbox = mailbox_from_userid (line);
859 if (!mbox || !(domain = strchr (mbox, '@')))
861 err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
865 domain_orig = domain;
867 /* First check whether we already know that the domain does not
871 if (domaininfo_is_wkd_not_supported (domain_orig))
873 err = gpg_error (GPG_ERR_NO_DATA);
878 /* Check for SRV records. */
881 struct srventry *srvs;
882 unsigned int srvscount;
883 size_t domainlen, targetlen;
886 err = get_dns_srv (domain, "openpgpkey", NULL, &srvs, &srvscount);
890 /* Check for rogue DNS names. */
891 for (i = 0; i < srvscount; i++)
893 if (!is_valid_domain_name (srvs[i].target))
895 err = gpg_error (GPG_ERR_DNS_ADDRESS);
896 log_error ("rogue openpgpkey SRV record for '%s'\n", domain);
902 /* Find the first target which also ends in DOMAIN or is equal
904 domainlen = strlen (domain);
905 for (i = 0; i < srvscount; i++)
908 log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port);
909 targetlen = strlen (srvs[i].target);
910 if ((targetlen > domainlen + 1
911 && srvs[i].target[targetlen - domainlen - 1] == '.'
912 && !ascii_strcasecmp (srvs[i].target + targetlen - domainlen,
914 || (targetlen == domainlen
915 && !ascii_strcasecmp (srvs[i].target, domain)))
918 domainbuf = xtrystrdup (srvs[i].target);
921 err = gpg_error_from_syserror ();
927 snprintf (portstr, sizeof portstr, ":%hu", srvs[i].port);
934 gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
935 encodedhash = zb32_encode (sha1buf, 8*20);
938 err = gpg_error_from_syserror ();
942 if (opt_submission_addr)
944 uri = strconcat ("https://",
947 "/.well-known/openpgpkey/submission-address",
950 else if (opt_policy_flags)
952 uri = strconcat ("https://",
955 "/.well-known/openpgpkey/policy",
962 escapedmbox = http_escape_string (mbox, "%;?&=");
965 uri = strconcat ("https://",
968 "/.well-known/openpgpkey/hu/",
977 err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
986 err = gpg_error_from_syserror ();
990 /* Setup an output stream and perform the get. */
994 outfp = ctx? es_fopencookie (ctx, "w", data_line_cookie_functions) : NULL;
996 err = set_error (GPG_ERR_ASS_GENERAL,
997 "error setting up a data stream");
1000 if (ctrl->server_local)
1003 ctrl->server_local->inhibit_data_logging = 1;
1004 ctrl->server_local->inhibit_data_logging_now = 0;
1005 ctrl->server_local->inhibit_data_logging_count = 0;
1007 err = ks_action_fetch (ctrl, uri, outfp);
1009 if (ctrl->server_local)
1010 ctrl->server_local->inhibit_data_logging = 0;
1012 /* Register the result under the domain name of MBOX. */
1013 switch (gpg_err_code (err))
1016 domaininfo_set_wkd_supported (domain_orig);
1019 case GPG_ERR_NO_NAME:
1020 /* There is no such domain. */
1021 domaininfo_set_no_name (domain_orig);
1024 case GPG_ERR_NO_DATA:
1025 if (is_wkd_query && ctrl->server_local)
1027 /* Mark that and schedule a check. */
1028 domaininfo_set_wkd_not_found (domain_orig);
1029 workqueue_add_task (task_check_wkd_support, domain_orig,
1030 ctrl->server_local->session_id, 1);
1032 else if (opt_policy_flags) /* No policy file - no support. */
1033 domaininfo_set_wkd_not_supported (domain_orig);
1037 /* Don't register other errors. */
1045 xfree (encodedhash);
1052 static const char hlp_wkd_get[] =
1053 "WKD_GET [--submission-address|--policy-flags] <user_id>\n"
1055 "Return the key or other info for <user_id>\n"
1056 "from the Web Key Directory.";
1058 cmd_wkd_get (assuan_context_t ctx, char *line)
1060 ctrl_t ctrl = assuan_get_pointer (ctx);
1063 err = proc_wkd_get (ctrl, ctx, line);
1065 return leave_cmd (ctx, err);
1069 /* A task to check whether DOMAIN supports WKD. This is done by
1070 * checking whether the policy flags file can be read. */
1072 task_check_wkd_support (ctrl_t ctrl, const char *domain)
1076 if (!ctrl || !domain)
1077 return "check_wkd_support";
1079 string = strconcat ("--policy-flags foo@", domain, NULL);
1081 log_error ("%s: %s\n", __func__, gpg_strerror (gpg_error_from_syserror ()));
1084 proc_wkd_get (ctrl, NULL, string);
1093 static const char hlp_ldapserver[] =
1094 "LDAPSERVER <data>\n"
1096 "Add a new LDAP server to the list of configured LDAP servers.\n"
1097 "DATA is in the same format as expected in the configure file.";
1099 cmd_ldapserver (assuan_context_t ctx, char *line)
1102 ctrl_t ctrl = assuan_get_pointer (ctx);
1103 ldap_server_t server;
1104 ldap_server_t *last_next_p;
1106 while (spacep (line))
1109 return leave_cmd (ctx, PARM_ERROR (_("ldapserver missing")));
1111 server = ldapserver_parse_one (line, "", 0);
1113 return leave_cmd (ctx, gpg_error (GPG_ERR_INV_ARG));
1115 last_next_p = &ctrl->server_local->ldapservers;
1116 while (*last_next_p)
1117 last_next_p = &(*last_next_p)->next;
1118 *last_next_p = server;
1119 return leave_cmd (ctx, 0);
1122 return leave_cmd (ctx, gpg_error (GPG_ERR_NOT_IMPLEMENTED));
1127 static const char hlp_isvalid[] =
1128 "ISVALID [--only-ocsp] [--force-default-responder]"
1129 " <certificate_id> [<certificate_fpr>]\n"
1131 "This command checks whether the certificate identified by the\n"
1132 "certificate_id is valid. This is done by consulting CRLs or\n"
1133 "whatever has been configured. Note, that the returned error codes\n"
1134 "are from gpg-error.h. The command may callback using the inquire\n"
1135 "function. See the manual for details.\n"
1137 "The CERTIFICATE_ID is a hex encoded string consisting of two parts,\n"
1138 "delimited by a single dot. The first part is the SHA-1 hash of the\n"
1139 "issuer name and the second part the serial number.\n"
1141 "If an OCSP check is desired CERTIFICATE_FPR with the hex encoded\n"
1142 "fingerprint of the certificate is required. In this case an OCSP\n"
1143 "request is done before consulting the CRL.\n"
1145 "If the option --only-ocsp is given, no fallback to a CRL check will\n"
1148 "If the option --force-default-responder is given, only the default\n"
1149 "OCSP responder will be used and any other methods of obtaining an\n"
1150 "OCSP responder URL won't be used.";
1152 cmd_isvalid (assuan_context_t ctx, char *line)
1154 ctrl_t ctrl = assuan_get_pointer (ctx);
1155 char *issuerhash, *serialno, *fpr;
1157 int did_inquire = 0;
1160 int force_default_responder;
1162 only_ocsp = has_option (line, "--only-ocsp");
1163 force_default_responder = has_option (line, "--force-default-responder");
1164 line = skip_options (line);
1166 /* We need to work on a copy of the line because that same Assuan
1167 * context may be used for an inquiry. That is because Assuan
1168 * reuses its line buffer. */
1169 issuerhash = xstrdup (line);
1171 serialno = strchr (issuerhash, '.');
1175 return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID")));
1178 if (strlen (issuerhash) != 40)
1181 return leave_cmd (ctx, PARM_ERROR ("cert ID is too short"));
1184 fpr = strchr (serialno, ' ');
1185 while (fpr && spacep (fpr))
1189 char *endp = strchr (fpr, ' ');
1192 if (strlen (fpr) != 40)
1195 return leave_cmd (ctx, PARM_ERROR ("fingerprint too short"));
1204 /* Note, that we currently ignore the supplied fingerprint FPR;
1205 * instead ocsp_isvalid does an inquire to ask for the cert.
1206 * The fingerprint may eventually be used to lookup the
1207 * certificate in a local cache. */
1208 if (!opt.allow_ocsp)
1209 err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1211 err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
1213 if (gpg_err_code (err) == GPG_ERR_CONFIGURATION
1214 && gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR)
1216 /* No default responder configured - fallback to CRL. */
1218 log_info ("falling back to CRL check\n");
1224 err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1227 switch (crl_cache_isvalid (ctrl,
1228 issuerhash, serialno,
1229 ctrl->force_crl_refresh))
1231 case CRL_CACHE_VALID:
1234 case CRL_CACHE_INVALID:
1235 err = gpg_error (GPG_ERR_CERT_REVOKED);
1237 case CRL_CACHE_DONTKNOW:
1239 err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1240 else if (!(err = inquire_cert_and_load_crl (ctx)))
1246 case CRL_CACHE_CANTUSE:
1247 err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1250 log_fatal ("crl_cache_isvalid returned invalid code\n");
1255 return leave_cmd (ctx, err);
1259 /* If the line contains a SHA-1 fingerprint as the first argument,
1260 return the FPR vuffer on success. The function checks that the
1261 fingerprint consists of valid characters and prints and error
1262 message if it does not and returns NULL. Fingerprints are
1263 considered optional and thus no explicit error is returned. NULL is
1264 also returned if there is no fingerprint at all available.
1265 FPR must be a caller provided buffer of at least 20 bytes.
1267 Note that colons within the fingerprint are allowed to separate 2
1268 hex digits; this allows for easier cutting and pasting using the
1269 usual fingerprint rendering.
1271 static unsigned char *
1272 get_fingerprint_from_line (const char *line, unsigned char *fpr)
1277 for (s=line, i=0; *s && *s != ' '; s++ )
1279 if ( hexdigitp (s) && hexdigitp (s+1) )
1282 return NULL; /* Fingerprint too long. */
1283 fpr[i++] = xtoi_2 (s);
1286 else if ( *s != ':' )
1287 return NULL; /* Invalid. */
1290 return NULL; /* Fingerprint to short. */
1296 static const char hlp_checkcrl[] =
1297 "CHECKCRL [<fingerprint>]\n"
1299 "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1300 "entire X.509 certificate blob) is valid or not by consulting the\n"
1301 "CRL responsible for this certificate. If the fingerprint has not\n"
1302 "been given or the certificate is not known, the function \n"
1303 "inquires the certificate using an\n"
1305 " INQUIRE TARGETCERT\n"
1307 "and the caller is expected to return the certificate for the\n"
1308 "request (which should match FINGERPRINT) as a binary blob.\n"
1309 "Processing then takes place without further interaction; in\n"
1310 "particular dirmngr tries to locate other required certificate by\n"
1311 "its own mechanism which includes a local certificate store as well\n"
1312 "as a list of trusted root certificates.\n"
1314 "The return value is the usual gpg-error code or 0 for ducesss;\n"
1315 "i.e. the certificate validity has been confirmed by a valid CRL.";
1317 cmd_checkcrl (assuan_context_t ctx, char *line)
1319 ctrl_t ctrl = assuan_get_pointer (ctx);
1321 unsigned char fprbuffer[20], *fpr;
1324 fpr = get_fingerprint_from_line (line, fprbuffer);
1325 cert = fpr? get_cert_byfpr (fpr) : NULL;
1329 /* We do not have this certificate yet or the fingerprint has
1330 not been given. Inquire it from the client. */
1331 unsigned char *value = NULL;
1334 err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1335 &value, &valuelen, MAX_CERT_LENGTH);
1338 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1342 if (!valuelen) /* No data returned; return a comprehensible error. */
1343 err = gpg_error (GPG_ERR_MISSING_CERT);
1346 err = ksba_cert_new (&cert);
1348 err = ksba_cert_init_from_mem (cert, value, valuelen);
1357 err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
1358 if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
1360 err = crl_cache_reload_crl (ctrl, cert);
1362 err = crl_cache_cert_isvalid (ctrl, cert, 0);
1366 ksba_cert_release (cert);
1367 return leave_cmd (ctx, err);
1371 static const char hlp_checkocsp[] =
1372 "CHECKOCSP [--force-default-responder] [<fingerprint>]\n"
1374 "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1375 "entire X.509 certificate blob) is valid or not by asking an OCSP\n"
1376 "responder responsible for this certificate. The optional\n"
1377 "fingerprint may be used for a quick check in case an OCSP check has\n"
1378 "been done for this certificate recently (we always cache OCSP\n"
1379 "responses for a couple of minutes). If the fingerprint has not been\n"
1380 "given or there is no cached result, the function inquires the\n"
1381 "certificate using an\n"
1383 " INQUIRE TARGETCERT\n"
1385 "and the caller is expected to return the certificate for the\n"
1386 "request (which should match FINGERPRINT) as a binary blob.\n"
1387 "Processing then takes place without further interaction; in\n"
1388 "particular dirmngr tries to locate other required certificates by\n"
1389 "its own mechanism which includes a local certificate store as well\n"
1390 "as a list of trusted root certificates.\n"
1392 "If the option --force-default-responder is given, only the default\n"
1393 "OCSP responder will be used and any other methods of obtaining an\n"
1394 "OCSP responder URL won't be used.\n"
1396 "The return value is the usual gpg-error code or 0 for ducesss;\n"
1397 "i.e. the certificate validity has been confirmed by a valid CRL.";
1399 cmd_checkocsp (assuan_context_t ctx, char *line)
1401 ctrl_t ctrl = assuan_get_pointer (ctx);
1403 unsigned char fprbuffer[20], *fpr;
1405 int force_default_responder;
1407 force_default_responder = has_option (line, "--force-default-responder");
1408 line = skip_options (line);
1410 fpr = get_fingerprint_from_line (line, fprbuffer);
1411 cert = fpr? get_cert_byfpr (fpr) : NULL;
1415 /* We do not have this certificate yet or the fingerprint has
1416 not been given. Inquire it from the client. */
1417 unsigned char *value = NULL;
1420 err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1421 &value, &valuelen, MAX_CERT_LENGTH);
1424 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1428 if (!valuelen) /* No data returned; return a comprehensible error. */
1429 err = gpg_error (GPG_ERR_MISSING_CERT);
1432 err = ksba_cert_new (&cert);
1434 err = ksba_cert_init_from_mem (cert, value, valuelen);
1443 if (!opt.allow_ocsp)
1444 err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1446 err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder);
1449 ksba_cert_release (cert);
1450 return leave_cmd (ctx, err);
1456 lookup_cert_by_url (assuan_context_t ctx, const char *url)
1458 ctrl_t ctrl = assuan_get_pointer (ctx);
1459 gpg_error_t err = 0;
1460 unsigned char *value = NULL;
1463 /* Fetch single certificate given it's URL. */
1464 err = fetch_cert_by_url (ctrl, url, &value, &valuelen);
1467 log_error (_("fetch_cert_by_url failed: %s\n"), gpg_strerror (err));
1471 /* Send the data, flush the buffer and then send an END. */
1472 err = assuan_send_data (ctx, value, valuelen);
1474 err = assuan_send_data (ctx, NULL, 0);
1476 err = assuan_write_line (ctx, "END");
1479 log_error (_("error sending data: %s\n"), gpg_strerror (err));
1489 /* Send the certificate, flush the buffer and then send an END. */
1491 return_one_cert (void *opaque, ksba_cert_t cert)
1493 assuan_context_t ctx = opaque;
1495 const unsigned char *der;
1498 der = ksba_cert_get_image (cert, &derlen);
1500 err = gpg_error (GPG_ERR_INV_CERT_OBJ);
1503 err = assuan_send_data (ctx, der, derlen);
1505 err = assuan_send_data (ctx, NULL, 0);
1507 err = assuan_write_line (ctx, "END");
1510 log_error (_("error sending data: %s\n"), gpg_strerror (err));
1515 /* Lookup certificates from the internal cache or using the ldap
1518 lookup_cert_by_pattern (assuan_context_t ctx, char *line,
1519 int single, int cache_only)
1521 gpg_error_t err = 0;
1523 strlist_t sl, list = NULL;
1524 int truncated = 0, truncation_forced = 0;
1526 int local_count = 0;
1528 ctrl_t ctrl = assuan_get_pointer (ctx);
1529 unsigned char *value = NULL;
1531 struct ldapserver_iter ldapserver_iter;
1532 cert_fetch_context_t fetch_context;
1534 int any_no_data = 0;
1536 /* Break the line down into an STRLIST */
1537 for (p=line; *p; line = p)
1539 while (*p && *p != ' ')
1546 sl = xtrymalloc (sizeof *sl + strlen (line));
1549 err = gpg_error_from_errno (errno);
1552 memset (sl, 0, sizeof *sl);
1553 strcpy_escaped_plus (sl->d, line);
1559 /* First look through the internal cache. The certificates returned
1560 here are not counted towards the truncation limit. */
1561 if (single && !cache_only)
1562 ; /* Do not read from the local cache in this case. */
1565 for (sl=list; sl; sl = sl->next)
1567 err = get_certs_bypattern (sl->d, return_one_cert, ctx);
1573 if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1579 else if (gpg_err_code (err) == GPG_ERR_INV_NAME && !cache_only)
1581 /* No real fault because the internal pattern lookup
1582 can't yet cope with all types of pattern. */
1590 /* Loop over all configured servers unless we want only the
1591 certificates from the cache. */
1593 for (ldapserver_iter_begin (&ldapserver_iter, ctrl);
1594 !cache_only && !ldapserver_iter_end_p (&ldapserver_iter)
1595 && ldapserver_iter.server->host && !truncation_forced;
1596 ldapserver_iter_next (&ldapserver_iter))
1598 ldap_server_t ldapserver = ldapserver_iter.server;
1601 log_debug ("cmd_lookup: trying %s:%d base=%s\n",
1602 ldapserver->host, ldapserver->port,
1603 ldapserver->base?ldapserver->base : "[default]");
1605 /* Fetch certificates matching pattern */
1606 err = start_cert_fetch (ctrl, &fetch_context, list, ldapserver);
1607 if ( gpg_err_code (err) == GPG_ERR_NO_DATA )
1610 log_debug ("cmd_lookup: no data\n");
1617 log_error (_("start_cert_fetch failed: %s\n"), gpg_strerror (err));
1621 /* Fetch the certificates for this query. */
1622 while (!truncation_forced)
1624 xfree (value); value = NULL;
1625 err = fetch_next_cert (fetch_context, &value, &valuelen);
1626 if (gpg_err_code (err) == GPG_ERR_NO_DATA )
1632 if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
1638 if (gpg_err_code (err) == GPG_ERR_EOF)
1645 err = gpg_error (GPG_ERR_BUG);
1650 log_error (_("fetch_next_cert failed: %s\n"),
1651 gpg_strerror (err));
1652 end_cert_fetch (fetch_context);
1657 log_debug ("cmd_lookup: returning one cert%s\n",
1658 truncated? " (truncated)":"");
1660 /* Send the data, flush the buffer and then send an END line
1661 as a certificate delimiter. */
1662 err = assuan_send_data (ctx, value, valuelen);
1664 err = assuan_send_data (ctx, NULL, 0);
1666 err = assuan_write_line (ctx, "END");
1669 log_error (_("error sending data: %s\n"), gpg_strerror (err));
1670 end_cert_fetch (fetch_context);
1674 if (++count >= opt.max_replies )
1676 truncation_forced = 1;
1677 log_info (_("max_replies %d exceeded\n"), opt.max_replies );
1683 end_cert_fetch (fetch_context);
1688 if (truncated || truncation_forced)
1692 sprintf (str, "%d", count);
1693 assuan_write_status (ctx, "TRUNCATED", str);
1696 if (!err && !count && !local_count && any_no_data)
1697 err = gpg_error (GPG_ERR_NO_DATA);
1700 free_strlist (list);
1705 static const char hlp_lookup[] =
1706 "LOOKUP [--url] [--single] [--cache-only] <pattern>\n"
1708 "Lookup certificates matching PATTERN. With --url the pattern is\n"
1709 "expected to be one URL.\n"
1711 "If --url is not given: To allow for multiple patterns (which are ORed)\n"
1712 "quoting is required: Spaces are translated to \"+\" or \"%20\";\n"
1713 "obviously this requires that the usual escape quoting rules are applied.\n"
1715 "If --url is given no special escaping is required because URLs are\n"
1716 "already escaped this way.\n"
1718 "If --single is given the first and only the first match will be\n"
1719 "returned. If --cache-only is _not_ given, no local query will be\n"
1722 "If --cache-only is given no external lookup is done so that only\n"
1723 "certificates from the cache may get returned.";
1725 cmd_lookup (assuan_context_t ctx, char *line)
1728 int lookup_url, single, cache_only;
1730 lookup_url = has_leading_option (line, "--url");
1731 single = has_leading_option (line, "--single");
1732 cache_only = has_leading_option (line, "--cache-only");
1733 line = skip_options (line);
1735 if (lookup_url && cache_only)
1736 err = gpg_error (GPG_ERR_NOT_FOUND);
1737 else if (lookup_url && single)
1738 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1739 else if (lookup_url)
1740 err = lookup_cert_by_url (ctx, line);
1742 err = lookup_cert_by_pattern (ctx, line, single, cache_only);
1744 return leave_cmd (ctx, err);
1748 static const char hlp_loadcrl[] =
1749 "LOADCRL [--url] <filename|url>\n"
1751 "Load the CRL in the file with name FILENAME into our cache. Note\n"
1752 "that FILENAME should be given with an absolute path because\n"
1753 "Dirmngrs cwd is not known. With --url the CRL is directly loaded\n"
1754 "from the given URL.\n"
1756 "This command is usually used by gpgsm using the invocation \"gpgsm\n"
1757 "--call-dirmngr loadcrl <filename>\". A direct invocation of Dirmngr\n"
1758 "is not useful because gpgsm might need to callback gpgsm to ask for\n"
1759 "the CA's certificate.";
1761 cmd_loadcrl (assuan_context_t ctx, char *line)
1763 ctrl_t ctrl = assuan_get_pointer (ctx);
1764 gpg_error_t err = 0;
1765 int use_url = has_leading_option (line, "--url");
1767 line = skip_options (line);
1771 ksba_reader_t reader;
1773 err = crl_fetch (ctrl, line, &reader);
1775 log_error (_("fetching CRL from '%s' failed: %s\n"),
1776 line, gpg_strerror (err));
1779 err = crl_cache_insert (ctrl, line, reader);
1781 log_error (_("processing CRL from '%s' failed: %s\n"),
1782 line, gpg_strerror (err));
1783 crl_close_reader (reader);
1790 buf = xtrymalloc (strlen (line)+1);
1792 err = gpg_error_from_syserror ();
1795 strcpy_escaped_plus (buf, line);
1796 err = crl_cache_load (ctrl, buf);
1801 return leave_cmd (ctx, err);
1805 static const char hlp_listcrls[] =
1808 "List the content of all CRLs in a readable format. This command is\n"
1809 "usually used by gpgsm using the invocation \"gpgsm --call-dirmngr\n"
1810 "listcrls\". It may also be used directly using \"dirmngr\n"
1813 cmd_listcrls (assuan_context_t ctx, char *line)
1820 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
1822 err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
1825 err = crl_cache_list (fp);
1828 return leave_cmd (ctx, err);
1832 static const char hlp_cachecert[] =
1835 "Put a certificate into the internal cache. This command might be\n"
1836 "useful if a client knows in advance certificates required for a\n"
1837 "test and wants to make sure they get added to the internal cache.\n"
1838 "It is also helpful for debugging. To get the actual certificate,\n"
1839 "this command immediately inquires it using\n"
1841 " INQUIRE TARGETCERT\n"
1843 "and the caller is expected to return the certificate for the\n"
1844 "request as a binary blob.";
1846 cmd_cachecert (assuan_context_t ctx, char *line)
1848 ctrl_t ctrl = assuan_get_pointer (ctx);
1850 ksba_cert_t cert = NULL;
1851 unsigned char *value = NULL;
1856 err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1857 &value, &valuelen, MAX_CERT_LENGTH);
1860 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1864 if (!valuelen) /* No data returned; return a comprehensible error. */
1865 err = gpg_error (GPG_ERR_MISSING_CERT);
1868 err = ksba_cert_new (&cert);
1870 err = ksba_cert_init_from_mem (cert, value, valuelen);
1876 err = cache_cert (cert);
1879 ksba_cert_release (cert);
1880 return leave_cmd (ctx, err);
1884 static const char hlp_validate[] =
1885 "VALIDATE [--systrust] [--tls] [--no-crl]\n"
1887 "Validate a certificate using the certificate validation function\n"
1888 "used internally by dirmngr. This command is only useful for\n"
1889 "debugging. To get the actual certificate, this command immediately\n"
1890 "inquires it using\n"
1892 " INQUIRE TARGETCERT\n"
1894 "and the caller is expected to return the certificate for the\n"
1895 "request as a binary blob. The option --tls modifies this by asking\n"
1896 "for list of certificates with\n"
1898 " INQUIRE CERTLIST\n"
1900 "Here the first certificate is the target certificate, the remaining\n"
1901 "certificates are suggested intermediary certificates. All certificates\n"
1902 "need to be PEM encoded.\n"
1904 "The option --systrust changes the behaviour to include the system\n"
1905 "provided root certificates as trust anchors. The option --no-crl\n"
1908 cmd_validate (assuan_context_t ctx, char *line)
1910 ctrl_t ctrl = assuan_get_pointer (ctx);
1912 ksba_cert_t cert = NULL;
1913 certlist_t certlist = NULL;
1914 unsigned char *value = NULL;
1916 int systrust_mode, tls_mode, no_crl;
1918 systrust_mode = has_option (line, "--systrust");
1919 tls_mode = has_option (line, "--tls");
1920 no_crl = has_option (line, "--no-crl");
1921 line = skip_options (line);
1924 err = assuan_inquire (ctrl->server_local->assuan_ctx, "CERTLIST",
1925 &value, &valuelen, MAX_CERTLIST_LENGTH);
1927 err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1928 &value, &valuelen, MAX_CERT_LENGTH);
1931 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1935 if (!valuelen) /* No data returned; return a comprehensible error. */
1936 err = gpg_error (GPG_ERR_MISSING_CERT);
1941 fp = es_fopenmem_init (0, "rb", value, valuelen);
1943 err = gpg_error_from_syserror ();
1946 err = read_certlist_from_stream (&certlist, fp);
1948 if (!err && !certlist)
1949 err = gpg_error (GPG_ERR_MISSING_CERT);
1952 /* Extract the first certificate from the list. */
1953 cert = certlist->cert;
1954 ksba_cert_ref (cert);
1960 err = ksba_cert_new (&cert);
1962 err = ksba_cert_init_from_mem (cert, value, valuelen);
1970 /* If we have this certificate already in our cache, use the
1971 * cached version for validation because this will take care of
1972 * any cached results. We don't need to do this in tls mode
1973 * because this has already been done for certificate in a
1975 unsigned char fpr[20];
1976 ksba_cert_t tmpcert;
1978 cert_compute_fpr (cert, fpr);
1979 tmpcert = get_cert_byfpr (fpr);
1982 ksba_cert_release (cert);
1987 /* Quick hack to make verification work by inserting the supplied
1988 * certs into the cache. */
1989 if (tls_mode && certlist)
1993 for (cl = certlist->next; cl; cl = cl->next)
1994 cache_cert (cl->cert);
1997 err = validate_cert_chain (ctrl, cert, NULL,
1998 (VALIDATE_FLAG_TRUST_CONFIG
1999 | (tls_mode ? VALIDATE_FLAG_TLS : 0)
2000 | (systrust_mode ? VALIDATE_FLAG_TRUST_SYSTEM : 0)
2001 | (no_crl ? VALIDATE_FLAG_NOCRLCHECK : 0)),
2005 ksba_cert_release (cert);
2006 release_certlist (certlist);
2007 return leave_cmd (ctx, err);
2012 /* Parse an keyserver URI and store it in a new uri item which is
2013 returned at R_ITEM. On error return an error code. */
2015 make_keyserver_item (const char *uri, uri_item_t *r_item)
2022 /* We used to have DNS CNAME redirection from the URLs below to
2023 * sks-keyserver. pools. The idea was to allow for a quick way to
2024 * switch to a different set of pools. The problem with that
2025 * approach is that TLS needs to verify the hostname and - because
2026 * DNS is not secured - it can only check the user supplied hostname
2027 * and not a hostname from a CNAME RR. Thus the final server all
2028 * need to have certificates with the actual pool name as well as
2029 * for keys.gnupg.net - that would render the advantage of
2030 * keys.gnupg.net useless and so we better give up on this. Because
2031 * the keys.gnupg.net URL are still in widespread use we do a static
2034 if (!strcmp (uri, "hkps://keys.gnupg.net")
2035 || !strcmp (uri, "keys.gnupg.net"))
2036 uri = "hkps://hkps.pool.sks-keyservers.net";
2037 else if (!strcmp (uri, "https://keys.gnupg.net"))
2038 uri = "https://hkps.pool.sks-keyservers.net";
2039 else if (!strcmp (uri, "hkp://keys.gnupg.net"))
2040 uri = "hkp://hkps.pool.sks-keyservers.net";
2041 else if (!strcmp (uri, "http://keys.gnupg.net"))
2042 uri = "http://hkps.pool.sks-keyservers.net";
2043 else if (!strcmp (uri, "hkps://http-keys.gnupg.net")
2044 || !strcmp (uri, "http-keys.gnupg.net"))
2045 uri = "hkps://ha.pool.sks-keyservers.net";
2046 else if (!strcmp (uri, "https://http-keys.gnupg.net"))
2047 uri = "https://ha.pool.sks-keyservers.net";
2048 else if (!strcmp (uri, "hkp://http-keys.gnupg.net"))
2049 uri = "hkp://ha.pool.sks-keyservers.net";
2050 else if (!strcmp (uri, "http://http-keys.gnupg.net"))
2051 uri = "http://ha.pool.sks-keyservers.net";
2053 item = xtrymalloc (sizeof *item + strlen (uri));
2055 return gpg_error_from_syserror ();
2058 item->parsed_uri = NULL;
2059 strcpy (item->uri, uri);
2062 if (ldap_uri_p (item->uri))
2063 err = ldap_parse_uri (&item->parsed_uri, uri);
2067 err = http_parse_uri (&item->parsed_uri, uri, 1);
2078 /* If no keyserver is stored in CTRL but a global keyserver has been
2079 set, put that global keyserver into CTRL. We need use this
2080 function to help migrate from the old gpg based keyserver
2081 configuration to the new dirmngr based configuration. */
2083 ensure_keyserver (ctrl_t ctrl)
2087 uri_item_t onion_items = NULL;
2088 uri_item_t plain_items = NULL;
2092 if (ctrl->server_local->keyservers)
2093 return 0; /* Already set for this session. */
2096 /* No global option set. Fall back to default: */
2097 return make_keyserver_item (DIRMNGR_DEFAULT_KEYSERVER,
2098 &ctrl->server_local->keyservers);
2101 for (sl = opt.keyserver; sl; sl = sl->next)
2103 err = make_keyserver_item (sl->d, &item);
2106 if (item->parsed_uri->onion)
2108 item->next = onion_items;
2113 item->next = plain_items;
2118 /* Decide which to use. Note that the session has no keyservers
2120 if (onion_items && !onion_items->next && plain_items && !plain_items->next)
2122 /* If there is just one onion and one plain keyserver given, we take
2123 only one depending on whether Tor is running or not. */
2124 if (is_tor_running (ctrl))
2126 ctrl->server_local->keyservers = onion_items;
2131 ctrl->server_local->keyservers = plain_items;
2135 else if (!is_tor_running (ctrl))
2137 /* Tor is not running. It does not make sense to add Onion
2139 ctrl->server_local->keyservers = plain_items;
2144 /* In all other cases add all keyservers. */
2145 ctrl->server_local->keyservers = onion_items;
2147 for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next)
2150 ui->next = plain_items;
2152 ctrl->server_local->keyservers = plain_items;
2157 release_uri_item_list (onion_items);
2158 release_uri_item_list (plain_items);
2164 static const char hlp_keyserver[] =
2165 "KEYSERVER [<options>] [<uri>|<host>]\n"
2168 " --clear Remove all configured keyservers\n"
2169 " --resolve Resolve HKP host names and rotate\n"
2170 " --hosttable Print table of known hosts and pools\n"
2171 " --dead Mark <host> as dead\n"
2172 " --alive Mark <host> as alive\n"
2174 "If called without arguments list all configured keyserver URLs.\n"
2175 "If called with an URI add this as keyserver. Note that keyservers\n"
2176 "are configured on a per-session base. A default keyserver may already be\n"
2177 "present, thus the \"--clear\" option must be used to get full control.\n"
2178 "If \"--clear\" and an URI are used together the clear command is\n"
2179 "obviously executed first. A RESET command does not change the list\n"
2180 "of configured keyservers.";
2182 cmd_keyserver (assuan_context_t ctx, char *line)
2184 ctrl_t ctrl = assuan_get_pointer (ctx);
2185 gpg_error_t err = 0;
2186 int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
2187 int dead_flag, alive_flag;
2188 uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
2189 is always initialized. */
2191 clear_flag = has_option (line, "--clear");
2192 help_flag = has_option (line, "--help");
2193 resolve_flag = has_option (line, "--resolve");
2194 host_flag = has_option (line, "--hosttable");
2195 dead_flag = has_option (line, "--dead");
2196 alive_flag = has_option (line, "--alive");
2197 line = skip_options (line);
2202 err = ks_action_help (ctrl, line);
2208 err = ensure_keyserver (ctrl);
2211 assuan_set_error (ctx, err,
2212 "Bad keyserver configuration in dirmngr.conf");
2215 err = ks_action_resolve (ctrl, ctrl->server_local->keyservers);
2220 if (alive_flag && dead_flag)
2222 err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies");
2227 err = check_owner_permission (ctx, "no permission to use --dead");
2231 if (alive_flag || dead_flag)
2235 err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing");
2239 err = ks_hkp_mark_host (ctrl, line, alive_flag);
2246 err = ks_hkp_print_hosttable (ctrl);
2250 if (resolve_flag || host_flag || alive_flag || dead_flag)
2255 err = make_keyserver_item (line, &item);
2260 release_ctrl_keyservers (ctrl);
2263 item->next = ctrl->server_local->keyservers;
2264 ctrl->server_local->keyservers = item;
2267 if (!add_flag && !clear_flag && !help_flag)
2269 /* List configured keyservers. However, we first add a global
2273 err = ensure_keyserver (ctrl);
2276 assuan_set_error (ctx, err,
2277 "Bad keyserver configuration in dirmngr.conf");
2281 for (u=ctrl->server_local->keyservers; u; u = u->next)
2282 dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
2287 return leave_cmd (ctx, err);
2292 static const char hlp_ks_search[] =
2293 "KS_SEARCH {<pattern>}\n"
2295 "Search the configured OpenPGP keyservers (see command KEYSERVER)\n"
2296 "for keys matching PATTERN";
2298 cmd_ks_search (assuan_context_t ctx, char *line)
2300 ctrl_t ctrl = assuan_get_pointer (ctx);
2306 if (has_option (line, "--quick"))
2307 ctrl->timeout = opt.connect_quick_timeout;
2308 line = skip_options (line);
2310 /* Break the line down into an strlist. Each pattern is
2311 percent-plus escaped. */
2313 for (p=line; *p; line = p)
2315 while (*p && *p != ' ')
2321 sl = xtrymalloc (sizeof *sl + strlen (line));
2324 err = gpg_error_from_syserror ();
2328 strcpy_escaped_plus (sl->d, line);
2334 err = ensure_keyserver (ctrl);
2338 /* Setup an output stream and perform the search. */
2339 outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2341 err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2344 err = ks_action_search (ctrl, ctrl->server_local->keyservers,
2350 free_strlist (list);
2351 return leave_cmd (ctx, err);
2356 static const char hlp_ks_get[] =
2357 "KS_GET {<pattern>}\n"
2359 "Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
2360 "(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
2361 "or an exact name indicated by the '=' prefix.";
2363 cmd_ks_get (assuan_context_t ctx, char *line)
2365 ctrl_t ctrl = assuan_get_pointer (ctx);
2371 if (has_option (line, "--quick"))
2372 ctrl->timeout = opt.connect_quick_timeout;
2373 line = skip_options (line);
2375 /* Break the line into a strlist. Each pattern is by
2376 definition percent-plus escaped. However we only support keyids
2377 and fingerprints and thus the client has no need to apply the
2380 for (p=line; *p; line = p)
2382 while (*p && *p != ' ')
2388 sl = xtrymalloc (sizeof *sl + strlen (line));
2391 err = gpg_error_from_syserror ();
2395 strcpy_escaped_plus (sl->d, line);
2401 err = ensure_keyserver (ctrl);
2405 /* Setup an output stream and perform the get. */
2406 outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2408 err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2411 ctrl->server_local->inhibit_data_logging = 1;
2412 ctrl->server_local->inhibit_data_logging_now = 0;
2413 ctrl->server_local->inhibit_data_logging_count = 0;
2414 err = ks_action_get (ctrl, ctrl->server_local->keyservers, list, outfp);
2416 ctrl->server_local->inhibit_data_logging = 0;
2420 free_strlist (list);
2421 return leave_cmd (ctx, err);
2425 static const char hlp_ks_fetch[] =
2428 "Get the key(s) from URL.";
2430 cmd_ks_fetch (assuan_context_t ctx, char *line)
2432 ctrl_t ctrl = assuan_get_pointer (ctx);
2436 if (has_option (line, "--quick"))
2437 ctrl->timeout = opt.connect_quick_timeout;
2438 line = skip_options (line);
2440 err = ensure_keyserver (ctrl); /* FIXME: Why do we needs this here? */
2444 /* Setup an output stream and perform the get. */
2445 outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2447 err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2450 ctrl->server_local->inhibit_data_logging = 1;
2451 ctrl->server_local->inhibit_data_logging_now = 0;
2452 ctrl->server_local->inhibit_data_logging_count = 0;
2453 err = ks_action_fetch (ctrl, line, outfp);
2455 ctrl->server_local->inhibit_data_logging = 0;
2459 return leave_cmd (ctx, err);
2464 static const char hlp_ks_put[] =
2467 "Send a key to the configured OpenPGP keyservers. The actual key material\n"
2468 "is then requested by Dirmngr using\n"
2470 " INQUIRE KEYBLOCK\n"
2472 "The client shall respond with a binary version of the keyblock (e.g.,\n"
2473 "the output of `gpg --export KEYID'). For LDAP\n"
2474 "keyservers Dirmngr may ask for meta information of the provided keyblock\n"
2477 " INQUIRE KEYBLOCK_INFO\n"
2479 "The client shall respond with a colon delimited info lines (the output\n"
2480 "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n";
2482 cmd_ks_put (assuan_context_t ctx, char *line)
2484 ctrl_t ctrl = assuan_get_pointer (ctx);
2486 unsigned char *value = NULL;
2488 unsigned char *info = NULL;
2491 /* No options for now. */
2492 line = skip_options (line);
2494 err = ensure_keyserver (ctrl);
2498 /* Ask for the key material. */
2499 err = assuan_inquire (ctx, "KEYBLOCK",
2500 &value, &valuelen, MAX_KEYBLOCK_LENGTH);
2503 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2507 if (!valuelen) /* No data returned; return a comprehensible error. */
2509 err = gpg_error (GPG_ERR_MISSING_CERT);
2513 /* Ask for the key meta data. Not actually needed for HKP servers
2514 but we do it anyway to test the client implementation. */
2515 err = assuan_inquire (ctx, "KEYBLOCK_INFO",
2516 &info, &infolen, MAX_KEYBLOCK_LENGTH);
2519 log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2524 err = ks_action_put (ctrl, ctrl->server_local->keyservers,
2525 value, valuelen, info, infolen);
2530 return leave_cmd (ctx, err);
2535 static const char hlp_loadswdb[] =
2536 "LOADSWDB [--force]\n"
2538 "Load and verify the swdb.lst from the Net.";
2540 cmd_loadswdb (assuan_context_t ctx, char *line)
2542 ctrl_t ctrl = assuan_get_pointer (ctx);
2545 err = dirmngr_load_swdb (ctrl, has_option (line, "--force"));
2547 return leave_cmd (ctx, err);
2552 static const char hlp_getinfo[] =
2555 "Multi purpose command to return certain information. \n"
2556 "Supported values of WHAT are:\n"
2558 "version - Return the version of the program.\n"
2559 "pid - Return the process id of the server.\n"
2560 "tor - Return OK if running in Tor mode\n"
2561 "dnsinfo - Return info about the DNS resolver\n"
2562 "socket_name - Return the name of the socket.\n"
2563 "session_id - Return the current session_id.\n"
2564 "workqueue - Inspect the work queue\n"
2565 "getenv NAME - Return value of envvar NAME\n";
2567 cmd_getinfo (assuan_context_t ctx, char *line)
2569 ctrl_t ctrl = assuan_get_pointer (ctx);
2573 if (!strcmp (line, "version"))
2575 const char *s = VERSION;
2576 err = assuan_send_data (ctx, s, strlen (s));
2578 else if (!strcmp (line, "pid"))
2580 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
2581 err = assuan_send_data (ctx, numbuf, strlen (numbuf));
2583 else if (!strcmp (line, "socket_name"))
2585 const char *s = dirmngr_get_current_socket_name ();
2586 err = assuan_send_data (ctx, s, strlen (s));
2588 else if (!strcmp (line, "session_id"))
2590 snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id);
2591 err = assuan_send_data (ctx, numbuf, strlen (numbuf));
2593 else if (!strcmp (line, "tor"))
2597 use_tor = dirmngr_use_tor ();
2600 if (!is_tor_running (ctrl))
2601 err = assuan_write_status (ctx, "NO_TOR", "Tor not running");
2605 assuan_set_okay_line (ctx, use_tor == 1 ? "- Tor mode is enabled"
2606 /**/ : "- Tor mode is enforced");
2609 err = set_error (GPG_ERR_FALSE, "Tor mode is NOT enabled");
2611 else if (!strcmp (line, "dnsinfo"))
2613 if (standard_resolver_p ())
2614 assuan_set_okay_line
2615 (ctx, "- Forced use of System resolver (w/o Tor support)");
2619 assuan_set_okay_line (ctx, (recursive_resolver_p ()
2620 ? "- Libdns recursive resolver"
2621 : "- Libdns stub resolver"));
2623 assuan_set_okay_line (ctx, "- System resolver (w/o Tor support)");
2628 else if (!strcmp (line, "workqueue"))
2630 workqueue_dump_queue (ctrl);
2633 else if (!strncmp (line, "getenv", 6)
2634 && (line[6] == ' ' || line[6] == '\t' || !line[6]))
2637 while (*line == ' ' || *line == '\t')
2640 err = gpg_error (GPG_ERR_MISSING_VALUE);
2643 const char *s = getenv (line);
2645 err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
2647 err = assuan_send_data (ctx, s, strlen (s));
2651 err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
2653 return leave_cmd (ctx, err);
2658 static const char hlp_killdirmngr[] =
2661 "This command allows a user - given sufficient permissions -\n"
2662 "to kill this dirmngr process.\n";
2664 cmd_killdirmngr (assuan_context_t ctx, char *line)
2666 ctrl_t ctrl = assuan_get_pointer (ctx);
2670 ctrl->server_local->stopme = 1;
2671 assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
2672 return gpg_error (GPG_ERR_EOF);
2676 static const char hlp_reloaddirmngr[] =
2679 "This command is an alternative to SIGHUP\n"
2680 "to reload the configuration.";
2682 cmd_reloaddirmngr (assuan_context_t ctx, char *line)
2687 dirmngr_sighup_action ();
2692 static const char hlp_flushcrls[] =
2695 "Remove all cached CRLs from memory and\n"
2698 cmd_flushcrls (assuan_context_t ctx, char *line)
2702 return leave_cmd (ctx, crl_cache_flush () ? GPG_ERR_GENERAL : 0);
2707 /* Tell the assuan library about our commands. */
2709 register_commands (assuan_context_t ctx)
2713 assuan_handler_t handler;
2714 const char * const help;
2716 { "DNS_CERT", cmd_dns_cert, hlp_dns_cert },
2717 { "WKD_GET", cmd_wkd_get, hlp_wkd_get },
2718 { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
2719 { "ISVALID", cmd_isvalid, hlp_isvalid },
2720 { "CHECKCRL", cmd_checkcrl, hlp_checkcrl },
2721 { "CHECKOCSP", cmd_checkocsp, hlp_checkocsp },
2722 { "LOOKUP", cmd_lookup, hlp_lookup },
2723 { "LOADCRL", cmd_loadcrl, hlp_loadcrl },
2724 { "LISTCRLS", cmd_listcrls, hlp_listcrls },
2725 { "CACHECERT", cmd_cachecert, hlp_cachecert },
2726 { "VALIDATE", cmd_validate, hlp_validate },
2727 { "KEYSERVER", cmd_keyserver, hlp_keyserver },
2728 { "KS_SEARCH", cmd_ks_search, hlp_ks_search },
2729 { "KS_GET", cmd_ks_get, hlp_ks_get },
2730 { "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch },
2731 { "KS_PUT", cmd_ks_put, hlp_ks_put },
2732 { "GETINFO", cmd_getinfo, hlp_getinfo },
2733 { "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
2734 { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
2735 { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
2736 { "FLUSHCRLS", cmd_flushcrls, hlp_flushcrls },
2741 for (i=j=0; table[i].name; i++)
2743 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
2752 /* Note that we do not reset the list of configured keyservers. */
2754 reset_notify (assuan_context_t ctx, char *line)
2756 ctrl_t ctrl = assuan_get_pointer (ctx);
2760 ldapserver_list_free (ctrl->server_local->ldapservers);
2762 ctrl->server_local->ldapservers = NULL;
2767 /* This function is called by our assuan log handler to test whether a
2768 * log message shall really be printed. The function must return
2769 * false to inhibit the logging of MSG. CAT gives the requested log
2770 * category. MSG might be NULL. */
2772 dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
2775 ctrl_t ctrl = assuan_get_pointer (ctx);
2780 if (!ctrl || !ctrl->server_local)
2781 return 1; /* Can't decide - allow logging. */
2783 if (!ctrl->server_local->inhibit_data_logging)
2784 return 1; /* Not requested - allow logging. */
2786 /* Disallow logging if *_now is true. */
2787 return !ctrl->server_local->inhibit_data_logging_now;
2791 /* Startup the server and run the main command loop. With FD = -1,
2792 * use stdin/stdout. SESSION_ID is either 0 or a unique number
2793 * identifying a session. */
2795 start_command_handler (assuan_fd_t fd, unsigned int session_id)
2797 static const char hello[] = "Dirmngr " VERSION " at your service";
2798 static char *hello_line;
2800 assuan_context_t ctx;
2803 ctrl = xtrycalloc (1, sizeof *ctrl);
2805 ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
2806 if (!ctrl || !ctrl->server_local)
2808 log_error (_("can't allocate control structure: %s\n"),
2814 dirmngr_init_default_ctrl (ctrl);
2816 rc = assuan_new (&ctx);
2819 log_error (_("failed to allocate assuan context: %s\n"),
2824 if (fd == ASSUAN_INVALID_FD)
2826 assuan_fd_t filedes[2];
2828 filedes[0] = assuan_fdopen (0);
2829 filedes[1] = assuan_fdopen (1);
2830 rc = assuan_init_pipe_server (ctx, filedes);
2834 rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
2839 assuan_release (ctx);
2840 log_error (_("failed to initialize the server: %s\n"),
2845 rc = register_commands (ctx);
2848 log_error (_("failed to the register commands with Assuan: %s\n"),
2856 hello_line = xtryasprintf
2861 opt.config_filename? opt.config_filename : "[none]",
2865 ctrl->server_local->assuan_ctx = ctx;
2866 assuan_set_pointer (ctx, ctrl);
2868 assuan_set_hello_line (ctx, hello_line);
2869 assuan_register_option_handler (ctx, option_handler);
2870 assuan_register_reset_notify (ctx, reset_notify);
2872 ctrl->server_local->session_id = session_id;
2876 rc = assuan_accept (ctx);
2881 log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
2885 #ifndef HAVE_W32_SYSTEM
2888 assuan_peercred_t peercred;
2890 if (!assuan_get_peercred (ctx, &peercred))
2891 log_info ("connection from process %ld (%ld:%ld)\n",
2892 (long)peercred->pid, (long)peercred->uid,
2893 (long)peercred->gid);
2897 rc = assuan_process (ctx);
2900 log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
2907 ldap_wrapper_connection_cleanup (ctrl);
2909 ldapserver_list_free (ctrl->server_local->ldapservers);
2911 ctrl->server_local->ldapservers = NULL;
2913 release_ctrl_keyservers (ctrl);
2915 ctrl->server_local->assuan_ctx = NULL;
2916 assuan_release (ctx);
2918 if (ctrl->server_local->stopme)
2922 log_error ("oops: connection control structure still referenced (%d)\n",
2926 release_ctrl_ocsp_certs (ctrl);
2927 xfree (ctrl->server_local);
2928 dirmngr_deinit_default_ctrl (ctrl);
2934 /* Send a status line back to the client. KEYWORD is the status
2935 keyword, the optional string arguments are blank separated added to
2936 the line, the last argument must be a NULL. */
2938 dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
2940 gpg_error_t err = 0;
2942 assuan_context_t ctx;
2944 va_start (arg_ptr, keyword);
2946 if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
2948 err = vprint_assuan_status_strings (ctx, keyword, arg_ptr);
2956 /* Print a help status line. The function splits text at LFs. */
2958 dirmngr_status_help (ctrl_t ctrl, const char *text)
2960 gpg_error_t err = 0;
2961 assuan_context_t ctx;
2963 if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
2972 for ( ; *text && *text != '\n' && n < DIM (buf)-2; n++)
2977 err = assuan_write_status (ctx, "#", buf);
2979 while (!err && *text);
2986 /* Print a help status line using a printf like format. The function
2987 * splits text at LFs. */
2989 dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
2995 va_start (arg_ptr, format);
2996 buf = es_vbsprintf (format, arg_ptr);
2997 err = buf? 0 : gpg_error_from_syserror ();
3000 err = dirmngr_status_help (ctrl, buf);
3006 /* This function is similar to print_assuan_status but takes a CTRL
3007 * arg instead of an assuan context as first argument. */
3009 dirmngr_status_printf (ctrl_t ctrl, const char *keyword,
3010 const char *format, ...)
3014 assuan_context_t ctx;
3016 if (!ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
3019 va_start (arg_ptr, format);
3020 err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
3026 /* Send a tick progress indicator back. Fixme: This is only done for
3027 the currently active channel. */
3029 dirmngr_tick (ctrl_t ctrl)
3031 static time_t next_tick = 0;
3032 gpg_error_t err = 0;
3033 time_t now = time (NULL);
3037 next_tick = now + 1;
3039 else if ( now > next_tick )
3043 err = dirmngr_status (ctrl, "PROGRESS", "tick", "? 0 0", NULL);
3046 /* Take this as in indication for a cancel request. */
3047 err = gpg_error (GPG_ERR_CANCELED);
3052 next_tick = now + 1;