diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9bd59abfa --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +Makefile.in +aclocal.m4 +autom4te.cache/ +configure +config.h.in +config.h +common/audit-events.h +common/status-codes.h diff --git a/common/ChangeLog b/common/ChangeLog index de96b8dc8..1484ae0eb 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,15 @@ +2011-01-07 Werner Koch + + * util.h (GPG_ERR_NO_KEYSERVER): New. + + * keyserver.h (keyserver_spec): Move from ../g10/options.h to here. + + * http.c (do_parse_uri): Add arg NO_SCHEME_CHECK. Change all + callers. Support HKP and HKPS. + (_http_parse_uri): Do proper error management. + * http.h (parsed_uri_s): Add field IS_HTTP. + (http_parse_uri): Support NO_SCHEME_CHECK arg. + 2010-12-17 Werner Koch * asshelp.c (lock_spawning): Add arg VERBOSE. Improve timeout @@ -2251,7 +2263,7 @@ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010 Free Software Foundation, Inc. + 2009, 2010, 2011 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/common/http.c b/common/http.c index 1d84051a2..3d7c463b5 100644 --- a/common/http.c +++ b/common/http.c @@ -138,7 +138,8 @@ typedef unsigned long longcounter_t; typedef void * gnutls_session_t; #endif -static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part); +static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part, + int no_scheme_check); static int remove_escapes (char *string); static int insert_escapes (char *buffer, const char *string, const char *special); @@ -356,7 +357,7 @@ _http_open (http_t *r_hd, http_req_t reqtype, const char *url, hd->flags = flags; hd->tls_context = tls_context; - err = _http_parse_uri (&hd->uri, url, errsource); + err = _http_parse_uri (&hd->uri, url, 0, errsource); if (!err) err = send_request (hd, auth, proxy, srvtag, headers, errsource); @@ -368,7 +369,6 @@ _http_open (http_t *r_hd, http_req_t reqtype, const char *url, es_fclose (hd->fp_read); if (hd->fp_write) es_fclose (hd->fp_write); - http_release_parsed_uri (hd->uri); xfree (hd); } else @@ -511,18 +511,27 @@ http_get_status_code (http_t hd) /* * Parse an URI and put the result into the newly allocated RET_URI. - * The caller must always use release_parsed_uri() to releases the - * resources (even on error). + * On success the caller must use release_parsed_uri() to releases the + * resources. If NO_SCHEME_CHECK is set, the function tries to parse + * the URL in the same way it would do for an HTTP style URI. */ gpg_error_t -_http_parse_uri (parsed_uri_t * ret_uri, const char *uri, - gpg_err_source_t errsource) +_http_parse_uri (parsed_uri_t *ret_uri, const char *uri, + int no_scheme_check, gpg_err_source_t errsource) { + gpg_err_code_t ec; + *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri)); if (!*ret_uri) return gpg_err_make (errsource, gpg_err_code_from_syserror ()); strcpy ((*ret_uri)->buffer, uri); - return gpg_err_make (errsource, do_parse_uri (*ret_uri, 0)); + ec = do_parse_uri (*ret_uri, 0, no_scheme_check); + if (ec) + { + xfree (*ret_uri); + *ret_uri = NULL; + } + return gpg_err_make (errsource, ec); } void @@ -543,7 +552,7 @@ http_release_parsed_uri (parsed_uri_t uri) static gpg_err_code_t -do_parse_uri (parsed_uri_t uri, int only_local_part) +do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check) { uri_tuple_t *tail; char *p, *p2, *p3, *pp; @@ -557,6 +566,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) uri->port = 0; uri->params = uri->query = NULL; uri->use_tls = 0; + uri->is_http = 0; /* A quick validity check. */ if (strspn (p, VALID_URI_CHARS) != n) @@ -572,15 +582,24 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) *pp = tolower (*(unsigned char*)pp); uri->scheme = p; if (!strcmp (uri->scheme, "http")) - uri->port = 80; + { + uri->port = 80; + uri->is_http = 1; + } + else if (!strcmp (uri->scheme, "hkp")) + { + uri->port = 11371; + uri->is_http = 1; + } #ifdef HTTP_USE_GNUTLS - else if (!strcmp (uri->scheme, "https")) + else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps")) { uri->port = 443; + uri->is_http = 1; uri->use_tls = 1; } #endif - else + else if (!no_scheme_check) return GPG_ERR_INV_URI; /* Unsupported scheme */ p = p2; @@ -852,12 +871,11 @@ send_request (http_t hd, const char *auth, if (proxy) http_proxy = proxy; - err = _http_parse_uri (&uri, http_proxy, errsource); + err = _http_parse_uri (&uri, http_proxy, 0, errsource); if (err) { log_error ("invalid HTTP proxy (%s): %s\n", http_proxy, gpg_strerror (err)); - http_release_parsed_uri (uri); return gpg_err_make (errsource, GPG_ERR_CONFIGURATION); } @@ -1882,11 +1900,10 @@ main (int argc, char **argv) http_register_tls_callback (verify_callback); #endif /*HTTP_USE_GNUTLS*/ - rc = http_parse_uri (&uri, *argv); + rc = http_parse_uri (&uri, *argv, 0); if (rc) { log_error ("`%s': %s\n", *argv, gpg_strerror (rc)); - http_release_parsed_uri (uri); return 1; } diff --git a/common/http.h b/common/http.h index ac9cb1513..aaa2d3a13 100644 --- a/common/http.h +++ b/common/http.h @@ -23,7 +23,8 @@ #include #include "../common/estream.h" -struct uri_tuple_s { +struct uri_tuple_s +{ struct uri_tuple_s *next; const char *name; /* A pointer into name. */ char *value; /* A pointer to value (a Nul is always appended). */ @@ -36,8 +37,9 @@ typedef struct uri_tuple_s *uri_tuple_t; struct parsed_uri_s { /* All these pointers point into BUFFER; most stuff is not escaped. */ - char *scheme; /* Pointer to the scheme string (lowercase). */ - int use_tls; /* Whether TLS should be used. */ + char *scheme; /* Pointer to the scheme string (always lowercase). */ + unsigned int is_http:1; /* This is a HTTP style URI. */ + unsigned int use_tls:1; /* Whether TLS should be used. */ char *auth; /* username/password for basic auth */ char *host; /* Host (converted to lowercase). */ unsigned short port; /* Port (always set if the host is set). */ @@ -71,9 +73,9 @@ typedef struct http_context_s *http_t; void http_register_tls_callback (gpg_error_t (*cb) (http_t, void *, int)); gpg_error_t _http_parse_uri (parsed_uri_t *ret_uri, const char *uri, - gpg_err_source_t errsource); -#define http_parse_uri(a,b) \ - _http_parse_uri ((a), (b), GPG_ERR_SOURCE_DEFAULT) + int no_scheme_check, gpg_err_source_t errsource); +#define http_parse_uri(a,b,c) \ + _http_parse_uri ((a), (b), (c), GPG_ERR_SOURCE_DEFAULT) void http_release_parsed_uri (parsed_uri_t uri); diff --git a/common/keyserver.h b/common/keyserver.h index 6455e8c57..d286f7da7 100644 --- a/common/keyserver.h +++ b/common/keyserver.h @@ -1,5 +1,5 @@ /* keyserver.h - Public definitions for gpg keyserver helpers. - * Copyright (C) 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -39,4 +39,26 @@ /* Must be 127 due to shell internal magic. */ #define KEYSERVER_SCHEME_NOT_FOUND 127 +/* Object to hold information pertaining to a keyserver; it further + allows to build a list of keyservers. Note that g10/options.h has + a typedef for this. FIXME: We should make use of the + parse_uri_t. */ +struct keyserver_spec +{ + struct keyserver_spec *next; + char *uri; + char *scheme; + char *auth; + char *host; + char *port; + char *path; + char *opaque; + strlist_t options; + struct + { + unsigned int direct_uri:1; + } flags; +}; + + #endif /*GNUPG_COMMON_KEYSERVER_H*/ diff --git a/common/util.h b/common/util.h index 7c58b15c5..1f7964fc4 100644 --- a/common/util.h +++ b/common/util.h @@ -36,6 +36,9 @@ #ifndef GPG_ERR_MISSING_ISSUER_CERT #define GPG_ERR_MISSING_ISSUER_CERT 185 #endif +#ifndef GPG_ERR_NO_KEYSERVER +#define GPG_ERR_NO_KEYSERVER 186 +#endif #ifndef GPG_ERR_FULLY_CANCELED #define GPG_ERR_FULLY_CANCELED 198 #endif diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog index 2c208755d..f5b3dea12 100644 --- a/dirmngr/ChangeLog +++ b/dirmngr/ChangeLog @@ -1,3 +1,20 @@ +2011-01-06 Werner Koch + + * server.c (release_ctrl_keyservers): New. + (cmd_keyserver): New. + + * dirmngr.h (uri_item_t): New. + (struct server_control_s): Add field KEYSERVERS. + +2011-01-04 Werner Koch + + * ks-engine-hkp.c: New. + * ks-engine.h: New. + * ks-action.c, ks-action.h: New. + * server.c: Include ks-action.h. + (cmd_ks_search): New. + * Makefile.am (dirmngr_SOURCES): Add new files. + 2010-12-14 Werner Koch * cdb.h (struct cdb) [W32]: Add field CDB_MAPPING. @@ -1488,7 +1505,8 @@ [Update after merge with GnuPG: see ./ChangeLog.1] - Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 g10 Code GmbH + Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index 5b1fe30be..8c41c53b2 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -49,7 +49,8 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ ldapserver.h ldapserver.c certcache.c certcache.h \ cdb.h cdblib.c ldap.c misc.c dirmngr-err.h w32-ldap-help.h \ - ocsp.c ocsp.h validate.c validate.h ldap-wrapper.h $(ldap_url) + ocsp.c ocsp.h validate.c validate.h ldap-wrapper.h $(ldap_url) \ + ks-action.c ks-action.h ks-engine.h ks-engine-hkp.c if USE_LDAPWRAPPER dirmngr_SOURCES += ldap-wrapper.c diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 83897a698..057742389 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -160,7 +160,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) *reader = NULL; once_more: - err = http_parse_uri (&uri, url); + err = http_parse_uri (&uri, url, 0); http_release_parsed_uri (uri); if (err && url && !strncmp (url, "https:", 6)) { @@ -172,7 +172,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) if (free_this) { strcpy (stpcpy (free_this,"http:"), url+6); - err = http_parse_uri (&uri, free_this); + err = http_parse_uri (&uri, free_this, 0); http_release_parsed_uri (uri); if (!err) { diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 01478a64f..1ba90b8ed 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -32,7 +32,7 @@ #include "../common/membuf.h" #include "../common/sysutils.h" /* (gnupg_fd_t) */ #include "../common/i18n.h" - +#include "../common/http.h" /* (parsed_uri_t) */ /* This objects keeps information about a particular LDAP server and is used as item of a single linked list of servers. */ @@ -49,6 +49,17 @@ struct ldap_server_s typedef struct ldap_server_s *ldap_server_t; +/* This objects is used to build a list of URI consisting of the + original and the parsed URI. */ +struct uri_item_s +{ + struct uri_item_s *next; + parsed_uri_t parsed_uri; /* The broken down URI. */ + char uri[1]; /* The original URI. */ +}; +typedef struct uri_item_s *uri_item_t; + + /* A list of fingerprints. */ struct fingerprint_list_s; typedef struct fingerprint_list_s *fingerprint_list_t; @@ -163,6 +174,7 @@ struct server_control_s response. */ int audit_events; /* Send audit events to client. */ + uri_item_t keyservers; /* List of keyservers. */ }; diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c new file mode 100644 index 000000000..5ad4b1810 --- /dev/null +++ b/dirmngr/ks-action.c @@ -0,0 +1,90 @@ +/* ks-action.c - OpenPGP keyserver actions + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include +#include +#include +#include + +#include "dirmngr.h" +#include "misc.h" +#include "ks-engine.h" +#include "ks-action.h" + + +/* Copy all data from IN to OUT. */ +static gpg_error_t +copy_stream (estream_t in, estream_t out) +{ + char buffer[512]; + size_t nread; + + while (!es_read (in, buffer, sizeof buffer, &nread)) + { + if (!nread) + return 0; /* EOF */ + if (es_write (out, buffer, nread, NULL)) + break; + + } + return gpg_error_from_syserror (); +} + + + +/* Search all configured keyservers for keys matching PATTERNS and + write the result to the provided output stream. */ +gpg_error_t +ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp) +{ + gpg_error_t err = 0; + int any = 0; + uri_item_t uri; + estream_t infp; + + if (!patterns) + return gpg_error (GPG_ERR_NO_USER_ID); + + /* FIXME: We only take care of the first pattern. To fully support + multiple patterns we might either want to run several queries in + parallel and merge them. We also need to decide what to do with + errors - it might not be the best idea to ignore an error from + one server and silently continue with another server. For now we + stop at the first error. */ + for (uri = ctrl->keyservers; !err && uri; uri = uri->next) + { + if (uri->parsed_uri->is_http) + { + any = 1; + err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp); + if (!err) + { + err = copy_stream (infp, outfp); + es_fclose (infp); + } + } + } + + if (!any) + err = gpg_error (GPG_ERR_NO_KEYSERVER); + return err; +} + diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h new file mode 100644 index 000000000..57903398d --- /dev/null +++ b/dirmngr/ks-action.h @@ -0,0 +1,26 @@ +/* ks-action.h - OpenPGP keyserver actions definitions + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef DIRMNGR_KS_ACTION_H +#define DIRMNGR_KS_ACTION_H 1 + +gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp); + + +#endif /*DIRMNGR_KS_ACTION_H*/ diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c new file mode 100644 index 000000000..356f64348 --- /dev/null +++ b/dirmngr/ks-engine-hkp.c @@ -0,0 +1,258 @@ +/* ks-engine-hkp.c - HKP keyserver engine + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include +#include +#include +#include + +#include "dirmngr.h" +#include "misc.h" +#include "userids.h" +#include "ks-engine.h" + +/* To match the behaviour of our old gpgkeys helper code we escape + more characters than actually needed. */ +#define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" + +/* How many redirections do we allow. */ +#define MAX_REDIRECTS 2 + + +/* Search the keyserver identified by URI for keys matching PATTERN. + On success R_FP has an open stream to read the data. */ +gpg_error_t +ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, + estream_t *r_fp) +{ + gpg_error_t err; + KEYDB_SEARCH_DESC desc; + char fprbuf[2+40+1]; + const char *scheme; + char portstr[10]; + http_t http = NULL; + char *hostport = NULL; + char *request = NULL; + int redirects_left = MAX_REDIRECTS; + estream_t fp = NULL; + + *r_fp = NULL; + + /* Remove search type indicator and adjust PATTERN accordingly. + Note that HKP keyservers like the 0x to be present when searching + by keyid. We need to re-format the fingerprint and keyids so to + remove the gpg specific force-use-of-this-key flag ("!"). */ + err = classify_user_id (pattern, &desc); + if (err) + return err; + switch (desc.mode) + { + case KEYDB_SEARCH_MODE_EXACT: + case KEYDB_SEARCH_MODE_SUBSTR: + case KEYDB_SEARCH_MODE_MAIL: + case KEYDB_SEARCH_MODE_MAILSUB: + pattern = desc.u.name; + break; + case KEYDB_SEARCH_MODE_SHORT_KID: + snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]); + pattern = fprbuf; + break; + case KEYDB_SEARCH_MODE_LONG_KID: + snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX", + (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]); + pattern = fprbuf; + break; + case KEYDB_SEARCH_MODE_FPR16: + bin2hex (desc.u.fpr, 16, fprbuf); + pattern = fprbuf; + break; + case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR: + bin2hex (desc.u.fpr, 20, fprbuf); + pattern = fprbuf; + break; + default: + return gpg_error (GPG_ERR_INV_USER_ID); + } + + /* Map scheme and port. */ + if (!strcmp (uri->scheme,"hkps") || !strcmp (uri->scheme,"https")) + { + scheme = "https"; + strcpy (portstr, "443"); + } + else /* HKP or HTTP. */ + { + scheme = "http"; + strcpy (portstr, "11371"); + } + if (uri->port) + snprintf (portstr, sizeof portstr, "%hu", uri->port); + else + {} /*fixme_do_srv_lookup ()*/ + + /* Build the request string. */ + { + char *searchkey; + + hostport = strconcat (scheme, "://", + *uri->host? uri->host: "localhost", + ":", portstr, NULL); + if (!hostport) + { + err = gpg_error_from_syserror (); + goto leave; + } + + searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS); + if (!searchkey) + { + err = gpg_error_from_syserror (); + goto leave; + } + + request = strconcat (hostport, + "/pks/lookup?op=index&options=mr&search=", + searchkey, + NULL); + xfree (searchkey); + if (!request) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + + /* Send the request. */ + once_more: + err = http_open (&http, HTTP_REQ_GET, request, + /* fixme: AUTH */ NULL, + 0, + /* fixme: proxy*/ NULL, + NULL, NULL, + /*FIXME curl->srvtag*/NULL); + if (!err) + { + fp = http_get_write_ptr (http); + /* Avoid caches to get the most recent copy of the key. We set + both the Pragma and Cache-Control versions of the header, so + we're good with both HTTP 1.0 and 1.1. */ + es_fputs ("Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n", fp); + http_start_data (http); + if (es_ferror (fp)) + err = gpg_error_from_syserror (); + } + if (err) + { + /* Fixme: After a redirection we show the old host name. */ + log_error (_("error connecting to `%s': %s\n"), + hostport, gpg_strerror (err)); + goto leave; + } + + /* Wait for the response. */ + dirmngr_tick (ctrl); + err = http_wait_response (http); + if (err) + { + log_error (_("error reading HTTP response for `%s': %s\n"), + hostport, gpg_strerror (err)); + goto leave; + } + + switch (http_get_status_code (http)) + { + case 200: + break; /* Success. */ + + case 301: + case 302: + { + const char *s = http_get_header (http, "Location"); + + log_info (_("URL `%s' redirected to `%s' (%u)\n"), + request, s?s:"[none]", http_get_status_code (http)); + if (s && *s && redirects_left-- ) + { + xfree (request); + request = xtrystrdup (s); + if (request) + { + http_close (http, 0); + http = NULL; + goto once_more; + } + err = gpg_error_from_syserror (); + } + else + err = gpg_error (GPG_ERR_NO_DATA); + log_error (_("too many redirections\n")); + } + goto leave; + + default: + log_error (_("error accessing `%s': http status %u\n"), + request, http_get_status_code (http)); + err = gpg_error (GPG_ERR_NO_DATA); + goto leave; + } + + /* Start reading the response. */ + fp = http_get_read_ptr (http); + if (!fp) + { + err = gpg_error (GPG_ERR_BUG); + goto leave; + } + { + int c = es_getc (fp); + if (c == -1) + { + err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF); + log_error ("error reading response: %s\n", gpg_strerror (err)); + goto leave; + } + if (c == '<') + { + /* The document begins with a '<', assume it's a HTML + response, which we don't support. */ + err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING); + goto leave; + } + es_ungetc (c, fp); + } + + /* Return the read stream and close the HTTP context. */ + *r_fp = fp; + fp = NULL; + http_close (http, 1); + http = NULL; + + leave: + es_fclose (fp); + http_close (http, 0); + xfree (request); + xfree (hostport); + return err; +} + + diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h new file mode 100644 index 000000000..f68782f49 --- /dev/null +++ b/dirmngr/ks-engine.h @@ -0,0 +1,32 @@ +/* ks-engine.h - Keyserver engines definitions + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef DIRMNGR_KS_ENGINE_H +#define DIRMNGR_KS_ENGINE_H 1 + +#include "../common/estream.h" +#include "../common/http.h" + +/*-- ks-engine-hkp.c --*/ +gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, + estream_t *r_fp); + + + +#endif /*DIRMNGR_KS_ENGINE_H*/ diff --git a/dirmngr/server.c b/dirmngr/server.c index 11ba1fb87..40e8dabd4 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1,6 +1,6 @@ /* dirmngr.c - LDAP access * Copyright (C) 2002 Klarälvdalens Datakonsult AB - * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 g10 Code GmbH + * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH * * This file is part of DirMngr. * @@ -41,6 +41,7 @@ #include "validate.h" #include "misc.h" #include "ldap-wrapper.h" +#include "ks-action.h" /* To avoid DoS attacks we limit the size of a certificate to something reasonable. */ @@ -58,7 +59,7 @@ struct server_local_s /* Data used to associate an Assuan context with local server data */ assuan_context_t assuan_ctx; - /* Per-session LDAP serfver. */ + /* Per-session LDAP servers. */ ldap_server_t ldapservers; /* If this flag is set to true this dirmngr process will be @@ -94,6 +95,21 @@ get_ldapservers_from_ctrl (ctrl_t ctrl) } +/* 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; + } +} + + + /* Helper to print a message while leaving a command. */ static gpg_error_t leave_cmd (assuan_context_t ctx, gpg_error_t err) @@ -147,7 +163,7 @@ data_line_cookie_close (void *cookie) /* Copy the % and + escaped string S into the buffer D and replace the escape sequences. Note, that it is sufficient to allocate the target string D as long as the source string S, i.e.: strlen(s)+1. - NOte further that If S contains an escaped binary nul the resulting + Note further that if S contains an escaped binary Nul the resulting string D will contain the 0 as well as all other characters but it will be impossible to know whether this is the original EOS or a copied Nul. */ @@ -1335,6 +1351,130 @@ cmd_validate (assuan_context_t ctx, char *line) return leave_cmd (ctx, err); } + +static const char hlp_keyserver[] = + "KEYSERVER [--clear] []\n" + "\n" + "If called without arguments list all configured keyserver URLs.\n" + "If called with option \"--clear\" remove all configured keyservers\n" + "If called with an URI add this as keyserver. Note that keyservers\n" + "are configured on a per-session base. A default keyserver may already be\n" + "present, thus the \"--clear\" option must be used to get full control.\n" + "If \"--clear\" and an URI are used together the clear command is\n" + "obviously executed first. A RESET command does not change the list\n" + "of configured keyservers."; +static gpg_error_t +cmd_keyserver (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + int clear_flag, add_flag; + uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it + is always initialized. */ + + clear_flag = has_option (line, "--clear"); + line = skip_options (line); + add_flag = !!*line; + + 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); + if (err) + { + xfree (item); + goto leave; + } + } + if (clear_flag) + release_ctrl_keyservers (ctrl); + if (add_flag) + { + item->next = ctrl->keyservers; + ctrl->keyservers = item; + } + + if (!add_flag && !clear_flag) /* List configured keyservers. */ + { + uri_item_t u; + + for (u=ctrl->keyservers; u; u = u->next) + dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL); + } + err = 0; + + leave: + return leave_cmd (ctx, err); +} + + + +static const char hlp_ks_search[] = + "KS_SEARCH {}\n" + "\n" + "Search the configured OpenPGP keyservers (see command KEYSERVER)\n" + "for keys matching PATTERN"; +static gpg_error_t +cmd_ks_search (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + strlist_t list, sl; + char *p; + estream_t outfp; + + /* No options for now. */ + line = skip_options (line); + + /* Break the line down into an strlist. Each pattern is + percent-plus escaped. */ + list = NULL; + for (p=line; *p; line = p) + { + while (*p && *p != ' ') + p++; + if (*p) + *p++ = 0; + if (*line) + { + sl = xtrymalloc (sizeof *sl + strlen (line)); + if (!sl) + { + err = gpg_error_from_syserror (); + free_strlist (list); + goto leave; + } + sl->flags = 0; + strcpy_escaped_plus (sl->d, line); + sl->next = list; + list = sl; + } + } + + /* 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); + es_fclose (outfp); + } + + leave: + return leave_cmd (ctx, err); +} + + static const char hlp_getinfo[] = @@ -1469,6 +1609,8 @@ register_commands (assuan_context_t ctx) { "LISTCRLS", cmd_listcrls, hlp_listcrls }, { "CACHECERT", cmd_cachecert, hlp_cachecert }, { "VALIDATE", cmd_validate, hlp_validate }, + { "KEYSERVER", cmd_keyserver, hlp_keyserver }, + { "KS_SEARCH", cmd_ks_search, hlp_ks_search }, { "GETINFO", cmd_getinfo, hlp_getinfo }, { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr }, { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr }, @@ -1487,6 +1629,7 @@ register_commands (assuan_context_t ctx) } +/* Note that we do not reset the list of configured keyservers. */ static gpg_error_t reset_notify (assuan_context_t ctx, char *line) { @@ -1681,8 +1824,8 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...) } -/* Note, that we ignore CTRL for now but use the first connection to - send the progress info back. */ +/* Send a tick progress indicator back. Fixme: This is only does for + the currently active channel. */ gpg_error_t dirmngr_tick (ctrl_t ctrl) { diff --git a/g10/ChangeLog b/g10/ChangeLog index 0c8cbd418..1be035d39 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,18 @@ +2011-01-07 Werner Koch + + * call-dirmngr.c, call-dirmngr.h: New. + * gpg.h (server_control_s): Add DIRMNGR_LOCAL. + * gpg.c: Include call-dirmngr.h. + (gpg_deinit_default_ctrl): Call gpg_dirmngr_deinit_session_data. + +2011-01-06 Werner Koch + + * gpg.c (main): Use keyserver_spec_t. + + * options.h (struct opt): Factor definition of struct keyserver + out to ../common/keyserver.h. + (keyserver_spec_t): New. + 2010-12-09 Werner Koch * tdbio.c (tdbio_set_dbname) [W32CE]: Take care of missing errno. diff --git a/g10/Makefile.am b/g10/Makefile.am index c8fc4821e..475529c4e 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -102,6 +102,7 @@ gpg2_SOURCES = gpg.c \ helptext.c \ keyserver.c \ keyserver-internal.h \ + call-dirmngr.c call-dirmngr.h \ photoid.c photoid.h \ call-agent.c call-agent.h \ card-util.c \ diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c new file mode 100644 index 000000000..a18eb64b0 --- /dev/null +++ b/g10/call-dirmngr.c @@ -0,0 +1,256 @@ +/* call-dirmngr.c - GPG operations to the Dirmngr. + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +# include +#endif + +#include "gpg.h" +#include +#include "util.h" +#include "membuf.h" +#include "options.h" +#include "i18n.h" +#include "asshelp.h" +#include "call-dirmngr.h" + + +/* Data used to associate an session with dirmngr contexts. We can't + use a simple one to one mapping because we sometimes need two + connection s to the dirmngr; for example while doing a listing and + being in a data callback we may want to retrieve a key. The local + dirmngr data takes care of this. At the end of the session the + function dirmngr_deinit_session_data is called bu gpg.c to cleanup + these resources. Note that gpg.h defines a typedef dirmngr_local_t + for this structure. */ +struct dirmngr_local_s +{ + /* Link to other contexts which are used simultaneously. */ + struct dirmngr_local_s *next; + + /* The active Assuan context. */ + static assuan_context_t ctx; + + /* Flag set to true while an operation is running on CTX. */ + int is_active; +}; + + + +/* Deinitialize all session data of dirmngr pertaining to CTRL. */ +void +gpg_dirmngr_deinit_session_data (ctrl_t ctrl) +{ + dirmngr_local_t dml; + + while ((dml = ctrl->dirmngr_local)) + { + ctrl->dirmngr_local = dml->next; + if (dml->is_active) + log_error ("oops: trying to cleanup an active dirmngr context\n"); + else + assuan_release (dml->ctx); + xfree (dml); + } +} + + +/* Try to connect to the Dirmngr via a socket or fork it off if + possible. Handle the server's initial greeting and set global + options. */ +static gpg_error_t +create_context (ctrl_t ctrl, assuan_context_t *r_ctx) +{ + gpg_error_t err; + assuan_context_t ctx; + + *r_ctx = NULL; + err = start_new_dirmngr (&ctx, + GPG_ERR_SOURCE_DEFAULT, + opt.homedir, + NULL, + opt.verbose, DBG_ASSUAN, + NULL /*gpg_status2*/, ctrl); + if (!err) + { + keyserver_spec_t ksi; + + /* Tell the dirmngr that we want to collect audit event. */ + /* err = assuan_transact (agent_ctx, "OPTION audit-events=1", */ + /* NULL, NULL, NULL, NULL, NULL, NULL); */ + + /* Set all configured keyservers. We clear existing keyservers + so that any keyserver configured in GPG overrides keyservers + possibly configured in Dirmngr. */ + if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next) + { + char *line; + + line = xtryasprintf ("KEYSERVER%s %s", + ksi == opt.keyservers? " --clear":"", ksi->uri); + if (!line) + err = gpg_error_from_syserror (); + else + { + err = assuan_transact (ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (line); + } + } + } + + if (err) + assuan_release (ctx); + else + { + /* audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err); */ + *r_ctx = ctx; + } + + return err; +} + + +/* Get a context for accessing dirmngr. If no context is available a + new one is created and - if requred - dirmngr started. On success + an assuan context is stored at R_CTX. This Context may only be + released by means of close_context. Note that NULL is stored at + R_CTX on error. */ +static gpg_error_t +open_context (ctrl_t ctrl, assuan_context_t *r_ctx) +{ + gpg_error_t err; + dirmngr_local_t dml; + + *r_ctx = NULL; + for (;;) + { + for (dml = ctrl->dirmngr_local; dml && dml->is_active; dml = dml->next) + ; + if (dml) + { + /* Found an inactive local session - return that. */ + assert (!dml->is_active); + dml->is_active = 1; + return dml; + } + + dml = xtrycalloc (1, sizeof *dml); + if (!dml) + return gpg_error_from_syserror (); + err = create_context (ctrl, &dml->ctx); + if (err) + { + xfree (dml); + return err; + } + /* To be on the Pth thread safe site we need to add it to a + list; this is far easier than to have a lock for this + function. It should not happen anyway but the code is free + because we need it for the is_active check above. */ + dml->next = ctrl->dirmngr_local; + ctrl->dirmngr_local = dml; + } +} + + +/* Close the assuan context CTX or return it to a pool of unused + contexts. If CTX is NULL, the function does nothing. */ +static void +close_context (ctrl_t ctrl, assuan_context_t ctx) +{ + dirmngr_local_t dml; + + if (!ctx) + return; + + for (dml = ctrl->dirmngr_local; dml; dml = dml->next) + { + if (dml->ctx == ctx) + { + if (!ctx->is_active) + log_fatal ("closing inactive dirmngr context %p\n", ctx); + ctx->is_active = 0; + return; + } + } + log_fatal ("closing unknown dirmngr ctx %p\n", ctx); +} + + + + +int +gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names, + void (*cb)(void*, ksba_cert_t), void *cb_value) +{ + gpg_error_t err; + assuan_context_t ctx; + char *pattern; + char line[ASSUAN_LINELENGTH]; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + pattern = pattern_from_strlist (names); + if (!pattern) + { + if (ctx == dirmngr_ctx) + release_dirmngr (ctrl); + else + release_dirmngr2 (ctrl); + + return out_of_core (); + } + snprintf (line, DIM(line)-1, "LOOKUP%s %s", + cache_only? " --cache-only":"", pattern); + line[DIM(line)-1] = 0; + xfree (pattern); + + parm.ctrl = ctrl; + parm.ctx = ctx; + parm.cb = cb; + parm.cb_value = cb_value; + parm.error = 0; + init_membuf (&parm.data, 4096); + + rc = assuan_transact (ctx, line, lookup_cb, &parm, + NULL, NULL, lookup_status_cb, &parm); + xfree (get_membuf (&parm.data, &len)); + + if (ctx == dirmngr_ctx) + release_dirmngr (ctrl); + else + release_dirmngr2 (ctrl); + + if (rc) + return rc; + + close_context (ctrl, ctx); + return parm.error; +} diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h new file mode 100644 index 000000000..fa579ad5c --- /dev/null +++ b/g10/call-dirmngr.h @@ -0,0 +1,26 @@ +/* call-dirmngr.h - GPG operations to the Dirmngr + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef GNUPG_G10_CALL_DIRMNGR_H +#define GNUPG_G10_CALL_DIRMNGR_H + +void gpg_dirmngr_deinit_session_data (ctrl_t ctrl); + + + +#endif /*GNUPG_G10_CALL_DIRMNGR_H*/ diff --git a/g10/gpg.c b/g10/gpg.c index 4a17b2905..1866c1cc8 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1,6 +1,6 @@ /* gpg.c - The GnuPG utility (main for gpg) - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - * 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + * 2008, 2009, 2010, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -54,6 +54,7 @@ #include "exec.h" #include "gc-opt-flags.h" #include "asshelp.h" +#include "call-dirmngr.h" #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) #define MY_O_BINARY O_BINARY @@ -1822,7 +1823,7 @@ gpg_init_default_ctrl (ctrl_t ctrl) static void gpg_deinit_default_ctrl (ctrl_t ctrl) { - (void)ctrl; + gpg_dirmngr_deinit_session_data (ctrl); } @@ -2658,15 +2659,15 @@ main (int argc, char **argv) break; case oKeyServer: { - struct keyserver_spec *keyserver; - keyserver=parse_keyserver_uri(pargs.r.ret_str,0, - configname,configlineno); - if(!keyserver) - log_error(_("could not parse keyserver URL\n")); + keyserver_spec_t keyserver; + keyserver = parse_keyserver_uri (pargs.r.ret_str,0, + configname,configlineno); + if (!keyserver) + log_error (_("could not parse keyserver URL\n")); else { - keyserver->next=opt.keyserver; - opt.keyserver=keyserver; + keyserver->next = opt.keyserver; + opt.keyserver = keyserver; } } break; @@ -2853,14 +2854,14 @@ main (int argc, char **argv) break; case oDefaultKeyserverURL: { - struct keyserver_spec *keyserver; - keyserver=parse_keyserver_uri(pargs.r.ret_str,1, - configname,configlineno); - if(!keyserver) - log_error(_("could not parse keyserver URL\n")); + keyserver_spec_t keyserver; + keyserver = parse_keyserver_uri (pargs.r.ret_str,1, + configname,configlineno); + if (!keyserver) + log_error (_("could not parse keyserver URL\n")); else - free_keyserver_spec(keyserver); - + free_keyserver_spec (keyserver); + opt.def_keyserver_url = pargs.r.ret_str; } break; diff --git a/g10/gpg.h b/g10/gpg.h index 1d645ea25..29db15a45 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -48,6 +48,10 @@ /* Object used to keep state locally to server.c . */ struct server_local_s; +/* Object used to keep state locally to call-dirmngr.c . */ +struct dirmngr_local_s; +typedef struct dirmngr_local_s *dirmngr_local_t; + /* Object used to describe a keyblok node. */ typedef struct kbnode_struct *KBNODE; typedef struct kbnode_struct *kbnode_t; @@ -58,7 +62,11 @@ typedef struct kbnode_struct *kbnode_t; gpg_init_default_ctrl(). */ struct server_control_s { + /* Local data for server.c */ struct server_local_s *server_local; + + /* Local data for call-dirmngr.c */ + dirmngr_local_t dirmngr_local; }; diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index cbf3c04a8..2b1b64e35 100644 --- a/g10/keyserver-internal.h +++ b/g10/keyserver-internal.h @@ -40,7 +40,7 @@ int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid, struct keyserver_spec *keyserver); int keyserver_refresh (ctrl_t ctrl, strlist_t users); -int keyserver_search (ctrl_t ctrl, strlist_t tokens); +gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens); int keyserver_fetch (ctrl_t ctrl, strlist_t urilist); int keyserver_import_cert (ctrl_t ctrl, const char *name, unsigned char **fpr,size_t *fpr_len); diff --git a/g10/keyserver.c b/g10/keyserver.c index 422e62e78..60a117d2e 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -45,6 +45,7 @@ #ifdef USE_DNS_SRV #include "srv.h" #endif +#include "membuf.h" #ifdef HAVE_W32_SYSTEM @@ -236,9 +237,9 @@ keyserver_match(struct keyserver_spec *spec) parser any longer so it can be removed, or at least moved to keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */ -struct keyserver_spec * -parse_keyserver_uri(const char *string,int require_scheme, - const char *configname,unsigned int configlineno) +keyserver_spec_t +parse_keyserver_uri (const char *string,int require_scheme, + const char *configname,unsigned int configlineno) { int assume_hkp=0; struct keyserver_spec *keyserver; @@ -1530,6 +1531,7 @@ keyserver_spawn (ctrl_t ctrl, return ret; } + static int keyserver_work (ctrl_t ctrl, enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, @@ -1538,23 +1540,16 @@ keyserver_work (ctrl_t ctrl, { int rc=0,ret=0; - if(!keyserver) + if (!keyserver) { - log_error(_("no keyserver known (use option --keyserver)\n")); - return G10ERR_BAD_URI; + log_error (_("no keyserver known (use option --keyserver)\n")); + return gpg_error (GPG_ERR_BAD_URI); } -#ifdef DISABLE_KEYSERVER_HELPERS - - log_error(_("external keyserver calls are not supported in this build\n")); - return G10ERR_KEYSERVER; - -#else - /* Spawn a handler */ rc = keyserver_spawn (ctrl, action, list, desc, count, &ret, fpr, fpr_len, keyserver); - if(ret) + if (ret) { switch(ret) { @@ -1591,15 +1586,14 @@ keyserver_work (ctrl_t ctrl, return G10ERR_KEYSERVER; } - if(rc) + if (rc) { - log_error(_("keyserver communications error: %s\n"),g10_errstr(rc)); + log_error (_("keyserver communications error: %s\n"),g10_errstr(rc)); return rc; } return 0; -#endif /* ! DISABLE_KEYSERVER_HELPERS*/ } int @@ -1961,15 +1955,100 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users) return rc; } -int +/* Search for keys on the keyservers. The patterns are given in the + string list TOKENS. */ +gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens) { - if (tokens) - return keyserver_work (ctrl, KS_SEARCH, tokens, NULL, 0, - NULL, NULL, opt.keyserver); - return 0; + gpg_error_t err; + int rc=0,ret=0; + char *searchstr; + + /* FIXME: WORK IN PROGRESS */ + if (!tokens) + return 0; /* Return success if no patterns are given. */ + + if (!opt.keyserver) + { + log_error (_("no keyserver known (use option --keyserver)\n")); + return gpg_error (GPG_ERR_NO_KEYSERVER); + } + + /* switch(ret) */ + /* { */ + /* case KEYSERVER_SCHEME_NOT_FOUND: */ + /* log_error(_("no handler for keyserver scheme `%s'\n"), */ + /* opt.keyserver->scheme); */ + /* break; */ + + /* case KEYSERVER_NOT_SUPPORTED: */ + /* log_error(_("action `%s' not supported with keyserver " */ + /* "scheme `%s'\n"), "search", opt.keyserver->scheme); */ + /* break; */ + + /* case KEYSERVER_TIMEOUT: */ + /* log_error(_("keyserver timed out\n")); */ + /* break; */ + + /* case KEYSERVER_INTERNAL_ERROR: */ + /* default: */ + /* log_error(_("keyserver internal error\n")); */ + /* break; */ + /* } */ + + /* return gpg_error (GPG_ERR_KEYSERVER); */ + + + /* Write global options */ + + /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */ + /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */ + + /* Write per-keyserver options */ + + /* for(temp=keyserver->options;temp;temp=temp->next) */ + /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */ + + /* Which keys do we want? Remember that the gpgkeys_ program + is going to lump these together into a search string. */ + { + membuf_t mb; + strlist_t item; + + init_membuf (&mb, 1024); + for (item = tokens; item; item = item->next) + { + if (item != tokens) + put_membuf (&mb, " ", 1); + put_membuf_str (&mb, item->d); + } + put_membuf (&mb, "", 1); /* Append Nul. */ + searchstr = get_membuf (&mb, NULL); + if (!searchstr) + { + err = gpg_error_from_syserror (); + } + } + log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); + + { + estream_t fp; + err = gpg_dirmngr_ks_search (ctrl, searchstr, &fp); + + keyserver_search_prompt (ctrl, fp,searchstr); + } + + leave: + xfree(line); + xfree(searchstr); + + + *prog=exec_finish(spawn); + + return ret; } + int keyserver_fetch (ctrl_t ctrl, strlist_t urilist) { diff --git a/g10/options.h b/g10/options.h index 28a2805a9..cd0140651 100644 --- a/g10/options.h +++ b/g10/options.h @@ -1,6 +1,6 @@ /* options.h * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2010 Free Software Foundation, Inc. + * 2007, 2010, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -35,6 +35,13 @@ #endif #endif +/* Declaration of a keyserver spec type. The definition is found in + ../common/keyserver.h. */ +struct keyserver_spec; +typedef struct keyserver_spec *keyserver_spec_t; + + +/* Global options for GPG. */ EXTERN_UNLESS_MAIN_MODULE struct { @@ -130,22 +137,7 @@ struct int not_dash_escaped; int escape_from; int lock_once; - struct keyserver_spec - { - char *uri; - char *scheme; - char *auth; - char *host; - char *port; - char *path; - char *opaque; - strlist_t options; - struct - { - unsigned int direct_uri:1; - } flags; - struct keyserver_spec *next; - } *keyserver; + keyserver_spec_t keyserver; /* The list of configured keyservers. */ struct { unsigned int options; @@ -245,7 +237,7 @@ struct AKL_KEYSERVER, AKL_SPEC } type; - struct keyserver_spec *spec; + keyserver_spec_t spec; struct akl *next; } *auto_key_locate; diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c index a44f09131..dd2129051 100644 --- a/keyserver/gpgkeys_hkp.c +++ b/keyserver/gpgkeys_hkp.c @@ -687,7 +687,7 @@ main(int argc,char *argv[]) goto fail; } - if(ks_strcasecmp(opt->scheme,"hkps")==0) + if(ascii_strcasecmp(opt->scheme,"hkps")==0) { proto="https"; port="443";