Merge branch 'master' into ECC-INTEGRATION-2-1

This commit is contained in:
Werner Koch 2011-01-24 12:24:11 +01:00
commit c5e8a4c0fd
49 changed files with 3560 additions and 1653 deletions

View File

@ -1,3 +1,13 @@
2011-01-20 Werner Koch <wk@g10code.com>
* configure.ac (AC_CONFIG_FILES): Remove keyserver/.
2011-01-19 Werner Koch <wk@g10code.com>
* configure.ac: Add new option --enable-gpg2-is-gpg.
(NAME_OF_INSTALLED_GPG): New ac_define.
* autogen.sh [--build-w32ce]: Use --enable-gpg2-is-gpg.
2011-01-21 Werner Koch <wk@g10code.com>
* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
@ -21,7 +31,7 @@
2010-11-17 Werner Koch <wk@g10code.com>
* configure.ac (ENABLE_CARD_SUPPORT): Define.
* configure.ac (ENABLE_CARD_SUPPORT): Define.
2010-10-27 Werner Koch <wk@g10code.com>

View File

@ -35,7 +35,7 @@ endif
if BUILD_GPG
gpg = g10
if !HAVE_W32CE_SYSTEM
keyserver = keyserver
keyserver =
endif
else
gpg =

3
NEWS
View File

@ -17,6 +17,9 @@ Noteworthy changes in version 2.1.0beta2 (unreleased)
* Fixed TTY management for pinentries and session variable update
problem.
* Dirmngr has taken over the function of the keyserver helpers. Thus
we now have a specified direct interface to keyservers via Dirmngr.
Noteworthy changes in version 2.1.0beta1 (2010-10-26)
-----------------------------------------------------

View File

@ -1,3 +1,7 @@
2011-01-19 Werner Koch <wk@g10code.com>
* trustlist.c (read_one_trustfile): Also chop an CR.
2011-01-21 Werner Koch <wk@g10code.com>
* pksign.c (do_encode_dsa): Compare MDLEN to bytes.

View File

@ -139,8 +139,9 @@ read_one_trustfile (const char *fname, int allow_include,
while (es_fgets (line, DIM(line)-1, fp))
{
lnr++;
if (!*line || line[strlen(line)-1] != '\n')
n = strlen (line);
if (!n || line[n-1] != '\n')
{
/* Eat until end of line. */
while ( (c=es_getc (fp)) != EOF && c != '\n')
@ -151,7 +152,9 @@ read_one_trustfile (const char *fname, int allow_include,
fname, lnr, gpg_strerror (err));
continue;
}
line[strlen(line)-1] = 0; /* Chop the LF. */
line[--n] = 0; /* Chop the LF. */
if (n && line[n-1] == '\r')
line[--n] = 0; /* Chop an optional CR. */
/* Allow for empty lines and spaces */
for (p=line; spacep (p); p++)

View File

@ -104,7 +104,8 @@ if [ "$myhost" = "w32" ]; then
[ -z "$w32root" ] && w32root="$HOME/w32ce_root"
toolprefixes="$w32ce_toolprefixes arm-mingw32ce"
extraoptions="--enable-dirmngr-auto-start --disable-scdaemon "
extraoptions="$extraoptions --disable-zip $w32ce_extraoptions"
extraoptions="$extraoptions --disable-zip --enable-gpg2-is-gpg"
extraoptions="$extraoptions $w32ce_extraoptions"
;;
*)
[ -z "$w32root" ] && w32root="$HOME/w32root"

View File

@ -1,3 +1,55 @@
2011-01-20 Werner Koch <wk@g10code.com>
Fix bug#1313.
* http.c (my_select): New. Define to pth_select if building with Pth.
(start_server, write_server, cookie_read, cookie_write): Use it.
(my_connect): New. Define to pth_connect if building with Pth.
(connect_server): Use it.
(my_accept): New. Define to pth_accept if building with Pth.
(start_server): Use it.
2011-01-20 Werner Koch <wk@g10code.com>
* util.h (struct b64state): Add field LASTERR.
* b64enc.c (enc_start, b64enc_write, b64enc_finish): Handle
LASTERR. This is to make sure that we don't leak strduped data.
* b64dec.c (b64dec_start, b64dec_proc, b64dec_finish): Ditto.
* http.c (escape_data): New.
(insert_escapes): Implement using escape_data.
(http_escape_data): New.
2011-01-19 Werner Koch <wk@g10code.com>
* homedir.c (gnupg_module_name): Use NAME_OF_INSTALLED_GPG instead
of "gpg2".
2011-01-18 Werner Koch <wk@g10code.com>
* iobuf.c (file_es_filter_ctx_t): New.
(file_es_filter): New.
(iobuf_esopen): New.
* membuf.c (clear_membuf, peek_membuf): New.
* 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.
* estream.c (es_func_mem_write): Fix computation of NEWSIZE.
2011-01-10 Werner Koch <wk@g10code.com>
* session-env.c (update_var): Fix same value detection. Fixes
bug#1311.
2011-01-10 Werner Koch <wk@g10code.com>
* session-env.c (update_var): Fix same value detection. Fixes

View File

@ -1,5 +1,5 @@
/* b64dec.c - Simple Base64 decoder.
* Copyright (C) 2008 Free Software Foundation, Inc.
* Copyright (C) 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -72,16 +72,19 @@ b64dec_start (struct b64state *state, const char *title)
if (title)
{
if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
state->title = xtrystrdup (title);
if (!state->title)
return gpg_error_from_syserror ();
state->idx = s_init;
state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
else
{
state->title = xtrystrdup (title);
if (!state->title)
state->lasterr = gpg_error_from_syserror ();
else
state->idx = s_init;
}
}
else
state->idx = s_b64_0;
return 0;
return state->lasterr;
}
@ -96,12 +99,18 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
int pos = state->quad_count;
char *d, *s;
if (state->lasterr)
return state->lasterr;
if (state->stop_seen)
{
*r_nbytes = 0;
return gpg_error (GPG_ERR_EOF);
state->lasterr = gpg_error (GPG_ERR_EOF);
xfree (state->title);
state->title = NULL;
return state->lasterr;
}
for (s=d=buffer; length && !state->stop_seen; length--, s++)
{
switch (ds)
@ -210,6 +219,9 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
gpg_error_t
b64dec_finish (struct b64state *state)
{
if (state->lasterr)
return state->lasterr;
xfree (state->title);
state->title = NULL;
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;

View File

@ -1,5 +1,6 @@
/* b64enc.c - Simple Base64 encoder.
* Copyright (C) 2001, 2003, 2004, 2008, 2010 Free Software Foundation, Inc.
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
* 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -143,6 +144,7 @@ enc_start (struct b64state *state, FILE *fp, estream_t stream,
memset (state, 0, sizeof *state);
state->fp = fp;
state->stream = stream;
state->lasterr = 0;
if (title && !*title)
state->flags |= B64ENC_NO_LINEFEEDS;
else if (title)
@ -154,9 +156,9 @@ enc_start (struct b64state *state, FILE *fp, estream_t stream,
}
state->title = xtrystrdup (title);
if (!state->title)
return gpg_error_from_syserror ();
state->lasterr = gpg_error_from_syserror ();
}
return 0;
return state->lasterr;
}
@ -203,6 +205,8 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
int idx, quad_count;
const unsigned char *p;
if (state->lasterr)
return state->lasterr;
if (!nbytes)
{
@ -285,7 +289,13 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
return 0;
write_error:
return gpg_error_from_syserror ();
state->lasterr = gpg_error_from_syserror ();
if (state->title)
{
xfree (state->title);
state->title = NULL;
}
return state->lasterr;
}
@ -297,6 +307,9 @@ b64enc_finish (struct b64state *state)
int idx, quad_count;
char tmp[4];
if (state->lasterr)
return state->lasterr;
if (!(state->flags & B64ENC_DID_HEADER))
goto cleanup;
@ -404,6 +417,7 @@ b64enc_finish (struct b64state *state)
}
state->fp = NULL;
state->stream = NULL;
state->lasterr = err;
return err;
}

View File

@ -641,7 +641,7 @@ es_func_mem_write (void *cookie, const void *buffer, size_t size)
if (!mem_cookie->memory_size)
newsize = size; /* Not yet allocated. */
else
newsize = mem_cookie->memory_size + (nleft - size);
newsize = mem_cookie->memory_size + (size - nleft);
if (newsize < mem_cookie->offset)
{
_set_errno (EINVAL);

View File

@ -528,7 +528,7 @@ gnupg_module_name (int which)
X(bindir, "gpgsm");
case GNUPG_MODULE_NAME_GPG:
X(bindir, "gpg2");
X(bindir, NAME_OF_INSTALLED_GPG);
case GNUPG_MODULE_NAME_CONNECT_AGENT:
X(bindir, "gpg-connect-agent");

View File

@ -1,6 +1,6 @@
/* http.c - HTTP protocol handler
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006,
* 2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
* 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -105,6 +105,16 @@ struct srventry
#endif/*!USE_DNS_SRV*/
#ifdef HAVE_PTH
# define my_select(a,b,c,d,e) pth_select ((a), (b), (c), (d), (e))
# define my_connect(a,b,c) pth_connect ((a), (b), (c))
# define my_accept(a,b,c) pth_accept ((a), (b), (c))
#else
# define my_select(a,b,c,d,e) select ((a), (b), (c), (d), (e))
# define my_connect(a,b,c) connect ((a), (b), (c))
# define my_accept(a,b,c) accept ((a), (b), (c))
#endif
#ifdef HAVE_W32_SYSTEM
#define sock_close(a) closesocket(a)
#else
@ -138,7 +148,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 +367,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 +379,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 +521,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 +562,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 +576,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 +592,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;
@ -723,14 +752,14 @@ remove_escapes (char *string)
}
static int
insert_escapes (char *buffer, const char *string,
const char *special)
static size_t
escape_data (char *buffer, const void *data, size_t datalen,
const char *special)
{
const unsigned char *s = (const unsigned char*)string;
int n = 0;
const unsigned char *s;
size_t n = 0;
for (; *s; s++)
for (s = data; datalen; s++, datalen--)
{
if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
{
@ -752,6 +781,14 @@ insert_escapes (char *buffer, const char *string,
}
static int
insert_escapes (char *buffer, const char *string,
const char *special)
{
return escape_data (buffer, string, strlen (string), special);
}
/* Allocate a new string from STRING using standard HTTP escaping as
well as escaping of characters given in SPECIALS. A common pattern
for SPECIALS is "%;?&=". However it depends on the needs, for
@ -773,6 +810,27 @@ http_escape_string (const char *string, const char *specials)
return buf;
}
/* Allocate a new string from {DATA,DATALEN} using standard HTTP
escaping as well as escaping of characters given in SPECIALS. A
common pattern for SPECIALS is "%;?&=". However it depends on the
needs, for example "+" and "/: often needs to be escaped too.
Returns NULL on failure and sets ERRNO. */
char *
http_escape_data (const void *data, size_t datalen, const char *specials)
{
int n;
char *buf;
n = escape_data (NULL, data, datalen, specials);
buf = xtrymalloc (n+1);
if (buf)
{
escape_data (buf, data, datalen, specials);
buf[n] = 0;
}
return buf;
}
static uri_tuple_t
@ -852,12 +910,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);
}
@ -1374,14 +1431,14 @@ start_server ()
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
if (my_select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
continue; /* ignore any errors */
if (!FD_ISSET (fd, &rfds))
continue;
addrlen = sizeof peer;
client = accept (fd, (struct sockaddr *) &peer, &addrlen);
client = my_accept (fd, (struct sockaddr *) &peer, &addrlen);
if (client == -1)
continue; /* oops */
@ -1451,7 +1508,7 @@ connect_server (const char *server, unsigned short port,
addr.sin_port = htons(port);
memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
if (!my_connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
return sock;
sock_close(sock);
return -1;
@ -1519,7 +1576,7 @@ connect_server (const char *server, unsigned short port,
return -1;
}
if (connect (sock, ai->ai_addr, ai->ai_addrlen))
if (my_connect (sock, ai->ai_addr, ai->ai_addrlen))
last_errno = errno;
else
connected = 1;
@ -1573,7 +1630,7 @@ connect_server (const char *server, unsigned short port,
for (i = 0; host->h_addr_list[i] && !connected; i++)
{
memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
if (my_connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
last_errno = errno;
else
{
@ -1613,7 +1670,6 @@ write_server (int sock, const char *data, size_t length)
int nleft;
int nwritten;
/* FIXME: We would better use pth I/O functions. */
nleft = length;
while (nleft > 0)
{
@ -1640,7 +1696,7 @@ write_server (int sock, const char *data, size_t length)
tv.tv_sec = 0;
tv.tv_usec = 50000;
select (0, NULL, NULL, NULL, &tv);
my_select (0, NULL, NULL, NULL, &tv);
continue;
}
log_info ("network write failed: %s\n", strerror (errno));
@ -1686,7 +1742,7 @@ cookie_read (void *cookie, void *buffer, size_t size)
tv.tv_sec = 0;
tv.tv_usec = 50000;
select (0, NULL, NULL, NULL, &tv);
my_select (0, NULL, NULL, NULL, &tv);
goto again;
}
if (nread == GNUTLS_E_REHANDSHAKE)
@ -1748,7 +1804,7 @@ cookie_write (void *cookie, const void *buffer, size_t size)
tv.tv_sec = 0;
tv.tv_usec = 50000;
select (0, NULL, NULL, NULL, &tv);
my_select (0, NULL, NULL, NULL, &tv);
continue;
}
log_info ("TLS network write failed: %s\n",
@ -1882,11 +1938,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;
}

View File

@ -23,7 +23,8 @@
#include <gpg-error.h>
#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);
@ -115,6 +117,7 @@ unsigned int http_get_status_code (http_t hd);
const char *http_get_header (http_t hd, const char *name);
char *http_escape_string (const char *string, const char *specials);
char *http_escape_data (const void *data, size_t datalen, const char *specials);
#endif /*GNUPG_COMMON_HTTP_H*/

View File

@ -1,6 +1,6 @@
/* iobuf.c - File Handling for OpenPGP.
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008,
* 2009, 2010 Free Software Foundation, Inc.
* 2009, 2010, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -78,6 +78,17 @@ typedef struct
char fname[1]; /* Name of the file. */
} file_filter_ctx_t;
/* The context used by the estream filter. */
typedef struct
{
estream_t fp; /* Open estream handle. */
int keep_open;
int no_cache;
int eof_seen;
int print_only_name; /* Flags indicating that fname is not a real file. */
char fname[1]; /* Name of the file. */
} file_es_filter_ctx_t;
/* Object to control the "close cache". */
struct close_cache_s
@ -577,6 +588,96 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
}
/* Similar to file_filter but using the estream system. */
static int
file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
size_t * ret_len)
{
file_es_filter_ctx_t *a = opaque;
estream_t f = a->fp;
size_t size = *ret_len;
size_t nbytes = 0;
int rc = 0;
(void)chain; /* Not used. */
if (control == IOBUFCTRL_UNDERFLOW)
{
assert (size); /* We need a buffer. */
if (a->eof_seen)
{
rc = -1;
*ret_len = 0;
}
else
{
nbytes = 0;
rc = es_read (f, buf, size, &nbytes);
if (rc == -1)
{ /* error */
rc = gpg_error_from_syserror ();
log_error ("%s: read error: %s\n", a->fname, strerror (errno));
}
else if (!nbytes)
{ /* eof */
a->eof_seen = 1;
rc = -1;
}
*ret_len = nbytes;
}
}
else if (control == IOBUFCTRL_FLUSH)
{
if (size)
{
byte *p = buf;
size_t nwritten;
nbytes = size;
do
{
nwritten = 0;
if (es_write (f, p, nbytes, &nwritten))
{
rc = gpg_error_from_syserror ();
log_error ("%s: write error: %s\n",
a->fname, strerror (errno));
break;
}
p += nwritten;
nbytes -= nwritten;
}
while (nbytes);
nbytes = p - buf;
}
*ret_len = nbytes;
}
else if (control == IOBUFCTRL_INIT)
{
a->eof_seen = 0;
a->no_cache = 0;
}
else if (control == IOBUFCTRL_DESC)
{
*(char **) buf = "estream_filter";
}
else if (control == IOBUFCTRL_FREE)
{
if (f != es_stdin && f != es_stdout)
{
if (DBG_IOBUF)
log_debug ("%s: es_fclose %p\n", a->fname, f);
if (!a->keep_open)
es_fclose (f);
}
f = NULL;
xfree (a); /* We can free our context now. */
}
return rc;
}
#ifdef HAVE_W32_SYSTEM
/* Because network sockets are special objects under Lose32 we have to
use a dedicated filter for them. */
@ -1257,6 +1358,30 @@ iobuf_fdopen_nc (int fd, const char *mode)
}
iobuf_t
iobuf_esopen (estream_t estream, const char *mode, int keep_open)
{
iobuf_t a;
file_es_filter_ctx_t *fcx;
size_t len;
a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, IOBUF_BUFFER_SIZE);
fcx = xtrymalloc (sizeof *fcx + 30);
fcx->fp = estream;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
sprintf (fcx->fname, "[fd %p]", estream);
a->filter = file_es_filter;
a->filter_ov = fcx;
file_es_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
if (DBG_IOBUF)
log_debug ("iobuf-%d.%d: esopen%s `%s'\n",
a->no, a->subno, keep_open? "_nc":"", fcx->fname);
return a;
}
iobuf_t
iobuf_sockopen (int fd, const char *mode)
{

View File

@ -23,6 +23,7 @@
#include "../include/types.h" /* fixme: should be moved elsewhere. */
#include "../common/sysutils.h"
#include "../common/estream.h"
#define DBG_IOBUF iobuf_debug_mode
@ -102,6 +103,7 @@ iobuf_t iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname,
iobuf_t iobuf_open (const char *fname);
iobuf_t iobuf_fdopen (int fd, const char *mode);
iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open);
iobuf_t iobuf_sockopen (int fd, const char *mode);
iobuf_t iobuf_create (const char *fname);
iobuf_t iobuf_append (const char *fname);

View File

@ -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*/

View File

@ -1,5 +1,5 @@
/* membuf.c - A simple implementation of a dynamic buffer.
* Copyright (C) 2001, 2003, 2009 Free Software Foundation, Inc.
* Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -56,6 +56,26 @@ init_membuf_secure (membuf_t *mb, int initiallen)
}
/* Shift the the content of the membuf MB by AMOUNT bytes. The next
operation will then behave as if AMOUNT bytes had not been put into
the buffer. If AMOUNT is greater than the actual accumulated
bytes, the membuf is basically reset to its initial state. */
void
clear_membuf (membuf_t *mb, size_t amount)
{
/* No need to clear if we are already out of core. */
if (mb->out_of_core)
return;
if (amount >= mb->len)
mb->len = 0;
else
{
mb->len -= amount;
memmove (mb->buf, mb->buf+amount, mb->len);
}
}
void
put_membuf (membuf_t *mb, const void *buf, size_t len)
{
@ -116,3 +136,26 @@ get_membuf (membuf_t *mb, size_t *len)
mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
return p;
}
/* Peek at the membuf MB. On success a pointer to the buffer is
returned which is valid until the next operation on MB. If LEN is
not NULL the current LEN of the buffer is stored there. On error
NULL is returned and ERRNO is set. */
const void *
peek_membuf (membuf_t *mb, size_t *len)
{
const char *p;
if (mb->out_of_core)
{
gpg_err_set_errno (mb->out_of_core);
return NULL;
}
p = mb->buf;
if (len)
*len = mb->len;
return p;
}

View File

@ -39,9 +39,10 @@ typedef struct private_membuf_s membuf_t;
void init_membuf (membuf_t *mb, int initiallen);
void init_membuf_secure (membuf_t *mb, int initiallen);
void clear_membuf (membuf_t *mb, size_t amount);
void put_membuf (membuf_t *mb, const void *buf, size_t len);
void put_membuf_str (membuf_t *mb, const char *string);
void *get_membuf (membuf_t *mb, size_t *len);
const void *peek_membuf (membuf_t *mb, size_t *len);
#endif /*GNUPG_COMMON_MEMBUF_H*/

View File

@ -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
@ -147,6 +150,7 @@ struct b64state
u32 crc;
int stop_seen:1;
int invalid_encoding:1;
gpg_error_t lasterr;
};
gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);

View File

@ -168,6 +168,24 @@ show_gnupg_dirmngr_ldap_pgm="(default)"
test -n "$GNUPG_DIRMNGR_LDAP_PGM" \
&& show_gnupg_dirmngr_ldap_pgm="$GNUPG_DIRMNGR_LDAP_PGM"
#
# On some platforms gpg2 is usually installed as gpg without using a
# symlink. For correct operation of gpgconf it needs to know the
# installed name of gpg. This option sets "gpg2"'s installed name to
# just "gpg". Note that it might be required to rename gpg2 to gpg
# manually after the build process.
#
AC_ARG_ENABLE(gpg2-is-gpg,
AC_HELP_STRING([--enable-gpg2-is-gpg],[Set installed name of gpg2 to gpg]),
gpg2_is_gpg=$enableval)
if test "$gpg2_is_gpg" = "yes"; then
name_of_installed_gpg=gpg
else
name_of_installed_gpg=gpg2
fi
AC_DEFINE_UNQUOTED(NAME_OF_INSTALLED_GPG, "$name_of_installed_gpg",
[The name of the installed GPG tool])
# Some folks want to use only the agent from this packet. Make it
# easier for them by providing the configure option
@ -1679,9 +1697,6 @@ agent/Makefile
scd/Makefile
g13/Makefile
dirmngr/Makefile
keyserver/Makefile
keyserver/gpg2keys_mailto
keyserver/gpg2keys_test
tools/gpg-zip
tools/Makefile
doc/Makefile
@ -1689,6 +1704,11 @@ tests/Makefile
tests/openpgp/Makefile
tests/pkits/Makefile
])
#keyserver/Makefile
#keyserver/gpg2keys_mailto
#keyserver/gpg2keys_test
AC_OUTPUT

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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;

