mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Some work on the dirmngr
This commit is contained in:
parent
b6490d3656
commit
a22c38baad
4
NEWS
4
NEWS
@ -26,8 +26,8 @@ Noteworthy changes in version 2.1.x (under development)
|
|||||||
* If the agent's --use-standard-socket option is active, all tools
|
* If the agent's --use-standard-socket option is active, all tools
|
||||||
try to start and daemonize the agent on the fly. In the past this
|
try to start and daemonize the agent on the fly. In the past this
|
||||||
was only supported on W32; on non-W32 systems the new configure
|
was only supported on W32; on non-W32 systems the new configure
|
||||||
option --use-standard-socket may now be used to use this feature by
|
option --enable-standard-socket may now be used to use this feature
|
||||||
default.
|
by default.
|
||||||
|
|
||||||
* Dirmngr is now a part of this package.
|
* Dirmngr is now a part of this package.
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2010-07-19 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* utf8conv.c (utf8_to_wchar): s/malloc/jnlib_malloc/.
|
||||||
|
|
||||||
2010-07-16 Werner Koch <wk@g10code.com>
|
2010-07-16 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* http.h (HTTP_FLAG_IGNORE_CL): Add flag .
|
* http.h (HTTP_FLAG_IGNORE_CL): Add flag .
|
||||||
|
@ -802,7 +802,7 @@ utf8_to_wchar (const char *string)
|
|||||||
jnlib_set_errno (ENOMEM);
|
jnlib_set_errno (ENOMEM);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
result = malloc (nbytes);
|
result = jnlib_malloc (nbytes);
|
||||||
if (!result)
|
if (!result)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1,3 +1,23 @@
|
|||||||
|
2010-07-19 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* dirmngr.c: Include ldap-wrapper.h.
|
||||||
|
(launch_reaper_thread): Move code to ...
|
||||||
|
* ldap-wrapper.c (ldap_wrapper_launch_thread): .. here. Change
|
||||||
|
callers.
|
||||||
|
(ldap_wrapper_thread): Rename to ...
|
||||||
|
(wrapper_thread): this and make local.
|
||||||
|
|
||||||
|
* ldap.c (destroy_wrapper, print_log_line)
|
||||||
|
(read_log_data, ldap_wrapper_thread)
|
||||||
|
(ldap_wrapper_wait_connections, ldap_wrapper_release_context)
|
||||||
|
(ldap_wrapper_connection_cleanup, reader_callback, ldap_wrapper):
|
||||||
|
Factor code out to ...
|
||||||
|
* ldap-wrapper.c: new.
|
||||||
|
(ldap_wrapper): Make public.
|
||||||
|
(read_buffer): Copy from ldap.c.
|
||||||
|
* ldap-wrapper.h: New.
|
||||||
|
* Makefile.am (dirmngr_SOURCES): Add new files.
|
||||||
|
|
||||||
2010-07-16 Werner Koch <wk@g10code.com>
|
2010-07-16 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* http.c, http.h: Remove.
|
* http.c, http.h: Remove.
|
||||||
|
@ -39,7 +39,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
|
|||||||
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
||||||
ldapserver.h ldapserver.c certcache.c certcache.h \
|
ldapserver.h ldapserver.c certcache.c certcache.h \
|
||||||
cdb.h cdblib.c ldap.c misc.c dirmngr-err.h \
|
cdb.h cdblib.c ldap.c misc.c dirmngr-err.h \
|
||||||
ocsp.c ocsp.h validate.c validate.h
|
ocsp.c ocsp.h validate.c validate.h ldap-wrapper.c ldap-wrapper.h
|
||||||
|
|
||||||
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
||||||
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
|
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
|
||||||
|
@ -891,7 +891,7 @@ update_dir (crl_cache_t cache)
|
|||||||
|
|
||||||
xfree (line);
|
xfree (line);
|
||||||
}
|
}
|
||||||
if (!es_ferror (fp) && !ferror (es_fpout) && !lineerr)
|
if (!es_ferror (fp) && !es_ferror (fpout) && !lineerr)
|
||||||
{
|
{
|
||||||
/* Write out the remaining entries. */
|
/* Write out the remaining entries. */
|
||||||
for (e= cache->entries; e; e = e->next)
|
for (e= cache->entries; e; e = e->next)
|
||||||
|
@ -61,11 +61,6 @@ void crl_close_reader (ksba_reader_t reader);
|
|||||||
|
|
||||||
|
|
||||||
/*-- ldap.c --*/
|
/*-- ldap.c --*/
|
||||||
void *ldap_wrapper_thread (void*);
|
|
||||||
void ldap_wrapper_wait_connections (void);
|
|
||||||
void ldap_wrapper_release_context (ksba_reader_t reader);
|
|
||||||
void ldap_wrapper_connection_cleanup (ctrl_t);
|
|
||||||
|
|
||||||
gpg_error_t url_fetch_ldap (ctrl_t ctrl,
|
gpg_error_t url_fetch_ldap (ctrl_t ctrl,
|
||||||
const char *url, const char *host, int port,
|
const char *url, const char *host, int port,
|
||||||
ksba_reader_t *reader);
|
ksba_reader_t *reader);
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "ldapserver.h"
|
#include "ldapserver.h"
|
||||||
#include "asshelp.h"
|
#include "asshelp.h"
|
||||||
|
#include "ldap-wrapper.h"
|
||||||
|
|
||||||
/* The plain Windows version uses the windows service system. For
|
/* The plain Windows version uses the windows service system. For
|
||||||
example to start the service you may use "sc start dirmngr".
|
example to start the service you may use "sc start dirmngr".
|
||||||
@ -393,32 +394,6 @@ wrong_args (const char *text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helper to start the reaper thread for the ldap wrapper. */
|
|
||||||
static void
|
|
||||||
launch_reaper_thread (void)
|
|
||||||
{
|
|
||||||
static int done;
|
|
||||||
pth_attr_t tattr;
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
return;
|
|
||||||
done = 1;
|
|
||||||
|
|
||||||
tattr = pth_attr_new();
|
|
||||||
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
|
||||||
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
|
|
||||||
pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
|
|
||||||
|
|
||||||
if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
|
|
||||||
{
|
|
||||||
log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
|
|
||||||
strerror (errno) );
|
|
||||||
dirmngr_exit (1);
|
|
||||||
}
|
|
||||||
pth_attr_destroy (tattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Helper to stop the reaper thread for the ldap wrapper. */
|
/* Helper to stop the reaper thread for the ldap wrapper. */
|
||||||
static void
|
static void
|
||||||
shutdown_reaper (void)
|
shutdown_reaper (void)
|
||||||
@ -938,7 +913,7 @@ main (int argc, char **argv)
|
|||||||
log_debug ("... okay\n");
|
log_debug ("... okay\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
launch_reaper_thread ();
|
ldap_wrapper_launch_thread ();
|
||||||
cert_cache_init ();
|
cert_cache_init ();
|
||||||
crl_cache_init ();
|
crl_cache_init ();
|
||||||
start_command_handler (ASSUAN_INVALID_FD);
|
start_command_handler (ASSUAN_INVALID_FD);
|
||||||
@ -1101,7 +1076,7 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
launch_reaper_thread ();
|
ldap_wrapper_launch_thread ();
|
||||||
cert_cache_init ();
|
cert_cache_init ();
|
||||||
crl_cache_init ();
|
crl_cache_init ();
|
||||||
#ifdef USE_W32_SERVICE
|
#ifdef USE_W32_SERVICE
|
||||||
@ -1127,7 +1102,7 @@ main (int argc, char **argv)
|
|||||||
/* Just list the CRL cache and exit. */
|
/* Just list the CRL cache and exit. */
|
||||||
if (argc)
|
if (argc)
|
||||||
wrong_args ("--list-crls");
|
wrong_args ("--list-crls");
|
||||||
launch_reaper_thread ();
|
ldap_wrapper_launch_thread ();
|
||||||
crl_cache_init ();
|
crl_cache_init ();
|
||||||
crl_cache_list (es_stdout);
|
crl_cache_list (es_stdout);
|
||||||
}
|
}
|
||||||
@ -1138,7 +1113,7 @@ main (int argc, char **argv)
|
|||||||
memset (&ctrlbuf, 0, sizeof ctrlbuf);
|
memset (&ctrlbuf, 0, sizeof ctrlbuf);
|
||||||
dirmngr_init_default_ctrl (&ctrlbuf);
|
dirmngr_init_default_ctrl (&ctrlbuf);
|
||||||
|
|
||||||
launch_reaper_thread ();
|
ldap_wrapper_launch_thread ();
|
||||||
cert_cache_init ();
|
cert_cache_init ();
|
||||||
crl_cache_init ();
|
crl_cache_init ();
|
||||||
if (!argc)
|
if (!argc)
|
||||||
@ -1160,7 +1135,7 @@ main (int argc, char **argv)
|
|||||||
memset (&ctrlbuf, 0, sizeof ctrlbuf);
|
memset (&ctrlbuf, 0, sizeof ctrlbuf);
|
||||||
dirmngr_init_default_ctrl (&ctrlbuf);
|
dirmngr_init_default_ctrl (&ctrlbuf);
|
||||||
|
|
||||||
launch_reaper_thread ();
|
ldap_wrapper_launch_thread ();
|
||||||
cert_cache_init ();
|
cert_cache_init ();
|
||||||
crl_cache_init ();
|
crl_cache_init ();
|
||||||
rc = crl_fetch (&ctrlbuf, argv[0], &reader);
|
rc = crl_fetch (&ctrlbuf, argv[0], &reader);
|
||||||
|
333
dirmngr/ldap-wrapper-ce.c
Normal file
333
dirmngr/ldap-wrapper-ce.c
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/* ldap-wrapper-ce.c - LDAP access via W32 threads
|
||||||
|
* Copyright (C) 2010 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Alternative wrapper for use with WindowsCE. 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 wrapper based on native threads.
|
||||||
|
|
||||||
|
See ldap-wrapper.c for the standard wrapper interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <pth.h>
|
||||||
|
|
||||||
|
#include "dirmngr.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "ldap-wrapper.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* To keep track of the LDAP wrapper state we use this structure. */
|
||||||
|
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. */
|
||||||
|
pth_event_t log_ev;
|
||||||
|
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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* We keep a global list of spawed 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 need to know whether we are shutting down the process. */
|
||||||
|
static int shutting_down;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Start the reaper thread for this wrapper. */
|
||||||
|
void
|
||||||
|
ldap_wrapper_launch_thread (void)
|
||||||
|
{
|
||||||
|
static int done;
|
||||||
|
pth_attr_t tattr;
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
return;
|
||||||
|
done = 1;
|
||||||
|
|
||||||
|
tattr = pth_attr_new();
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
|
||||||
|
|
||||||
|
if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
|
||||||
|
{
|
||||||
|
log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
|
||||||
|
strerror (errno) );
|
||||||
|
dirmngr_exit (1);
|
||||||
|
}
|
||||||
|
pth_attr_destroy (tattr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
while (wrapper_list)
|
||||||
|
pth_yield (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function is to be used to release a context associated with the
|
||||||
|
given reader object. */
|
||||||
|
void
|
||||||
|
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);
|
||||||
|
|
||||||
|
ctx->reader = NULL;
|
||||||
|
SAFE_PTH_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup all resources held by the connection associated with
|
||||||
|
CTRL. This is used after a cancel to kill running wrappers. */
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fork and exec the LDAP wrapper and returns 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.
|
||||||
|
|
||||||
|
Special hack to avoid passing a password through the command line
|
||||||
|
which is globally visible: If the first element of ARGV is "--pass"
|
||||||
|
it will be removed and instead the environment variable
|
||||||
|
DIRMNGR_LDAP_PASS will be set to the next value of ARGV. On modern
|
||||||
|
OSes the environment is not visible to other users. For those old
|
||||||
|
systems where it can't be avoided, we don't want to go into the
|
||||||
|
hassle of passing the password via stdin; it's just too complicated
|
||||||
|
and an LDAP password used for public directory lookups should not
|
||||||
|
be that confidential. */
|
||||||
|
gpg_error_t
|
||||||
|
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
pid_t pid;
|
||||||
|
struct wrapper_context_s *ctx;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
const char **arg_list;
|
||||||
|
const char *pgmname;
|
||||||
|
int outpipe[2], errpipe[2];
|
||||||
|
|
||||||
|
/* It would be too simple to connect stderr just to our logging
|
||||||
|
stream. The problem is that if we are running multi-threaded
|
||||||
|
everything gets intermixed. Clearly we don't want this. So the
|
||||||
|
only viable solutions are either to have another thread
|
||||||
|
responsible for logging the messages or to add an option to the
|
||||||
|
wrapper module to do the logging on its own. Given that we anyway
|
||||||
|
need a way to rip the child process and this is best done using a
|
||||||
|
general ripping thread, that thread can do the logging too. */
|
||||||
|
|
||||||
|
*reader = NULL;
|
||||||
|
|
||||||
|
/* Files: We need to prepare stdin and stdout. We get stderr from
|
||||||
|
the function. */
|
||||||
|
if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
|
||||||
|
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
|
||||||
|
else
|
||||||
|
pgmname = opt.ldap_wrapper_program;
|
||||||
|
|
||||||
|
/* Create command line argument array. */
|
||||||
|
for (i = 0; argv[i]; i++)
|
||||||
|
;
|
||||||
|
arg_list = xtrycalloc (i + 2, sizeof *arg_list);
|
||||||
|
if (!arg_list)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
for (i = j = 0; argv[i]; i++, j++)
|
||||||
|
if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
|
||||||
|
{
|
||||||
|
arg_list[j] = "--env-pass";
|
||||||
|
setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
arg_list[j] = (char*) argv[i];
|
||||||
|
|
||||||
|
ctx = xtrycalloc (1, sizeof *ctx);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
||||||
|
xfree (arg_list);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gnupg_create_inbound_pipe (outpipe);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = gnupg_create_inbound_pipe (errpipe);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
close (outpipe[0]);
|
||||||
|
close (outpipe[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("error creating 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);
|
||||||
|
xfree (arg_list);
|
||||||
|
close (outpipe[1]);
|
||||||
|
close (errpipe[1]);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
close (outpipe[0]);
|
||||||
|
close (errpipe[0]);
|
||||||
|
xfree (ctx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pid = pid;
|
||||||
|
ctx->printable_pid = (int) pid;
|
||||||
|
ctx->fd = outpipe[0];
|
||||||
|
ctx->log_fd = errpipe[0];
|
||||||
|
ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
|
||||||
|
if (! ctx->log_ev)
|
||||||
|
{
|
||||||
|
xfree (ctx);
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
ctx->ctrl = ctrl;
|
||||||
|
ctrl->refcount++;
|
||||||
|
ctx->stamp = time (NULL);
|
||||||
|
|
||||||
|
err = ksba_reader_new (reader);
|
||||||
|
if (!err)
|
||||||
|
err = ksba_reader_set_cb (*reader, reader_callback, ctx);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("error initializing reader object: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
destroy_wrapper (ctx);
|
||||||
|
ksba_reader_release (*reader);
|
||||||
|
*reader = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
indications. The CRL loading logic assumes that after return
|
||||||
|
from this function, a failed search (e.g. host not found ) is
|
||||||
|
indicated right away. */
|
||||||
|
{
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
err = read_buffer (*reader, &c, 1);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ldap_wrapper_release_context (*reader);
|
||||||
|
ksba_reader_release (*reader);
|
||||||
|
*reader = NULL;
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||||
|
return gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
else
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ksba_reader_unread (*reader, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
747
dirmngr/ldap-wrapper.c
Normal file
747
dirmngr/ldap-wrapper.c
Normal file
@ -0,0 +1,747 @@
|
|||||||
|
/* ldap-wrapper.c - LDAP access via a wrapper process
|
||||||
|
* Copyright (C) 2004, 2005, 2007, 2008 g10 Code GmbH
|
||||||
|
* Copyright (C) 2010 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <pth.h>
|
||||||
|
|
||||||
|
#include "dirmngr.h"
|
||||||
|
#include "exechelp.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "ldap-wrapper.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
#define setenv(a,b,c) SetEnvironmentVariable ((a),(b))
|
||||||
|
#else
|
||||||
|
#define pth_close(fd) close(fd)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* In case sysconf does not return a value we need to have a limit. */
|
||||||
|
#ifdef _POSIX_OPEN_MAX
|
||||||
|
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
||||||
|
#else
|
||||||
|
#define MAX_OPEN_FDS 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INACTIVITY_TIMEOUT (opt.ldaptimeout + 60*5) /* seconds */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* To keep track of the LDAP wrapper state we use this structure. */
|
||||||
|
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. */
|
||||||
|
pth_event_t log_ev;
|
||||||
|
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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* We keep a global list of spawed 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 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_PTH_CLOSE(fd) \
|
||||||
|
do { int _fd = fd; if (_fd != -1) { pth_close (_fd); fd = -1;} } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
size_t nread;
|
||||||
|
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
err = ksba_reader_read (reader, buffer, count, &nread);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
buffer += nread;
|
||||||
|
count -= nread;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Release the wrapper context and kill a running wrapper process. */
|
||||||
|
static void
|
||||||
|
destroy_wrapper (struct wrapper_context_s *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->pid != (pid_t)(-1))
|
||||||
|
{
|
||||||
|
gnupg_kill_process (ctx->pid);
|
||||||
|
gnupg_release_process (ctx->pid);
|
||||||
|
}
|
||||||
|
ksba_reader_release (ctx->reader);
|
||||||
|
SAFE_PTH_CLOSE (ctx->fd);
|
||||||
|
SAFE_PTH_CLOSE (ctx->log_fd);
|
||||||
|
if (ctx->log_ev)
|
||||||
|
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
|
||||||
|
xfree (ctx->line);
|
||||||
|
xfree (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Print the content of LINE to thye log stream but make sure to only
|
||||||
|
print complete lines. Using NULL for LINE will flush any pending
|
||||||
|
output. LINE may be modified by this fucntion. */
|
||||||
|
static void
|
||||||
|
print_log_line (struct wrapper_context_s *ctx, char *line)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (!line)
|
||||||
|
{
|
||||||
|
if (ctx->line && ctx->linelen)
|
||||||
|
{
|
||||||
|
|
||||||
|
log_info ("%s\n", ctx->line);
|
||||||
|
ctx->linelen = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((s = strchr (line, '\n')))
|
||||||
|
{
|
||||||
|
*s = 0;
|
||||||
|
if (ctx->line && ctx->linelen)
|
||||||
|
{
|
||||||
|
log_info ("%s", ctx->line);
|
||||||
|
ctx->linelen = 0;
|
||||||
|
log_printf ("%s\n", line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_info ("%s\n", line);
|
||||||
|
line = s + 1;
|
||||||
|
}
|
||||||
|
n = strlen (line);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
if (ctx->linelen + n + 1 >= ctx->linesize)
|
||||||
|
{
|
||||||
|
char *tmp;
|
||||||
|
size_t newsize;
|
||||||
|
|
||||||
|
newsize = ctx->linesize + ((n + 255) & ~255) + 1;
|
||||||
|
tmp = (ctx->line ? xtryrealloc (ctx->line, newsize)
|
||||||
|
: xtrymalloc (newsize));
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
log_error (_("error printing log line: %s\n"), strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->line = tmp;
|
||||||
|
ctx->linesize = newsize;
|
||||||
|
}
|
||||||
|
memcpy (ctx->line + ctx->linelen, line, n);
|
||||||
|
ctx->linelen += n;
|
||||||
|
ctx->line[ctx->linelen] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read data from the log stream. Returns true if the log stream
|
||||||
|
indicated EOF or error. */
|
||||||
|
static int
|
||||||
|
read_log_data (struct wrapper_context_s *ctx)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
/* We must use the pth_read function for pipes, always. */
|
||||||
|
do
|
||||||
|
n = pth_read (ctx->log_fd, line, sizeof line - 1);
|
||||||
|
while (n < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (n <= 0) /* EOF or error. */
|
||||||
|
{
|
||||||
|
if (n < 0)
|
||||||
|
log_error (_("error reading log from ldap wrapper %d: %s\n"),
|
||||||
|
ctx->pid, strerror (errno));
|
||||||
|
print_log_line (ctx, NULL);
|
||||||
|
SAFE_PTH_CLOSE (ctx->log_fd);
|
||||||
|
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
|
||||||
|
ctx->log_ev = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
line[n] = 0;
|
||||||
|
print_log_line (ctx, line);
|
||||||
|
if (ctx->stamp != (time_t)(-1))
|
||||||
|
ctx->stamp = time (NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
int nfds;
|
||||||
|
struct wrapper_context_s *ctx;
|
||||||
|
struct wrapper_context_s *ctx_prev;
|
||||||
|
time_t current_time;
|
||||||
|
|
||||||
|
(void)dummy;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
pth_event_t timeout_ev;
|
||||||
|
int any_action = 0;
|
||||||
|
|
||||||
|
timeout_ev = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
|
||||||
|
if (! timeout_ev)
|
||||||
|
{
|
||||||
|
log_error (_("pth_event failed: %s\n"), strerror (errno));
|
||||||
|
pth_sleep (10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ctx = wrapper_list; ctx; ctx = ctx->next)
|
||||||
|
{
|
||||||
|
if (ctx->log_fd != -1)
|
||||||
|
{
|
||||||
|
pth_event_isolate (ctx->log_ev);
|
||||||
|
pth_event_concat (timeout_ev, ctx->log_ev, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that the read FDs are actually handles. Thus, we can
|
||||||
|
not use pth_select, but have to use pth_wait. */
|
||||||
|
nfds = pth_wait (timeout_ev);
|
||||||
|
if (nfds < 0)
|
||||||
|
{
|
||||||
|
pth_event_free (timeout_ev, PTH_FREE_THIS);
|
||||||
|
log_error (_("pth_wait failed: %s\n"), strerror (errno));
|
||||||
|
pth_sleep (10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pth_event_status (timeout_ev) == PTH_STATUS_OCCURRED)
|
||||||
|
nfds--;
|
||||||
|
pth_event_free (timeout_ev, PTH_FREE_THIS);
|
||||||
|
|
||||||
|
current_time = time (NULL);
|
||||||
|
if (current_time > INACTIVITY_TIMEOUT)
|
||||||
|
current_time -= 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
|
||||||
|
&& pth_event_status (ctx->log_ev) == PTH_STATUS_OCCURRED)
|
||||||
|
{
|
||||||
|
if (read_log_data (ctx))
|
||||||
|
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 < current_time)
|
||||||
|
{
|
||||||
|
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_PTH_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))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*NOTREACHED*/
|
||||||
|
return NULL; /* Make the compiler happy. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Start the reaper thread for the ldap wrapper. */
|
||||||
|
void
|
||||||
|
ldap_wrapper_launch_thread (void)
|
||||||
|
{
|
||||||
|
static int done;
|
||||||
|
pth_attr_t tattr;
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
return;
|
||||||
|
done = 1;
|
||||||
|
|
||||||
|
tattr = pth_attr_new();
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
|
||||||
|
pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
|
||||||
|
|
||||||
|
if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
|
||||||
|
{
|
||||||
|
log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
|
||||||
|
strerror (errno) );
|
||||||
|
dirmngr_exit (1);
|
||||||
|
}
|
||||||
|
pth_attr_destroy (tattr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
while (wrapper_list)
|
||||||
|
pth_yield (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function is to be used to release a context associated with the
|
||||||
|
given reader object. */
|
||||||
|
void
|
||||||
|
ldap_wrapper_release_context (ksba_reader_t reader)
|
||||||
|
{
|
||||||
|
struct wrapper_context_s *ctx;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ctx->reader = NULL;
|
||||||
|
SAFE_PTH_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup all resources held by the connection associated with
|
||||||
|
CTRL. This is used after a cancel to kill running wrappers. */
|
||||||
|
void
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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). */
|
||||||
|
|
||||||
|
if (!buffer && !count && !nread)
|
||||||
|
return -1; /* Rewind is not supported. */
|
||||||
|
|
||||||
|
/* If we ever encountered a read error don't allow to continue and
|
||||||
|
possible overwrite the last error cause. Bail out also if the
|
||||||
|
file descriptor has been closed. */
|
||||||
|
if (ctx->fd_error || ctx->fd == -1)
|
||||||
|
{
|
||||||
|
*nread = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nleft > 0)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
pth_event_t evt;
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
|
||||||
|
n = pth_read_ev (ctx->fd, buffer, nleft, evt);
|
||||||
|
if (n < 0 && evt && pth_event_occurred (evt))
|
||||||
|
{
|
||||||
|
n = 0;
|
||||||
|
err = dirmngr_tick (ctx->ctrl);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ctx->fd_error = err;
|
||||||
|
SAFE_PTH_CLOSE (ctx->fd);
|
||||||
|
if (evt)
|
||||||
|
pth_event_free (evt, PTH_FREE_THIS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (n < 0)
|
||||||
|
{
|
||||||
|
ctx->fd_error = gpg_error_from_errno (errno);
|
||||||
|
SAFE_PTH_CLOSE (ctx->fd);
|
||||||
|
if (evt)
|
||||||
|
pth_event_free (evt, PTH_FREE_THIS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (!n)
|
||||||
|
{
|
||||||
|
if (nleft == count)
|
||||||
|
{
|
||||||
|
if (evt)
|
||||||
|
pth_event_free (evt, PTH_FREE_THIS);
|
||||||
|
return -1; /* EOF. */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nleft -= n;
|
||||||
|
buffer += n;
|
||||||
|
if (evt)
|
||||||
|
pth_event_free (evt, PTH_FREE_THIS);
|
||||||
|
if (n > 0 && ctx->stamp != (time_t)(-1))
|
||||||
|
ctx->stamp = time (NULL);
|
||||||
|
}
|
||||||
|
*nread = count - nleft;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fork and exec the LDAP wrapper and returns 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.
|
||||||
|
|
||||||
|
Special hack to avoid passing a password through the command line
|
||||||
|
which is globally visible: If the first element of ARGV is "--pass"
|
||||||
|
it will be removed and instead the environment variable
|
||||||
|
DIRMNGR_LDAP_PASS will be set to the next value of ARGV. On modern
|
||||||
|
OSes the environment is not visible to other users. For those old
|
||||||
|
systems where it can't be avoided, we don't want to go into the
|
||||||
|
hassle of passing the password via stdin; it's just too complicated
|
||||||
|
and an LDAP password used for public directory lookups should not
|
||||||
|
be that confidential. */
|
||||||
|
gpg_error_t
|
||||||
|
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
pid_t pid;
|
||||||
|
struct wrapper_context_s *ctx;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
const char **arg_list;
|
||||||
|
const char *pgmname;
|
||||||
|
int outpipe[2], errpipe[2];
|
||||||
|
|
||||||
|
/* It would be too simple to connect stderr just to our logging
|
||||||
|
stream. The problem is that if we are running multi-threaded
|
||||||
|
everything gets intermixed. Clearly we don't want this. So the
|
||||||
|
only viable solutions are either to have another thread
|
||||||
|
responsible for logging the messages or to add an option to the
|
||||||
|
wrapper module to do the logging on its own. Given that we anyway
|
||||||
|
need a way to rip the child process and this is best done using a
|
||||||
|
general ripping thread, that thread can do the logging too. */
|
||||||
|
|
||||||
|
*reader = NULL;
|
||||||
|
|
||||||
|
/* Files: We need to prepare stdin and stdout. We get stderr from
|
||||||
|
the function. */
|
||||||
|
if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
|
||||||
|
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
|
||||||
|
else
|
||||||
|
pgmname = opt.ldap_wrapper_program;
|
||||||
|
|
||||||
|
/* Create command line argument array. */
|
||||||
|
for (i = 0; argv[i]; i++)
|
||||||
|
;
|
||||||
|
arg_list = xtrycalloc (i + 2, sizeof *arg_list);
|
||||||
|
if (!arg_list)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
for (i = j = 0; argv[i]; i++, j++)
|
||||||
|
if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
|
||||||
|
{
|
||||||
|
arg_list[j] = "--env-pass";
|
||||||
|
setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
arg_list[j] = (char*) argv[i];
|
||||||
|
|
||||||
|
ctx = xtrycalloc (1, sizeof *ctx);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
||||||
|
xfree (arg_list);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gnupg_create_inbound_pipe (outpipe);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = gnupg_create_inbound_pipe (errpipe);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
close (outpipe[0]);
|
||||||
|
close (outpipe[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("error creating 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);
|
||||||
|
xfree (arg_list);
|
||||||
|
close (outpipe[1]);
|
||||||
|
close (errpipe[1]);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
close (outpipe[0]);
|
||||||
|
close (errpipe[0]);
|
||||||
|
xfree (ctx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pid = pid;
|
||||||
|
ctx->printable_pid = (int) pid;
|
||||||
|
ctx->fd = outpipe[0];
|
||||||
|
ctx->log_fd = errpipe[0];
|
||||||
|
ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
|
||||||
|
if (! ctx->log_ev)
|
||||||
|
{
|
||||||
|
xfree (ctx);
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
ctx->ctrl = ctrl;
|
||||||
|
ctrl->refcount++;
|
||||||
|
ctx->stamp = time (NULL);
|
||||||
|
|
||||||
|
err = ksba_reader_new (reader);
|
||||||
|
if (!err)
|
||||||
|
err = ksba_reader_set_cb (*reader, reader_callback, ctx);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("error initializing reader object: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
destroy_wrapper (ctx);
|
||||||
|
ksba_reader_release (*reader);
|
||||||
|
*reader = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
indications. The CRL loading logic assumes that after return
|
||||||
|
from this function, a failed search (e.g. host not found ) is
|
||||||
|
indicated right away. */
|
||||||
|
{
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
err = read_buffer (*reader, &c, 1);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
ldap_wrapper_release_context (*reader);
|
||||||
|
ksba_reader_release (*reader);
|
||||||
|
*reader = NULL;
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||||
|
return gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
else
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ksba_reader_unread (*reader, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
33
dirmngr/ldap-wrapper.h
Normal file
33
dirmngr/ldap-wrapper.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* ldap-wrapper.h - Interface to an LDAP access wrapper.
|
||||||
|
* Copyright (C) 2010 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 LDAP_WRAPPER_H
|
||||||
|
#define LDAP_WRAPPER_H
|
||||||
|
|
||||||
|
void ldap_wrapper_launch_thread (void);
|
||||||
|
void ldap_wrapper_wait_connections (void);
|
||||||
|
void ldap_wrapper_release_context (ksba_reader_t reader);
|
||||||
|
void ldap_wrapper_connection_cleanup (ctrl_t);
|
||||||
|
gpg_error_t ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader,
|
||||||
|
const char *argv[]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*LDAP_WRAPPER_H*/
|
658
dirmngr/ldap.c
658
dirmngr/ldap.c
@ -35,22 +35,8 @@
|
|||||||
#include "crlfetch.h"
|
#include "crlfetch.h"
|
||||||
#include "ldapserver.h"
|
#include "ldapserver.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "ldap-wrapper.h"
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
#define setenv(a,b,c) SetEnvironmentVariable ((a),(b))
|
|
||||||
#else
|
|
||||||
#define pth_close(fd) close(fd)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* In case sysconf does not return a value we need to have a limit. */
|
|
||||||
#ifdef _POSIX_OPEN_MAX
|
|
||||||
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
|
||||||
#else
|
|
||||||
#define MAX_OPEN_FDS 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define INACTIVITY_TIMEOUT (opt.ldaptimeout + 60*5) /* seconds */
|
|
||||||
|
|
||||||
#define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz" \
|
#define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz" \
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
||||||
@ -72,50 +58,6 @@ struct cert_fetch_context_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* To keep track of the LDAP wrapper state we use this structure. */
|
|
||||||
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. */
|
|
||||||
pth_event_t log_ev;
|
|
||||||
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. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* We keep a global list of spawed 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 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_PTH_CLOSE(fd) \
|
|
||||||
do { int _fd = fd; if (_fd != -1) { pth_close (_fd); fd = -1;} } while (0)
|
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes. */
|
|
||||||
static gpg_error_t read_buffer (ksba_reader_t reader,
|
|
||||||
unsigned char *buffer, size_t count);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Add HOST and PORT to our list of LDAP servers. Fixme: We should
|
/* Add HOST and PORT to our list of LDAP servers. Fixme: We should
|
||||||
@ -165,604 +107,6 @@ add_server_to_servers (const char *host, int port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Release the wrapper context and kill a running wrapper process. */
|
|
||||||
static void
|
|
||||||
destroy_wrapper (struct wrapper_context_s *ctx)
|
|
||||||
{
|
|
||||||
if (ctx->pid != (pid_t)(-1))
|
|
||||||
{
|
|
||||||
gnupg_kill_process (ctx->pid);
|
|
||||||
gnupg_release_process (ctx->pid);
|
|
||||||
}
|
|
||||||
ksba_reader_release (ctx->reader);
|
|
||||||
SAFE_PTH_CLOSE (ctx->fd);
|
|
||||||
SAFE_PTH_CLOSE (ctx->log_fd);
|
|
||||||
if (ctx->log_ev)
|
|
||||||
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
|
|
||||||
xfree (ctx->line);
|
|
||||||
xfree (ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Print the content of LINE to thye log stream but make sure to only
|
|
||||||
print complete lines. Using NULL for LINE will flush any pending
|
|
||||||
output. LINE may be modified by this fucntion. */
|
|
||||||
static void
|
|
||||||
print_log_line (struct wrapper_context_s *ctx, char *line)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (!line)
|
|
||||||
{
|
|
||||||
if (ctx->line && ctx->linelen)
|
|
||||||
{
|
|
||||||
|
|
||||||
log_info ("%s\n", ctx->line);
|
|
||||||
ctx->linelen = 0;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((s = strchr (line, '\n')))
|
|
||||||
{
|
|
||||||
*s = 0;
|
|
||||||
if (ctx->line && ctx->linelen)
|
|
||||||
{
|
|
||||||
log_info ("%s", ctx->line);
|
|
||||||
ctx->linelen = 0;
|
|
||||||
log_printf ("%s\n", line);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
log_info ("%s\n", line);
|
|
||||||
line = s + 1;
|
|
||||||
}
|
|
||||||
n = strlen (line);
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
if (ctx->linelen + n + 1 >= ctx->linesize)
|
|
||||||
{
|
|
||||||
char *tmp;
|
|
||||||
size_t newsize;
|
|
||||||
|
|
||||||
newsize = ctx->linesize + ((n + 255) & ~255) + 1;
|
|
||||||
tmp = (ctx->line ? xtryrealloc (ctx->line, newsize)
|
|
||||||
: xtrymalloc (newsize));
|
|
||||||
if (!tmp)
|
|
||||||
{
|
|
||||||
log_error (_("error printing log line: %s\n"), strerror (errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx->line = tmp;
|
|
||||||
ctx->linesize = newsize;
|
|
||||||
}
|
|
||||||
memcpy (ctx->line + ctx->linelen, line, n);
|
|
||||||
ctx->linelen += n;
|
|
||||||
ctx->line[ctx->linelen] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Read data from the log stream. Returns true if the log stream
|
|
||||||
indicated EOF or error. */
|
|
||||||
static int
|
|
||||||
read_log_data (struct wrapper_context_s *ctx)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
char line[256];
|
|
||||||
|
|
||||||
/* We must use the pth_read function for pipes, always. */
|
|
||||||
do
|
|
||||||
n = pth_read (ctx->log_fd, line, sizeof line - 1);
|
|
||||||
while (n < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
if (n <= 0) /* EOF or error. */
|
|
||||||
{
|
|
||||||
if (n < 0)
|
|
||||||
log_error (_("error reading log from ldap wrapper %d: %s\n"),
|
|
||||||
ctx->pid, strerror (errno));
|
|
||||||
print_log_line (ctx, NULL);
|
|
||||||
SAFE_PTH_CLOSE (ctx->log_fd);
|
|
||||||
pth_event_free (ctx->log_ev, PTH_FREE_THIS);
|
|
||||||
ctx->log_ev = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
line[n] = 0;
|
|
||||||
print_log_line (ctx, line);
|
|
||||||
if (ctx->stamp != (time_t)(-1))
|
|
||||||
ctx->stamp = time (NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
int nfds;
|
|
||||||
struct wrapper_context_s *ctx;
|
|
||||||
struct wrapper_context_s *ctx_prev;
|
|
||||||
time_t current_time;
|
|
||||||
|
|
||||||
(void)dummy;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
pth_event_t timeout_ev;
|
|
||||||
int any_action = 0;
|
|
||||||
|
|
||||||
timeout_ev = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
|
|
||||||
if (! timeout_ev)
|
|
||||||
{
|
|
||||||
log_error (_("pth_event failed: %s\n"), strerror (errno));
|
|
||||||
pth_sleep (10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ctx = wrapper_list; ctx; ctx = ctx->next)
|
|
||||||
{
|
|
||||||
if (ctx->log_fd != -1)
|
|
||||||
{
|
|
||||||
pth_event_isolate (ctx->log_ev);
|
|
||||||
pth_event_concat (timeout_ev, ctx->log_ev, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note that the read FDs are actually handles. Thus, we can
|
|
||||||
not use pth_select, but have to use pth_wait. */
|
|
||||||
nfds = pth_wait (timeout_ev);
|
|
||||||
if (nfds < 0)
|
|
||||||
{
|
|
||||||
pth_event_free (timeout_ev, PTH_FREE_THIS);
|
|
||||||
log_error (_("pth_wait failed: %s\n"), strerror (errno));
|
|
||||||
pth_sleep (10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pth_event_status (timeout_ev) == PTH_STATUS_OCCURRED)
|
|
||||||
nfds--;
|
|
||||||
pth_event_free (timeout_ev, PTH_FREE_THIS);
|
|
||||||
|
|
||||||
current_time = time (NULL);
|
|
||||||
if (current_time > INACTIVITY_TIMEOUT)
|
|
||||||
current_time -= 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
|
|
||||||
&& pth_event_status (ctx->log_ev) == PTH_STATUS_OCCURRED)
|
|
||||||
{
|
|
||||||
if (read_log_data (ctx))
|
|
||||||
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 < current_time)
|
|
||||||
{
|
|
||||||
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_PTH_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))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*NOTREACHED*/
|
|
||||||
return NULL; /* Make the compiler happy. */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
while (wrapper_list)
|
|
||||||
pth_yield (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function is to be used to release a context associated with the
|
|
||||||
given reader object. */
|
|
||||||
void
|
|
||||||
ldap_wrapper_release_context (ksba_reader_t reader)
|
|
||||||
{
|
|
||||||
struct wrapper_context_s *ctx;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
ctx->reader = NULL;
|
|
||||||
SAFE_PTH_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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cleanup all resources held by the connection associated with
|
|
||||||
CTRL. This is used after a cancel to kill running wrappers. */
|
|
||||||
void
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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). */
|
|
||||||
|
|
||||||
if (!buffer && !count && !nread)
|
|
||||||
return -1; /* Rewind is not supported. */
|
|
||||||
|
|
||||||
/* If we ever encountered a read error don't allow to continue and
|
|
||||||
possible overwrite the last error cause. Bail out also if the
|
|
||||||
file descriptor has been closed. */
|
|
||||||
if (ctx->fd_error || ctx->fd == -1)
|
|
||||||
{
|
|
||||||
*nread = 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (nleft > 0)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
pth_event_t evt;
|
|
||||||
gpg_error_t err;
|
|
||||||
|
|
||||||
evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
|
|
||||||
n = pth_read_ev (ctx->fd, buffer, nleft, evt);
|
|
||||||
if (n < 0 && evt && pth_event_occurred (evt))
|
|
||||||
{
|
|
||||||
n = 0;
|
|
||||||
err = dirmngr_tick (ctx->ctrl);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
ctx->fd_error = err;
|
|
||||||
SAFE_PTH_CLOSE (ctx->fd);
|
|
||||||
if (evt)
|
|
||||||
pth_event_free (evt, PTH_FREE_THIS);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (n < 0)
|
|
||||||
{
|
|
||||||
ctx->fd_error = gpg_error_from_errno (errno);
|
|
||||||
SAFE_PTH_CLOSE (ctx->fd);
|
|
||||||
if (evt)
|
|
||||||
pth_event_free (evt, PTH_FREE_THIS);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (!n)
|
|
||||||
{
|
|
||||||
if (nleft == count)
|
|
||||||
{
|
|
||||||
if (evt)
|
|
||||||
pth_event_free (evt, PTH_FREE_THIS);
|
|
||||||
return -1; /* EOF. */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nleft -= n;
|
|
||||||
buffer += n;
|
|
||||||
if (evt)
|
|
||||||
pth_event_free (evt, PTH_FREE_THIS);
|
|
||||||
if (n > 0 && ctx->stamp != (time_t)(-1))
|
|
||||||
ctx->stamp = time (NULL);
|
|
||||||
}
|
|
||||||
*nread = count - nleft;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fork and exec the LDAP wrapper and returns 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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Special hack to avoid passing a password through the command line
|
|
||||||
which is globally visible: If the first element of ARGV is "--pass"
|
|
||||||
it will be removed and instead the environment variable
|
|
||||||
DIRMNGR_LDAP_PASS will be set to the next value of ARGV. On modern
|
|
||||||
OSes the environment is not visible to other users. For those old
|
|
||||||
systems where it can't be avoided, we don't want to go into the
|
|
||||||
hassle of passing the password via stdin; it's just too complicated
|
|
||||||
and an LDAP password used for public directory lookups should not
|
|
||||||
be that confidential. */
|
|
||||||
static gpg_error_t
|
|
||||||
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
pid_t pid;
|
|
||||||
struct wrapper_context_s *ctx;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
const char **arg_list;
|
|
||||||
const char *pgmname;
|
|
||||||
int outpipe[2], errpipe[2];
|
|
||||||
|
|
||||||
/* It would be too simple to connect stderr just to our logging
|
|
||||||
stream. The problem is that if we are running multi-threaded
|
|
||||||
everything gets intermixed. Clearly we don't want this. So the
|
|
||||||
only viable solutions are either to have another thread
|
|
||||||
responsible for logging the messages or to add an option to the
|
|
||||||
wrapper module to do the logging on its own. Given that we anyway
|
|
||||||
need a way to rip the child process and this is best done using a
|
|
||||||
general ripping thread, that thread can do the logging too. */
|
|
||||||
|
|
||||||
*reader = NULL;
|
|
||||||
|
|
||||||
/* Files: We need to prepare stdin and stdout. We get stderr from
|
|
||||||
the function. */
|
|
||||||
if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
|
|
||||||
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
|
|
||||||
else
|
|
||||||
pgmname = opt.ldap_wrapper_program;
|
|
||||||
|
|
||||||
/* Create command line argument array. */
|
|
||||||
for (i = 0; argv[i]; i++)
|
|
||||||
;
|
|
||||||
arg_list = xtrycalloc (i + 2, sizeof *arg_list);
|
|
||||||
if (!arg_list)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
for (i = j = 0; argv[i]; i++, j++)
|
|
||||||
if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
|
|
||||||
{
|
|
||||||
arg_list[j] = "--env-pass";
|
|
||||||
setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
arg_list[j] = (char*) argv[i];
|
|
||||||
|
|
||||||
ctx = xtrycalloc (1, sizeof *ctx);
|
|
||||||
if (!ctx)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_error (_("error allocating memory: %s\n"), strerror (errno));
|
|
||||||
xfree (arg_list);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = gnupg_create_inbound_pipe (outpipe);
|
|
||||||
if (!err)
|
|
||||||
{
|
|
||||||
err = gnupg_create_inbound_pipe (errpipe);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
close (outpipe[0]);
|
|
||||||
close (outpipe[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error (_("error creating 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);
|
|
||||||
xfree (arg_list);
|
|
||||||
close (outpipe[1]);
|
|
||||||
close (errpipe[1]);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
close (outpipe[0]);
|
|
||||||
close (errpipe[0]);
|
|
||||||
xfree (ctx);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->pid = pid;
|
|
||||||
ctx->printable_pid = (int) pid;
|
|
||||||
ctx->fd = outpipe[0];
|
|
||||||
ctx->log_fd = errpipe[0];
|
|
||||||
ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
|
|
||||||
if (! ctx->log_ev)
|
|
||||||
{
|
|
||||||
xfree (ctx);
|
|
||||||
return gpg_error_from_syserror ();
|
|
||||||
}
|
|
||||||
ctx->ctrl = ctrl;
|
|
||||||
ctrl->refcount++;
|
|
||||||
ctx->stamp = time (NULL);
|
|
||||||
|
|
||||||
err = ksba_reader_new (reader);
|
|
||||||
if (!err)
|
|
||||||
err = ksba_reader_set_cb (*reader, reader_callback, ctx);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error (_("error initializing reader object: %s\n"),
|
|
||||||
gpg_strerror (err));
|
|
||||||
destroy_wrapper (ctx);
|
|
||||||
ksba_reader_release (*reader);
|
|
||||||
*reader = NULL;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
indications. The CRL loading logic assumes that after return
|
|
||||||
from this function, a failed search (e.g. host not found ) is
|
|
||||||
indicated right away. */
|
|
||||||
{
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
err = read_buffer (*reader, &c, 1);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
ldap_wrapper_release_context (*reader);
|
|
||||||
ksba_reader_release (*reader);
|
|
||||||
*reader = NULL;
|
|
||||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
|
||||||
return gpg_error (GPG_ERR_NO_DATA);
|
|
||||||
else
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
ksba_reader_unread (*reader, &c, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Perform an LDAP query. Returns an gpg error code or 0 on success.
|
/* Perform an LDAP query. Returns an gpg error code or 0 on success.
|
||||||
|
@ -27,8 +27,8 @@ void ldapserver_list_free (ldap_server_t servers);
|
|||||||
|
|
||||||
|
|
||||||
/* Parse a single LDAP server configuration line. Returns the server
|
/* Parse a single LDAP server configuration line. Returns the server
|
||||||
or NULL in case of errors. The configuration lineis assumed to be
|
or NULL in case of errors. The configuration line is assumed to be
|
||||||
colon seprated with these fields:
|
colon separated with these fields:
|
||||||
|
|
||||||
1. field: Hostname
|
1. field: Hostname
|
||||||
2. field: Portnumber
|
2. field: Portnumber
|
||||||
|
@ -23,7 +23,9 @@ All applications using GnuPG's GPGSM tool to process S/MIME messages
|
|||||||
or manage X.509 certificates are affected. The bug exists in all
|
or manage X.509 certificates are affected. The bug exists in all
|
||||||
versions of GnuPG including the recently released GnuPG 2.0.16.
|
versions of GnuPG including the recently released GnuPG 2.0.16.
|
||||||
|
|
||||||
GnuPG 1.x is not affected because it does not come with the GPGSM
|
GPG (i.e. OpenPGP) is NOT affected.
|
||||||
|
|
||||||
|
GnuPG 1.x is NOT affected because it does not come with the GPGSM
|
||||||
tool.
|
tool.
|
||||||
|
|
||||||
An exploit is not yet known but it can't be ruled out for sure that
|
An exploit is not yet known but it can't be ruled out for sure that
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2010-07-20 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* mainproc.c (print_pkenc_list): Write a STATUS_ERROR. Fixes
|
||||||
|
bug#1255.
|
||||||
|
|
||||||
2010-06-17 Werner Koch <wk@g10code.com>
|
2010-06-17 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* gpg.c (main): Use CAST5 as default s2k algo. The macro
|
* gpg.c (main): Use CAST5 as default s2k algo. The macro
|
||||||
|
@ -481,8 +481,11 @@ print_pkenc_list( struct kidlist_item *list, int failed )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (list->reason)
|
else if (list->reason)
|
||||||
|
{
|
||||||
log_info(_("public key decryption failed: %s\n"),
|
log_info(_("public key decryption failed: %s\n"),
|
||||||
g10_errstr(list->reason));
|
g10_errstr(list->reason));
|
||||||
|
write_status_error ("pkdecrypt_failed", list->reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user