/* server.c - LDAP and Keyserver access server
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
- * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011, 2015 g10 Code GmbH
+ * Copyright (C) 2014, 2015, 2016 Werner Koch
*
* This file is part of GnuPG.
*
#include <unistd.h>
#include <errno.h>
-#define JNLIB_NEED_LOG_LOGV
#include "dirmngr.h"
#include <assuan.h>
#endif
#include "ks-action.h"
#include "ks-engine.h" /* (ks_hkp_print_hosttable) */
+#if USE_LDAP
+# include "ldap-parse-uri.h"
+#endif
+#include "dns-stuff.h"
+#include "mbox-util.h"
+#include "zb32.h"
+#include "server-help.h"
/* To avoid DoS attacks we limit the size of a certificate to
- something reasonable. */
-#define MAX_CERT_LENGTH (8*1024)
+ something reasonable. The DoS was actually only an issue back when
+ Dirmngr was a system service and not a user service. */
+#define MAX_CERT_LENGTH (16*1024)
/* The same goes for OpenPGP keyblocks, but here we need to allow for
much longer blocks; a 200k keyblock is not too unusual for keys
- with a lot of signatures (e.g. 0x5b0358a2). */
-#define MAX_KEYBLOCK_LENGTH (512*1024)
+ with a lot of signatures (e.g. 0x5b0358a2). 9C31503C6D866396 even
+ has 770 KiB as of 2015-08-23. To avoid adding a runtime option we
+ now use 20MiB which should really be enough. Well, a key with
+ several pictures could be larger (the parser as a 18MiB limit for
+ attribute packets) but it won't be nice to the keyservers to send
+ them such large blobs. */
+#define MAX_KEYBLOCK_LENGTH (20*1024*1024)
#define PARM_ERROR(t) assuan_set_error (ctx, \
/* Per-session LDAP servers. */
ldap_server_t ldapservers;
+ /* Per-session list of keyservers. */
+ uri_item_t keyservers;
+
/* If this flag is set to true this dirmngr process will be
terminated after the end of this session. */
int stopme;
+
+ /* State variable private to is_tor_running. */
+ int tor_state;
};
/* Cookie definition for assuan data line output. */
-static ssize_t data_line_cookie_write (void *cookie,
- const void *buffer, size_t size);
+static gpgrt_ssize_t data_line_cookie_write (void *cookie,
+ const void *buffer, size_t size);
static int data_line_cookie_close (void *cookie);
static es_cookie_io_functions_t data_line_cookie_functions =
{
return NULL;
}
+/* Release an uri_item_t list. */
+static void
+release_uri_item_list (uri_item_t list)
+{
+ while (list)
+ {
+ uri_item_t tmp = list->next;
+ http_release_parsed_uri (list->parsed_uri);
+ xfree (list);
+ list = tmp;
+ }
+}
/* Release all configured keyserver info from CTRL. */
void
release_ctrl_keyservers (ctrl_t ctrl)
{
- while (ctrl->keyservers)
- {
- uri_item_t tmp = ctrl->keyservers->next;
- http_release_parsed_uri (ctrl->keyservers->parsed_uri);
- xfree (ctrl->keyservers);
- ctrl->keyservers = tmp;
- }
+ if (! ctrl->server_local)
+ return;
+
+ release_uri_item_list (ctrl->server_local->keyservers);
+ ctrl->server_local->keyservers = NULL;
}
/* Helper to print a message while leaving a command. */
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
-
{
if (err)
{
return err;
}
-/* A write handler used by es_fopencookie to write assuan data
- lines. */
-static ssize_t
-data_line_cookie_write (void *cookie, const void *buffer_arg, size_t size)
+
+/* This is a wrapper around assuan_send_data which makes debugging the
+ output in verbose mode easier. */
+static gpg_error_t
+data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size)
{
- assuan_context_t ctx = cookie;
const char *buffer = buffer_arg;
+ gpg_error_t err;
if (opt.verbose && buffer && size)
{
{
p = memchr (buffer, '\n', nbytes);
n = p ? (p - buffer) + 1 : nbytes;
- if (assuan_send_data (ctx, buffer, n))
+ err = assuan_send_data (ctx, buffer, n);
+ if (err)
{
gpg_err_set_errno (EIO);
- return -1;
+ return err;
}
buffer += n;
nbytes -= n;
- if (nbytes && assuan_send_data (ctx, NULL, 0)) /* Flush line. */
+ if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
{
gpg_err_set_errno (EIO);
- return -1;
+ return err;
}
}
while (nbytes);
}
else
{
- if (assuan_send_data (ctx, buffer, size))
+ err = assuan_send_data (ctx, buffer, size);
+ if (err)
{
- gpg_err_set_errno (EIO);
- return -1;
+ gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */
+ return err;
}
}
- return size;
+ return 0;
+}
+
+
+/* A write handler used by es_fopencookie to write assuan data
+ lines. */
+static gpgrt_ssize_t
+data_line_cookie_write (void *cookie, const void *buffer, size_t size)
+{
+ assuan_context_t ctx = cookie;
+
+ if (data_line_write (ctx, buffer, size))
+ return -1;
+ return (gpgrt_ssize_t)size;
}
+
static int
data_line_cookie_close (void *cookie)
{
}
-/* Check whether the option NAME appears in LINE */
+/* This fucntion returns true if a Tor server is running. The sattus
+ is cached for the current conenction. */
static int
-has_option (const char *line, const char *name)
+is_tor_running (ctrl_t ctrl)
{
- const char *s;
- int n = strlen (name);
+#if ASSUAN_VERSION_NUMBER >= 0x020402
+ /* Check whether we can connect to the proxy. We use a
+ special feature introduced with libassuan 2.4.2. */
- s = strstr (line, name);
- return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-/* Same as has_option but only considers options at the begin of the
- line. This is useful for commands which allow arbitrary strings on
- the line. */
-static int
-has_leading_option (const char *line, const char *name)
-{
- const char *s;
- int n;
+ if (!ctrl || !ctrl->server_local)
+ return 0; /* Ooops. */
- if (name[0] != '-' || name[1] != '-' || !name[2] || spacep (name+2))
- return 0;
- n = strlen (name);
- while ( *line == '-' && line[1] == '-' )
+ if (!ctrl->server_local->tor_state)
{
- s = line;
- while (*line && !spacep (line))
- line++;
- if (n == (line - s) && !strncmp (s, name, n))
- return 1;
- while (spacep (line))
- line++;
- }
- return 0;
-}
+ assuan_fd_t sock;
-
-/* Same as has_option but does only test for the name of the option
- and ignores an argument, i.e. with NAME being "--hash" it would
- return a pointer for "--hash" as well as for "--hash=foo". If
- thhere is no such option NULL is returned. The pointer returned
- points right behind the option name, this may be an equal sign, Nul
- or a space. */
-/* static const char * */
-/* has_option_name (const char *line, const char *name) */
-/* { */
-/* const char *s; */
-/* int n = strlen (name); */
-
-/* s = strstr (line, name); */
-/* return (s && (s == line || spacep (s-1)) */
-/* && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL; */
-/* } */
-
-
-/* Skip over options. It is assumed that leading spaces have been
- removed (this is the case for lines passed to a handler from
- assuan). Blanks after the options are also removed. */
-static char *
-skip_options (char *line)
-{
- while ( *line == '-' && line[1] == '-' )
- {
- while (*line && !spacep (line))
- line++;
- while (spacep (line))
- line++;
+ sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
+ if (sock == ASSUAN_INVALID_FD)
+ ctrl->server_local->tor_state = -1; /* Not running. */
+ else
+ {
+ assuan_sock_close (sock);
+ ctrl->server_local->tor_state = 1; /* Running. */
+ }
}
- return line;
+ return (ctrl->server_local->tor_state > 0);
+#else /* Libassuan < 2.4.2 */
+ return 0; /* We don't know. */
+#endif
}
option_handler (assuan_context_t ctx, const char *key, const char *value)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err = 0;
if (!strcmp (key, "force-crl-refresh"))
{
int i = *value? atoi (value) : 0;
ctrl->audit_events = i;
}
+ else if (!strcmp (key, "http-proxy"))
+ {
+ xfree (ctrl->http_proxy);
+ if (!*value || !strcmp (value, "none"))
+ ctrl->http_proxy = NULL;
+ else if (!(ctrl->http_proxy = xtrystrdup (value)))
+ err = gpg_error_from_syserror ();
+ }
+ else if (!strcmp (key, "honor-keyserver-url-used"))
+ {
+ /* Return an error if we are running in Tor mode. */
+ if (opt.use_tor)
+ err = gpg_error (GPG_ERR_FORBIDDEN);
+ }
else
- return gpg_error (GPG_ERR_UNKNOWN_OPTION);
+ err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
- return 0;
+ return err;
}
+
+\f
+static const char hlp_dns_cert[] =
+ "DNS_CERT <subtype> <name>\n"
+ "DNS_CERT --pka <user_id>\n"
+ "DNS_CERT --dane <user_id>\n"
+ "\n"
+ "Return the CERT record for <name>. <subtype> is one of\n"
+ " * Return the first record of any supported subtype\n"
+ " PGP Return the first record of subtype PGP (3)\n"
+ " IPGP Return the first record of subtype IPGP (6)\n"
+ "If the content of a certificate is available (PGP) it is returned\n"
+ "by data lines. Fingerprints and URLs are returned via status lines.\n"
+ "In --pka mode the fingerprint and if available an URL is returned.\n"
+ "In --dane mode the key is returned from RR type 61";
+static gpg_error_t
+cmd_dns_cert (assuan_context_t ctx, char *line)
+{
+ /* ctrl_t ctrl = assuan_get_pointer (ctx); */
+ gpg_error_t err = 0;
+ int pka_mode, dane_mode;
+ char *mbox = NULL;
+ char *namebuf = NULL;
+ char *encodedhash = NULL;
+ const char *name;
+ int certtype;
+ char *p;
+ void *key = NULL;
+ size_t keylen;
+ unsigned char *fpr = NULL;
+ size_t fprlen;
+ char *url = NULL;
+
+ pka_mode = has_option (line, "--pka");
+ dane_mode = has_option (line, "--dane");
+ line = skip_options (line);
+
+ if (pka_mode && dane_mode)
+ {
+ err = PARM_ERROR ("either --pka or --dane may be given");
+ goto leave;
+ }
+
+ if (pka_mode || dane_mode)
+ ; /* No need to parse here - we do this later. */
+ else
+ {
+ p = strchr (line, ' ');
+ if (!p)
+ {
+ err = PARM_ERROR ("missing arguments");
+ goto leave;
+ }
+ *p++ = 0;
+ if (!strcmp (line, "*"))
+ certtype = DNS_CERTTYPE_ANY;
+ else if (!strcmp (line, "IPGP"))
+ certtype = DNS_CERTTYPE_IPGP;
+ else if (!strcmp (line, "PGP"))
+ certtype = DNS_CERTTYPE_PGP;
+ else
+ {
+ err = PARM_ERROR ("unknown subtype");
+ goto leave;
+ }
+ while (spacep (p))
+ p++;
+ line = p;
+ if (!*line)
+ {
+ err = PARM_ERROR ("name missing");
+ goto leave;
+ }
+ }
+
+ if (opt.use_tor && (err = enable_dns_tormode (0)))
+ {
+ /* Tor mode is requested but the DNS code can't enable it. */
+ assuan_set_error (ctx, err, "error enabling Tor mode");
+ goto leave;
+ }
+
+ if (pka_mode || dane_mode)
+ {
+ char *domain; /* Points to mbox. */
+ char hashbuf[32]; /* For SHA-1 and SHA-256. */
+
+ /* We lowercase ascii characters but the DANE I-D does not allow
+ this. FIXME: Check after the release of the RFC whether to
+ change this. */
+ mbox = mailbox_from_userid (line);
+ if (!mbox || !(domain = strchr (mbox, '@')))
+ {
+ err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
+ goto leave;
+ }
+ *domain++ = 0;
+
+ if (pka_mode)
+ {
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+ encodedhash = zb32_encode (hashbuf, 8*20);
+ if (!encodedhash)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ namebuf = strconcat (encodedhash, "._pka.", domain, NULL);
+ if (!namebuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ name = namebuf;
+ certtype = DNS_CERTTYPE_IPGP;
+ }
+ else
+ {
+ /* Note: The hash is truncated to 28 bytes and we lowercase
+ the result only for aesthetic reasons. */
+ gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
+ encodedhash = bin2hex (hashbuf, 28, NULL);
+ if (!encodedhash)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ ascii_strlwr (encodedhash);
+ namebuf = strconcat (encodedhash, "._openpgpkey.", domain, NULL);
+ if (!namebuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ name = namebuf;
+ certtype = DNS_CERTTYPE_RR61;
+ }
+ }
+ else
+ name = line;
+
+ err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url);
+ if (err)
+ goto leave;
+
+ if (key)
+ {
+ err = data_line_write (ctx, key, keylen);
+ if (err)
+ goto leave;
+ }
+
+ if (fpr)
+ {
+ char *tmpstr;
+
+ tmpstr = bin2hex (fpr, fprlen, NULL);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = assuan_write_status (ctx, "FPR", tmpstr);
+ xfree (tmpstr);
+ }
+ if (err)
+ goto leave;
+ }
+
+ if (url)
+ {
+ err = assuan_write_status (ctx, "URL", url);
+ if (err)
+ goto leave;
+ }
+
+
+ leave:
+ xfree (key);
+ xfree (fpr);
+ xfree (url);
+ xfree (mbox);
+ xfree (namebuf);
+ xfree (encodedhash);
+ return leave_cmd (ctx, err);
+}
+
+
+\f
+static const char hlp_wkd_get[] =
+ "WKD_GET <user_id>\n"
+ "\n"
+ "Return the key for <user_id> from a Web Key Directory.\n";
+static gpg_error_t
+cmd_wkd_get (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err = 0;
+ char *mbox = NULL;
+ char *domain; /* Points to mbox. */
+ char sha1buf[20];
+ char *uri = NULL;
+ char *encodedhash = NULL;
+
+ line = skip_options (line);
+
+ mbox = mailbox_from_userid (line);
+ if (!mbox || !(domain = strchr (mbox, '@')))
+ {
+ err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
+ goto leave;
+ }
+ *domain++ = 0;
+
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
+ encodedhash = zb32_encode (sha1buf, 8*20);
+ if (!encodedhash)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ uri = strconcat ("https://",
+ domain,
+ "/.well-known/openpgpkey/hu/",
+ encodedhash,
+ NULL);
+ if (!uri)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ /* Setup an output stream and perform the get. */
+ {
+ estream_t outfp;
+
+ outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
+ if (!outfp)
+ err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
+ else
+ {
+ err = ks_action_fetch (ctrl, uri, outfp);
+ es_fclose (outfp);
+ }
+ }
+
+ leave:
+ xfree (uri);
+ xfree (encodedhash);
+ xfree (mbox);
+ return leave_cmd (ctx, err);
+}
+
+
+\f
static const char hlp_ldapserver[] =
"LDAPSERVER <data>\n"
"\n"
"Processing then takes place without further interaction; in\n"
"particular dirmngr tries to locate other required certificates by\n"
"its own mechanism which includes a local certificate store as well\n"
- "as a list of trusted root certifciates.\n"
+ "as a list of trusted root certificates.\n"
"\n"
"If the option --force-default-responder is given, only the default\n"
"OCSP responder will be used and any other methods of obtaining an\n"
return leave_cmd (ctx, err);
}
+
\f
+/* Parse an keyserver URI and store it in a new uri item which is
+ returned at R_ITEM. On error return an error code. */
+static gpg_error_t
+make_keyserver_item (const char *uri, uri_item_t *r_item)
+{
+ gpg_error_t err;
+ uri_item_t item;
+
+ *r_item = NULL;
+ item = xtrymalloc (sizeof *item + strlen (uri));
+ if (!item)
+ return gpg_error_from_syserror ();
+
+ item->next = NULL;
+ item->parsed_uri = NULL;
+ strcpy (item->uri, uri);
+
+#if USE_LDAP
+ if (ldap_uri_p (item->uri))
+ err = ldap_parse_uri (&item->parsed_uri, uri);
+ else
+#endif
+ {
+ err = http_parse_uri (&item->parsed_uri, uri, 1);
+ }
+
+ if (err)
+ xfree (item);
+ else
+ *r_item = item;
+ return err;
+}
+
+
+/* If no keyserver is stored in CTRL but a global keyserver has been
+ set, put that global keyserver into CTRL. We need use this
+ function to help migrate from the old gpg based keyserver
+ configuration to the new dirmngr based configuration. */
+static gpg_error_t
+ensure_keyserver (ctrl_t ctrl)
+{
+ gpg_error_t err;
+ uri_item_t item;
+ uri_item_t onion_items = NULL;
+ uri_item_t plain_items = NULL;
+ uri_item_t ui;
+ strlist_t sl;
+
+ if (ctrl->server_local->keyservers)
+ return 0; /* Already set for this session. */
+ if (!opt.keyserver)
+ return 0; /* No global option set. */
+
+ for (sl = opt.keyserver; sl; sl = sl->next)
+ {
+ err = make_keyserver_item (sl->d, &item);
+ if (err)
+ goto leave;
+ if (item->parsed_uri->onion)
+ {
+ item->next = onion_items;
+ onion_items = item;
+ }
+ else
+ {
+ item->next = plain_items;
+ plain_items = item;
+ }
+ }
+
+ /* Decide which to use. Note that the sesssion has no keyservers
+ yet set. */
+ if (onion_items && !onion_items->next && plain_items && !plain_items->next)
+ {
+ /* If there is just one onion and one plain keyserver given, we take
+ only one depending on whether Tor is running or not. */
+ if (is_tor_running (ctrl))
+ {
+ ctrl->server_local->keyservers = onion_items;
+ onion_items = NULL;
+ }
+ else
+ {
+ ctrl->server_local->keyservers = plain_items;
+ plain_items = NULL;
+ }
+ }
+ else if (!is_tor_running (ctrl))
+ {
+ /* Tor is not running. It does not make sense to add Onion
+ addresses. */
+ ctrl->server_local->keyservers = plain_items;
+ plain_items = NULL;
+ }
+ else
+ {
+ /* In all other cases add all keyservers. */
+ ctrl->server_local->keyservers = onion_items;
+ onion_items = NULL;
+ for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next)
+ ;
+ if (ui)
+ ui->next = plain_items;
+ else
+ ctrl->server_local->keyservers = plain_items;
+ plain_items = NULL;
+ }
+
+ leave:
+ release_uri_item_list (onion_items);
+ release_uri_item_list (plain_items);
+
+ return err;
+}
+
+
static const char hlp_keyserver[] =
"KEYSERVER [<options>] [<uri>|<host>]\n"
"Options are:\n"
if (resolve_flag)
{
- err = ks_action_resolve (ctrl);
+ err = ensure_keyserver (ctrl);
+ if (!err)
+ err = ks_action_resolve (ctrl, ctrl->server_local->keyservers);
if (err)
goto leave;
}
if (add_flag)
{
- item = xtrymalloc (sizeof *item + strlen (line));
- if (!item)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- item->next = NULL;
- item->parsed_uri = NULL;
- strcpy (item->uri, line);
-
- err = http_parse_uri (&item->parsed_uri, line, 1);
+ err = make_keyserver_item (line, &item);
if (err)
- {
- xfree (item);
- goto leave;
- }
+ goto leave;
}
if (clear_flag)
release_ctrl_keyservers (ctrl);
if (add_flag)
{
- item->next = ctrl->keyservers;
- ctrl->keyservers = item;
+ item->next = ctrl->server_local->keyservers;
+ ctrl->server_local->keyservers = item;
}
- if (!add_flag && !clear_flag && !help_flag) /* List configured keyservers. */
+ if (!add_flag && !clear_flag && !help_flag)
{
+ /* List configured keyservers. However, we first add a global
+ keyserver. */
uri_item_t u;
- for (u=ctrl->keyservers; u; u = u->next)
+ err = ensure_keyserver (ctrl);
+ if (err)
+ {
+ assuan_set_error (ctx, err,
+ "Bad keyserver configuration in dirmngr.conf");
+ goto leave;
+ }
+
+ for (u=ctrl->server_local->keyservers; u; u = u->next)
dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
}
err = 0;
}
}
+ err = ensure_keyserver (ctrl);
+ if (err)
+ goto leave;
+
/* Setup an output stream and perform the search. */
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
else
{
- err = ks_action_search (ctrl, list, outfp);
+ err = ks_action_search (ctrl, ctrl->server_local->keyservers,
+ list, outfp);
es_fclose (outfp);
}
"\n"
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
"(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
- "or an exact name indicastes by the '=' prefix.";
+ "or an exact name indicated by the '=' prefix.";
static gpg_error_t
cmd_ks_get (assuan_context_t ctx, char *line)
{
/* No options for now. */
line = skip_options (line);
- /* Break the line down into an strlist. Each pattern is by
+ /* Break the line into a strlist. Each pattern is by
definition percent-plus escaped. However we only support keyids
and fingerprints and thus the client has no need to apply the
escaping. */
}
}
+ err = ensure_keyserver (ctrl);
+ if (err)
+ goto leave;
+
/* Setup an output stream and perform the get. */
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
else
{
- err = ks_action_get (ctrl, list, outfp);
+ err = ks_action_get (ctrl, ctrl->server_local->keyservers, list, outfp);
es_fclose (outfp);
}
/* No options for now. */
line = skip_options (line);
+ err = ensure_keyserver (ctrl); /* FIXME: Why do we needs this here? */
+ if (err)
+ goto leave;
+
/* Setup an output stream and perform the get. */
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
es_fclose (outfp);
}
+ leave:
return leave_cmd (ctx, err);
}
"\n"
" INQUIRE KEYBLOCK\n"
"\n"
- "The client shall respond with a binary version of the keyblock. For LDAP\n"
+ "The client shall respond with a binary version of the keyblock (e.g.,\n"
+ "the output of `gpg --export KEYID'). For LDAP\n"
"keyservers Dirmngr may ask for meta information of the provided keyblock\n"
"using:\n"
"\n"
" INQUIRE KEYBLOCK_INFO\n"
"\n"
- "The client shall respond with a colon delimited info lines";
+ "The client shall respond with a colon delimited info lines (the output\n"
+ "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n";
static gpg_error_t
cmd_ks_put (assuan_context_t ctx, char *line)
{
/* No options for now. */
line = skip_options (line);
+ err = ensure_keyserver (ctrl);
+ if (err)
+ goto leave;
+
/* Ask for the key material. */
err = assuan_inquire (ctx, "KEYBLOCK",
&value, &valuelen, MAX_KEYBLOCK_LENGTH);
}
/* Ask for the key meta data. Not actually needed for HKP servers
- but we do it anyway test the client implementaion. */
+ but we do it anyway to test the client implementaion. */
err = assuan_inquire (ctx, "KEYBLOCK_INFO",
&info, &infolen, MAX_KEYBLOCK_LENGTH);
if (err)
}
/* Send the key. */
- err = ks_action_put (ctrl, value, valuelen);
+ err = ks_action_put (ctrl, ctrl->server_local->keyservers,
+ value, valuelen, info, infolen);
leave:
xfree (info);
"\n"
"version - Return the version of the program.\n"
"pid - Return the process id of the server.\n"
- "\n"
+ "tor - Return OK if running in Tor mode\n"
+ "dnsinfo - Return info about the DNS resolver\n"
"socket_name - Return the name of the socket.\n";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
if (!strcmp (line, "version"))
else
err = gpg_error (GPG_ERR_NO_DATA);
}
+ else if (!strcmp (line, "tor"))
+ {
+ if (opt.use_tor)
+ {
+ if (!is_tor_running (ctrl))
+ err = assuan_write_status (ctx, "NO_TOR", "Tor not running");
+ else
+ err = 0;
+ if (!err)
+ assuan_set_okay_line (ctx, "- Tor mode is enabled");
+ }
+ else
+ err = set_error (GPG_ERR_FALSE, "Tor mode is NOT enabled");
+ }
+ else if (!strcmp (line, "dnsinfo"))
+ {
+#if USE_ADNS && HAVE_ADNS_IF_TORMODE
+ assuan_set_okay_line (ctx, "- ADNS with Tor support");
+#elif USE_ADNS
+ assuan_set_okay_line (ctx, "- ADNS w/o Tor support");
+#else
+ assuan_set_okay_line (ctx, "- System resolver w/o Tor support");
+#endif
+ err = 0;
+ }
else
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
if (!err)
{
ctrl->server_local->stopme = 1;
+ assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
err = gpg_error (GPG_ERR_EOF);
}
return err;
{
#ifndef HAVE_W32_SYSTEM
{
- gpg_err_code_t ec;
- assuan_peercred_t cred;
-
- ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
- if (!ec && cred->uid)
- ec = GPG_ERR_EPERM; /* Only root may terminate. */
- if (ec)
- return set_error (ec, "no permission to reload this process");
+ gpg_error_t err;
+
+ err = check_owner_permission (ctx,
+ "no permission to reload this process");
+ if (err)
+ return err;
}
#endif
}
assuan_handler_t handler;
const char * const help;
} table[] = {
+ { "DNS_CERT", cmd_dns_cert, hlp_dns_cert },
+ { "WKD_GET", cmd_wkd_get, hlp_wkd_get },
{ "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
{ "ISVALID", cmd_isvalid, hlp_isvalid },
{ "CHECKCRL", cmd_checkcrl, hlp_checkcrl },
}
-/* Startup the server and run the main command loop. With FD = -1
- used stdin/stdout. */
+/* Startup the server and run the main command loop. With FD = -1,
+ use stdin/stdout. */
void
start_command_handler (assuan_fd_t fd)
{
if (!hello_line)
{
- size_t n;
- const char *cfgname;
-
- cfgname = opt.config_filename? opt.config_filename : "[none]";
-
- n = (30 + strlen (opt.homedir) + strlen (cfgname)
- + strlen (hello) + 1);
- hello_line = xmalloc (n+1);
- snprintf (hello_line, n,
- "Home: %s\n"
- "Config: %s\n"
- "%s",
- opt.homedir,
- cfgname,
- hello);
- hello_line[n] = 0;
+ hello_line = xtryasprintf
+ ("Home: %s\n"
+ "Config: %s\n"
+ "%s",
+ gnupg_homedir (),
+ opt.config_filename? opt.config_filename : "[none]",
+ hello);
}
ctrl->server_local->assuan_ctx = ctx;
}
}
+
#if USE_LDAP
ldap_wrapper_connection_cleanup (ctrl);
#endif /*USE_LDAP*/
ctrl->server_local->ldapservers = NULL;
+ release_ctrl_keyservers (ctrl);
+
ctrl->server_local->assuan_ctx = NULL;
assuan_release (ctx);
{
release_ctrl_ocsp_certs (ctrl);
xfree (ctrl->server_local);
+ dirmngr_deinit_default_ctrl (ctrl);
xfree (ctrl);
}
}