View File

@ -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
View 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
View 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
View 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
View 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*/

View File

@ -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)
{

View File

@ -103,7 +103,7 @@ used. Using the keyserver debug option as in
is thus often helpful. Note that the actual output depends on the
backend and may change from release to release.
@ifset gpgtwoone
@item Logging on WindowsCE
For development, the best logging method on WindowsCE is the use of
@ -113,7 +113,7 @@ on the given port. (@pxref{option watchgnupg --tcp}). For in the field
tests it is better to make use of the logging facility provided by the
@command{gpgcedev} driver (part of libassuan); this is enabled by using
a log file name of @file{GPG2:}. (@pxref{option --log-file}).
@end ifset
@end itemize

View File

@ -34,7 +34,7 @@ Published by the Free Software Foundation@*
Boston, MA 02110-1301 USA
@end iftex
Copyright @copyright{} 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Copyright @copyright{} 2002, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
@ -51,8 +51,10 @@ section entitled ``Copying''.
* gpg2: (gnupg). OpenPGP encryption and signing tool.
* gpgsm: (gnupg). S/MIME encryption and signing tool.
* gpg-agent: (gnupg). The secret key daemon.
@ifset gpgtwoone
* dirmngr: (gnupg). X.509 CRL and OCSP server.
* dirmngr-client: (gnupg). X.509 CRL and OCSP client.
@end ifset
@end direntry
@ -124,7 +126,9 @@ the administration and the architecture.
* Installation:: A short installation guide.
* Invoking GPG-AGENT:: How to launch the secret key daemon.
@ifset gpgtwoone
* Invoking DIRMNGR:: How to launch the CRL and OCSP daemon.
@end ifset
* Invoking GPG:: Using the OpenPGP protocol.
* Invoking GPGSM:: Using the S/MIME protocol.
* Invoking SCDAEMON:: How to handle Smartcards.
@ -156,7 +160,9 @@ the administration and the architecture.
@include instguide.texi
@include gpg-agent.texi
@ifset gpgtwoone
@include dirmngr.texi
@end ifset
@include gpg.texi
@include gpgsm.texi
@include scdaemon.texi

View File

@ -16,7 +16,9 @@ GnuPG comes with a couple of smaller tools:
* gpgsm-gencert.sh:: Generate an X.509 certificate request.
* gpg-preset-passphrase:: Put a passphrase into the cache.
* gpg-connect-agent:: Communicate with a running agent.
@ifset gpgtwoone
* dirmngr-client:: How to use the Dirmngr client tool.
@end ifset
* gpgparsemail:: Parse a mail message into an annotated format
* symcryptrun:: Call a simple symmetric encryption tool.
* gpg-zip:: Encrypt or sign files into an archive.
@ -1434,6 +1436,7 @@ Print a list of available control commands.
@include see-also-note.texi
@end ifset
@ifset gpgtwoone
@c
@c DIRMNGR-CLIENT
@c
@ -1594,7 +1597,7 @@ Squid's @option{external_acl_type} option.
@command{gpgsm}(1)
@include see-also-note.texi
@end ifset
@end ifset
@c
@c GPGPARSEMAIL

View File

@ -1,3 +1,25 @@
2011-01-20 Werner Koch <wk@g10code.com>
* keyserver.c: Rewrite most stuff for use with dirmngr. Get rid
of all spawn code. Work work pending.
* export.c (export_pubkeys_buffer): New.
* import.c (import_keys_es_stream): New.
* 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 <wk@g10code.com>
* 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.
2011-01-21 Werner Koch <wk@g10code.com>
* seskey.c (encode_md_value): Truncate the DSA hash again.
@ -11654,7 +11676,7 @@ Thu Feb 12 22:24:42 1998 Werner Koch (wk@frodo)
Copyright 1998,1999,2000,2001,2002,2003,2004,2005,
2006,2007,2008,2009,2010 Free Software Foundation, Inc.
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

View File

@ -103,6 +103,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 \

611
g10/call-dirmngr.c Normal file
View File

@ -0,0 +1,611 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#include "gpg.h"
#include <assuan.h>
#include "util.h"
#include "membuf.h"
#include "options.h"
#include "i18n.h"
#include "asshelp.h"
#include "keyserver.h"
#include "call-dirmngr.h"
/* Parameter structure used with the KS_SEARCH command. */
struct ks_search_parm_s
{
gpg_error_t lasterr; /* Last error code. */
membuf_t saveddata; /* Buffer to build complete lines. */
char *helpbuf; /* NULL or malloced buffer. */
size_t helpbufsize; /* Allocated size of HELPBUF. */
gpg_error_t (*data_cb)(void*, char*); /* Callback. */
void *data_cb_value; /* First argument for DATA_CB. */
};
/* Parameter structure used with the KS_GET command. */
struct ks_get_parm_s
{
estream_t memfp;
};
/* Parameter structure used with the KS_PUT command. */
struct ks_put_parm_s
{
assuan_context_t ctx;
kbnode_t keyblock; /* The optional keyblock. */
const void *data; /* The key in OpenPGP binary format. */
size_t datalen; /* The length of DATA. */
};
/* 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. */
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. */
for (ksi = opt.keyserver; !err && ksi; ksi = ksi->next)
{
char *line;
line = xtryasprintf ("KEYSERVER%s %s",
ksi == opt.keyserver? " --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;
*r_ctx = dml->ctx;
return 0;
}
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 (!dml->is_active)
log_fatal ("closing inactive dirmngr context %p\n", ctx);
dml->is_active = 0;
return;
}
}
log_fatal ("closing unknown dirmngr ctx %p\n", ctx);
}
/* Data callback for the KS_SEARCH command. */
static gpg_error_t
ks_search_data_cb (void *opaque, const void *data, size_t datalen)
{
gpg_error_t err = 0;
struct ks_search_parm_s *parm = opaque;
const char *line, *s;
size_t rawlen, linelen;
char fixedbuf[256];
if (parm->lasterr)
return 0;
if (!data)
return 0; /* Ignore END commands. */
put_membuf (&parm->saveddata, data, datalen);
again:
line = peek_membuf (&parm->saveddata, &rawlen);
if (!line)
{
parm->lasterr = gpg_error_from_syserror ();
return parm->lasterr; /* Tell the server about our problem. */
}
if ((s = memchr (line, '\n', rawlen)))
{
linelen = s - line; /* That is the length excluding the LF. */
if (linelen + 1 < sizeof fixedbuf)
{
/* We can use the static buffer. */
memcpy (fixedbuf, line, linelen);
fixedbuf[linelen] = 0;
if (linelen && fixedbuf[linelen-1] == '\r')
fixedbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, fixedbuf);
}
else
{
if (linelen + 1 >= parm->helpbufsize)
{
xfree (parm->helpbuf);
parm->helpbufsize = linelen + 1 + 1024;
parm->helpbuf = xtrymalloc (parm->helpbufsize);
if (!parm->helpbuf)
{
parm->lasterr = gpg_error_from_syserror ();
return parm->lasterr;
}
}
memcpy (parm->helpbuf, line, linelen);
parm->helpbuf[linelen] = 0;
if (linelen && parm->helpbuf[linelen-1] == '\r')
parm->helpbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, parm->helpbuf);
}
if (err)
parm->lasterr = err;
else
{
clear_membuf (&parm->saveddata, linelen+1);
goto again; /* There might be another complete line. */
}
}
return err;
}
/* Run the KS_SEARCH command using the search string SEARCHSTR. All
data lines are passed to the CB function. That function is called
with CB_VALUE as its first argument and the decoded data line as
second argument. The callback function may modify the data line
and it is guaranteed that this data line is a complete line with a
terminating 0 character but without the linefeed. NULL is passed
to the callback to indicate EOF. */
gpg_error_t
gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
gpg_error_t (*cb)(void*, char *), void *cb_value)
{
gpg_error_t err;
assuan_context_t ctx;
struct ks_search_parm_s parm;
char line[ASSUAN_LINELENGTH];
err = open_context (ctrl, &ctx);
if (err)
return err;
{
char *escsearchstr = percent_plus_escape (searchstr);
if (!escsearchstr)
{
err = gpg_error_from_syserror ();
close_context (ctrl, ctx);
return err;
}
snprintf (line, sizeof line, "KS_SEARCH -- %s", escsearchstr);
xfree (escsearchstr);
}
memset (&parm, 0, sizeof parm);
init_membuf (&parm.saveddata, 1024);
parm.data_cb = cb;
parm.data_cb_value = cb_value;
err = assuan_transact (ctx, line, ks_search_data_cb, &parm,
NULL, NULL, NULL, NULL);
if (!err)
err = cb (cb_value, NULL); /* Send EOF. */
xfree (get_membuf (&parm.saveddata, NULL));
xfree (parm.helpbuf);
close_context (ctrl, ctx);
return err;
}
/* Data callback for the KS_GET command. */
static gpg_error_t
ks_get_data_cb (void *opaque, const void *data, size_t datalen)
{
gpg_error_t err = 0;
struct ks_get_parm_s *parm = opaque;
size_t nwritten;
if (!data)
return 0; /* Ignore END commands. */
if (es_write (parm->memfp, data, datalen, &nwritten))
err = gpg_error_from_syserror ();
return err;
}
/* Run the KS_GET command using the patterns in the array PATTERN. On
success an estream object is returned to retrieve the keys. On
error an error code is returned and NULL stored at R_FP.
The pattern may only use search specification which a keyserver can
use to retriev keys. Because we know the format of the pattern we
don't need to escape the patterns before sending them to the
server.
If there are too many patterns the function returns an error. That
could be fixed by issuing several search commands or by
implementing a different interface. However with long keyids we
are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */
gpg_error_t
gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp)
{
gpg_error_t err;
assuan_context_t ctx;
struct ks_get_parm_s parm;
char *line = NULL;
size_t linelen;
membuf_t mb;
int idx;
memset (&parm, 0, sizeof parm);
*r_fp = NULL;
err = open_context (ctrl, &ctx);
if (err)
return err;
/* Lump all patterns into one string. */
init_membuf (&mb, 1024);
put_membuf_str (&mb, "KS_GET --");
for (idx=0; pattern[idx]; idx++)
{
put_membuf (&mb, " ", 1); /* Append Delimiter. */
put_membuf_str (&mb, pattern[idx]);
}
put_membuf (&mb, "", 1); /* Append Nul. */
line = get_membuf (&mb, &linelen);
if (!line)
{
err = gpg_error_from_syserror ();
goto leave;
}
if (linelen + 2 >= ASSUAN_LINELENGTH)
{
err = gpg_error (GPG_ERR_TOO_MANY);
goto leave;
}
parm.memfp = es_fopenmem (0, "rwb");
if (!parm.memfp)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = assuan_transact (ctx, line, ks_get_data_cb, &parm,
NULL, NULL, NULL, NULL);
if (err)
goto leave;
es_rewind (parm.memfp);
*r_fp = parm.memfp;
parm.memfp = NULL;
leave:
es_fclose (parm.memfp);
xfree (line);
close_context (ctrl, ctx);
return err;
}
/* Handle the KS_PUT inquiries. */
static gpg_error_t
ks_put_inq_cb (void *opaque, const char *line)
{
struct ks_put_parm_s *parm = opaque;
gpg_error_t err = 0;
if (!strncmp (line, "KEYBLOCK", 8) && (line[8] == ' ' || !line[8]))
{
if (parm->data)
err = assuan_send_data (parm->ctx, parm->data, parm->datalen);
}
else if (!strncmp (line, "KEYBLOCK_INFO", 13) && (line[13]==' ' || !line[13]))
{
kbnode_t node;
estream_t fp;
/* Parse the keyblock and send info lines back to the server. */
fp = es_fopenmem (0, "rw");
if (!fp)
err = gpg_error_from_syserror ();
for (node = parm->keyblock; !err && node; node=node->next)
{
switch(node->pkt->pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
{
PKT_public_key *pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, NULL);
es_fprintf (fp, "%s:%08lX%08lX:%u:%u:%u:%u:%s%s:\n",
node->pkt->pkttype==PKT_PUBLIC_KEY? "pub" : "sub",
(ulong)pk->keyid[0], (ulong)pk->keyid[1],
pk->pubkey_algo,
nbits_from_pk (pk),
pk->timestamp,
pk->expiredate,
pk->flags.revoked? "r":"",
pk->has_expired? "e":"");
}
break;
case PKT_USER_ID:
{
PKT_user_id *uid = node->pkt->pkt.user_id;
int r;
if (!uid->attrib_data)
{
es_fprintf (fp, "uid:");
/* Quote ':', '%', and any 8-bit characters. */
for (r=0; r < uid->len; r++)
{
if (uid->name[r] == ':'
|| uid->name[r]== '%'
|| (uid->name[r]&0x80))
es_fprintf (fp, "%%%02X", (byte)uid->name[r]);
else
es_putc (uid->name[r], fp);
}
es_fprintf (fp, ":%u:%u:%s%s:\n",
uid->created,uid->expiredate,
uid->is_revoked? "r":"",
uid->is_expired? "e":"");
}
}
break;
/* This bit is really for the benefit of people who
store their keys in LDAP servers. It makes it easy
to do queries for things like "all keys signed by
Isabella". */
case PKT_SIGNATURE:
{
PKT_signature *sig = node->pkt->pkt.signature;
if (IS_UID_SIG (sig))
{
es_fprintf (fp, "sig:%08lX%08lX:%X:%u:%u:\n",
(ulong)sig->keyid[0],(ulong)sig->keyid[1],
sig->sig_class, sig->timestamp,
sig->expiredate);
}
}
break;
default:
continue;
}
/* Given that the last operation was an es_fprintf we should
get the correct ERRNO if ferror indicates an error. */
if (es_ferror (fp))
err = gpg_error_from_syserror ();
}
/* Without an error and if we have an keyblock at all, send the
data back. */
if (!err && parm->keyblock)
{
int rc;
char buffer[512];
size_t nread;
es_rewind (fp);
while (!(rc=es_read (fp, buffer, sizeof buffer, &nread)) && nread)
{
err = assuan_send_data (parm->ctx, buffer, nread);
if (err)
break;
}
if (!err && rc)
err = gpg_error_from_syserror ();
}
es_fclose (fp);
}
else
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
return err;
}
/* Send a key to the configured server. {DATA,DATLEN} contains the
key in OpenPGP binary transport format. If KEYBLOCK is not NULL it
has the internal representaion of that key; this is for example
used to convey meta data to LDAP keyservers. */
gpg_error_t
gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock)
{
gpg_error_t err;
assuan_context_t ctx;
struct ks_put_parm_s parm;
memset (&parm, 0, sizeof parm);
/* We are going to parse the keyblock, thus we better make sure the
all information is readily available. */
if (keyblock)
merge_keys_and_selfsig (keyblock);
err = open_context (ctrl, &ctx);
if (err)
return err;
parm.ctx = ctx;
parm.keyblock = keyblock;
parm.data = data;
parm.datalen = datalen;
err = assuan_transact (ctx, "KS_PUT", NULL, NULL,
ks_put_inq_cb, &parm, NULL, NULL);
close_context (ctrl, ctx);
return err;
}

32
g10/call-dirmngr.h Normal file
View File

@ -0,0 +1,32 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GNUPG_G10_CALL_DIRMNGR_H
#define GNUPG_G10_CALL_DIRMNGR_H
void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
gpg_error_t (*cb)(void*, char *),
void *cb_value);
gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[], estream_t *r_fp);
gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen,
kbnode_t keyblock);
#endif /*GNUPG_G10_CALL_DIRMNGR_H*/

View File

@ -114,6 +114,60 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
return rc;
}
/*
* Export a single key into a memory buffer.
*/
gpg_error_t
export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
{
gpg_error_t err;
iobuf_t iobuf;
int any;
strlist_t helplist;
*r_keyblock = NULL;
*r_data = NULL;
*r_datalen = 0;
helplist = NULL;
if (!add_to_strlist_try (&helplist, keyspec))
return gpg_error_from_syserror ();
iobuf = iobuf_temp ();
err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &any);
if (!err && !any)
err = gpg_error (GPG_ERR_NOT_FOUND);
if (!err)
{
const void *src;
size_t datalen;
iobuf_flush_temp (iobuf);
src = iobuf_get_temp_buffer (iobuf);
datalen = iobuf_get_temp_length (iobuf);
if (!datalen)
err = gpg_error (GPG_ERR_NO_PUBKEY);
else if (!(*r_data = xtrymalloc (datalen)))
err = gpg_error_from_syserror ();
else
{
memcpy (*r_data, src, datalen);
*r_datalen = datalen;
}
}
iobuf_close (iobuf);
free_strlist (helplist);
if (err && *r_keyblock)
{
release_kbnode (*r_keyblock);
*r_keyblock = NULL;
}
return err;
}
int
export_seckeys (ctrl_t ctrl, strlist_t users )
{

View File

@ -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;
@ -3751,12 +3752,12 @@ main (int argc, char **argv)
case aSearchKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
append_to_strlist2( &sl, *argv, utf8_strings );
for (; argc; argc--, argv++)
append_to_strlist2 (&sl, *argv, utf8_strings);
rc = keyserver_search (ctrl, sl);
if(rc)
log_error(_("keyserver search failed: %s\n"),g10_errstr(rc));
free_strlist(sl);
if (rc)
log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
free_strlist (sl);
break;
case aRefreshKeys:

View File

@ -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;
};

View File

@ -243,6 +243,32 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
fpr, fpr_len, options);
}
/* Variant of import_keys_stream reading from an estream_t. */
int
import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
unsigned int options)
{
int rc;
iobuf_t inp;
inp = iobuf_esopen (fp, "r", 1);
if (!inp)
{
rc = gpg_error_from_syserror ();
log_error ("iobuf_esopen failed: %s\n", gpg_strerror (rc));
return rc;
}
rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
fpr, fpr_len, options);
iobuf_close (inp);
return rc;
}
static int
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options )

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -287,6 +287,9 @@ void import_keys (ctrl_t ctrl, char **fnames, int nnames,
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd,
unsigned char **fpr,
size_t *fpr_len, unsigned int options);
int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
unsigned int options);
void *import_new_stats_handle (void);
void import_release_stats_handle (void *p);
void import_print_stats (void *hd);
@ -299,6 +302,10 @@ int parse_export_options(char *str,unsigned int *options,int noisy);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options );
int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
kbnode_t *keyblock_out, unsigned int options );
gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
unsigned int options,
kbnode_t *r_keyblock,
void **r_data, size_t *r_datalen);
int export_seckeys (ctrl_t ctrl, strlist_t users);
int export_secsubkeys (ctrl_t ctrl, strlist_t users);

View File

@ -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;

View File

@ -1,3 +1,9 @@
2011-01-20 Werner Koch <wk@g10code.com>
* gpgkeys_hkp.c (get_name): Remove test for KS_GETNAME. It is
always true.
(search_key): Remove test for KS_GETNAME. It is always false.
2009-08-26 Werner Koch <wk@g10code.com>
* gpgkeys_hkp.c: Include util.h.

View File

@ -340,7 +340,7 @@ get_name(const char *getkey)
opt->path,
appendable_path (opt->path,"/pks/lookup?op=get&options=mr&search="),
searchkey_encoded,
opt->action == KS_GETNAME? "&exact=on":"",
"&exact=on",
NULL);
if(!request)
{
@ -429,7 +429,6 @@ search_key(const char *searchkey)
appendable_path (opt->path, "/pks/lookup?op=index&options=mr&search="),
hexprefix,
searchkey_encoded,
opt->action == KS_GETNAME? "&exact=on":"",
NULL);
if(!request)
{
@ -687,7 +686,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";

View File

@ -1,3 +1,7 @@
2011-01-20 Werner Koch <wk@g10code.com>
* de.po: Fix two fuzzies.
2010-10-21 Werner Koch <wk@g10code.com>
* POTFILES.in: Add files in dirmngr/.

1176
po/de.po

File diff suppressed because it is too large Load Diff