Merged Dirmngr with GnuPG.

A few code changes to support dirmngr.
This commit is contained in:
Werner Koch 2010-06-09 16:53:51 +00:00
parent 70f3a9bbb6
commit c3f08dcb72
61 changed files with 22335 additions and 177 deletions

View File

@ -1,5 +1,23 @@
2010-06-09 Werner Koch <wk@g10code.com>
* configure.ac (GNUPG_DIRMNGR_LDAP_PGM): Add option
--with-dirmngr-ldap-pgm.
* am/cmacros.am (-DGNUPG_LOCALSTATEDIR): New.
(GNUPG_DEFAULT_DIRMNGR_LDAP): New.
2010-06-08 Werner Koch <wk@g10code.com>
* configure.ac: Add build support for dirmngr.
(try_ldap): Rename to try_ks_ldap.
(GNUPG_CHECK_LDAP): Also test if dirmngr is to be build.
* Makefile.am (SUBDIRS): Add dirmngr.
2010-06-07 Werner Koch <wk@g10code.com>
* dirmngr/: New.
* configure.ac: Add option --enable-gpgtar.
2010-05-31 Werner Koch <wk@g10code.com>

View File

@ -61,6 +61,11 @@ g13 = g13
else
g13 =
endif
if BUILD_DIRMNGR
dirmngr = dirmngr
else
dirmngr =
endif
if BUILD_TOOLS
tools = tools
else
@ -79,7 +84,8 @@ tests = tests
endif
SUBDIRS = m4 gl include common ${kbx} \
${gpg} ${keyserver} ${sm} ${agent} ${scd} ${g13} ${tools} po ${doc} ${tests}
${gpg} ${keyserver} ${sm} ${agent} ${scd} ${g13} ${dirmngr} \
${tools} po ${doc} ${tests}
dist_doc_DATA = README

2
NEWS
View File

@ -29,6 +29,8 @@ Noteworthy changes in version 2.1.x (under development)
option --use-standard-socket may now be used to use this feature by
default.
* Dirmngr is now a part of this package.
Noteworthy changes in version 2.0.13 (2009-09-04)
-------------------------------------------------

View File

@ -129,10 +129,11 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw)
if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid))
result = 1; /* Execute error - assume password should no be used. */
else if (gnupg_wait_process (pgmname, pid, NULL))
else if (gnupg_wait_process (pgmname, pid, 0, NULL))
result = 1; /* Helper returned an error - probably a match. */
else
result = 0; /* Success; i.e. no match. */
gnupg_release_process (pid);
/* Overwrite our temporary file. */
fseek (infp, 0, SEEK_SET);

View File

@ -25,7 +25,8 @@ AM_CPPFLAGS += -DGNUPG_BINDIR="\"$(bindir)\"" \
-DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \
-DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \
-DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
-DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\""
-DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" \
-DGNUPG_LOCALSTATEDIR="\"$(localstatedir)\""
endif
@ -47,6 +48,9 @@ endif
if GNUPG_PROTECT_TOOL_PGM
AM_CPPFLAGS += -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\""
endif
if GNUPG_DIRMNGR_LDAP_PGM
AM_CPPFLAGS += -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\""
endif
# Under Windows we use LockFileEx. WindowsCE provides this only on
# the WindowsMobile 6 platform and thus we need to use the coredll6

View File

@ -103,7 +103,7 @@ if [ "$myhost" = "w32" ]; then
w32root="$w32ce_root"
[ -z "$w32root" ] && w32root="$HOME/w32ce_root"
toolprefixes="$w32ce_toolprefixes arm-mingw32ce"
extraoptions="--disable-scdaemon --disable-zip $w32ce_extraoptions"
extraoptions="--disable-scdaemon --disable-zip --disable-ldap --disable-dirmngr $w32ce_extraoptions"
;;
*)
[ -z "$w32root" ] && w32root="$HOME/w32root"

View File

@ -1,3 +1,21 @@
2010-06-09 Werner Koch <wk@g10code.com>
* exechelp-posix.c, exechelp-w32.c
* exechelp-w32ce.c (gnupg_wait_process): Add new arg HANG. Change
all callers.
(gnupg_release_process): New. Use it after all calls to
gnupg_wait_process.
* util.h (GNUPG_MODULE_NAME_DIRMNGR_LDAP): New.
* homedir.c (gnupg_cachedir): New.
(w32_try_mkdir): New.
(dirmngr_socket_name): Chanmge standard socket name.
(gnupg_module_name): Support GNUPG_MODULE_NAME_DIRMNGR_LDAP.
* logging.c (log_set_get_tid_callback): Replace by ...
(log_set_pid_suffix_cb): .. new.
(do_logv): Change accordingly.
2010-06-08 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS).
@ -5,7 +23,7 @@
* sysutils.c: Include <assuan.h>.
(translate_sys2libc_fd_int): Cast to silence gcc warning.
* iobuf.c: Include <assuan.h>
(translate_file_handle): Fix syntax error.
(translate_file_handle): Fix syntax error.
2010-06-08 Werner Koch <wk@g10code.com>

View File

@ -362,12 +362,13 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (err)
log_debug ("starting `%s' for testing failed: %s\n",
agent_program, gpg_strerror (err));
else if ((err = gnupg_wait_process (agent_program, pid, &excode)))
else if ((err = gnupg_wait_process (agent_program, pid, 0, &excode)))
{
if (excode == -1)
log_debug ("running `%s' for testing failed: %s\n",
agent_program, gpg_strerror (err));
}
gnupg_release_process (pid);
if (!err && !excode)
{

View File

@ -416,37 +416,39 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
}
/* Wait for the process identified by PID to terminate. PGMNAME should
be the same as supplied to the spawn function and is only used for
diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
for any failures of the spawned program or other error codes. If
EXITCODE is not NULL the exit code of the process is stored at this
address or -1 if it could not be retrieved and no error message is
logged. */
/* See exechelp.h for the description. */
gpg_error_t
gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
{
gpg_err_code_t ec;
int i, status;
if (exitcode)
*exitcode = -1;
if (r_exitcode)
*r_exitcode = -1;
if (pid == (pid_t)(-1))
return gpg_error (GPG_ERR_INV_VALUE);
#ifdef USE_GNU_PTH
i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
#else
while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
;
if (pth_waitpid)
i = pth_waitpid (pid, &status, hang? 0:WNOHANG);
else
#endif
{
while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
&& errno == EINTR)
;
}
if (i == (pid_t)(-1))
{
ec = gpg_err_code_from_errno (errno);
log_error (_("waiting for process %d to terminate failed: %s\n"),
(int)pid, strerror (errno));
ec = gpg_err_code_from_errno (errno);
}
else if (!i)
{
ec = GPG_ERR_TIMEOUT; /* Still running. */
}
else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
{
@ -455,11 +457,11 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
}
else if (WIFEXITED (status) && WEXITSTATUS (status))
{
if (!exitcode)
if (!r_exitcode)
log_error (_("error running `%s': exit status %d\n"), pgmname,
WEXITSTATUS (status));
else
*exitcode = WEXITSTATUS (status);
*r_exitcode = WEXITSTATUS (status);
ec = GPG_ERR_GENERAL;
}
else if (!WIFEXITED (status))
@ -469,8 +471,8 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
}
else
{
if (exitcode)
*exitcode = 0;
if (r_exitcode)
*r_exitcode = 0;
ec = 0;
}
@ -478,7 +480,14 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
}
/* Spawn a new process and immediatley detach from it. The name of
void
gnupg_release_process (pid_t pid)
{
(void)pid;
}
/* Spawn a new process and immediately detach from it. The name of
the program to exec is PGMNAME and its arguments are in ARGV (the
programname is automatically passed as first argument).
Environment strings in ENVP are set. An error is returned if

View File

@ -382,7 +382,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
int cr_flags;
char *cmdline;
int fd, fdout, rp[2];
HANDLE nullhd[];
HANDLE nullhd[2];
int i;
(void)preexec;
@ -428,7 +428,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
}
nullhd[0] = fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
nullhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
/* Start the process. Note that we can't run the PREEXEC function
because this would change our own environment. */
@ -437,7 +437,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
si.hStdInput = fd == -1? nullhd[0] : fd_to_handle (fd);
si.hStdOutput = outfd == -1? nullhd[1] : fd_to_handle (fdout);
si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout);
si.hStdError = fd_to_handle (rp[1]);
cr_flags = (CREATE_DEFAULT_ERROR_MODE
@ -599,22 +599,17 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
}
/* Wait for the process identified by PID to terminate. PGMNAME should
be the same as supplied to the spawn function and is only used for
diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
for any failures of the spawned program or other error codes. If
EXITCODE is not NULL the exit code of the process is stored at this
address or -1 if it could not be retrieved. */
/* See exechelp.h for a description. */
gpg_error_t
gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
{
gpg_err_code_t ec;
HANDLE proc = fd_to_handle (pid);
int code;
DWORD exc;
if (exitcode)
*exitcode = -1;
if (r_exitcode)
*r_exitcode = -1;
if (pid == (pid_t)(-1))
return gpg_error (GPG_ERR_INV_VALUE);
@ -622,50 +617,66 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
/* FIXME: We should do a pth_waitpid here. However this has not yet
been implemented. A special W32 pth system call would even be
better. */
code = WaitForSingleObject (proc, INFINITE);
code = WaitForSingleObject (proc, hang? INFINITE : 0);
switch (code)
{
case WAIT_FAILED:
log_error (_("waiting for process %d to terminate failed: %s\n"),
(int)pid, w32_strerror (-1));
ec = GPG_ERR_GENERAL;
break;
case WAIT_TIMEOUT:
ec = GPG_ERR_TIMEOUT;
break;
case WAIT_OBJECT_0:
if (!GetExitCodeProcess (proc, &exc))
{
log_error (_("error getting exit code of process %d: %s\n"),
(int)pid, w32_strerror (-1) );
ec = GPG_ERR_GENERAL;
}
else if (exc)
{
log_error (_("error running `%s': exit status %d\n"),
pgmname, (int)exc );
if (exitcode)
*exitcode = (int)exc;
ec = GPG_ERR_GENERAL;
}
else
{
if (exitcode)
*exitcode = 0;
ec = 0;
}
CloseHandle (proc);
break;
case WAIT_FAILED:
log_error (_("waiting for process %d to terminate failed: %s\n"),
(int)pid, w32_strerror (-1));
ec = GPG_ERR_GENERAL;
break;
default:
log_error ("WaitForSingleObject returned unexpected "
"code %d for pid %d\n", code, (int)pid );
ec = GPG_ERR_GENERAL;
break;
case WAIT_OBJECT_0:
if (!GetExitCodeProcess (proc, &exc))
{
log_error (_("error getting exit code of process %d: %s\n"),
(int)pid, w32_strerror (-1) );
ec = GPG_ERR_GENERAL;
}
else if (exc)
{
log_error (_("error running `%s': exit status %d\n"),
pgmname, (int)exc );
if (r_exitcode)
*r_exitcode = (int)exc;
ec = GPG_ERR_GENERAL;
}
else
{
if (r_exitcode)
*r_exitcode = 0;
ec = 0;
}
break;
default:
log_error ("WaitForSingleObject returned unexpected "
"code %d for pid %d\n", code, (int)pid );
ec = GPG_ERR_GENERAL;
break;
}
return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
}
void
gnupg_release_process (pid_t pid)
{
if (pid != (pid_t)INVALID_HANDLE_VALUE)
{
HANDLE process = (HANDLE)pid;
CloseHandle (process);
}
}
/* Spawn a new process and immediatley detach from it. The name of
the program to exec is PGMNAME and its arguments are in ARGV (the
programname is automatically passed as first argument).

View File

@ -653,14 +653,10 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
return 0;
}
/* Wait for the process identified by PID to terminate. PGMNAME should
be the same as supplied to the spawn function and is only used for
diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
for any failures of the spawned program or other error codes. If
EXITCODE is not NULL the exit code of the process is stored at this
address or -1 if it could not be retrieved. */
/* See exechelp.h for a description. */
gpg_error_t
gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode)
{
gpg_err_code_t ec;
HANDLE proc = fd_to_handle (pid);
@ -676,50 +672,65 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
/* FIXME: We should do a pth_waitpid here. However this has not yet
been implemented. A special W32 pth system call would even be
better. */
code = WaitForSingleObject (proc, INFINITE);
code = WaitForSingleObject (proc, hang? INFINITE : 0);
switch (code)
{
case WAIT_FAILED:
log_error (_("waiting for process %d to terminate failed: %s\n"),
(int)pid, w32_strerror (-1));
ec = GPG_ERR_GENERAL;
break;
case WAIT_TIMEOUT:
ec = GPG_ERR_TIMEOUT;
break;
case WAIT_FAILED:
log_error (_("waiting for process %d to terminate failed: %s\n"),
(int)pid, w32_strerror (-1));
ec = GPG_ERR_GENERAL;
break;
case WAIT_OBJECT_0:
if (!GetExitCodeProcess (proc, &exc))
{
log_error (_("error getting exit code of process %d: %s\n"),
(int)pid, w32_strerror (-1) );
ec = GPG_ERR_GENERAL;
case WAIT_OBJECT_0:
if (!GetExitCodeProcess (proc, &exc))
{
log_error (_("error getting exit code of process %d: %s\n"),
(int)pid, w32_strerror (-1) );
ec = GPG_ERR_GENERAL;
}
else if (exc)
{
log_error (_("error running `%s': exit status %d\n"),
else if (exc)
{
log_error (_("error running `%s': exit status %d\n"),
pgmname, (int)exc );
if (exitcode)
*exitcode = (int)exc;
ec = GPG_ERR_GENERAL;
}
else
{
if (exitcode)
*exitcode = 0;
ec = 0;
}
CloseHandle (proc);
break;
default:
log_error ("WaitForSingleObject returned unexpected "
"code %d for pid %d\n", code, (int)pid );
ec = GPG_ERR_GENERAL;
break;
if (exitcode)
*exitcode = (int)exc;
ec = GPG_ERR_GENERAL;
}
else
{
if (exitcode)
*exitcode = 0;
ec = 0;
}
break;
default:
log_error ("WaitForSingleObject returned unexpected "
"code %d for pid %d\n", code, (int)pid );
ec = GPG_ERR_GENERAL;
break;
}
return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
}
void
gnupg_release_process (pid_t pid)
{
if (pid != (pid_t)INVALID_HANDLE_VALUE)
{
HANDLE process = (HANDLE)pid;
CloseHandle (process);
}
}
/* Spawn a new process and immediatley detach from it. The name of
the program to exec is PGMNAME and its arguments are in ARGV (the
programname is automatically passed as first argument).

View File

@ -59,8 +59,8 @@ gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
process are expected in the NULL terminated array ARGV. The
program name itself should not be included there. If PREEXEC is
not NULL, that function will be called right before the exec.
Calling gnupg_wait_process is required. Returns 0 on success or an
error code.
Calling gnupg_wait_process and gnupg_release_process is required.
Returns 0 on success or an error code.
FLAGS is a bit vector:
@ -85,21 +85,41 @@ gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
and ERRFD to stderr (any of them may be -1 to connect them to
/dev/null). The arguments for the process are expected in the NULL
terminated array ARGV. The program name itself should not be
included there. Calling gnupg_wait_process is required. Returns 0
on success or an error code. */
included there. Calling gnupg_wait_process and
gnupg_release_process is required. Returns 0 on success or an
error code. */
gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
const char *argv[],
int infd, int outfd, int errfd,
pid_t *pid);
/* Wait for the process identified by PID to terminate. PGMNAME should
be the same as supplied to the spawn fucntion and is only used for
diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL
for any failures of the spawned program or other error codes. If
EXITCODE is not NULL the exit code of the process is stored at this
address or -1 if it could not be retrieved. */
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode);
/* If HANG is true, waits for the process identified by PID to exit;
if HANG is false, checks whether the process has terminated.
PGMNAME should be the same as supplied to the spawn function and is
only used for diagnostics. Return values:
0
The process exited successful. 0 is stored at R_EXITCODE.
GPG_ERR_GENERAL
The process exited without success. The exit code of process
is then stored at R_EXITCODE. An exit code of -1 indicates
that the process terminated abnormally (e.g. due to a signal).
GPG_ERR_TIMEOUT
The process is still running (returned only if HANG is false).
GPG_ERR_INV_VALUE
An invalid PID has been specified.
Other error codes may be returned as well. Unless otherwise noted,
-1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
if the exit code is not required (in that case an error messge will
be printed). Note that under Windows PID is not the process id but
the handle of the process. */
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
int *r_exitcode);
/* Kill a process; that is send an appropriate signal to the process.
@ -107,6 +127,11 @@ gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode);
from the system. An invalid PID is ignored. */
void gnupg_kill_process (pid_t pid);
/* Release the process identified by PID. This function is actually
only required for Windows but it does not harm to always call it.
It is a nop if PID is invalid. */
void gnupg_release_process (pid_t pid);
/* Spawn a new process and immediatley detach from it. The name of
the program to exec is PGMNAME and its arguments are in ARGV (the

View File

@ -44,6 +44,24 @@
#include "sysutils.h"
#ifdef HAVE_W32_SYSTEM
static void
w32_try_mkdir (const char *dir)
{
#ifdef HAVE_W32CE_SYSTEM
wchar_t *wdir = utf8_to_wchar (dir);
if (wdir)
{
CreateDirectory (wdir, NULL);
xfree (wdir);
}
#else
CreateDirectory (dir, NULL);
#endif
}
#endif
/* This is a helper function to load a Windows function from either of
one DLLs. */
#ifdef HAVE_W32_SYSTEM
@ -114,18 +132,7 @@ standard_homedir (void)
/* Try to create the directory if it does not yet exists. */
if (access (dir, F_OK))
{
#ifdef HAVE_W32CE_SYSTEM
wchar_t *wdir = utf8_to_wchar (dir);
if (wdir)
{
CreateDirectory (wdir, NULL);
xfree (wdir);
}
#else
CreateDirectory (dir, NULL);
#endif
}
w32_try_mkdir (dir);
}
else
dir = GNUPG_DEFAULT_HOMEDIR;
@ -366,6 +373,54 @@ gnupg_localedir (void)
}
/* Return the name of the cache directory. The name is allocated in a
static area on the first use. Windows only: If the directory does
not exist it is created. */
const char *
gnupg_cachedir (void)
{
#ifdef HAVE_W32_SYSTEM
static const char *dir;
if (!dir)
{
char path[MAX_PATH];
const char *s1[] = { "GNU", "cache", "gnupg", NULL };
int s1_len;
const char **comp;
s1_len = 0;
for (comp = s1; *comp; comp++)
s1_len += 1 + strlen (*comp);
if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
NULL, 0, path) >= 0)
{
char *tmp = xmalloc (strlen (path) + s1_len + 1);
char *p;
p = stpcpy (tmp, path);
for (comp = s1; *comp; comp++)
{
p = stpcpy (p, "\\");
p = stpcpy (p, *comp);
if (access (tmp, F_OK))
w32_try_mkdir (tmp);
}
dir = tmp;
}
else
dir = "c:\\temp\\cache\\dirmngr";
}
return dir;
#else /*!HAVE_W32_SYSTEM*/
return GNUPG_LOCALSTATEDIR "/cache/" PACKAGE_NAME;
#endif /*!HAVE_W32_SYSTEM*/
}
/* Return the default socket name used by DirMngr. */
const char *
dirmngr_socket_name (void)
@ -379,7 +434,10 @@ dirmngr_socket_name (void)
const char *s2;
/* We need something akin CSIDL_COMMON_PROGRAMS, but local
(non-roaming). */
(non-roaming). This is becuase the file needs to be on the
local machine and makes only sense on that machine.
CSIDL_WINDOWS seems to be the only location which guarantees
that. */
if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0)
strcpy (s1, "C:\\WINDOWS");
s2 = DIRSEP_S "S.dirmngr";
@ -388,7 +446,7 @@ dirmngr_socket_name (void)
}
return name;
#else /*!HAVE_W32_SYSTEM*/
return "/var/run/dirmngr/socket";
return GNUPG_LOCALSTATEDIR "/run/" PACKAGE_NAME "/S.dirmngr";
#endif /*!HAVE_W32_SYSTEM*/
}
@ -450,6 +508,13 @@ gnupg_module_name (int which)
X(libexecdir, "gpg-protect-tool");
#endif
case GNUPG_MODULE_NAME_DIRMNGR_LDAP:
#ifdef GNUPG_DEFAULT_DIRMNGR_LDAP
return GNUPG_DEFAULT_DIRMNGR_LDAP;
#else
X(libexecdir, "dirmngr_ldap");
#endif
case GNUPG_MODULE_NAME_CHECK_PATTERN:
X(libexecdir, "gpg-check-pattern");

View File

@ -63,7 +63,7 @@ static char prefix_buffer[80];
static int with_time;
static int with_prefix;
static int with_pid;
static unsigned long (*get_tid_callback)(void);
static int (*get_pid_suffix_cb)(unsigned long *r_value);
static int running_detached;
static int force_prefixes;
@ -336,9 +336,9 @@ log_set_fd (int fd)
void
log_set_get_tid_callback (unsigned long (*cb)(void))
log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value))
{
get_tid_callback = cb;
get_pid_suffix_cb = cb;
}
@ -441,9 +441,12 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
es_fputs_unlocked (prefix_buffer, logstream);
if (with_pid || force_prefixes)
{
if (get_tid_callback)
es_fprintf_unlocked (logstream, "[%u.%lx]",
(unsigned int)getpid (), get_tid_callback ());
unsigned long pidsuf;
int pidfmt;
if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf)))
es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]",
(unsigned int)getpid (), pidsuf);
else
es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
}

View File

@ -35,7 +35,7 @@ int log_get_errorcount (int clear);
void log_inc_errorcount (void);
void log_set_file( const char *name );
void log_set_fd (int fd);
void log_set_get_tid_callback (unsigned long (*cb)(void));
void log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value));
void log_set_prefix (const char *text, unsigned int flags);
const char *log_get_prefix (unsigned int *flags);
int log_test_fd (int fd);

View File

@ -192,6 +192,7 @@ const char *gnupg_libexecdir (void);
const char *gnupg_libdir (void);
const char *gnupg_datadir (void);
const char *gnupg_localedir (void);
const char *gnupg_cachedir (void);
const char *dirmngr_socket_name (void);
/* All module names. We also include gpg and gpgsm for the sake for
@ -206,6 +207,7 @@ const char *dirmngr_socket_name (void);
#define GNUPG_MODULE_NAME_GPG 8
#define GNUPG_MODULE_NAME_CONNECT_AGENT 9
#define GNUPG_MODULE_NAME_GPGCONF 10
#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
const char *gnupg_module_name (int which);

View File

@ -1,6 +1,6 @@
# configure.ac - for GnuPG 2.1
# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
#
@ -81,11 +81,14 @@ disable_keyserver_path=no
use_ccid_driver=yes
use_standard_socket=no
try_ks_ldap=no
GNUPG_BUILD_PROGRAM(gpg, yes)
GNUPG_BUILD_PROGRAM(gpgsm, yes)
GNUPG_BUILD_PROGRAM(agent, yes)
GNUPG_BUILD_PROGRAM(scdaemon, yes)
GNUPG_BUILD_PROGRAM(g13, yes)
GNUPG_BUILD_PROGRAM(dirmngr, yes)
GNUPG_BUILD_PROGRAM(tools, yes)
GNUPG_BUILD_PROGRAM(doc, yes)
GNUPG_BUILD_PROGRAM(symcryptrun, no)
@ -155,6 +158,15 @@ show_gnupg_protect_tool_pgm="(default)"
test -n "$GNUPG_PROTECT_TOOL_PGM" \
&& show_gnupg_protect_tool_pgm="$GNUPG_PROTECT_TOOL_PGM"
AC_ARG_WITH(dirmngr-ldap-pgm,
[ --with-dirmngr-ldap-pgm=PATH Use PATH as the default for the dirmnge ldap wrapper)],
GNUPG_DIRMNGR_LDAP_PGM="$withval", GNUPG_DIRMNGR_LDAP_PGM="" )
AC_SUBST(GNUPG_DIRMNGR_LDAP_PGM)
AM_CONDITIONAL(GNUPG_DIRMNGR_LDAP_PGM, test -n "$GNUPG_DIRMNGR_LDAP_PGM")
show_gnupg_dirmngr_ldap_pgm="(default)"
test -n "$GNUPG_DIRMNGR_LDAP_PGM" \
&& show_gnupg_dirmngr_ldap_pgm="$GNUPG_DIRMNGR_LDAP_PGM"
# Some folks want to use only the agent from this packet. Make it
# easier for them by providing the configure option
@ -239,8 +251,8 @@ if test "$use_exec" = yes ; then
AC_MSG_CHECKING([whether LDAP keyserver support is requested])
AC_ARG_ENABLE(ldap,
AC_HELP_STRING([--disable-ldap],[disable LDAP keyserver interface only]),
try_ldap=$enableval, try_ldap=yes)
AC_MSG_RESULT($try_ldap)
try_ks_ldap=$enableval, try_ks_ldap=yes)
AC_MSG_RESULT($try_ks_ldap)
AC_MSG_CHECKING([whether HKP keyserver support is requested])
AC_ARG_ENABLE(hkp,
@ -528,6 +540,7 @@ have_dosish_system=no
have_w32_system=no
have_w32ce_system=no
use_simple_gettext=no
mmap_needed=yes
case "${host}" in
*-mingw32*)
# special stuff for Windoze NT
@ -552,6 +565,7 @@ case "${host}" in
esac
try_gettext="no"
use_simple_gettext=yes
mmap_needed=no
;;
i?86-emx-os2 | i?86-*-os2*emx )
# OS/2 with the EMX environment
@ -738,6 +752,10 @@ AC_PATH_PROG(FUSERMOUNT, fusermount, /usr/bin/fusermount)
AC_DEFINE_UNQUOTED(FUSERMOUNT,
"${FUSERMOUNT}", [defines the filename of the fusermount program])
# Checks for dirmngr
#
# Checks for symcryptrun:
#
@ -943,7 +961,7 @@ AM_CONDITIONAL(USE_DNS_SRV, test x"$use_dns_srv" = xyes)
#
# Check for LDAP
#
if test "$try_ldap" = yes ; then
if test "$try_ks_ldap" = yes || test "$build_dirmngr" = "yes" ; then
GNUPG_CHECK_LDAP($NETLIBS)
fi
@ -1152,9 +1170,9 @@ AC_CHECK_DECLS(getpagesize)
AC_FUNC_FSEEKO
AC_FUNC_VPRINTF
AC_FUNC_FORK
AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap])
AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r])
AC_CHECK_FUNCS([unsetenv fcntl ftruncate])
AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap canonicalize_file_name])
AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r strtoull])
AC_CHECK_FUNCS([unsetenv fcntl ftruncate canonicalize_file_name])
AC_CHECK_FUNCS([gettimeofday getrusage getrlimit setrlimit clock_gettime])
AC_CHECK_FUNCS([atexit raise getpagesize strftime nl_langinfo setlocale])
AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo])
@ -1162,6 +1180,11 @@ AC_CHECK_FUNCS([ttyname rand ftello fsync stat lstat])
AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
# Dirmngr requires mmap on Unix systems.
if test $ac_cv_func_mmap != yes -a $mmap_needed = yes; then
AC_MSG_ERROR([[Sorry, the current implemenation requires mmap.]])
fi
#
# These are needed by the jnlib parts in common.
# Note: We already checked pwd.h.
@ -1170,6 +1193,9 @@ AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \
memrchr isascii timegm getrusage setrlimit stat setlocale \
flockfile funlockfile fopencookie funopen getpwnam getpwuid \
getenv ])
# end jnlib checks.
#
# gnulib checks
@ -1466,18 +1492,19 @@ if test "$build_agent_only" = "yes" ; then
fi
AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes")
AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes")
AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes")
AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes")
AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes")
AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes")
AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes")
AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes")
AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes")
AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes")
AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes")
AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes")
AM_CONDITIONAL(BUILD_DIRMNGR, test "$build_dirmngr" = "yes")
AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes")
AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes")
AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes")
AM_CONDITIONAL(BUILD_GPGTAR,test "$build_gpgtar" = "yes")
AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes")
AM_CONDITIONAL(RUN_GPG_TESTS,
test x$cross_compiling = xno -a "$build_gpg" = yes )
test x$cross_compiling = xno -a "$build_gpg" = yes )
#
@ -1524,6 +1551,16 @@ if test "$have_ksba" = "no"; then
*** (at least version $NEED_KSBA_VERSION using API $NEED_KSBA_API is required).
***]])
fi
if test "$gnupg_have_ldap" = "no"; then
die=yes
AC_MSG_NOTICE([[
***
*** You need a LDAP library to build this program.
*** Check out
*** http://www.openldap.org
*** for a suitable implementation.
***]])
fi
if test "$missing_pth" = "yes"; then
AC_MSG_NOTICE([[
***
@ -1562,6 +1599,7 @@ sm/Makefile
agent/Makefile
scd/Makefile
g13/Makefile
dirmngr/Makefile
keyserver/Makefile
keyserver/gpg2keys_mailto
keyserver/gpg2keys_test
@ -1585,9 +1623,11 @@ echo "
Agent: $build_agent $build_agent_threaded
Smartcard: $build_scdaemon $build_scdaemon_extra
G13: $build_g13
Dirmngr: $build_dirmngr
Gpgtar: $build_gpgtar
Protect tool: $show_gnupg_protect_tool_pgm
LDAP wrapper: $show_gnupg_dirmngr_ldap_pgm
Default agent: $show_gnupg_agent_pgm
Default pinentry: $show_gnupg_pinentry_pgm
Default scdaemon: $show_gnupg_scdaemon_pgm

1345
dirmngr/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

802
dirmngr/ChangeLog.1 Normal file
View File

@ -0,0 +1,802 @@
There are old Dirmngr ChangeLog entries.
2004-10-04 Werner Koch <wk@g10code.com>
* src/dirmngr.c: Changed an help entry description.
2004-09-30 Werner Koch <wk@g10code.com>
* src/dirmngr.c (i18n_init): Always use LC_ALL.
2004-09-28 Werner Koch <wk@g10code.com>
Released 0.5.6.
* config.guess, config.sub: Updated.
2004-06-21 Werner Koch <wk@g10code.com>
* src/crlfetch.c (crl_fetch): Bad hack to use the right attribute.
2004-05-13 Werner Koch <wk@gnupg.org>
Released 0.5.5.
* src/ldap.c (start_cert_fetch_ldap, start_cert_fetch_ldap): More
detailed error messages.
* src/crlcache.c (update_dir): Handle i-records properly.
2004-04-29 Werner Koch <wk@gnupg.org>
Released 0.5.4.
* src/crlcache.h (crl_cache_result_t): Add CRL_CACHE_CANTUSE.
* src/server.c (cmd_isvalid): Handle it here.
* src/crlcache.c (crl_cache_isvalid): Issue this code if the CRL
cant be used.
(open_dir): Parse new fields 8,9 and 10 as well as the invalid flag.
(write_dir_line_crl): Write new fields.
(get_crl_number, get_auth_key_id): New.
(crl_cache_insert): Fill new fields. Mark the entry invalid if
the CRL is too old after an update or an unknown critical
extension was seen.
(list_one_crl_entry): Print the new fields.
2004-04-28 Werner Koch <wk@gnupg.org>
* configure.ac: Requires libksba 0.9.6.
* src/dirmngr.c: New option --ocsp-signer.
* src/dirmngr.h (opt): Renamed member OCSP_REPONDERS to
OCSP_RESPONDER and made ist a simple string. Add OCSP_SIGNER.
* src/ocsp.c (ocsp_isvalid): Changed it accordingly.
(ocsp_isvalid): Pass the ocsp_signer to check_signature.
(check_signature): New arg SIGNER_FPR. Use it to retrieve the
certificate. Factored out common code to ..
(check_signature_core): .. New.
2004-04-27 Werner Koch <wk@gnupg.org>
* src/server.c (start_command_handler): Keep track of the first
connection.
(dirmngr_tick): New.
* src/ldap.c (attr_fetch_fun_reader): Call it from time to time.
2004-04-23 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (main): Removed the add-servers option from the
gpgconf list. It is not really useful.
2004-04-02 Thomas Schwinge <schwinge@nic-nac-project.de>
* autogen.sh: Added ACLOCAL_FLAGS.
2004-04-13 Werner Koch <wk@gnupg.org>
* src/crlcache.c (update_dir): Do not double close FPOUT.
2004-04-09 Werner Koch <wk@gnupg.org>
* src/cdblib.c (cdb_make_start): Wipeout the entire buffer to
shutup valgrind.
(ewrite): Fixed writing bad data on EINTR.
* src/ldap.c (get_attr_from_result_ldap): Fixed bad copy and
terminate of a string.
* src/crlfetch.c (crl_fetch): Fixed freeing of VALUE on error.
2004-04-07 Werner Koch <wk@gnupg.org>
* src/dirmngr.h (server_control_s): Add member force_crl_refresh.
* src/server.c (option_handler): New.
(start_command_handler): Register option handler
* src/crlcache.c (crl_cache_isvalid): Add arg FORCE_REFRESH.
(crl_cache_insert): Record last refresh in memory.
* src/server.c (inquire_cert_and_load_crl): Renamed from
inquire_cert.
2004-04-06 Werner Koch <wk@gnupg.org>
Released 0.5.3
* doc/dirmngr.texi: Updated.
* doc/texinfo.tex: Updated.
2004-04-05 Werner Koch <wk@gnupg.org>
* src/ocsp.c (ocsp_isvalid): Check THIS_UPDATE.
* src/misc.c (add_isotime): New.
(date2jd, jd2date, days_per_month, days_per_year): New. Taken from
my ancient (1988) code used in Wedit (time2.c).
2004-04-02 Werner Koch <wk@gnupg.org>
* autogen.sh: Check gettext version.
* configure.ac: Add AM_GNU_GETTEXT.
2004-04-02 gettextize <bug-gnu-gettext@gnu.org>
* Makefile.am (SUBDIRS): Add intl.
(EXTRA_DIST): Add config.rpath.
* configure.ac (AC_CONFIG_FILES): Add intl/Makefile,
2004-04-02 Werner Koch <wk@gnupg.org>
Add i18n at most places.
* src/dirmngr.c (i18n_init): New.
(main): Call it.
* src/dirmngr.h: Add i18n stuff.
2004-04-01 Werner Koch <wk@gnupg.org>
* src/misc.c (get_fingerprint_hexstring): New.
* src/server.c (dirmngr_status): New.
2004-03-26 Werner Koch <wk@gnupg.org>
* configure.ac: Add AC_SYS_LARGEFILE.
* doc/dirmngr.texi: Changed the license to the GPL as per message
by Mathhias Kalle Dalheimer of Klaralvdalens-Datakonsult dated
Jan 7, 2004.
* doc/fdl.texi: Removed.
2004-03-25 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (main): New command --fetch-crl.
2004-03-23 Werner Koch <wk@gnupg.org>
* src/dirmngr.c: New option --allow-ocsp.
* src/server.c (cmd_isvalid): Make use of allow_ocsp.
2004-03-17 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (main) <gpgconf>: Fixed default value quoting.
2004-03-16 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (main): Add ocsp-responder to the gpgconf list.
Add option --debug-level.
(set_debug): New.
2004-03-15 Werner Koch <wk@gnupg.org>
* src/misc.c (canon_sexp_to_grcy): New.
2004-03-12 Werner Koch <wk@gnupg.org>
* src/crlfetch.c (crl_fetch): Hack to substitute http for https.
2004-03-10 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (parse_ldapserver_file): Don't skip the entire
file on errors.
2004-03-09 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (my_ksba_hash_buffer): New.
(main): Initialize the internal libksba hashing.
* src/server.c (get_issuer_cert_local): Renamed to ...
(get_cert_local): ... this. Changed all callers. Allow NULL for
ISSUER to return the current target cert.
(get_issuing_cert_local): New.
(do_get_cert_local): Moved common code to here.
2004-03-06 Werner Koch <wk@gnupg.org>
Released 0.5.2.
* configure.ac: Fixed last change to check the API version of
libgcrypt.
2004-03-05 Werner Koch <wk@gnupg.org>
* configure.ac: Also check the SONAME of libgcrypt.
2004-03-03 Werner Koch <wk@gnupg.org>
* src/dirmngr.c: New option --ocsp-responder.
* src/dirmngr.h (opt): Add member OCSP_RESPONDERS.
2004-02-26 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/server.c (start_command_handler): Corrected typo and made
dirmngr output it's version in the greeting message.
2004-02-24 Marcus Brinkmann <marcus@g10code.de>
* src/dirmngr.c (DEFAULT_ADD_SERVERS): Removed. If this were
true, there'd be no way to disable it.
(main): Dump options in new gpgconf format.
2004-02-11 Werner Koch <wk@gnupg.org>
* autogen.sh (check_version): Removed bashism and simplified.
2004-02-06 Moritz Schulte <mo@g10code.com>
* src/crlfetch.c (crl_fetch_default): Do not dereference VALUE,
when checking for non-zero.
2004-02-01 Marcus Brinkmann <marcus@g10code.de>
* src/dirmngr.c (DEFAULT_ADD_SERVERS, DEFAULT_MAX_REPLIES)
(DEFAULT_LDAP_TIMEOUT): New macros.
(main): Use them.
(enum cmd_and_opt_values): New command aGPGConfList.
(main): Add handler here.
2004-01-17 Werner Koch <wk@gnupg.org>
* configure.ac: Added AC_CHECK_FUNCS tests again, because the
other test occurrences belong to the jnlib tests block.
2004-01-15 Moritz Schulte <mo@g10code.com>
* configure.ac: Fixed funopen replacement mechanism; removed
unnecessary AC_CHECK_FUNCS calls.
2004-01-14 Werner Koch <wk@gnupg.org>
* src/crlcache.c (list_one_crl_entry): Don't use putchar.
* src/server.c (cmd_listcrls): New.
2003-12-23 Werner Koch <wk@gnupg.org>
Released 0.5.1.
2003-12-17 Werner Koch <wk@gnupg.org>
* configure.ac (CFLAGS): Add -Wformat-noliteral in gcc +
maintainer mode.
(NEED_LIBASSUAN_VERSION): Bump up to 0.6.2.
2003-12-16 Werner Koch <wk@gnupg.org>
* configure.ac: Update the tests for jnlib.
* src/dirmngr.c (main): Ignore SIGPIPE in server mode.
2003-12-12 Werner Koch <wk@gnupg.org>
* src/crlcache.c (hash_dbfile): Also hash version info of the
cache file format.
* src/Makefile.am (dirmngr_SOURCES): Add http.h.
* configure.ac: Removed checking for DB2. Add checking for mmap.
* src/cdb.h, src/cdblib.h: New. Add a few comments from the
original man page and fixed typos.
* src/cdblib.c (cdb_findinit, cdb_findnext): Modified to allow
walking over all entries.
* src/crlcache.h: Removed DB2/4 cruft.
(release_one_cache_entry, lock_db_file, crl_parse_insert)
(crl_cache_insert, crl_cache_isvalid, list_one_crl_entry): Use the
new CDB interface.
* src/dirmngr.c: Beautified the help messages.
(wrong_args): New.
(main): new option --force. Revamped the command handling code.
Allow to pass multiple CRLS as well as stdin to --local-crl.
* src/crlcache.c (crl_cache_insert): Make --force work.
2003-12-11 Werner Koch <wk@gnupg.org>
* src/crlfetch.c (crl_fetch): Enhanced to allow fetching binary
data using HTTP.
* src/http.c, src/http.h: Replaced by the code from gnupg 1.3 and
modified acording to our needs.
(read_line): New. Based on the code from GnuPG's iobuf_read_line.
* configure.ac: Check for getaddrinfo.
* src/dirmngr.c (parse_ldapserver_file): Close the stream.
(main): Free ldapfile.
* src/ocsp.c, src/ocsp.h: New. Albeit not functionality.
* src/server.c (inquire_cert): Catch EOF when reading dist points.
* src/crlcache.c (hash_dbfile, check_dbfile): New.
(lock_db_file, crl_cache_insert): Use them here to detect
corrupted CRL files.
(open_dir): Read the new dbfile hash field.
* src/crlfetch.c (crl_fetch, crl_fetch_default): Changed to retrun
a stream.
(fun_reader, fun_closer, setup_funopen): New.
* src/server.c (inquire_cert): Changed to use the new stream interface
of crlfetch.c.
2003-12-10 Werner Koch <wk@gnupg.org>
* src/funopen.c: New.
* configure.ac (funopen): Add test.
* src/Makefile.am (dirmngr_LDADD): Add LIBOBJS.
* src/crlcache.c (next_line_from_file): Remove the limit on the
line length.
(crl_cache_new): Removed.
(open_dbcontent): New.
(crl_cache_init): Use it here.
(crl_cache_flush): The DB content fie is now in the cache
directory, so we can simplify it.
(make_db_file_name, lock_db_file, unlock_db_file): New.
(release_cache): Close the cached DB files.
(crl_cache_isvalid): Make use of the new lock_db_file.
(crl_cache_insert): Changed to take a stream as argument.
(crl_parse_insert): Rewritten to use a temporary DB and to avoid
using up large amounts of memory.
(db_entry_new): Removed.
(release_cache,release_one_cache_entry): Splitted up.
(find_entry): Take care of the new deleted flag.
(crl_cache_load): Simplified becuase we can now pass a FP to the
insert code.
(save_contents): Removed.
(update_dir): New.
(open_dbcontent_file): Renamed to open_dir_file.
(check_dbcontent_version): Renamed to check_dir_version.
(open_dbcontent): Renamed to open_dir.
* src/dirmngr.c: New option --faked-system-time.
* src/misc.c (faked_time_p, set_time, get_time): New. Taken from GnuPG.
(check_isotime): New.
(unpercent_string): New.
2003-12-09 Werner Koch <wk@gnupg.org>
* src/crlcache.h (DBDIR,DBCONTENTFILE): Changed value.
* autogen.sh: Reworked.
* README.CVS: New.
* configure.ac: Added min_automake_version.
2003-12-03 Werner Koch <wk@gnupg.org>
* src/server.c (cmd_lookup): Send an END line after each
certificate.
2003-11-28 Werner Koch <wk@gnupg.org>
* src/Makefile.am (dirmngr_LDADD): Remove DB_LIBS
because it never got defined and -ldb{2,4} is implictly set
by the AC_CHECK_LIB test in configure.
* src/crlcache.c (mydbopen): DB4 needs an extra parameter; I
wonder who ever tested DB4 support. Add an error statement in
case no DB support is configured.
* tests/Makefile.am: Don't use AM_CPPFLAGS but AM_CFLAGS, replaced
variables by configure templates.
* src/Makefile.am: Ditto.
2003-11-19 Werner Koch <wk@gnupg.org>
* src/crlcache.c (list_one_crl_entry): Define X to nothing for non
DB4 systems. Thanks to Luca M. G. Centamore.
2003-11-17 Werner Koch <wk@gnupg.org>
Released 0.5.0
* src/crlcache.c (crl_cache_new): Fixed eof detection.
* src/server.c (cmd_loadcrl): Do the unescaping.
* doc/dirmngr.texi: Added a history section for this modified
version.
2003-11-14 Werner Koch <wk@gnupg.org>
* tests/asschk.c: New. Taken from GnuPG.
* tests/Makefile.am: Added asschk.
2003-11-13 Werner Koch <wk@gnupg.org>
* src/ldap.c (fetch_next_cert_ldap): Get the pattern switching
right.
* tests/test-dirmngr.c: Replaced a couple of deprecated types.
* configure.ac (GPG_ERR_SOURCE_DEFAULT): Added.
(fopencookie, asprintf): Removed unneeded test.
(PRINTABLE_OS_NAME): Updated the test from gnupg.
(CFLAGS): Do full warnings only in maintainer mode. Add flag
--enable gcc-warnings to override it and to enable even more
warnings.
* acinclude.m4: Removed the libgcrypt test.
* src/ldap.c (get_attr_from_result_ldap): Simplified the binary
hack and return a proper gpg error.
(attr_fetch_ldap_internal): Changed error handling.
(attr_fetch_ldap): Reworked. Return configuration error if no
servers are configured.
(url_fetch_ldap, add_server_to_servers)
(url_fetch_ldap_internal): Reworked.
(struct cert_fetch_context_s): New to get rid of a global state.
(start_cert_fetch_ldap): Allocate context and do a bind with a
timeout. Parse pattern.
(end_cert_fetch_ldap): Take context and don't return anything.
(find_next_pattern): Removed.
(parse_one_pattern): Redone.
(get_cert_ldap): Redone.
* src/server.c (cmd_lookup): Changed for changed fetch functions.
* doc/dirmngr.texi: Reworked a bit to get rid of tex errors.
* configure.ac: Enable makeinfo test.
* src/crlcache.c (crl_cache_insert): Fixed for latest KSBA API
changes.
* tests/test-dirmngr.c (main): Ditto. Also added some more error
checking.
2003-11-11 Werner Koch <wk@gnupg.org>
* src/cert.c (hashify_data, hexify_data, serial_hex)
(serial_to_buffer): Moved all to ...
* src/misc.c: .. here.
* src/Makefile.am (cert.c, cert.h): Removed.
* cert.c, cert.h: Removed.
* m4/: New.
* configure.ac, Makefile.am: Include m4 directory support, updated
required library versions.
* src/cert.c (make_cert): Removed.
* src/ldap.c (fetch_next_cert_ldap): Return a gpg style error.
* src/misc.h (copy_time): New.
* src/misc.c (get_isotime): New.
(iso_string2time, iso_time2string): Removed.
(unhexify): New.
* src/crlcache.h (DBCONTENTSVERSION): Bumbed to 0.6.
* src/crlcache.c (finish_sig_check): New. Factored out from
crl_parse_insert and entirely redone.
(do_encode_md): Removed.
(print_time): Removed
(crl_cache_isvalid): Reworked.
2003-11-10 Werner Koch <wk@gnupg.org>
* src/crlcache.c (make_db_val, parse_db_val): Removed.
* src/cert.c (serial_to_buffer): New.
* src/server.c (get_issuer_cert_local): Rewritten.
* src/crlcache.c (crl_parse_insert): Rewritten. Takes now a CTRL
instead of the Assuan context. Changed caller accordingly.
(get_issuer_cert): Cleaned up.
* src/crlfetch.c (crl_fetch): Changed VALUE to unsigned char* for
documentation reasons. Make sure that VALUE is released on error.
(crl_fetch_default, ca_cert_fetch): Ditto.
* src/crlcache.c (release_cache): New.
(crl_cache_deinit): Use it here.
(crl_cache_flush): Redone.
(save_contents): Redone.
(crl_cache_list, list_one_crl_entry): Print error messages.
2003-11-06 Werner Koch <wk@gnupg.org>
* src/crlcache.c (create_directory_if_needed, cleanup_cache_dir):
New. Factored out from crl_cache_new and mostly rewritten.
(crl_cache_new): Rewritten.
(next_line_from_file): New.
(find_entry): Cleaned up.
(crl_cache_deinit): Cleaned up.
* src/dirmngr.c (dirmngr_init_default_ctrl): New stub.
* src/dirmngr.h (ctrl_t): New.
(DBG_ASSUAN,...): Added the usual debug test macros.
* src/server.c: Removed the GET_PTR cruft, replaced it by ctrl_t.
Removed the recursion flag.
(get_issuer_cert_local): Allow for arbitary large
certificates. 4096 is definitely too small.
(inquire_cert): Ditto.
(start_command_handler): Set a hello line and call the default
init function.
(cmd_isvalid): Rewritten.
(inquire_cert): Removed unused arg LINE. General cleanup.
(map_assuan_err,map_to_assuan_status): New. Taken from gnupg 1.9.
(cmd_lookup): Rewritten.
(cmd_loadcrl): Started to rewrite it.
2003-10-29 Werner Koch <wk@gnupg.org>
* src/dirmngr.c (parse_ldapserver_file): Entirely rewritten.
(cleanup): New.
(main): Cleaned up.
2003-10-28 Werner Koch <wk@gnupg.org>
* src/dirmngr.h: Renamed dirmngr_opt to opt.
* src/dirmngr.c (parse_ldapserver_file, free_ldapservers_list):
Moved with this file. Cleaned up. Replaced too deep recursion in
the free function.
2003-10-21 Werner Koch <wk@gnupg.org>
Changed all occurrences of assuan.h to use use the system provided
one.
* src/server.c (register_commands): Adjusted for Assuan API change.
2003-08-14 Werner Koch <wk@gnupg.org>
* src/Makefile.am: s/LIBKSBA_/KSBA_/. Changed for external Assuan lib.
* tests/Makefile.am: Ditto.
* configure.ac: Partly restructured, add standard checks for
required libraries, removed included libassuan.
* Makefile.am (SUBDIRS): Removed assuan becuase we now use the
libassuan package.
* src/dirmngr.c (main): Properly initialize Libgcrypt and libksba.
2003-08-13 Werner Koch <wk@gnupg.org>
* src/server.c (get_issuer_cert_local): Print error using
assuan_strerror.
* src/crlcache.c (do_encode_md, start_sig_check): Adjust for
changed Libgcrypt API.
2003-06-19 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* configure.ac: Upped version to 0.4.7-cvs.
2003-06-19 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* configure.ac: Release 0.4.6.
2003-06-17 Bernhard Reiter <bernhard@intevation.de>
* src/ldap.c (url_fetch_ldap()):
try other default servers when an url with hostname failed
* AUTHORS: added Steffen and Werner
* THANKS: Thanked people in the ChangeLog and the Ägypten-Team
2003-06-16 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* configure.ac, src/crlcache.h, src/crlcache.c: Added db4 support.
* src/Makefile.am, tests/Makefile.am: Removed automake warning.
* tests/test-dirmngr.c: Removed a warning.
2003-05-12 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* doc/Makefile.am: Added dirmngr.ops to DISTCLEANFILES.
* ChangeLog, doc/ChangeLog, src/ChangeLog: Merged dirmngr ChangeLogs
into one toplevel file.
* acinclude.m4, configure.ac: Renamed PFX to PATH for consistency.
2003-05-12 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/ldap.c: Fixed end-of-certificates-list indication.
2003-05-08 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/server.c: Fixed iteration over server list
2003-02-23 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/crlcache.h, src/crlcache.c, src/dirmngr.c: Implemented --flush command.
2003-02-07 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Release 0.4.4.
2003-02-05 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/ldap.c: Try harder with and without ";binary" in the
attribute name when fetching certificates.
* src/ldap.c, src/server.c: Support multiple userCertificate attributes
per entry.
2003-02-04 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* src/ldap.c: Include the sn attribute in the search filter.
Better log messages.
2002-11-20 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Doc updates (fixes #1373)
* Fix for #1419 (crash in free_ldapservers_list())
* Fix for #1375. Dirmngr now asks back with an INQUIRE SENDCERT before
querying the LDAP servers for an issuer certificate to validate a CRL
2002-11-12 Werner Koch <wk@gnupg.org>
* config.sub, config.guess: Updated from ftp.gnu.org/gnu/config
to version 2002-11-08.
2002-11-12 Werner Koch <wk@gnupg.org>
* dirmngr.c (main) <load_crl_filename>: Better pass NULL instead
of an unitialized Assuan context. Let's hope that the other
functions can cope with this.
2002-10-25 Bernhard Reiter <bernhard@intevation.de>
* src/ldap.c (get_attr_from_result_ldap()):
added value extraction retry for CRLs and Certs without ";binary"
* changed version number to reflect cvs status to "0.4.3-cvs"
2002-08-21 Werner Koch <wk@gnupg.org>
* dirmngr.c (main): Changed default homedir to .gnupg.
2002-08-07 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Added configure check to examine whether db2 cursor() uses 3 or
4 parameters.
2002-07-31 Werner Koch <wk@gnupg.org>
* doc/dirmngr.texi: Fixed the structure and added menu entries
for the other nodes.
2002-07-30 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Added doc dir and first steps towards manual.
2002-07-29 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Got rid of the default server for CRL lookup. We now use the
same list of servers that we use for cert. lookup.
2002-07-29 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* New option --add-servers to allow dirmngr to add LDAP servers
found in CRL distribution points to the list of servers it
searches. NOTE: The added servers are only active in the currently
running dirmngr -- the info isn't written to persistens storage.
2002-07-26 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Default LDAP timeout is 100 seconds now.
* Use DB2 instead of DB1. Check for libresolv, fixed bug when
libldap was found in the default search path.
2002-07-22 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Implemented --load-crl <filename> option. Also available as
LOADCRL assuan command when in server mode.
2002-07-22 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Implemented new option --ldaptimeout to specify the number of seconds to
wait for an LDAP request before timeout.
* Added --list-crls option to print the contents of the CRL cache
* Added some items to the dbcontents file to make printout nicer
and updated it's version number
2002-07-02 Werner Koch <wk@gnupg.org>
* crlcache.c (crl_parse_insert): Fixed log_debug format string.
2002-07-02 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* configure.ac: Use DB->get() return value correctly.
2002-06-28 Werner Koch <wk@gnupg.org>
* crlcache.c (crl_parse_insert): Keep track of newly allocated
ENTRY so that we don't free existing errors after a bad signature.
* dirmngr.h: Include prototype for start_command_handler.
* crlfetch.c, crlcache.c, http.c, cert.c, ldap.c: Include
config.h.
* crlcache.c (crl_parse_insert): Fixed format type specifiers for
time_t variables in log_debug.
* error.h: Use log_debug instead of dirmngr_debug. Changed all
callers.
* Makefile.am (dirmngr_SOURCES): Removed error.c
* dirmngr.c (main): Register gcrypt malloc functions with ksba so
that we don't run into problems by using the wrong free function.
The gcrypt malloc function have the additional benefit of a
providing allocation sanity checks when compiled with that
feature.
* crlcache.c (get_issuer_cert): Use xfree instead of ksba_free.
2002-06-27 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* ldap.c: Look for both userCertificate and caCertificate
2002-06-26 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* configure.ac: Upped version number to 0.3.1
2002-06-25 Werner Koch <wk@gnupg.org>
* server.c (cmd_lookup): Use assuan_write_status which ensures a
correct syntax.
2002-06-20 Werner Koch <wk@gnupg.org>
* crlcache.c (crl_cache_isvalid): Started with some nicer logging.
However, this will need a lot more work.
(get_issuer_cert): Ditto.
* dirmngr.c (main): Changed required libgcrypt version and don't
print the prefix when using a logfile.
2002-06-20 Werner Koch <wk@gnupg.org>
* tests/Makefile.am (TESTS): Removed test-dirmngr because it
is not a proper test program.
(EXTRA_DIST): Removed the non-existent test certificate.
2002-05-21 Werner Koch <wk@gnupg.org>
* server.c (start_command_handler): Enable assuan debugging.
2002-05-08 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Replaced gdbm check with db1 check
2002-05-08 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Replaced gdbm with db1, updated file format version
2002-03-01 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Added gdbm configure check
2002-01-23 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Return ASSUAN_CRL_Too_Old if the CRL is too old
2002-01-17 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
Added commandline options --ldapserver <host> --ldapport <port>
--ldapuser <user> --ldappassword <passwd>.
Cleaned up CRL parsing, signature evaluation a bit, changed
datetime format in config file to ISO, added version string to
contents format and cache file clean up code in case of mismatch.
2002-01-14 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
* Use dirmngr_opt.homedir for storing the db. Added Makefile.am to
tests, bugfixes.
* First code.
Things that work:
Loading/saving database (paths hardcoded)
Fetching CRL from hardcoded server, parsing and inserting in database
Answer ISVALID xxx.yyy requests
Things that are missing:
Some error-checking/handling
Proper autoconf handling of gdbm and OpenLDAP
Signature checking downloaded CRLs
Answer LOOKUP requests
...
How to test:
cd tests
ldapsearch -v -x -h www.trustcenter.de -b '<some-users-DN>' userCertificate -t
cp /tmp/<cert-file> testcert.der
./test-dirmngr

65
dirmngr/Makefile.am Normal file
View File

@ -0,0 +1,65 @@
# Makefile.am - dirmngr
# Copyright (C) 2002 Klarälvdalens Datakonsult AB
# Copyright (C) 2004, 2007, 2010 g10 Code GmbH
#
# 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/>.
## Process this file with automake to produce Makefile.in
EXTRA_DIST = OAUTHORS ONEWS ChangeLog.1
bin_PROGRAMS = dirmngr dirmngr-client
libexec_PROGRAMS = dirmngr_ldap
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) \
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS)
BUILT_SOURCES = no-libgcrypt.c
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
ldapserver.h ldapserver.c certcache.c certcache.h \
b64dec.c cdb.h cdblib.c ldap.c http.c http.h misc.c \
ocsp.c ocsp.h validate.c validate.h
dirmngr_LDADD = $(libcommonpth) $(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
if HAVE_W32_SYSTEM
ldap_url = ldap-url.h ldap-url.c
else
ldap_url =
endif
dirmngr_ldap_SOURCES = dirmngr_ldap.c $(ldap_url) no-libgcrypt.c
dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS)
dirmngr_ldap_LDFLAGS =
dirmngr_ldap_LDADD = $(libcommon) $(DNSLIBS) \
$(GPG_ERROR_LIBS) $(LDAPLIBS) $(LIBINTL) $(LIBICONV)
dirmngr_client_SOURCES = dirmngr-client.c b64enc.c no-libgcrypt.c
dirmngr_client_LDADD = $(libcommon) $(LIBASSUAN_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
no-libgcrypt.c : $(top_srcdir)/tools/no-libgcrypt.c
cat $(top_srcdir)/tools/no-libgcrypt.c > no-libgcrypt.c

40
dirmngr/OAUTHORS Normal file
View File

@ -0,0 +1,40 @@
The old AUTHORS file from the separate dirmngr package.
Package: dirmngr
Maintainer: Werner Koch <wk@gnupg.org>
Bug reports: bug-dirmngr@gnupg.org
Security related bug reports: security@gnupg.org
License: GPLv2+
Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
- Initial code
g10 Code GmbH <code@g10code.com>
- All stuff written since October 2003.
Werner Koch <wk@gnupg.org>, <wk@g10code.com>
- Help with initial code.
Free Software Foundation <gnu@gnu.org>
- Code taken from GnuPG.
Michael Tokarev <mjt@corpit.ru>
- src/cdb.h and src/cdblib.c from the public domain tinycdb 0.73.
The actual code is under the GNU GPL, except for src/cdb.h and
src/cdblib.h which are in the public domain.
Copyright 2003, 2004, 2006, 2007, 2008, 2010 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

240
dirmngr/ONEWS Normal file
View File

@ -0,0 +1,240 @@
These are NEWS entries from the old separate dirmngr package
Noteworthy changes in version 1.1.0 (unreleased)
------------------------------------------------
* Fixed a resource problem with LDAP CRLs.
* Fixed a bad EOF detection with HTTP CRLs.
* Made "dirmngr-client --url --load-crl URL" work.
* New option --ignore-cert-extension.
* Make use of libassuan 2.0 which is available as a DSO.
Noteworthy changes in version 1.0.3 (2009-06-17)
------------------------------------------------
* Client based trust anchors are now supported.
* Configured certificates with the suffix ".der" are now also used.
* Libgcrypt 1.4 is now required.
Noteworthy changes in version 1.0.2 (2008-07-31)
------------------------------------------------
* New option --url for the LOOKUP command and dirmngr-client.
* The LOOKUP command does now also consults the local cache. New
option --cache-only for it and --local for dirmngr-client.
* Port to Windows completed.
* Improved certificate chain construction.
* Support loading of PEM encoded CRLs via HTTP.
Noteworthy changes in version 1.0.1 (2007-08-16)
------------------------------------------------
* The option --ocsp-signer may now take a filename to allow several
certificates to be valid signers for the default responder.
* New option --ocsp-max-period and improved the OCSP time checks.
* New option --force-default-signer for dirmngr-client.
* Ported to Windows.
Noteworthy changes in version 1.0.0 (2006-11-29)
------------------------------------------------
* Bumbed the version number.
* Removed included gettext. We now require the system to provide a
suitable installation.
Noteworthy changes in version 0.9.7 (2006-11-17)
------------------------------------------------
* Internal cleanups.
* Fixed updating of DIR.txt. Add additional diagnostics.
* Updated gettext package.
Noteworthy changes in version 0.9.6 (2006-09-04)
------------------------------------------------
* A couple of bug fixes for OCSP.
* OCSP does now make use of the responder ID and optionally included
certificates in the response to locate certificates.
* No more lost file descriptors when loading CRLs via HTTP.
* HTTP redirection for CRL and OCSP has been implemented.
* Man pages are now build and installed from the texinfo source.
Noteworthy changes in version 0.9.5 (2006-06-27)
------------------------------------------------
* Fixed a problems with the CRL caching and CRL certificate
validation.
* Improved diagnostics.
Noteworthy changes in version 0.9.4 (2006-05-16)
------------------------------------------------
* Try all names of each crlDP.
* Don't shutdown the socket after sending the HTTP request.
Noteworthy changes in version 0.9.3 (2005-10-26)
------------------------------------------------
* Minor bug fixes.
Noteworthy changes in version 0.9.2 (2005-04-21)
------------------------------------------------
* Make use of authorityKeyidentifier.keyIdentifier.
* Fixed a possible hang on exit.
Noteworthy changes in version 0.9.1 (2005-02-08)
------------------------------------------------
* New option --pem for dirmngr-client to allow requesting service
using a PEM encoded certificate.
* New option --squid-mode to allow using dirmngr-client directly as a
Squid helper.
* Bug fixes.
Noteworthy changes in version 0.9.0 (2004-12-17)
------------------------------------------------
* New option --daemon to start dirmngr as a system daemon. This
switches to the use of different directories and also does
CRL signing certificate validation on its own.
* New tool dirmngr-client.
* New options: --ldap-wrapper-program, --http-wrapper-program,
--disable-ldap, --disable-http, --honor-http-proxy, --http-proxy,
--ldap-proxy, --only-ldap-proxy, --ignore-ldap-dp and
--ignore-http-dp.
* Uses an external ldap wrapper to cope with timeouts and general
LDAP problems.
* SIGHUP may be used to reread the configuration and to flush the
certificate cache.
* An authorithyKeyIdentifier in a CRL is now handled correctly.
Noteworthy changes in version 0.5.6 (2004-09-28)
------------------------------------------------
* LDAP fix.
* Logging fixes.
* Updated some configuration files.
Noteworthy changes in version 0.5.5 (2004-05-13)
------------------------------------------------
* Fixed the growing-dir.txt bug.
* Better LDAP error logging.
Noteworthy changes in version 0.5.4 (2004-04-29)
------------------------------------------------
* New commands --ocsp-responder and --ocsp-signer to define a default
OCSP reponder if a certificate does not contain an assigned OCSP
responder.
Noteworthy changes in version 0.5.3 (2004-04-06)
------------------------------------------------
* Basic OCSP support.
Noteworthy changes in version 0.5.2 (2004-03-06)
------------------------------------------------
* New Assuan command LISTCRLS.
* A couple of minor bug fixes.
Noteworthy changes in version 0.5.1 (2003-12-23)
------------------------------------------------
* New options --faked-system-time and --force.
* Changed the name of the cache directory to $HOMEDIR/dirmngr-cache.d
and renamed the dbcontents file. You may delete the now obsolete
cache/ directory and the dbcontents file.
* Dropped DB2 or DB4 use. There is no need for it because a constant
database fits our needs far better.
* Experimental support for retrieving CRLs via http.
* The --log-file option may now be used to print logs to a socket.
Prefix the socket name with "socket://" to enable this. This does
not work on all systems and falls back to stderr if there is a
problem with the socket.
Noteworthy changes in version 0.5.0 (2003-11-17)
------------------------------------------------
* Revamped the entire thing.
* Does now require Libgcrypt 1.1.90 or higher, as well as the latest
libksba and libassuan.
* Fixed a bug in the assuan inquire processing.
Noteworthy changes as of 2002-08-21
------------------------------------
* The default home directory is now .gnupg
Copyright 2003, 2004, 2005 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

217
dirmngr/b64dec.c Normal file
View File

@ -0,0 +1,217 @@
/* b64dec.c - Simple Base64 decoder.
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "i18n.h"
#include "util.h"
/* The reverse base-64 list used for base-64 decoding. */
static unsigned char const asctobin[128] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
};
enum decoder_states
{
s_init, s_idle, s_lfseen, s_begin,
s_b64_0, s_b64_1, s_b64_2, s_b64_3,
s_waitendtitle, s_waitend
};
/* Initialize the context for the base64 decoder. If TITLE is NULL a
plain base64 decoding is done. If it is the empty string the
decoder will skip everything until a "-----BEGIN " line has been
seen, decoding ends at a "----END " line.
Not yet implemented: If TITLE is either "PGP" or begins with "PGP "
the PGP armor lines are skipped as well. */
gpg_error_t
b64dec_start (struct b64state *state, const char *title)
{
memset (state, 0, sizeof *state);
if (title)
{
if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
state->title = xtrystrdup (title);
if (!state->title)
return gpg_error_from_syserror ();
state->idx = s_init;
}
else
state->idx = s_b64_0;
return 0;
}
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
new length of the buffer at R_NBYTES. */
gpg_error_t
b64dec_proc (struct b64state *state, void *buffer, size_t length,
size_t *r_nbytes)
{
enum decoder_states ds = state->idx;
unsigned char val = state->radbuf[0];
int pos = state->quad_count;
char *d, *s;
if (state->stop_seen)
{
*r_nbytes = 0;
return gpg_error (GPG_ERR_EOF);
}
for (s=d=buffer; length && !state->stop_seen; length--, s++)
{
switch (ds)
{
case s_idle:
if (*s == '\n')
{
ds = s_lfseen;
pos = 0;
}
break;
case s_init:
ds = s_lfseen;
case s_lfseen:
if (*s != "-----BEGIN "[pos])
ds = s_idle;
else if (pos == 10)
ds = s_begin;
else
pos++;
break;
case s_begin:
if (*s == '\n')
ds = s_b64_0;
break;
case s_b64_0:
case s_b64_1:
case s_b64_2:
case s_b64_3:
{
int c;
if (*s == '-' && state->title)
{
/* Not a valid Base64 character: assume end
header. */
ds = s_waitend;
}
else if (*s == '=')
{
/* Pad character: stop */
if (ds == s_b64_1)
*d++ = val;
ds = state->title? s_waitendtitle : s_waitend;
}
else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
; /* Skip white spaces. */
else if ( (*s & 0x80)
|| (c = asctobin[*(unsigned char *)s]) == 255)
{
/* Skip invalid encodings. */
state->invalid_encoding = 1;
}
else if (ds == s_b64_0)
{
val = c << 2;
ds = s_b64_1;
}
else if (ds == s_b64_1)
{
val |= (c>>4)&3;
*d++ = val;
val = (c<<4)&0xf0;
ds = s_b64_2;
}
else if (ds == s_b64_2)
{
val |= (c>>2)&15;
*d++ = val;
val = (c<<6)&0xc0;
ds = s_b64_3;
}
else
{
val |= c&0x3f;
*d++ = val;
ds = s_b64_0;
}
}
break;
case s_waitendtitle:
if (*s == '-')
ds = s_waitend;
break;
case s_waitend:
if ( *s == '\n')
state->stop_seen = 1;
break;
default:
BUG();
}
}
state->idx = ds;
state->radbuf[0] = val;
state->quad_count = pos;
*r_nbytes = (d -(char*) buffer);
return 0;
}
/* This function needs to be called before releasing the decoder
state. It may return an error code in case an encoding error has
been found during decoding. */
gpg_error_t
b64dec_finish (struct b64state *state)
{
xfree (state->title);
state->title = NULL;
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
}

213
dirmngr/b64enc.c Normal file
View File

@ -0,0 +1,213 @@
/* b64enc.c - Simple Base64 encoder.
* Copyright (C) 2001, 2003, 2004 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "i18n.h"
#include "util.h"
#define B64ENC_DID_HEADER 1
#define B64ENC_DID_TRAILER 2
#define B64ENC_NO_LINEFEEDS 16
/* The base-64 character list */
static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
and not an empty string, this string will be used as the title for
the armor lines, with TITLE being an empty string, we don't write
the header lines and furthermore even don't write any linefeeds.
With TITLE beeing NULL, we merely don't write header but make sure
that lines are not too long. Note, that we don't write any output
unless at least one byte get written using b64enc_write. */
gpg_error_t
b64enc_start (struct b64state *state, FILE *fp, const char *title)
{
memset (state, 0, sizeof *state);
state->fp = fp;
if (title && !*title)
state->flags |= B64ENC_NO_LINEFEEDS;
else if (title)
{
state->title = strdup (title);
if (!state->title)
return gpg_error_from_errno (errno);
}
return 0;
}
/* Write NBYTES from BUFFER to the Base 64 stream identified by
STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
stream. */
gpg_error_t
b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
{
unsigned char radbuf[4];
int idx, quad_count;
const unsigned char *p;
FILE *fp = state->fp;
if (!nbytes)
{
if (buffer && fflush (fp))
goto write_error;
return 0;
}
if (!(state->flags & B64ENC_DID_HEADER))
{
if (state->title)
{
if ( fputs ("-----BEGIN ", fp) == EOF
|| fputs (state->title, fp) == EOF
|| fputs ("-----\n", fp) == EOF)
goto write_error;
}
state->flags |= B64ENC_DID_HEADER;
}
idx = state->idx;
quad_count = state->quad_count;
assert (idx < 4);
memcpy (radbuf, state->radbuf, idx);
for (p=buffer; nbytes; p++, nbytes--)
{
radbuf[idx++] = *p;
if (idx > 2)
{
char tmp[4];
tmp[0] = bintoasc[(*radbuf >> 2) & 077];
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
tmp[3] = bintoasc[radbuf[2]&077];
for (idx=0; idx < 4; idx++)
putc (tmp[idx], fp);
idx = 0;
if (ferror (fp))
goto write_error;
if (++quad_count >= (64/4))
{
quad_count = 0;
if (!(state->flags & B64ENC_NO_LINEFEEDS)
&& fputs ("\n", fp) == EOF)
goto write_error;
}
}
}
memcpy (state->radbuf, radbuf, idx);
state->idx = idx;
state->quad_count = quad_count;
return 0;
write_error:
return gpg_error_from_errno (errno);
}
gpg_error_t
b64enc_finish (struct b64state *state)
{
gpg_error_t err = 0;
unsigned char radbuf[4];
int idx, quad_count;
FILE *fp;
if (!(state->flags & B64ENC_DID_HEADER))
goto cleanup;
/* Flush the base64 encoding */
fp = state->fp;
idx = state->idx;
quad_count = state->quad_count;
assert (idx < 4);
memcpy (radbuf, state->radbuf, idx);
if (idx)
{
char tmp[4];
tmp[0] = bintoasc[(*radbuf>>2)&077];
if (idx == 1)
{
tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
tmp[2] = '=';
tmp[3] = '=';
}
else
{
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
tmp[3] = '=';
}
for (idx=0; idx < 4; idx++)
putc (tmp[idx], fp);
idx = 0;
if (ferror (fp))
goto write_error;
if (++quad_count >= (64/4))
{
quad_count = 0;
if (!(state->flags & B64ENC_NO_LINEFEEDS)
&& fputs ("\n", fp) == EOF)
goto write_error;
}
}
/* Finish the last line and write the trailer. */
if (quad_count
&& !(state->flags & B64ENC_NO_LINEFEEDS)
&& fputs ("\n", fp) == EOF)
goto write_error;
if (state->title)
{
if ( fputs ("-----END ", fp) == EOF
|| fputs (state->title, fp) == EOF
|| fputs ("-----\n", fp) == EOF)
goto write_error;
}
goto cleanup;
write_error:
err = gpg_error_from_errno (errno);
cleanup:
if (state->title)
{
free (state->title);
state->title = NULL;
}
state->fp = NULL;
return err;
}

91
dirmngr/cdb.h Normal file
View File

@ -0,0 +1,91 @@
/* $Id: cdb.h 106 2003-12-12 17:36:49Z werner $
* public cdb include file
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*
* Taken from tinycdb-0.73. By Werner Koch <wk@gnupg.org> 2003-12-12.
*/
#ifndef TINYCDB_VERSION
#define TINYCDB_VERSION 0.73
typedef unsigned int cdbi_t; /*XXX should be at least 32 bits long */
/* common routines */
cdbi_t cdb_hash(const void *buf, cdbi_t len);
cdbi_t cdb_unpack(const unsigned char buf[4]);
void cdb_pack(cdbi_t num, unsigned char buf[4]);
struct cdb {
int cdb_fd; /* file descriptor */
/* private members */
cdbi_t cdb_fsize; /* datafile size */
const unsigned char *cdb_mem; /* mmap'ed file memory */
cdbi_t cdb_vpos, cdb_vlen; /* found data */
cdbi_t cdb_kpos, cdb_klen; /* found key (only set if cdb_findinit
was called with KEY set to NULL). */
};
#define cdb_datapos(c) ((c)->cdb_vpos)
#define cdb_datalen(c) ((c)->cdb_vlen)
#define cdb_keypos(c) ((c)->cdb_kpos)
#define cdb_keylen(c) ((c)->cdb_klen)
#define cdb_fileno(c) ((c)->cdb_fd)
int cdb_init(struct cdb *cdbp, int fd);
void cdb_free(struct cdb *cdbp);
int cdb_read(const struct cdb *cdbp,
void *buf, unsigned len, cdbi_t pos);
int cdb_find(struct cdb *cdbp, const void *key, unsigned klen);
struct cdb_find {
struct cdb *cdb_cdbp;
cdbi_t cdb_hval;
const unsigned char *cdb_htp, *cdb_htab, *cdb_htend;
cdbi_t cdb_httodo;
const void *cdb_key;
cdbi_t cdb_klen;
};
int cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
const void *key, cdbi_t klen);
int cdb_findnext(struct cdb_find *cdbfp);
/* old simple interface */
/* open file using standard routine, then: */
int cdb_seek(int fd, const void *key, unsigned klen, cdbi_t *dlenp);
int cdb_bread(int fd, void *buf, int len);
/* cdb_make */
struct cdb_make {
int cdb_fd; /* file descriptor */
/* private */
cdbi_t cdb_dpos; /* data position so far */
cdbi_t cdb_rcnt; /* record count so far */
char cdb_buf[4096]; /* write buffer */
char *cdb_bpos; /* current buf position */
struct cdb_rl *cdb_rec[256]; /* list of arrays of record infos */
};
int cdb_make_start(struct cdb_make *cdbmp, int fd);
int cdb_make_add(struct cdb_make *cdbmp,
const void *key, cdbi_t klen,
const void *val, cdbi_t vlen);
int cdb_make_exists(struct cdb_make *cdbmp,
const void *key, cdbi_t klen);
int cdb_make_put(struct cdb_make *cdbmp,
const void *key, cdbi_t klen,
const void *val, cdbi_t vlen,
int flag);
#define CDB_PUT_ADD 0 /* add unconditionnaly, like cdb_make_add() */
#define CDB_PUT_REPLACE 1 /* replace: do not place to index OLD record */
#define CDB_PUT_INSERT 2 /* add only if not already exists */
#define CDB_PUT_WARN 3 /* add unconditionally but ret. 1 if exists */
int cdb_make_finish(struct cdb_make *cdbmp);
#endif /* include guard */

925
dirmngr/cdblib.c Normal file
View File

@ -0,0 +1,925 @@
/* cdblib.c - all CDB library functions.
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*
* Taken from tinycdb-0.73 and merged into one file for easier
* inclusion into Dirmngr. By Werner Koch <wk@gnupg.org> 2003-12-12.
*/
/* A cdb database is a single file used to map `keys' to `values',
having records of (key,value) pairs. File consists of 3 parts: toc
(table of contents), data and index (hash tables).
Toc has fixed length of 2048 bytes, containing 256 pointers to hash
tables inside index sections. Every pointer consists of position
of a hash table in bytes from the beginning of a file, and a size
of a hash table in entries, both are 4-bytes (32 bits) unsigned
integers in little-endian form. Hash table length may have zero
length, meaning that corresponding hash table is empty.
Right after toc section, data section follows without any
alingment. It consists of series of records, each is a key length,
value (data) length, key and value. Again, key and value length
are 4-byte unsigned integers. Each next record follows previous
without any special alignment.
After data section, index (hash tables) section follows. It should
be looked to in conjunction with toc section, where each of max 256
hash tables are defined. Index section consists of series of hash
tables, with starting position and length defined in toc section.
Every hash table is a sequence of records each holds two numbers:
key's hash value and record position inside data section (bytes
from the beginning of a file to first byte of key length starting
data record). If record position is zero, then this is an empty
hash table slot, pointed to nowhere.
CDB hash function is
hv = ((hv << 5) + hv) ^ c
for every single c byte of a key, starting with hv = 5381.
Toc section indexed by (hv % 256), i.e. hash value modulo 256
(number of entries in toc section).
In order to find a record, one should: first, compute the hash
value (hv) of a key. Second, look to hash table number hv modulo
256. If it is empty, then there is no such key exists. If it is
not empty, then third, loop by slots inside that hash table,
starting from slot with number hv divided by 256 modulo length of
that table, or ((hv / 256) % htlen), searching for this hv in hash
table. Stop search on empty slot (if record position is zero) or
when all slots was probed (note cyclic search, jumping from end to
beginning of a table). When hash value in question is found in
hash table, look to key of corresponding record, comparing it with
key in question. If them of the same length and equals to each
other, then record is found, overwise, repeat with next hash table
slot. Note that there may be several records with the same key.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/mman.h>
# ifndef MAP_FAILED
# define MAP_FAILED ((void*)-1)
# endif
#endif
#include <sys/stat.h>
#include "cdb.h"
#ifndef EPROTO
# define EPROTO EINVAL
#endif
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
struct cdb_rec {
cdbi_t hval;
cdbi_t rpos;
};
struct cdb_rl {
struct cdb_rl *next;
cdbi_t cnt;
struct cdb_rec rec[254];
};
static int make_find(struct cdb_make *cdbmp,
const void *key, cdbi_t klen, cdbi_t hval,
struct cdb_rl **rlp);
static int make_write(struct cdb_make *cdbmp,
const char *ptr, cdbi_t len);
/* Initializes structure given by CDBP pointer and associates it with
the open file descriptor FD. Allocate memory for the structure
itself if needed and file open operation should be done by
application. File FD should be opened at least read-only, and
should be seekable. Routine returns 0 on success or negative value
on error. */
int
cdb_init(struct cdb *cdbp, int fd)
{
struct stat st;
unsigned char *mem;
unsigned fsize;
#ifdef _WIN32
HANDLE hFile, hMapping;
#endif
/* get file size */
if (fstat(fd, &st) < 0)
return -1;
/* trivial sanity check: at least toc should be here */
if (st.st_size < 2048) {
errno = EPROTO;
return -1;
}
fsize = (unsigned)(st.st_size & 0xffffffffu);
/* memory-map file */
#ifdef _WIN32
hFile = (HANDLE) _get_osfhandle(fd);
if (hFile == (HANDLE) -1)
return -1;
hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMapping)
return -1;
mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
if (!mem)
return -1;
#else
mem = (unsigned char*)mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED)
return -1;
#endif /* _WIN32 */
cdbp->cdb_fd = fd;
cdbp->cdb_fsize = st.st_size;
cdbp->cdb_mem = mem;
#if 0
/* XXX don't know well about madvise syscall -- is it legal
to set different options for parts of one mmap() region?
There is also posix_madvise() exist, with POSIX_MADV_RANDOM etc...
*/
#ifdef MADV_RANDOM
/* set madvise() parameters. Ignore errors for now if system
doesn't support it */
madvise(mem, 2048, MADV_WILLNEED);
madvise(mem + 2048, cdbp->cdb_fsize - 2048, MADV_RANDOM);
#endif
#endif
cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
return 0;
}
/* Frees the internal resources held by structure. Note that this
routine does not close the file. */
void
cdb_free(struct cdb *cdbp)
{
if (cdbp->cdb_mem) {
#ifdef _WIN32
HANDLE hFile, hMapping;
#endif
#ifdef _WIN32
hFile = (HANDLE) _get_osfhandle(cdbp->cdb_fd);
hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
UnmapViewOfFile((void*) cdbp->cdb_mem);
CloseHandle(hMapping);
#else
munmap((void*)cdbp->cdb_mem, cdbp->cdb_fsize);
#endif /* _WIN32 */
cdbp->cdb_mem = NULL;
}
cdbp->cdb_fsize = 0;
}
/* Read data from cdb file, starting at position pos of length len,
placing result to buf. This routine may be used to get actual
value found by cdb_find() or other routines that returns position
and length of a data. Returns 0 on success or negative value on
error. */
int
cdb_read(const struct cdb *cdbp, void *buf, unsigned len, cdbi_t pos)
{
if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) {
errno = EPROTO;
return -1;
}
memcpy(buf, cdbp->cdb_mem + pos, len);
return 0;
}
/* Attempts to find a key given by (key,klen) parameters. If key
exists in database, routine returns 1 and places position and
length of value associated with this key to internal fields inside
cdbp structure, to be accessible by cdb_datapos() and
cdb_datalen(). If key is not in database, routines returns 0. On
error, negative value is returned. Note that using cdb_find() it
is possible to lookup only first record with a given key. */
int
cdb_find(struct cdb *cdbp, const void *key, cdbi_t klen)
{
const unsigned char *htp; /* hash table pointer */
const unsigned char *htab; /* hash table */
const unsigned char *htend; /* end of hash table */
cdbi_t httodo; /* ht bytes left to look */
cdbi_t pos, n;
cdbi_t hval;
if (klen > cdbp->cdb_fsize) /* if key size is larger than file */
return 0;
hval = cdb_hash(key, klen);
/* find (pos,n) hash table to use */
/* first 2048 bytes (toc) are always available */
/* (hval % 256) * 8 */
htp = cdbp->cdb_mem + ((hval << 3) & 2047); /* index in toc (256x8) */
n = cdb_unpack(htp + 4); /* table size */
if (!n) /* empty table */
return 0; /* not found */
httodo = n << 3; /* bytes of htab to lookup */
pos = cdb_unpack(htp); /* htab position */
if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
|| pos > cdbp->cdb_fsize /* htab start within file ? */
|| httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
{
errno = EPROTO;
return -1;
}
htab = cdbp->cdb_mem + pos; /* htab pointer */
htend = htab + httodo; /* after end of htab */
/* htab starting position: rest of hval modulo htsize, 8bytes per elt */
htp = htab + (((hval >> 8) % n) << 3);
for(;;) {
pos = cdb_unpack(htp + 4); /* record position */
if (!pos)
return 0;
if (cdb_unpack(htp) == hval) {
if (pos > cdbp->cdb_fsize - 8) { /* key+val lengths */
errno = EPROTO;
return -1;
}
if (cdb_unpack(cdbp->cdb_mem + pos) == klen) {
if (cdbp->cdb_fsize - klen < pos + 8) {
errno = EPROTO;
return -1;
}
if (memcmp(key, cdbp->cdb_mem + pos + 8, klen) == 0) {
n = cdb_unpack(cdbp->cdb_mem + pos + 4);
pos += 8 + klen;
if (cdbp->cdb_fsize < n || cdbp->cdb_fsize - n < pos) {
errno = EPROTO;
return -1;
}
cdbp->cdb_vpos = pos;
cdbp->cdb_vlen = n;
return 1;
}
}
}
httodo -= 8;
if (!httodo)
return 0;
if ((htp += 8) >= htend)
htp = htab;
}
}
/* Sequential-find routines that used separate structure. It is
possible to have many than one record with the same key in a
database, and these routines allows to enumerate all them.
cdb_findinit() initializes search structure pointed to by cdbfp.
It will return negative value on error or 0 on success. cdb_find­
next() attempts to find next matching key, setting value position
and length in cdbfp structure. It will return positive value if
given key was found, 0 if there is no more such key(s), or negative
value on error. To access value position and length after
successeful call to cdb_findnext() (when it returned positive
result), use cdb_datapos() and cdb_datalen() macros with cdbp
pointer. It is error to use cdb_findnext() after it returned 0 or
error condition. These routines is a bit slower than
cdb_find().
Setting KEY to NULL will start a sequential search through the
entire DB.
*/
int
cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
const void *key, cdbi_t klen)
{
cdbi_t n, pos;
cdbfp->cdb_cdbp = cdbp;
cdbfp->cdb_key = key;
cdbfp->cdb_klen = klen;
cdbfp->cdb_hval = key? cdb_hash(key, klen) : 0;
if (key)
{
cdbfp->cdb_htp = cdbp->cdb_mem + ((cdbfp->cdb_hval << 3) & 2047);
n = cdb_unpack(cdbfp->cdb_htp + 4);
cdbfp->cdb_httodo = n << 3; /* Set to size of hash table. */
if (!n)
return 0; /* The hash table is empry. */
pos = cdb_unpack(cdbfp->cdb_htp);
if (n > (cdbp->cdb_fsize >> 3)
|| pos > cdbp->cdb_fsize
|| cdbfp->cdb_httodo > cdbp->cdb_fsize - pos)
{
errno = EPROTO;
return -1;
}
cdbfp->cdb_htab = cdbp->cdb_mem + pos;
cdbfp->cdb_htend = cdbfp->cdb_htab + cdbfp->cdb_httodo;
cdbfp->cdb_htp = cdbfp->cdb_htab + (((cdbfp->cdb_hval >> 8) % n) << 3);
}
else /* Walk over all entries. */
{
cdbfp->cdb_hval = 0;
/* Force stepping in findnext. */
cdbfp->cdb_htp = cdbfp->cdb_htend = cdbp->cdb_mem;
}
return 0;
}
/* See cdb_findinit. */
int
cdb_findnext(struct cdb_find *cdbfp)
{
cdbi_t pos, n;
struct cdb *cdbp = cdbfp->cdb_cdbp;
if (cdbfp->cdb_key)
{
while(cdbfp->cdb_httodo) {
pos = cdb_unpack(cdbfp->cdb_htp + 4);
if (!pos)
return 0;
n = cdb_unpack(cdbfp->cdb_htp) == cdbfp->cdb_hval;
if ((cdbfp->cdb_htp += 8) >= cdbfp->cdb_htend)
cdbfp->cdb_htp = cdbfp->cdb_htab;
cdbfp->cdb_httodo -= 8;
if (n) {
if (pos > cdbp->cdb_fsize - 8) {
errno = EPROTO;
return -1;
}
if (cdb_unpack(cdbp->cdb_mem + pos) == cdbfp->cdb_klen) {
if (cdbp->cdb_fsize - cdbfp->cdb_klen < pos + 8) {
errno = EPROTO;
return -1;
}
if (memcmp(cdbfp->cdb_key,
cdbp->cdb_mem + pos + 8, cdbfp->cdb_klen) == 0) {
n = cdb_unpack(cdbp->cdb_mem + pos + 4);
pos += 8 + cdbfp->cdb_klen;
if (cdbp->cdb_fsize < n || cdbp->cdb_fsize - n < pos) {
errno = EPROTO;
return -1;
}
cdbp->cdb_vpos = pos;
cdbp->cdb_vlen = n;
return 1;
}
}
}
}
}
else /* Walk over all entries. */
{
do
{
while (cdbfp->cdb_htp >= cdbfp->cdb_htend)
{
if (cdbfp->cdb_hval > 255)
return 0; /* No more items. */
cdbfp->cdb_htp = cdbp->cdb_mem + cdbfp->cdb_hval * 8;
cdbfp->cdb_hval++; /* Advance for next round. */
pos = cdb_unpack (cdbfp->cdb_htp); /* Offset of table. */
n = cdb_unpack (cdbfp->cdb_htp + 4); /* Number of entries. */
cdbfp->cdb_httodo = n * 8; /* Size of table. */
if (n > (cdbp->cdb_fsize / 8)
|| pos > cdbp->cdb_fsize
|| cdbfp->cdb_httodo > cdbp->cdb_fsize - pos)
{
errno = EPROTO;
return -1;
}
cdbfp->cdb_htab = cdbp->cdb_mem + pos;
cdbfp->cdb_htend = cdbfp->cdb_htab + cdbfp->cdb_httodo;
cdbfp->cdb_htp = cdbfp->cdb_htab;
}
pos = cdb_unpack (cdbfp->cdb_htp + 4); /* Offset of record. */
cdbfp->cdb_htp += 8;
}
while (!pos);
if (pos > cdbp->cdb_fsize - 8)
{
errno = EPROTO;
return -1;
}
cdbp->cdb_kpos = pos + 8;
cdbp->cdb_klen = cdb_unpack(cdbp->cdb_mem + pos);
cdbp->cdb_vpos = pos + 8 + cdbp->cdb_klen;
cdbp->cdb_vlen = cdb_unpack(cdbp->cdb_mem + pos + 4);
n = 8 + cdbp->cdb_klen + cdbp->cdb_vlen;
if ( pos > cdbp->cdb_fsize || pos > cdbp->cdb_fsize - n)
{
errno = EPROTO;
return -1;
}
return 1; /* Found. */
}
return 0;
}
/* Read a chunk from file, ignoring interrupts (EINTR) */
int
cdb_bread(int fd, void *buf, int len)
{
int l;
while(len > 0) {
do l = read(fd, buf, len);
while(l < 0 && errno == EINTR);
if (l <= 0) {
if (!l)
errno = EIO;
return -1;
}
buf = (char*)buf + l;
len -= l;
}
return 0;
}
/* Find a given key in cdb file, seek a file pointer to it's value and
place data length to *dlenp. */
int
cdb_seek(int fd, const void *key, unsigned klen, cdbi_t *dlenp)
{
cdbi_t htstart; /* hash table start position */
cdbi_t htsize; /* number of elements in a hash table */
cdbi_t httodo; /* hash table elements left to look */
cdbi_t hti; /* hash table index */
cdbi_t pos; /* position in a file */
cdbi_t hval; /* key's hash value */
unsigned char rbuf[64]; /* read buffer */
int needseek = 1; /* if we should seek to a hash slot */
hval = cdb_hash(key, klen);
pos = (hval & 0xff) << 3; /* position in TOC */
/* read the hash table parameters */
if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
return -1;
if ((htsize = cdb_unpack(rbuf + 4)) == 0)
return 0;
hti = (hval >> 8) % htsize; /* start position in hash table */
httodo = htsize;
htstart = cdb_unpack(rbuf);
for(;;) {
if (needseek && lseek(fd, htstart + (hti << 3), SEEK_SET) < 0)
return -1;
if (cdb_bread(fd, rbuf, 8) < 0)
return -1;
if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */
return 0;
if (cdb_unpack(rbuf) != hval) /* hash value not matched */
needseek = 0;
else { /* hash value matched */
if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
return -1;
if (cdb_unpack(rbuf) == klen) { /* key length matches */
/* read the key from file and compare with wanted */
cdbi_t l = klen, c;
const char *k = (const char*)key;
if (*dlenp)
*dlenp = cdb_unpack(rbuf + 4); /* save value length */
for(;;) {
if (!l) /* the whole key read and matches, return */
return 1;
c = l > sizeof(rbuf) ? sizeof(rbuf) : l;
if (cdb_bread(fd, rbuf, c) < 0)
return -1;
if (memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */
break;
k += c; l -= c;
}
}
needseek = 1; /* we're looked to other place, should seek back */
}
if (!--httodo)
return 0;
if (++hti == htsize) {
hti = htstart;
needseek = 1;
}
}
}
cdbi_t
cdb_unpack(const unsigned char buf[4])
{
cdbi_t n = buf[3];
n <<= 8; n |= buf[2];
n <<= 8; n |= buf[1];
n <<= 8; n |= buf[0];
return n;
}
/* Add record with key (KEY,KLEN) and value (VAL,VLEN) to a database.
Returns 0 on success or negative value on error. Note that this
routine does not checks if given key already exists, but cdb_find()
will not see second record with the same key. It is not possible
to continue building a database if cdb_make_add() returned an error
indicator. */
int
cdb_make_add(struct cdb_make *cdbmp,
const void *key, cdbi_t klen,
const void *val, cdbi_t vlen)
{
unsigned char rlen[8];
cdbi_t hval;
struct cdb_rl *rl;
if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) ||
vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) {
errno = ENOMEM;
return -1;
}
hval = cdb_hash(key, klen);
rl = cdbmp->cdb_rec[hval&255];
if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) {
rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl));
if (!rl) {
errno = ENOMEM;
return -1;
}
rl->cnt = 0;
rl->next = cdbmp->cdb_rec[hval&255];
cdbmp->cdb_rec[hval&255] = rl;
}
rl->rec[rl->cnt].hval = hval;
rl->rec[rl->cnt].rpos = cdbmp->cdb_dpos;
++rl->cnt;
++cdbmp->cdb_rcnt;
cdb_pack(klen, rlen);
cdb_pack(vlen, rlen + 4);
if (make_write(cdbmp, rlen, 8) < 0 ||
make_write(cdbmp, key, klen) < 0 ||
make_write(cdbmp, val, vlen) < 0)
return -1;
return 0;
}
int
cdb_make_put(struct cdb_make *cdbmp,
const void *key, cdbi_t klen,
const void *val, cdbi_t vlen,
int flags)
{
unsigned char rlen[8];
cdbi_t hval = cdb_hash(key, klen);
struct cdb_rl *rl;
int c, r;
switch(flags) {
case CDB_PUT_REPLACE:
case CDB_PUT_INSERT:
case CDB_PUT_WARN:
c = make_find(cdbmp, key, klen, hval, &rl);
if (c < 0)
return -1;
if (c) {
if (flags == CDB_PUT_INSERT) {
errno = EEXIST;
return 1;
}
else if (flags == CDB_PUT_REPLACE) {
--c;
r = 1;
break;
}
else
r = 1;
}
/* fall */
case CDB_PUT_ADD:
rl = cdbmp->cdb_rec[hval&255];
if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) {
rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl));
if (!rl) {
errno = ENOMEM;
return -1;
}
rl->cnt = 0;
rl->next = cdbmp->cdb_rec[hval&255];
cdbmp->cdb_rec[hval&255] = rl;
}
c = rl->cnt;
r = 0;
break;
default:
errno = EINVAL;
return -1;
}
if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) ||
vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) {
errno = ENOMEM;
return -1;
}
rl->rec[c].hval = hval;
rl->rec[c].rpos = cdbmp->cdb_dpos;
if (c == rl->cnt) {
++rl->cnt;
++cdbmp->cdb_rcnt;
}
cdb_pack(klen, rlen);
cdb_pack(vlen, rlen + 4);
if (make_write(cdbmp, rlen, 8) < 0 ||
make_write(cdbmp, key, klen) < 0 ||
make_write(cdbmp, val, vlen) < 0)
return -1;
return r;
}
static int
match(int fd, cdbi_t pos, const char *key, cdbi_t klen)
{
unsigned char buf[64]; /*XXX cdb_buf may be used here instead */
if (lseek(fd, pos, SEEK_SET) < 0 || read(fd, buf, 8) != 8)
return -1;
if (cdb_unpack(buf) != klen)
return 0;
while(klen > sizeof(buf)) {
if (read(fd, buf, sizeof(buf)) != sizeof(buf))
return -1;
if (memcmp(buf, key, sizeof(buf)) != 0)
return 0;
key += sizeof(buf);
klen -= sizeof(buf);
}
if (klen) {
if (read(fd, buf, klen) != klen)
return -1;
if (memcmp(buf, key, klen) != 0)
return 0;
}
return 1;
}
static int
make_find (struct cdb_make *cdbmp,
const void *key, cdbi_t klen, cdbi_t hval,
struct cdb_rl **rlp)
{
struct cdb_rl *rl = cdbmp->cdb_rec[hval&255];
int r, i;
int seeked = 0;
while(rl) {
for(i = rl->cnt - 1; i >= 0; --i) { /* search backward */
if (rl->rec[i].hval != hval)
continue;
/*XXX this explicit flush may be unnecessary having
* smarter match() that looks to cdb_buf too, but
* most of a time here spent in finding hash values
* (above), not keys */
if (cdbmp->cdb_bpos != cdbmp->cdb_buf) {
if (write(cdbmp->cdb_fd, cdbmp->cdb_buf,
cdbmp->cdb_bpos - cdbmp->cdb_buf) < 0)
return -1;
cdbmp->cdb_bpos = cdbmp->cdb_buf;
}
seeked = 1;
r = match(cdbmp->cdb_fd, rl->rec[i].rpos, key, klen);
if (!r)
continue;
if (r < 0)
return -1;
if (lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0)
return -1;
if (rlp)
*rlp = rl;
return i + 1;
}
rl = rl->next;
}
if (seeked && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0)
return -1;
return 0;
}
int
cdb_make_exists(struct cdb_make *cdbmp,
const void *key, cdbi_t klen)
{
return make_find(cdbmp, key, klen, cdb_hash(key, klen), NULL);
}
void
cdb_pack(cdbi_t num, unsigned char buf[4])
{
buf[0] = num & 255; num >>= 8;
buf[1] = num & 255; num >>= 8;
buf[2] = num & 255;
buf[3] = num >> 8;
}
/* Initializes structure to create a database. File FD should be
opened read-write and should be seekable. Returns 0 on success or
negative value on error. */
int
cdb_make_start(struct cdb_make *cdbmp, int fd)
{
memset (cdbmp, 0, sizeof *cdbmp);
cdbmp->cdb_fd = fd;
cdbmp->cdb_dpos = 2048;
cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048;
return 0;
}
static int
ewrite(int fd, const char *buf, int len)
{
while(len) {
int l = write(fd, buf, len);
if (l < 0 && errno != EINTR)
return -1;
if (l > 0)
{
len -= l;
buf += l;
}
}
return 0;
}
static int
make_write(struct cdb_make *cdbmp, const char *ptr, cdbi_t len)
{
cdbi_t l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf);
cdbmp->cdb_dpos += len;
if (len > l) {
memcpy(cdbmp->cdb_bpos, ptr, l);
if (ewrite(cdbmp->cdb_fd, cdbmp->cdb_buf, sizeof(cdbmp->cdb_buf)) < 0)
return -1;
ptr += l; len -= l;
l = len / sizeof(cdbmp->cdb_buf);
if (l) {
l *= sizeof(cdbmp->cdb_buf);
if (ewrite(cdbmp->cdb_fd, ptr, l) < 0)
return -1;
ptr += l; len -= l;
}
cdbmp->cdb_bpos = cdbmp->cdb_buf;
}
if (len) {
memcpy(cdbmp->cdb_bpos, ptr, len);
cdbmp->cdb_bpos += len;
}
return 0;
}
static int
cdb_make_finish_internal(struct cdb_make *cdbmp)
{
cdbi_t hcnt[256]; /* hash table counts */
cdbi_t hpos[256]; /* hash table positions */
struct cdb_rec *htab;
unsigned char *p;
struct cdb_rl *rl;
cdbi_t hsize;
unsigned t, i;
if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt) {
errno = ENOMEM;
return -1;
}
/* count htab sizes and reorder reclists */
hsize = 0;
for (t = 0; t < 256; ++t) {
struct cdb_rl *rlt = NULL;
i = 0;
rl = cdbmp->cdb_rec[t];
while(rl) {
struct cdb_rl *rln = rl->next;
rl->next = rlt;
rlt = rl;
i += rl->cnt;
rl = rln;
}
cdbmp->cdb_rec[t] = rlt;
if (hsize < (hcnt[t] = i << 1))
hsize = hcnt[t];
}
/* allocate memory to hold max htable */
htab = (struct cdb_rec*)malloc((hsize + 2) * sizeof(struct cdb_rec));
if (!htab) {
errno = ENOENT;
return -1;
}
p = (unsigned char *)htab;
htab += 2;
/* build hash tables */
for (t = 0; t < 256; ++t) {
cdbi_t len, hi;
hpos[t] = cdbmp->cdb_dpos;
if ((len = hcnt[t]) == 0)
continue;
for (i = 0; i < len; ++i)
htab[i].hval = htab[i].rpos = 0;
for (rl = cdbmp->cdb_rec[t]; rl; rl = rl->next)
for (i = 0; i < rl->cnt; ++i) {
hi = (rl->rec[i].hval >> 8) % len;
while(htab[hi].rpos)
if (++hi == len)
hi = 0;
htab[hi] = rl->rec[i];
}
for (i = 0; i < len; ++i) {
cdb_pack(htab[i].hval, p + (i << 3));
cdb_pack(htab[i].rpos, p + (i << 3) + 4);
}
if (make_write(cdbmp, p, len << 3) < 0) {
free(p);
return -1;
}
}
free(p);
if (cdbmp->cdb_bpos != cdbmp->cdb_buf &&
ewrite(cdbmp->cdb_fd, cdbmp->cdb_buf,
cdbmp->cdb_bpos - cdbmp->cdb_buf) != 0)
return -1;
p = cdbmp->cdb_buf;
for (t = 0; t < 256; ++t) {
cdb_pack(hpos[t], p + (t << 3));
cdb_pack(hcnt[t], p + (t << 3) + 4);
}
if (lseek(cdbmp->cdb_fd, 0, 0) != 0 ||
ewrite(cdbmp->cdb_fd, p, 2048) != 0)
return -1;
return 0;
}
static void
cdb_make_free(struct cdb_make *cdbmp)
{
unsigned t;
for(t = 0; t < 256; ++t) {
struct cdb_rl *rl = cdbmp->cdb_rec[t];
while(rl) {
struct cdb_rl *tm = rl;
rl = rl->next;
free(tm);
}
}
}
/* Finalizes database file, constructing all needed indexes, and frees
memory structures. It does not close the file descriptor. Returns
0 on success or a negative value on error. */
int
cdb_make_finish(struct cdb_make *cdbmp)
{
int r = cdb_make_finish_internal(cdbmp);
cdb_make_free(cdbmp);
return r;
}
cdbi_t
cdb_hash(const void *buf, cdbi_t len)
{
register const unsigned char *p = (const unsigned char *)buf;
register const unsigned char *end = p + len;
register cdbi_t hash = 5381; /* start value */
while (p < end)
hash = (hash + (hash << 5)) ^ *p++;
return hash;
}

1384
dirmngr/certcache.c Normal file

File diff suppressed because it is too large Load Diff

103
dirmngr/certcache.h Normal file
View File

@ -0,0 +1,103 @@
/* certcache.h - Certificate caching
* Copyright (C) 2004, 2008 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef CERTCACHE_H
#define CERTCACHE_H
/* First time initialization of the certificate cache. */
void cert_cache_init (void);
/* Deinitialize the certificate cache. */
void cert_cache_deinit (int full);
/* Print some statistics to the log file. */
void cert_cache_print_stats (void);
/* Compute the fingerprint of the certificate CERT and put it into
the 20 bytes large buffer DIGEST. Return address of this buffer. */
unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest);
/* Put CERT into the certificate cache. */
gpg_error_t cache_cert (ksba_cert_t cert);
/* Put CERT into the certificate cache and return the fingerprint. */
gpg_error_t cache_cert_silent (ksba_cert_t cert, void *fpr_buffer);
/* Return 0 if the certificate is a trusted certificate. Returns
GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
case of systems errors. */
gpg_error_t is_trusted_cert (ksba_cert_t cert);
/* Return a certificate object for the given fingerprint. FPR is
expected to be a 20 byte binary SHA-1 fingerprint. If no matching
certificate is available in the cache NULL is returned. The caller
must release a returned certificate. */
ksba_cert_t get_cert_byfpr (const unsigned char *fpr);
/* Return a certificate object for the given fingerprint. STRING is
expected to be a SHA-1 fingerprint in standard hex notation with or
without colons. If no matching certificate is available in the
cache NULL is returned. The caller must release a returned
certificate. */
ksba_cert_t get_cert_byhexfpr (const char *string);
/* Return the certificate matching ISSUER_DN and SERIALNO. */
ksba_cert_t get_cert_bysn (const char *issuer_dn, ksba_sexp_t serialno);
/* Return the certificate matching ISSUER_DN. SEQ should initially be
set to 0 and bumped up to get the next issuer with that DN. */
ksba_cert_t get_cert_byissuer (const char *issuer_dn, unsigned int seq);
/* Return the certificate matching SUBJECT_DN. SEQ should initially be
set to 0 and bumped up to get the next issuer with that DN. */
ksba_cert_t get_cert_bysubject (const char *subject_dn, unsigned int seq);
/* Given PATTERN, which is a string as used by GnuPG to specify a
certificate, return all matching certificates by calling the
supplied function RETFNC. */
gpg_error_t get_certs_bypattern (const char *pattern,
gpg_error_t (*retfnc)(void*,ksba_cert_t),
void *retfnc_data);
/* Return the certificate matching ISSUER_DN and SERIALNO; if it is
not already in the cache, try to find it from other resources. */
ksba_cert_t find_cert_bysn (ctrl_t ctrl,
const char *issuer_dn, ksba_sexp_t serialno);
/* Return the certificate matching SUBJECT_DN and (if not NULL) KEYID. If
it is not already in the cache, try to find it from other
resources. Note, that the external search does not work for user
certificates because the LDAP lookup is on the caCertificate
attribute. For our purposes this is just fine. */
ksba_cert_t find_cert_bysubject (ctrl_t ctrl,
const char *subject_dn, ksba_sexp_t keyid);
/* Given the certificate CERT locate the issuer for this certificate
and return it at R_CERT. Returns 0 on success or
GPG_ERR_NOT_FOUND. */
gpg_error_t find_issuing_cert (ctrl_t ctrl,
ksba_cert_t cert, ksba_cert_t *r_cert);
#endif /*CERTCACHE_H*/

2544
dirmngr/crlcache.c Normal file

File diff suppressed because it is too large Load Diff

70
dirmngr/crlcache.h Normal file
View File

@ -0,0 +1,70 @@
/* crlcache.h - LDAP access
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef CRLCACHE_H
#define CRLCACHE_H
typedef enum
{
CRL_CACHE_VALID = 0,
CRL_CACHE_INVALID,
CRL_CACHE_DONTKNOW,
CRL_CACHE_CANTUSE
}
crl_cache_result_t;
typedef enum foo
{
CRL_SIG_OK = 0,
CRL_SIG_NOT_OK,
CRL_TOO_OLD,
CRL_SIG_ERROR,
CRL_GENERAL_ERROR
}
crl_sig_result_t;
struct crl_cache_entry_s;
typedef struct crl_cache_entry_s *crl_cache_entry_t;
void crl_cache_init (void);
void crl_cache_deinit (void);
int crl_cache_flush(void);
crl_cache_result_t crl_cache_isvalid (ctrl_t ctrl,
const char *issuer_hash,
const char *cert_id,
int force_refresh);
gpg_error_t crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
int force_refresh);
gpg_error_t crl_cache_insert (ctrl_t ctrl, const char *url,
ksba_reader_t reader);
gpg_error_t crl_cache_list (FILE* fp);
gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename);
gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
#endif /* CRLCACHE_H */

479
dirmngr/crlfetch.c Normal file
View File

@ -0,0 +1,479 @@
/* crlfetch.c - LDAP access
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
* Copyright (C) 2003, 2004, 2005, 2006, 2007 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <errno.h>
#include <pth.h>
#include "crlfetch.h"
#include "dirmngr.h"
#include "misc.h"
#include "http.h"
#include "estream.h"
/* For detecting armored CRLs received via HTTP (yes, such CRLS really
exits, e.g. http://grid.fzk.de/ca/gridka-crl.pem at least in June
2008) we need a context in the reader callback. */
struct reader_cb_context_s
{
estream_t fp; /* The stream used with the ksba reader. */
int checked:1; /* PEM/binary detection ahs been done. */
int is_pem:1; /* The file stream is PEM encoded. */
struct b64state b64state; /* The state used for Base64 decoding. */
};
/* We need to associate a reader object with the reader callback
context. This table is used for it. */
struct file_reader_map_s
{
ksba_reader_t reader;
struct reader_cb_context_s *cb_ctx;
};
#define MAX_FILE_READER 50
static struct file_reader_map_s file_reader_map[MAX_FILE_READER];
/* Associate FP with READER. If the table is full wait until another
thread has removed an entry. */
static void
register_file_reader (ksba_reader_t reader, struct reader_cb_context_s *cb_ctx)
{
int i;
for (;;)
{
for (i=0; i < MAX_FILE_READER; i++)
if (!file_reader_map[i].reader)
{
file_reader_map[i].reader = reader;
file_reader_map[i].cb_ctx = cb_ctx;
return;
}
log_info (_("reader to file mapping table full - waiting\n"));
pth_sleep (2);
}
}
/* Scan the table for an entry matching READER, remove that entry and
return the associated file pointer. */
static struct reader_cb_context_s *
get_file_reader (ksba_reader_t reader)
{
struct reader_cb_context_s *cb_ctx = NULL;
int i;
for (i=0; i < MAX_FILE_READER; i++)
if (file_reader_map[i].reader == reader)
{
cb_ctx = file_reader_map[i].cb_ctx;
file_reader_map[i].reader = NULL;
file_reader_map[i].cb_ctx = NULL;
break;
}
return cb_ctx;
}
static int
my_es_read (void *opaque, char *buffer, size_t nbytes, size_t *nread)
{
struct reader_cb_context_s *cb_ctx = opaque;
int result;
result = es_read (cb_ctx->fp, buffer, nbytes, nread);
if (result)
return result;
/* Fixme we should check whether the semantics of es_read are okay
and well defined. I have some doubts. */
if (nbytes && !*nread && es_feof (cb_ctx->fp))
return gpg_error (GPG_ERR_EOF);
if (!nread && es_ferror (cb_ctx->fp))
return gpg_error (GPG_ERR_EIO);
if (!cb_ctx->checked && *nread)
{
int c = *(unsigned char *)buffer;
cb_ctx->checked = 1;
if ( ((c & 0xc0) >> 6) == 0 /* class: universal */
&& (c & 0x1f) == 16 /* sequence */
&& (c & 0x20) /* is constructed */ )
; /* Binary data. */
else
{
cb_ctx->is_pem = 1;
b64dec_start (&cb_ctx->b64state, "");
}
}
if (cb_ctx->is_pem && *nread)
{
size_t nread2;
if (b64dec_proc (&cb_ctx->b64state, buffer, *nread, &nread2))
{
/* EOF from decoder. */
*nread = 0;
result = gpg_error (GPG_ERR_EOF);
}
else
*nread = nread2;
}
return result;
}
/* Fetch CRL from URL and return the entire CRL using new ksba reader
object in READER. Note that this reader object should be closed
only using ldap_close_reader. */
gpg_error_t
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. */
*reader = NULL;
once_more:
err = http_parse_uri (&uri, url);
http_release_parsed_uri (uri);
if (err && url && !strncmp (url, "https:", 6))
{
/* 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);
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"),
"HTTP");
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
}
else
err = http_open_document (&hd, url, NULL,
(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
|HTTP_FLAG_NEED_HEADER
|(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0),
opt.http_proxy, 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;
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. */
register_file_reader (*reader, cb_ctx);
http_close (hd, 1);
}
}
break;
case 301: /* Redirection (perm.). */
case 302: /* Redirection (temp.). */
{
const char *s = http_get_header (hd, "Location");
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 foer 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);
}
}
else /* Let the LDAP code try other schemes. */
{
if (opt.disable_ldap)
{
log_error (_("CRL access not possible due to disabled %s\n"),
"LDAP");
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
}
else
err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
}
xfree (free_this);
return err;
}
/* Fetch CRL for ISSUER using a default server. Return the entire CRL
as a newly opened stream returned in R_FP. */
gpg_error_t
crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
{
if (opt.disable_ldap)
{
log_error (_("CRL access not possible due to disabled %s\n"),
"LDAP");
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
reader);
}
/* Fetch a CA certificate for DN using the default server. This
function only initiates the fetch; fetch_next_cert must be used to
actually read the certificate; end_cert_fetch to end the
operation. */
gpg_error_t
ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
{
if (opt.disable_ldap)
{
log_error (_("CRL access not possible due to disabled %s\n"),
"LDAP");
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
}
gpg_error_t
start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
strlist_t patterns, const ldap_server_t server)
{
if (opt.disable_ldap)
{
log_error (_("certificate search not possible due to disabled %s\n"),
"LDAP");
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
return start_cert_fetch_ldap (ctrl, context, patterns, server);
}
gpg_error_t
fetch_next_cert (cert_fetch_context_t context,
unsigned char **value, size_t * valuelen)
{
return fetch_next_cert_ldap (context, value, valuelen);
}
/* Fetch the next data from CONTEXT, assuming it is a certificate and return
it as a cert object in R_CERT. */
gpg_error_t
fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
{
gpg_error_t err;
unsigned char *value;
size_t valuelen;
ksba_cert_t cert;
*r_cert = NULL;
err = fetch_next_cert_ldap (context, &value, &valuelen);
if (!err && !value)
err = gpg_error (GPG_ERR_BUG);
if (err)
return err;
err = ksba_cert_new (&cert);
if (err)
{
xfree (value);
return err;
}
err = ksba_cert_init_from_mem (cert, value, valuelen);
xfree (value);
if (err)
{
ksba_cert_release (cert);
return err;
}
*r_cert = cert;
return 0;
}
void
end_cert_fetch (cert_fetch_context_t context)
{
return end_cert_fetch_ldap (context);
}
/* Lookup a cert by it's URL. */
gpg_error_t
fetch_cert_by_url (ctrl_t ctrl, const char *url,
unsigned char **value, size_t *valuelen)
{
const unsigned char *cert_image;
size_t cert_image_n;
ksba_reader_t reader;
ksba_cert_t cert;
gpg_error_t err;
*value = NULL;
*valuelen = 0;
cert_image = NULL;
reader = NULL;
cert = NULL;
err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
if (err)
goto leave;
err = ksba_cert_new (&cert);
if (err)
goto leave;
err = ksba_cert_read_der (cert, reader);
if (err)
goto leave;
cert_image = ksba_cert_get_image (cert, &cert_image_n);
if (!cert_image || !cert_image_n)
{
err = gpg_error (GPG_ERR_INV_CERT_OBJ);
goto leave;
}
*value = xtrymalloc (cert_image_n);
if (!*value)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (*value, cert_image, cert_image_n);
*valuelen = cert_image_n;
leave:
ksba_cert_release (cert);
ldap_wrapper_release_context (reader);
return err;
}
/* This function is to be used to close the reader object. In
addition to running ksba_reader_release it also releases the LDAP
or HTTP contexts associated with that reader. */
void
crl_close_reader (ksba_reader_t reader)
{
struct reader_cb_context_s *cb_ctx;
if (!reader)
return;
/* Check whether this is a HTTP one. */
cb_ctx = get_file_reader (reader);
if (cb_ctx)
{
/* This is an HTTP context. */
if (cb_ctx->fp)
es_fclose (cb_ctx->fp);
/* Release the base64 decoder state. */
if (cb_ctx->is_pem)
b64dec_finish (&cb_ctx->b64state);
/* Release the callback context. */
xfree (cb_ctx);
}
else /* This is an ldap wrapper context (Currently not used). */
ldap_wrapper_release_context (reader);
/* Now get rid of the reader object. */
ksba_reader_release (reader);
}

93
dirmngr/crlfetch.h Normal file
View File

@ -0,0 +1,93 @@
/* crlfetch.h - LDAP access
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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 CRLFETCH_H
#define CRLFETCH_H
#include "dirmngr.h"
struct cert_fetch_context_s;
typedef struct cert_fetch_context_s *cert_fetch_context_t;
/* Fetch CRL from URL. */
gpg_error_t crl_fetch (ctrl_t ctrl, const char* url, ksba_reader_t *reader);
/* Fetch CRL for ISSUER using default server. */
gpg_error_t crl_fetch_default (ctrl_t ctrl,
const char* issuer, ksba_reader_t *reader);
/* Fetch cert for DN. */
gpg_error_t ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
const char *dn);
/* Query the server for certs matching patterns. */
gpg_error_t start_cert_fetch (ctrl_t ctrl,
cert_fetch_context_t *context,
strlist_t patterns,
const ldap_server_t server);
gpg_error_t fetch_next_cert(cert_fetch_context_t context,
unsigned char **value, size_t *valuelen);
gpg_error_t fetch_next_ksba_cert (cert_fetch_context_t context,
ksba_cert_t *r_cert);
void end_cert_fetch (cert_fetch_context_t context);
/* Lookup a cert by it's URL. */
gpg_error_t fetch_cert_by_url (ctrl_t ctrl, const char *url,
unsigned char **value, size_t *valuelen);
/* Close a reader object. */
void crl_close_reader (ksba_reader_t reader);
/*-- 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,
const char *url, const char *host, int port,
ksba_reader_t *reader);
gpg_error_t attr_fetch_ldap (ctrl_t ctrl,
const char *dn, const char *attr,
ksba_reader_t *reader);
gpg_error_t start_default_fetch_ldap (ctrl_t ctrl,
cert_fetch_context_t *context,
const char *dn, const char *attr);
gpg_error_t start_cert_fetch_ldap( ctrl_t ctrl,
cert_fetch_context_t *context,
strlist_t patterns,
const ldap_server_t server );
gpg_error_t fetch_next_cert_ldap (cert_fetch_context_t context,
unsigned char **value, size_t *valuelen );
void end_cert_fetch_ldap (cert_fetch_context_t context);
#endif /* CRLFETCH_H */

1042
dirmngr/dirmngr-client.c Normal file

File diff suppressed because it is too large Load Diff

1829
dirmngr/dirmngr.c Normal file

File diff suppressed because it is too large Load Diff

189
dirmngr/dirmngr.h Normal file
View File

@ -0,0 +1,189 @@
/* dirmngr.h - Common definitions for the dirmngr
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
* Copyright (C) 2004 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIRMNGR_H
#define DIRMNGR_H
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_DIRMNGR
#include <gpg-error.h>
#define map_assuan_err(a) \
map_assuan_err_with_source (GPG_ERR_SOURCE_DEFAULT, (a))
#include <errno.h>
#include <gcrypt.h>
#include <ksba.h>
#include "../common/util.h"
#include "../common/membuf.h"
#include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/i18n.h"
/* This objects keeps information about a particular LDAP server and
is used as item of a single linked list of servers. */
struct ldap_server_s
{
struct ldap_server_s* next;
char *host;
int port;
char *user;
char *pass;
char *base;
};
typedef struct ldap_server_s *ldap_server_t;
/* A list of fingerprints. */
struct fingerprint_list_s;
typedef struct fingerprint_list_s *fingerprint_list_t;
struct fingerprint_list_s
{
fingerprint_list_t next;
char hexfpr[20+20+1];
};
/* A large struct named "opt" to keep global flags. */
struct
{
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
int verbose; /* verbosity level */
int quiet; /* be as quiet as possible */
int dry_run; /* don't change any persistent data */
int batch; /* batch mode */
const char *homedir; /* Configuration directory name */
const char *homedir_data; /* Ditto for data files (/usr/share/dirmngr). */
const char *homedir_cache; /* Ditto for cache files (/var/cache/dirmngr). */
char *config_filename; /* Name of a config file, which will be
reread on a HUP if it is not NULL. */
char *ldap_wrapper_program; /* Override value for the LDAP wrapper
program. */
char *http_wrapper_program; /* Override value for the HTTP wrapper
program. */
int system_service; /* We are running as W32 service (implies daemon). */
int system_daemon; /* We are running in system daemon mode. */
int running_detached; /* We are running in detached mode. */
int force; /* Force loading outdated CRLs. */
int disable_http; /* Do not use HTTP at all. */
int disable_ldap; /* Do not use LDAP at all. */
int honor_http_proxy; /* Honor the http_proxy env variable. */
const char *http_proxy; /* Use given HTTP proxy. */
const char *ldap_proxy; /* Use given LDAP proxy. */
int only_ldap_proxy; /* Only use the LDAP proxy; no fallback. */
int ignore_http_dp; /* Ignore HTTP CRL distribution points. */
int ignore_ldap_dp; /* Ignore LDAP CRL distribution points. */
int ignore_ocsp_service_url; /* Ignore OCSP service URLs as given in
the certificate. */
/* A list of certificate extension OIDs which are ignored so that
one can claim that a critical extension has been handled. One
OID per string. */
strlist_t ignored_cert_extensions;
int allow_ocsp; /* Allow using OCSP. */
int max_replies;
unsigned int ldaptimeout;
ldap_server_t ldapservers;
int add_new_ldapservers;
const char *ocsp_responder; /* Standard OCSP responder's URL. */
fingerprint_list_t ocsp_signer; /* The list of fingerprints with allowed
standard OCSP signer certificates. */
unsigned int ocsp_max_clock_skew; /* Allowed seconds of clocks skew. */
unsigned int ocsp_max_period; /* Seconds a response is at maximum
considered valid after thisUpdate. */
unsigned int ocsp_current_period; /* Seconds a response is considered
current after nextUpdate. */
} opt;
#define DBG_X509_VALUE 1 /* debug x.509 parsing */
#define DBG_LOOKUP_VALUE 2 /* debug lookup details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
#define DBG_ASSUAN_VALUE 1024 /* debug assuan communication */
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
/* A simple list of certificate references. */
struct cert_ref_s
{
struct cert_ref_s *next;
unsigned char fpr[20];
};
typedef struct cert_ref_s *cert_ref_t;
/* Forward references; access only through server.c. */
struct server_local_s;
/* Connection control structure. */
struct server_control_s
{
int refcount; /* Count additional references to this object. */
int no_server; /* We are not running under server control. */
int status_fd; /* Only for non-server mode. */
struct server_local_s *server_local;
int force_crl_refresh; /* Always load a fresh CRL. */
int check_revocations_nest_level; /* Internal to check_revovations. */
cert_ref_t ocsp_certs; /* Certificates from the current OCSP
response. */
int audit_events; /* Send audit events to client. */
};
/*-- dirmngr.c --*/
void dirmngr_exit( int ); /* Wrapper for exit() */
void dirmngr_init_default_ctrl (ctrl_t ctrl);
/*-- server.c --*/
ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer);
ksba_cert_t get_issuing_cert_local (ctrl_t ctrl, const char *issuer);
ksba_cert_t get_cert_local_ski (ctrl_t ctrl,
const char *name, ksba_sexp_t keyid);
gpg_error_t get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr);
void start_command_handler (gnupg_fd_t fd);
gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...);
gpg_error_t dirmngr_tick (ctrl_t ctrl);
#endif /*DIRMNGR_H*/

646
dirmngr/dirmngr_ldap.c Normal file
View File

@ -0,0 +1,646 @@
/* dirmngr-ldap.c - The LDAP helper for dirmngr.
* Copyright (C) 2004 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include <unistd.h>
#ifdef HAVE_W32_SYSTEM
#include <winsock2.h>
#include <winldap.h>
#include <fcntl.h>
#include "ldap-url.h"
#else
/* For OpenLDAP, to enable the API that we're using. */
#define LDAP_DEPRECATED 1
#include <ldap.h>
#endif
#define JNLIB_NEED_LOG_LOGV
#include "../common/logging.h"
#include "../common/argparse.h"
#include "../common/stringhelp.h"
#include "../common/mischelp.h"
#include "../common/strlist.h"
#include "i18n.h"
#include "util.h"
#define DEFAULT_LDAP_TIMEOUT 100 /* Arbitrary long timeout. */
/* Constants for the options. */
enum
{
oQuiet = 'q',
oVerbose = 'v',
oTimeout = 500,
oMulti,
oProxy,
oHost,
oPort,
oUser,
oPass,
oEnvPass,
oDN,
oFilter,
oAttr,
oOnlySearchTimeout,
oLogWithPID
};
/* The list of options as used by the argparse.c code. */
static ARGPARSE_OPTS opts[] = {
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
{ oTimeout, "timeout", 1, N_("|N|set LDAP timeout to N seconds")},
{ oMulti, "multi", 0, N_("return all values in"
" a record oriented format")},
{ oProxy, "proxy", 2,
N_("|NAME|ignore host part and connect through NAME")},
{ oHost, "host", 2, N_("|NAME|connect to host NAME")},
{ oPort, "port", 1, N_("|N|connect to port N")},
{ oUser, "user", 2, N_("|NAME|use user NAME for authentication")},
{ oPass, "pass", 2, N_("|PASS|use password PASS"
" for authentication")},
{ oEnvPass, "env-pass", 0, N_("take password from $DIRMNGR_LDAP_PASS")},
{ oDN, "dn", 2, N_("|STRING|query DN STRING")},
{ oFilter, "filter", 2, N_("|STRING|use STRING as filter expression")},
{ oAttr, "attr", 2, N_("|STRING|return the attribute STRING")},
{ oOnlySearchTimeout, "only-search-timeout", 0, "@"},
{ oLogWithPID,"log-with-pid", 0, "@"},
{ 0, NULL, 0, NULL }
};
/* The usual structure for the program flags. */
static struct
{
int quiet;
int verbose;
struct timeval timeout; /* Timeout for the LDAP search functions. */
unsigned int alarm_timeout; /* And for the alarm based timeout. */
int multi;
/* Note that we can't use const for the strings because ldap_* are
not defined that way. */
char *proxy; /* Host and Port override. */
char *user; /* Authentication user. */
char *pass; /* Authentication password. */
char *host; /* Override host. */
int port; /* Override port. */
char *dn; /* Override DN. */
char *filter;/* Override filter. */
char *attr; /* Override attribute. */
} opt;
/* Prototypes. */
static void catch_alarm (int dummy);
static int process_url (const char *url);
/* Function called by argparse.c to display information. */
static const char *
my_strusage (int level)
{
const char *p;
switch(level)
{
case 11: p = "dirmngr_ldap (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
case 49: p = PACKAGE_BUGREPORT; break;
case 1:
case 40: p =
_("Usage: dirmngr_ldap [options] [URL] (-h for help)\n");
break;
case 41: p =
_("Syntax: dirmngr_ldap [options] [URL]\n"
"Internal LDAP helper for Dirmngr.\n"
"Interface and options may change without notice.\n");
break;
default: p = NULL;
}
return p;
}
static void
my_i18n_init (void)
{
#warning Better use common init functions
#ifdef USE_SIMPLE_GETTEXT
set_gettext_file (PACKAGE);
#else
# ifdef ENABLE_NLS
setlocale (LC_ALL, "" );
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
# endif
#endif
}
int
main (int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int any_err = 0;
char *p;
int only_search_timeout = 0;
#ifdef HAVE_W32_SYSTEM
/* Yeah, right. Sigh. */
_setmode (_fileno (stdout), _O_BINARY);
#endif
set_strusage (my_strusage);
log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX);
/* Setup I18N. */
my_i18n_init();
/* LDAP defaults */
opt.timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
opt.timeout.tv_usec = 0;
opt.alarm_timeout = 0;
/* Parse the command line. */
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* Do not remove the args. */
while (arg_parse (&pargs, opts) )
{
switch (pargs.r_opt)
{
case oVerbose: opt.verbose++; break;
case oQuiet: opt.quiet++; break;
case oTimeout:
opt.timeout.tv_sec = pargs.r.ret_int;
opt.timeout.tv_usec = 0;
opt.alarm_timeout = pargs.r.ret_int;
break;
case oOnlySearchTimeout: only_search_timeout = 1; break;
case oMulti: opt.multi = 1; break;
case oUser: opt.user = pargs.r.ret_str; break;
case oPass: opt.pass = pargs.r.ret_str; break;
case oEnvPass:
opt.pass = getenv ("DIRMNGR_LDAP_PASS");
break;
case oProxy: opt.proxy = pargs.r.ret_str; break;
case oHost: opt.host = pargs.r.ret_str; break;
case oPort: opt.port = pargs.r.ret_int; break;
case oDN: opt.dn = pargs.r.ret_str; break;
case oFilter: opt.filter = pargs.r.ret_str; break;
case oAttr: opt.attr = pargs.r.ret_str; break;
case oLogWithPID:
{
unsigned int oldflags;
log_get_prefix (&oldflags);
log_set_prefix (NULL, oldflags | JNLIB_LOG_WITH_PID);
}
break;
default : pargs.err = 2; break;
}
}
if (only_search_timeout)
opt.alarm_timeout = 0;
if (opt.proxy)
{
opt.host = xstrdup (opt.proxy);
p = strchr (opt.host, ':');
if (p)
{
*p++ = 0;
opt.port = atoi (p);
}
if (!opt.port)
opt.port = 389; /* make sure ports gets overridden. */
}
if (opt.port < 0 || opt.port > 65535)
log_error (_("invalid port number %d\n"), opt.port);
if (log_get_errorcount (0))
exit (2);
if (argc < 1)
usage (1);
if (opt.alarm_timeout)
{
#ifndef HAVE_W32_SYSTEM
# if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
struct sigaction act;
act.sa_handler = catch_alarm;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
if (sigaction (SIGALRM,&act,NULL))
# else
if (signal (SIGALRM, catch_alarm) == SIG_ERR)
# endif
log_fatal ("unable to register timeout handler\n");
#endif
}
for (; argc; argc--, argv++)
if (process_url (*argv))
any_err = 1;
return any_err;
}
static void
catch_alarm (int dummy)
{
(void)dummy;
_exit (10);
}
static void
set_timeout (void)
{
#ifndef HAVE_W32_SYSTEM
/* FIXME for W32. */
if (opt.alarm_timeout)
alarm (opt.alarm_timeout);
#endif
}
/* Helper for fetch_ldap(). */
static int
print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
{
LDAPMessage *item;
int any = 0;
for (item = ldap_first_entry (ld, msg); item;
item = ldap_next_entry (ld, item))
{
BerElement *berctx;
char *attr;
if (opt.verbose > 1)
log_info (_("scanning result for attribute `%s'\n"),
want_attr? want_attr : "[all]");
if (opt.multi)
{ /* Write item marker. */
if (fwrite ("I\0\0\0\0", 5, 1, stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
return -1;
}
}
for (attr = ldap_first_attribute (ld, item, &berctx); attr;
attr = ldap_next_attribute (ld, item, berctx))
{
struct berval **values;
int idx;
if (opt.verbose > 1)
log_info (_(" available attribute `%s'\n"), attr);
set_timeout ();
/* I case we want only one attribute we do a case
insensitive compare without the optional extension
(i.e. ";binary"). Case insensitive is not really correct
but the best we can do. */
if (want_attr)
{
char *cp1, *cp2;
int cmpres;
cp1 = strchr (want_attr, ';');
if (cp1)
*cp1 = 0;
cp2 = strchr (attr, ';');
if (cp2)
*cp2 = 0;
cmpres = ascii_strcasecmp (want_attr, attr);
if (cp1)
*cp1 = ';';
if (cp2)
*cp2 = ';';
if (cmpres)
{
ldap_memfree (attr);
continue; /* Not found: Try next attribute. */
}
}
values = ldap_get_values_len (ld, item, attr);
if (!values)
{
if (opt.verbose)
log_info (_("attribute `%s' not found\n"), attr);
ldap_memfree (attr);
continue;
}
if (opt.verbose)
{
log_info (_("found attribute `%s'\n"), attr);
if (opt.verbose > 1)
for (idx=0; values[idx]; idx++)
log_info (" length[%d]=%d\n",
idx, (int)values[0]->bv_len);
}
if (opt.multi)
{ /* Write attribute marker. */
unsigned char tmp[5];
size_t n = strlen (attr);
tmp[0] = 'A';
tmp[1] = (n >> 24);
tmp[2] = (n >> 16);
tmp[3] = (n >> 8);
tmp[4] = (n);
if (fwrite (tmp, 5, 1, stdout) != 1
|| fwrite (attr, n, 1, stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
ldap_value_free_len (values);
ldap_memfree (attr);
ber_free (berctx, 0);
return -1;
}
}
for (idx=0; values[idx]; idx++)
{
if (opt.multi)
{ /* Write value marker. */
unsigned char tmp[5];
size_t n = values[0]->bv_len;
tmp[0] = 'V';
tmp[1] = (n >> 24);
tmp[2] = (n >> 16);
tmp[3] = (n >> 8);
tmp[4] = (n);
if (fwrite (tmp, 5, 1, stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
ldap_value_free_len (values);
ldap_memfree (attr);
ber_free (berctx, 0);
return -1;
}
}
#if 1
/* Note: this does not work for STDOUT on a Windows
console, where it fails with "Not enough space" for
CRLs which are 52 KB or larger. */
if (fwrite (values[0]->bv_val, values[0]->bv_len,
1, stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
ldap_value_free_len (values);
ldap_memfree (attr);
ber_free (berctx, 0);
return -1;
}
#else
/* On Windows console STDOUT, we have to break up the
writes into small parts. */
{
int n = 0;
while (n < values[0]->bv_len)
{
int cnt = values[0]->bv_len - n;
/* The actual limit is (52 * 1024 - 1) on Windows XP SP2. */
#define MAX_CNT (32*1024)
if (cnt > MAX_CNT)
cnt = MAX_CNT;
if (fwrite (((char *) values[0]->bv_val) + n, cnt, 1,
stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
ldap_value_free_len (values);
ldap_memfree (attr);
ber_free (berctx, 0);
return -1;
}
n += cnt;
}
}
#endif
any = 1;
if (!opt.multi)
break; /* Print only the first value. */
}
ldap_value_free_len (values);
ldap_memfree (attr);
if (want_attr || !opt.multi)
break; /* We only want to return the first attribute. */
}
ber_free (berctx, 0);
}
if (opt.verbose > 1 && any)
log_info ("result has been printed\n");
return any?0:-1;
}
/* Helper for the URL based LDAP query. */
static int
fetch_ldap (const char *url, const LDAPURLDesc *ludp)
{
LDAP *ld;
LDAPMessage *msg;
int rc = 0;
char *host, *dn, *filter, *attrs[2], *attr;
int port;
host = opt.host? opt.host : ludp->lud_host;
port = opt.port? opt.port : ludp->lud_port;
dn = opt.dn? opt.dn : ludp->lud_dn;
filter = opt.filter? opt.filter : ludp->lud_filter;
attrs[0] = opt.attr? opt.attr : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
attrs[1] = NULL;
attr = attrs[0];
if (!port)
port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 636:389;
if (opt.verbose)
{
log_info (_("processing url `%s'\n"), url);
if (opt.user)
log_info (_(" user `%s'\n"), opt.user);
if (opt.pass)
log_info (_(" pass `%s'\n"), *opt.pass?"*****":"");
if (host)
log_info (_(" host `%s'\n"), host);
log_info (_(" port %d\n"), port);
if (dn)
log_info (_(" DN `%s'\n"), dn);
if (filter)
log_info (_(" filter `%s'\n"), filter);
if (opt.multi && !opt.attr && ludp->lud_attrs)
{
int i;
for (i=0; ludp->lud_attrs[i]; i++)
log_info (_(" attr `%s'\n"), ludp->lud_attrs[i]);
}
else if (attr)
log_info (_(" attr `%s'\n"), attr);
}
if (!host || !*host)
{
log_error (_("no host name in `%s'\n"), url);
return -1;
}
if (!opt.multi && !attr)
{
log_error (_("no attribute given for query `%s'\n"), url);
return -1;
}
if (!opt.multi && !opt.attr
&& ludp->lud_attrs && ludp->lud_attrs[0] && ludp->lud_attrs[1])
log_info (_("WARNING: using first attribute only\n"));
set_timeout ();
ld = ldap_init (host, port);
if (!ld)
{
log_error (_("LDAP init to `%s:%d' failed: %s\n"),
host, port, strerror (errno));
return -1;
}
if (ldap_simple_bind_s (ld, opt.user, opt.pass))
{
log_error (_("binding to `%s:%d' failed: %s\n"),
host, port, strerror (errno));
/* FIXME: Need deinit (ld)? */
return -1;
}
set_timeout ();
rc = ldap_search_st (ld, dn, ludp->lud_scope, filter,
opt.multi && !opt.attr && ludp->lud_attrs?
ludp->lud_attrs:attrs,
0,
&opt.timeout, &msg);
if (rc == LDAP_SIZELIMIT_EXCEEDED && opt.multi)
{
if (fwrite ("E\0\0\0\x09truncated", 14, 1, stdout) != 1)
{
log_error (_("error writing to stdout: %s\n"),
strerror (errno));
return -1;
}
}
else if (rc)
{
log_error (_("searching `%s' failed: %s\n"),
url, ldap_err2string (rc));
if (rc != LDAP_NO_SUCH_OBJECT)
{
/* FIXME: Need deinit (ld)? */
/* Hmmm: Do we need to released MSG in case of an error? */
return -1;
}
}
rc = print_ldap_entries (ld, msg, opt.multi? NULL:attr);
ldap_msgfree (msg);
/* FIXME: Need deinit (ld)? */
return rc;
}
/* Main processing. Take the URL and run the LDAP query. The result
is printed to stdout, errors are logged to the log stream. */
static int
process_url (const char *url)
{
int rc;
LDAPURLDesc *ludp = NULL;
if (!ldap_is_ldap_url (url))
{
log_error (_("`%s' is not an LDAP URL\n"), url);
return -1;
}
if (ldap_url_parse (url, &ludp))
{
log_error (_("`%s' is an invalid LDAP URL\n"), url);
return -1;
}
rc = fetch_ldap (url, ludp);
ldap_free_urldesc (ludp);
return rc;
}

620
dirmngr/get-path.c Normal file
View File

@ -0,0 +1,620 @@
/* get-path.c - Utility functions for the W32 API
Copyright (C) 1999 Free Software Foundation, Inc
Copyright (C) 2001 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
This file is part of DirMngr.
DirMngr 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 2 of the License, or
(at your option) any later version.
DirMngr 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA */
#error Code has been replaced by common/homedir.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#include <shlobj.h>
#include <io.h>
#endif
#include "util.h"
#ifdef HAVE_W32_SYSTEM
#define GNUPG_DEFAULT_HOMEDIR "c:/gnupg"
#elif defined(__VMS)
#define GNUPG_DEFAULT_HOMEDIR "/SYS\$LOGIN/gnupg"
#else
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
#endif
#ifdef HAVE_DOSISH_SYSTEM
#define DIRSEP_C '\\'
#define DIRSEP_S "\\"
#else
#define DIRSEP_C '/'
#define DIRSEP_S "/"
#endif
#ifdef HAVE_W32_SYSTEM
#define RTLD_LAZY 0
static __inline__ void *
dlopen (const char * name, int flag)
{
void * hd = LoadLibrary (name);
return hd;
}
static __inline__ void *
dlsym (void * hd, const char * sym)
{
if (hd && sym)
{
void * fnc = GetProcAddress (hd, sym);
if (!fnc)
return NULL;
return fnc;
}
return NULL;
}
static __inline__ int
dlclose (void * hd)
{
if (hd)
{
FreeLibrary (hd);
return 0;
}
return -1;
}
/* Return a string from the W32 Registry or NULL in case of error.
Caller must release the return value. A NULL for root is an alias
for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
static char *
read_w32_registry_string (const char *root, const char *dir, const char *name)
{
HKEY root_key, key_handle;
DWORD n1, nbytes, type;
char *result = NULL;
if ( !root )
root_key = HKEY_CURRENT_USER;
else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
root_key = HKEY_CLASSES_ROOT;
else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
root_key = HKEY_CURRENT_USER;
else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
root_key = HKEY_LOCAL_MACHINE;
else if ( !strcmp( root, "HKEY_USERS" ) )
root_key = HKEY_USERS;
else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
root_key = HKEY_PERFORMANCE_DATA;
else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
root_key = HKEY_CURRENT_CONFIG;
else
return NULL;
if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) )
{
if (root)
return NULL; /* no need for a RegClose, so return direct */
/* It seems to be common practise to fall back to HKLM. */
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
return NULL; /* still no need for a RegClose, so return direct */
}
nbytes = 1;
if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
{
if (root)
goto leave;
/* Try to fallback to HKLM also vor a missing value. */
RegCloseKey (key_handle);
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
return NULL; /* Nope. */
if (RegQueryValueEx ( key_handle, name, 0, NULL, NULL, &nbytes))
goto leave;
}
result = malloc ( (n1=nbytes+1) );
if ( !result )
goto leave;
if ( RegQueryValueEx ( key_handle, name, 0, &type, result, &n1 ) )
{
free(result); result = NULL;
goto leave;
}
result[nbytes] = 0; /* Make sure it is really a string. */
if (type == REG_EXPAND_SZ && strchr (result, '%'))
{
char *tmp;
n1 += 1000;
tmp = malloc (n1+1);
if (!tmp)
goto leave;
nbytes = ExpandEnvironmentStrings (result, tmp, n1);
if (nbytes && nbytes > n1)
{
free (tmp);
n1 = nbytes;
tmp = malloc (n1 + 1);
if (!tmp)
goto leave;
nbytes = ExpandEnvironmentStrings (result, tmp, n1);
if (nbytes && nbytes > n1) {
free (tmp); /* Oops - truncated, better don't expand at all. */
goto leave;
}
tmp[nbytes] = 0;
free (result);
result = tmp;
}
else if (nbytes) /* Okay, reduce the length. */
{
tmp[nbytes] = 0;
free (result);
result = malloc (strlen (tmp)+1);
if (!result)
result = tmp;
else
{
strcpy (result, tmp);
free (tmp);
}
}
else /* Error - don't expand. */
{
free (tmp);
}
}
leave:
RegCloseKey( key_handle );
return result;
}
/* This is a helper function to load and run a Windows function from
either of one DLLs. */
static HRESULT
w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
{
static int initialized;
static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
if (!initialized)
{
static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
void *handle;
int i;
initialized = 1;
for (i=0, handle = NULL; !handle && dllnames[i]; i++)
{
handle = dlopen (dllnames[i], RTLD_LAZY);
if (handle)
{
func = dlsym (handle, "SHGetFolderPathA");
if (!func)
{
dlclose (handle);
handle = NULL;
}
}
}
}
if (func)
return func (a,b,c,d,e);
else
return -1;
}
#if 0
static char *
find_program_in_inst_dir (const char *name)
{
char *result = NULL;
char *tmp;
tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
"Software\\GNU\\GnuPG",
"Install Directory");
if (!tmp)
return NULL;
result = malloc (strlen (tmp) + 1 + strlen (name) + 1);
if (!result)
{
free (tmp);
return NULL;
}
strcpy (stpcpy (stpcpy (result, tmp), "\\"), name);
free (tmp);
if (access (result, F_OK))
{
free (result);
return NULL;
}
return result;
}
static char *
find_program_at_standard_place (const char *name)
{
char path[MAX_PATH];
char *result = NULL;
if (w32_shgetfolderpath (NULL, CSIDL_PROGRAM_FILES, NULL, 0, path) >= 0)
{
result = malloc (strlen (path) + 1 + strlen (name) + 1);
if (result)
{
strcpy (stpcpy (stpcpy (result, path), "\\"), name);
if (access (result, F_OK))
{
free (result);
result = NULL;
}
}
}
return result;
}
#endif
#endif
const char *
get_dirmngr_ldap_path (void)
{
static char *pgmname;
#ifdef HAVE_W32_SYSTEM
if (! pgmname)
{
const char *dir = dirmngr_libexecdir ();
const char *exe = "\\dirmngr_ldap.exe";
pgmname = malloc (strlen (dir) + strlen (exe) + 1);
if (pgmname)
strcpy (stpcpy (pgmname, dir), exe);
}
#endif
if (!pgmname)
pgmname = DIRMNGR_LIBEXECDIR "/dirmngr_ldap";
return pgmname;
}
/* Home directory. */
#ifdef HAVE_W32_SYSTEM
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_COMMON_APPDATA
#define CSIDL_COMMON_APPDATA 0x0023
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE 0x8000
#endif
#endif /*HAVE_W32_SYSTEM*/
/* Get the standard home directory. In general this function should
not be used as it does not consider a registry value (under W32) or
the GNUPGHOME environment variable. It is better to use
default_homedir(). */
const char *
standard_homedir (void)
{
#ifdef HAVE_W32_SYSTEM
static const char *dir;
if (!dir)
{
char path[MAX_PATH];
/* It might be better to use LOCAL_APPDATA because this is
defined as "non roaming" and thus more likely to be kept
locally. For private keys this is desired. However, given
that many users copy private keys anyway forth and back,
using a system roaming services might be better than to let
them do it manually. A security conscious user will anyway
use the registry entry to have better control. */
if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
NULL, 0, path) >= 0)
{
char *tmp = xmalloc (strlen (path) + 6 +1);
strcpy (stpcpy (tmp, path), "\\gnupg");
dir = tmp;
/* Try to create the directory if it does not yet exists. */
if (access (dir, F_OK))
CreateDirectory (dir, NULL);
}
else
dir = GNUPG_DEFAULT_HOMEDIR;
}
return dir;
#else/*!HAVE_W32_SYSTEM*/
return GNUPG_DEFAULT_HOMEDIR;
#endif /*!HAVE_W32_SYSTEM*/
}
/* Set up the default home directory. The usual --homedir option
should be parsed later. */
const char *
default_homedir (void)
{
const char *dir;
dir = getenv ("GNUPGHOME");
#ifdef HAVE_W32_SYSTEM
if (!dir || !*dir)
{
static const char *saved_dir;
if (!saved_dir)
{
if (!dir || !*dir)
{
char *tmp;
tmp = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG",
"HomeDir");
if (tmp && *tmp)
{
xfree (tmp);
tmp = NULL;
}
if (tmp)
saved_dir = tmp;
}
if (!saved_dir)
saved_dir = standard_homedir ();
}
dir = saved_dir;
}
#endif /*HAVE_W32_SYSTEM*/
if (!dir || !*dir)
dir = GNUPG_DEFAULT_HOMEDIR;
return dir;
}
#ifdef HAVE_W32_SYSTEM
static const char *
w32_rootdir (void)
{
static int got_dir;
static char dir[MAX_PATH+5];
if (!got_dir)
{
char *p;
if ( !GetModuleFileName ( NULL, dir, MAX_PATH) )
{
log_debug ("GetModuleFileName failed: %s\n", w32_strerror (0));
*dir = 0;
}
got_dir = 1;
p = strrchr (dir, DIRSEP_C);
if (p)
*p = 0;
else
{
log_debug ("bad filename `%s' returned for this process\n", dir);
*dir = 0;
}
}
if (*dir)
return dir;
/* Fallback to the hardwired value. */
return DIRMNGR_LIBEXECDIR;
}
static const char *
w32_commondir (void)
{
static char *dir;
if (!dir)
{
char path[MAX_PATH];
if (w32_shgetfolderpath (NULL, CSIDL_COMMON_APPDATA,
NULL, 0, path) >= 0)
{
char *tmp = xmalloc (strlen (path) + 4 +1);
strcpy (stpcpy (tmp, path), "\\GNU");
dir = tmp;
/* No auto create of the directory. Either the installer or
the admin has to create these directories. */
}
else
{
/* Ooops: Not defined - probably an old Windows version.
Use the installation directory instead. */
dir = xstrdup (w32_rootdir ());
}
}
return dir;
}
#endif /*HAVE_W32_SYSTEM*/
/* Return the name of the sysconfdir. This is a static string. This
function is required because under Windows we can't simply compile
it in. */
const char *
dirmngr_sysconfdir (void)
{
#ifdef HAVE_W32_SYSTEM
static char *name;
if (!name)
{
const char *s1, *s2;
s1 = w32_commondir ();
s2 = DIRSEP_S "etc" DIRSEP_S "dirmngr";
name = xmalloc (strlen (s1) + strlen (s2) + 1);
strcpy (stpcpy (name, s1), s2);
}
return name;
#else /*!HAVE_W32_SYSTEM*/
return DIRMNGR_SYSCONFDIR;
#endif /*!HAVE_W32_SYSTEM*/
}
/* Return the name of the libexec directory. The name is allocated in
a static area on the first use. This function won't fail. */
const char *
dirmngr_libexecdir (void)
{
#ifdef HAVE_W32_SYSTEM
return w32_rootdir ();
#else /*!HAVE_W32_SYSTEM*/
return DIRMNGR_LIBEXECDIR;
#endif /*!HAVE_W32_SYSTEM*/
}
const char *
dirmngr_datadir (void)
{
#ifdef HAVE_W32_SYSTEM
static char *name;
if (!name)
{
const char *s1, *s2;
s1 = w32_commondir ();
s2 = DIRSEP_S "lib" DIRSEP_S "dirmngr";
name = xmalloc (strlen (s1) + strlen (s2) + 1);
strcpy (stpcpy (name, s1), s2);
}
return name;
#else /*!HAVE_W32_SYSTEM*/
return DIRMNGR_DATADIR;
#endif /*!HAVE_W32_SYSTEM*/
}
const char *
dirmngr_cachedir (void)
{
#ifdef HAVE_W32_SYSTEM
static const char *dir;
if (!dir)
{
char path[MAX_PATH];
const char *s1[] = { "GNU", "cache", "dirmngr", NULL };
int s1_len;
const char **comp;
s1_len = 0;
for (comp = s1; *comp; comp++)
{
/* Take account for the separator. */
s1_len += 1 + strlen (*comp);
}
if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
NULL, 0, path) >= 0)
{
char *tmp = xmalloc (strlen (path) + s1_len + 1);
char *p;
p = stpcpy (tmp, path);
for (comp = s1; *comp; comp++)
{
p = stpcpy (p, "\\");
p = stpcpy (p, *comp);
if (access (tmp, F_OK))
CreateDirectory (tmp, NULL);
}
dir = tmp;
}
else
dir = "c:\\temp\\cache\\dirmngr";
}
return dir;
#else /*!HAVE_W32_SYSTEM*/
return DIRMNGR_CACHEDIR;
#endif /*!HAVE_W32_SYSTEM*/
}
const char *
default_socket_name (void)
{
#ifdef HAVE_W32_SYSTEM
static char *name;
if (!name)
{
char s1[MAX_PATH];
const char *s2;
/* We need something akin CSIDL_COMMON_PROGRAMS, but local
(non-roaming). This is becuase the file needs to be on the
local machine and makes only sense on that machine.
CSIDL_WINDOWS seems to be the only location which guarantees
that. */
if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0)
strcpy (s1, "C:\\WINDOWS");
s2 = DIRSEP_S "S.dirmngr";
name = xmalloc (strlen (s1) + strlen (s2) + 1);
strcpy (stpcpy (name, s1), s2);
}
return name;
#else /*!HAVE_W32_SYSTEM*/
return DIRMNGR_SOCKETDIR "/socket";
#endif /*!HAVE_W32_SYSTEM*/
}

1861
dirmngr/http.c Normal file

File diff suppressed because it is too large Load Diff

109
dirmngr/http.h Normal file
View File

@ -0,0 +1,109 @@
/* http.h - HTTP protocol handler
* Copyright (C) 1999, 2000, 2001, 2003,
* 2006 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifndef GNUPG_COMMON_HTTP_H
#define GNUPG_COMMON_HTTP_H
#include <gpg-error.h>
#include "estream.h"
struct uri_tuple_s {
struct uri_tuple_s *next;
const char *name; /* A pointer into name. */
char *value; /* A pointer to value (a Nul is always appended). */
size_t valuelen; /* The real length of the value; we need it
because the value may contain embedded Nuls. */
int no_value; /* True if no value has been given in the URL. */
};
typedef struct uri_tuple_s *uri_tuple_t;
struct parsed_uri_s
{
/* All these pointers point into BUFFER; most stuff is not escaped. */
char *scheme; /* Pointer to the scheme string (lowercase). */
int use_tls; /* Whether TLS should be used. */
char *auth; /* username/password for basic auth */
char *host; /* Host (converted to lowercase). */
unsigned short port; /* Port (always set if the host is set). */
char *path; /* Path. */
uri_tuple_t params; /* ";xxxxx" */
uri_tuple_t query; /* "?xxx=yyy" */
char buffer[1]; /* Buffer which holds a (modified) copy of the URI. */
};
typedef struct parsed_uri_s *parsed_uri_t;
typedef enum
{
HTTP_REQ_GET = 1,
HTTP_REQ_HEAD = 2,
HTTP_REQ_POST = 3
}
http_req_t;
/* We put the flag values into an enum, so that gdb can display them. */
enum
{
HTTP_FLAG_TRY_PROXY = 1,
HTTP_FLAG_SHUTDOWN = 2,
HTTP_FLAG_TRY_SRV = 4,
HTTP_FLAG_LOG_RESP = 8,
HTTP_FLAG_NEED_HEADER = 16,
HTTP_FLAG_IGNORE_CL = 32
};
struct http_context_s;
typedef struct http_context_s *http_t;
void http_register_tls_callback (gpg_error_t (*cb) (http_t, void *, int));
gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri);
void http_release_parsed_uri (parsed_uri_t uri);
gpg_error_t http_open (http_t *r_hd, http_req_t reqtype,
const char *url,
const char *auth,
unsigned int flags,
const char *proxy,
void *tls_context);
void http_start_data (http_t hd);
gpg_error_t http_wait_response (http_t hd);
void http_close (http_t hd, int keep_read_stream);
gpg_error_t http_open_document (http_t *r_hd,
const char *document,
const char *auth,
unsigned int flags,
const char *proxy,
void *tls_context);
estream_t http_get_read_ptr (http_t hd);
estream_t http_get_write_ptr (http_t hd);
unsigned int http_get_status_code (http_t hd);
const char *http_get_header (http_t hd, const char *name);
char *http_escape_string (const char *string, const char *specials);
#endif /*GNUPG_COMMON_HTTP_H*/

932
dirmngr/ldap-url.c Normal file
View File

@ -0,0 +1,932 @@
/* The following code comes from the OpenLDAP project. The references
to the COPYRIGHT file below refer to the corresponding file in the
OpenLDAP distribution, which is reproduced here in full:
Copyright 1998-2004 The OpenLDAP Foundation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted only as authorized by the OpenLDAP
Public License.
A copy of this license is available in the file LICENSE in the
top-level directory of the distribution or, alternatively, at
<http://www.OpenLDAP.org/license.html>.
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
Individual files and/or contributed packages may be copyright by
other parties and subject to additional restrictions.
This work is derived from the University of Michigan LDAP v3.3
distribution. Information concerning this software is available
at <http://www.umich.edu/~dirsvcs/ldap/>.
This work also contains materials derived from public sources.
Additional information about OpenLDAP can be obtained at
<http://www.openldap.org/>.
---
Portions Copyright 1998-2004 Kurt D. Zeilenga.
Portions Copyright 1998-2004 Net Boolean Incorporated.
Portions Copyright 2001-2004 IBM Corporation.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted only as authorized by the OpenLDAP
Public License.
---
Portions Copyright 1999-2003 Howard Y.H. Chu.
Portions Copyright 1999-2003 Symas Corporation.
Portions Copyright 1998-2003 Hallvard B. Furuseth.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that this notice is preserved.
The names of the copyright holders may not be used to endorse or
promote products derived from this software without their specific
prior written permission. This software is provided ``as is''
without express or implied warranty.
---
Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
All rights reserved.
Redistribution and use in source and binary forms are permitted
provided that this notice is preserved and that due credit is given
to the University of Michigan at Ann Arbor. The name of the
University may not be used to endorse or promote products derived
from this software without specific prior written permission. This
software is provided ``as is'' without express or implied warranty. */
#include <config.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winsock2.h>
#include <winldap.h>
#include "ldap-url.h"
#define LDAP_P(protos) protos
#define LDAP_URL_URLCOLON "URL:"
#define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1)
#define LDAP_URL_PREFIX "ldap://"
#define LDAP_URL_PREFIX_LEN (sizeof(LDAP_URL_PREFIX)-1)
#define LDAPS_URL_PREFIX "ldaps://"
#define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1)
#define LDAPI_URL_PREFIX "ldapi://"
#define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1)
#define LDAP_VFREE(v) { int _i; for (_i = 0; (v)[_i]; _i++) free((v)[_i]); }
#define LDAP_FREE free
#define LDAP_STRDUP strdup
#define LDAP_CALLOC calloc
#define LDAP_MALLOC malloc
#define LDAP_REALLOC realloc
#define ldap_utf8_strchr strchr
#define ldap_utf8_strtok(n,d,s) strtok (n,d)
#define Debug(a,b,c,d,e)
void ldap_pvt_hex_unescape( char *s );
/* $OpenLDAP: pkg/ldap/libraries/libldap/charray.c,v 1.9.2.2 2003/03/03 17:10:04 kurt Exp $ */
/*
* Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* charray.c - routines for dealing with char * arrays */
int
ldap_charray_add(
char ***a,
char *s
)
{
int n;
if ( *a == NULL ) {
*a = (char **) LDAP_MALLOC( 2 * sizeof(char *) );
n = 0;
if( *a == NULL ) {
return -1;
}
} else {
char **new;
for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
; /* NULL */
}
new = (char **) LDAP_REALLOC( (char *) *a,
(n + 2) * sizeof(char *) );
if( new == NULL ) {
/* caller is required to call ldap_charray_free(*a) */
return -1;
}
*a = new;
}
(*a)[n] = LDAP_STRDUP(s);
if( (*a)[n] == NULL ) {
return 1;
}
(*a)[++n] = NULL;
return 0;
}
int
ldap_charray_merge(
char ***a,
char **s
)
{
int i, n, nn;
char **aa;
for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
; /* NULL */
}
for ( nn = 0; s[nn] != NULL; nn++ ) {
; /* NULL */
}
aa = (char **) LDAP_REALLOC( (char *) *a, (n + nn + 1) * sizeof(char *) );
if( aa == NULL ) {
return -1;
}
*a = aa;
for ( i = 0; i < nn; i++ ) {
(*a)[n + i] = LDAP_STRDUP(s[i]);
if( (*a)[n + i] == NULL ) {
for( --i ; i >= 0 ; i-- ) {
LDAP_FREE( (*a)[n + i] );
(*a)[n + i] = NULL;
}
return -1;
}
}
(*a)[n + nn] = NULL;
return 0;
}
void
ldap_charray_free( char **a )
{
char **p;
if ( a == NULL ) {
return;
}
for ( p = a; *p != NULL; p++ ) {
if ( *p != NULL ) {
LDAP_FREE( *p );
}
}
LDAP_FREE( (char *) a );
}
int
ldap_charray_inlist(
char **a,
char *s
)
{
int i;
if( a == NULL ) return 0;
for ( i=0; a[i] != NULL; i++ ) {
if ( strcasecmp( s, a[i] ) == 0 ) {
return 1;
}
}
return 0;
}
char **
ldap_charray_dup( char **a )
{
int i;
char **new;
for ( i = 0; a[i] != NULL; i++ )
; /* NULL */
new = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) );
if( new == NULL ) {
return NULL;
}
for ( i = 0; a[i] != NULL; i++ ) {
new[i] = LDAP_STRDUP( a[i] );
if( new[i] == NULL ) {
for( --i ; i >= 0 ; i-- ) {
LDAP_FREE( new[i] );
}
LDAP_FREE( new );
return NULL;
}
}
new[i] = NULL;
return( new );
}
char **
ldap_str2charray( const char *str_in, const char *brkstr )
{
char **res;
char *str, *s;
char *lasts;
int i;
/* protect the input string from strtok */
str = LDAP_STRDUP( str_in );
if( str == NULL ) {
return NULL;
}
i = 1;
for ( s = str; *s; s++ ) {
if ( ldap_utf8_strchr( brkstr, *s ) != NULL ) {
i++;
}
}
res = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) );
if( res == NULL ) {
LDAP_FREE( str );
return NULL;
}
i = 0;
for ( s = ldap_utf8_strtok( str, brkstr, &lasts );
s != NULL;
s = ldap_utf8_strtok( NULL, brkstr, &lasts ) )
{
res[i] = LDAP_STRDUP( s );
if(res[i] == NULL) {
for( --i ; i >= 0 ; i-- ) {
LDAP_FREE( res[i] );
}
LDAP_FREE( res );
LDAP_FREE( str );
return NULL;
}
i++;
}
res[i] = NULL;
LDAP_FREE( str );
return( res );
}
char * ldap_charray2str( char **a, const char *sep )
{
char *s, **v, *p;
int len;
int slen;
if( sep == NULL ) sep = " ";
slen = strlen( sep );
len = 0;
for ( v = a; *v != NULL; v++ ) {
len += strlen( *v ) + slen;
}
if ( len == 0 ) {
return NULL;
}
/* trim extra sep len */
len -= slen;
s = LDAP_MALLOC ( len + 1 );
if ( s == NULL ) {
return NULL;
}
p = s;
for ( v = a; *v != NULL; v++ ) {
if ( v != a ) {
strncpy( p, sep, slen );
p += slen;
}
len = strlen( *v );
strncpy( p, *v, len );
p += len;
}
*p = '\0';
return s;
}
/* $OpenLDAP: pkg/ldap/libraries/libldap/url.c,v 1.64.2.5 2003/03/03 17:10:05 kurt Exp $ */
/*
* Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* Portions
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
*
* LIBLDAP url.c -- LDAP URL (RFC 2255) related routines
*
* LDAP URLs look like this:
* ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
*
* where:
* attributes is a comma separated list
* scope is one of these three strings: base one sub (default=base)
* filter is an string-represented filter as in RFC 2254
*
* e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
*
* We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
*/
/* local functions */
static const char* skip_url_prefix LDAP_P((
const char *url,
int *enclosedp,
const char **scheme ));
int
ldap_is_ldap_url( LDAP_CONST char *url )
{
int enclosed;
const char * scheme;
if( url == NULL ) {
return 0;
}
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
return 0;
}
return 1;
}
static const char*
skip_url_prefix(
const char *url,
int *enclosedp,
const char **scheme )
{
/*
* return non-zero if this looks like a LDAP URL; zero if not
* if non-zero returned, *urlp will be moved past "ldap://" part of URL
*/
const char *p;
if ( url == NULL ) {
return( NULL );
}
p = url;
/* skip leading '<' (if any) */
if ( *p == '<' ) {
*enclosedp = 1;
++p;
} else {
*enclosedp = 0;
}
/* skip leading "URL:" (if any) */
if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
p += LDAP_URL_URLCOLON_LEN;
}
/* check for "ldap://" prefix */
if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
/* skip over "ldap://" prefix and return success */
p += LDAP_URL_PREFIX_LEN;
*scheme = "ldap";
return( p );
}
/* check for "ldaps://" prefix */
if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
/* skip over "ldaps://" prefix and return success */
p += LDAPS_URL_PREFIX_LEN;
*scheme = "ldaps";
return( p );
}
/* check for "ldapi://" prefix */
if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
/* skip over "ldapi://" prefix and return success */
p += LDAPI_URL_PREFIX_LEN;
*scheme = "ldapi";
return( p );
}
#ifdef LDAP_CONNECTIONLESS
/* check for "cldap://" prefix */
if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
/* skip over "cldap://" prefix and return success */
p += LDAPC_URL_PREFIX_LEN;
*scheme = "cldap";
return( p );
}
#endif
return( NULL );
}
static int str2scope( const char *p )
{
if ( strcasecmp( p, "one" ) == 0 ) {
return LDAP_SCOPE_ONELEVEL;
} else if ( strcasecmp( p, "onetree" ) == 0 ) {
return LDAP_SCOPE_ONELEVEL;
} else if ( strcasecmp( p, "base" ) == 0 ) {
return LDAP_SCOPE_BASE;
} else if ( strcasecmp( p, "sub" ) == 0 ) {
return LDAP_SCOPE_SUBTREE;
} else if ( strcasecmp( p, "subtree" ) == 0 ) {
return LDAP_SCOPE_SUBTREE;
}
return( -1 );
}
int
ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
{
/*
* Pick apart the pieces of an LDAP URL.
*/
LDAPURLDesc *ludp;
char *p, *q, *r;
int i, enclosed;
const char *scheme = NULL;
const char *url_tmp;
char *url;
if( url_in == NULL || ludpp == NULL ) {
return LDAP_URL_ERR_PARAM;
}
#ifndef LDAP_INT_IN_KERNEL
/* Global options may not be created yet
* We can't test if the global options are initialized
* because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
* the options and cause infinite recursion
*/
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ENTRY, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
#endif
#endif
*ludpp = NULL; /* pessimistic */
url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
if ( url_tmp == NULL ) {
return LDAP_URL_ERR_BADSCHEME;
}
assert( scheme );
/* make working copy of the remainder of the URL */
url = LDAP_STRDUP( url_tmp );
if ( url == NULL ) {
return LDAP_URL_ERR_MEM;
}
if ( enclosed ) {
p = &url[strlen(url)-1];
if( *p != '>' ) {
LDAP_FREE( url );
return LDAP_URL_ERR_BADENCLOSURE;
}
*p = '\0';
}
/* allocate return struct */
ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
if ( ludp == NULL ) {
LDAP_FREE( url );
return LDAP_URL_ERR_MEM;
}
ludp->lud_next = NULL;
ludp->lud_host = NULL;
ludp->lud_port = 0;
ludp->lud_dn = NULL;
ludp->lud_attrs = NULL;
ludp->lud_filter = NULL;
ludp->lud_scope = LDAP_SCOPE_DEFAULT;
ludp->lud_filter = NULL;
ludp->lud_exts = NULL;
ludp->lud_scheme = LDAP_STRDUP( scheme );
if ( ludp->lud_scheme == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_MEM;
}
/* scan forward for '/' that marks end of hostport and begin. of dn */
p = strchr( url, '/' );
if( p != NULL ) {
/* terminate hostport; point to start of dn */
*p++ = '\0';
}
/* IPv6 syntax with [ip address]:port */
if ( *url == '[' ) {
r = strchr( url, ']' );
if ( r == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADURL;
}
*r++ = '\0';
q = strchr( r, ':' );
} else {
q = strchr( url, ':' );
}
if ( q != NULL ) {
*q++ = '\0';
ldap_pvt_hex_unescape( q );
if( *q == '\0' ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADURL;
}
ludp->lud_port = atoi( q );
}
ldap_pvt_hex_unescape( url );
/* If [ip address]:port syntax, url is [ip and we skip the [ */
ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) );
if( ludp->lud_host == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_MEM;
}
/*
* Kludge. ldap://111.222.333.444:389??cn=abc,o=company
*
* On early Novell releases, search references/referrals were returned
* in this format, i.e., the dn was kind of in the scope position,
* but the required slash is missing. The whole thing is illegal syntax,
* but we need to account for it. Fortunately it can't be confused with
* anything real.
*/
if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) {
q++;
/* ? immediately followed by question */
if( *q == '?') {
q++;
if( *q != '\0' ) {
/* parse dn part */
ldap_pvt_hex_unescape( q );
ludp->lud_dn = LDAP_STRDUP( q );
} else {
ludp->lud_dn = LDAP_STRDUP( "" );
}
if( ludp->lud_dn == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_MEM;
}
}
}
if( p == NULL ) {
LDAP_FREE( url );
*ludpp = ludp;
return LDAP_URL_SUCCESS;
}
/* scan forward for '?' that may marks end of dn */
q = strchr( p, '?' );
if( q != NULL ) {
/* terminate dn part */
*q++ = '\0';
}
if( *p != '\0' ) {
/* parse dn part */
ldap_pvt_hex_unescape( p );
ludp->lud_dn = LDAP_STRDUP( p );
} else {
ludp->lud_dn = LDAP_STRDUP( "" );
}
if( ludp->lud_dn == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_MEM;
}
if( q == NULL ) {
/* no more */
LDAP_FREE( url );
*ludpp = ludp;
return LDAP_URL_SUCCESS;
}
/* scan forward for '?' that may marks end of attributes */
p = q;
q = strchr( p, '?' );
if( q != NULL ) {
/* terminate attributes part */
*q++ = '\0';
}
if( *p != '\0' ) {
/* parse attributes */
ldap_pvt_hex_unescape( p );
ludp->lud_attrs = ldap_str2charray( p, "," );
if( ludp->lud_attrs == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADATTRS;
}
}
if ( q == NULL ) {
/* no more */
LDAP_FREE( url );
*ludpp = ludp;
return LDAP_URL_SUCCESS;
}
/* scan forward for '?' that may marks end of scope */
p = q;
q = strchr( p, '?' );
if( q != NULL ) {
/* terminate the scope part */
*q++ = '\0';
}
if( *p != '\0' ) {
/* parse the scope */
ldap_pvt_hex_unescape( p );
ludp->lud_scope = str2scope( p );
if( ludp->lud_scope == -1 ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADSCOPE;
}
}
if ( q == NULL ) {
/* no more */
LDAP_FREE( url );
*ludpp = ludp;
return LDAP_URL_SUCCESS;
}
/* scan forward for '?' that may marks end of filter */
p = q;
q = strchr( p, '?' );
if( q != NULL ) {
/* terminate the filter part */
*q++ = '\0';
}
if( *p != '\0' ) {
/* parse the filter */
ldap_pvt_hex_unescape( p );
if( ! *p ) {
/* missing filter */
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADFILTER;
}
LDAP_FREE( ludp->lud_filter );
ludp->lud_filter = LDAP_STRDUP( p );
if( ludp->lud_filter == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_MEM;
}
}
if ( q == NULL ) {
/* no more */
LDAP_FREE( url );
*ludpp = ludp;
return LDAP_URL_SUCCESS;
}
/* scan forward for '?' that may marks end of extensions */
p = q;
q = strchr( p, '?' );
if( q != NULL ) {
/* extra '?' */
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADURL;
}
/* parse the extensions */
ludp->lud_exts = ldap_str2charray( p, "," );
if( ludp->lud_exts == NULL ) {
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADEXTS;
}
for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
ldap_pvt_hex_unescape( ludp->lud_exts[i] );
if( *ludp->lud_exts[i] == '!' ) {
/* count the number of critical extensions */
ludp->lud_crit_exts++;
}
}
if( i == 0 ) {
/* must have 1 or more */
LDAP_FREE( url );
ldap_free_urldesc( ludp );
return LDAP_URL_ERR_BADEXTS;
}
/* no more */
*ludpp = ludp;
LDAP_FREE( url );
return LDAP_URL_SUCCESS;
}
int
ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
{
int rc = ldap_url_parse_ext( url_in, ludpp );
if( rc != LDAP_URL_SUCCESS ) {
return rc;
}
if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) {
(*ludpp)->lud_scope = LDAP_SCOPE_BASE;
}
if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') {
LDAP_FREE( (*ludpp)->lud_host );
(*ludpp)->lud_host = NULL;
}
if ((*ludpp)->lud_port == 0) {
if( strcmp((*ludpp)->lud_scheme, "ldap") == 0 ) {
(*ludpp)->lud_port = LDAP_PORT;
#ifdef LDAP_CONNECTIONLESS
} else if( strcmp((*ludpp)->lud_scheme, "cldap") == 0 ) {
(*ludpp)->lud_port = LDAP_PORT;
#endif
} else if( strcmp((*ludpp)->lud_scheme, "ldaps") == 0 ) {
(*ludpp)->lud_port = LDAPS_PORT;
}
}
return rc;
}
void
ldap_free_urldesc( LDAPURLDesc *ludp )
{
if ( ludp == NULL ) {
return;
}
if ( ludp->lud_scheme != NULL ) {
LDAP_FREE( ludp->lud_scheme );
}
if ( ludp->lud_host != NULL ) {
LDAP_FREE( ludp->lud_host );
}
if ( ludp->lud_dn != NULL ) {
LDAP_FREE( ludp->lud_dn );
}
if ( ludp->lud_filter != NULL ) {
LDAP_FREE( ludp->lud_filter);
}
if ( ludp->lud_attrs != NULL ) {
LDAP_VFREE( ludp->lud_attrs );
}
if ( ludp->lud_exts != NULL ) {
LDAP_VFREE( ludp->lud_exts );
}
LDAP_FREE( ludp );
}
static int
ldap_int_unhex( int c )
{
return( c >= '0' && c <= '9' ? c - '0'
: c >= 'A' && c <= 'F' ? c - 'A' + 10
: c - 'a' + 10 );
}
void
ldap_pvt_hex_unescape( char *s )
{
/*
* Remove URL hex escapes from s... done in place. The basic concept for
* this routine is borrowed from the WWW library HTUnEscape() routine.
*/
char *p;
for ( p = s; *s != '\0'; ++s ) {
if ( *s == '%' ) {
if ( *++s == '\0' ) {
break;
}
*p = ldap_int_unhex( *s ) << 4;
if ( *++s == '\0' ) {
break;
}
*p++ += ldap_int_unhex( *s );
} else {
*p++ = *s;
}
}
*p = '\0';
}

50
dirmngr/ldap-url.h Normal file
View File

@ -0,0 +1,50 @@
/* Copyright 2007 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. */
#ifndef LDAP_URL_H
#define LDAP_URL_H 1
#define LDAP_CONST const
typedef struct ldap_url_desc
{
struct ldap_url_desc *lud_next;
char *lud_scheme;
char *lud_host;
int lud_port;
char *lud_dn;
char **lud_attrs;
int lud_scope;
char *lud_filter;
char **lud_exts;
int lud_crit_exts;
} LDAPURLDesc;
#define LDAP_URL_SUCCESS 0x00
#define LDAP_URL_ERR_MEM 0x01
#define LDAP_URL_ERR_PARAM 0x02
#define LDAP_URL_ERR_BADSCHEME 0x03
#define LDAP_URL_ERR_BADENCLOSURE 0x04
#define LDAP_URL_ERR_BADURL 0x05
#define LDAP_URL_ERR_BADHOST 0x06
#define LDAP_URL_ERR_BADATTRS 0x07
#define LDAP_URL_ERR_BADSCOPE 0x08
#define LDAP_URL_ERR_BADFILTER 0x09
#define LDAP_URL_ERR_BADEXTS 0x0a
#define LDAPS_PORT 636
int ldap_is_ldap_url (LDAP_CONST char *url);
int ldap_url_parse (LDAP_CONST char *url_in, LDAPURLDesc **ludpp);
void ldap_free_urldesc (LDAPURLDesc *ludp);
#endif /* !LDAP_URL_H */

1499
dirmngr/ldap.c Normal file

File diff suppressed because it is too large Load Diff

133
dirmngr/ldapserver.c Normal file
View File

@ -0,0 +1,133 @@
/* dirmngr.c - LDAP access
Copyright (C) 2008 g10 Code GmbH
This file is part of DirMngr.
DirMngr 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 2 of the License, or
(at your option) any later version.
DirMngr 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "dirmngr.h"
#include "ldapserver.h"
/* Release the list of SERVERS. As usual it is okay to call this
function with SERVERS passed as NULL. */
void
ldapserver_list_free (ldap_server_t servers)
{
while (servers)
{
ldap_server_t tmp = servers->next;
xfree (servers->host);
xfree (servers->user);
if (servers->pass)
memset (servers->pass, 0, strlen (servers->pass));
xfree (servers->pass);
xfree (servers->base);
xfree (servers);
servers = tmp;
}
}
/* Parse a single LDAP server configuration line. Returns the server
or NULL in case of errors. The configuration lineis assumed to be
colon seprated with these fields:
1. field: Hostname
2. field: Portnumber
3. field: Username
4. field: Password
5. field: Base DN
FILENAME and LINENO are used for diagnostic purposes only.
*/
ldap_server_t
ldapserver_parse_one (char *line,
const char *filename, unsigned int lineno)
{
char *p;
char *endp;
ldap_server_t server;
int fieldno;
int fail = 0;
/* Parse the colon separated fields. */
server = xcalloc (1, sizeof *server);
for (fieldno = 1, p = line; p; p = endp, fieldno++ )
{
endp = strchr (p, ':');
if (endp)
*endp++ = '\0';
trim_spaces (p);
switch (fieldno)
{
case 1:
if (*p)
server->host = xstrdup (p);
else
{
log_error (_("%s:%u: no hostname given\n"),
filename, lineno);
fail = 1;
}
break;
case 2:
if (*p)
server->port = atoi (p);
break;
case 3:
if (*p)
server->user = xstrdup (p);
break;
case 4:
if (*p && !server->user)
{
log_error (_("%s:%u: password given without user\n"),
filename, lineno);
fail = 1;
}
else if (*p)
server->pass = xstrdup (p);
break;
case 5:
if (*p)
server->base = xstrdup (p);
break;
default:
/* (We silently ignore extra fields.) */
break;
}
}
if (fail)
{
log_info (_("%s:%u: skipping this line\n"), filename, lineno);
ldapserver_list_free (server);
}
return server;
}

90
dirmngr/ldapserver.h Normal file
View File

@ -0,0 +1,90 @@
/* ldapserver.h
Copyright (C) 2008 g10 Code GmbH
This file is part of DirMngr.
DirMngr 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 2 of the License, or
(at your option) any later version.
DirMngr 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 LDAPSERVER_H
#define LDAPSERVER_H
#include "dirmngr.h"
/* Release the list of SERVERS. As usual it is okay to call this
function with SERVERS passed as NULL. */
void ldapserver_list_free (ldap_server_t servers);
/* Parse a single LDAP server configuration line. Returns the server
or NULL in case of errors. The configuration lineis assumed to be
colon seprated with these fields:
1. field: Hostname
2. field: Portnumber
3. field: Username
4. field: Password
5. field: Base DN
FILENAME and LINENO are used for diagnostic purposes only.
*/
ldap_server_t ldapserver_parse_one (char *line,
const char *filename, unsigned int lineno);
/* Iterate over all servers. */
struct ldapserver_iter
{
ctrl_t ctrl;
enum { LDAPSERVER_SESSION, LDAPSERVER_OPT } group;
ldap_server_t server;
};
static inline void
ldapserver_iter_next (struct ldapserver_iter *iter)
{
if (iter->server)
iter->server = iter->server->next;
if (! iter->server)
{
if (iter->group == LDAPSERVER_SESSION)
{
iter->group = LDAPSERVER_OPT;
iter->server = opt.ldapservers;
}
}
}
static inline int
ldapserver_iter_end_p (struct ldapserver_iter *iter)
{
return (iter->group == LDAPSERVER_OPT && iter->server == NULL);
}
static inline void
ldapserver_iter_begin (struct ldapserver_iter *iter, ctrl_t ctrl)
{
iter->ctrl = ctrl;
iter->group = LDAPSERVER_SESSION;
iter->server = get_ldapservers_from_ctrl (ctrl);
while (iter->server == NULL && ! ldapserver_iter_end_p (iter))
ldapserver_iter_next (iter);
}
#endif /* LDAPSERVER_H */

486
dirmngr/misc.c Normal file
View File

@ -0,0 +1,486 @@
/* misc.c - miscellaneous
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "dirmngr.h"
#include "util.h"
#include "misc.h"
/* Convert the hex encoded STRING back into binary and store the
result into the provided buffer RESULT. The actual size of that
buffer will be returned. The caller should provide RESULT of at
least strlen(STRING)/2 bytes. There is no error detection, the
parsing stops at the first non hex character. With RESULT given as
NULL, the fucntion does only return the size of the buffer which
would be needed. */
size_t
unhexify (unsigned char *result, const char *string)
{
const char *s;
size_t n;
for (s=string,n=0; hexdigitp (s) && hexdigitp(s+1); s += 2)
{
if (result)
result[n] = xtoi_2 (s);
n++;
}
return n;
}
char*
hashify_data( const char* data, size_t len )
{
unsigned char buf[20];
gcry_md_hash_buffer (GCRY_MD_SHA1, buf, data, len);
return hexify_data( buf, 20 );
}
char*
hexify_data( const unsigned char* data, size_t len )
{
int i;
char* result = xmalloc( sizeof( char ) * (2*len+1));
for( i = 0; i < 2*len; i+=2 )
sprintf( result+i, "%02X", *data++);
return result;
}
char *
serial_hex (ksba_sexp_t serial )
{
unsigned char* p = serial;
char *endp;
unsigned long n;
char *certid;
if (!p)
return NULL;
else {
p++; /* ignore initial '(' */
n = strtoul (p, (char**)&endp, 10);
p = endp;
if (*p!=':')
return NULL;
else {
int i = 0;
certid = xmalloc( sizeof( char )*(2*n + 1 ) );
for (p++; n; n--, p++) {
sprintf ( certid+i , "%02X", *p);
i += 2;
}
}
}
return certid;
}
/* Take an S-Expression encoded blob and return a pointer to the
actual data as well as its length. Return NULL for an invalid
S-Expression.*/
const unsigned char *
serial_to_buffer (const ksba_sexp_t serial, size_t *length)
{
unsigned char *p = serial;
char *endp;
unsigned long n;
if (!p || *p != '(')
return NULL;
p++;
n = strtoul (p, &endp, 10);
p = endp;
if (*p != ':')
return NULL;
p++;
*length = n;
return p;
}
/* Do an in-place percent unescaping of STRING. Returns STRING. Noet
that this function does not do a '+'-to-space unescaping.*/
char *
unpercent_string (char *string)
{
char *s = string;
char *d = string;
while (*s)
{
if (*s == '%' && s[1] && s[2])
{
s++;
*d++ = xtoi_2 ( s);
s += 2;
}
else
*d++ = *s++;
}
*d = 0;
return string;
}
/* Convert a canonical encoded S-expression in CANON into the GCRY
type. */
gpg_error_t
canon_sexp_to_gcry (const unsigned char *canon, gcry_sexp_t *r_sexp)
{
gpg_error_t err;
size_t n;
gcry_sexp_t sexp;
*r_sexp = NULL;
n = gcry_sexp_canon_len (canon, 0, NULL, NULL);
if (!n)
{
log_error (_("invalid canonical S-expression found\n"));
err = gpg_error (GPG_ERR_INV_SEXP);
}
else if ((err = gcry_sexp_sscan (&sexp, NULL, canon, n)))
log_error (_("converting S-expression failed: %s\n"), gcry_strerror (err));
else
*r_sexp = sexp;
return err;
}
/* Return an allocated buffer with the formatted fingerprint as one
large hexnumber */
char *
get_fingerprint_hexstring (ksba_cert_t cert)
{
unsigned char digest[20];
gcry_md_hd_t md;
int rc;
char *buf;
int i;
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (rc)
log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
if (rc)
{
log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
memset (digest, 0xff, 20); /* Use a dummy value. */
}
else
{
gcry_md_final (md);
memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
}
gcry_md_close (md);
buf = xmalloc (41);
*buf = 0;
for (i=0; i < 20; i++ )
sprintf (buf+strlen(buf), "%02X", digest[i]);
return buf;
}
/* Return an allocated buffer with the formatted fingerprint as one
large hexnumber. This version inserts the usual colons. */
char *
get_fingerprint_hexstring_colon (ksba_cert_t cert)
{
unsigned char digest[20];
gcry_md_hd_t md;
int rc;
char *buf;
int i;
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (rc)
log_fatal (_("gcry_md_open failed: %s\n"), gpg_strerror (rc));
rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
if (rc)
{
log_error (_("oops: ksba_cert_hash failed: %s\n"), gpg_strerror (rc));
memset (digest, 0xff, 20); /* Use a dummy value. */
}
else
{
gcry_md_final (md);
memcpy (digest, gcry_md_read (md, GCRY_MD_SHA1), 20);
}
gcry_md_close (md);
buf = xmalloc (61);
*buf = 0;
for (i=0; i < 20; i++ )
sprintf (buf+strlen(buf), "%02X:", digest[i]);
buf[strlen(buf)-1] = 0; /* Remove railing colon. */
return buf;
}
/* Dump the serial number SERIALNO to the log stream. */
void
dump_serial (ksba_sexp_t serialno)
{
char *p;
p = serial_hex (serialno);
log_printf ("%s", p?p:"?");
xfree (p);
}
/* Dump STRING to the log file but choose the best readable
format. */
void
dump_string (const char *string)
{
if (!string)
log_printf ("[error]");
else
{
const unsigned char *s;
for (s=string; *s; s++)
{
if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
break;
}
if (!*s && *string != '[')
log_printf ("%s", string);
else
{
log_printf ( "[ ");
log_printhex (NULL, string, strlen (string));
log_printf ( " ]");
}
}
}
/* Dump an KSBA cert object to the log stream. Prefix the output with
TEXT. This is used for debugging. */
void
dump_cert (const char *text, ksba_cert_t cert)
{
ksba_sexp_t sexp;
char *p;
ksba_isotime_t t;
log_debug ("BEGIN Certificate `%s':\n", text? text:"");
if (cert)
{
sexp = ksba_cert_get_serial (cert);
p = serial_hex (sexp);
log_debug (" serial: %s\n", p?p:"?");
xfree (p);
ksba_free (sexp);
ksba_cert_get_validity (cert, 0, t);
log_debug (" notBefore: ");
dump_isotime (t);
log_printf ("\n");
ksba_cert_get_validity (cert, 1, t);
log_debug (" notAfter: ");
dump_isotime (t);
log_printf ("\n");
p = ksba_cert_get_issuer (cert, 0);
log_debug (" issuer: ");
dump_string (p);
ksba_free (p);
log_printf ("\n");
p = ksba_cert_get_subject (cert, 0);
log_debug (" subject: ");
dump_string (p);
ksba_free (p);
log_printf ("\n");
log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert));
p = get_fingerprint_hexstring (cert);
log_debug (" SHA1 fingerprint: %s\n", p);
xfree (p);
}
log_debug ("END Certificate\n");
}
/* Log the certificate's name in "#SN/ISSUERDN" format along with
TEXT. */
void
cert_log_name (const char *text, ksba_cert_t cert)
{
log_info ("%s", text? text:"certificate" );
if (cert)
{
ksba_sexp_t sn;
char *p;
p = ksba_cert_get_issuer (cert, 0);
sn = ksba_cert_get_serial (cert);
if (p && sn)
{
log_printf (" #");
dump_serial (sn);
log_printf ("/");
dump_string (p);
}
else
log_printf (" [invalid]");
ksba_free (sn);
xfree (p);
}
log_printf ("\n");
}
/* Log the certificate's subject DN along with TEXT. */
void
cert_log_subject (const char *text, ksba_cert_t cert)
{
log_info ("%s", text? text:"subject" );
if (cert)
{
char *p;
p = ksba_cert_get_subject (cert, 0);
if (p)
{
log_printf (" /");
dump_string (p);
xfree (p);
}
else
log_printf (" [invalid]");
}
log_printf ("\n");
}
/****************
* Remove all %xx escapes; this is done inplace.
* Returns: New length of the string.
*/
static int
remove_percent_escapes (unsigned char *string)
{
int n = 0;
unsigned char *p, *s;
for (p = s = string; *s; s++)
{
if (*s == '%')
{
if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
{
s++;
*p = xtoi_2 (s);
s++;
p++;
n++;
}
else
{
*p++ = *s++;
if (*s)
*p++ = *s++;
if (*s)
*p++ = *s++;
if (*s)
*p = 0;
return -1; /* Bad URI. */
}
}
else
{
*p++ = *s;
n++;
}
}
*p = 0; /* Always keep a string terminator. */
return n;
}
/* Return the host name and the port (0 if none was given) from the
URL. Return NULL on error or if host is not included in the
URL. */
char *
host_and_port_from_url (const char *url, int *port)
{
const char *s, *s2;
char *buf, *p;
int n;
s = url;
*port = 0;
/* Find the scheme */
if ( !(s2 = strchr (s, ':')) || s2 == s )
return NULL; /* No scheme given. */
s = s2+1;
/* Find the hostname */
if (*s != '/')
return NULL; /* Does not start with a slash. */
s++;
if (*s != '/')
return NULL; /* No host name. */
s++;
buf = xtrystrdup (s);
if (!buf)
{
log_error (_("malloc failed: %s\n"), strerror (errno));
return NULL;
}
if ((p = strchr (buf, '/')))
*p++ = 0;
strlwr (buf);
if ((p = strchr (p, ':')))
{
*p++ = 0;
*port = atoi (p);
}
/* Remove quotes and make sure that no Nul has been encoded. */
if ((n = remove_percent_escapes (buf)) < 0
|| n != strlen (buf) )
{
log_error (_("bad URL encoding detected\n"));
xfree (buf);
return NULL;
}
return buf;
}

87
dirmngr/misc.h Normal file
View File

@ -0,0 +1,87 @@
/* misc.h - miscellaneous
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef MISC_H
#define MISC_H
/* Convert hex encoded string back to binary. */
size_t unhexify (unsigned char *result, const char *string);
/* Returns SHA1 hash of the data. */
char* hashify_data( const char* data, size_t len );
/* Returns data as a hex string. */
char* hexify_data( const unsigned char* data, size_t len );
/* Returns the serial number as a hex string. */
char* serial_hex ( ksba_sexp_t serial );
/* Take an S-Expression encoded blob and return a pointer to the
actual data as well as its length. */
const unsigned char *serial_to_buffer (const ksba_sexp_t serial,
size_t *length);
/* Do an in-place percent unescaping of STRING. Returns STRING. */
char *unpercent_string (char *string);
gpg_error_t canon_sexp_to_gcry (const unsigned char *canon,
gcry_sexp_t *r_sexp);
/* Return an allocated hex-string with the SHA-1 fingerprint of
CERT. */
char *get_fingerprint_hexstring (ksba_cert_t cert);
/* Return an allocated hex-string with the SHA-1 fingerprint of
CERT. This version inserts the usual colons. */
char *get_fingerprint_hexstring_colon (ksba_cert_t cert);
/* Log CERT in short format with s/n and issuer DN prefixed by TEXT. */
void cert_log_name (const char *text, ksba_cert_t cert);
/* Log CERT in short format with the subject DN prefixed by TEXT. */
void cert_log_subject (const char *text, ksba_cert_t cert);
/* Dump the serial number SERIALNO to the log stream. */
void dump_serial (ksba_sexp_t serialno);
/* Dump STRING to the log file but choose the best readable
format. */
void dump_string (const char *string);
/* Dump an KSBA cert object to the log stream. Prefix the output with
TEXT. This is used for debugging. */
void dump_cert (const char *text, ksba_cert_t cert);
/* Return the host name and the port (0 if none was given) from the
URL. Return NULL on error or if host is not included in the
URL. */
char *host_and_port_from_url (const char *url, int *port);
#ifdef HAVE_FOPENCOOKIE
/* We have to implement funopen in terms of glibc's fopencookie. */
FILE *funopen(void *cookie,
int (*readfn)(void *, char *, int),
int (*writefn)(void *, const char *, int),
fpos_t (*seekfn)(void *, fpos_t, int),
int (*closefn)(void *));
#endif /*HAVE_FOPENCOOKIE*/
#endif /* MISC_H */

154
dirmngr/no-libgcrypt.c Normal file
View File

@ -0,0 +1,154 @@
/* no-libgcrypt.c - Replacement functions for libgcrypt.
* Copyright (C) 2003 Free Software Foundation, Inc.
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "../common/util.h"
#include "i18n.h"
/* Replace libgcrypt's malloc functions which are used by
../jnlib/libjnlib.a . ../common/util.h defines macros to map them
to xmalloc etc. */
static void
out_of_memory (void)
{
log_fatal (_("error allocating enough memory: %s\n"), strerror (errno));
}
void *
gcry_malloc (size_t n)
{
return malloc (n);
}
void *
gcry_malloc_secure (size_t n)
{
return malloc (n);
}
void *
gcry_xmalloc (size_t n)
{
void *p = malloc (n);
if (!p)
out_of_memory ();
return p;
}
char *
gcry_strdup (const char *string)
{
char *p = malloc (strlen (string)+1);
if (p)
strcpy (p, string);
return p;
}
void *
gcry_realloc (void *a, size_t n)
{
return realloc (a, n);
}
void *
gcry_xrealloc (void *a, size_t n)
{
void *p = realloc (a, n);
if (!p)
out_of_memory ();
return p;
}
void *
gcry_calloc (size_t n, size_t m)
{
return calloc (n, m);
}
void *
gcry_xcalloc (size_t n, size_t m)
{
void *p = calloc (n, m);
if (!p)
out_of_memory ();
return p;
}
char *
gcry_xstrdup (const char *string)
{
void *p = malloc (strlen (string)+1);
if (!p)
out_of_memory ();
strcpy( p, string );
return p;
}
void
gcry_free (void *a)
{
if (a)
free (a);
}
/* We need this dummy because exechelp.c uses gcry_control to
terminate the secure memeory. */
gcry_error_t
gcry_control (enum gcry_ctl_cmds cmd, ...)
{
(void)cmd;
return 0;
}
void
gcry_set_outofcore_handler (gcry_handler_no_mem_t h, void *opaque)
{
(void)h;
(void)opaque;
}
void
gcry_set_fatalerror_handler (gcry_handler_error_t fnc, void *opaque)
{
(void)fnc;
(void)opaque;
}
void
gcry_set_log_handler (gcry_handler_log_t f, void *opaque)
{
(void)f;
(void)opaque;
}
void
gcry_create_nonce (void *buffer, size_t length)
{
(void)buffer;
(void)length;
log_fatal ("unexpected call to gcry_create_nonce\n");
}

799
dirmngr/ocsp.c Normal file
View File

@ -0,0 +1,799 @@
/* ocsp.c - OCSP management
* Copyright (C) 2004, 2007 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "dirmngr.h"
#include "misc.h"
#include "http.h"
#include "validate.h"
#include "certcache.h"
#include "ocsp.h"
#include "estream.h"
/* The maximum size we allow as a response from an OCSP reponder. */
#define MAX_RESPONSE_SIZE 65536
static const char oidstr_ocsp[] = "1.3.6.1.5.5.7.48.1";
/* Telesec attribute used to implement a positive confirmation.
CertHash ::= SEQUENCE {
HashAlgorithm AlgorithmIdentifier,
certificateHash OCTET STRING }
*/
static const char oidstr_certHash[] = "1.3.36.8.3.13";
/* Read from FP and return a newly allocated buffer in R_BUFFER with the
entire data read from FP. */
static gpg_error_t
read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
{
gpg_error_t err;
unsigned char *buffer;
size_t bufsize, nbytes;
*r_buffer = NULL;
*r_buflen = 0;
bufsize = 4096;
buffer = xtrymalloc (bufsize);
if (!buffer)
return gpg_error_from_errno (errno);
nbytes = 0;
for (;;)
{
unsigned char *tmp;
size_t nread = 0;
assert (nbytes < bufsize);
nread = es_fread (buffer+nbytes, 1, bufsize-nbytes, fp);
if (nread < bufsize-nbytes && es_ferror (fp))
{
err = gpg_error_from_errno (errno);
log_error (_("error reading from responder: %s\n"),
strerror (errno));
xfree (buffer);
return err;
}
if ( !(nread == bufsize-nbytes && !es_feof (fp)))
{ /* Response succesfully received. */
nbytes += nread;
*r_buffer = buffer;
*r_buflen = nbytes;
return 0;
}
nbytes += nread;
/* Need to enlarge the buffer. */
if (bufsize >= MAX_RESPONSE_SIZE)
{
log_error (_("response from server too large; limit is %d bytes\n"),
MAX_RESPONSE_SIZE);
xfree (buffer);
return gpg_error (GPG_ERR_TOO_LARGE);
}
bufsize += 4096;
tmp = xtryrealloc (buffer, bufsize);
if (!tmp)
{
err = gpg_error_from_errno (errno);
xfree (buffer);
return err;
}
buffer = tmp;
}
}
/* Construct an OCSP request, send it to the configured OCSP responder
and parse the response. On success the OCSP context may be used to
further process the reponse. */
static gpg_error_t
do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert)
{
gpg_error_t err;
unsigned char *request, *response;
size_t requestlen, responselen;
http_t http;
ksba_ocsp_response_status_t response_status;
const char *t;
int redirects_left = 2;
char *free_this = NULL;
(void)ctrl;
if (opt.disable_http)
{
log_error (_("OCSP request not possible due to disabled HTTP\n"));
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
if (err)
{
log_error (_("error setting OCSP target: %s\n"), gpg_strerror (err));
return err;
}
{
size_t n;
unsigned char nonce[32];
n = ksba_ocsp_set_nonce (ocsp, NULL, 0);
if (n > sizeof nonce)
n = sizeof nonce;
gcry_create_nonce (nonce, n);
ksba_ocsp_set_nonce (ocsp, nonce, n);
}
err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
if (err)
{
log_error (_("error building OCSP request: %s\n"), gpg_strerror (err));
return err;
}
once_more:
err = http_open (&http, HTTP_REQ_POST, url, NULL,
(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
|HTTP_FLAG_NEED_HEADER,
opt.http_proxy,
NULL);
if (err)
{
log_error (_("error connecting to `%s': %s\n"), url, gpg_strerror (err));
xfree (free_this);
return err;
}
es_fprintf (http_get_write_ptr (http),
"Content-Type: application/ocsp-request\r\n"
"Content-Length: %lu\r\n",
(unsigned long)requestlen );
http_start_data (http);
if (es_fwrite (request, requestlen, 1, http_get_write_ptr (http)) != 1)
{
err = gpg_error_from_errno (errno);
log_error ("error sending request to `%s': %s\n", url, strerror (errno));
http_close (http, 0);
xfree (request);
xfree (free_this);
return err;
}
xfree (request);
request = NULL;
err = http_wait_response (http);
if (err || http_get_status_code (http) != 200)
{
if (err)
log_error (_("error reading HTTP response for `%s': %s\n"),
url, gpg_strerror (err));
else
{
switch (http_get_status_code (http))
{
case 301:
case 302:
{
const char *s = http_get_header (http, "Location");
log_info (_("URL `%s' redirected to `%s' (%u)\n"),
url, s?s:"[none]", http_get_status_code (http));
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 (http, 0);
goto once_more;
}
}
else
err = gpg_error (GPG_ERR_NO_DATA);
log_error (_("too many redirections\n"));
}
break;
default:
log_error (_("error accessing `%s': http status %u\n"),
url, http_get_status_code (http));
err = gpg_error (GPG_ERR_NO_DATA);
break;
}
}
http_close (http, 0);
xfree (free_this);
return err;
}
err = read_response (http_get_read_ptr (http), &response, &responselen);
http_close (http, 0);
if (err)
{
log_error (_("error reading HTTP response for `%s': %s\n"),
url, gpg_strerror (err));
xfree (free_this);
return err;
}
err = ksba_ocsp_parse_response (ocsp, response, responselen,
&response_status);
if (err)
{
log_error (_("error parsing OCSP response for `%s': %s\n"),
url, gpg_strerror (err));
xfree (response);
xfree (free_this);
return err;
}
switch (response_status)
{
case KSBA_OCSP_RSPSTATUS_SUCCESS: t = "success"; break;
case KSBA_OCSP_RSPSTATUS_MALFORMED: t = "malformed"; break;
case KSBA_OCSP_RSPSTATUS_INTERNAL: t = "internal error"; break;
case KSBA_OCSP_RSPSTATUS_TRYLATER: t = "try later"; break;
case KSBA_OCSP_RSPSTATUS_SIGREQUIRED: t = "must sign request"; break;
case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break;
case KSBA_OCSP_RSPSTATUS_REPLAYED: t = "replay detected"; break;
case KSBA_OCSP_RSPSTATUS_OTHER: t = "other (unknown)"; break;
case KSBA_OCSP_RSPSTATUS_NONE: t = "no status"; break;
default: t = "[unknown status]"; break;
}
if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS)
{
if (opt.verbose)
log_info (_("OCSP responder at `%s' status: %s\n"), url, t);
err = ksba_ocsp_hash_response (ocsp, response, responselen,
HASH_FNC, md);
if (err)
log_error (_("hashing the OCSP response for `%s' failed: %s\n"),
url, gpg_strerror (err));
}
else
{
log_error (_("OCSP responder at `%s' status: %s\n"), url, t);
err = gpg_error (GPG_ERR_GENERAL);
}
xfree (response);
xfree (free_this);
return err;
}
/* Validate that CERT is indeed valid to sign an OCSP response. If
SIGNER_FPR_LIST is not NULL we simply check that CERT matches one
of the fingerprints in this list. */
static gpg_error_t
validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
fingerprint_list_t signer_fpr_list)
{
gpg_error_t err;
char *fpr;
if (signer_fpr_list)
{
fpr = get_fingerprint_hexstring (cert);
for (; signer_fpr_list && strcmp (signer_fpr_list->hexfpr, fpr);
signer_fpr_list = signer_fpr_list->next)
;
if (signer_fpr_list)
err = 0;
else
{
log_error (_("not signed by a default OCSP signer's certificate"));
err = gpg_error (GPG_ERR_BAD_CA_CERT);
}
xfree (fpr);
}
else if (opt.system_daemon)
{
err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_OCSP, NULL);
}
else
{
/* We avoid duplicating the entire certificate validation code
from gpgsm here. Because we have no way calling back to the
client and letting it compute the validity, we use the ugly
hack of telling the client that the response will only be
valid if the certificate given in this status message is
valid.
Note, that in theory we could simply ask the client via an
inquire to validate a certificate but this might involve
calling DirMngr again recursivly - we can't do that as of now
(neither DirMngr nor gpgsm have the ability for concurrent
access to DirMngr. */
/* FIXME: We should cache this certificate locally, so that the next
call to dirmngr won't need to look it up - if this works at
all. */
fpr = get_fingerprint_hexstring (cert);
dirmngr_status (ctrl, "ONLY_VALID_IF_CERT_VALID", fpr, NULL);
xfree (fpr);
err = 0;
}
return err;
}
/* Helper for check_signature. */
static int
check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
gcry_sexp_t s_hash, fingerprint_list_t signer_fpr_list)
{
gpg_error_t err;
ksba_sexp_t pubkey;
gcry_sexp_t s_pkey = NULL;
pubkey = ksba_cert_get_public_key (cert);
if (!pubkey)
err = gpg_error (GPG_ERR_INV_OBJ);
else
err = canon_sexp_to_gcry (pubkey, &s_pkey);
xfree (pubkey);
if (!err)
err = gcry_pk_verify (s_sig, s_hash, s_pkey);
if (!err)
err = validate_responder_cert (ctrl, cert, signer_fpr_list);
if (!err)
{
gcry_sexp_release (s_pkey);
return 0; /* Successfully verified the signature. */
}
/* We simply ignore all errors. */
gcry_sexp_release (s_pkey);
return -1;
}
/* Check the signature of an OCSP repsonse. OCSP is the context,
S_SIG the signature value and MD the handle of the hash we used for
the response. This function automagically finds the correct public
key. If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
used and thus the certificate is one of those identified by
the fingerprints. */
static gpg_error_t
check_signature (ctrl_t ctrl,
ksba_ocsp_t ocsp, gcry_sexp_t s_sig, gcry_md_hd_t md,
fingerprint_list_t signer_fpr_list)
{
gpg_error_t err;
int algo, cert_idx;
gcry_sexp_t s_hash;
ksba_cert_t cert;
/* Create a suitable S-expression with the hash value of our response. */
gcry_md_final (md);
algo = gcry_md_get_algo (md);
if (algo != GCRY_MD_SHA1 )
{
log_error (_("only SHA-1 is supported for OCSP responses\n"));
return gpg_error (GPG_ERR_DIGEST_ALGO);
}
err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
gcry_md_get_algo_dlen (algo),
gcry_md_read (md, algo));
if (err)
{
log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
return err;
}
/* Get rid of old OCSP specific certificate references. */
release_ctrl_ocsp_certs (ctrl);
if (signer_fpr_list && !signer_fpr_list->next)
{
/* There is exactly one signer fingerprint given. Thus we use
the default OCSP responder's certificate and instantly know
the certificate to use. */
cert = get_cert_byhexfpr (signer_fpr_list->hexfpr);
if (!cert)
cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
if (cert)
{
err = check_signature_core (ctrl, cert, s_sig, s_hash,
signer_fpr_list);
ksba_cert_release (cert);
cert = NULL;
if (!err)
{
gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */
}
}
}
else
{
char *name;
ksba_sexp_t keyid;
/* Put all certificates included in the response into the cache
and setup a list of those certificate which will later be
preferred used when locating certificates. */
for (cert_idx=0; (cert = ksba_ocsp_get_cert (ocsp, cert_idx));
cert_idx++)
{
cert_ref_t cref;
cref = xtrymalloc (sizeof *cref);
if (!cref)
log_error (_("allocating list item failed: %s\n"),
gcry_strerror (err));
else if (!cache_cert_silent (cert, &cref->fpr))
{
cref->next = ctrl->ocsp_certs;
ctrl->ocsp_certs = cref;
}
else
xfree (cref);
}
/* Get the certificate by means of the responder ID. */
err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
if (err)
{
log_error (_("error getting responder ID: %s\n"),
gcry_strerror (err));
return err;
}
cert = find_cert_bysubject (ctrl, name, keyid);
if (!cert)
{
log_error ("responder certificate ");
if (name)
log_printf ("`/%s' ", name);
if (keyid)
{
log_printf ("{");
dump_serial (keyid);
log_printf ("} ");
}
log_printf ("not found\n");
}
ksba_free (name);
ksba_free (keyid);
if (cert)
{
err = check_signature_core (ctrl, cert, s_sig, s_hash,
signer_fpr_list);
ksba_cert_release (cert);
if (!err)
{
gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */
}
}
}
gcry_sexp_release (s_hash);
log_error (_("no suitable certificate found to verify the OCSP response\n"));
return gpg_error (GPG_ERR_NO_PUBKEY);
}
/* Check whether the certificate either given by fingerprint CERT_FPR
or directly through the CERT object is valid by running an OCSP
transaction. With FORCE_DEFAULT_RESPONDER set only the configured
default responder is used. */
gpg_error_t
ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
int force_default_responder)
{
gpg_error_t err;
ksba_ocsp_t ocsp = NULL;
ksba_cert_t issuer_cert = NULL;
ksba_sexp_t sigval = NULL;
gcry_sexp_t s_sig = NULL;
ksba_isotime_t current_time;
ksba_isotime_t this_update, next_update, revocation_time, produced_at;
ksba_isotime_t tmp_time;
ksba_status_t status;
ksba_crl_reason_t reason;
char *url_buffer = NULL;
const char *url;
gcry_md_hd_t md = NULL;
int i, idx;
char *oid;
ksba_name_t name;
fingerprint_list_t default_signer = NULL;
/* Get the certificate. */
if (cert)
{
ksba_cert_ref (cert);
err = find_issuing_cert (ctrl, cert, &issuer_cert);
if (err)
{
log_error (_("issuer certificate not found: %s\n"),
gpg_strerror (err));
goto leave;
}
}
else
{
cert = get_cert_local (ctrl, cert_fpr);
if (!cert)
{
log_error (_("caller did not return the target certificate\n"));
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
issuer_cert = get_issuing_cert_local (ctrl, NULL);
if (!issuer_cert)
{
log_error (_("caller did not return the issuing certificate\n"));
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
}
/* Create an OCSP instance. */
err = ksba_ocsp_new (&ocsp);
if (err)
{
log_error (_("failed to allocate OCSP context: %s\n"),
gpg_strerror (err));
goto leave;
}
/* Figure out the OCSP responder to use.
1. Try to get the reponder from the certificate.
We do only take http and https style URIs into account.
2. If this fails use the default responder, if any.
*/
url = NULL;
for (idx=0; !url && !opt.ignore_ocsp_service_url && !force_default_responder
&& !(err=ksba_cert_get_authority_info_access (cert, idx,
&oid, &name)); idx++)
{
if ( !strcmp (oid, oidstr_ocsp) )
{
for (i=0; !url && ksba_name_enum (name, i); i++)
{
char *p = ksba_name_get_uri (name, i);
if (p && (!ascii_strncasecmp (p, "http:", 5)
|| !ascii_strncasecmp (p, "https:", 6)))
url = url_buffer = p;
else
xfree (p);
}
}
ksba_name_release (name);
ksba_free (oid);
}
if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
goto leave;
}
if (!url)
{
if (!opt.ocsp_responder || !*opt.ocsp_responder)
{
log_info (_("no default OCSP responder defined\n"));
err = gpg_error (GPG_ERR_CONFIGURATION);
goto leave;
}
if (!opt.ocsp_signer)
{
log_info (_("no default OCSP signer defined\n"));
err = gpg_error (GPG_ERR_CONFIGURATION);
goto leave;
}
url = opt.ocsp_responder;
default_signer = opt.ocsp_signer;
if (opt.verbose)
log_info (_("using default OCSP responder `%s'\n"), url);
}
else
{
if (opt.verbose)
log_info (_("using OCSP responder `%s'\n"), url);
}
/* Ask the OCSP responder. */
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (err)
{
log_error (_("failed to establish a hashing context for OCSP: %s\n"),
gpg_strerror (err));
goto leave;
}
err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
if (err)
goto leave;
/* We got a useful answer, check that the answer has a valid signature. */
sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
if (!sigval || !*produced_at)
{
err = gpg_error (GPG_ERR_INV_OBJ);
goto leave;
}
if ( (err = canon_sexp_to_gcry (sigval, &s_sig)) )
goto leave;
xfree (sigval);
sigval = NULL;
err = check_signature (ctrl, ocsp, s_sig, md, default_signer);
if (err)
goto leave;
/* We only support one certificate per request. Check that the
answer matches the right certificate. */
err = ksba_ocsp_get_status (ocsp, cert,
&status, this_update, next_update,
revocation_time, &reason);
if (err)
{
log_error (_("error getting OCSP status for target certificate: %s\n"),
gpg_strerror (err));
goto leave;
}
/* In case the certificate has been revoked, we better invalidate
our cached validation status. */
if (status == KSBA_STATUS_REVOKED)
{
time_t validated_at = 0; /* That is: No cached validation available. */
err = ksba_cert_set_user_data (cert, "validated_at",
&validated_at, sizeof (validated_at));
if (err)
{
log_error ("set_user_data(validated_at) failed: %s\n",
gpg_strerror (err));
err = 0; /* The certificate is anyway revoked, and that is a
more important message than the failure of our
cache. */
}
}
if (opt.verbose)
{
log_info (_("certificate status is: %s (this=%s next=%s)\n"),
status == KSBA_STATUS_GOOD? _("good"):
status == KSBA_STATUS_REVOKED? _("revoked"):
status == KSBA_STATUS_UNKNOWN? _("unknown"):
status == KSBA_STATUS_NONE? _("none"): "?",
this_update, next_update);
if (status == KSBA_STATUS_REVOKED)
log_info (_("certificate has been revoked at: %s due to: %s\n"),
revocation_time,
reason == KSBA_CRLREASON_UNSPECIFIED? "unspecified":
reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
reason == KSBA_CRLREASON_CA_COMPROMISE? "CA compromise":
reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
"affiliation changed":
reason == KSBA_CRLREASON_SUPERSEDED? "superseeded":
reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
"cessation of operation":
reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
"certificate on hold":
reason == KSBA_CRLREASON_REMOVE_FROM_CRL?
"removed from CRL":
reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
"privilege withdrawn":
reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
reason == KSBA_CRLREASON_OTHER? "other":"?");
}
if (status == KSBA_STATUS_REVOKED)
err = gpg_error (GPG_ERR_CERT_REVOKED);
else if (status == KSBA_STATUS_UNKNOWN)
err = gpg_error (GPG_ERR_NO_DATA);
else if (status != KSBA_STATUS_GOOD)
err = gpg_error (GPG_ERR_GENERAL);
/* Allow for some clock skew. */
gnupg_get_isotime (current_time);
add_seconds_to_isotime (current_time, opt.ocsp_max_clock_skew);
if (strcmp (this_update, current_time) > 0 )
{
log_error (_("OCSP responder returned a status in the future\n"));
log_info ("used now: %s this_update: %s\n", current_time, this_update);
if (!err)
err = gpg_error (GPG_ERR_TIME_CONFLICT);
}
/* Check that THIS_UPDATE is not too far back in the past. */
gnupg_copy_time (tmp_time, this_update);
add_seconds_to_isotime (tmp_time,
opt.ocsp_max_period+opt.ocsp_max_clock_skew);
if (!*tmp_time || strcmp (tmp_time, current_time) < 0 )
{
log_error (_("OCSP responder returned a non-current status\n"));
log_info ("used now: %s this_update: %s\n",
current_time, this_update);
if (!err)
err = gpg_error (GPG_ERR_TIME_CONFLICT);
}
/* Check that we are not beyound NEXT_UPDATE (plus some extra time). */
if (*next_update)
{
gnupg_copy_time (tmp_time, next_update);
add_seconds_to_isotime (tmp_time,
opt.ocsp_current_period+opt.ocsp_max_clock_skew);
if (!*tmp_time && strcmp (tmp_time, current_time) < 0 )
{
log_error (_("OCSP responder returned an too old status\n"));
log_info ("used now: %s next_update: %s\n",
current_time, next_update);
if (!err)
err = gpg_error (GPG_ERR_TIME_CONFLICT);
}
}
leave:
gcry_md_close (md);
gcry_sexp_release (s_sig);
xfree (sigval);
ksba_cert_release (issuer_cert);
ksba_cert_release (cert);
ksba_ocsp_release (ocsp);
xfree (url_buffer);
return err;
}
/* Release the list of OCSP certificates hold in the CTRL object. */
void
release_ctrl_ocsp_certs (ctrl_t ctrl)
{
while (ctrl->ocsp_certs)
{
cert_ref_t tmp = ctrl->ocsp_certs->next;
xfree (ctrl->ocsp_certs);
ctrl->ocsp_certs = tmp;
}
}

31
dirmngr/ocsp.h Normal file
View File

@ -0,0 +1,31 @@
/* ocsp.h - OCSP management
* Copyright (C) 2003 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifndef OCSP_H
#define OCSP_H
gpg_error_t ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
int force_default_responder);
/* Release the list of OCSP certificates hold in the CTRL object. */
void release_ctrl_ocsp_certs (ctrl_t ctrl);
#endif /*OCSP_H*/

1539
dirmngr/server.c Normal file

File diff suppressed because it is too large Load Diff

1160
dirmngr/validate.c Normal file

File diff suppressed because it is too large Load Diff

55
dirmngr/validate.h Normal file
View File

@ -0,0 +1,55 @@
/* validate.h - Certificate validation
* Copyright (C) 2004 g10 Code GmbH
*
* This file is part of DirMngr.
*
* DirMngr 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 2 of the License, or
* (at your option) any later version.
*
* DirMngr 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef VALIDATE_H
#define VALIDATE_H
enum {
/* Simple certificate validation mode. */
VALIDATE_MODE_CERT = 0,
/* Standard CRL issuer certificate validation; i.e. CRLs are not
considered for CRL issuer certificates. */
VALIDATE_MODE_CRL = 1,
/* Full CRL validation. */
VALIDATE_MODE_CRL_RECURSIVE = 2,
/* Validation as used for OCSP. */
VALIDATE_MODE_OCSP = 3
};
/* Validate the certificate CHAIN up to the trust anchor. Optionally
return the closest expiration time in R_EXPTIME. */
gpg_error_t validate_cert_chain (ctrl_t ctrl,
ksba_cert_t cert, ksba_isotime_t r_exptime,
int mode, char **r_trust_anchor);
/* Return 0 if the certificate CERT is usable for certification. */
gpg_error_t cert_use_cert_p (ksba_cert_t cert);
/* Return 0 if the certificate CERT is usable for signing OCSP
responses. */
gpg_error_t cert_use_ocsp_p (ksba_cert_t cert);
/* Return 0 if the certificate CERT is usable for signing CRLs. */
gpg_error_t cert_use_crl_p (ksba_cert_t cert);
#endif /*VALIDATE_H*/

View File

@ -304,7 +304,8 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
close (outbound[1]);
if (pid != (pid_t)(-1))
{
gnupg_wait_process (pgmname, pid, NULL);
gnupg_wait_process (pgmname, pid, 0, NULL);
gnupg_release_process (pid);
}
runner_release (runner);
encfs_handler_cleanup (parm);

View File

@ -165,7 +165,8 @@ runner_release (runner_t runner)
arbitrary NAME of the runner object. However it does not
matter because that information is only used for
diagnostics.) */
gnupg_wait_process (runner->name, runner->pid, NULL);
gnupg_wait_process (runner->name, runner->pid, 0, NULL);
gnupg_release_process (runner->pid);
}
xfree (runner->name);
@ -370,7 +371,8 @@ runner_thread (void *arg)
int exitcode;
log_debug ("runner thread waiting ...\n");
err = gnupg_wait_process (runner->name, runner->pid, &exitcode);
err = gnupg_wait_process (runner->name, runner->pid, 0, &exitcode);
gnupg_release_process (runner->pid);
runner->pid = (pid_t)(-1);
if (err)
log_error ("running `%s' failed (exitcode=%d): %s\n",

View File

@ -1,3 +1,7 @@
2010-06-08 Werner Koch <wk@g10code.com>
* ldap.m4 (gnupg_have_ldap): Set variable.
2009-09-03 Werner Koch <wk@g10code.com>
* estream.m4: Update for libestream.

View File

@ -17,7 +17,7 @@ AC_DEFUN([GNUPG_CHECK_LDAP],
# OpenLDAP, circa 1999, was terrible with creating weird dependencies.
# If all else fails, the user can play guess-the-dependency by using
# something like ./configure LDAPLIBS="-Lfoo -lbar"
gnupg_have_ldap=no
AC_ARG_WITH(ldap,
AC_HELP_STRING([--with-ldap=DIR],[look for the LDAP library in DIR]),
[_ldap_with=$withval])
@ -66,6 +66,7 @@ if test x$_ldap_with != xno ; then
test "$gnupg_cv_func_ldaplber_init" = yes ; then
LDAPLIBS="$LDAP_LDFLAGS $MY_LDAPLIBS"
GPGKEYS_LDAP="gpg2keys_ldap$EXEEXT"
gnupg_have_ldap=yes
AC_CHECK_FUNCS(ldap_get_option ldap_set_option)
# The extra test for ldap_start_tls_sA is for W32 because

View File

@ -1,3 +1,8 @@
2010-06-09 Werner Koch <wk@g10code.com>
* scdaemon.c (main): s/log_set_get_tid_callback/log_set_pid_suffix_cb/.
(tid_log_callback): Adjust for this change.
2010-03-11 Werner Koch <wk@g10code.com>
* scdaemon.c: Include "asshelp.h".

View File

@ -269,14 +269,15 @@ my_strusage (int level)
}
static unsigned long
tid_log_callback (void)
static int
tid_log_callback (unsigned long *rvalue)
{
#ifdef PTH_HAVE_PTH_THREAD_ID
return pth_thread_id ();
*rvalue = pth_thread_id ();
#else
return (unsigned long)pth_self ();
*rvalue = (unsigned long)pth_self ();
#endif
return 2; /* Use use hex representation. */
}
@ -551,7 +552,7 @@ main (int argc, char **argv )
break;
case oDebugDisableTicker: ticker_disabled = 1; break;
case oDebugLogTid:
log_set_get_tid_callback (tid_log_callback);
log_set_pid_suffix_cb (tid_log_callback);
break;
case oOptions:

View File

@ -715,8 +715,9 @@ export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen,
es_fclose (fp);
if (pid != -1)
{
if (!gnupg_wait_process (pgmname, pid, NULL))
if (!gnupg_wait_process (pgmname, pid, 0, NULL))
child_err = 0;
gnupg_release_process (pid);
}
if (!err)
err = child_err;

View File

@ -773,8 +773,9 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader,
es_fclose (fp);
if (pid != -1)
{
if (!gnupg_wait_process (pgmname, pid, NULL))
if (!gnupg_wait_process (pgmname, pid, 0, NULL))
child_err = 0;
gnupg_release_process (pid);
}
if (!err)
err = child_err;

View File

@ -1051,10 +1051,11 @@ gpg_agent_runtime_change (void)
err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
if (!err)
err = gnupg_wait_process (pgmname, pid, NULL);
err = gnupg_wait_process (pgmname, pid, 0, NULL);
if (err)
gc_error (0, 0, "error running `%s%s': %s",
pgmname, " reloadagent", gpg_strerror (err));
gnupg_release_process (pid);
#endif /*!HAVE_W32_SYSTEM*/
}
@ -1082,10 +1083,11 @@ scdaemon_runtime_change (void)
err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
if (!err)
err = gnupg_wait_process (pgmname, pid, NULL);
err = gnupg_wait_process (pgmname, pid, 0, NULL);
if (err)
gc_error (0, 0, "error running `%s%s': %s",
pgmname, " scd killscd", gpg_strerror (err));
gnupg_release_process (pid);
}
@ -1501,13 +1503,14 @@ gc_component_check_options (int component, FILE *out, const char *conf_file)
close (filedes[1]);
errlines = collect_error_output (filedes[0],
gc_component[component].name);
if (gnupg_wait_process (pgmname, pid, &exitcode))
if (gnupg_wait_process (pgmname, pid, 0, &exitcode))
{
if (exitcode == -1)
result |= 1; /* Program could not be run or it
terminated abnormally. */
result |= 2; /* Program returned an error. */
}
gnupg_release_process (pid);
}
/* If the program could not be run, we can't tell whether
@ -1919,10 +1922,11 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
if (fclose (config) && ferror (config))
gc_error (1, errno, "error closing %s", pgmname);
err = gnupg_wait_process (pgmname, pid, &exitcode);
err = gnupg_wait_process (pgmname, pid, 0, &exitcode);
if (err)
gc_error (1, 0, "running %s failed (exitcode=%d): %s",
pgmname, exitcode, gpg_strerror (err));
gnupg_release_process (pid);
/* At this point, we can parse the configuration file. */