mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Merge branch 'STABLE-BRANCH-2-2' into master
-- Resolved Conflicts: NEWS - removed configure.ac - removed Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
commit
7b7576637d
73 changed files with 3270 additions and 3583 deletions
|
@ -423,6 +423,9 @@ load_certs_from_dir (const char *dirname, unsigned int trustclass)
|
|||
log_info (_("certificate '%s' already cached\n"), fname);
|
||||
else if (!err)
|
||||
{
|
||||
if ((trustclass & CERTTRUST_CLASS_CONFIG))
|
||||
http_register_cfg_ca (fname);
|
||||
|
||||
if (trustclass)
|
||||
log_info (_("trusted certificate '%s' loaded\n"), fname);
|
||||
else
|
||||
|
@ -763,6 +766,8 @@ cert_cache_deinit (int full)
|
|||
}
|
||||
}
|
||||
|
||||
http_register_cfg_ca (NULL);
|
||||
|
||||
total_nonperm_certificates = 0;
|
||||
any_cert_of_class = 0;
|
||||
initialization_done = 0;
|
||||
|
|
|
@ -125,6 +125,9 @@
|
|||
idea anyway to limit the number of opened cache files. */
|
||||
#define MAX_OPEN_DB_FILES 5
|
||||
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
static const char oidstr_crlNumber[] = "2.5.29.20";
|
||||
/* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
|
||||
|
@ -1139,7 +1142,7 @@ lock_db_file (crl_cache_t cache, crl_cache_entry_t entry)
|
|||
xfree (fname);
|
||||
return NULL;
|
||||
}
|
||||
fd = open (fname, O_RDONLY);
|
||||
fd = open (fname, O_RDONLY | O_BINARY);
|
||||
if (fd == -1)
|
||||
{
|
||||
log_error (_("error opening cache file '%s': %s\n"),
|
||||
|
@ -2051,7 +2054,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
|
|||
}
|
||||
}
|
||||
|
||||
fd_cdb = open (fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
fd_cdb = open (fname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
||||
if (fd_cdb == -1)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "dirmngr.h"
|
||||
#include "misc.h"
|
||||
#include "http.h"
|
||||
#include "ks-engine.h" /* For ks_http_fetch. */
|
||||
|
||||
#if USE_LDAP
|
||||
# include "ldap-wrapper.h"
|
||||
|
@ -154,41 +155,17 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
|||
{
|
||||
gpg_error_t err;
|
||||
parsed_uri_t uri;
|
||||
char *free_this = NULL;
|
||||
int redirects_left = 2; /* We allow for 2 redirect levels. */
|
||||
estream_t httpfp = NULL;
|
||||
|
||||
*reader = NULL;
|
||||
|
||||
if (!url)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
once_more:
|
||||
err = http_parse_uri (&uri, url, 0);
|
||||
http_release_parsed_uri (uri);
|
||||
if (err && !strncmp (url, "https:", 6))
|
||||
{
|
||||
/* FIXME: We now support https.
|
||||
* Our HTTP code does not support TLS, thus we can't use this
|
||||
* scheme and it is frankly not useful for CRL retrieval anyway.
|
||||
* We resort to using http, assuming that the server also
|
||||
* provides plain http access. */
|
||||
free_this = xtrymalloc (strlen (url) + 1);
|
||||
if (free_this)
|
||||
{
|
||||
strcpy (stpcpy (free_this,"http:"), url+6);
|
||||
err = http_parse_uri (&uri, free_this, 0);
|
||||
http_release_parsed_uri (uri);
|
||||
if (!err)
|
||||
{
|
||||
log_info (_("using \"http\" instead of \"https\"\n"));
|
||||
url = free_this;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!err) /* Yes, our HTTP code groks that. */
|
||||
{
|
||||
http_t hd;
|
||||
|
||||
if (opt.disable_http)
|
||||
{
|
||||
log_error (_("CRL access not possible due to disabled %s\n"),
|
||||
|
@ -196,97 +173,57 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
|||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
else
|
||||
err = http_open_document (&hd, url, NULL,
|
||||
((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
|
||||
|(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0)
|
||||
|(dirmngr_use_tor()? HTTP_FLAG_FORCE_TOR:0)
|
||||
|(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4:0)
|
||||
|(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6:0)
|
||||
),
|
||||
ctrl->http_proxy, NULL, NULL, NULL);
|
||||
|
||||
switch ( err? 99999 : http_get_status_code (hd) )
|
||||
{
|
||||
case 200:
|
||||
{
|
||||
estream_t fp = http_get_read_ptr (hd);
|
||||
struct reader_cb_context_s *cb_ctx;
|
||||
/* Note that we also allow root certificates loaded from
|
||||
* "/etc/gnupg/trusted-certs/". We also do not consult the
|
||||
* CRL for the TLS connection - that may lead to a loop.
|
||||
* Due to cacert.org redirecting their https URL to http we
|
||||
* also allow such a downgrade. */
|
||||
err = ks_http_fetch (ctrl, url,
|
||||
(KS_HTTP_FETCH_TRUST_CFG
|
||||
| KS_HTTP_FETCH_NO_CRL
|
||||
| KS_HTTP_FETCH_ALLOW_DOWNGRADE ),
|
||||
&httpfp);
|
||||
}
|
||||
|
||||
cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
|
||||
if (!cb_ctx)
|
||||
err = gpg_error_from_syserror ();
|
||||
if (!err)
|
||||
err = ksba_reader_new (reader);
|
||||
if (!err)
|
||||
{
|
||||
cb_ctx->fp = fp;
|
||||
err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error initializing reader object: %s\n"),
|
||||
gpg_strerror (err));
|
||||
ksba_reader_release (*reader);
|
||||
*reader = NULL;
|
||||
http_close (hd, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The ksba reader misses a user pointer thus we need
|
||||
to come up with our own way of associating a file
|
||||
pointer (or well the callback context) with the
|
||||
reader. It is only required when closing the
|
||||
reader thus there is no performance issue doing it
|
||||
this way. FIXME: We now have a close notification
|
||||
which might be used here. */
|
||||
register_file_reader (*reader, cb_ctx);
|
||||
http_close (hd, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (err)
|
||||
log_error (_("error retrieving '%s': %s\n"), url, gpg_strerror (err));
|
||||
else
|
||||
{
|
||||
struct reader_cb_context_s *cb_ctx;
|
||||
|
||||
case 301: /* Redirection (perm.). */
|
||||
case 302: /* Redirection (temp.). */
|
||||
{
|
||||
const char *s = http_get_header (hd, "Location");
|
||||
cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
|
||||
if (!cb_ctx)
|
||||
err = gpg_error_from_syserror ();
|
||||
else if (!(err = ksba_reader_new (reader)))
|
||||
{
|
||||
cb_ctx->fp = httpfp;
|
||||
err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
|
||||
if (!err)
|
||||
{
|
||||
/* The ksba reader misses a user pointer thus we
|
||||
* need to come up with our own way of associating a
|
||||
* file pointer (or well the callback context) with
|
||||
* the reader. It is only required when closing the
|
||||
* reader thus there is no performance issue doing
|
||||
* it this way. FIXME: We now have a close
|
||||
* notification which might be used here. */
|
||||
register_file_reader (*reader, cb_ctx);
|
||||
httpfp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
|
||||
url, s?s:"[none]", http_get_status_code (hd));
|
||||
if (s && *s && redirects_left-- )
|
||||
{
|
||||
xfree (free_this); url = NULL;
|
||||
free_this = xtrystrdup (s);
|
||||
if (!free_this)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
{
|
||||
url = free_this;
|
||||
http_close (hd, 0);
|
||||
/* Note, that our implementation of redirection
|
||||
actually handles a redirect to LDAP. */
|
||||
goto once_more;
|
||||
}
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
log_error (_("too many redirections\n")); /* Or no "Location". */
|
||||
http_close (hd, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 99999: /* Made up status code for error reporting. */
|
||||
log_error (_("error retrieving '%s': %s\n"),
|
||||
url, gpg_strerror (err));
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error (_("error retrieving '%s': http status %u\n"),
|
||||
url, http_get_status_code (hd));
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
http_close (hd, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error initializing reader object: %s\n"),
|
||||
gpg_strerror (err));
|
||||
ksba_reader_release (*reader);
|
||||
*reader = NULL;
|
||||
xfree (cb_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Let the LDAP code try other schemes. */
|
||||
else /* Let the LDAP code parse other schemes. */
|
||||
{
|
||||
if (opt.disable_ldap)
|
||||
{
|
||||
|
@ -310,7 +247,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
|||
}
|
||||
}
|
||||
|
||||
xfree (free_this);
|
||||
es_fclose (httpfp);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -2243,7 +2243,8 @@ handle_connections (assuan_fd_t listen_fd)
|
|||
npth_timersub (&abstime, &curtime, &timeout);
|
||||
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
|
||||
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
|
||||
npth_sigev_sigmask());
|
||||
saved_errno = errno;
|
||||
|
||||
while (npth_sigev_get_pending(&signo))
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
# include <signal.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#ifndef USE_LDAPWRAPPER
|
||||
|
@ -343,7 +342,7 @@ ldap_wrapper_main (char **argv, estream_t outstream)
|
|||
usage (1);
|
||||
#else
|
||||
/* All passed arguments should be fine in this case. */
|
||||
assert (argc);
|
||||
log_assert (argc);
|
||||
#endif
|
||||
|
||||
#ifdef USE_LDAPWRAPPER
|
||||
|
@ -382,16 +381,56 @@ catch_alarm (int dummy)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static DWORD CALLBACK
|
||||
alarm_thread (void *arg)
|
||||
{
|
||||
HANDLE timer = arg;
|
||||
|
||||
WaitForSingleObject (timer, INFINITE);
|
||||
_exit (10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
set_timeout (my_opt_t myopt)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* FIXME for W32. */
|
||||
(void)myopt;
|
||||
#else
|
||||
if (myopt->alarm_timeout)
|
||||
alarm (myopt->alarm_timeout);
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static HANDLE timer;
|
||||
LARGE_INTEGER due_time;
|
||||
|
||||
/* A negative value is a relative time. */
|
||||
due_time.QuadPart = (unsigned long long)-10000000 * myopt->alarm_timeout;
|
||||
|
||||
if (!timer)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sec_attr;
|
||||
DWORD tid;
|
||||
|
||||
memset (&sec_attr, 0, sizeof sec_attr);
|
||||
sec_attr.nLength = sizeof sec_attr;
|
||||
sec_attr.bInheritHandle = FALSE;
|
||||
|
||||
/* Create a manual resetable timer. */
|
||||
timer = CreateWaitableTimer (NULL, TRUE, NULL);
|
||||
/* Intially set the timer. */
|
||||
SetWaitableTimer (timer, &due_time, 0, NULL, NULL, 0);
|
||||
|
||||
if (CreateThread (&sec_attr, 0, alarm_thread, timer, 0, &tid))
|
||||
log_error ("failed to create alarm thread\n");
|
||||
}
|
||||
else /* Retrigger the timer. */
|
||||
SetWaitableTimer (timer, &due_time, 0, NULL, NULL, 0);
|
||||
#else
|
||||
alarm (myopt->alarm_timeout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -87,13 +87,15 @@ gnupg_http_tls_verify_cb (void *opaque,
|
|||
}
|
||||
else /* Use the certificates as requested from the HTTP module. */
|
||||
{
|
||||
if ((http_flags & HTTP_FLAG_TRUST_CFG))
|
||||
validate_flags |= VALIDATE_FLAG_TRUST_CONFIG;
|
||||
if ((http_flags & HTTP_FLAG_TRUST_DEF))
|
||||
validate_flags |= VALIDATE_FLAG_TRUST_HKP;
|
||||
if ((http_flags & HTTP_FLAG_TRUST_SYS))
|
||||
validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM;
|
||||
|
||||
/* If HKP trust is requested and there are no HKP certificates
|
||||
* configured, also try thye standard system certificates. */
|
||||
* configured, also try the standard system certificates. */
|
||||
if ((validate_flags & VALIDATE_FLAG_TRUST_HKP)
|
||||
&& !cert_cache_any_in_class (CERTTRUST_CLASS_HKP))
|
||||
validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM;
|
||||
|
|
|
@ -318,6 +318,9 @@ static gpg_error_t (*tls_callback) (http_t, http_session_t, int);
|
|||
/* The list of files with trusted CA certificates. */
|
||||
static strlist_t tls_ca_certlist;
|
||||
|
||||
/* The list of files with extra trusted CA certificates. */
|
||||
static strlist_t cfg_ca_certlist;
|
||||
|
||||
/* The global callback for net activity. */
|
||||
static void (*netactivity_cb)(void);
|
||||
|
||||
|
@ -596,6 +599,35 @@ http_register_tls_ca (const char *fname)
|
|||
}
|
||||
|
||||
|
||||
/* Register a CA certificate for future use. The certificate is
|
||||
* expected to be in FNAME. PEM format is assume if FNAME has a
|
||||
* suffix of ".pem". If FNAME is NULL the list of CA files is
|
||||
* removed. This is a variant of http_register_tls_ca which puts the
|
||||
* certificate into a separate list enabled using HTTP_FLAG_TRUST_CFG. */
|
||||
void
|
||||
http_register_cfg_ca (const char *fname)
|
||||
{
|
||||
strlist_t sl;
|
||||
|
||||
if (!fname)
|
||||
{
|
||||
free_strlist (cfg_ca_certlist);
|
||||
cfg_ca_certlist = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Warn if we can't access right now, but register it anyway in
|
||||
case it becomes accessible later */
|
||||
if (access (fname, F_OK))
|
||||
log_info (_("can't access '%s': %s\n"), fname,
|
||||
gpg_strerror (gpg_error_from_syserror()));
|
||||
sl = add_to_strlist (&cfg_ca_certlist, fname);
|
||||
if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
|
||||
sl->flags = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register a callback which is called every time the HTTP mode has
|
||||
* made a successful connection to some server. */
|
||||
void
|
||||
|
@ -680,6 +712,7 @@ http_session_release (http_session_t sess)
|
|||
* Valid values for FLAGS are:
|
||||
* HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca
|
||||
* HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system
|
||||
* HTTP_FLAG_TRUST_CFG - Also use CAs set with http_register_cfg_ca
|
||||
* HTTP_FLAG_NO_CRL - Do not consult CRLs for https.
|
||||
*/
|
||||
gpg_error_t
|
||||
|
@ -793,6 +826,21 @@ http_session_new (http_session_t *r_session,
|
|||
#endif /* gnutls >= 3.0.20 */
|
||||
}
|
||||
|
||||
/* Add other configured certificates to the session. */
|
||||
if ((flags & HTTP_FLAG_TRUST_CFG))
|
||||
{
|
||||
for (sl = cfg_ca_certlist; sl; sl = sl->next)
|
||||
{
|
||||
rc = gnutls_certificate_set_x509_trust_file
|
||||
(sess->certcred, sl->d,
|
||||
(sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
|
||||
if (rc < 0)
|
||||
log_info ("setting extra CA from file '%s' failed: %s\n",
|
||||
sl->d, gnutls_strerror (rc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
|
||||
if (rc < 0)
|
||||
{
|
||||
|
@ -1688,9 +1736,19 @@ send_request (http_t hd, const char *httphost, const char *auth,
|
|||
#ifdef USE_TLS
|
||||
if (hd->uri->use_tls && !hd->session->tls_session)
|
||||
{
|
||||
log_error ("TLS requested but no GNUTLS context available\n");
|
||||
log_error ("TLS requested but no TLS context available\n");
|
||||
return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
|
||||
}
|
||||
if (opt_debug)
|
||||
log_debug ("Using TLS library: %s %s\n",
|
||||
# if HTTP_USE_NTBTLS
|
||||
"NTBTLS", ntbtls_check_version (NULL)
|
||||
# elif HTTP_USE_GNUTLS
|
||||
"GNUTLS", gnutls_check_version (NULL)
|
||||
# else
|
||||
"?", "?"
|
||||
# endif /*HTTP_USE_*TLS*/
|
||||
);
|
||||
#endif /*USE_TLS*/
|
||||
|
||||
if ((hd->flags & HTTP_FLAG_FORCE_TOR))
|
||||
|
|
|
@ -88,8 +88,9 @@ enum
|
|||
HTTP_FLAG_IGNORE_IPv4 = 64, /* Do not use IPv4. */
|
||||
HTTP_FLAG_IGNORE_IPv6 = 128, /* Do not use IPv6. */
|
||||
HTTP_FLAG_TRUST_DEF = 256, /* Use the CAs configured for HKP. */
|
||||
HTTP_FLAG_TRUST_SYS = 512, /* Also use the system defined CAs. */
|
||||
HTTP_FLAG_NO_CRL = 1024 /* Do not consult CRLs for https. */
|
||||
HTTP_FLAG_TRUST_SYS = 512, /* Also use the system defined CAs. */
|
||||
HTTP_FLAG_TRUST_CFG = 1024, /* Also use configured CAs. */
|
||||
HTTP_FLAG_NO_CRL = 2048 /* Do not consult CRLs for https. */
|
||||
};
|
||||
|
||||
|
||||
|
@ -110,6 +111,7 @@ void http_set_verbose (int verbose, int debug);
|
|||
|
||||
void http_register_tls_callback (gpg_error_t (*cb)(http_t,http_session_t,int));
|
||||
void http_register_tls_ca (const char *fname);
|
||||
void http_register_cfg_ca (const char *fname);
|
||||
void http_register_netactivity_cb (void (*cb)(void));
|
||||
|
||||
|
||||
|
|
|
@ -257,7 +257,9 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
|||
if (is_hkp_s)
|
||||
err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
|
||||
else if (is_http_s)
|
||||
err = ks_http_fetch (ctrl, uri->parsed_uri->original, &infp);
|
||||
err = ks_http_fetch (ctrl, uri->parsed_uri->original,
|
||||
KS_HTTP_FETCH_NOCACHE,
|
||||
&infp);
|
||||
else
|
||||
BUG ();
|
||||
|
||||
|
@ -314,7 +316,7 @@ ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
|
|||
|
||||
if (parsed_uri->is_http)
|
||||
{
|
||||
err = ks_http_fetch (ctrl, url, &infp);
|
||||
err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_NOCACHE, &infp);
|
||||
if (!err)
|
||||
{
|
||||
err = copy_stream (infp, outfp);
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
|
||||
|
||||
/* Number of seconds after a host is marked as resurrected. */
|
||||
#define RESURRECT_INTERVAL (3600*3) /* 3 hours */
|
||||
#define RESURRECT_INTERVAL (3600+1800) /* 1.5 hours */
|
||||
|
||||
/* To match the behaviour of our old gpgkeys helper code we escape
|
||||
more characters than actually needed. */
|
||||
|
@ -110,7 +110,7 @@ static hostinfo_t *hosttable;
|
|||
static int hosttable_size;
|
||||
|
||||
/* The number of host slots we initially allocate for HOSTTABLE. */
|
||||
#define INITIAL_HOSTTABLE_SIZE 10
|
||||
#define INITIAL_HOSTTABLE_SIZE 50
|
||||
|
||||
|
||||
/* Create a new hostinfo object, fill in NAME and put it into
|
||||
|
@ -583,7 +583,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
|
|||
/* Deal with the pool name before selecting a host. */
|
||||
if (r_httphost)
|
||||
{
|
||||
*r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name);
|
||||
*r_httphost = xtrystrdup (hi->name);
|
||||
if (!*r_httphost)
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
|
|
|
@ -62,12 +62,17 @@ ks_http_help (ctrl_t ctrl, parsed_uri_t uri)
|
|||
|
||||
|
||||
/* Get the key from URL which is expected to specify a http style
|
||||
scheme. On success R_FP has an open stream to read the data. */
|
||||
* scheme. On success R_FP has an open stream to read the data.
|
||||
* Despite its name this function is also used to retrieve arbitrary
|
||||
* data via https or http.
|
||||
*/
|
||||
gpg_error_t
|
||||
ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
||||
ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
estream_t *r_fp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
http_session_t session = NULL;
|
||||
unsigned int session_flags;
|
||||
http_t http = NULL;
|
||||
int redirects_left = MAX_REDIRECTS;
|
||||
estream_t fp = NULL;
|
||||
|
@ -81,12 +86,16 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
|||
is_onion = uri->onion;
|
||||
is_https = uri->use_tls;
|
||||
|
||||
once_more:
|
||||
/* Note that we only use the system provided certificates with the
|
||||
/* By default we only use the system provided certificates with this
|
||||
* fetch command. */
|
||||
err = http_session_new (&session, NULL,
|
||||
((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
|
||||
| HTTP_FLAG_TRUST_SYS),
|
||||
session_flags = HTTP_FLAG_TRUST_SYS;
|
||||
if ((flags & KS_HTTP_FETCH_NO_CRL) || ctrl->http_no_crl)
|
||||
session_flags |= HTTP_FLAG_NO_CRL;
|
||||
if ((flags & KS_HTTP_FETCH_TRUST_CFG))
|
||||
session_flags |= HTTP_FLAG_TRUST_CFG;
|
||||
|
||||
once_more:
|
||||
err = http_session_new (&session, NULL, session_flags,
|
||||
gnupg_http_tls_verify_cb, ctrl);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
@ -100,6 +109,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
|||
/* httphost */ NULL,
|
||||
/* fixme: AUTH */ NULL,
|
||||
((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
|
||||
| (DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0)
|
||||
| (dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
|
||||
| (opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
|
||||
| (opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
|
||||
|
@ -111,10 +121,11 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
|||
{
|
||||
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);
|
||||
* both the Pragma and Cache-Control versions of the header, so
|
||||
* we're good with both HTTP 1.0 and 1.1. */
|
||||
if ((flags & KS_HTTP_FETCH_NOCACHE))
|
||||
es_fputs ("Pragma: no-cache\r\n"
|
||||
"Cache-Control: no-cache\r\n", fp);
|
||||
http_start_data (http);
|
||||
if (es_ferror (fp))
|
||||
err = gpg_error_from_syserror ();
|
||||
|
@ -164,7 +175,13 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
|||
if (err)
|
||||
goto leave;
|
||||
|
||||
if ((is_onion && ! uri->onion) || (is_https && ! uri->use_tls))
|
||||
if (is_onion && !uri->onion)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
goto leave;
|
||||
}
|
||||
if (!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE)
|
||||
&& is_https && !uri->use_tls)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
goto leave;
|
||||
|
|
|
@ -41,8 +41,16 @@ gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri,
|
|||
const void *data, size_t datalen);
|
||||
|
||||
/*-- ks-engine-http.c --*/
|
||||
|
||||
/* Flags for the ks_http_fetch. */
|
||||
#define KS_HTTP_FETCH_NOCACHE 1 /* Request no caching. */
|
||||
#define KS_HTTP_FETCH_TRUST_CFG 2 /* Requests HTTP_FLAG_TRUST_CFG. */
|
||||
#define KS_HTTP_FETCH_NO_CRL 4 /* Requests HTTP_FLAG_NO_CRL. */
|
||||
#define KS_HTTP_FETCH_ALLOW_DOWNGRADE 8 /* Allow redirect https -> http. */
|
||||
|
||||
gpg_error_t ks_http_help (ctrl_t ctrl, parsed_uri_t uri);
|
||||
gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp);
|
||||
gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
estream_t *r_fp);
|
||||
|
||||
|
||||
/*-- ks-engine-finger.c --*/
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#ifdef USE_LDAPWRAPPER
|
||||
# error This module is not expected to be build.
|
||||
#endif
|
||||
#error This module might not anymore work.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* ldap-wrapper.c - LDAP access via a wrapper process
|
||||
* Copyright (C) 2004, 2005, 2007, 2008 g10 Code GmbH
|
||||
* Copyright (C) 2004, 2005, 2007, 2008, 2018 g10 Code GmbH
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
|
@ -19,31 +19,34 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
We can't use LDAP directly for these reasons:
|
||||
|
||||
1. On some systems the LDAP library uses (indirectly) pthreads and
|
||||
that is not compatible with PTh.
|
||||
|
||||
2. It is huge library in particular if TLS comes into play. So
|
||||
problems with unfreed memory might turn up and we don't want
|
||||
this in a long running daemon.
|
||||
|
||||
3. There is no easy way for timeouts. In particular the timeout
|
||||
value does not work for DNS lookups (well, this is usual) and it
|
||||
seems not to work while loading a large attribute like a
|
||||
CRL. Having a separate process allows us to either tell the
|
||||
process to commit suicide or have our own housekepping function
|
||||
kill it after some time. The latter also allows proper
|
||||
cancellation of a query at any point of time.
|
||||
|
||||
4. Given that we are going out to the network and usually get back
|
||||
a long response, the fork/exec overhead is acceptable.
|
||||
|
||||
Note that under WindowsCE the number of processes is strongly
|
||||
limited (32 processes including the kernel processes) and thus we
|
||||
don't use the process approach but implement a different wrapper in
|
||||
ldap-wrapper-ce.c.
|
||||
*/
|
||||
* We can't use LDAP directly for these reasons:
|
||||
*
|
||||
* 1. On some systems the LDAP library uses (indirectly) pthreads and
|
||||
* that is not compatible with GNU Pth. Since 2.1 we use nPth
|
||||
* instead of GNU Pth which does not have this problem anymore
|
||||
* because it will use pthreads if the platform supports it. Thus
|
||||
* this was a historical reasons.
|
||||
*
|
||||
* 2. It is huge library in particular if TLS comes into play. So
|
||||
* problems with unfreed memory might turn up and we don't want
|
||||
* this in a long running daemon.
|
||||
*
|
||||
* 3. There is no easy way for timeouts. In particular the timeout
|
||||
* value does not work for DNS lookups (well, this is usual) and it
|
||||
* seems not to work while loading a large attribute like a
|
||||
* CRL. Having a separate process allows us to either tell the
|
||||
* process to commit suicide or have our own housekepping function
|
||||
* kill it after some time. The latter also allows proper
|
||||
* cancellation of a query at any point of time.
|
||||
*
|
||||
* 4. Given that we are going out to the network and usually get back
|
||||
* a long response, the fork/exec overhead is acceptable.
|
||||
*
|
||||
* Note that under WindowsCE the number of processes is strongly
|
||||
* limited (32 processes including the kernel processes) and thus we
|
||||
* don't use the process approach but implement a different wrapper in
|
||||
* ldap-wrapper-ce.c.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
@ -89,39 +92,66 @@ struct wrapper_context_s
|
|||
{
|
||||
struct wrapper_context_s *next;
|
||||
|
||||
pid_t pid; /* The pid of the wrapper process. */
|
||||
int printable_pid; /* Helper to print diagnostics after the process has
|
||||
been cleaned up. */
|
||||
int fd; /* Connected with stdout of the ldap wrapper. */
|
||||
gpg_error_t fd_error; /* Set to the gpg_error of the last read error
|
||||
if any. */
|
||||
int log_fd; /* Connected with stderr of the ldap wrapper. */
|
||||
ctrl_t ctrl; /* Connection data. */
|
||||
int ready; /* Internally used to mark to be removed contexts. */
|
||||
ksba_reader_t reader; /* The ksba reader object or NULL. */
|
||||
char *line; /* Used to print the log lines (malloced). */
|
||||
size_t linesize;/* Allocated size of LINE. */
|
||||
size_t linelen; /* Use size of LINE. */
|
||||
time_t stamp; /* The last time we noticed ativity. */
|
||||
pid_t pid; /* The pid of the wrapper process. */
|
||||
int printable_pid; /* Helper to print diagnostics after the process has
|
||||
* been cleaned up. */
|
||||
estream_t fp; /* Connected with stdout of the ldap wrapper. */
|
||||
gpg_error_t fp_err; /* Set to the gpg_error of the last read error
|
||||
* if any. */
|
||||
estream_t log_fp; /* Connected with stderr of the ldap wrapper. */
|
||||
ctrl_t ctrl; /* Connection data. */
|
||||
int ready; /* Internally used to mark to be removed contexts. */
|
||||
ksba_reader_t reader;/* The ksba reader object or NULL. */
|
||||
char *line; /* Used to print the log lines (malloced). */
|
||||
size_t linesize; /* Allocated size of LINE. */
|
||||
size_t linelen; /* Use size of LINE. */
|
||||
time_t stamp; /* The last time we noticed ativity. */
|
||||
int reaper_idx; /* Private to ldap_wrapper_thread. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* We keep a global list of spawned wrapper process. A separate thread
|
||||
makes use of this list to log error messages and to watch out for
|
||||
finished processes. */
|
||||
static struct wrapper_context_s *wrapper_list;
|
||||
/* We keep a global list of spawned wrapper process. A separate
|
||||
* thread makes use of this list to log error messages and to watch
|
||||
* out for finished processes. Access to list is protected by a
|
||||
* mutex. The condition variable is used to wakeup the reaper
|
||||
* thread. */
|
||||
static struct wrapper_context_s *reaper_list;
|
||||
static npth_mutex_t reaper_list_mutex = NPTH_MUTEX_INITIALIZER;
|
||||
static npth_cond_t reaper_run_cond = NPTH_COND_INITIALIZER;
|
||||
|
||||
/* We need to know whether we are shutting down the process. */
|
||||
static int shutting_down;
|
||||
|
||||
/* Close the pth file descriptor FD and set it to -1. */
|
||||
#define SAFE_CLOSE(fd) \
|
||||
do { int _fd = fd; if (_fd != -1) { close (_fd); fd = -1;} } while (0)
|
||||
|
||||
|
||||
/* Close the estream fp and set it to NULL. */
|
||||
#define SAFE_CLOSE(fp) \
|
||||
do { estream_t _fp = fp; es_fclose (_fp); fp = NULL; } while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
lock_reaper_list (void)
|
||||
{
|
||||
if (npth_mutex_lock (&reaper_list_mutex))
|
||||
log_fatal ("%s: failed to acquire mutex: %s\n", __func__,
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
unlock_reaper_list (void)
|
||||
{
|
||||
if (npth_mutex_unlock (&reaper_list_mutex))
|
||||
log_fatal ("%s: failed to release mutex: %s\n", __func__,
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read a fixed amount of data from READER into BUFFER. */
|
||||
static gpg_error_t
|
||||
read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
|
||||
|
@ -151,8 +181,8 @@ destroy_wrapper (struct wrapper_context_s *ctx)
|
|||
gnupg_release_process (ctx->pid);
|
||||
}
|
||||
ksba_reader_release (ctx->reader);
|
||||
SAFE_CLOSE (ctx->fd);
|
||||
SAFE_CLOSE (ctx->log_fd);
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
xfree (ctx->line);
|
||||
xfree (ctx);
|
||||
}
|
||||
|
@ -218,25 +248,27 @@ print_log_line (struct wrapper_context_s *ctx, char *line)
|
|||
|
||||
|
||||
/* Read data from the log stream. Returns true if the log stream
|
||||
indicated EOF or error. */
|
||||
* indicated EOF or error. */
|
||||
static int
|
||||
read_log_data (struct wrapper_context_s *ctx)
|
||||
{
|
||||
int n;
|
||||
int rc;
|
||||
size_t n;
|
||||
char line[256];
|
||||
|
||||
/* We must use the npth_read function for pipes, always. */
|
||||
do
|
||||
n = npth_read (ctx->log_fd, line, sizeof line - 1);
|
||||
while (n < 0 && errno == EINTR);
|
||||
|
||||
if (n <= 0) /* EOF or error. */
|
||||
rc = es_read (ctx->log_fp, line, sizeof line - 1, &n);
|
||||
if (rc || !n) /* Error or EOF. */
|
||||
{
|
||||
if (n < 0)
|
||||
log_error (_("error reading log from ldap wrapper %d: %s\n"),
|
||||
(int)ctx->pid, strerror (errno));
|
||||
print_log_line (ctx, NULL);
|
||||
SAFE_CLOSE (ctx->log_fd);
|
||||
if (rc)
|
||||
{
|
||||
gpg_error_t err = gpg_error_from_syserror ();
|
||||
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
|
||||
return 0;
|
||||
log_error (_("error reading log from ldap wrapper %d: %s\n"),
|
||||
(int)ctx->pid, gpg_strerror (err));
|
||||
}
|
||||
print_log_line (ctx, NULL); /* Flush. */
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -251,15 +283,18 @@ read_log_data (struct wrapper_context_s *ctx)
|
|||
/* This function is run by a separate thread to maintain the list of
|
||||
wrappers and to log error messages from these wrappers. */
|
||||
void *
|
||||
ldap_wrapper_thread (void *dummy)
|
||||
ldap_reaper_thread (void *dummy)
|
||||
{
|
||||
int nfds;
|
||||
gpg_error_t err;
|
||||
struct wrapper_context_s *ctx;
|
||||
struct wrapper_context_s *ctx_prev;
|
||||
struct timespec abstime;
|
||||
struct timespec curtime;
|
||||
struct timespec timeout;
|
||||
fd_set fdset;
|
||||
int millisecs;
|
||||
gpgrt_poll_t *fparray = NULL;
|
||||
int fparraysize = 0;
|
||||
int count, i;
|
||||
int ret;
|
||||
time_t exptime;
|
||||
|
||||
|
@ -272,6 +307,61 @@ ldap_wrapper_thread (void *dummy)
|
|||
{
|
||||
int any_action = 0;
|
||||
|
||||
/* Wait until we are needed and then setup the FPARRAY. */
|
||||
/* Note: There is one unlock inside the block! */
|
||||
lock_reaper_list ();
|
||||
{
|
||||
while (!reaper_list && !shutting_down)
|
||||
{
|
||||
if (npth_cond_wait (&reaper_run_cond, &reaper_list_mutex))
|
||||
log_error ("ldap-reaper: waiting on condition failed: %s\n",
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
}
|
||||
|
||||
for (count = 0, ctx = reaper_list; ctx; ctx = ctx->next)
|
||||
if (ctx->log_fp)
|
||||
count++;
|
||||
if (count > fparraysize || !fparray)
|
||||
{
|
||||
/* Need to realloc the array. We simply discard it and
|
||||
* replace it by a new one. */
|
||||
xfree (fparray);
|
||||
fparray = xtrycalloc (count? count : 1, sizeof *fparray);
|
||||
if (!fparray)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("ldap-reaper can't allocate poll array: %s"
|
||||
" - waiting 1s\n", gpg_strerror (err));
|
||||
/* Note: Here we unlock and continue! */
|
||||
unlock_reaper_list ();
|
||||
npth_sleep (1);
|
||||
continue;
|
||||
}
|
||||
fparraysize = count;
|
||||
}
|
||||
for (count = 0, ctx = reaper_list; ctx; ctx = ctx->next)
|
||||
{
|
||||
if (ctx->log_fp)
|
||||
{
|
||||
log_assert (count < fparraysize);
|
||||
fparray[count].stream = ctx->log_fp;
|
||||
fparray[count].want_read = 1;
|
||||
fparray[count].ignore = 0;
|
||||
ctx->reaper_idx = count;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->reaper_idx = -1;
|
||||
fparray[count].ignore = 1;
|
||||
}
|
||||
}
|
||||
for (i=count; i < fparraysize; i++)
|
||||
fparray[i].ignore = 1;
|
||||
}
|
||||
unlock_reaper_list (); /* Note the one unlock inside the block. */
|
||||
|
||||
/* Compute the next timeout. */
|
||||
npth_clock_gettime (&curtime);
|
||||
if (!(npth_timercmp (&curtime, &abstime, <)))
|
||||
{
|
||||
|
@ -280,142 +370,166 @@ ldap_wrapper_thread (void *dummy)
|
|||
abstime.tv_sec += TIMERTICK_INTERVAL;
|
||||
}
|
||||
npth_timersub (&abstime, &curtime, &timeout);
|
||||
millisecs = timeout.tv_sec * 1000;
|
||||
millisecs += timeout.tv_nsec / 1000000;
|
||||
if (millisecs < 0)
|
||||
millisecs = 1;
|
||||
|
||||
FD_ZERO (&fdset);
|
||||
nfds = -1;
|
||||
for (ctx = wrapper_list; ctx; ctx = ctx->next)
|
||||
if (DBG_EXTPROG)
|
||||
{
|
||||
if (ctx->log_fd != -1)
|
||||
{
|
||||
FD_SET (ctx->log_fd, &fdset);
|
||||
if (ctx->log_fd > nfds)
|
||||
nfds = ctx->log_fd;
|
||||
}
|
||||
log_debug ("ldap-reaper: next run (count=%d size=%d, timeout=%d)\n",
|
||||
count, fparraysize, millisecs);
|
||||
for (count=0; count < fparraysize; count++)
|
||||
if (!fparray[count].ignore)
|
||||
log_debug ("ldap-reaper: fp[%d] stream=%p want=%d\n",
|
||||
count, fparray[count].stream,fparray[count].want_read);
|
||||
}
|
||||
nfds++;
|
||||
|
||||
/* FIXME: For Windows, we have to use a reader thread on the
|
||||
pipe that signals an event (and a npth_select_ev variant). */
|
||||
ret = npth_pselect (nfds + 1, &fdset, NULL, NULL, &timeout, NULL);
|
||||
if (ret == -1)
|
||||
ret = es_poll (fparray, fparraysize, millisecs);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
log_error (_("npth_select failed: %s - waiting 1s\n"),
|
||||
strerror (errno));
|
||||
npth_sleep (1);
|
||||
}
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("ldap-reaper failed to poll: %s"
|
||||
" - waiting 1s\n", gpg_strerror (err));
|
||||
/* In case the reason for the error is a too large array, we
|
||||
* release it so that it will be allocated smaller in the
|
||||
* next round. */
|
||||
xfree (fparray);
|
||||
fparray = NULL;
|
||||
fparraysize = 0;
|
||||
npth_sleep (1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DBG_EXTPROG)
|
||||
{
|
||||
for (count=0; count < fparraysize; count++)
|
||||
if (!fparray[count].ignore)
|
||||
log_debug ("ldap-reaper: fp[%d] stream=%p r=%d %c%c%c%c%c%c%c\n",
|
||||
count, fparray[count].stream, ret,
|
||||
fparray[count].got_read? 'r':'-',
|
||||
fparray[count].got_write?'w':'-',
|
||||
fparray[count].got_oob? 'o':'-',
|
||||
fparray[count].got_rdhup?'H':'-',
|
||||
fparray[count].got_err? 'e':'-',
|
||||
fparray[count].got_hup? 'h':'-',
|
||||
fparray[count].got_nval? 'n':'-');
|
||||
}
|
||||
|
||||
/* All timestamps before exptime should be considered expired. */
|
||||
exptime = time (NULL);
|
||||
if (exptime > INACTIVITY_TIMEOUT)
|
||||
exptime -= INACTIVITY_TIMEOUT;
|
||||
|
||||
/* Note that there is no need to lock the list because we always
|
||||
add entries at the head (with a pending event status) and
|
||||
thus traversing the list will even work if we have a context
|
||||
switch in waitpid (which should anyway only happen with Pth's
|
||||
hard system call mapping). */
|
||||
for (ctx = wrapper_list; ctx; ctx = ctx->next)
|
||||
{
|
||||
/* Check whether there is any logging to be done. */
|
||||
if (nfds && ctx->log_fd != -1 && FD_ISSET (ctx->log_fd, &fdset))
|
||||
{
|
||||
if (read_log_data (ctx))
|
||||
{
|
||||
SAFE_CLOSE (ctx->log_fd);
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether the process is still running. */
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
{
|
||||
gpg_error_t err;
|
||||
int status;
|
||||
|
||||
err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0,
|
||||
&status);
|
||||
if (!err)
|
||||
{
|
||||
log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
any_action = 1;
|
||||
}
|
||||
else if (gpg_err_code (err) == GPG_ERR_GENERAL)
|
||||
{
|
||||
if (status == 10)
|
||||
log_info (_("ldap wrapper %d ready: timeout\n"),
|
||||
(int)ctx->pid);
|
||||
else
|
||||
log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
|
||||
(int)ctx->pid, status);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
any_action = 1;
|
||||
}
|
||||
else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
|
||||
{
|
||||
log_error (_("waiting for ldap wrapper %d failed: %s\n"),
|
||||
(int)ctx->pid, gpg_strerror (err));
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether we should terminate the process. */
|
||||
if (ctx->pid != (pid_t)(-1)
|
||||
&& ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
|
||||
{
|
||||
gnupg_kill_process (ctx->pid);
|
||||
ctx->stamp = (time_t)(-1);
|
||||
log_info (_("ldap wrapper %d stalled - killing\n"),
|
||||
(int)ctx->pid);
|
||||
/* We need to close the log fd because the cleanup loop
|
||||
waits for it. */
|
||||
SAFE_CLOSE (ctx->log_fd);
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If something has been printed to the log file or we got an
|
||||
EOF from a wrapper, we now print the list of active
|
||||
wrappers. */
|
||||
if (any_action && DBG_LOOKUP)
|
||||
{
|
||||
log_info ("ldap worker stati:\n");
|
||||
for (ctx = wrapper_list; ctx; ctx = ctx->next)
|
||||
log_info (" c=%p pid=%d/%d rdr=%p ctrl=%p/%d la=%lu rdy=%d\n",
|
||||
ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->reader,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
|
||||
(unsigned long)ctx->stamp, ctx->ready);
|
||||
}
|
||||
|
||||
|
||||
/* Use a separate loop to check whether ready marked wrappers
|
||||
may be removed. We may only do so if the ksba reader object
|
||||
is not anymore in use or we are in shutdown state. */
|
||||
again:
|
||||
for (ctx_prev=NULL, ctx=wrapper_list; ctx; ctx_prev=ctx, ctx=ctx->next)
|
||||
if (ctx->ready
|
||||
&& ((ctx->log_fd == -1 && !ctx->reader) || shutting_down))
|
||||
lock_reaper_list ();
|
||||
{
|
||||
for (ctx = reaper_list; ctx; ctx = ctx->next)
|
||||
{
|
||||
if (ctx_prev)
|
||||
ctx_prev->next = ctx->next;
|
||||
else
|
||||
wrapper_list = ctx->next;
|
||||
destroy_wrapper (ctx);
|
||||
/* We need to restart because destroy_wrapper might have
|
||||
done a context switch. */
|
||||
goto again;
|
||||
/* Check whether there is any logging to be done. We need
|
||||
* to check FPARRAYSIZE because it can be 0 in case
|
||||
* es_poll returned a timeout. */
|
||||
if (fparraysize && ctx->log_fp && ctx->reaper_idx >= 0)
|
||||
{
|
||||
log_assert (ctx->reaper_idx < fparraysize);
|
||||
if (fparray[ctx->reaper_idx].got_read)
|
||||
{
|
||||
if (read_log_data (ctx))
|
||||
{
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether the process is still running. */
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
{
|
||||
int status;
|
||||
|
||||
err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0,
|
||||
&status);
|
||||
if (!err)
|
||||
{
|
||||
if (DBG_EXTPROG)
|
||||
log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
any_action = 1;
|
||||
}
|
||||
else if (gpg_err_code (err) == GPG_ERR_GENERAL)
|
||||
{
|
||||
if (status == 10)
|
||||
log_info (_("ldap wrapper %d ready: timeout\n"),
|
||||
(int)ctx->pid);
|
||||
else
|
||||
log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
|
||||
(int)ctx->pid, status);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
any_action = 1;
|
||||
}
|
||||
else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
|
||||
{
|
||||
log_error (_("waiting for ldap wrapper %d failed: %s\n"),
|
||||
(int)ctx->pid, gpg_strerror (err));
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether we should terminate the process. */
|
||||
if (ctx->pid != (pid_t)(-1)
|
||||
&& ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
|
||||
{
|
||||
gnupg_kill_process (ctx->pid);
|
||||
ctx->stamp = (time_t)(-1);
|
||||
log_info (_("ldap wrapper %d stalled - killing\n"),
|
||||
(int)ctx->pid);
|
||||
/* We need to close the log stream because the cleanup
|
||||
* loop waits for it. */
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If something has been printed to the log file or we got an
|
||||
* EOF from a wrapper, we now print the list of active
|
||||
* wrappers. */
|
||||
if (any_action && DBG_EXTPROG)
|
||||
{
|
||||
log_debug ("ldap worker stati:\n");
|
||||
for (ctx = reaper_list; ctx; ctx = ctx->next)
|
||||
log_debug (" c=%p pid=%d/%d rdr=%p logfp=%p"
|
||||
" ctrl=%p/%d la=%lu rdy=%d\n",
|
||||
ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->reader, ctx->log_fp,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
|
||||
(unsigned long)ctx->stamp, ctx->ready);
|
||||
}
|
||||
|
||||
/* An extra loop to check whether ready marked wrappers may be
|
||||
* removed. We may only do so if the ksba reader object is
|
||||
* not anymore in use or we are in shutdown state. */
|
||||
again:
|
||||
for (ctx_prev=NULL, ctx=reaper_list; ctx; ctx_prev=ctx, ctx=ctx->next)
|
||||
{
|
||||
if (ctx->ready
|
||||
&& ((!ctx->log_fp && !ctx->reader) || shutting_down))
|
||||
{
|
||||
if (ctx_prev)
|
||||
ctx_prev->next = ctx->next;
|
||||
else
|
||||
reaper_list = ctx->next;
|
||||
destroy_wrapper (ctx);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock_reaper_list ();
|
||||
}
|
||||
|
||||
/*NOTREACHED*/
|
||||
return NULL; /* Make the compiler happy. */
|
||||
}
|
||||
|
@ -424,7 +538,7 @@ ldap_wrapper_thread (void *dummy)
|
|||
|
||||
/* Start the reaper thread for the ldap wrapper. */
|
||||
void
|
||||
ldap_wrapper_launch_thread (void)
|
||||
ldap_reaper_launch_thread (void)
|
||||
{
|
||||
static int done;
|
||||
npth_attr_t tattr;
|
||||
|
@ -435,14 +549,21 @@ ldap_wrapper_launch_thread (void)
|
|||
return;
|
||||
done = 1;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Static init does not yet work in W32 nPth. */
|
||||
if (npth_cond_init (&reaper_run_cond, NULL))
|
||||
log_fatal ("%s: failed to init condition variabale: %s\n",
|
||||
__func__, gpg_strerror (gpg_error_from_syserror ()));
|
||||
#endif
|
||||
|
||||
npth_attr_init (&tattr);
|
||||
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
|
||||
|
||||
err = npth_create (&thread, &tattr, ldap_wrapper_thread, NULL);
|
||||
if (err)
|
||||
if (npth_create (&thread, &tattr, ldap_reaper_thread, NULL))
|
||||
{
|
||||
log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
|
||||
strerror (err) );
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error spawning ldap reaper reaper thread: %s\n",
|
||||
gpg_strerror (err) );
|
||||
dirmngr_exit (1);
|
||||
}
|
||||
npth_setname_np (thread, "ldap-reaper");
|
||||
|
@ -451,16 +572,20 @@ ldap_wrapper_launch_thread (void)
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Wait until all ldap wrappers have terminated. We assume that the
|
||||
kill has already been sent to all of them. */
|
||||
void
|
||||
ldap_wrapper_wait_connections ()
|
||||
{
|
||||
shutting_down = 1;
|
||||
/* FIXME: This is a busy wait. */
|
||||
while (wrapper_list)
|
||||
lock_reaper_list ();
|
||||
{
|
||||
shutting_down = 1;
|
||||
if (npth_cond_signal (&reaper_run_cond))
|
||||
log_error ("%s: Ooops: signaling condition failed: %s\n",
|
||||
__func__, gpg_strerror (gpg_error_from_syserror ()));
|
||||
}
|
||||
unlock_reaper_list ();
|
||||
while (reaper_list)
|
||||
npth_usleep (200);
|
||||
}
|
||||
|
||||
|
@ -475,30 +600,35 @@ ldap_wrapper_release_context (ksba_reader_t reader)
|
|||
if (!reader )
|
||||
return;
|
||||
|
||||
for (ctx=wrapper_list; ctx; ctx=ctx->next)
|
||||
if (ctx->reader == reader)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_info ("releasing ldap worker c=%p pid=%d/%d rdr=%p ctrl=%p/%d\n",
|
||||
ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->reader,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
|
||||
lock_reaper_list ();
|
||||
{
|
||||
for (ctx=reaper_list; ctx; ctx=ctx->next)
|
||||
if (ctx->reader == reader)
|
||||
{
|
||||
if (DBG_EXTPROG)
|
||||
log_debug ("releasing ldap worker c=%p pid=%d/%d rdr=%p"
|
||||
" ctrl=%p/%d\n", ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->reader,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
|
||||
|
||||
ctx->reader = NULL;
|
||||
SAFE_CLOSE (ctx->fd);
|
||||
if (ctx->ctrl)
|
||||
{
|
||||
ctx->ctrl->refcount--;
|
||||
ctx->ctrl = NULL;
|
||||
}
|
||||
if (ctx->fd_error)
|
||||
log_info (_("reading from ldap wrapper %d failed: %s\n"),
|
||||
ctx->printable_pid, gpg_strerror (ctx->fd_error));
|
||||
break;
|
||||
}
|
||||
ctx->reader = NULL;
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
if (ctx->ctrl)
|
||||
{
|
||||
ctx->ctrl->refcount--;
|
||||
ctx->ctrl = NULL;
|
||||
}
|
||||
if (ctx->fp_err)
|
||||
log_info ("%s: reading from ldap wrapper %d failed: %s\n",
|
||||
__func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock_reaper_list ();
|
||||
}
|
||||
|
||||
|
||||
/* Cleanup all resources held by the connection associated with
|
||||
CTRL. This is used after a cancel to kill running wrappers. */
|
||||
void
|
||||
|
@ -506,41 +636,45 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
|
|||
{
|
||||
struct wrapper_context_s *ctx;
|
||||
|
||||
for (ctx=wrapper_list; ctx; ctx=ctx->next)
|
||||
if (ctx->ctrl && ctx->ctrl == ctrl)
|
||||
{
|
||||
ctx->ctrl->refcount--;
|
||||
ctx->ctrl = NULL;
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
gnupg_kill_process (ctx->pid);
|
||||
if (ctx->fd_error)
|
||||
log_info (_("reading from ldap wrapper %d failed: %s\n"),
|
||||
ctx->printable_pid, gpg_strerror (ctx->fd_error));
|
||||
}
|
||||
lock_reaper_list ();
|
||||
{
|
||||
for (ctx=reaper_list; ctx; ctx=ctx->next)
|
||||
if (ctx->ctrl && ctx->ctrl == ctrl)
|
||||
{
|
||||
ctx->ctrl->refcount--;
|
||||
ctx->ctrl = NULL;
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
gnupg_kill_process (ctx->pid);
|
||||
if (ctx->fp_err)
|
||||
log_info ("%s: reading from ldap wrapper %d failed: %s\n",
|
||||
__func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
|
||||
}
|
||||
}
|
||||
unlock_reaper_list ();
|
||||
}
|
||||
|
||||
|
||||
/* This is the callback used by the ldap wrapper to feed the ksba
|
||||
reader with the wrappers stdout. See the description of
|
||||
ksba_reader_set_cb for details. */
|
||||
* reader with the wrapper's stdout. See the description of
|
||||
* ksba_reader_set_cb for details. */
|
||||
static int
|
||||
reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct wrapper_context_s *ctx = cb_value;
|
||||
size_t nleft = count;
|
||||
int nfds;
|
||||
struct timespec abstime;
|
||||
struct timespec curtime;
|
||||
struct timespec timeout;
|
||||
int saved_errno;
|
||||
fd_set fdset, read_fdset;
|
||||
int millisecs;
|
||||
gpgrt_poll_t fparray[1];
|
||||
int ret;
|
||||
gpg_error_t err;
|
||||
|
||||
|
||||
/* FIXME: We might want to add some internal buffering because the
|
||||
ksba code does not do any buffering for itself (because a ksba
|
||||
reader may be detached from another stream to read other data and
|
||||
the it would be cumbersome to get back already buffered
|
||||
stuff). */
|
||||
then it would be cumbersome to get back already buffered stuff). */
|
||||
|
||||
if (!buffer && !count && !nread)
|
||||
return -1; /* Rewind is not supported. */
|
||||
|
@ -548,81 +682,108 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread)
|
|||
/* If we ever encountered a read error, don't continue (we don't want to
|
||||
possibly overwrite the last error cause). Bail out also if the
|
||||
file descriptor has been closed. */
|
||||
if (ctx->fd_error || ctx->fd == -1)
|
||||
if (ctx->fp_err || !ctx->fp)
|
||||
{
|
||||
*nread = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO (&fdset);
|
||||
FD_SET (ctx->fd, &fdset);
|
||||
nfds = ctx->fd + 1;
|
||||
memset (fparray, 0, sizeof fparray);
|
||||
fparray[0].stream = ctx->fp;
|
||||
fparray[0].want_read = 1;
|
||||
|
||||
npth_clock_gettime (&abstime);
|
||||
abstime.tv_sec += TIMERTICK_INTERVAL;
|
||||
|
||||
while (nleft > 0)
|
||||
{
|
||||
int n;
|
||||
gpg_error_t err;
|
||||
|
||||
npth_clock_gettime (&curtime);
|
||||
if (!(npth_timercmp (&curtime, &abstime, <)))
|
||||
{
|
||||
err = dirmngr_tick (ctx->ctrl);
|
||||
if (err)
|
||||
{
|
||||
ctx->fd_error = err;
|
||||
SAFE_CLOSE (ctx->fd);
|
||||
ctx->fp_err = err;
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
return -1;
|
||||
}
|
||||
npth_clock_gettime (&abstime);
|
||||
abstime.tv_sec += TIMERTICK_INTERVAL;
|
||||
}
|
||||
npth_timersub (&abstime, &curtime, &timeout);
|
||||
millisecs = timeout.tv_sec * 1000;
|
||||
millisecs += timeout.tv_nsec / 1000000;
|
||||
if (millisecs < 0)
|
||||
millisecs = 1;
|
||||
|
||||
read_fdset = fdset;
|
||||
ret = npth_pselect (nfds, &read_fdset, NULL, NULL, &timeout, NULL);
|
||||
saved_errno = errno;
|
||||
if (DBG_EXTPROG)
|
||||
{
|
||||
log_debug ("%s: fp[0] stream=%p want=%d\n",
|
||||
__func__, fparray[0].stream,fparray[0].want_read);
|
||||
}
|
||||
|
||||
if (ret == -1 && saved_errno != EINTR)
|
||||
ret = es_poll (fparray, DIM (fparray), millisecs);
|
||||
if (ret < 0)
|
||||
{
|
||||
ctx->fd_error = gpg_error_from_errno (errno);
|
||||
SAFE_CLOSE (ctx->fd);
|
||||
ctx->fp_err = gpg_error_from_syserror ();
|
||||
log_error ("error polling stdout of ldap wrapper %d: %s\n",
|
||||
ctx->printable_pid, gpg_strerror (ctx->fp_err));
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
return -1;
|
||||
}
|
||||
if (ret <= 0)
|
||||
/* Timeout. Will be handled when calculating the next timeout. */
|
||||
continue;
|
||||
if (DBG_EXTPROG)
|
||||
{
|
||||
log_debug ("%s: fp[0] stream=%p r=%d %c%c%c%c%c%c%c\n",
|
||||
__func__, fparray[0].stream, ret,
|
||||
fparray[0].got_read? 'r':'-',
|
||||
fparray[0].got_write?'w':'-',
|
||||
fparray[0].got_oob? 'o':'-',
|
||||
fparray[0].got_rdhup?'H':'-',
|
||||
fparray[0].got_err? 'e':'-',
|
||||
fparray[0].got_hup? 'h':'-',
|
||||
fparray[0].got_nval? 'n':'-');
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
/* Timeout. Will be handled when calculating the next timeout. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This should not block now that select returned with a file
|
||||
descriptor. So it shouldn't be necessary to use npth_read
|
||||
(and it is slightly dangerous in the sense that a concurrent
|
||||
thread might (accidentially?) change the status of ctx->fd
|
||||
before we read. FIXME: Set ctx->fd to nonblocking? */
|
||||
n = read (ctx->fd, buffer, nleft);
|
||||
if (n < 0)
|
||||
if (fparray[0].got_read)
|
||||
{
|
||||
ctx->fd_error = gpg_error_from_errno (errno);
|
||||
SAFE_CLOSE (ctx->fd);
|
||||
return -1;
|
||||
size_t n;
|
||||
|
||||
if (es_read (ctx->fp, buffer, nleft, &n))
|
||||
{
|
||||
ctx->fp_err = gpg_error_from_syserror ();
|
||||
if (gpg_err_code (ctx->fp_err) == GPG_ERR_EAGAIN)
|
||||
ctx->fp_err = 0;
|
||||
else
|
||||
{
|
||||
log_error ("%s: error reading: %s (%d)\n",
|
||||
__func__, gpg_strerror (ctx->fp_err), ctx->fp_err);
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (!n) /* EOF */
|
||||
{
|
||||
if (nleft == count)
|
||||
return -1; /* EOF. */
|
||||
break;
|
||||
}
|
||||
nleft -= n;
|
||||
buffer += n;
|
||||
if (n > 0 && ctx->stamp != (time_t)(-1))
|
||||
ctx->stamp = time (NULL);
|
||||
}
|
||||
else if (!n)
|
||||
{
|
||||
if (nleft == count)
|
||||
return -1; /* EOF. */
|
||||
break;
|
||||
}
|
||||
nleft -= n;
|
||||
buffer += n;
|
||||
if (n > 0 && ctx->stamp != (time_t)(-1))
|
||||
ctx->stamp = time (NULL);
|
||||
}
|
||||
*nread = count - nleft;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Fork and exec the LDAP wrapper and return a new libksba reader
|
||||
object at READER. ARGV is a NULL terminated list of arguments for
|
||||
the wrapper. The function returns 0 on success or an error code.
|
||||
|
@ -646,7 +807,7 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
int j;
|
||||
const char **arg_list;
|
||||
const char *pgmname;
|
||||
int outpipe[2], errpipe[2];
|
||||
estream_t outfp, errfp;
|
||||
|
||||
/* It would be too simple to connect stderr just to our logging
|
||||
stream. The problem is that if we are running multi-threaded
|
||||
|
@ -656,7 +817,7 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
wrapper module to do the logging on its own. Given that we anyway
|
||||
need a way to reap the child process and this is best done using a
|
||||
general reaping thread, that thread can do the logging too. */
|
||||
ldap_wrapper_launch_thread ();
|
||||
ldap_reaper_launch_thread ();
|
||||
|
||||
*reader = NULL;
|
||||
|
||||
|
@ -696,41 +857,21 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
return err;
|
||||
}
|
||||
|
||||
err = gnupg_create_inbound_pipe (outpipe, NULL, 0);
|
||||
if (!err)
|
||||
{
|
||||
err = gnupg_create_inbound_pipe (errpipe, NULL, 0);
|
||||
if (err)
|
||||
{
|
||||
close (outpipe[0]);
|
||||
close (outpipe[1]);
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
|
||||
xfree (arg_list);
|
||||
xfree (ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gnupg_spawn_process_fd (pgmname, arg_list,
|
||||
-1, outpipe[1], errpipe[1], &pid);
|
||||
err = gnupg_spawn_process (pgmname, arg_list,
|
||||
NULL, NULL, GNUPG_SPAWN_NONBLOCK,
|
||||
NULL, &outfp, &errfp, &pid);
|
||||
xfree (arg_list);
|
||||
close (outpipe[1]);
|
||||
close (errpipe[1]);
|
||||
if (err)
|
||||
{
|
||||
close (outpipe[0]);
|
||||
close (errpipe[0]);
|
||||
xfree (ctx);
|
||||
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
ctx->pid = pid;
|
||||
ctx->printable_pid = (int) pid;
|
||||
ctx->fd = outpipe[0];
|
||||
ctx->log_fd = errpipe[0];
|
||||
ctx->fp = outfp;
|
||||
ctx->log_fp = errfp;
|
||||
ctx->ctrl = ctrl;
|
||||
ctrl->refcount++;
|
||||
ctx->stamp = time (NULL);
|
||||
|
@ -749,12 +890,20 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
}
|
||||
|
||||
/* Hook the context into our list of running wrappers. */
|
||||
ctx->reader = *reader;
|
||||
ctx->next = wrapper_list;
|
||||
wrapper_list = ctx;
|
||||
if (opt.verbose)
|
||||
log_info ("ldap wrapper %d started (reader %p)\n",
|
||||
(int)ctx->pid, ctx->reader);
|
||||
lock_reaper_list ();
|
||||
{
|
||||
ctx->reader = *reader;
|
||||
ctx->next = reaper_list;
|
||||
reaper_list = ctx;
|
||||
if (npth_cond_signal (&reaper_run_cond))
|
||||
log_error ("ldap-wrapper: Ooops: signaling condition failed: %s (%d)\n",
|
||||
gpg_strerror (gpg_error_from_syserror ()), errno);
|
||||
}
|
||||
unlock_reaper_list ();
|
||||
|
||||
if (DBG_EXTPROG)
|
||||
log_debug ("ldap wrapper %d started (%p, %s)\n",
|
||||
(int)ctx->pid, ctx->reader, pgmname);
|
||||
|
||||
/* Need to wait for the first byte so we are able to detect an empty
|
||||
output and not let the consumer see an EOF without further error
|
||||
|
|
|
@ -136,8 +136,12 @@ run_ldap_wrapper (ctrl_t ctrl,
|
|||
argv[argc++] = "--pass";
|
||||
argv[argc++] = pass;
|
||||
}
|
||||
if (opt.verbose)
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
argv[argc++] = "-vv";
|
||||
else if (DBG_EXTPROG)
|
||||
argv[argc++] = "-v";
|
||||
|
||||
argv[argc++] = "--log-with-pid";
|
||||
if (multi_mode)
|
||||
argv[argc++] = "--multi";
|
||||
|
@ -564,8 +568,12 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
|
|||
argv[argc++] = "--pass";
|
||||
argv[argc++] = pass;
|
||||
}
|
||||
if (opt.verbose)
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
argv[argc++] = "-vv";
|
||||
else if (DBG_EXTPROG)
|
||||
argv[argc++] = "-v";
|
||||
|
||||
argv[argc++] = "--log-with-pid";
|
||||
argv[argc++] = "--multi";
|
||||
if (opt.ldaptimeout)
|
||||
|
|
|
@ -126,7 +126,7 @@ fetch_file (ctrl_t ctrl, const char *url, estream_t *r_fp)
|
|||
size_t nread, nwritten;
|
||||
char buffer[1024];
|
||||
|
||||
if ((err = ks_http_fetch (ctrl, url, &httpfp)))
|
||||
if ((err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_NOCACHE, &httpfp)))
|
||||
goto leave;
|
||||
|
||||
/* We now read the data from the web server into a memory buffer.
|
||||
|
|
121
dirmngr/server.c
121
dirmngr/server.c
|
@ -1105,7 +1105,7 @@ cmd_ldapserver (assuan_context_t ctx, char *line)
|
|||
|
||||
static const char hlp_isvalid[] =
|
||||
"ISVALID [--only-ocsp] [--force-default-responder]"
|
||||
" <certificate_id>|<certificate_fpr>\n"
|
||||
" <certificate_id> [<certificate_fpr>]\n"
|
||||
"\n"
|
||||
"This command checks whether the certificate identified by the\n"
|
||||
"certificate_id is valid. This is done by consulting CRLs or\n"
|
||||
|
@ -1117,8 +1117,9 @@ static const char hlp_isvalid[] =
|
|||
"delimited by a single dot. The first part is the SHA-1 hash of the\n"
|
||||
"issuer name and the second part the serial number.\n"
|
||||
"\n"
|
||||
"Alternatively the certificate's fingerprint may be given in which\n"
|
||||
"case an OCSP request is done before consulting the CRL.\n"
|
||||
"If an OCSP check is desired CERTIFICATE_FPR with the hex encoded\n"
|
||||
"fingerprint of the certificate is required. In this case an OCSP\n"
|
||||
"request is done before consulting the CRL.\n"
|
||||
"\n"
|
||||
"If the option --only-ocsp is given, no fallback to a CRL check will\n"
|
||||
"be used.\n"
|
||||
|
@ -1130,7 +1131,7 @@ static gpg_error_t
|
|||
cmd_isvalid (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
char *issuerhash, *serialno;
|
||||
char *issuerhash, *serialno, *fpr;
|
||||
gpg_error_t err;
|
||||
int did_inquire = 0;
|
||||
int ocsp_mode = 0;
|
||||
|
@ -1141,25 +1142,36 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
|||
force_default_responder = has_option (line, "--force-default-responder");
|
||||
line = skip_options (line);
|
||||
|
||||
issuerhash = xstrdup (line); /* We need to work on a copy of the
|
||||
line because that same Assuan
|
||||
context may be used for an inquiry.
|
||||
That is because Assuan reuses its
|
||||
line buffer.
|
||||
*/
|
||||
/* We need to work on a copy of the line because that same Assuan
|
||||
* context may be used for an inquiry. That is because Assuan
|
||||
* reuses its line buffer. */
|
||||
issuerhash = xstrdup (line);
|
||||
|
||||
serialno = strchr (issuerhash, '.');
|
||||
if (serialno)
|
||||
*serialno++ = 0;
|
||||
else
|
||||
if (!serialno)
|
||||
{
|
||||
char *endp = strchr (issuerhash, ' ');
|
||||
xfree (issuerhash);
|
||||
return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID")));
|
||||
}
|
||||
*serialno++ = 0;
|
||||
if (strlen (issuerhash) != 40)
|
||||
{
|
||||
xfree (issuerhash);
|
||||
return leave_cmd (ctx, PARM_ERROR ("cert ID is too short"));
|
||||
}
|
||||
|
||||
fpr = strchr (serialno, ' ');
|
||||
while (fpr && spacep (fpr))
|
||||
fpr++;
|
||||
if (fpr && *fpr)
|
||||
{
|
||||
char *endp = strchr (fpr, ' ');
|
||||
if (endp)
|
||||
*endp = 0;
|
||||
if (strlen (issuerhash) != 40)
|
||||
if (strlen (fpr) != 40)
|
||||
{
|
||||
xfree (issuerhash);
|
||||
return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID")));
|
||||
return leave_cmd (ctx, PARM_ERROR ("fingerprint too short"));
|
||||
}
|
||||
ocsp_mode = 1;
|
||||
}
|
||||
|
@ -1168,17 +1180,24 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
|||
again:
|
||||
if (ocsp_mode)
|
||||
{
|
||||
/* Note, that we ignore the given issuer hash and instead rely
|
||||
on the current certificate semantics used with this
|
||||
command. */
|
||||
/* Note, that we currently ignore the supplied fingerprint FPR;
|
||||
* instead ocsp_isvalid does an inquire to ask for the cert.
|
||||
* The fingerprint may eventually be used to lookup the
|
||||
* certificate in a local cache. */
|
||||
if (!opt.allow_ocsp)
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
|
||||
/* Fixme: If we got no ocsp response and --only-ocsp is not used
|
||||
we should fall back to CRL mode. Thus we need to clear
|
||||
OCSP_MODE, get the issuerhash and the serialno from the
|
||||
current certificate and jump to again. */
|
||||
|
||||
if (gpg_err_code (err) == GPG_ERR_CONFIGURATION
|
||||
&& gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR)
|
||||
{
|
||||
/* No default responder configured - fallback to CRL. */
|
||||
if (!only_ocsp)
|
||||
log_info ("falling back to CRL check\n");
|
||||
ocsp_mode = 0;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else if (only_ocsp)
|
||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||
|
@ -1858,7 +1877,7 @@ static const char hlp_validate[] =
|
|||
" INQUIRE CERTLIST\n"
|
||||
"\n"
|
||||
"Here the first certificate is the target certificate, the remaining\n"
|
||||
"certificates are suggested intermediary certificates. All certifciates\n"
|
||||
"certificates are suggested intermediary certificates. All certificates\n"
|
||||
"need to be PEM encoded.\n"
|
||||
"\n"
|
||||
"The option --systrust changes the behaviour to include the system\n"
|
||||
|
@ -1909,7 +1928,7 @@ cmd_validate (assuan_context_t ctx, char *line)
|
|||
err = gpg_error (GPG_ERR_MISSING_CERT);
|
||||
if (!err)
|
||||
{
|
||||
/* Extraxt the first certificate from the list. */
|
||||
/* Extract the first certificate from the list. */
|
||||
cert = certlist->cert;
|
||||
ksba_cert_ref (cert);
|
||||
}
|
||||
|
@ -1978,6 +1997,38 @@ make_keyserver_item (const char *uri, uri_item_t *r_item)
|
|||
uri_item_t item;
|
||||
|
||||
*r_item = NULL;
|
||||
|
||||
/* We used to have DNS CNAME redirection from the URLs below to
|
||||
* sks-keyserver. pools. The idea was to allow for a quick way to
|
||||
* switch to a different set of pools. The problem with that
|
||||
* approach is that TLS needs to verify the hostname and - because
|
||||
* DNS is not secured - it can only check the user supplied hostname
|
||||
* and not a hostname from a CNAME RR. Thus the final server all
|
||||
* need to have certificates with the actual pool name as well as
|
||||
* for keys.gnupg.net - that would render the advantage of
|
||||
* keys.gnupg.net useless and so we better give up on this. Because
|
||||
* the keys.gnupg.net URL are still in widespread use we do a static
|
||||
* mapping here.
|
||||
*/
|
||||
if (!strcmp (uri, "hkps://keys.gnupg.net")
|
||||
|| !strcmp (uri, "keys.gnupg.net"))
|
||||
uri = "hkps://hkps.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "https://keys.gnupg.net"))
|
||||
uri = "https://hkps.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "hkp://keys.gnupg.net"))
|
||||
uri = "hkp://hkps.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "http://keys.gnupg.net"))
|
||||
uri = "http://hkps.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "hkps://http-keys.gnupg.net")
|
||||
|| !strcmp (uri, "http-keys.gnupg.net"))
|
||||
uri = "hkps://ha.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "https://http-keys.gnupg.net"))
|
||||
uri = "https://ha.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "hkp://http-keys.gnupg.net"))
|
||||
uri = "hkp://ha.pool.sks-keyservers.net";
|
||||
else if (!strcmp (uri, "http://http-keys.gnupg.net"))
|
||||
uri = "http://ha.pool.sks-keyservers.net";
|
||||
|
||||
item = xtrymalloc (sizeof *item + strlen (uri));
|
||||
if (!item)
|
||||
return gpg_error_from_syserror ();
|
||||
|
@ -2489,7 +2540,8 @@ static const char hlp_getinfo[] =
|
|||
"dnsinfo - Return info about the DNS resolver\n"
|
||||
"socket_name - Return the name of the socket.\n"
|
||||
"session_id - Return the current session_id.\n"
|
||||
"workqueue - Inspect the work queue\n";
|
||||
"workqueue - Inspect the work queue\n"
|
||||
"getenv NAME - Return value of envvar NAME\n";
|
||||
static gpg_error_t
|
||||
cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
{
|
||||
|
@ -2557,6 +2609,23 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||
workqueue_dump_queue (ctrl);
|
||||
err = 0;
|
||||
}
|
||||
else if (!strncmp (line, "getenv", 6)
|
||||
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
|
||||
{
|
||||
line += 6;
|
||||
while (*line == ' ' || *line == '\t')
|
||||
line++;
|
||||
if (!*line)
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
else
|
||||
{
|
||||
const char *s = getenv (line);
|
||||
if (!s)
|
||||
err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
|
||||
else
|
||||
err = assuan_send_data (ctx, s, strlen (s));
|
||||
}
|
||||
}
|
||||
else
|
||||
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue