mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
Merge branch 'master' into ECC-INTEGRATION-2-1
This commit is contained in:
commit
c5e8a4c0fd
49 changed files with 3560 additions and 1653 deletions
|
@ -1,3 +1,20 @@
|
|||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* server.c (release_ctrl_keyservers): New.
|
||||
(cmd_keyserver, cmd_ks_seach, cmd_ks_get, cmd_ks_put): New.
|
||||
* dirmngr.h (uri_item_t): New.
|
||||
(struct server_control_s): Add field KEYSERVERS.
|
||||
* 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.
|
||||
|
||||
2011-01-19 Werner Koch <wk@g10code.com>
|
||||
|
||||
* dirmngr.c (main): Use es_printf for --gpgconf-list.
|
||||
|
||||
2010-12-14 Werner Koch <wk@g10code.com>
|
||||
|
||||
* 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1019,7 +1019,7 @@ main (int argc, char **argv)
|
|||
start of the dirmngr. */
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
pid = getpid ();
|
||||
printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid);
|
||||
es_printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid);
|
||||
#else
|
||||
pid = pth_fork ();
|
||||
if (pid == (pid_t)-1)
|
||||
|
@ -1051,11 +1051,11 @@ main (int argc, char **argv)
|
|||
if (csh_style)
|
||||
{
|
||||
*strchr (infostr, '=') = ' ';
|
||||
printf ( "setenv %s\n", infostr);
|
||||
es_printf ( "setenv %s\n", infostr);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ( "%s; export DIRMNGR_INFO;\n", infostr);
|
||||
es_printf ( "%s; export DIRMNGR_INFO;\n", infostr);
|
||||
}
|
||||
free (infostr);
|
||||
exit (0);
|
||||
|
@ -1220,15 +1220,15 @@ main (int argc, char **argv)
|
|||
"dirmngr.conf", NULL );
|
||||
|
||||
filename = percent_escape (opt.config_filename, NULL);
|
||||
printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
|
||||
es_printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
|
||||
GC_OPT_FLAG_DEFAULT, filename);
|
||||
xfree (filename);
|
||||
|
||||
printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
|
||||
printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
|
||||
es_printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
|
||||
/* --csh and --sh are mutually exclusive, something we can not
|
||||
express in GPG Conf. --options is only usable from the
|
||||
|
@ -1241,34 +1241,34 @@ main (int argc, char **argv)
|
|||
"ldapservers.conf":"dirmngr_ldapservers.conf",
|
||||
NULL);
|
||||
filename_esc = percent_escape (filename, NULL);
|
||||
printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
|
||||
es_printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
|
||||
filename_esc);
|
||||
xfree (filename_esc);
|
||||
xfree (filename);
|
||||
|
||||
printf ("ldaptimeout:%lu:%u\n",
|
||||
es_printf ("ldaptimeout:%lu:%u\n",
|
||||
flags | GC_OPT_FLAG_DEFAULT, DEFAULT_LDAP_TIMEOUT);
|
||||
printf ("max-replies:%lu:%u\n",
|
||||
es_printf ("max-replies:%lu:%u\n",
|
||||
flags | GC_OPT_FLAG_DEFAULT, DEFAULT_MAX_REPLIES);
|
||||
printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
|
||||
printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
|
||||
printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
/* Note: The next one is to fix a typo in gpgconf - should be
|
||||
removed eventually. */
|
||||
printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
es_printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
|
||||
}
|
||||
cleanup ();
|
||||
return !!rc;
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
||||
|
||||
|
|
183
dirmngr/ks-action.c
Normal file
183
dirmngr/ks-action.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!any)
|
||||
err = gpg_error (GPG_ERR_NO_KEYSERVER);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Get the requested keys (matching PATTERNS) using all configured
|
||||
keyservers and write the result to the provided output stream. */
|
||||
gpg_error_t
|
||||
ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
gpg_error_t first_err = 0;
|
||||
int any = 0;
|
||||
strlist_t sl;
|
||||
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 keyserver. To fully
|
||||
support multiple keyservers we need to track the result for each
|
||||
pattern and use the next keyserver if one key was not found. The
|
||||
keyservers might not all be fully synced thus it is not clear
|
||||
whether the first keyserver has the freshest copy of the key.
|
||||
Need to think about a better strategy. */
|
||||
for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
|
||||
{
|
||||
if (uri->parsed_uri->is_http)
|
||||
{
|
||||
any = 1;
|
||||
for (sl = patterns; !err && sl; sl = sl->next)
|
||||
{
|
||||
err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
|
||||
if (err)
|
||||
{
|
||||
/* It is possible that a server does not carry a
|
||||
key, thus we only save the error and continue
|
||||
with the next pattern. FIXME: It is an open
|
||||
question how to return such an error condition to
|
||||
the caller. */
|
||||
first_err = err;
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = copy_stream (infp, outfp);
|
||||
/* Reading from the keyserver should nver fail, thus
|
||||
return this error. */
|
||||
es_fclose (infp);
|
||||
infp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!any)
|
||||
err = gpg_error (GPG_ERR_NO_KEYSERVER);
|
||||
else if (!err && first_err)
|
||||
err = first_err; /* fixme: Do we really want to do that? */
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
|
||||
is expected in OpenPGP binary transport format. */
|
||||
gpg_error_t
|
||||
ks_action_put (ctrl_t ctrl, const void *data, size_t datalen)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
gpg_error_t first_err = 0;
|
||||
int any = 0;
|
||||
uri_item_t uri;
|
||||
|
||||
for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
|
||||
{
|
||||
if (uri->parsed_uri->is_http)
|
||||
{
|
||||
any = 1;
|
||||
err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
|
||||
if (err)
|
||||
{
|
||||
first_err = err;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!any)
|
||||
err = gpg_error (GPG_ERR_NO_KEYSERVER);
|
||||
else if (!err && first_err)
|
||||
err = first_err; /* fixme: Do we really want to do that? */
|
||||
return err;
|
||||
}
|
||||
|
28
dirmngr/ks-action.h
Normal file
28
dirmngr/ks-action.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
gpg_error_t ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
|
||||
gpg_error_t ks_action_put (ctrl_t ctrl, const void *data, size_t datalen);
|
||||
|
||||
|
||||
#endif /*DIRMNGR_KS_ACTION_H*/
|
558
dirmngr/ks-engine-hkp.c
Normal file
558
dirmngr/ks-engine-hkp.c
Normal file
|
@ -0,0 +1,558 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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
|
||||
|
||||
|
||||
/* Send an HTTP request. On success returns an estream object at
|
||||
R_FP. HOSTPORTSTR is only used for diagnostics. If POST_CB is not
|
||||
NULL a post request is used and that callback is called to allow
|
||||
writing the post data. */
|
||||
static gpg_error_t
|
||||
send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
|
||||
estream_t *r_fp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
http_t http = NULL;
|
||||
int redirects_left = MAX_REDIRECTS;
|
||||
estream_t fp = NULL;
|
||||
char *request_buffer = NULL;
|
||||
|
||||
*r_fp = NULL;
|
||||
once_more:
|
||||
err = http_open (&http,
|
||||
post_cb? HTTP_REQ_POST : 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);
|
||||
if (post_cb)
|
||||
err = post_cb (post_cb_value, http);
|
||||
if (!err)
|
||||
{
|
||||
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"),
|
||||
hostportstr, 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"),
|
||||
hostportstr, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
switch (http_get_status_code (http))
|
||||
{
|
||||
case 200:
|
||||
err = 0;
|
||||
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_buffer);
|
||||
request_buffer = xtrystrdup (s);
|
||||
if (request_buffer)
|
||||
{
|
||||
request = request_buffer;
|
||||
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;
|
||||
}
|
||||
|
||||
fp = http_get_read_ptr (http);
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Return the read stream and close the HTTP context. */
|
||||
*r_fp = fp;
|
||||
http_close (http, 1);
|
||||
http = NULL;
|
||||
|
||||
leave:
|
||||
http_close (http, 0);
|
||||
xfree (request_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
armor_data (char **r_string, const void *data, size_t datalen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct b64state b64state;
|
||||
estream_t fp;
|
||||
long length;
|
||||
char *buffer;
|
||||
size_t nread;
|
||||
|
||||
*r_string = NULL;
|
||||
|
||||
fp = es_fopenmem (0, "rw");
|
||||
if (!fp)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
|
||||
|| (err=b64enc_write (&b64state, data, datalen))
|
||||
|| (err = b64enc_finish (&b64state)))
|
||||
{
|
||||
es_fclose (fp);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* FIXME: To avoid the extra buffer allocation estream should
|
||||
provide a function to snatch the internal allocated memory from
|
||||
such a memory stream. */
|
||||
length = es_ftell (fp);
|
||||
if (length < 0)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
es_fclose (fp);
|
||||
return err;
|
||||
}
|
||||
|
||||
buffer = xtrymalloc (length+1);
|
||||
if (!buffer)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
es_fclose (fp);
|
||||
return err;
|
||||
}
|
||||
|
||||
es_rewind (fp);
|
||||
if (es_read (fp, buffer, length, &nread))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
es_fclose (fp);
|
||||
return err;
|
||||
}
|
||||
buffer[nread] = 0;
|
||||
es_fclose (fp);
|
||||
|
||||
*r_string = buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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];
|
||||
char *hostport = NULL;
|
||||
char *request = NULL;
|
||||
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. */
|
||||
err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Start reading the response. */
|
||||
{
|
||||
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. */
|
||||
*r_fp = fp;
|
||||
fp = NULL;
|
||||
|
||||
leave:
|
||||
es_fclose (fp);
|
||||
xfree (request);
|
||||
xfree (hostport);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Get the key described key the KEYSPEC string from the keyserver
|
||||
identified by URI. On success R_FP has an open stream to read the
|
||||
data. */
|
||||
gpg_error_t
|
||||
ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
char kidbuf[8+1];
|
||||
const char *scheme;
|
||||
char portstr[10];
|
||||
char *hostport = NULL;
|
||||
char *request = NULL;
|
||||
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 (keyspec, &desc);
|
||||
if (err)
|
||||
return err;
|
||||
switch (desc.mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]);
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
/* This is a v4 fingerprint. Take the last 8 hex digits from
|
||||
the fingerprint which is the expected short keyid. */
|
||||
bin2hex (desc.u.fpr+16, 4, kidbuf);
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
log_error ("HKP keyserver do not support v3 fingerprints\n");
|
||||
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. */
|
||||
{
|
||||
hostport = strconcat (scheme, "://",
|
||||
*uri->host? uri->host: "localhost",
|
||||
":", portstr, NULL);
|
||||
if (!hostport)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
request = strconcat (hostport,
|
||||
"/pks/lookup?op=get&options=mr&search=0x",
|
||||
kidbuf,
|
||||
NULL);
|
||||
if (!request)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the request. */
|
||||
err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Return the read stream and close the HTTP context. */
|
||||
*r_fp = fp;
|
||||
fp = NULL;
|
||||
|
||||
leave:
|
||||
es_fclose (fp);
|
||||
xfree (request);
|
||||
xfree (hostport);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Callback parameters for put_post_cb. */
|
||||
struct put_post_parm_s
|
||||
{
|
||||
char *datastring;
|
||||
};
|
||||
|
||||
|
||||
/* Helper for ks_hkp_put. */
|
||||
static gpg_error_t
|
||||
put_post_cb (void *opaque, http_t http)
|
||||
{
|
||||
struct put_post_parm_s *parm = opaque;
|
||||
gpg_error_t err = 0;
|
||||
estream_t fp;
|
||||
size_t len;
|
||||
|
||||
fp = http_get_write_ptr (http);
|
||||
len = strlen (parm->datastring);
|
||||
|
||||
es_fprintf (fp,
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
"Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
|
||||
http_start_data (http);
|
||||
if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
|
||||
err = gpg_error_from_syserror ();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
|
||||
gpg_error_t
|
||||
ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char *scheme;
|
||||
char portstr[10];
|
||||
char *hostport = NULL;
|
||||
char *request = NULL;
|
||||
estream_t fp = NULL;
|
||||
struct put_post_parm_s parm;
|
||||
char *armored = NULL;
|
||||
|
||||
parm.datastring = NULL;
|
||||
|
||||
/* 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 ()*/
|
||||
|
||||
err = armor_data (&armored, data, datalen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
|
||||
if (!parm.datastring)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
xfree (armored);
|
||||
armored = NULL;
|
||||
|
||||
/* Build the request string. */
|
||||
hostport = strconcat (scheme, "://",
|
||||
*uri->host? uri->host: "localhost",
|
||||
":", portstr, NULL);
|
||||
if (!hostport)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
request = strconcat (hostport, "/pks/add", NULL);
|
||||
if (!request)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Send the request. */
|
||||
err = send_request (ctrl, request, hostport, put_post_cb, &parm, &fp);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
leave:
|
||||
es_fclose (fp);
|
||||
xfree (parm.datastring);
|
||||
xfree (armored);
|
||||
xfree (request);
|
||||
xfree (hostport);
|
||||
return err;
|
||||
}
|
36
dirmngr/ks-engine.h
Normal file
36
dirmngr/ks-engine.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
gpg_error_t ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri,
|
||||
const char *keyspec, estream_t *r_fp);
|
||||
gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri,
|
||||
const void *data, size_t datalen);
|
||||
|
||||
|
||||
|
||||
#endif /*DIRMNGR_KS_ENGINE_H*/
|
285
dirmngr/server.c
285
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,11 +41,18 @@
|
|||
#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. */
|
||||
#define MAX_CERT_LENGTH (8*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)
|
||||
|
||||
|
||||
#define PARM_ERROR(t) assuan_set_error (ctx, \
|
||||
gpg_error (GPG_ERR_ASS_PARAMETER), (t))
|
||||
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
|
||||
|
@ -58,7 +65,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 +101,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 +169,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 +1357,254 @@ cmd_validate (assuan_context_t ctx, char *line)
|
|||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_keyserver[] =
|
||||
"KEYSERVER [--clear] [<uri>]\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 {<pattern>}\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_ks_get[] =
|
||||
"KS_GET {<pattern>}\n"
|
||||
"\n"
|
||||
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
|
||||
"(see command KEYSERVER). Each pattern should be a keyid or a fingerprint";
|
||||
static gpg_error_t
|
||||
cmd_ks_get (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 by
|
||||
definition percent-plus escaped. However we only support keyids
|
||||
and fingerprints and thus the client has no need to apply the
|
||||
escaping. */
|
||||
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 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);
|
||||
es_fclose (outfp);
|
||||
}
|
||||
|
||||
leave:
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char hlp_ks_put[] =
|
||||
"KS_PUT\n"
|
||||
"\n"
|
||||
"Send a key to the configured OpenPGP keyservers. The actual key material\n"
|
||||
"is then requested by Dirmngr using\n"
|
||||
"\n"
|
||||
" INQUIRE KEYBLOCK\n"
|
||||
"\n"
|
||||
"The client shall respond with a binary version of the keyblock. 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";
|
||||
static gpg_error_t
|
||||
cmd_ks_put (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
gpg_error_t err;
|
||||
unsigned char *value = NULL;
|
||||
size_t valuelen;
|
||||
unsigned char *info = NULL;
|
||||
size_t infolen;
|
||||
|
||||
/* No options for now. */
|
||||
line = skip_options (line);
|
||||
|
||||
/* Ask for the key material. */
|
||||
err = assuan_inquire (ctx, "KEYBLOCK",
|
||||
&value, &valuelen, MAX_KEYBLOCK_LENGTH);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!valuelen) /* No data returned; return a comprehensible error. */
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_CERT);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Ask for the key meta data. Not actually needed for HKP servers
|
||||
but we do it anyway test the client implementaion. */
|
||||
err = assuan_inquire (ctx, "KEYBLOCK_INFO",
|
||||
&info, &infolen, MAX_KEYBLOCK_LENGTH);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Send the key. */
|
||||
err = ks_action_put (ctrl, value, valuelen);
|
||||
|
||||
leave:
|
||||
xfree (info);
|
||||
xfree (value);
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static const char hlp_getinfo[] =
|
||||
|
@ -1469,6 +1739,10 @@ 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 },
|
||||
{ "KS_GET", cmd_ks_get, hlp_ks_get },
|
||||
{ "KS_PUT", cmd_ks_put, hlp_ks_put },
|
||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
|
||||
{ "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
|
||||
|
@ -1487,6 +1761,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 +1956,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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue