mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merged Dirmngr with GnuPG.
A few code changes to support dirmngr.
This commit is contained in:
parent
70f3a9bbb6
commit
c3f08dcb72
18
ChangeLog
18
ChangeLog
@ -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>
|
||||
|
@ -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
2
NEWS
@ -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)
|
||||
-------------------------------------------------
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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).
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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,9 +617,13 @@ 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_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));
|
||||
@ -642,17 +641,16 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
|
||||
{
|
||||
log_error (_("error running `%s': exit status %d\n"),
|
||||
pgmname, (int)exc );
|
||||
if (exitcode)
|
||||
*exitcode = (int)exc;
|
||||
if (r_exitcode)
|
||||
*r_exitcode = (int)exc;
|
||||
ec = GPG_ERR_GENERAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exitcode)
|
||||
*exitcode = 0;
|
||||
if (r_exitcode)
|
||||
*r_exitcode = 0;
|
||||
ec = 0;
|
||||
}
|
||||
CloseHandle (proc);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -666,6 +664,19 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
|
||||
}
|
||||
|
||||
|
||||
|
||||
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).
|
||||
|
@ -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,9 +672,13 @@ 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_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));
|
||||
@ -706,7 +706,6 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
|
||||
*exitcode = 0;
|
||||
ec = 0;
|
||||
}
|
||||
CloseHandle (proc);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -720,6 +719,18 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
|
||||
}
|
||||
|
||||
|
||||
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).
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 ());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
54
configure.ac
54
configure.ac
@ -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
|
||||
@ -1471,6 +1497,7 @@ 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")
|
||||
@ -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
1345
dirmngr/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
802
dirmngr/ChangeLog.1
Normal file
802
dirmngr/ChangeLog.1
Normal 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
65
dirmngr/Makefile.am
Normal 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
40
dirmngr/OAUTHORS
Normal 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
240
dirmngr/ONEWS
Normal 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
217
dirmngr/b64dec.c
Normal 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
213
dirmngr/b64enc.c
Normal 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
91
dirmngr/cdb.h
Normal 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
925
dirmngr/cdblib.c
Normal 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
1384
dirmngr/certcache.c
Normal file
File diff suppressed because it is too large
Load Diff
103
dirmngr/certcache.h
Normal file
103
dirmngr/certcache.h
Normal 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
2544
dirmngr/crlcache.c
Normal file
File diff suppressed because it is too large
Load Diff
70
dirmngr/crlcache.h
Normal file
70
dirmngr/crlcache.h
Normal 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
479
dirmngr/crlfetch.c
Normal 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
93
dirmngr/crlfetch.h
Normal 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
1042
dirmngr/dirmngr-client.c
Normal file
File diff suppressed because it is too large
Load Diff
1829
dirmngr/dirmngr.c
Normal file
1829
dirmngr/dirmngr.c
Normal file
File diff suppressed because it is too large
Load Diff
189
dirmngr/dirmngr.h
Normal file
189
dirmngr/dirmngr.h
Normal 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
646
dirmngr/dirmngr_ldap.c
Normal 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
620
dirmngr/get-path.c
Normal 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
1861
dirmngr/http.c
Normal file
File diff suppressed because it is too large
Load Diff
109
dirmngr/http.h
Normal file
109
dirmngr/http.h
Normal 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
932
dirmngr/ldap-url.c
Normal 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
50
dirmngr/ldap-url.h
Normal 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
1499
dirmngr/ldap.c
Normal file
File diff suppressed because it is too large
Load Diff
133
dirmngr/ldapserver.c
Normal file
133
dirmngr/ldapserver.c
Normal 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
90
dirmngr/ldapserver.h
Normal 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
486
dirmngr/misc.c
Normal 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
87
dirmngr/misc.h
Normal 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
154
dirmngr/no-libgcrypt.c
Normal 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
799
dirmngr/ocsp.c
Normal 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
31
dirmngr/ocsp.h
Normal 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
1539
dirmngr/server.c
Normal file
File diff suppressed because it is too large
Load Diff
1160
dirmngr/validate.c
Normal file
1160
dirmngr/validate.c
Normal file
File diff suppressed because it is too large
Load Diff
55
dirmngr/validate.h
Normal file
55
dirmngr/validate.h
Normal 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*/
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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".
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user