diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 21beb29c7..a1964ece8 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -1,3243 +1,3255 @@
/* gpg-agent.c - The GnuPG Agent
* Copyright (C) 2000-2007, 2009-2010 Free Software Foundation, Inc.
* Copyright (C) 2000-2016 Werner Koch
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_W32_SYSTEM
# ifndef WINVER
# define WINVER 0x0500 /* Same as in common/sysutils.c */
# endif
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
# include
#else /*!HAVE_W32_SYSTEM*/
# include
# include
#endif /*!HAVE_W32_SYSTEM*/
#include
#ifdef HAVE_SIGNAL_H
# include
#endif
#include
#define GNUPG_COMMON_NEED_AFLOCAL
#include "agent.h"
#include /* Malloc hooks and socket wrappers. */
#include "../common/i18n.h"
#include "../common/sysutils.h"
#include "../common/gc-opt-flags.h"
#include "../common/exechelp.h"
#include "../common/asshelp.h"
#include "../common/init.h"
enum cmd_and_opt_values
{ aNull = 0,
oCsh = 'c',
oQuiet = 'q',
oSh = 's',
oVerbose = 'v',
oNoVerbose = 500,
aGPGConfList,
aGPGConfTest,
aUseStandardSocketP,
oOptions,
oDebug,
oDebugAll,
oDebugLevel,
oDebugWait,
oDebugQuickRandom,
oDebugPinentry,
oNoGreeting,
oNoOptions,
oHomedir,
oNoDetach,
oGrab,
oNoGrab,
oLogFile,
oServer,
oDaemon,
oSupervised,
oBatch,
oPinentryProgram,
oPinentryTouchFile,
oPinentryInvisibleChar,
oPinentryTimeout,
oDisplay,
oTTYname,
oTTYtype,
oLCctype,
oLCmessages,
oXauthority,
oScdaemonProgram,
oDefCacheTTL,
oDefCacheTTLSSH,
oMaxCacheTTL,
oMaxCacheTTLSSH,
oEnforcePassphraseConstraints,
oMinPassphraseLen,
oMinPassphraseNonalpha,
oCheckPassphrasePattern,
oMaxPassphraseDays,
oEnablePassphraseHistory,
oEnableExtendedKeyFormat,
oUseStandardSocket,
oNoUseStandardSocket,
oExtraSocket,
oBrowserSocket,
oFakedSystemTime,
oIgnoreCacheForSigning,
oAllowMarkTrusted,
oNoAllowMarkTrusted,
oAllowPresetPassphrase,
oAllowLoopbackPinentry,
oNoAllowLoopbackPinentry,
oNoAllowExternalCache,
oAllowEmacsPinentry,
oKeepTTY,
oKeepDISPLAY,
oSSHSupport,
oSSHFingerprintDigest,
oPuttySupport,
oDisableScdaemon,
oDisableCheckOwnSocket,
oS2KCount,
oAutoExpandSecmem,
+ oListenBacklog,
oWriteEnvFile
};
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
ARGPARSE_c (aUseStandardSocketP, "use-standard-socket-p", "@"),
ARGPARSE_group (301, N_("@Options:\n ")),
ARGPARSE_s_n (oDaemon, "daemon", N_("run in daemon mode (background)")),
ARGPARSE_s_n (oServer, "server", N_("run in server mode (foreground)")),
#ifndef HAVE_W32_SYSTEM
ARGPARSE_s_n (oSupervised, "supervised", N_("run in supervised mode")),
#endif
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
ARGPARSE_s_n (oSh, "sh", N_("sh-style command output")),
ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oDebugQuickRandom, "debug-quick-random", "@"),
ARGPARSE_s_n (oDebugPinentry, "debug-pinentry", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_n (oGrab, "grab", "@"),
/* FIXME: Add the below string for 2.3 */
/* N_("let PIN-Entry grab keyboard and mouse")), */
ARGPARSE_s_n (oNoGrab, "no-grab", "@"),
ARGPARSE_s_s (oLogFile, "log-file", N_("use a log file for the server")),
ARGPARSE_s_s (oPinentryProgram, "pinentry-program",
/* */ N_("|PGM|use PGM as the PIN-Entry program")),
ARGPARSE_s_s (oPinentryTouchFile, "pinentry-touch-file", "@"),
ARGPARSE_s_s (oPinentryInvisibleChar, "pinentry-invisible-char", "@"),
ARGPARSE_s_u (oPinentryTimeout, "pinentry-timeout", "@"),
ARGPARSE_s_s (oScdaemonProgram, "scdaemon-program",
/* */ N_("|PGM|use PGM as the SCdaemon program") ),
ARGPARSE_s_n (oDisableScdaemon, "disable-scdaemon",
/* */ N_("do not use the SCdaemon") ),
ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
ARGPARSE_s_s (oExtraSocket, "extra-socket",
/* */ N_("|NAME|accept some commands via NAME")),
ARGPARSE_s_s (oBrowserSocket, "browser-socket", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
ARGPARSE_s_n (oBatch, "batch", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"),
ARGPARSE_s_s (oTTYname, "ttyname", "@"),
ARGPARSE_s_s (oTTYtype, "ttytype", "@"),
ARGPARSE_s_s (oLCctype, "lc-ctype", "@"),
ARGPARSE_s_s (oLCmessages, "lc-messages", "@"),
ARGPARSE_s_s (oXauthority, "xauthority", "@"),
ARGPARSE_s_n (oKeepTTY, "keep-tty",
/* */ N_("ignore requests to change the TTY")),
ARGPARSE_s_n (oKeepDISPLAY, "keep-display",
/* */ N_("ignore requests to change the X display")),
ARGPARSE_s_u (oDefCacheTTL, "default-cache-ttl",
N_("|N|expire cached PINs after N seconds")),
ARGPARSE_s_u (oDefCacheTTLSSH, "default-cache-ttl-ssh", "@" ),
ARGPARSE_s_u (oMaxCacheTTL, "max-cache-ttl", "@" ),
ARGPARSE_s_u (oMaxCacheTTLSSH, "max-cache-ttl-ssh", "@" ),
ARGPARSE_s_n (oEnforcePassphraseConstraints, "enforce-passphrase-constraints",
/* */ "@"),
ARGPARSE_s_u (oMinPassphraseLen, "min-passphrase-len", "@"),
ARGPARSE_s_u (oMinPassphraseNonalpha, "min-passphrase-nonalpha", "@"),
ARGPARSE_s_s (oCheckPassphrasePattern, "check-passphrase-pattern", "@"),
ARGPARSE_s_u (oMaxPassphraseDays, "max-passphrase-days", "@"),
ARGPARSE_s_n (oEnablePassphraseHistory, "enable-passphrase-history", "@"),
ARGPARSE_s_n (oIgnoreCacheForSigning, "ignore-cache-for-signing",
/* */ N_("do not use the PIN cache when signing")),
ARGPARSE_s_n (oNoAllowExternalCache, "no-allow-external-cache",
/* */ N_("disallow the use of an external password cache")),
ARGPARSE_s_n (oNoAllowMarkTrusted, "no-allow-mark-trusted",
/* */ N_("disallow clients to mark keys as \"trusted\"")),
ARGPARSE_s_n (oAllowMarkTrusted, "allow-mark-trusted", "@"),
ARGPARSE_s_n (oAllowPresetPassphrase, "allow-preset-passphrase",
/* */ N_("allow presetting passphrase")),
ARGPARSE_s_n (oNoAllowLoopbackPinentry, "no-allow-loopback-pinentry",
N_("disallow caller to override the pinentry")),
ARGPARSE_s_n (oAllowLoopbackPinentry, "allow-loopback-pinentry", "@"),
ARGPARSE_s_n (oAllowEmacsPinentry, "allow-emacs-pinentry",
/* */ N_("allow passphrase to be prompted through Emacs")),
ARGPARSE_s_n (oSSHSupport, "enable-ssh-support", N_("enable ssh support")),
ARGPARSE_s_s (oSSHFingerprintDigest, "ssh-fingerprint-digest",
N_("|ALGO|use ALGO to show ssh fingerprints")),
ARGPARSE_s_n (oPuttySupport, "enable-putty-support",
#ifdef HAVE_W32_SYSTEM
/* */ N_("enable putty support")
#else
/* */ "@"
#endif
),
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
ARGPARSE_s_u (oS2KCount, "s2k-count", "@"),
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
+ ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
+
/* Dummy options for backward compatibility. */
ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"),
ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"),
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
ARGPARSE_end () /* End of list */
};
/* The list of supported debug flags. */
static struct debug_flags_s debug_flags [] =
{
{ DBG_MPI_VALUE , "mpi" },
{ DBG_CRYPTO_VALUE , "crypto" },
{ DBG_MEMORY_VALUE , "memory" },
{ DBG_CACHE_VALUE , "cache" },
{ DBG_MEMSTAT_VALUE, "memstat" },
{ DBG_HASHING_VALUE, "hashing" },
{ DBG_IPC_VALUE , "ipc" },
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
};
#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */
#define DEFAULT_CACHE_TTL_SSH (30*60) /* 30 minutes */
#define MAX_CACHE_TTL (120*60) /* 2 hours */
#define MAX_CACHE_TTL_SSH (120*60) /* 2 hours */
#define MIN_PASSPHRASE_LEN (8)
#define MIN_PASSPHRASE_NONALPHA (1)
#define MAX_PASSPHRASE_DAYS (0)
/* The timer tick used for housekeeping stuff. Note that on Windows
* we use a SetWaitableTimer seems to signal earlier than about 2
* seconds. Thus we use 4 seconds on all platforms except for
* Windowsce. CHECK_OWN_SOCKET_INTERVAL defines how often we check
* our own socket in standard socket mode. If that value is 0 we
* don't check at all. All values are in seconds. */
#if defined(HAVE_W32CE_SYSTEM)
# define TIMERTICK_INTERVAL (60)
# define CHECK_OWN_SOCKET_INTERVAL (0) /* Never */
#else
# define TIMERTICK_INTERVAL (4)
# define CHECK_OWN_SOCKET_INTERVAL (60)
#endif
/* Flag indicating that the ssh-agent subsystem has been enabled. */
static int ssh_support;
#ifdef HAVE_W32_SYSTEM
/* Flag indicating that support for Putty has been enabled. */
static int putty_support;
/* A magic value used with WM_COPYDATA. */
#define PUTTY_IPC_MAGIC 0x804e50ba
/* To avoid surprises we limit the size of the mapped IPC file to this
value. Putty currently (0.62) uses 8k, thus 16k should be enough
for the foreseeable future. */
#define PUTTY_IPC_MAXLEN 16384
#endif /*HAVE_W32_SYSTEM*/
/* The list of open file descriptors at startup. Note that this list
* has been allocated using the standard malloc. */
#ifndef HAVE_W32_SYSTEM
static int *startup_fd_list;
#endif
/* The signal mask at startup and a flag telling whether it is valid. */
#ifdef HAVE_SIGPROCMASK
static sigset_t startup_signal_mask;
static int startup_signal_mask_valid;
#endif
/* Flag to indicate that a shutdown was requested. */
static int shutdown_pending;
/* Counter for the currently running own socket checks. */
static int check_own_socket_running;
/* Flags to indicate that check_own_socket shall not be called. */
static int disable_check_own_socket;
/* Flag indicating that we are in supervised mode. */
static int is_supervised;
/* Flag to inhibit socket removal in cleanup. */
static int inhibit_socket_removal;
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
/* Name of the communication socket used for native gpg-agent
requests. The second variable is either NULL or a malloced string
with the real socket name in case it has been redirected. */
static char *socket_name;
static char *redir_socket_name;
/* Name of the optional extra socket used for native gpg-agent requests. */
static char *socket_name_extra;
static char *redir_socket_name_extra;
/* Name of the optional browser socket used for native gpg-agent requests. */
static char *socket_name_browser;
static char *redir_socket_name_browser;
/* Name of the communication socket used for ssh-agent protocol. */
static char *socket_name_ssh;
static char *redir_socket_name_ssh;
/* We need to keep track of the server's nonces (these are dummies for
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
static assuan_sock_nonce_t socket_nonce_extra;
static assuan_sock_nonce_t socket_nonce_browser;
static assuan_sock_nonce_t socket_nonce_ssh;
+/* Value for the listen() backlog argument. We use the same value for
+ * all sockets - 64 is on current Linux half of the default maximum.
+ * Let's try this as default. Change at runtime with --listen-backlog. */
+static int listen_backlog = 64;
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
static char *default_ttytype;
static char *default_lc_ctype;
static char *default_lc_messages;
static char *default_xauthority;
/* Name of a config file, which will be reread on a HUP if it is not NULL. */
static char *config_filename;
/* Helper to implement --debug-level */
static const char *debug_level;
/* Keep track of the current log file so that we can avoid updating
the log file after a SIGHUP if it didn't changed. Malloced. */
static char *current_logfile;
/* The handle_tick() function may test whether a parent is still
* running. We record the PID of the parent here or -1 if it should
* be watched. */
static pid_t parent_pid = (pid_t)(-1);
/* This flag is true if the inotify mechanism for detecting the
* removal of the homedir is active. This flag is used to disable the
* alternative but portable stat based check. */
static int have_homedir_inotify;
/* Depending on how gpg-agent was started, the homedir inotify watch
* may not be reliable. This flag is set if we assume that inotify
* works reliable. */
static int reliable_homedir_inotify;
/* Number of active connections. */
static int active_connections;
/* This object is used to dispatch progress messages from Libgcrypt to
* the right thread. Given that we will have at max only a few dozen
* connections at a time, using a linked list is the easiest way to
* handle this. */
struct progress_dispatch_s
{
struct progress_dispatch_s *next;
/* The control object of the connection. If this is NULL no
* connection is associated with this item and it is free for reuse
* by new connections. */
ctrl_t ctrl;
/* The thread id of (npth_self) of the connection. */
npth_t tid;
/* The callback set by the connection. This is similar to the
* Libgcrypt callback but with the control object passed as the
* first argument. */
void (*cb)(ctrl_t ctrl,
const char *what, int printchar,
int current, int total);
};
struct progress_dispatch_s *progress_dispatch_list;
/*
Local prototypes.
*/
static char *create_socket_name (char *standard_name, int with_homedir);
static gnupg_fd_t create_server_socket (char *name, int primary, int cygwin,
char **r_redir_name,
assuan_sock_nonce_t *nonce);
static void create_directories (void);
static void agent_libgcrypt_progress_cb (void *data, const char *what,
int printchar,
int current, int total);
static void agent_init_default_ctrl (ctrl_t ctrl);
static void agent_deinit_default_ctrl (ctrl_t ctrl);
static void handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh);
static void check_own_socket (void);
static int check_for_running_agent (int silent);
/* Pth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
/*
Functions.
*/
/* Allocate a string describing a library version by calling a GETFNC.
This function is expected to be called only once. GETFNC is
expected to have a semantic like gcry_check_version (). */
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
const char *s;
char *result;
if (maybe_setuid)
{
gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */
maybe_setuid = 0;
}
s = getfnc (NULL);
result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
strcpy (stpcpy (stpcpy (result, libname), " "), s);
return result;
}
/* Return strings describing this program. The case values are
described in common/argparse.c:strusage. The values here override
the default values given by strusage. */
static const char *
my_strusage (int level)
{
static char *ver_gcry;
const char *p;
switch (level)
{
case 11: p = "@GPG_AGENT@ (@GNUPG@)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
/* TRANSLATORS: @EMAIL@ will get replaced by the actual bug
reporting address. This is so that we can change the
reporting address without breaking the translations. */
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
case 20:
if (!ver_gcry)
ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
p = ver_gcry;
break;
case 1:
case 40: p = _("Usage: @GPG_AGENT@ [options] (-h for help)");
break;
case 41: p = _("Syntax: @GPG_AGENT@ [options] [command [args]]\n"
"Secret key management for @GNUPG@\n");
break;
default: p = NULL;
}
return p;
}
/* Setup the debugging. With the global variable DEBUG_LEVEL set to NULL
only the active debug flags are propagated to the subsystems. With
DEBUG_LEVEL set, a specific set of debug flags is set; thus overriding
all flags already set. Note that we don't fail here, because it is
important to keep gpg-agent running even after re-reading the
options due to a SIGHUP. */
static void
set_debug (void)
{
int numok = (debug_level && digitp (debug_level));
int numlvl = numok? atoi (debug_level) : 0;
if (!debug_level)
;
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
opt.debug = (DBG_IPC_VALUE | DBG_CACHE_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
opt.debug = ~0;
/* Unless the "guru" string has been used we don't want to allow
hashing debugging. The rationale is that people tend to
select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */
if (numok)
opt.debug &= ~(DBG_HASHING_VALUE);
}
else
{
log_error (_("invalid debug-level '%s' given\n"), debug_level);
opt.debug = 0; /* Reset debugging, so that prior debug
statements won't have an undesired effect. */
}
if (opt.debug && !opt.verbose)
opt.verbose = 1;
if (opt.debug && opt.quiet)
opt.quiet = 0;
if (opt.debug & DBG_MPI_VALUE)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
parse_debug_flag (NULL, &opt.debug, debug_flags);
}
/* Helper for cleanup to remove one socket with NAME. REDIR_NAME is
the corresponding real name if the socket has been redirected. */
static void
remove_socket (char *name, char *redir_name)
{
if (name && *name)
{
if (redir_name)
name = redir_name;
gnupg_remove (name);
*name = 0;
}
}
/* Discover which inherited file descriptors correspond to which
* services/sockets offered by gpg-agent, using the LISTEN_FDS and
* LISTEN_FDNAMES convention. The understood labels are "ssh",
* "extra", and "browser". "std" or other labels will be interpreted
* as the standard socket.
*
* This function is designed to log errors when the expected file
* descriptors don't make sense, but to do its best to continue to
* work even in the face of minor misconfigurations.
*
* For more information on the LISTEN_FDS convention, see
* sd_listen_fds(3) on certain Linux distributions.
*/
#ifndef HAVE_W32_SYSTEM
static void
map_supervised_sockets (gnupg_fd_t *r_fd,
gnupg_fd_t *r_fd_extra,
gnupg_fd_t *r_fd_browser,
gnupg_fd_t *r_fd_ssh)
{
struct {
const char *label;
int **fdaddr;
char **nameaddr;
} tbl[] = {
{ "ssh", &r_fd_ssh, &socket_name_ssh },
{ "browser", &r_fd_browser, &socket_name_browser },
{ "extra", &r_fd_extra, &socket_name_extra },
{ "std", &r_fd, &socket_name } /* (Must be the last item.) */
};
const char *envvar;
char **fdnames;
int nfdnames;
int fd_count;
*r_fd = *r_fd_extra = *r_fd_browser = *r_fd_ssh = -1;
/* Print a warning if LISTEN_PID does not match outr pid. */
envvar = getenv ("LISTEN_PID");
if (!envvar)
log_error ("no LISTEN_PID environment variable found in "
"--supervised mode (ignoring)\n");
else if (strtoul (envvar, NULL, 10) != (unsigned long)getpid ())
log_error ("environment variable LISTEN_PID (%lu) does not match"
" our pid (%lu) in --supervised mode (ignoring)\n",
(unsigned long)strtoul (envvar, NULL, 10),
(unsigned long)getpid ());
/* Parse LISTEN_FDNAMES into the array FDNAMES. */
envvar = getenv ("LISTEN_FDNAMES");
if (envvar)
{
fdnames = strtokenize (envvar, ":");
if (!fdnames)
{
log_error ("strtokenize failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
agent_exit (1);
}
for (nfdnames=0; fdnames[nfdnames]; nfdnames++)
;
}
else
{
fdnames = NULL;
nfdnames = 0;
}
/* Parse LISTEN_FDS into fd_count or provide a replacement. */
envvar = getenv ("LISTEN_FDS");
if (envvar)
fd_count = atoi (envvar);
else if (fdnames)
{
log_error ("no LISTEN_FDS environment variable found in --supervised"
" mode (relying on LISTEN_FDNAMES instead)\n");
fd_count = nfdnames;
}
else
{
log_error ("no LISTEN_FDS or LISTEN_FDNAMES environment variables "
"found in --supervised mode"
" (assuming 1 active descriptor)\n");
fd_count = 1;
}
if (fd_count < 1)
{
log_error ("--supervised mode expects at least one file descriptor"
" (was told %d, carrying on as though it were 1)\n",
fd_count);
fd_count = 1;
}
/* Assign the descriptors to the return values. */
if (!fdnames)
{
struct stat statbuf;
if (fd_count != 1)
log_error ("no LISTEN_FDNAMES and LISTEN_FDS (%d) != 1"
" in --supervised mode."
" (ignoring all sockets but the first one)\n",
fd_count);
if (fstat (3, &statbuf) == -1 && errno ==EBADF)
log_fatal ("file descriptor 3 must be valid in --supervised mode"
" if LISTEN_FDNAMES is not set\n");
*r_fd = 3;
socket_name = gnupg_get_socket_name (3);
}
else if (fd_count != nfdnames)
{
log_fatal ("number of items in LISTEN_FDNAMES (%d) does not match "
"LISTEN_FDS (%d) in --supervised mode\n",
nfdnames, fd_count);
}
else
{
int i, j, fd;
char *name;
for (i = 0; i < nfdnames; i++)
{
for (j = 0; j < DIM (tbl); j++)
{
if (!strcmp (fdnames[i], tbl[j].label) || j == DIM(tbl)-1)
{
fd = 3 + i;
if (**tbl[j].fdaddr == -1)
{
name = gnupg_get_socket_name (fd);
if (name)
{
**tbl[j].fdaddr = fd;
*tbl[j].nameaddr = name;
log_info ("using fd %d for %s socket (%s)\n",
fd, tbl[j].label, name);
}
else
{
log_error ("cannot listen on fd %d for %s socket\n",
fd, tbl[j].label);
close (fd);
}
}
else
{
log_error ("cannot listen on more than one %s socket\n",
tbl[j].label);
close (fd);
}
break;
}
}
}
}
xfree (fdnames);
}
#endif /*!HAVE_W32_SYSTEM*/
/* Cleanup code for this program. This is either called has an atexit
handler or directly. */
static void
cleanup (void)
{
static int done;
if (done)
return;
done = 1;
deinitialize_module_cache ();
if (!is_supervised && !inhibit_socket_removal)
{
remove_socket (socket_name, redir_socket_name);
if (opt.extra_socket > 1)
remove_socket (socket_name_extra, redir_socket_name_extra);
if (opt.browser_socket > 1)
remove_socket (socket_name_browser, redir_socket_name_browser);
remove_socket (socket_name_ssh, redir_socket_name_ssh);
}
}
/* Handle options which are allowed to be reset after program start.
Return true when the current option in PARGS could be handled and
false if not. As a special feature, passing a value of NULL for
PARGS, resets the options to the default. REREAD should be set
true if it is not the initial option parsing. */
static int
parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
{
int i;
if (!pargs)
{ /* reset mode */
opt.quiet = 0;
opt.verbose = 0;
opt.debug = 0;
opt.no_grab = 1;
opt.debug_pinentry = 0;
opt.pinentry_program = NULL;
opt.pinentry_touch_file = NULL;
xfree (opt.pinentry_invisible_char);
opt.pinentry_invisible_char = NULL;
opt.pinentry_timeout = 0;
opt.scdaemon_program = NULL;
opt.def_cache_ttl = DEFAULT_CACHE_TTL;
opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
opt.max_cache_ttl = MAX_CACHE_TTL;
opt.max_cache_ttl_ssh = MAX_CACHE_TTL_SSH;
opt.enforce_passphrase_constraints = 0;
opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
opt.check_passphrase_pattern = NULL;
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
opt.enable_passphrase_history = 0;
opt.enable_extended_key_format = 0;
opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1;
opt.allow_external_cache = 1;
opt.allow_loopback_pinentry = 1;
opt.allow_emacs_pinentry = 0;
opt.disable_scdaemon = 0;
disable_check_own_socket = 0;
/* Note: When changing the next line, change also gpgconf_list. */
opt.ssh_fingerprint_digest = GCRY_MD_MD5;
opt.s2k_count = 0;
return 1;
}
switch (pargs->r_opt)
{
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
case oDebug:
parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
break;
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs->r.ret_str; break;
case oDebugPinentry: opt.debug_pinentry = 1; break;
case oLogFile:
if (!reread)
return 0; /* not handeld */
if (!current_logfile || !pargs->r.ret_str
|| strcmp (current_logfile, pargs->r.ret_str))
{
log_set_file (pargs->r.ret_str);
xfree (current_logfile);
current_logfile = xtrystrdup (pargs->r.ret_str);
}
break;
case oNoGrab: opt.no_grab |= 1; break;
case oGrab: opt.no_grab |= 2; break;
case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
case oPinentryInvisibleChar:
xfree (opt.pinentry_invisible_char);
opt.pinentry_invisible_char = xtrystrdup (pargs->r.ret_str); break;
break;
case oPinentryTimeout: opt.pinentry_timeout = pargs->r.ret_ulong; break;
case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
case oDisableScdaemon: opt.disable_scdaemon = 1; break;
case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break;
case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break;
case oMaxCacheTTLSSH: opt.max_cache_ttl_ssh = pargs->r.ret_ulong; break;
case oEnforcePassphraseConstraints:
opt.enforce_passphrase_constraints=1;
break;
case oMinPassphraseLen: opt.min_passphrase_len = pargs->r.ret_ulong; break;
case oMinPassphraseNonalpha:
opt.min_passphrase_nonalpha = pargs->r.ret_ulong;
break;
case oCheckPassphrasePattern:
opt.check_passphrase_pattern = pargs->r.ret_str;
break;
case oMaxPassphraseDays:
opt.max_passphrase_days = pargs->r.ret_ulong;
break;
case oEnablePassphraseHistory:
opt.enable_passphrase_history = 1;
break;
case oEnableExtendedKeyFormat:
opt.enable_extended_key_format = 1;
break;
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
case oNoAllowMarkTrusted: opt.allow_mark_trusted = 0; break;
case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
case oAllowLoopbackPinentry: opt.allow_loopback_pinentry = 1; break;
case oNoAllowLoopbackPinentry: opt.allow_loopback_pinentry = 0; break;
case oNoAllowExternalCache: opt.allow_external_cache = 0;
break;
case oAllowEmacsPinentry: opt.allow_emacs_pinentry = 1;
break;
case oSSHFingerprintDigest:
i = gcry_md_map_name (pargs->r.ret_str);
if (!i)
log_error (_("selected digest algorithm is invalid\n"));
else
opt.ssh_fingerprint_digest = i;
break;
case oS2KCount:
opt.s2k_count = pargs->r.ret_ulong;
break;
default:
return 0; /* not handled */
}
return 1; /* handled */
}
/* Fixup some options after all have been processed. */
static void
finalize_rereadable_options (void)
{
/* Hack to allow --grab to override --no-grab. */
if ((opt.no_grab & 2))
opt.no_grab = 0;
}
static void
thread_init_once (void)
{
static int npth_initialized = 0;
if (!npth_initialized)
{
npth_initialized++;
npth_init ();
}
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Now that we have set the syscall clamp we need to tell Libgcrypt
* that it should get them from libgpg-error. Note that Libgcrypt
* has already been initialized but at that point nPth was not
* initialized and thus Libgcrypt could not set its system call
* clamp. */
#if GCRYPT_VERSION_NUMBER >= 0x010800 /* 1.8.0 */
gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
#endif
}
static void
initialize_modules (void)
{
thread_init_once ();
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
initialize_module_cache ();
initialize_module_call_pinentry ();
initialize_module_call_scd ();
initialize_module_trustlist ();
}
/* The main entry point. */
int
main (int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int orig_argc;
char **orig_argv;
FILE *configfp = NULL;
char *configname = NULL;
const char *shell;
unsigned configlineno;
int parse_debug = 0;
int default_config =1;
int pipe_server = 0;
int is_daemon = 0;
int nodetach = 0;
int csh_style = 0;
char *logfile = NULL;
int debug_wait = 0;
int gpgconf_list = 0;
gpg_error_t err;
struct assuan_malloc_hooks malloc_hooks;
early_system_init ();
/* Before we do anything else we save the list of currently open
file descriptors and the signal mask. This info is required to
do the exec call properly. We don't need it on Windows. */
#ifndef HAVE_W32_SYSTEM
startup_fd_list = get_all_open_fds ();
#endif /*!HAVE_W32_SYSTEM*/
#ifdef HAVE_SIGPROCMASK
if (!sigprocmask (SIG_UNBLOCK, NULL, &startup_signal_mask))
startup_signal_mask_valid = 1;
#endif /*HAVE_SIGPROCMASK*/
/* Set program name etc. */
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
/* Please note that we may running SUID(ROOT), so be very CAREFUL
when adding any stuff between here and the call to INIT_SECMEM()
somewhere after the option parsing */
log_set_prefix (GPG_AGENT_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_WITH_PID);
/* Make sure that our subsystems are ready. */
i18n_init ();
init_common_subsystems (&argc, &argv);
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_sock_init ();
assuan_sock_set_system_hooks (ASSUAN_SYSTEM_NPTH);
setup_libassuan_logging (&opt.debug, NULL);
setup_libgcrypt_logging ();
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
gcry_set_progress_handler (agent_libgcrypt_progress_cb, NULL);
disable_core_dumps ();
/* Set default options. */
parse_rereadable_options (NULL, 0); /* Reset them to default values. */
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1;
/* Record some of the original environment strings. */
{
const char *s;
int idx;
static const char *names[] =
{ "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
err = 0;
opt.startup_env = session_env_new ();
if (!opt.startup_env)
err = gpg_error_from_syserror ();
for (idx=0; !err && names[idx]; idx++)
{
s = getenv (names[idx]);
if (s)
err = session_env_setenv (opt.startup_env, names[idx], s);
}
if (!err)
{
s = gnupg_ttyname (0);
if (s)
err = session_env_setenv (opt.startup_env, "GPG_TTY", s);
}
if (err)
log_fatal ("error recording startup environment: %s\n",
gpg_strerror (err));
/* Fixme: Better use the locale function here. */
opt.startup_lc_ctype = getenv ("LC_CTYPE");
if (opt.startup_lc_ctype)
opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype);
opt.startup_lc_messages = getenv ("LC_MESSAGES");
if (opt.startup_lc_messages)
opt.startup_lc_messages = xstrdup (opt.startup_lc_messages);
}
/* Check whether we have a config file on the commandline */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
while (arg_parse( &pargs, opts))
{
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
parse_debug++;
else if (pargs.r_opt == oOptions)
{ /* yes there is one, so we do not try the default one, but
read the option file when it is encountered at the
commandline */
default_config = 0;
}
else if (pargs.r_opt == oNoOptions)
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
gnupg_set_homedir (pargs.r.ret_str);
else if (pargs.r_opt == oDebugQuickRandom)
{
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
}
}
/* Initialize the secure memory. */
gcry_control (GCRYCTL_INIT_SECMEM, SECMEM_BUFFER_SIZE, 0);
maybe_setuid = 0;
/*
Now we are now working under our real uid
*/
if (default_config)
configname = make_filename (gnupg_homedir (),
GPG_AGENT_NAME EXTSEP_S "conf", NULL);
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
next_pass:
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if( parse_debug )
log_info (_("Note: no default option file '%s'\n"),
configname );
/* Save the default conf file name so that
reread_configuration is able to test whether the
config file has been created in the meantime. */
xfree (config_filename);
config_filename = configname;
configname = NULL;
}
else
{
log_error (_("option file '%s': %s\n"),
configname, strerror(errno) );
exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname )
log_info (_("reading options from '%s'\n"), configname );
default_config = 0;
}
while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
{
if (parse_rereadable_options (&pargs, 0))
continue; /* Already handled */
switch (pargs.r_opt)
{
case aGPGConfList: gpgconf_list = 1; break;
case aGPGConfTest: gpgconf_list = 2; break;
case aUseStandardSocketP: gpgconf_list = 3; break;
case oBatch: opt.batch=1; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if (!configfp)
{
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoGreeting: /* Dummy option. */ break;
case oNoVerbose: opt.verbose = 0; break;
case oNoOptions: break; /* no-options */
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
case oNoDetach: nodetach = 1; break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; break;
case oServer: pipe_server = 1; break;
case oDaemon: is_daemon = 1; break;
case oSupervised: is_supervised = 1; break;
case oDisplay: default_display = xstrdup (pargs.r.ret_str); break;
case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break;
case oTTYtype: default_ttytype = xstrdup (pargs.r.ret_str); break;
case oLCctype: default_lc_ctype = xstrdup (pargs.r.ret_str); break;
case oLCmessages: default_lc_messages = xstrdup (pargs.r.ret_str);
break;
case oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
break;
case oUseStandardSocket:
case oNoUseStandardSocket:
obsolete_option (configname, configlineno, "use-standard-socket");
break;
case oFakedSystemTime:
{
time_t faked_time = isotime2epoch (pargs.r.ret_str);
if (faked_time == (time_t)(-1))
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
gnupg_set_time (faked_time, 0);
}
break;
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
case oSSHSupport:
ssh_support = 1;
break;
case oPuttySupport:
# ifdef HAVE_W32_SYSTEM
putty_support = 1;
# endif
break;
case oExtraSocket:
opt.extra_socket = 1; /* (1 = points into argv) */
socket_name_extra = pargs.r.ret_str;
break;
case oBrowserSocket:
opt.browser_socket = 1; /* (1 = points into argv) */
socket_name_browser = pargs.r.ret_str;
break;
case oAutoExpandSecmem:
/* Try to enable this option. It will officially only be
* supported by Libgcrypt 1.9 but 1.8.2 already supports it
* on the quiet and thus we use the numeric value value. */
gcry_control (78 /*GCRYCTL_AUTO_EXPAND_SECMEM*/,
(unsigned int)pargs.r.ret_ulong, 0);
break;
+ case oListenBacklog:
+ listen_backlog = pargs.r.ret_int;
+ break;
+
case oDebugQuickRandom:
/* Only used by the first stage command line parser. */
break;
case oWriteEnvFile:
obsolete_option (configname, configlineno, "write-env-file");
break;
default : pargs.err = configfp? 1:2; break;
}
}
if (configfp)
{
fclose( configfp );
configfp = NULL;
/* Keep a copy of the name so that it can be read on SIGHUP. */
if (config_filename != configname)
{
xfree (config_filename);
config_filename = configname;
}
configname = NULL;
goto next_pass;
}
xfree (configname);
configname = NULL;
if (log_get_errorcount(0))
exit(2);
finalize_rereadable_options ();
/* Print a warning if an argument looks like an option. */
if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
{
int i;
for (i=0; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == '-')
log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
}
#ifdef ENABLE_NLS
/* gpg-agent usually does not output any messages because it runs in
the background. For log files it is acceptable to have messages
always encoded in utf-8. We switch here to utf-8, so that
commands like --help still give native messages. It is far
easier to switch only once instead of for every message and it
actually helps when more then one thread is active (avoids an
extra copy step). */
bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
#endif
if (!pipe_server && !is_daemon && !gpgconf_list && !is_supervised)
{
/* We have been called without any command and thus we merely
check whether an agent is already running. We do this right
here so that we don't clobber a logfile with this check but
print the status directly to stderr. */
opt.debug = 0;
set_debug ();
check_for_running_agent (0);
agent_exit (0);
}
if (is_supervised)
;
else if (!opt.extra_socket)
opt.extra_socket = 1;
else if (socket_name_extra
&& (!strcmp (socket_name_extra, "none")
|| !strcmp (socket_name_extra, "/dev/null")))
{
/* User requested not to create this socket. */
opt.extra_socket = 0;
socket_name_extra = NULL;
}
if (is_supervised)
;
else if (!opt.browser_socket)
opt.browser_socket = 1;
else if (socket_name_browser
&& (!strcmp (socket_name_browser, "none")
|| !strcmp (socket_name_browser, "/dev/null")))
{
/* User requested not to create this socket. */
opt.browser_socket = 0;
socket_name_browser = NULL;
}
set_debug ();
if (atexit (cleanup))
{
log_error ("atexit failed\n");
cleanup ();
exit (1);
}
/* Try to create missing directories. */
create_directories ();
if (debug_wait && pipe_server)
{
thread_init_once ();
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}
if (gpgconf_list == 3)
{
/* We now use the standard socket always - return true for
backward compatibility. */
agent_exit (0);
}
else if (gpgconf_list == 2)
agent_exit (0);
else if (gpgconf_list)
{
char *filename;
char *filename_esc;
/* List options and default values in the GPG Conf format. */
filename = make_filename (gnupg_homedir (),
GPG_AGENT_NAME EXTSEP_S "conf", NULL);
filename_esc = percent_escape (filename, NULL);
es_printf ("%s-%s.conf:%lu:\"%s\n",
GPGCONF_NAME, GPG_AGENT_NAME,
GC_OPT_FLAG_DEFAULT, filename_esc);
xfree (filename);
xfree (filename_esc);
es_printf ("verbose:%lu:\n"
"quiet:%lu:\n"
"debug-level:%lu:\"none:\n"
"log-file:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME,
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME,
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME );
es_printf ("default-cache-ttl:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL );
es_printf ("default-cache-ttl-ssh:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL_SSH );
es_printf ("max-cache-ttl:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
es_printf ("max-cache-ttl-ssh:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL_SSH );
es_printf ("enforce-passphrase-constraints:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("min-passphrase-len:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
es_printf ("min-passphrase-nonalpha:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
MIN_PASSPHRASE_NONALPHA);
es_printf ("check-passphrase-pattern:%lu:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
es_printf ("max-passphrase-days:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
MAX_PASSPHRASE_DAYS);
es_printf ("enable-passphrase-history:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("no-grab:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("ignore-cache-for-signing:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("no-allow-external-cache:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("no-allow-mark-trusted:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("disable-scdaemon:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("ssh-fingerprint-digest:%lu:\"%s:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, "md5");
#ifdef HAVE_W32_SYSTEM
es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
#endif
es_printf ("no-allow-loopback-pinentry:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("allow-emacs-pinentry:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("pinentry-timeout:%lu:0:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
es_printf ("enable-extended-key-format:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("grab:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
agent_exit (0);
}
/* Now start with logging to a file if this is desired. */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
| GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID));
current_logfile = xstrdup (logfile);
}
/* Make sure that we have a default ttyname. */
if (!default_ttyname && gnupg_ttyname (1))
default_ttyname = xstrdup (gnupg_ttyname (1));
if (!default_ttytype && getenv ("TERM"))
default_ttytype = xstrdup (getenv ("TERM"));
if (pipe_server)
{
/* This is the simple pipe based server */
ctrl_t ctrl;
initialize_modules ();
ctrl = xtrycalloc (1, sizeof *ctrl);
if (!ctrl)
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
agent_exit (1);
}
ctrl->session_env = session_env_new ();
if (!ctrl->session_env)
{
log_error ("error allocating session environment block: %s\n",
strerror (errno) );
xfree (ctrl);
agent_exit (1);
}
agent_init_default_ctrl (ctrl);
start_command_handler (ctrl, GNUPG_INVALID_FD, GNUPG_INVALID_FD);
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
}
else if (is_supervised)
{
#ifndef HAVE_W32_SYSTEM
gnupg_fd_t fd, fd_extra, fd_browser, fd_ssh;
initialize_modules ();
/* when supervised and sending logs to stderr, the process
supervisor should handle log entry metadata (pid, name,
timestamp) */
if (!logfile)
log_set_prefix (NULL, 0);
log_info ("%s %s starting in supervised mode.\n",
strusage(11), strusage(13) );
/* See below in "regular server mode" on why we remove certain
* envvars. */
if (!opt.keep_display)
gnupg_unsetenv ("DISPLAY");
gnupg_unsetenv ("INSIDE_EMACS");
/* Virtually create the sockets. Note that we use -1 here
* because the whole thing works only on Unix. */
map_supervised_sockets (&fd, &fd_extra, &fd_browser, &fd_ssh);
if (fd == -1)
log_fatal ("no standard socket provided\n");
#ifdef HAVE_SIGPROCMASK
if (startup_signal_mask_valid)
{
if (sigprocmask (SIG_SETMASK, &startup_signal_mask, NULL))
log_error ("error restoring signal mask: %s\n",
strerror (errno));
}
else
log_info ("no saved signal mask\n");
#endif /*HAVE_SIGPROCMASK*/
log_info ("listening on: std=%d extra=%d browser=%d ssh=%d\n",
fd, fd_extra, fd_browser, fd_ssh);
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
#endif /*!HAVE_W32_SYSTEM*/
}
else if (!is_daemon)
; /* NOTREACHED */
else
{ /* Regular server mode */
gnupg_fd_t fd;
gnupg_fd_t fd_extra = GNUPG_INVALID_FD;
gnupg_fd_t fd_browser = GNUPG_INVALID_FD;
gnupg_fd_t fd_ssh = GNUPG_INVALID_FD;
#ifndef HAVE_W32_SYSTEM
pid_t pid;
#endif
/* Remove the DISPLAY variable so that a pinentry does not
default to a specific display. There is still a default
display when gpg-agent was started using --display or a
client requested this using an OPTION command. Note, that we
don't do this when running in reverse daemon mode (i.e. when
exec the program given as arguments). */
#ifndef HAVE_W32_SYSTEM
if (!opt.keep_display && !argc)
gnupg_unsetenv ("DISPLAY");
#endif
/* Remove the INSIDE_EMACS variable so that a pinentry does not
always try to interact with Emacs. The variable is set when
a client requested this using an OPTION command. */
gnupg_unsetenv ("INSIDE_EMACS");
/* Create the sockets. */
socket_name = create_socket_name (GPG_AGENT_SOCK_NAME, 1);
fd = create_server_socket (socket_name, 1, 0,
&redir_socket_name, &socket_nonce);
if (opt.extra_socket)
{
if (socket_name_extra)
socket_name_extra = create_socket_name (socket_name_extra, 0);
else
socket_name_extra = create_socket_name
/**/ (GPG_AGENT_EXTRA_SOCK_NAME, 1);
opt.extra_socket = 2; /* Indicate that it has been malloced. */
fd_extra = create_server_socket (socket_name_extra, 0, 0,
&redir_socket_name_extra,
&socket_nonce_extra);
}
if (opt.browser_socket)
{
if (socket_name_browser)
socket_name_browser = create_socket_name (socket_name_browser, 0);
else
socket_name_browser= create_socket_name
/**/ (GPG_AGENT_BROWSER_SOCK_NAME, 1);
opt.browser_socket = 2; /* Indicate that it has been malloced. */
fd_browser = create_server_socket (socket_name_browser, 0, 0,
&redir_socket_name_browser,
&socket_nonce_browser);
}
socket_name_ssh = create_socket_name (GPG_AGENT_SSH_SOCK_NAME, 1);
fd_ssh = create_server_socket (socket_name_ssh, 0, 1,
&redir_socket_name_ssh,
&socket_nonce_ssh);
/* If we are going to exec a program in the parent, we record
the PID, so that the child may check whether the program is
still alive. */
if (argc)
parent_pid = getpid ();
fflush (NULL);
#ifdef HAVE_W32_SYSTEM
(void)csh_style;
(void)nodetach;
initialize_modules ();
#else /*!HAVE_W32_SYSTEM*/
pid = fork ();
if (pid == (pid_t)-1)
{
log_fatal ("fork failed: %s\n", strerror (errno) );
exit (1);
}
else if (pid)
{ /* We are the parent */
char *infostr_ssh_sock, *infostr_ssh_valid;
/* Close the socket FD. */
close (fd);
/* The signal mask might not be correct right now and thus
we restore it. That is not strictly necessary but some
programs falsely assume a cleared signal mask. */
#ifdef HAVE_SIGPROCMASK
if (startup_signal_mask_valid)
{
if (sigprocmask (SIG_SETMASK, &startup_signal_mask, NULL))
log_error ("error restoring signal mask: %s\n",
strerror (errno));
}
else
log_info ("no saved signal mask\n");
#endif /*HAVE_SIGPROCMASK*/
/* Create the SSH info string if enabled. */
if (ssh_support)
{
if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
socket_name_ssh) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
exit (1);
}
if (asprintf (&infostr_ssh_valid, "gnupg_SSH_AUTH_SOCK_by=%lu",
(unsigned long)getpid()) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
exit (1);
}
}
*socket_name = 0; /* Don't let cleanup() remove the socket -
the child should do this from now on */
if (opt.extra_socket)
*socket_name_extra = 0;
if (opt.browser_socket)
*socket_name_browser = 0;
*socket_name_ssh = 0;
if (argc)
{ /* Run the program given on the commandline. */
if (ssh_support && (putenv (infostr_ssh_sock)
|| putenv (infostr_ssh_valid)))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
kill (pid, SIGTERM );
exit (1);
}
/* Close all the file descriptors except the standard
ones and those open at startup. We explicitly don't
close 0,1,2 in case something went wrong collecting
them at startup. */
close_all_fds (3, startup_fd_list);
/* Run the command. */
execvp (argv[0], argv);
log_error ("failed to run the command: %s\n", strerror (errno));
kill (pid, SIGTERM);
exit (1);
}
else
{
/* Print the environment string, so that the caller can use
shell's eval to set it */
if (csh_style)
{
if (ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
es_printf ("setenv %s;\n", infostr_ssh_sock);
}
}
else
{
if (ssh_support)
{
es_printf ("%s; export SSH_AUTH_SOCK;\n",
infostr_ssh_sock);
}
}
if (ssh_support)
{
xfree (infostr_ssh_sock);
xfree (infostr_ssh_valid);
}
exit (0);
}
/*NOTREACHED*/
} /* End parent */
/*
This is the child
*/
initialize_modules ();
/* Detach from tty and put process into a new session */
if (!nodetach )
{
int i;
unsigned int oldflags;
/* Close stdin, stdout and stderr unless it is the log stream */
for (i=0; i <= 2; i++)
{
if (!log_test_fd (i) && i != fd )
{
if ( ! close (i)
&& open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
{
log_error ("failed to open '%s': %s\n",
"/dev/null", strerror (errno));
cleanup ();
exit (1);
}
}
}
if (setsid() == -1)
{
log_error ("setsid() failed: %s\n", strerror(errno) );
cleanup ();
exit (1);
}
log_get_prefix (&oldflags);
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
opt.running_detached = 1;
/* Unless we are running with a program given on the command
* line we can assume that the inotify things works and thus
* we can avoid tye regular stat calls. */
if (!argc)
reliable_homedir_inotify = 1;
}
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
}
#endif /*!HAVE_W32_SYSTEM*/
if (gnupg_chdir (gnupg_daemon_rootdir ()))
{
log_error ("chdir to '%s' failed: %s\n",
gnupg_daemon_rootdir (), strerror (errno));
exit (1);
}
log_info ("%s %s started\n", strusage(11), strusage(13) );
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
assuan_sock_close (fd);
}
return 0;
}
/* Exit entry point. This function should be called instead of a
plain exit. */
void
agent_exit (int rc)
{
/*FIXME: update_random_seed_file();*/
/* We run our cleanup handler because that may close cipher contexts
stored in secure memory and thus this needs to be done before we
explicitly terminate secure memory. */
cleanup ();
#if 1
/* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE)
{
gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
#endif
gcry_control (GCRYCTL_TERM_SECMEM );
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit (rc);
}
/* This is our callback function for gcrypt progress messages. It is
set once at startup and dispatches progress messages to the
corresponding threads of the agent. */
static void
agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
int current, int total)
{
struct progress_dispatch_s *dispatch;
npth_t mytid = npth_self ();
(void)data;
for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
if (dispatch->ctrl && dispatch->tid == mytid)
break;
if (dispatch && dispatch->cb)
dispatch->cb (dispatch->ctrl, what, printchar, current, total);
/* Libgcrypt < 1.8 does not know about nPth and thus when it reads
* from /dev/random this will block the process. To mitigate this
* problem we yield the thread when Libgcrypt tells us that it needs
* more entropy. This way other threads have chance to run. */
#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */
if (what && !strcmp (what, "need_entropy"))
{
#if GPGRT_VERSION_NUMBER < 0x011900 /* 1.25 */
/* In older gpg-error versions gpgrt_yield is buggy for use with
* nPth and thus we need to resort to a sleep call. */
npth_usleep (1000); /* 1ms */
#else
gpgrt_yield ();
#endif
}
#endif
}
/* If a progress dispatcher callback has been associated with the
* current connection unregister it. */
static void
unregister_progress_cb (void)
{
struct progress_dispatch_s *dispatch;
npth_t mytid = npth_self ();
for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
if (dispatch->ctrl && dispatch->tid == mytid)
break;
if (dispatch)
{
dispatch->ctrl = NULL;
dispatch->cb = NULL;
}
}
/* Setup a progress callback CB for the current connection. Using a
* CB of NULL disables the callback. */
void
agent_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what,
int printchar, int current, int total),
ctrl_t ctrl)
{
struct progress_dispatch_s *dispatch, *firstfree;
npth_t mytid = npth_self ();
firstfree = NULL;
for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
{
if (dispatch->ctrl && dispatch->tid == mytid)
break;
if (!dispatch->ctrl && !firstfree)
firstfree = dispatch;
}
if (!dispatch) /* None allocated: Reuse or allocate a new one. */
{
if (firstfree)
{
dispatch = firstfree;
}
else if ((dispatch = xtrycalloc (1, sizeof *dispatch)))
{
dispatch->next = progress_dispatch_list;
progress_dispatch_list = dispatch;
}
else
{
log_error ("error allocating new progress dispatcher slot: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
return;
}
dispatch->ctrl = ctrl;
dispatch->tid = mytid;
}
dispatch->cb = cb;
}
/* Each thread has its own local variables conveyed by a control
structure usually identified by an argument named CTRL. This
function is called immediately after allocating the control
structure. Its purpose is to setup the default values for that
structure. Note that some values may have already been set. */
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
assert (ctrl->session_env);
/* Note we ignore malloc errors because we can't do much about it
and the request will fail anyway shortly after this
initialization. */
session_env_setenv (ctrl->session_env, "DISPLAY", default_display);
session_env_setenv (ctrl->session_env, "GPG_TTY", default_ttyname);
session_env_setenv (ctrl->session_env, "TERM", default_ttytype);
session_env_setenv (ctrl->session_env, "XAUTHORITY", default_xauthority);
session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", NULL);
if (ctrl->lc_ctype)
xfree (ctrl->lc_ctype);
ctrl->lc_ctype = default_lc_ctype? xtrystrdup (default_lc_ctype) : NULL;
if (ctrl->lc_messages)
xfree (ctrl->lc_messages);
ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
/**/ : NULL;
ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
}
/* Release all resources allocated by default in the control
structure. This is the counterpart to agent_init_default_ctrl. */
static void
agent_deinit_default_ctrl (ctrl_t ctrl)
{
unregister_progress_cb ();
session_env_release (ctrl->session_env);
if (ctrl->lc_ctype)
xfree (ctrl->lc_ctype);
if (ctrl->lc_messages)
xfree (ctrl->lc_messages);
}
/* Because the ssh protocol does not send us information about the
current TTY setting, we use this function to use those from startup
or those explicitly set. This is also used for the restricted mode
where we ignore requests to change the environment. */
gpg_error_t
agent_copy_startup_env (ctrl_t ctrl)
{
static const char *names[] =
{"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL};
gpg_error_t err = 0;
int idx;
const char *value;
for (idx=0; !err && names[idx]; idx++)
if ((value = session_env_getenv (opt.startup_env, names[idx])))
err = session_env_setenv (ctrl->session_env, names[idx], value);
if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
err = gpg_error_from_syserror ();
if (!err && !ctrl->lc_messages && opt.startup_lc_messages)
if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages)))
err = gpg_error_from_syserror ();
if (err)
log_error ("error setting default session environment: %s\n",
gpg_strerror (err));
return err;
}
/* Reread parts of the configuration. Note, that this function is
obviously not thread-safe and should only be called from the PTH
signal handler.
Fixme: Due to the way the argument parsing works, we create a
memory leak here for all string type arguments. There is currently
no clean way to tell whether the memory for the argument has been
allocated or points into the process' original arguments. Unless
we have a mechanism to tell this, we need to live on with this. */
static void
reread_configuration (void)
{
ARGPARSE_ARGS pargs;
FILE *fp;
unsigned int configlineno = 0;
int dummy;
if (!config_filename)
return; /* No config file. */
fp = fopen (config_filename, "r");
if (!fp)
{
log_info (_("option file '%s': %s\n"),
config_filename, strerror(errno) );
return;
}
parse_rereadable_options (NULL, 1); /* Start from the default values. */
memset (&pargs, 0, sizeof pargs);
dummy = 0;
pargs.argc = &dummy;
pargs.flags = 1; /* do not remove the args */
while (optfile_parse (fp, config_filename, &configlineno, &pargs, opts) )
{
if (pargs.r_opt < -1)
pargs.err = 1; /* Print a warning. */
else /* Try to parse this option - ignore unchangeable ones. */
parse_rereadable_options (&pargs, 1);
}
fclose (fp);
finalize_rereadable_options ();
set_debug ();
}
/* Return the file name of the socket we are using for native
requests. */
const char *
get_agent_socket_name (void)
{
const char *s = socket_name;
return (s && *s)? s : NULL;
}
/* Return the file name of the socket we are using for SSH
requests. */
const char *
get_agent_ssh_socket_name (void)
{
const char *s = socket_name_ssh;
return (s && *s)? s : NULL;
}
/* Return the number of active connections. */
int
get_agent_active_connection_count (void)
{
return active_connections;
}
/* Under W32, this function returns the handle of the scdaemon
notification event. Calling it the first time creates that
event. */
#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
void *
get_agent_scd_notify_event (void)
{
static HANDLE the_event = INVALID_HANDLE_VALUE;
if (the_event == INVALID_HANDLE_VALUE)
{
HANDLE h, h2;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
/* We need to use a manual reset event object due to the way our
w32-pth wait function works: If we would use an automatic
reset event we are not able to figure out which handle has
been signaled because at the time we single out the signaled
handles using WFSO the event has already been reset due to
the WFMO. */
h = CreateEvent (&sa, TRUE, FALSE, NULL);
if (!h)
log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
else if (!DuplicateHandle (GetCurrentProcess(), h,
GetCurrentProcess(), &h2,
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
{
log_error ("setting syncronize for scd notify event failed: %s\n",
w32_strerror (-1) );
CloseHandle (h);
}
else
{
CloseHandle (h);
the_event = h2;
}
}
return the_event;
}
#endif /*HAVE_W32_SYSTEM && !HAVE_W32CE_SYSTEM*/
/* Create a name for the socket in the home directory as using
STANDARD_NAME. We also check for valid characters as well as
against a maximum allowed length for a unix domain socket is done.
The function terminates the process in case of an error. Returns:
Pointer to an allocated string with the absolute name of the socket
used. */
static char *
create_socket_name (char *standard_name, int with_homedir)
{
char *name;
if (with_homedir)
name = make_filename (gnupg_socketdir (), standard_name, NULL);
else
name = make_filename (standard_name, NULL);
if (strchr (name, PATHSEP_C))
{
log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
agent_exit (2);
}
return name;
}
/* Create a Unix domain socket with NAME. Returns the file descriptor
or terminates the process in case of an error. Note that this
function needs to be used for the regular socket first (indicated
by PRIMARY) and only then for the extra and the ssh sockets. If
the socket has been redirected the name of the real socket is
stored as a malloced string at R_REDIR_NAME. If CYGWIN is set a
Cygwin compatible socket is created (Windows only). */
static gnupg_fd_t
create_server_socket (char *name, int primary, int cygwin,
char **r_redir_name, assuan_sock_nonce_t *nonce)
{
struct sockaddr *addr;
struct sockaddr_un *unaddr;
socklen_t len;
gnupg_fd_t fd;
int rc;
xfree (*r_redir_name);
*r_redir_name = NULL;
fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
agent_exit (2);
}
if (cygwin)
assuan_sock_set_flag (fd, "cygwin", 1);
unaddr = xmalloc (sizeof *unaddr);
addr = (struct sockaddr*)unaddr;
{
int redirected;
if (assuan_sock_set_sockaddr_un (name, addr, &redirected))
{
if (errno == ENAMETOOLONG)
log_error (_("socket name '%s' is too long\n"), name);
else
log_error ("error preparing socket '%s': %s\n",
name, gpg_strerror (gpg_error_from_syserror ()));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
xfree (unaddr);
agent_exit (2);
}
if (redirected)
{
*r_redir_name = xstrdup (unaddr->sun_path);
if (opt.verbose)
log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
}
}
len = SUN_LEN (unaddr);
rc = assuan_sock_bind (fd, addr, len);
/* Our error code mapping on W32CE returns EEXIST thus we also test
for this. */
if (rc == -1
&& (errno == EADDRINUSE
#ifdef HAVE_W32_SYSTEM
|| errno == EEXIST
#endif
))
{
/* Check whether a gpg-agent is already running. We do this
test only if this is the primary socket. For secondary
sockets we assume that a test for gpg-agent has already been
done and reuse the requested socket. Testing the ssh-socket
is not possible because at this point, though we know the new
Assuan socket, the Assuan server and thus the ssh-agent
server is not yet operational; this would lead to a hang. */
if (primary && !check_for_running_agent (1))
{
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX);
log_set_file (NULL);
log_error (_("a gpg-agent is already running - "
"not starting a new one\n"));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
assuan_sock_close (fd);
xfree (unaddr);
agent_exit (2);
}
gnupg_remove (unaddr->sun_path);
rc = assuan_sock_bind (fd, addr, len);
}
if (rc != -1 && (rc=assuan_sock_get_nonce (addr, len, nonce)))
log_error (_("error getting nonce for the socket\n"));
if (rc == -1)
{
/* We use gpg_strerror here because it allows us to get strings
for some W32 socket error codes. */
log_error (_("error binding socket to '%s': %s\n"),
unaddr->sun_path,
gpg_strerror (gpg_error_from_syserror ()));
assuan_sock_close (fd);
*name = 0; /* Inhibit removal of the socket by cleanup(). */
xfree (unaddr);
agent_exit (2);
}
if (gnupg_chmod (unaddr->sun_path, "-rwx"))
log_error (_("can't set permissions of '%s': %s\n"),
unaddr->sun_path, strerror (errno));
- if (listen (FD2INT(fd), 5 ) == -1)
+ if (listen (FD2INT(fd), listen_backlog ) == -1)
{
- log_error (_("listen() failed: %s\n"), strerror (errno));
+ log_error ("listen(fd,%d) failed: %s\n",
+ listen_backlog, strerror (errno));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
assuan_sock_close (fd);
xfree (unaddr);
agent_exit (2);
}
if (opt.verbose)
log_info (_("listening on socket '%s'\n"), unaddr->sun_path);
xfree (unaddr);
return fd;
}
/* Check that the directory for storing the private keys exists and
create it if not. This function won't fail as it is only a
convenience function and not strictly necessary. */
static void
create_private_keys_directory (const char *home)
{
char *fname;
struct stat statbuf;
fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL);
if (stat (fname, &statbuf) && errno == ENOENT)
{
if (gnupg_mkdir (fname, "-rwx"))
log_error (_("can't create directory '%s': %s\n"),
fname, strerror (errno) );
else if (!opt.quiet)
log_info (_("directory '%s' created\n"), fname);
}
if (gnupg_chmod (fname, "-rwx"))
log_error (_("can't set permissions of '%s': %s\n"),
fname, strerror (errno));
xfree (fname);
}
/* Create the directory only if the supplied directory name is the
same as the default one. This way we avoid to create arbitrary
directories when a non-default home directory is used. To cope
with HOME, we compare only the suffix if we see that the default
homedir does start with a tilde. We don't stop here in case of
problems because other functions will throw an error anyway.*/
static void
create_directories (void)
{
struct stat statbuf;
const char *defhome = standard_homedir ();
char *home;
home = make_filename (gnupg_homedir (), NULL);
if ( stat (home, &statbuf) )
{
if (errno == ENOENT)
{
if (
#ifdef HAVE_W32_SYSTEM
( !compare_filenames (home, defhome) )
#else
(*defhome == '~'
&& (strlen (home) >= strlen (defhome+1)
&& !strcmp (home + strlen(home)
- strlen (defhome+1), defhome+1)))
|| (*defhome != '~' && !strcmp (home, defhome) )
#endif
)
{
if (gnupg_mkdir (home, "-rwx"))
log_error (_("can't create directory '%s': %s\n"),
home, strerror (errno) );
else
{
if (!opt.quiet)
log_info (_("directory '%s' created\n"), home);
create_private_keys_directory (home);
}
}
}
else
log_error (_("stat() failed for '%s': %s\n"), home, strerror (errno));
}
else if ( !S_ISDIR(statbuf.st_mode))
{
log_error (_("can't use '%s' as home directory\n"), home);
}
else /* exists and is a directory. */
{
create_private_keys_directory (home);
}
xfree (home);
}
/* This is the worker for the ticker. It is called every few seconds
and may only do fast operations. */
static void
handle_tick (void)
{
static time_t last_minute;
struct stat statbuf;
if (!last_minute)
last_minute = time (NULL);
/* Check whether the scdaemon has died and cleanup in this case. */
agent_scd_check_aliveness ();
/* If we are running as a child of another process, check whether
the parent is still alive and shutdown if not. */
#ifndef HAVE_W32_SYSTEM
if (parent_pid != (pid_t)(-1))
{
if (kill (parent_pid, 0))
{
shutdown_pending = 2;
log_info ("parent process died - shutting down\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
agent_exit (0);
}
}
#endif /*HAVE_W32_SYSTEM*/
/* Code to be run from time to time. */
#if CHECK_OWN_SOCKET_INTERVAL > 0
if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
{
check_own_socket ();
last_minute = time (NULL);
}
#endif
/* Check whether the homedir is still available. */
if (!shutdown_pending
&& (!have_homedir_inotify || !reliable_homedir_inotify)
&& stat (gnupg_homedir (), &statbuf) && errno == ENOENT)
{
shutdown_pending = 1;
log_info ("homedir has been removed - shutting down\n");
}
}
/* A global function which allows us to call the reload stuff from
other places too. This is only used when build for W32. */
void
agent_sighup_action (void)
{
log_info ("SIGHUP received - "
"re-reading configuration and flushing cache\n");
agent_flush_cache ();
reread_configuration ();
agent_reload_trustlist ();
/* We flush the module name cache so that after installing a
"pinentry" binary that one can be used in case the
"pinentry-basic" fallback was in use. */
gnupg_module_name_flush_some ();
}
/* A helper function to handle SIGUSR2. */
static void
agent_sigusr2_action (void)
{
if (opt.verbose)
log_info ("SIGUSR2 received - updating card event counter\n");
/* Nothing to check right now. We only increment a counter. */
bump_card_eventcounter ();
}
#ifndef HAVE_W32_SYSTEM
/* The signal handler for this program. It is expected to be run in
its own thread and not in the context of a signal handler. */
static void
handle_signal (int signo)
{
switch (signo)
{
#ifndef HAVE_W32_SYSTEM
case SIGHUP:
agent_sighup_action ();
break;
case SIGUSR1:
log_info ("SIGUSR1 received - printing internal information:\n");
/* Fixme: We need to see how to integrate pth dumping into our
logging system. */
/* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
agent_query_dump_state ();
agent_scd_dump_state ();
break;
case SIGUSR2:
agent_sigusr2_action ();
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
log_info ("SIGTERM received - still %i open connections\n",
active_connections);
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info ("shutdown forced\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
agent_exit (0);
}
break;
case SIGINT:
log_info ("SIGINT received - immediate shutdown\n");
log_info( "%s %s stopped\n", strusage(11), strusage(13));
cleanup ();
agent_exit (0);
break;
#endif
default:
log_info ("signal %d received - no action defined\n", signo);
}
}
#endif
/* Check the nonce on a new connection. This is a NOP unless we
are using our Unix domain socket emulation under Windows. */
static int
check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
{
if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
{
log_info (_("error reading nonce on fd %d: %s\n"),
FD2INT(ctrl->thread_startup.fd), strerror (errno));
assuan_sock_close (ctrl->thread_startup.fd);
xfree (ctrl);
return -1;
}
else
return 0;
}
#ifdef HAVE_W32_SYSTEM
/* The window message processing function for Putty. Warning: This
code runs as a native Windows thread. Use of our own functions
needs to be bracket with pth_leave/pth_enter. */
static LRESULT CALLBACK
putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
int ret = 0;
int w32rc;
COPYDATASTRUCT *cds;
const char *mapfile;
HANDLE maphd;
PSID mysid = NULL;
PSID mapsid = NULL;
void *data = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
ctrl_t ctrl = NULL;
if (msg != WM_COPYDATA)
{
return DefWindowProc (hwnd, msg, wparam, lparam);
}
cds = (COPYDATASTRUCT*)lparam;
if (cds->dwData != PUTTY_IPC_MAGIC)
return 0; /* Ignore data with the wrong magic. */
mapfile = cds->lpData;
if (!cds->cbData || mapfile[cds->cbData - 1])
return 0; /* Ignore empty and non-properly terminated strings. */
if (DBG_IPC)
{
npth_protect ();
log_debug ("ssh map file '%s'", mapfile);
npth_unprotect ();
}
maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
if (DBG_IPC)
{
npth_protect ();
log_debug ("ssh map handle %p\n", maphd);
npth_unprotect ();
}
if (!maphd || maphd == INVALID_HANDLE_VALUE)
return 0;
npth_protect ();
mysid = w32_get_user_sid ();
if (!mysid)
{
log_error ("error getting my sid\n");
goto leave;
}
w32rc = GetSecurityInfo (maphd, SE_KERNEL_OBJECT,
OWNER_SECURITY_INFORMATION,
&mapsid, NULL, NULL, NULL,
&psd);
if (w32rc)
{
log_error ("error getting sid of ssh map file: rc=%d", w32rc);
goto leave;
}
if (DBG_IPC)
{
char *sidstr;
if (!ConvertSidToStringSid (mysid, &sidstr))
sidstr = NULL;
log_debug (" my sid: '%s'", sidstr? sidstr: "[error]");
LocalFree (sidstr);
if (!ConvertSidToStringSid (mapsid, &sidstr))
sidstr = NULL;
log_debug ("ssh map file sid: '%s'", sidstr? sidstr: "[error]");
LocalFree (sidstr);
}
if (!EqualSid (mysid, mapsid))
{
log_error ("ssh map file has a non-matching sid\n");
goto leave;
}
data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (DBG_IPC)
log_debug ("ssh IPC buffer at %p\n", data);
if (!data)
goto leave;
/* log_printhex ("request:", data, 20); */
ctrl = xtrycalloc (1, sizeof *ctrl);
if (!ctrl)
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
goto leave;
}
ctrl->session_env = session_env_new ();
if (!ctrl->session_env)
{
log_error ("error allocating session environment block: %s\n",
strerror (errno) );
goto leave;
}
agent_init_default_ctrl (ctrl);
if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN))
ret = 1; /* Valid ssh message has been constructed. */
agent_deinit_default_ctrl (ctrl);
/* log_printhex (" reply:", data, 20); */
leave:
xfree (ctrl);
if (data)
UnmapViewOfFile (data);
xfree (mapsid);
if (psd)
LocalFree (psd);
xfree (mysid);
CloseHandle (maphd);
npth_unprotect ();
return ret;
}
#endif /*HAVE_W32_SYSTEM*/
#ifdef HAVE_W32_SYSTEM
/* The thread handling Putty's IPC requests. */
static void *
putty_message_thread (void *arg)
{
WNDCLASS wndwclass = {0, putty_message_proc, 0, 0,
NULL, NULL, NULL, NULL, NULL, "Pageant"};
HWND hwnd;
MSG msg;
(void)arg;
if (opt.verbose)
log_info ("putty message loop thread started\n");
/* The message loop runs as thread independent from our nPth system.
This also means that we need to make sure that we switch back to
our system before calling any no-windows function. */
npth_unprotect ();
/* First create a window to make sure that a message queue exists
for this thread. */
if (!RegisterClass (&wndwclass))
{
npth_protect ();
log_error ("error registering Pageant window class");
return NULL;
}
hwnd = CreateWindowEx (0, "Pageant", "Pageant", 0,
0, 0, 0, 0,
HWND_MESSAGE, /* hWndParent */
NULL, /* hWndMenu */
NULL, /* hInstance */
NULL); /* lpParm */
if (!hwnd)
{
npth_protect ();
log_error ("error creating Pageant window");
return NULL;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* Back to nPth. */
npth_protect ();
if (opt.verbose)
log_info ("putty message loop thread stopped\n");
return NULL;
}
#endif /*HAVE_W32_SYSTEM*/
static void *
do_start_connection_thread (ctrl_t ctrl)
{
active_connections++;
agent_init_default_ctrl (ctrl);
if (opt.verbose && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d started\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
if (opt.verbose && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d terminated\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
active_connections--;
return NULL;
}
/* This is the standard connection thread's main function. */
static void *
start_connection_thread_std (void *arg)
{
ctrl_t ctrl = arg;
if (check_nonce (ctrl, &socket_nonce))
{
log_error ("handler 0x%lx nonce check FAILED\n",
(unsigned long) npth_self());
return NULL;
}
return do_start_connection_thread (ctrl);
}
/* This is the extra socket connection thread's main function. */
static void *
start_connection_thread_extra (void *arg)
{
ctrl_t ctrl = arg;
if (check_nonce (ctrl, &socket_nonce_extra))
{
log_error ("handler 0x%lx nonce check FAILED\n",
(unsigned long) npth_self());
return NULL;
}
ctrl->restricted = 1;
return do_start_connection_thread (ctrl);
}
/* This is the browser socket connection thread's main function. */
static void *
start_connection_thread_browser (void *arg)
{
ctrl_t ctrl = arg;
if (check_nonce (ctrl, &socket_nonce_browser))
{
log_error ("handler 0x%lx nonce check FAILED\n",
(unsigned long) npth_self());
return NULL;
}
ctrl->restricted = 2;
return do_start_connection_thread (ctrl);
}
/* This is the ssh connection thread's main function. */
static void *
start_connection_thread_ssh (void *arg)
{
ctrl_t ctrl = arg;
if (check_nonce (ctrl, &socket_nonce_ssh))
return NULL;
active_connections++;
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d started\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
active_connections--;
return NULL;
}
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh)
{
gpg_error_t err;
npth_attr_t tattr;
struct sockaddr_un paddr;
socklen_t plen;
fd_set fdset, read_fdset;
int ret;
gnupg_fd_t fd;
int nfd;
int saved_errno;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
#ifdef HAVE_W32_SYSTEM
HANDLE events[2];
unsigned int events_set;
#endif
int sock_inotify_fd = -1;
int home_inotify_fd = -1;
struct {
const char *name;
void *(*func) (void *arg);
gnupg_fd_t l_fd;
} listentbl[] = {
{ "std", start_connection_thread_std },
{ "extra", start_connection_thread_extra },
{ "browser", start_connection_thread_browser },
{ "ssh", start_connection_thread_ssh }
};
ret = npth_attr_init(&tattr);
if (ret)
log_fatal ("error allocating thread attributes: %s\n",
strerror (ret));
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
#ifndef HAVE_W32_SYSTEM
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
#else
# ifdef HAVE_W32CE_SYSTEM
/* Use a dummy event. */
sigs = 0;
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
# else
events[0] = get_agent_scd_notify_event ();
events[1] = INVALID_HANDLE_VALUE;
# endif
#endif
if (disable_check_own_socket)
sock_inotify_fd = -1;
else if ((err = gnupg_inotify_watch_socket (&sock_inotify_fd, socket_name)))
{
if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
log_info ("error enabling daemon termination by socket removal: %s\n",
gpg_strerror (err));
}
if (disable_check_own_socket)
home_inotify_fd = -1;
else if ((err = gnupg_inotify_watch_delete_self (&home_inotify_fd,
gnupg_homedir ())))
{
if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
log_info ("error enabling daemon termination by homedir removal: %s\n",
gpg_strerror (err));
}
else
have_homedir_inotify = 1;
/* On Windows we need to fire up a separate thread to listen for
requests from Putty (an SSH client), so we can replace Putty's
Pageant (its ssh-agent implementation). */
#ifdef HAVE_W32_SYSTEM
if (putty_support)
{
npth_t thread;
ret = npth_create (&thread, &tattr, putty_message_thread, NULL);
if (ret)
{
log_error ("error spawning putty message loop: %s\n", strerror (ret));
}
}
#endif /*HAVE_W32_SYSTEM*/
/* Set a flag to tell call-scd.c that it may enable event
notifications. */
opt.sigusr2_enabled = 1;
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
if (listen_fd_extra != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_extra), &fdset);
if (FD2INT (listen_fd_extra) > nfd)
nfd = FD2INT (listen_fd_extra);
}
if (listen_fd_browser != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_browser), &fdset);
if (FD2INT (listen_fd_browser) > nfd)
nfd = FD2INT (listen_fd_browser);
}
if (listen_fd_ssh != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
if (FD2INT (listen_fd_ssh) > nfd)
nfd = FD2INT (listen_fd_ssh);
}
if (sock_inotify_fd != -1)
{
FD_SET (sock_inotify_fd, &fdset);
if (sock_inotify_fd > nfd)
nfd = sock_inotify_fd;
}
if (home_inotify_fd != -1)
{
FD_SET (home_inotify_fd, &fdset);
if (home_inotify_fd > nfd)
nfd = home_inotify_fd;
}
listentbl[0].l_fd = listen_fd;
listentbl[1].l_fd = listen_fd_extra;
listentbl[2].l_fd = listen_fd_browser;
listentbl[3].l_fd = listen_fd_ssh;
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
for (;;)
{
/* Shutdown test. */
if (shutdown_pending)
{
if (active_connections == 0)
break; /* ready */
/* Do not accept new connections but keep on running the
* loop to cope with the timer events.
*
* Note that we do not close the listening socket because a
* client trying to connect to that socket would instead
* restart a new dirmngr instance - which is unlikely the
* intention of a shutdown. */
FD_ZERO (&fdset);
nfd = -1;
if (sock_inotify_fd != -1)
{
FD_SET (sock_inotify_fd, &fdset);
nfd = sock_inotify_fd;
}
if (home_inotify_fd != -1)
{
FD_SET (home_inotify_fd, &fdset);
if (home_inotify_fd > nfd)
nfd = home_inotify_fd;
}
}
/* POSIX says that fd_set should be implemented as a structure,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
/* Timeout. */
handle_tick ();
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
}
npth_timersub (&abstime, &curtime, &timeout);
#ifndef HAVE_W32_SYSTEM
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
npth_sigev_sigmask ());
saved_errno = errno;
{
int signo;
while (npth_sigev_get_pending (&signo))
handle_signal (signo);
}
#else
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
events, &events_set);
saved_errno = errno;
/* This is valid even if npth_eselect returns an error. */
if (events_set & 1)
agent_sigusr2_action ();
#endif
if (ret == -1 && saved_errno != EINTR)
{
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
strerror (saved_errno));
npth_sleep (1);
continue;
}
if (ret <= 0)
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
/* The inotify fds are set even when a shutdown is pending (see
* above). So we must handle them in any case. To avoid that
* they trigger a second time we close them immediately. */
if (sock_inotify_fd != -1
&& FD_ISSET (sock_inotify_fd, &read_fdset)
&& gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
{
shutdown_pending = 1;
close (sock_inotify_fd);
sock_inotify_fd = -1;
log_info ("socket file has been removed - shutting down\n");
}
if (home_inotify_fd != -1
&& FD_ISSET (home_inotify_fd, &read_fdset))
{
shutdown_pending = 1;
close (home_inotify_fd);
home_inotify_fd = -1;
log_info ("homedir has been removed - shutting down\n");
}
if (!shutdown_pending)
{
int idx;
ctrl_t ctrl;
npth_t thread;
for (idx=0; idx < DIM(listentbl); idx++)
{
if (listentbl[idx].l_fd == GNUPG_INVALID_FD)
continue;
if (!FD_ISSET (FD2INT (listentbl[idx].l_fd), &read_fdset))
continue;
plen = sizeof paddr;
fd = INT2FD (npth_accept (FD2INT(listentbl[idx].l_fd),
(struct sockaddr *)&paddr, &plen));
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed for %s: %s\n",
listentbl[idx].name, strerror (errno));
}
else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)))
{
log_error ("error allocating connection data for %s: %s\n",
listentbl[idx].name, strerror (errno) );
assuan_sock_close (fd);
}
else if ( !(ctrl->session_env = session_env_new ()))
{
log_error ("error allocating session env block for %s: %s\n",
listentbl[idx].name, strerror (errno) );
xfree (ctrl);
assuan_sock_close (fd);
}
else
{
ctrl->thread_startup.fd = fd;
ret = npth_create (&thread, &tattr,
listentbl[idx].func, ctrl);
if (ret)
{
log_error ("error spawning connection handler for %s:"
" %s\n", listentbl[idx].name, strerror (ret));
assuan_sock_close (fd);
xfree (ctrl);
}
}
}
}
}
if (sock_inotify_fd != -1)
close (sock_inotify_fd);
if (home_inotify_fd != -1)
close (home_inotify_fd);
cleanup ();
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
npth_attr_destroy (&tattr);
}
/* Helper for check_own_socket. */
static gpg_error_t
check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
{
membuf_t *mb = opaque;
put_membuf (mb, buffer, length);
return 0;
}
/* The thread running the actual check. We need to run this in a
separate thread so that check_own_thread can be called from the
timer tick. */
static void *
check_own_socket_thread (void *arg)
{
int rc;
char *sockname = arg;
assuan_context_t ctx = NULL;
membuf_t mb;
char *buffer;
check_own_socket_running++;
rc = assuan_new (&ctx);
if (rc)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
goto leave;
}
assuan_set_flag (ctx, ASSUAN_NO_LOGGING, 1);
rc = assuan_socket_connect (ctx, sockname, (pid_t)(-1), 0);
if (rc)
{
log_error ("can't connect my own socket: %s\n", gpg_strerror (rc));
goto leave;
}
init_membuf (&mb, 100);
rc = assuan_transact (ctx, "GETINFO pid", check_own_socket_pid_cb, &mb,
NULL, NULL, NULL, NULL);
put_membuf (&mb, "", 1);
buffer = get_membuf (&mb, NULL);
if (rc || !buffer)
{
log_error ("sending command \"%s\" to my own socket failed: %s\n",
"GETINFO pid", gpg_strerror (rc));
rc = 1;
}
else if ( (pid_t)strtoul (buffer, NULL, 10) != getpid ())
{
log_error ("socket is now serviced by another server\n");
rc = 1;
}
else if (opt.verbose > 1)
log_error ("socket is still served by this server\n");
xfree (buffer);
leave:
xfree (sockname);
if (ctx)
assuan_release (ctx);
if (rc)
{
/* We may not remove the socket as it is now in use by another
server. */
inhibit_socket_removal = 1;
shutdown_pending = 2;
log_info ("this process is useless - shutting down\n");
}
check_own_socket_running--;
return NULL;
}
/* Check whether we are still listening on our own socket. In case
another gpg-agent process started after us has taken ownership of
our socket, we would linger around without any real task. Thus we
better check once in a while whether we are really needed. */
static void
check_own_socket (void)
{
char *sockname;
npth_t thread;
npth_attr_t tattr;
int err;
if (disable_check_own_socket)
return;
if (check_own_socket_running || shutdown_pending)
return; /* Still running or already shutting down. */
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
if (!sockname)
return; /* Out of memory. */
err = npth_attr_init (&tattr);
if (err)
return;
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
err = npth_create (&thread, &tattr, check_own_socket_thread, sockname);
if (err)
log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
npth_attr_destroy (&tattr);
}
/* Figure out whether an agent is available and running. Prints an
error if not. If SILENT is true, no messages are printed.
Returns 0 if the agent is running. */
static int
check_for_running_agent (int silent)
{
gpg_error_t err;
char *sockname;
assuan_context_t ctx = NULL;
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
if (!sockname)
return gpg_error_from_syserror ();
err = assuan_new (&ctx);
if (!err)
err = assuan_socket_connect (ctx, sockname, (pid_t)(-1), 0);
xfree (sockname);
if (err)
{
if (!silent)
log_error (_("no gpg-agent running in this session\n"));
if (ctx)
assuan_release (ctx);
return -1;
}
if (!opt.quiet && !silent)
log_info ("gpg-agent running and available\n");
assuan_release (ctx);
return 0;
}
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 9cb02036e..17adae2f4 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -1,2320 +1,2331 @@
/* dirmngr.c - Keyserver and X.509 LDAP access
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH
* Copyright (C) 2014 Werner Koch
*
* 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 .
*
* SPDX-License-Identifier: GPL-3.0+
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef HAVE_W32_SYSTEM
#include
#include
#endif
#include
#include
#ifdef HAVE_SIGNAL_H
# include
#endif
#ifdef HAVE_INOTIFY_INIT
# include
#endif /*HAVE_INOTIFY_INIT*/
#include
#include "dirmngr-err.h"
#if HTTP_USE_NTBTLS
# include
#elif HTTP_USE_GNUTLS
# include
#endif /*HTTP_USE_GNUTLS*/
#define GNUPG_COMMON_NEED_AFLOCAL
#include "dirmngr.h"
#include
#include "certcache.h"
#include "crlcache.h"
#include "crlfetch.h"
#include "misc.h"
#if USE_LDAP
# include "ldapserver.h"
#endif
#include "../common/asshelp.h"
#if USE_LDAP
# include "ldap-wrapper.h"
#endif
#include "../common/init.h"
#include "../common/gc-opt-flags.h"
#include "dns-stuff.h"
#include "http-common.h"
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
enum cmd_and_opt_values {
aNull = 0,
oCsh = 'c',
oQuiet = 'q',
oSh = 's',
oVerbose = 'v',
oNoVerbose = 500,
aServer,
aDaemon,
aSupervised,
aListCRLs,
aLoadCRL,
aFetchCRL,
aShutdown,
aFlush,
aGPGConfList,
aGPGConfTest,
oOptions,
oDebug,
oDebugAll,
oDebugWait,
oDebugLevel,
oGnutlsDebug,
oNoGreeting,
oNoOptions,
oHomedir,
oNoDetach,
oLogFile,
oBatch,
oDisableHTTP,
oDisableLDAP,
oDisableIPv4,
oDisableIPv6,
oIgnoreLDAPDP,
oIgnoreHTTPDP,
oIgnoreOCSPSvcUrl,
oHonorHTTPProxy,
oHTTPProxy,
oLDAPProxy,
oOnlyLDAPProxy,
oLDAPFile,
oLDAPTimeout,
oLDAPAddServers,
oOCSPResponder,
oOCSPSigner,
oOCSPMaxClockSkew,
oOCSPMaxPeriod,
oOCSPCurrentPeriod,
oMaxReplies,
oHkpCaCert,
oFakedSystemTime,
oForce,
oAllowOCSP,
oAllowVersionCheck,
oSocketName,
oLDAPWrapperProgram,
oHTTPWrapperProgram,
oIgnoreCertExtension,
oUseTor,
oNoUseTor,
oKeyServer,
oNameServer,
oDisableCheckOwnSocket,
oStandardResolver,
oRecursiveResolver,
oResolverTimeout,
oConnectTimeout,
oConnectQuickTimeout,
+ oListenBacklog,
aTest
};
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (300, N_("@Commands:\n ")),
ARGPARSE_c (aServer, "server", N_("run in server mode (foreground)") ),
ARGPARSE_c (aDaemon, "daemon", N_("run in daemon mode (background)") ),
#ifndef HAVE_W32_SYSTEM
ARGPARSE_c (aSupervised, "supervised", N_("run in supervised mode")),
#endif
ARGPARSE_c (aListCRLs, "list-crls", N_("list the contents of the CRL cache")),
ARGPARSE_c (aLoadCRL, "load-crl", N_("|FILE|load CRL from FILE into cache")),
ARGPARSE_c (aFetchCRL, "fetch-crl", N_("|URL|fetch a CRL from URL")),
ARGPARSE_c (aShutdown, "shutdown", N_("shutdown the dirmngr")),
ARGPARSE_c (aFlush, "flush", N_("flush the cache")),
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
ARGPARSE_s_n (oSh, "sh", N_("sh-style command output")),
ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_s_s (oDebugLevel, "debug-level",
N_("|LEVEL|set the debugging level to LEVEL")),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file",
N_("|FILE|write server mode logs to FILE")),
ARGPARSE_s_n (oBatch, "batch", N_("run without asking a user")),
ARGPARSE_s_n (oForce, "force", N_("force loading of outdated CRLs")),
ARGPARSE_s_n (oAllowOCSP, "allow-ocsp", N_("allow sending OCSP requests")),
ARGPARSE_s_n (oAllowVersionCheck, "allow-version-check",
N_("allow online software version check")),
ARGPARSE_s_n (oDisableHTTP, "disable-http", N_("inhibit the use of HTTP")),
ARGPARSE_s_n (oDisableLDAP, "disable-ldap", N_("inhibit the use of LDAP")),
ARGPARSE_s_n (oIgnoreHTTPDP,"ignore-http-dp",
N_("ignore HTTP CRL distribution points")),
ARGPARSE_s_n (oIgnoreLDAPDP,"ignore-ldap-dp",
N_("ignore LDAP CRL distribution points")),
ARGPARSE_s_n (oIgnoreOCSPSvcUrl, "ignore-ocsp-service-url",
N_("ignore certificate contained OCSP service URLs")),
ARGPARSE_s_s (oHTTPProxy, "http-proxy",
N_("|URL|redirect all HTTP requests to URL")),
ARGPARSE_s_s (oLDAPProxy, "ldap-proxy",
N_("|HOST|use HOST for LDAP queries")),
ARGPARSE_s_n (oOnlyLDAPProxy, "only-ldap-proxy",
N_("do not use fallback hosts with --ldap-proxy")),
ARGPARSE_s_s (oLDAPFile, "ldapserverlist-file",
N_("|FILE|read LDAP server list from FILE")),
ARGPARSE_s_n (oLDAPAddServers, "add-servers",
N_("add new servers discovered in CRL distribution"
" points to serverlist")),
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
N_("|N|set LDAP timeout to N seconds")),
ARGPARSE_s_s (oOCSPResponder, "ocsp-responder",
N_("|URL|use OCSP responder at URL")),
ARGPARSE_s_s (oOCSPSigner, "ocsp-signer",
N_("|FPR|OCSP response signed by FPR")),
ARGPARSE_s_i (oOCSPMaxClockSkew, "ocsp-max-clock-skew", "@"),
ARGPARSE_s_i (oOCSPMaxPeriod, "ocsp-max-period", "@"),
ARGPARSE_s_i (oOCSPCurrentPeriod, "ocsp-current-period", "@"),
ARGPARSE_s_i (oMaxReplies, "max-replies",
N_("|N|do not return more than N items in one query")),
ARGPARSE_s_s (oNameServer, "nameserver", "@"),
ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
ARGPARSE_s_s (oHkpCaCert, "hkp-cacert",
N_("|FILE|use the CA certificates in FILE for HKP over TLS")),
ARGPARSE_s_n (oUseTor, "use-tor", N_("route all network traffic via Tor")),
ARGPARSE_s_n (oNoUseTor, "no-use-tor", "@"),
ARGPARSE_s_n (oDisableIPv4, "disable-ipv4", "@"),
ARGPARSE_s_n (oDisableIPv6, "disable-ipv6", "@"),
ARGPARSE_s_s (oSocketName, "socket-name", "@"), /* Only for debugging. */
ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"),
ARGPARSE_s_i (oGnutlsDebug, "tls-debug", "@"),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_s (oLDAPWrapperProgram, "ldap-wrapper-program", "@"),
ARGPARSE_s_s (oHTTPWrapperProgram, "http-wrapper-program", "@"),
ARGPARSE_s_n (oHonorHTTPProxy, "honor-http-proxy", "@"),
ARGPARSE_s_s (oIgnoreCertExtension,"ignore-cert-extension", "@"),
ARGPARSE_s_n (oStandardResolver, "standard-resolver", "@"),
ARGPARSE_s_n (oRecursiveResolver, "recursive-resolver", "@"),
ARGPARSE_s_i (oResolverTimeout, "resolver-timeout", "@"),
ARGPARSE_s_i (oConnectTimeout, "connect-timeout", "@"),
ARGPARSE_s_i (oConnectQuickTimeout, "connect-quick-timeout", "@"),
+ ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_group (302,N_("@\n(See the \"info\" manual for a complete listing "
"of all commands and options)\n")),
ARGPARSE_end ()
};
/* The list of supported debug flags. */
static struct debug_flags_s debug_flags [] =
{
{ DBG_X509_VALUE , "x509" },
{ DBG_CRYPTO_VALUE , "crypto" },
{ DBG_MEMORY_VALUE , "memory" },
{ DBG_CACHE_VALUE , "cache" },
{ DBG_MEMSTAT_VALUE, "memstat" },
{ DBG_HASHING_VALUE, "hashing" },
{ DBG_IPC_VALUE , "ipc" },
{ DBG_DNS_VALUE , "dns" },
{ DBG_NETWORK_VALUE, "network" },
{ DBG_LOOKUP_VALUE , "lookup" },
{ DBG_EXTPROG_VALUE, "extprog" },
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
};
#define DEFAULT_MAX_REPLIES 10
#define DEFAULT_LDAP_TIMEOUT 15 /* seconds */
#define DEFAULT_CONNECT_TIMEOUT (15*1000) /* 15 seconds */
#define DEFAULT_CONNECT_QUICK_TIMEOUT ( 2*1000) /* 2 seconds */
/* For the cleanup handler we need to keep track of the socket's name. */
static const char *socket_name;
/* If the socket has been redirected, this is the name of the
redirected socket.. */
static const char *redir_socket_name;
/* We need to keep track of the server's nonces (these are dummies for
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
+/* Value for the listen() backlog argument.
+ * Change at runtime with --listen-backlog. */
+static int listen_backlog = 64;
+
/* Only if this flag has been set will we remove the socket file. */
static int cleanup_socket;
/* Keep track of the current log file so that we can avoid updating
the log file after a SIGHUP if it didn't changed. Malloced. */
static char *current_logfile;
/* Helper to implement --debug-level. */
static const char *debug_level;
/* Helper to set the NTBTLS or GNUTLS log level. */
static int opt_gnutls_debug = -1;
/* Flag indicating that a shutdown has been requested. */
static volatile int shutdown_pending;
/* Flags to indicate that we shall not watch our own socket. */
static int disable_check_own_socket;
/* Flag to control the Tor mode. */
static enum
{ TOR_MODE_AUTO = 0, /* Switch to NO or YES */
TOR_MODE_NEVER, /* Never use Tor. */
TOR_MODE_NO, /* Do not use Tor */
TOR_MODE_YES, /* Use Tor */
TOR_MODE_FORCE /* Force using Tor */
} tor_mode;
/* Counter for the active connections. */
static int active_connections;
/* This flag is set by any network access and used by the housekeeping
* thread to run background network tasks. */
static int network_activity_seen;
/* A list of filenames registred with --hkp-cacert. */
static strlist_t hkp_cacert_filenames;
/* The timer tick used for housekeeping stuff. The second constant is used when a shutdown is pending. */
#define TIMERTICK_INTERVAL (60)
#define TIMERTICK_INTERVAL_SHUTDOWN (4)
/* How oft to run the housekeeping. */
#define HOUSEKEEPING_INTERVAL (600)
/* This union is used to avoid compiler warnings in case a pointer is
64 bit and an int 32 bit. We store an integer in a pointer and get
it back later (npth_getspecific et al.). */
union int_and_ptr_u
{
int aint;
assuan_fd_t afd;
void *aptr;
};
/* The key used to store the current file descriptor in the thread
local storage. We use this in conjunction with the
log_set_pid_suffix_cb feature. */
#ifndef HAVE_W32_SYSTEM
static npth_key_t my_tlskey_current_fd;
#endif
/* Prototypes. */
static void cleanup (void);
#if USE_LDAP
static ldap_server_t parse_ldapserver_file (const char* filename);
#endif /*USE_LDAP*/
static fingerprint_list_t parse_ocsp_signer (const char *string);
static void netactivity_action (void);
static void handle_connections (assuan_fd_t listen_fd);
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static const char *
my_strusage( int level )
{
const char *p;
switch ( level )
{
case 11: p = "@DIRMNGR@ (@GNUPG@)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
/* TRANSLATORS: @EMAIL@ will get replaced by the actual bug
reporting address. This is so that we can change the
reporting address without breaking the translations. */
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
case 49: p = PACKAGE_BUGREPORT; break;
case 1:
case 40: p = _("Usage: @DIRMNGR@ [options] (-h for help)");
break;
case 41: p = _("Syntax: @DIRMNGR@ [options] [command [args]]\n"
"Keyserver, CRL, and OCSP access for @GNUPG@\n");
break;
default: p = NULL;
}
return p;
}
/* Callback from libksba to hash a provided buffer. Our current
implementation does only allow SHA-1 for hashing. This may be
extended by mapping the name, testing for algorithm availibility
and adjust the length checks accordingly. */
static gpg_error_t
my_ksba_hash_buffer (void *arg, const char *oid,
const void *buffer, size_t length, size_t resultsize,
unsigned char *result, size_t *resultlen)
{
(void)arg;
if (oid && strcmp (oid, "1.3.14.3.2.26"))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (resultsize < 20)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
gcry_md_hash_buffer (2, result, buffer, length);
*resultlen = 20;
return 0;
}
/* GNUTLS log function callback. */
#ifdef HTTP_USE_GNUTLS
static void
my_gnutls_log (int level, const char *text)
{
int n;
n = strlen (text);
while (n && text[n-1] == '\n')
n--;
log_debug ("gnutls:L%d: %.*s\n", level, n, text);
}
#endif /*HTTP_USE_GNUTLS*/
/* Setup the debugging. With a LEVEL of NULL only the active debug
flags are propagated to the subsystems. With LEVEL set, a specific
set of debug flags is set; thus overriding all flags already
set. */
static void
set_debug (void)
{
int numok = (debug_level && digitp (debug_level));
int numlvl = numok? atoi (debug_level) : 0;
if (!debug_level)
;
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
|DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
opt.debug = ~0;
/* Unless the "guru" string has been used we don't want to allow
hashing debugging. The rationale is that people tend to
select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */
if (numok)
opt.debug &= ~(DBG_HASHING_VALUE);
}
else
{
log_error (_("invalid debug-level '%s' given\n"), debug_level);
log_info (_("valid debug levels are: %s\n"),
"none, basic, advanced, expert, guru");
opt.debug = 0; /* Reset debugging, so that prior debug
statements won't have an undesired effect. */
}
if (opt.debug && !opt.verbose)
{
opt.verbose = 1;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
}
if (opt.debug && opt.quiet)
opt.quiet = 0;
if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
#if HTTP_USE_NTBTLS
if (opt_gnutls_debug >= 0)
{
ntbtls_set_debug (opt_gnutls_debug, NULL, NULL);
}
#elif HTTP_USE_GNUTLS
if (opt_gnutls_debug >= 0)
{
gnutls_global_set_log_function (my_gnutls_log);
gnutls_global_set_log_level (opt_gnutls_debug);
}
#endif /*HTTP_USE_GNUTLS*/
if (opt.debug)
parse_debug_flag (NULL, &opt.debug, debug_flags);
}
static void
set_tor_mode (void)
{
if (dirmngr_use_tor ())
{
/* Enable Tor mode and when called again force a new curcuit
* (e.g. on SIGHUP). */
enable_dns_tormode (1);
if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
{
log_error ("error enabling Tor mode: %s\n", strerror (errno));
log_info ("(is your Libassuan recent enough?)\n");
}
}
else
disable_dns_tormode ();
}
/* Return true if Tor shall be used. */
int
dirmngr_use_tor (void)
{
if (tor_mode == TOR_MODE_AUTO)
{
/* Figure out whether Tor is running. */
assuan_fd_t sock;
sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
if (sock == ASSUAN_INVALID_FD)
tor_mode = TOR_MODE_NO;
else
{
tor_mode = TOR_MODE_YES;
assuan_sock_close (sock);
}
}
if (tor_mode == TOR_MODE_FORCE)
return 2; /* Use Tor (using 2 to indicate force mode) */
else if (tor_mode == TOR_MODE_YES)
return 1; /* Use Tor */
else
return 0; /* Do not use Tor. */
}
static void
wrong_args (const char *text)
{
es_fprintf (es_stderr, _("usage: %s [options] "), DIRMNGR_NAME);
es_fputs (text, es_stderr);
es_putc ('\n', es_stderr);
dirmngr_exit (2);
}
/* Helper to stop the reaper thread for the ldap wrapper. */
static void
shutdown_reaper (void)
{
#if USE_LDAP
ldap_wrapper_wait_connections ();
#endif
}
/* Handle options which are allowed to be reset after program start.
Return true if the current option in PARGS could be handled and
false if not. As a special feature, passing a value of NULL for
PARGS, resets the options to the default. REREAD should be set
true if it is not the initial option parsing. */
static int
parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
{
if (!pargs)
{ /* Reset mode. */
opt.quiet = 0;
opt.verbose = 0;
opt.debug = 0;
opt.ldap_wrapper_program = NULL;
opt.disable_http = 0;
opt.disable_ldap = 0;
opt.honor_http_proxy = 0;
opt.http_proxy = NULL;
opt.ldap_proxy = NULL;
opt.only_ldap_proxy = 0;
opt.ignore_http_dp = 0;
opt.ignore_ldap_dp = 0;
opt.ignore_ocsp_service_url = 0;
opt.allow_ocsp = 0;
opt.allow_version_check = 0;
opt.ocsp_responder = NULL;
opt.ocsp_max_clock_skew = 10 * 60; /* 10 minutes. */
opt.ocsp_max_period = 90 * 86400; /* 90 days. */
opt.ocsp_current_period = 3 * 60 * 60; /* 3 hours. */
opt.max_replies = DEFAULT_MAX_REPLIES;
while (opt.ocsp_signer)
{
fingerprint_list_t tmp = opt.ocsp_signer->next;
xfree (opt.ocsp_signer);
opt.ocsp_signer = tmp;
}
FREE_STRLIST (opt.ignored_cert_extensions);
http_register_tls_ca (NULL);
FREE_STRLIST (hkp_cacert_filenames);
FREE_STRLIST (opt.keyserver);
/* Note: We do not allow resetting of TOR_MODE_FORCE at runtime. */
if (tor_mode != TOR_MODE_FORCE)
tor_mode = TOR_MODE_AUTO;
disable_check_own_socket = 0;
enable_standard_resolver (0);
set_dns_timeout (0);
opt.connect_timeout = 0;
opt.connect_quick_timeout = 0;
return 1;
}
switch (pargs->r_opt)
{
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
case oDebug:
parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
break;
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs->r.ret_str; break;
case oGnutlsDebug: opt_gnutls_debug = pargs->r.ret_int; break;
case oLogFile:
if (!reread)
return 0; /* Not handled. */
if (!current_logfile || !pargs->r.ret_str
|| strcmp (current_logfile, pargs->r.ret_str))
{
log_set_file (pargs->r.ret_str);
xfree (current_logfile);
current_logfile = xtrystrdup (pargs->r.ret_str);
}
break;
case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
case oLDAPWrapperProgram:
opt.ldap_wrapper_program = pargs->r.ret_str;
break;
case oHTTPWrapperProgram:
opt.http_wrapper_program = pargs->r.ret_str;
break;
case oDisableHTTP: opt.disable_http = 1; break;
case oDisableLDAP: opt.disable_ldap = 1; break;
case oDisableIPv4: opt.disable_ipv4 = 1; break;
case oDisableIPv6: opt.disable_ipv6 = 1; break;
case oHonorHTTPProxy: opt.honor_http_proxy = 1; break;
case oHTTPProxy: opt.http_proxy = pargs->r.ret_str; break;
case oLDAPProxy: opt.ldap_proxy = pargs->r.ret_str; break;
case oOnlyLDAPProxy: opt.only_ldap_proxy = 1; break;
case oIgnoreHTTPDP: opt.ignore_http_dp = 1; break;
case oIgnoreLDAPDP: opt.ignore_ldap_dp = 1; break;
case oIgnoreOCSPSvcUrl: opt.ignore_ocsp_service_url = 1; break;
case oAllowOCSP: opt.allow_ocsp = 1; break;
case oAllowVersionCheck: opt.allow_version_check = 1; break;
case oOCSPResponder: opt.ocsp_responder = pargs->r.ret_str; break;
case oOCSPSigner:
opt.ocsp_signer = parse_ocsp_signer (pargs->r.ret_str);
break;
case oOCSPMaxClockSkew: opt.ocsp_max_clock_skew = pargs->r.ret_int; break;
case oOCSPMaxPeriod: opt.ocsp_max_period = pargs->r.ret_int; break;
case oOCSPCurrentPeriod: opt.ocsp_current_period = pargs->r.ret_int; break;
case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
case oHkpCaCert:
{
/* We need to register the filenames with gnutls (http.c) and
* also for our own cert cache. */
char *tmpname;
/* Do tilde expansion and make path absolute. */
tmpname = make_absfilename (pargs->r.ret_str, NULL);
http_register_tls_ca (tmpname);
add_to_strlist (&hkp_cacert_filenames, pargs->r.ret_str);
xfree (tmpname);
}
break;
case oIgnoreCertExtension:
add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
break;
case oUseTor:
tor_mode = TOR_MODE_FORCE;
break;
case oNoUseTor:
if (tor_mode != TOR_MODE_FORCE)
tor_mode = TOR_MODE_NEVER;
break;
case oStandardResolver: enable_standard_resolver (1); break;
case oRecursiveResolver: enable_recursive_resolver (1); break;
case oKeyServer:
if (*pargs->r.ret_str)
add_to_strlist (&opt.keyserver, pargs->r.ret_str);
break;
case oNameServer:
set_dns_nameserver (pargs->r.ret_str);
break;
case oResolverTimeout:
set_dns_timeout (pargs->r.ret_int);
break;
case oConnectTimeout:
opt.connect_timeout = pargs->r.ret_ulong * 1000;
break;
case oConnectQuickTimeout:
opt.connect_quick_timeout = pargs->r.ret_ulong * 1000;
break;
default:
return 0; /* Not handled. */
}
set_dns_verbose (opt.verbose, !!DBG_DNS);
http_set_verbose (opt.verbose, !!DBG_NETWORK);
set_dns_disable_ipv4 (opt.disable_ipv4);
set_dns_disable_ipv6 (opt.disable_ipv6);
return 1; /* Handled. */
}
/* This fucntion is called after option parsing to adjust some values
* and call option setup functions. */
static void
post_option_parsing (void)
{
/* It would be too surpirsing if the quick timeout is larger than
* the standard value. */
if (opt.connect_quick_timeout > opt.connect_timeout)
opt.connect_quick_timeout = opt.connect_timeout;
set_debug ();
set_tor_mode ();
}
#ifndef HAVE_W32_SYSTEM
static int
pid_suffix_callback (unsigned long *r_suffix)
{
union int_and_ptr_u value;
memset (&value, 0, sizeof value);
value.aptr = npth_getspecific (my_tlskey_current_fd);
*r_suffix = value.aint;
return (*r_suffix != -1); /* Use decimal representation. */
}
#endif /*!HAVE_W32_SYSTEM*/
#if HTTP_USE_NTBTLS
static void
my_ntbtls_log_handler (void *opaque, int level, const char *fmt, va_list argv)
{
(void)opaque;
if (level == -1)
log_logv_with_prefix (GPGRT_LOG_INFO, "ntbtls: ", fmt, argv);
else
{
char prefix[10+20];
snprintf (prefix, sizeof prefix, "ntbtls(%d): ", level);
log_logv_with_prefix (GPGRT_LOG_DEBUG, prefix, fmt, argv);
}
}
#endif
static void
thread_init (void)
{
npth_init ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Now with NPth running we can set the logging callback. Our
windows implementation does not yet feature the NPth TLS
functions. */
#ifndef HAVE_W32_SYSTEM
if (npth_key_create (&my_tlskey_current_fd, NULL) == 0)
if (npth_setspecific (my_tlskey_current_fd, NULL) == 0)
log_set_pid_suffix_cb (pid_suffix_callback);
#endif /*!HAVE_W32_SYSTEM*/
}
int
main (int argc, char **argv)
{
enum cmd_and_opt_values cmd = 0;
ARGPARSE_ARGS pargs;
int orig_argc;
char **orig_argv;
FILE *configfp = NULL;
char *configname = NULL;
const char *shell;
unsigned configlineno;
int parse_debug = 0;
int default_config =1;
int greeting = 0;
int nogreeting = 0;
int nodetach = 0;
int csh_style = 0;
char *logfile = NULL;
#if USE_LDAP
char *ldapfile = NULL;
#endif /*USE_LDAP*/
int debug_wait = 0;
int rc;
struct assuan_malloc_hooks malloc_hooks;
early_system_init ();
set_strusage (my_strusage);
log_set_prefix (DIRMNGR_NAME, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID);
/* Make sure that our subsystems are ready. */
i18n_init ();
init_common_subsystems (&argc, &argv);
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
/* Check that the libraries are suitable. Do it here because
the option parsing may need services of the libraries. */
if (!ksba_check_version (NEED_KSBA_VERSION) )
log_fatal( _("%s is too old (need %s, have %s)\n"), "libksba",
NEED_KSBA_VERSION, ksba_check_version (NULL) );
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
ksba_set_hash_buffer_function (my_ksba_hash_buffer, NULL);
/* Init TLS library. */
#if HTTP_USE_NTBTLS
if (!ntbtls_check_version (NEED_NTBTLS_VERSION) )
log_fatal( _("%s is too old (need %s, have %s)\n"), "ntbtls",
NEED_NTBTLS_VERSION, ntbtls_check_version (NULL) );
#elif HTTP_USE_GNUTLS
rc = gnutls_global_init ();
if (rc)
log_fatal ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
#endif /*HTTP_USE_GNUTLS*/
/* Init Assuan. */
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
assuan_sock_init ();
setup_libassuan_logging (&opt.debug, dirmngr_assuan_log_monitor);
setup_libgcrypt_logging ();
#if HTTP_USE_NTBTLS
ntbtls_set_log_handler (my_ntbtls_log_handler, NULL);
#endif
/* Setup defaults. */
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1;
/* Reset rereadable options to default values. */
parse_rereadable_options (NULL, 0);
/* Default TCP timeouts. */
opt.connect_timeout = DEFAULT_CONNECT_TIMEOUT;
opt.connect_quick_timeout = DEFAULT_CONNECT_QUICK_TIMEOUT;
/* LDAP defaults. */
opt.add_new_ldapservers = 0;
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
/* Other defaults. */
/* Check whether we have a config file given on the commandline */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
while (arg_parse( &pargs, opts))
{
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
parse_debug++;
else if (pargs.r_opt == oOptions)
{ /* Yes there is one, so we do not try the default one, but
read the option file when it is encountered at the
commandline */
default_config = 0;
}
else if (pargs.r_opt == oNoOptions)
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
{
gnupg_set_homedir (pargs.r.ret_str);
}
}
socket_name = dirmngr_socket_name ();
if (default_config)
configname = make_filename (gnupg_homedir (), DIRMNGR_NAME".conf", NULL );
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
next_pass:
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if( parse_debug )
log_info (_("Note: no default option file '%s'\n"),
configname );
}
else
{
log_error (_("option file '%s': %s\n"),
configname, strerror(errno) );
exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname )
log_info (_("reading options from '%s'\n"), configname );
default_config = 0;
}
while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
{
if (parse_rereadable_options (&pargs, 0))
continue; /* Already handled */
switch (pargs.r_opt)
{
case aServer:
case aDaemon:
case aSupervised:
case aShutdown:
case aFlush:
case aListCRLs:
case aLoadCRL:
case aFetchCRL:
case aGPGConfList:
case aGPGConfTest:
cmd = pargs.r_opt;
break;
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
case oBatch: opt.batch=1; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oOptions:
/* Config files may not be nested (silently ignore them) */
if (!configfp)
{
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoGreeting: nogreeting = 1; break;
case oNoVerbose: opt.verbose = 0; break;
case oNoOptions: break; /* no-options */
case oHomedir: /* Ignore this option here. */; break;
case oNoDetach: nodetach = 1; break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; break;
case oLDAPFile:
# if USE_LDAP
ldapfile = pargs.r.ret_str;
# endif /*USE_LDAP*/
break;
case oLDAPAddServers: opt.add_new_ldapservers = 1; break;
case oLDAPTimeout:
opt.ldaptimeout = pargs.r.ret_int;
break;
case oFakedSystemTime:
gnupg_set_time ((time_t)pargs.r.ret_ulong, 0);
break;
case oForce: opt.force = 1; break;
case oSocketName: socket_name = pargs.r.ret_str; break;
+ case oListenBacklog:
+ listen_backlog = pargs.r.ret_int;
+ break;
+
default : pargs.err = configfp? 1:2; break;
}
}
if (configfp)
{
fclose (configfp);
configfp = NULL;
/* Keep a copy of the name so that it can be read on SIGHUP. */
opt.config_filename = configname;
configname = NULL;
goto next_pass;
}
xfree (configname);
configname = NULL;
if (log_get_errorcount(0))
exit(2);
if (nogreeting )
greeting = 0;
if (!opt.homedir_cache)
opt.homedir_cache = xstrdup (gnupg_homedir ());
if (greeting)
{
es_fprintf (es_stderr, "%s %s; %s\n",
strusage(11), strusage(13), strusage(14) );
es_fprintf (es_stderr, "%s\n", strusage(15) );
}
#ifdef IS_DEVELOPMENT_VERSION
log_info ("NOTE: this is a development version!\n");
#endif
/* Print a warning if an argument looks like an option. */
if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
{
int i;
for (i=0; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == '-')
log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
}
if (!access ("/etc/"DIRMNGR_NAME, F_OK)
&& !strncmp (gnupg_homedir (), "/etc/", 5))
log_info
("NOTE: DirMngr is now a proper part of %s. The configuration and"
" other directory names changed. Please check that no other version"
" of dirmngr is still installed. To disable this warning, remove the"
" directory '/etc/dirmngr'.\n", GNUPG_NAME);
if (gnupg_faked_time_p ())
{
gnupg_isotime_t tbuf;
log_info (_("WARNING: running with faked system time: "));
gnupg_get_isotime (tbuf);
dump_isotime (tbuf);
log_printf ("\n");
}
post_option_parsing ();
/* Get LDAP server list from file. */
#if USE_LDAP
if (!ldapfile)
{
ldapfile = make_filename (gnupg_homedir (),
"dirmngr_ldapservers.conf",
NULL);
opt.ldapservers = parse_ldapserver_file (ldapfile);
xfree (ldapfile);
}
else
opt.ldapservers = parse_ldapserver_file (ldapfile);
#endif /*USE_LDAP*/
#ifndef HAVE_W32_SYSTEM
/* We need to ignore the PIPE signal because the we might log to a
socket and that code handles EPIPE properly. The ldap wrapper
also requires us to ignore this silly signal. Assuan would set
this signal to ignore anyway.*/
signal (SIGPIPE, SIG_IGN);
#endif
/* Ready. Now to our duties. */
if (!cmd)
cmd = aServer;
rc = 0;
if (cmd == aServer)
{
/* Note that this server mode is mainly useful for debugging. */
if (argc)
wrong_args ("--server");
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
}
if (debug_wait)
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
http_register_netactivity_cb (netactivity_action);
start_command_handler (ASSUAN_INVALID_FD, 0);
shutdown_reaper ();
}
#ifndef HAVE_W32_SYSTEM
else if (cmd == aSupervised)
{
/* In supervised mode, we expect file descriptor 3 to be an
already opened, listening socket.
We will also not detach from the controlling process or close
stderr; the supervisor should handle all of that. */
struct stat statbuf;
if (fstat (3, &statbuf) == -1 && errno == EBADF)
{
log_error ("file descriptor 3 must be validin --supervised mode\n");
dirmngr_exit (1);
}
socket_name = gnupg_get_socket_name (3);
/* Now start with logging to a file if this is desired. */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
|GPGRT_LOG_WITH_TIME
|GPGRT_LOG_WITH_PID));
current_logfile = xstrdup (logfile);
}
else
log_set_prefix (NULL, 0);
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
http_register_netactivity_cb (netactivity_action);
handle_connections (3);
shutdown_reaper ();
}
#endif /*HAVE_W32_SYSTEM*/
else if (cmd == aDaemon)
{
assuan_fd_t fd;
pid_t pid;
int len;
struct sockaddr_un serv_addr;
if (argc)
wrong_args ("--daemon");
/* Now start with logging to a file if this is desired. */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
|GPGRT_LOG_WITH_TIME
|GPGRT_LOG_WITH_PID));
current_logfile = xstrdup (logfile);
}
#ifndef HAVE_W32_SYSTEM
if (strchr (socket_name, ':'))
{
log_error (_("colons are not allowed in the socket name\n"));
dirmngr_exit (1);
}
#endif
fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
cleanup ();
dirmngr_exit (1);
}
{
int redirected;
if (assuan_sock_set_sockaddr_un (socket_name,
(struct sockaddr*)&serv_addr,
&redirected))
{
if (errno == ENAMETOOLONG)
log_error (_("socket name '%s' is too long\n"), socket_name);
else
log_error ("error preparing socket '%s': %s\n",
socket_name,
gpg_strerror (gpg_error_from_syserror ()));
dirmngr_exit (1);
}
if (redirected)
{
redir_socket_name = xstrdup (serv_addr.sun_path);
if (opt.verbose)
log_info ("redirecting socket '%s' to '%s'\n",
socket_name, redir_socket_name);
}
}
len = SUN_LEN (&serv_addr);
rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
if (rc == -1
&& (errno == EADDRINUSE
#ifdef HAVE_W32_SYSTEM
|| errno == EEXIST
#endif
))
{
/* Fixme: We should test whether a dirmngr is already running. */
gnupg_remove (redir_socket_name? redir_socket_name : socket_name);
rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
}
if (rc != -1
&& (rc = assuan_sock_get_nonce ((struct sockaddr*) &serv_addr, len, &socket_nonce)))
log_error (_("error getting nonce for the socket\n"));
if (rc == -1)
{
log_error (_("error binding socket to '%s': %s\n"),
serv_addr.sun_path,
gpg_strerror (gpg_error_from_errno (errno)));
assuan_sock_close (fd);
dirmngr_exit (1);
}
cleanup_socket = 1;
if (gnupg_chmod (serv_addr.sun_path, "-rwx"))
log_error (_("can't set permissions of '%s': %s\n"),
serv_addr.sun_path, strerror (errno));
- if (listen (FD2INT (fd), 5) == -1)
+ if (listen (FD2INT (fd), listen_backlog) == -1)
{
- log_error (_("listen() failed: %s\n"), strerror (errno));
+ log_error ("listen(fd,%d) failed: %s\n",
+ listen_backlog, strerror (errno));
assuan_sock_close (fd);
dirmngr_exit (1);
}
if (opt.verbose)
log_info (_("listening on socket '%s'\n"), serv_addr.sun_path);
es_fflush (NULL);
/* Note: We keep the dirmngr_info output only for the sake of
existing scripts which might use this to detect a successful
start of the dirmngr. */
#ifdef HAVE_W32_SYSTEM
(void)csh_style;
(void)nodetach;
pid = getpid ();
es_printf ("set %s=%s;%lu;1\n",
DIRMNGR_INFO_NAME, socket_name, (ulong) pid);
#else
pid = fork();
if (pid == (pid_t)-1)
{
log_fatal (_("error forking process: %s\n"), strerror (errno));
dirmngr_exit (1);
}
if (pid)
{ /* We are the parent */
char *infostr;
/* Don't let cleanup() remove the socket - the child is
responsible for doing that. */
cleanup_socket = 0;
close (fd);
/* Create the info string: :: */
if (asprintf (&infostr, "%s=%s:%lu:1",
DIRMNGR_INFO_NAME, serv_addr.sun_path, (ulong)pid ) < 0)
{
log_error (_("out of core\n"));
kill (pid, SIGTERM);
dirmngr_exit (1);
}
/* Print the environment string, so that the caller can use
shell's eval to set it. But see above. */
if (csh_style)
{
*strchr (infostr, '=') = ' ';
es_printf ( "setenv %s;\n", infostr);
}
else
{
es_printf ( "%s; export %s;\n", infostr, DIRMNGR_INFO_NAME);
}
free (infostr);
exit (0);
/*NEVER REACHED*/
} /* end parent */
/*
This is the child
*/
/* Detach from tty and put process into a new session */
if (!nodetach )
{
int i;
unsigned int oldflags;
/* Close stdin, stdout and stderr unless it is the log stream */
for (i=0; i <= 2; i++)
{
if (!log_test_fd (i) && i != fd )
{
if ( !close (i)
&& open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
{
log_error ("failed to open '%s': %s\n",
"/dev/null", strerror (errno));
cleanup ();
dirmngr_exit (1);
}
}
}
if (setsid() == -1)
{
log_error ("setsid() failed: %s\n", strerror(errno) );
dirmngr_exit (1);
}
log_get_prefix (&oldflags);
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
opt.running_detached = 1;
}
#endif
if (!nodetach )
{
if (gnupg_chdir (gnupg_daemon_rootdir ()))
{
log_error ("chdir to '%s' failed: %s\n",
gnupg_daemon_rootdir (), strerror (errno));
dirmngr_exit (1);
}
}
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
http_register_netactivity_cb (netactivity_action);
handle_connections (fd);
shutdown_reaper ();
}
else if (cmd == aListCRLs)
{
/* Just list the CRL cache and exit. */
if (argc)
wrong_args ("--list-crls");
crl_cache_init ();
crl_cache_list (es_stdout);
}
else if (cmd == aLoadCRL)
{
struct server_control_s ctrlbuf;
memset (&ctrlbuf, 0, sizeof ctrlbuf);
dirmngr_init_default_ctrl (&ctrlbuf);
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
if (!argc)
rc = crl_cache_load (&ctrlbuf, NULL);
else
{
for (; !rc && argc; argc--, argv++)
rc = crl_cache_load (&ctrlbuf, *argv);
}
dirmngr_deinit_default_ctrl (&ctrlbuf);
}
else if (cmd == aFetchCRL)
{
ksba_reader_t reader;
struct server_control_s ctrlbuf;
if (argc != 1)
wrong_args ("--fetch-crl URL");
memset (&ctrlbuf, 0, sizeof ctrlbuf);
dirmngr_init_default_ctrl (&ctrlbuf);
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
rc = crl_fetch (&ctrlbuf, argv[0], &reader);
if (rc)
log_error (_("fetching CRL from '%s' failed: %s\n"),
argv[0], gpg_strerror (rc));
else
{
rc = crl_cache_insert (&ctrlbuf, argv[0], reader);
if (rc)
log_error (_("processing CRL from '%s' failed: %s\n"),
argv[0], gpg_strerror (rc));
crl_close_reader (reader);
}
dirmngr_deinit_default_ctrl (&ctrlbuf);
}
else if (cmd == aFlush)
{
/* Delete cache and exit. */
if (argc)
wrong_args ("--flush");
rc = crl_cache_flush();
}
else if (cmd == aGPGConfTest)
dirmngr_exit (0);
else if (cmd == aGPGConfList)
{
unsigned long flags = 0;
char *filename;
char *filename_esc;
/* First the configuration file. This is not an option, but it
is vital information for GPG Conf. */
if (!opt.config_filename)
opt.config_filename = make_filename (gnupg_homedir (),
"dirmngr.conf", NULL );
filename = percent_escape (opt.config_filename, NULL);
es_printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
GC_OPT_FLAG_DEFAULT, filename);
xfree (filename);
es_printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
es_printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
/* --csh and --sh are mutually exclusive, something we can not
express in GPG Conf. --options is only usable from the
command line, really. --debug-all interacts with --debug,
and having both of them is thus problematic. --no-detach is
also only usable on the command line. --batch is unused. */
filename = make_filename (gnupg_homedir (),
"dirmngr_ldapservers.conf",
NULL);
filename_esc = percent_escape (filename, NULL);
es_printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
filename_esc);
xfree (filename_esc);
xfree (filename);
es_printf ("ldaptimeout:%lu:%u\n",
flags | GC_OPT_FLAG_DEFAULT, DEFAULT_LDAP_TIMEOUT);
es_printf ("max-replies:%lu:%u\n",
flags | GC_OPT_FLAG_DEFAULT, DEFAULT_MAX_REPLIES);
es_printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("allow-version-check:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
es_printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
/* Note: The next one is to fix a typo in gpgconf - should be
removed eventually. */
es_printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("use-tor:%lu:\n", flags | GC_OPT_FLAG_NONE);
filename_esc = percent_escape (get_default_keyserver (0), NULL);
es_printf ("keyserver:%lu:\"%s:\n", flags | GC_OPT_FLAG_DEFAULT,
filename_esc);
xfree (filename_esc);
es_printf ("nameserver:%lu:\n", flags | GC_OPT_FLAG_NONE);
es_printf ("resolver-timeout:%lu:%u\n",
flags | GC_OPT_FLAG_DEFAULT, 0);
}
cleanup ();
return !!rc;
}
static void
cleanup (void)
{
crl_cache_deinit ();
cert_cache_deinit (1);
reload_dns_stuff (1);
#if USE_LDAP
ldapserver_list_free (opt.ldapservers);
#endif /*USE_LDAP*/
opt.ldapservers = NULL;
if (cleanup_socket)
{
cleanup_socket = 0;
if (redir_socket_name)
gnupg_remove (redir_socket_name);
else if (socket_name && *socket_name)
gnupg_remove (socket_name);
}
}
void
dirmngr_exit (int rc)
{
cleanup ();
exit (rc);
}
void
dirmngr_init_default_ctrl (ctrl_t ctrl)
{
ctrl->magic = SERVER_CONTROL_MAGIC;
if (opt.http_proxy)
ctrl->http_proxy = xstrdup (opt.http_proxy);
ctrl->http_no_crl = 1;
ctrl->timeout = opt.connect_timeout;
}
void
dirmngr_deinit_default_ctrl (ctrl_t ctrl)
{
if (!ctrl)
return;
ctrl->magic = 0xdeadbeef;
xfree (ctrl->http_proxy);
ctrl->http_proxy = NULL;
}
/* Create a list of LDAP servers from the file FILENAME. Returns the
list or NULL in case of errors.
The format fo such a file is line oriented where empty lines and
lines starting with a hash mark are ignored. All other lines are
assumed to be colon seprated with these fields:
1. field: Hostname
2. field: Portnumber
3. field: Username
4. field: Password
5. field: Base DN
*/
#if USE_LDAP
static ldap_server_t
parse_ldapserver_file (const char* filename)
{
char buffer[1024];
char *p;
ldap_server_t server, serverstart, *serverend;
int c;
unsigned int lineno = 0;
estream_t fp;
fp = es_fopen (filename, "r");
if (!fp)
{
log_error (_("error opening '%s': %s\n"), filename, strerror (errno));
return NULL;
}
serverstart = NULL;
serverend = &serverstart;
while (es_fgets (buffer, sizeof buffer, fp))
{
lineno++;
if (!*buffer || buffer[strlen(buffer)-1] != '\n')
{
if (*buffer && es_feof (fp))
; /* Last line not terminated - continue. */
else
{
log_error (_("%s:%u: line too long - skipped\n"),
filename, lineno);
while ( (c=es_fgetc (fp)) != EOF && c != '\n')
; /* Skip until end of line. */
continue;
}
}
/* Skip empty and comment lines.*/
for (p=buffer; spacep (p); p++)
;
if (!*p || *p == '\n' || *p == '#')
continue;
/* Parse the colon separated fields. */
server = ldapserver_parse_one (buffer, filename, lineno);
if (server)
{
*serverend = server;
serverend = &server->next;
}
}
if (es_ferror (fp))
log_error (_("error reading '%s': %s\n"), filename, strerror (errno));
es_fclose (fp);
return serverstart;
}
#endif /*USE_LDAP*/
static fingerprint_list_t
parse_ocsp_signer (const char *string)
{
gpg_error_t err;
char *fname;
estream_t fp;
char line[256];
char *p;
fingerprint_list_t list, *list_tail, item;
unsigned int lnr = 0;
int c, i, j;
int errflag = 0;
/* Check whether this is not a filename and treat it as a direct
fingerprint specification. */
if (!strpbrk (string, "/.~\\"))
{
item = xcalloc (1, sizeof *item);
for (i=j=0; (string[i] == ':' || hexdigitp (string+i)) && j < 40; i++)
if ( string[i] != ':' )
item->hexfpr[j++] = string[i] >= 'a'? (string[i] & 0xdf): string[i];
item->hexfpr[j] = 0;
if (j != 40 || !(spacep (string+i) || !string[i]))
{
log_error (_("%s:%u: invalid fingerprint detected\n"),
"--ocsp-signer", 0);
xfree (item);
return NULL;
}
return item;
}
/* Well, it is a filename. */
if (*string == '/' || (*string == '~' && string[1] == '/'))
fname = make_filename (string, NULL);
else
{
if (string[0] == '.' && string[1] == '/' )
string += 2;
fname = make_filename (gnupg_homedir (), string, NULL);
}
fp = es_fopen (fname, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
xfree (fname);
return NULL;
}
list = NULL;
list_tail = &list;
for (;;)
{
if (!es_fgets (line, DIM(line)-1, fp) )
{
if (!es_feof (fp))
{
err = gpg_error_from_syserror ();
log_error (_("%s:%u: read error: %s\n"),
fname, lnr, gpg_strerror (err));
errflag = 1;
}
es_fclose (fp);
if (errflag)
{
while (list)
{
fingerprint_list_t tmp = list->next;
xfree (list);
list = tmp;
}
}
xfree (fname);
return list; /* Ready. */
}
lnr++;
if (!*line || line[strlen(line)-1] != '\n')
{
/* Eat until end of line. */
while ( (c=es_getc (fp)) != EOF && c != '\n')
;
err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
/* */: GPG_ERR_INCOMPLETE_LINE);
log_error (_("%s:%u: read error: %s\n"),
fname, lnr, gpg_strerror (err));
errflag = 1;
continue;
}
/* Allow for empty lines and spaces */
for (p=line; spacep (p); p++)
;
if (!*p || *p == '\n' || *p == '#')
continue;
item = xcalloc (1, sizeof *item);
*list_tail = item;
list_tail = &item->next;
for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
if ( p[i] != ':' )
item->hexfpr[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
item->hexfpr[j] = 0;
if (j != 40 || !(spacep (p+i) || p[i] == '\n'))
{
log_error (_("%s:%u: invalid fingerprint detected\n"), fname, lnr);
errflag = 1;
}
i++;
while (spacep (p+i))
i++;
if (p[i] && p[i] != '\n')
log_info (_("%s:%u: garbage at end of line ignored\n"), fname, lnr);
}
/*NOTREACHED*/
}
/*
Stuff used in daemon mode.
*/
/* Reread parts of the configuration. Note, that this function is
obviously not thread-safe and should only be called from the NPTH
signal handler.
Fixme: Due to the way the argument parsing works, we create a
memory leak here for all string type arguments. There is currently
no clean way to tell whether the memory for the argument has been
allocated or points into the process' original arguments. Unless
we have a mechanism to tell this, we need to live on with this. */
static void
reread_configuration (void)
{
ARGPARSE_ARGS pargs;
FILE *fp;
unsigned int configlineno = 0;
int dummy;
if (!opt.config_filename)
return; /* No config file. */
fp = fopen (opt.config_filename, "r");
if (!fp)
{
log_error (_("option file '%s': %s\n"),
opt.config_filename, strerror(errno) );
return;
}
parse_rereadable_options (NULL, 1); /* Start from the default values. */
memset (&pargs, 0, sizeof pargs);
dummy = 0;
pargs.argc = &dummy;
pargs.flags = 1; /* do not remove the args */
while (optfile_parse (fp, opt.config_filename, &configlineno, &pargs, opts) )
{
if (pargs.r_opt < -1)
pargs.err = 1; /* Print a warning. */
else /* Try to parse this option - ignore unchangeable ones. */
parse_rereadable_options (&pargs, 1);
}
fclose (fp);
post_option_parsing ();
}
/* A global function which allows us to trigger the reload stuff from
other places. */
void
dirmngr_sighup_action (void)
{
log_info (_("SIGHUP received - "
"re-reading configuration and flushing caches\n"));
reread_configuration ();
cert_cache_deinit (0);
crl_cache_deinit ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
reload_dns_stuff (0);
ks_hkp_reload ();
}
/* This function is called if some network activity was done. At this
* point we know the we have a network and we can decide whether to
* run scheduled background tasks soon. The function should return
* quickly and only trigger actions for another thread. */
static void
netactivity_action (void)
{
network_activity_seen = 1;
}
/* The signal handler. */
#ifndef HAVE_W32_SYSTEM
static void
handle_signal (int signo)
{
switch (signo)
{
case SIGHUP:
dirmngr_sighup_action ();
break;
case SIGUSR1:
cert_cache_print_stats ();
domaininfo_print_stats ();
break;
case SIGUSR2:
log_info (_("SIGUSR2 received - no action defined\n"));
break;
case SIGTERM:
if (!shutdown_pending)
log_info (_("SIGTERM received - shutting down ...\n"));
else
log_info (_("SIGTERM received - still %d active connections\n"),
active_connections);
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info (_("shutdown forced\n"));
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
dirmngr_exit (0);
}
break;
case SIGINT:
log_info (_("SIGINT received - immediate shutdown\n"));
log_info( "%s %s stopped\n", strusage(11), strusage(13));
cleanup ();
dirmngr_exit (0);
break;
default:
log_info (_("signal %d received - no action defined\n"), signo);
}
}
#endif /*!HAVE_W32_SYSTEM*/
/* Thread to do the housekeeping. */
static void *
housekeeping_thread (void *arg)
{
static int sentinel;
time_t curtime;
struct server_control_s ctrlbuf;
(void)arg;
curtime = gnupg_get_time ();
if (sentinel)
{
log_info ("housekeeping is already going on\n");
return NULL;
}
sentinel++;
if (opt.verbose > 1)
log_info ("starting housekeeping\n");
memset (&ctrlbuf, 0, sizeof ctrlbuf);
dirmngr_init_default_ctrl (&ctrlbuf);
ks_hkp_housekeeping (curtime);
if (network_activity_seen)
{
network_activity_seen = 0;
if (opt.allow_version_check)
dirmngr_load_swdb (&ctrlbuf, 0);
workqueue_run_global_tasks (&ctrlbuf, 1);
}
else
workqueue_run_global_tasks (&ctrlbuf, 0);
dirmngr_deinit_default_ctrl (&ctrlbuf);
if (opt.verbose > 1)
log_info ("ready with housekeeping\n");
sentinel--;
return NULL;
}
#if GPGRT_GCC_HAVE_PUSH_PRAGMA
# pragma GCC push_options
# pragma GCC optimize ("no-strict-overflow")
#endif
static int
time_for_housekeeping_p (time_t curtime)
{
static time_t last_housekeeping;
if (!last_housekeeping)
last_housekeeping = curtime;
if (last_housekeeping + HOUSEKEEPING_INTERVAL <= curtime
|| last_housekeeping > curtime /*(be prepared for y2038)*/)
{
last_housekeeping = curtime;
return 1;
}
return 0;
}
#if GPGRT_GCC_HAVE_PUSH_PRAGMA
# pragma GCC pop_options
#endif
/* This is the worker for the ticker. It is called every few seconds
and may only do fast operations. */
static void
handle_tick (void)
{
struct stat statbuf;
if (time_for_housekeeping_p (gnupg_get_time ()))
{
npth_t thread;
npth_attr_t tattr;
int err;
err = npth_attr_init (&tattr);
if (err)
log_error ("error preparing housekeeping thread: %s\n", strerror (err));
else
{
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
err = npth_create (&thread, &tattr, housekeeping_thread, NULL);
if (err)
log_error ("error spawning housekeeping thread: %s\n",
strerror (err));
npth_attr_destroy (&tattr);
}
}
/* Check whether the homedir is still available. */
if (!shutdown_pending
&& stat (gnupg_homedir (), &statbuf) && errno == ENOENT)
{
shutdown_pending = 1;
log_info ("homedir has been removed - shutting down\n");
}
}
/* Check the nonce on a new connection. This is a NOP unless we are
using our Unix domain socket emulation under Windows. */
static int
check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
{
if (assuan_sock_check_nonce (fd, nonce))
{
log_info (_("error reading nonce on fd %d: %s\n"),
FD2INT (fd), strerror (errno));
assuan_sock_close (fd);
return -1;
}
else
return 0;
}
/* Helper to call a connection's main function. */
static void *
start_connection_thread (void *arg)
{
static unsigned int last_session_id;
unsigned int session_id;
union int_and_ptr_u argval;
gnupg_fd_t fd;
memset (&argval, 0, sizeof argval);
argval.aptr = arg;
fd = argval.afd;
if (check_nonce (fd, &socket_nonce))
{
log_error ("handler nonce check FAILED\n");
return NULL;
}
#ifndef HAVE_W32_SYSTEM
npth_setspecific (my_tlskey_current_fd, argval.aptr);
#endif
active_connections++;
if (opt.verbose)
log_info (_("handler for fd %d started\n"), FD2INT (fd));
session_id = ++last_session_id;
if (!session_id)
session_id = ++last_session_id;
start_command_handler (fd, session_id);
if (opt.verbose)
log_info (_("handler for fd %d terminated\n"), FD2INT (fd));
active_connections--;
workqueue_run_post_session_tasks (session_id);
#ifndef HAVE_W32_SYSTEM
argval.afd = ASSUAN_INVALID_FD;
npth_setspecific (my_tlskey_current_fd, argval.aptr);
#endif
return NULL;
}
#ifdef HAVE_INOTIFY_INIT
/* Read an inotify event and return true if it matches NAME. */
static int
my_inotify_is_name (int fd, const char *name)
{
union {
struct inotify_event ev;
char _buf[sizeof (struct inotify_event) + 100 + 1];
} buf;
int n;
const char *s;
s = strrchr (name, '/');
if (s && s[1])
name = s + 1;
n = npth_read (fd, &buf, sizeof buf);
if (n < sizeof (struct inotify_event))
return 0;
if (buf.ev.len < strlen (name)+1)
return 0;
if (strcmp (buf.ev.name, name))
return 0; /* Not the desired file. */
return 1; /* Found. */
}
#endif /*HAVE_INOTIFY_INIT*/
/* Main loop in daemon mode. Note that LISTEN_FD will be owned by
* this function. */
static void
handle_connections (assuan_fd_t listen_fd)
{
npth_attr_t tattr;
#ifndef HAVE_W32_SYSTEM
int signo;
#endif
struct sockaddr_un paddr;
socklen_t plen = sizeof( paddr );
int nfd, ret;
fd_set fdset, read_fdset;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
int saved_errno;
int my_inotify_fd = -1;
npth_attr_init (&tattr);
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
#ifndef HAVE_W32_SYSTEM /* FIXME */
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
#endif
#ifdef HAVE_INOTIFY_INIT
if (disable_check_own_socket)
my_inotify_fd = -1;
else if ((my_inotify_fd = inotify_init ()) == -1)
log_info ("error enabling fast daemon termination: %s\n",
strerror (errno));
else
{
/* We need to watch the directory for the file because there
* won't be an IN_DELETE_SELF for a socket file. */
char *slash = strrchr (socket_name, '/');
log_assert (slash && slash[1]);
*slash = 0;
if (inotify_add_watch (my_inotify_fd, socket_name, IN_DELETE) == -1)
{
close (my_inotify_fd);
my_inotify_fd = -1;
}
*slash = '/';
}
#endif /*HAVE_INOTIFY_INIT*/
/* Setup the fdset. It has only one member. This is because we use
pth_select instead of pth_accept to properly sync timeouts with
to full second. */
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
if (my_inotify_fd != -1)
{
FD_SET (my_inotify_fd, &fdset);
if (my_inotify_fd > nfd)
nfd = my_inotify_fd;
}
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
/* Main loop. */
for (;;)
{
/* Shutdown test. */
if (shutdown_pending)
{
if (!active_connections)
break; /* ready */
/* Do not accept new connections but keep on running the
* loop to cope with the timer events.
*
* Note that we do not close the listening socket because a
* client trying to connect to that socket would instead
* restart a new dirmngr instance - which is unlikely the
* intention of a shutdown. */
/* assuan_sock_close (listen_fd); */
/* listen_fd = -1; */
FD_ZERO (&fdset);
nfd = -1;
if (my_inotify_fd != -1)
{
FD_SET (my_inotify_fd, &fdset);
nfd = my_inotify_fd;
}
}
/* Take a copy of the fdset. */
read_fdset = fdset;
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
/* Timeout. When a shutdown is pending we use a shorter
* interval to handle the shutdown more quickly. */
handle_tick ();
npth_clock_gettime (&abstime);
abstime.tv_sec += (shutdown_pending
? TIMERTICK_INTERVAL_SHUTDOWN
: TIMERTICK_INTERVAL);
}
npth_timersub (&abstime, &curtime, &timeout);
#ifndef HAVE_W32_SYSTEM
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
saved_errno = errno;
while (npth_sigev_get_pending(&signo))
handle_signal (signo);
#else
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
saved_errno = errno;
#endif
if (ret == -1 && saved_errno != EINTR)
{
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
strerror (saved_errno));
npth_sleep (1);
continue;
}
if (ret <= 0)
{
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
}
if (shutdown_pending)
{
/* Do not anymore accept connections. */
continue;
}
#ifdef HAVE_INOTIFY_INIT
if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset)
&& my_inotify_is_name (my_inotify_fd, socket_name))
{
shutdown_pending = 1;
log_info ("socket file has been removed - shutting down\n");
}
#endif /*HAVE_INOTIFY_INIT*/
if (FD_ISSET (FD2INT (listen_fd), &read_fdset))
{
gnupg_fd_t fd;
plen = sizeof paddr;
fd = INT2FD (npth_accept (FD2INT(listen_fd),
(struct sockaddr *)&paddr, &plen));
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed: %s\n", strerror (errno));
}
else
{
char threadname[50];
union int_and_ptr_u argval;
npth_t thread;
memset (&argval, 0, sizeof argval);
argval.afd = fd;
snprintf (threadname, sizeof threadname,
"conn fd=%d", FD2INT(fd));
ret = npth_create (&thread, &tattr,
start_connection_thread, argval.aptr);
if (ret)
{
log_error ("error spawning connection handler: %s\n",
strerror (ret) );
assuan_sock_close (fd);
}
npth_setname_np (thread, threadname);
}
}
}
#ifdef HAVE_INOTIFY_INIT
if (my_inotify_fd != -1)
close (my_inotify_fd);
#endif /*HAVE_INOTIFY_INIT*/
npth_attr_destroy (&tattr);
if (listen_fd != GNUPG_INVALID_FD)
assuan_sock_close (listen_fd);
cleanup ();
log_info ("%s %s stopped\n", strusage(11), strusage(13));
}
const char*
dirmngr_get_current_socket_name (void)
{
if (socket_name)
return socket_name;
else
return dirmngr_socket_name ();
}
diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi
index 9654a0e74..800955c52 100644
--- a/doc/dirmngr.texi
+++ b/doc/dirmngr.texi
@@ -1,1177 +1,1181 @@
@c Copyright (C) 2002 Klar"alvdalens Datakonsult AB
@c Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@include defs.inc
@node Invoking DIRMNGR
@chapter Invoking DIRMNGR
@cindex DIRMNGR command options
@cindex command options
@cindex options, DIRMNGR command
@manpage dirmngr.8
@ifset manverb
.B dirmngr
\- CRL and OCSP daemon
@end ifset
@mansect synopsis
@ifset manverb
.B dirmngr
.RI [ options ]
.I command
.RI [ args ]
@end ifset
@mansect description
Since version 2.1 of GnuPG, @command{dirmngr} takes care of accessing
the OpenPGP keyservers. As with previous versions it is also used as
a server for managing and downloading certificate revocation lists
(CRLs) for X.509 certificates, downloading X.509 certificates, and
providing access to OCSP providers. Dirmngr is invoked internally by
@command{gpg}, @command{gpgsm}, or via the @command{gpg-connect-agent}
tool.
@manpause
@noindent
@xref{Option Index},for an index to @command{DIRMNGR}'s commands and
options.
@mancont
@menu
* Dirmngr Commands:: List of all commands.
* Dirmngr Options:: List of all options.
* Dirmngr Configuration:: Configuration files.
* Dirmngr Signals:: Use of signals.
* Dirmngr Examples:: Some usage examples.
* Dirmngr Protocol:: The protocol dirmngr uses.
@end menu
@node Dirmngr Commands
@section Commands
@mansect commands
Commands are not distinguished from options except for the fact that
only one command is allowed.
@table @gnupgtabopt
@item --version
@opindex version
Print the program version and licensing information. Note that you cannot
abbreviate this command.
@item --help, -h
@opindex help
Print a usage message summarizing the most useful command-line options.
Note that you cannot abbreviate this command.
@item --dump-options
@opindex dump-options
Print a list of all available options and commands. Note that you cannot
abbreviate this command.
@item --server
@opindex server
Run in server mode and wait for commands on the @code{stdin}. The
default mode is to create a socket and listen for commands there.
This is only used for testing.
@item --daemon
@opindex daemon
Run in background daemon mode and listen for commands on a socket.
This is the way @command{dirmngr} is started on demand by the other
GnuPG components. To force starting @command{dirmngr} it is in
general best to use @code{gpgconf --launch dirmngr}.
@item --supervised
@opindex supervised
Run in the foreground, sending logs to stderr, and listening on file
descriptor 3, which must already be bound to a listening socket. This
is useful when running under systemd or other similar process
supervision schemes. This option is not supported on Windows.
@item --list-crls
@opindex list-crls
List the contents of the CRL cache on @code{stdout}. This is probably
only useful for debugging purposes.
@item --load-crl @var{file}
@opindex load-crl
This command requires a filename as additional argument, and it will
make Dirmngr try to import the CRL in @var{file} into it's cache.
Note, that this is only possible if Dirmngr is able to retrieve the
CA's certificate directly by its own means. In general it is better
to use @code{gpgsm}'s @code{--call-dirmngr loadcrl filename} command
so that @code{gpgsm} can help dirmngr.
@item --fetch-crl @var{url}
@opindex fetch-crl
This command requires an URL as additional argument, and it will make
dirmngr try to retrieve and import the CRL from that @var{url} into
it's cache. This is mainly useful for debugging purposes. The
@command{dirmngr-client} provides the same feature for a running dirmngr.
@item --shutdown
@opindex shutdown
This commands shuts down an running instance of Dirmngr. This command
has currently no effect.
@item --flush
@opindex flush
This command removes all CRLs from Dirmngr's cache. Client requests
will thus trigger reading of fresh CRLs.
@end table
@mansect options
@node Dirmngr Options
@section Option Summary
Note that all long options with the exception of @option{--options}
and @option{--homedir} may also be given in the configuration file
after stripping off the two leading dashes.
@table @gnupgtabopt
@item --options @var{file}
@opindex options
Reads configuration from @var{file} instead of from the default
per-user configuration file. The default configuration file is named
@file{dirmngr.conf} and expected in the home directory.
@item --homedir @var{dir}
@opindex options
Set the name of the home directory to @var{dir}. This option is only
effective when used on the command line. The default is
the directory named @file{.gnupg} directly below the home directory
of the user unless the environment variable @code{GNUPGHOME} has been set
in which case its value will be used. Many kinds of data are stored within
this directory.
@item -v
@item --verbose
@opindex v
@opindex verbose
Outputs additional information while running.
You can increase the verbosity by giving several
verbose commands to @sc{dirmngr}, such as @option{-vv}.
@item --log-file @var{file}
@opindex log-file
Append all logging output to @var{file}. This is very helpful in
seeing what the agent actually does. Use @file{socket://} to log to
socket.
@item --debug-level @var{level}
@opindex debug-level
Select the debug level for investigating problems. @var{level} may be a
numeric value or by a keyword:
@table @code
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
More verbose debug messages. A value between 3 and 5 may be used
instead of the keyword.
@item expert
Even more detailed messages. A value between 6 and 8 may be used
instead of the keyword.
@item guru
All of the debug messages you can get. A value greater than 8 may be
used instead of the keyword. The creation of hash tracing files is
only enabled if the keyword is used.
@end table
How these messages are mapped to the actual debugging flags is not
specified and may change with newer releases of this program. They are
however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
Set debugging flags. This option is only useful for debugging and its
behavior may change with a new release. All flags are or-ed and may
be given in C syntax (e.g. 0x0042) or as a comma separated list of
flag names. To get a list of all supported flags the single word
"help" can be used.
@item --debug-all
@opindex debug-all
Same as @code{--debug=0xffffffff}
@item --gnutls-debug @var{level}
@opindex gnutls-debug
Enable debugging of GNUTLS at @var{level}.
@item --debug-wait @var{n}
@opindex debug-wait
When running in server mode, wait @var{n} seconds before entering the
actual processing loop and print the pid. This gives time to attach a
debugger.
@item --disable-check-own-socket
@opindex disable-check-own-socket
On some platforms @command{dirmngr} is able to detect the removal of
its socket file and shutdown itself. This option disable this
self-test for debugging purposes.
@item -s
@itemx --sh
@itemx -c
@itemx --csh
@opindex s
@opindex sh
@opindex c
@opindex csh
Format the info output in daemon mode for use with the standard Bourne
shell respective the C-shell. The default is to guess it based on the
environment variable @code{SHELL} which is in almost all cases
sufficient.
@item --force
@opindex force
Enabling this option forces loading of expired CRLs; this is only
useful for debugging.
@item --use-tor
@itemx --no-use-tor
@opindex use-tor
@opindex no-use-tor
The option @option{--use-tor} switches Dirmngr and thus GnuPG into
``Tor mode'' to route all network access via Tor (an anonymity
network). Certain other features are disabled in this mode. The
effect of @option{--use-tor} cannot be overridden by any other command
or even be reloading gpg-agent. The use of @option{--no-use-tor}
disables the use of Tor. The default is to use Tor if it is available
on startup or after reloading dirmngr.
@item --standard-resolver
@opindex standard-resolver
This option forces the use of the system's standard DNS resolver code.
This is mainly used for debugging. Note that on Windows a standard
resolver is not used and all DNS access will return the error ``Not
Implemented'' if this function is used.
@item --recursive-resolver
@opindex recursive-resolver
When possible use a recursive resolver instead of a stub resolver.
@item --resolver-timeout @var{n}
@opindex resolver-timeout
Set the timeout for the DNS resolver to N seconds. The default are 30
seconds.
@item --connect-timeout @var{n}
@item --connect-quick-timeout @var{n}
@opindex connect-timeout
@opindex connect-quick-timeout
Set the timeout for HTTP and generic TCP connection attempts to N
seconds. The value set with the quick variant is used when the
--quick option has been given to certain Assuan commands. The quick
value is capped at the value of the regular connect timeout. The
default values are 15 and 2 seconds. Note that the timeout values are
for each connection attempt; the connection code will attempt to
connect all addresses listed for a server.
+@item --listen-backlog @var{n}
+@opindex listen-backlog
+Set the size of the queue for pending connections. The default is 64.
+
@item --allow-version-check
@opindex allow-version-check
Allow Dirmngr to connect to @code{https://versions.gnupg.org} to get
the list of current software versions. If this option is enabled
the list is retrieved in case the local
copy does not exist or is older than 5 to 7 days. See the option
@option{--query-swdb} of the command @command{gpgconf} for more
details. Note, that regardless of this option a version check can
always be triggered using this command:
@example
gpg-connect-agent --dirmngr 'loadswdb --force' /bye
@end example
@item --keyserver @var{name}
@opindex keyserver
Use @var{name} as your keyserver. This is the server that @command{gpg}
communicates with to receive keys, send keys, and search for
keys. The format of the @var{name} is a URI:
`scheme:[//]keyservername[:port]' The scheme is the type of keyserver:
"hkp" for the HTTP (or compatible) keyservers, "ldap" for the LDAP
keyservers, or "mailto" for the Graff email keyserver. Note that your
particular installation of GnuPG may have other keyserver types
available as well. Keyserver schemes are case-insensitive. After the
keyserver name, optional keyserver configuration options may be
provided. These are the same as the @option{--keyserver-options} of
@command{gpg}, but apply only to this particular keyserver.
Most keyservers synchronize with each other, so there is generally no
need to send keys to more than one server. The keyserver
@code{hkp://keys.gnupg.net} uses round robin DNS to give a different
keyserver each time you use it.
If exactly two keyservers are configured and only one is a Tor hidden
service (.onion), Dirmngr selects the keyserver to use depending on
whether Tor is locally running or not. The check for a running Tor is
done for each new connection.
If no keyserver is explicitly configured, dirmngr will use the
built-in default of hkps://hkps.pool.sks-keyservers.net.
@item --nameserver @var{ipaddr}
@opindex nameserver
In ``Tor mode'' Dirmngr uses a public resolver via Tor to resolve DNS
names. If the default public resolver, which is @code{8.8.8.8}, shall
not be used a different one can be given using this option. Note that
a numerical IP address must be given (IPv6 or IPv4) and that no error
checking is done for @var{ipaddr}.
@item --disable-ipv4
@item --disable-ipv6
@opindex disable-ipv4
@opindex disable-ipv6
Disable the use of all IPv4 or IPv6 addresses.
@item --disable-ldap
@opindex disable-ldap
Entirely disables the use of LDAP.
@item --disable-http
@opindex disable-http
Entirely disables the use of HTTP.
@item --ignore-http-dp
@opindex ignore-http-dp
When looking for the location of a CRL, the to be tested certificate
usually contains so called @dfn{CRL Distribution Point} (DP) entries
which are URLs describing the way to access the CRL. The first found DP
entry is used. With this option all entries using the @acronym{HTTP}
scheme are ignored when looking for a suitable DP.
@item --ignore-ldap-dp
@opindex ignore-ldap-dp
This is similar to @option{--ignore-http-dp} but ignores entries using
the @acronym{LDAP} scheme. Both options may be combined resulting in
ignoring DPs entirely.
@item --ignore-ocsp-service-url
@opindex ignore-ocsp-service-url
Ignore all OCSP URLs contained in the certificate. The effect is to
force the use of the default responder.
@item --honor-http-proxy
@opindex honor-http-proxy
If the environment variable @env{http_proxy} has been set, use its
value to access HTTP servers.
@item --http-proxy @var{host}[:@var{port}]
@opindex http-proxy
@efindex http_proxy
Use @var{host} and @var{port} to access HTTP servers. The use of this
option overrides the environment variable @env{http_proxy} regardless
whether @option{--honor-http-proxy} has been set.
@item --ldap-proxy @var{host}[:@var{port}]
@opindex ldap-proxy
Use @var{host} and @var{port} to connect to LDAP servers. If @var{port}
is omitted, port 389 (standard LDAP port) is used. This overrides any
specified host and port part in a LDAP URL and will also be used if host
and port have been omitted from the URL.
@item --only-ldap-proxy
@opindex only-ldap-proxy
Never use anything else but the LDAP "proxy" as configured with
@option{--ldap-proxy}. Usually @command{dirmngr} tries to use other
configured LDAP server if the connection using the "proxy" failed.
@item --ldapserverlist-file @var{file}
@opindex ldapserverlist-file
Read the list of LDAP servers to consult for CRLs and certificates from
file instead of the default per-user ldap server list file. The default
value for @var{file} is @file{dirmngr_ldapservers.conf}.
This server list file contains one LDAP server per line in the format
@sc{hostname:port:username:password:base_dn}
Lines starting with a @samp{#} are comments.
Note that as usual all strings entered are expected to be UTF-8 encoded.
Obviously this will lead to problems if the password has originally been
encoded as Latin-1. There is no other solution here than to put such a
password in the binary encoding into the file (i.e. non-ascii characters
won't show up readable).@footnote{The @command{gpgconf} tool might be
helpful for frontends as it enables editing this configuration file using
percent-escaped strings.}
@item --ldaptimeout @var{secs}
@opindex ldaptimeout
Specify the number of seconds to wait for an LDAP query before timing
out. The default are 15 seconds. 0 will never timeout.
@item --add-servers
@opindex add-servers
This option makes dirmngr add any servers it discovers when validating
certificates against CRLs to the internal list of servers to consult for
certificates and CRLs.
This option is useful when trying to validate a certificate that has
a CRL distribution point that points to a server that is not already
listed in the ldapserverlist. Dirmngr will always go to this server and
try to download the CRL, but chances are high that the certificate used
to sign the CRL is located on the same server. So if dirmngr doesn't add
that new server to list, it will often not be able to verify the
signature of the CRL unless the @code{--add-servers} option is used.
Note: The current version of dirmngr has this option disabled by default.
@item --allow-ocsp
@opindex allow-ocsp
This option enables OCSP support if requested by the client.
OCSP requests are rejected by default because they may violate the
privacy of the user; for example it is possible to track the time when
a user is reading a mail.
@item --ocsp-responder @var{url}
@opindex ocsp-responder
Use @var{url} as the default OCSP Responder if the certificate does
not contain information about an assigned responder. Note, that
@code{--ocsp-signer} must also be set to a valid certificate.
@item --ocsp-signer @var{fpr}|@var{file}
@opindex ocsp-signer
Use the certificate with the fingerprint @var{fpr} to check the
responses of the default OCSP Responder. Alternatively a filename can be
given in which case the response is expected to be signed by one of the
certificates described in that file. Any argument which contains a
slash, dot or tilde is considered a filename. Usual filename expansion
takes place: A tilde at the start followed by a slash is replaced by the
content of @env{HOME}, no slash at start describes a relative filename
which will be searched at the home directory. To make sure that the
@var{file} is searched in the home directory, either prepend the name
with "./" or use a name which contains a dot.
If a response has been signed by a certificate described by these
fingerprints no further check upon the validity of this certificate is
done.
The format of the @var{FILE} is a list of SHA-1 fingerprint, one per
line with optional colons between the bytes. Empty lines and lines
prefix with a hash mark are ignored.
@item --ocsp-max-clock-skew @var{n}
@opindex ocsp-max-clock-skew
The number of seconds a skew between the OCSP responder and them local
clock is accepted. Default is 600 (10 minutes).
@item --ocsp-max-period @var{n}
@opindex ocsp-max-period
Seconds a response is at maximum considered valid after the time given
in the thisUpdate field. Default is 7776000 (90 days).
@item --ocsp-current-period @var{n}
@opindex ocsp-current-period
The number of seconds an OCSP response is considered valid after the
time given in the NEXT_UPDATE datum. Default is 10800 (3 hours).
@item --max-replies @var{n}
@opindex max-replies
Do not return more that @var{n} items in one query. The default is
10.
@item --ignore-cert-extension @var{oid}
@opindex ignore-cert-extension
Add @var{oid} to the list of ignored certificate extensions. The
@var{oid} is expected to be in dotted decimal form, like
@code{2.5.29.3}. This option may be used more than once. Critical
flagged certificate extensions matching one of the OIDs in the list
are treated as if they are actually handled and thus the certificate
won't be rejected due to an unknown critical extension. Use this
option with care because extensions are usually flagged as critical
for a reason.
@item --hkp-cacert @var{file}
Use the root certificates in @var{file} for verification of the TLS
certificates used with @code{hkps} (keyserver access over TLS). If
the file is in PEM format a suffix of @code{.pem} is expected for
@var{file}. This option may be given multiple times to add more
root certificates. Tilde expansion is supported.
If no @code{hkp-cacert} directive is present, dirmngr will make a
reasonable choice: if the keyserver in question is the special pool
@code{hkps.pool.sks-keyservers.net}, it will use the bundled root
certificate for that pool. Otherwise, it will use the system CAs.
@end table
@c
@c Dirmngr Configuration
@c
@mansect files
@node Dirmngr Configuration
@section Configuration
Dirmngr makes use of several directories when running in daemon mode:
There are a few configuration files whih control the operation of
dirmngr. By default they may all be found in the current home
directory (@pxref{option --homedir}).
@table @file
@item dirmngr.conf
@efindex dirmngr.conf
This is the standard configuration file read by @command{dirmngr} on
startup. It may contain any valid long option; the leading two dashes
may not be entered and the option may not be abbreviated. This file
is also read after a @code{SIGHUP} however not all options will
actually have an effect. This default name may be changed on the
command line (@pxref{option --options}). You should backup this file.
@item /etc/gnupg/trusted-certs
This directory should be filled with certificates of Root CAs you
are trusting in checking the CRLs and signing OCSP Responses.
Usually these are the same certificates you use with the applications
making use of dirmngr. It is expected that each of these certificate
files contain exactly one @acronym{DER} encoded certificate in a file
with the suffix @file{.crt} or @file{.der}. @command{dirmngr} reads
those certificates on startup and when given a SIGHUP. Certificates
which are not readable or do not make up a proper X.509 certificate
are ignored; see the log file for details.
Applications using dirmngr (e.g. gpgsm) can request these
certificates to complete a trust chain in the same way as with the
extra-certs directory (see below).
Note that for OCSP responses the certificate specified using the option
@option{--ocsp-signer} is always considered valid to sign OCSP requests.
@item /etc/gnupg/extra-certs
This directory may contain extra certificates which are preloaded
into the internal cache on startup. Applications using dirmngr (e.g. gpgsm)
can request cached certificates to complete a trust chain.
This is convenient in cases you have a couple intermediate CA certificates
or certificates usually used to sign OCSP responses.
These certificates are first tried before going
out to the net to look for them. These certificates must also be
@acronym{DER} encoded and suffixed with @file{.crt} or @file{.der}.
@item ~/.gnupg/crls.d
This directory is used to store cached CRLs. The @file{crls.d}
part will be created by dirmngr if it does not exists but you need to
make sure that the upper directory exists.
@end table
@manpause
To be able to see what's going on you should create the configure file
@file{~/gnupg/dirmngr.conf} with at least one line:
@example
log-file ~/dirmngr.log
@end example
To be able to perform OCSP requests you probably want to add the line:
@example
allow-ocsp
@end example
To make sure that new options are read and that after the installation
of a new GnuPG versions the installed dirmngr is running, you may want
to kill an existing dirmngr first:
@example
gpgconf --kill dirmngr
@end example
You may check the log file to see whether all desired root
certificates have been loaded correctly.
@c
@c Dirmngr Signals
@c
@mansect signals
@node Dirmngr Signals
@section Use of signals
A running @command{dirmngr} may be controlled by signals, i.e. using
the @command{kill} command to send a signal to the process.
Here is a list of supported signals:
@table @gnupgtabopt
@item SIGHUP
@cpindex SIGHUP
This signal flushes all internally cached CRLs as well as any cached
certificates. Then the certificate cache is reinitialized as on
startup. Options are re-read from the configuration file. Instead of
sending this signal it is better to use
@example
gpgconf --reload dirmngr
@end example
@item SIGTERM
@cpindex SIGTERM
Shuts down the process but waits until all current requests are
fulfilled. If the process has received 3 of these signals and requests
are still pending, a shutdown is forced. You may also use
@example
gpgconf --kill dirmngr
@end example
instead of this signal
@item SIGINT
@cpindex SIGINT
Shuts down the process immediately.
@item SIGUSR1
@cpindex SIGUSR1
This prints some caching statistics to the log file.
@end table
@c
@c Examples
@c
@mansect examples
@node Dirmngr Examples
@section Examples
Here is an example on how to show dirmngr's internal table of OpenPGP
keyserver addresses. The output is intended for debugging purposes
and not part of a defined API.
@example
gpg-connect-agent --dirmngr 'keyserver --hosttable' /bye
@end example
To inhibit the use of a particular host you have noticed in one of the
keyserver pools, you may use
@example
gpg-connect-agent --dirmngr 'keyserver --dead pgpkeys.bnd.de' /bye
@end example
The description of the @code{keyserver} command can be printed using
@example
gpg-connect-agent --dirmngr 'help keyserver' /bye
@end example
@c
@c Assuan Protocol
@c
@manpause
@node Dirmngr Protocol
@section Dirmngr's Assuan Protocol
Assuan is the IPC protocol used to access dirmngr. This is a
description of the commands implemented by dirmngr.
@menu
* Dirmngr LOOKUP:: Look up a certificate via LDAP
* Dirmngr ISVALID:: Validate a certificate using a CRL or OCSP.
* Dirmngr CHECKCRL:: Validate a certificate using a CRL.
* Dirmngr CHECKOCSP:: Validate a certificate using OCSP.
* Dirmngr CACHECERT:: Put a certificate into the internal cache.
* Dirmngr VALIDATE:: Validate a certificate for debugging.
@end menu
@node Dirmngr LOOKUP
@subsection Return the certificate(s) found
Lookup certificate. To allow multiple patterns (which are ORed)
quoting is required: Spaces are to be translated into "+" or into
"%20"; obviously this requires that the usual escape quoting rules
are applied. The server responds with:
@example
S: D
S: END
S: D
S: END
S: OK
@end example
In this example 2 certificates are returned. The server may return
any number of certificates; OK will also be returned when no
certificates were found. The dirmngr might return a status line
@example
S: S TRUNCATED
@end example
To indicate that the output was truncated to N items due to a
limitation of the server or by an arbitrary set limit.
The option @option{--url} may be used if instead of a search pattern a
complete URL to the certificate is known:
@example
C: LOOKUP --url CN%3DWerner%20Koch,o%3DIntevation%20GmbH,c%3DDE?userCertificate
@end example
If the option @option{--cache-only} is given, no external lookup is done
so that only certificates from the cache are returned.
With the option @option{--single}, the first and only the first match
will be returned. Unless option @option{--cache-only} is also used, no
local lookup will be done in this case.
@node Dirmngr ISVALID
@subsection Validate a certificate using a CRL or OCSP
@example
ISVALID [--only-ocsp] [--force-default-responder] @var{certid}|@var{certfpr}
@end example
Check whether the certificate described by the @var{certid} has been
revoked. Due to caching, the Dirmngr is able to answer immediately in
most cases.
The @var{certid} is a hex encoded string consisting of two parts,
delimited by a single dot. The first part is the SHA-1 hash of the
issuer name and the second part the serial number.
Alternatively the certificate's SHA-1 fingerprint @var{certfpr} may be
given in which case an OCSP request is done before consulting the CRL.
If the option @option{--only-ocsp} is given, no fallback to a CRL check
will be used. If the option @option{--force-default-responder} is
given, only the default OCSP responder will be used and any other
methods of obtaining an OCSP responder URL won't be used.
@noindent
Common return values are:
@table @code
@item GPG_ERR_NO_ERROR (0)
This is the positive answer: The certificate is not revoked and we have
an up-to-date revocation list for that certificate. If OCSP was used
the responder confirmed that the certificate has not been revoked.
@item GPG_ERR_CERT_REVOKED
This is the negative answer: The certificate has been revoked. Either
it is in a CRL and that list is up to date or an OCSP responder informed
us that it has been revoked.
@item GPG_ERR_NO_CRL_KNOWN
No CRL is known for this certificate or the CRL is not valid or out of
date.
@item GPG_ERR_NO_DATA
The OCSP responder returned an ``unknown'' status. This means that it
is not aware of the certificate's status.
@item GPG_ERR_NOT_SUPPORTED
This is commonly seen if OCSP support has not been enabled in the
configuration.
@end table
If DirMngr has not enough information about the given certificate (which
is the case for not yet cached certificates), it will inquire the
missing data:
@example
S: INQUIRE SENDCERT
C: D
C: END
@end example
A client should be aware that DirMngr may ask for more than one
certificate.
If Dirmngr has a certificate but the signature of the certificate
could not been validated because the root certificate is not known to
dirmngr as trusted, it may ask back to see whether the client trusts
this the root certificate:
@example
S: INQUIRE ISTRUSTED
C: D 1
C: END
@end example
Only this answer will let Dirmngr consider the certificate as valid.
@node Dirmngr CHECKCRL
@subsection Validate a certificate using a CRL
Check whether the certificate with FINGERPRINT (SHA-1 hash of the
entire X.509 certificate blob) is valid or not by consulting the CRL
responsible for this certificate. If the fingerprint has not been
given or the certificate is not known, the function inquires the
certificate using:
@example
S: INQUIRE TARGETCERT
C: D
C: END
@end example
Thus the caller is expected to return the certificate for the request
(which should match FINGERPRINT) as a binary blob. Processing then
takes place without further interaction; in particular dirmngr tries
to locate other required certificate by its own mechanism which
includes a local certificate store as well as a list of trusted root
certificates.
@noindent
The return code is 0 for success; i.e. the certificate has not been
revoked or one of the usual error codes from libgpg-error.
@node Dirmngr CHECKOCSP
@subsection Validate a certificate using OCSP
@example
CHECKOCSP [--force-default-responder] [@var{fingerprint}]
@end example
Check whether the certificate with @var{fingerprint} (the SHA-1 hash of
the entire X.509 certificate blob) is valid by consulting the appropriate
OCSP responder. If the fingerprint has not been given or the
certificate is not known by Dirmngr, the function inquires the
certificate using:
@example
S: INQUIRE TARGETCERT
C: D
C: END
@end example
Thus the caller is expected to return the certificate for the request
(which should match @var{fingerprint}) as a binary blob. Processing
then takes place without further interaction; in particular dirmngr
tries to locate other required certificates by its own mechanism which
includes a local certificate store as well as a list of trusted root
certificates.
If the option @option{--force-default-responder} is given, only the
default OCSP responder is used. This option is the per-command variant
of the global option @option{--ignore-ocsp-service-url}.
@noindent
The return code is 0 for success; i.e. the certificate has not been
revoked or one of the usual error codes from libgpg-error.
@node Dirmngr CACHECERT
@subsection Put a certificate into the internal cache
Put a certificate into the internal cache. This command might be
useful if a client knows in advance certificates required for a test and
wants to make sure they get added to the internal cache. It is also
helpful for debugging. To get the actual certificate, this command
immediately inquires it using
@example
S: INQUIRE TARGETCERT
C: D
C: END
@end example
Thus the caller is expected to return the certificate for the request
as a binary blob.
@noindent
The return code is 0 for success; i.e. the certificate has not been
successfully cached or one of the usual error codes from libgpg-error.
@node Dirmngr VALIDATE
@subsection Validate a certificate for debugging
Validate a certificate using the certificate validation function used
internally by dirmngr. This command is only useful for debugging. To
get the actual certificate, this command immediately inquires it using
@example
S: INQUIRE TARGETCERT
C: D
C: END
@end example
Thus the caller is expected to return the certificate for the request
as a binary blob.
@mansect see also
@ifset isman
@command{gpgsm}(1),
@command{dirmngr-client}(1)
@end ifset
@include see-also-note.texi
@c
@c !!! UNDER CONSTRUCTION !!!
@c
@c
@c @section Verifying a Certificate
@c
@c There are several ways to request services from Dirmngr. Almost all of
@c them are done using the Assuan protocol. What we describe here is the
@c Assuan command CHECKCRL as used for example by the dirmnr-client tool if
@c invoked as
@c
@c @example
@c dirmngr-client foo.crt
@c @end example
@c
@c This command will send an Assuan request to an already running Dirmngr
@c instance. foo.crt is expected to be a standard X.509 certificate and
@c dirmngr will receive the Assuan command
@c
@c @example
@c CHECKCRL @var [{fingerprint}]
@c @end example
@c
@c @var{fingerprint} is optional and expected to be the SHA-1 has of the
@c DER encoding of the certificate under question. It is to be HEX
@c encoded. The rationale for sending the fingerprint is that it allows
@c dirmngr to reply immediately if it has already cached such a request. If
@c this is not the case and no certificate has been found in dirmngr's
@c internal certificate storage, dirmngr will request the certificate using
@c the Assuan inquiry
@c
@c @example
@c INQUIRE TARGETCERT
@c @end example
@c
@c The caller (in our example dirmngr-client) is then expected to return
@c the certificate for the request (which should match @var{fingerprint})
@c as a binary blob.
@c
@c Dirmngr now passes control to @code{crl_cache_cert_isvalid}. This
@c function checks whether a CRL item exists for target certificate. These
@c CRL items are kept in a database of already loaded and verified CRLs.
@c This mechanism is called the CRL cache. Obviously timestamps are kept
@c there with each item to cope with the expiration date of the CRL. The
@c possible return values are: @code{0} to indicate that a valid CRL is
@c available for the certificate and the certificate itself is not listed
@c in this CRL, @code{GPG_ERR_CERT_REVOKED} to indicate that the certificate is
@c listed in the CRL or @code{GPG_ERR_NO_CRL_KNOWN} in cases where no CRL or no
@c information is available. The first two codes are immediately returned to
@c the caller and the processing of this request has been done.
@c
@c Only the @code{GPG_ERR_NO_CRL_KNOWN} needs more attention: Dirmngr now
@c calls @code{clr_cache_reload_crl} and if this succeeds calls
@c @code{crl_cache_cert_isvald) once more. All further errors are
@c immediately returned to the caller.
@c
@c @code{crl_cache_reload_crl} is the actual heart of the CRL management.
@c It locates the corresponding CRL for the target certificate, reads and
@c verifies this CRL and stores it in the CRL cache. It works like this:
@c
@c * Loop over all crlDPs in the target certificate.
@c * If the crlDP is invalid immediately terminate the loop.
@c * Loop over all names in the current crlDP.
@c * If the URL scheme is unknown or not enabled
@c (--ignore-http-dp, --ignore-ldap-dp) continues with
@c the next name.
@c * @code{crl_fetch} is called to actually retrieve the CRL.
@c In case of problems this name is ignore and we continue with
@c the next name. Note that @code{crl_fetch} does only return
@c a descriptor for the CRL for further reading so does the CRL
@c does not yet end up in memory.
@c * @code{crl_cache_insert} is called with that descriptor to
@c actually read the CRL into the cache. See below for a
@c description of this function. If there is any error (e.g. read
@c problem, CRL not correctly signed or verification of signature
@c not possible), this descriptor is rejected and we continue
@c with the next name. If the CRL has been successfully loaded,
@c the loop is terminated.
@c * If no crlDP has been found in the previous loop use a default CRL.
@c Note, that if any crlDP has been found but loading of the CRL failed,
@c this condition is not true.
@c * Try to load a CRL from all configured servers (ldapservers.conf)
@c in turn. The first server returning a CRL is used.
@c * @code(crl_cache_insert) is then used to actually insert the CRL
@c into the cache. If this failed we give up immediately without
@c checking the rest of the servers from the first step.
@c * Ready.
@c
@c
@c The @code{crl_cache_insert} function takes care of reading the bulk of
@c the CRL, parsing it and checking the signature. It works like this: A
@c new database file is created using a temporary file name. The CRL
@c parsing machinery is started and all items of the CRL are put into
@c this database file. At the end the issuer certificate of the CRL
@c needs to be retrieved. Three cases are to be distinguished:
@c
@c a) An authorityKeyIdentifier with an issuer and serialno exits: The
@c certificate is retrieved using @code{find_cert_bysn}. If
@c the certificate is in the certificate cache, it is directly
@c returned. Then the requester (i.e. the client who requested the
@c CRL check) is asked via the Assuan inquiry ``SENDCERT'' whether
@c he can provide this certificate. If this succeed the returned
@c certificate gets cached and returned. Note, that dirmngr does not
@c verify in any way whether the expected certificate is returned.
@c It is in the interest of the client to return a useful certificate
@c as otherwise the service request will fail due to a bad signature.
@c The last way to get the certificate is by looking it up at
@c external resources. This is done using the @code{ca_cert_fetch}
@c and @code{fetch_next_ksba_cert} and comparing the returned
@c certificate to match the requested issuer and seriano (This is
@c needed because the LDAP layer may return several certificates as
@c LDAP as no standard way to retrieve by serial number).
@c
@c b) An authorityKeyIdentifier with a key ID exists: The certificate is
@c retrieved using @code{find_cert_bysubject}. If the certificate is
@c in the certificate cache, it is directly returned. Then the
@c requester is asked via the Assuan inquiry ``SENDCERT_SKI'' whether
@c he can provide this certificate. If this succeed the returned
@c certificate gets cached and returned. Note, that dirmngr does not
@c verify in any way whether the expected certificate is returned.
@c It is in the interest of the client to return a useful certificate
@c as otherwise the service request will fail due to a bad signature.
@c The last way to get the certificate is by looking it up at
@c external resources. This is done using the @code{ca_cert_fetch}
@c and @code{fetch_next_ksba_cert} and comparing the returned
@c certificate to match the requested subject and key ID.
@c
@c c) No authorityKeyIdentifier exits: The certificate is retrieved
@c using @code{find_cert_bysubject} without the key ID argument. If
@c the certificate is in the certificate cache the first one with a
@c matching subject is directly returned. Then the requester is
@c asked via the Assuan inquiry ``SENDCERT'' and an exact
@c specification of the subject whether he can
@c provide this certificate. If this succeed the returned
@c certificate gets cached and returned. Note, that dirmngr does not
@c verify in any way whether the expected certificate is returned.
@c It is in the interest of the client to return a useful certificate
@c as otherwise the service request will fail due to a bad signature.
@c The last way to get the certificate is by looking it up at
@c external resources. This is done using the @code{ca_cert_fetch}
@c and @code{fetch_next_ksba_cert} and comparing the returned
@c certificate to match the requested subject; the first certificate
@c with a matching subject is then returned.
@c
@c If no certificate was found, the function returns with the error
@c GPG_ERR_MISSING_CERT. Now the signature is verified. If this fails,
@c the erro is returned. On success the @code{validate_cert_chain} is
@c used to verify that the certificate is actually valid.
@c
@c Here we may encounter a recursive situation:
@c @code{validate_cert_chain} needs to look at other certificates and
@c also at CRLs to check whether these other certificates and well, the
@c CRL issuer certificate itself are not revoked. FIXME: We need to make
@c sure that @code{validate_cert_chain} does not try to lookup the CRL we
@c are currently processing. This would be a catch-22 and may indicate a
@c broken PKI. However, due to overlapping expiring times and imprecise
@c clocks this may actually happen.
@c
@c For historical reasons the Assuan command ISVALID is a bit different
@c to CHECKCRL but this is mainly due to different calling conventions.
@c In the end the same fucntionality is used, albeit hidden by a couple
@c of indirection and argument and result code mangling. It furthere
@c ingetrages OCSP checking depending on options are the way it is
@c called. GPGSM still uses this command but might eventuall switch over
@c to CHECKCRL and CHECKOCSP so that ISVALID can be retired.
@c
@c
@c @section Validating a certificate
@c
@c We describe here how the internal function @code{validate_cert_chain}
@c works. Note that mainly testing purposes this functionality may be
@c called directly using @cmd{dirmngr-client --validate @file{foo.crt}}.
@c
@c The function takes the target certificate and a mode argument as
@c parameters and returns an error code and optionally the closes
@c expiration time of all certificates in the chain.
@c
@c We first check that the certificate may be used for the requested
@c purpose (i.e. OCSP or CRL signing). If this is not the case
@c GPG_ERR_WRONG_KEY_USAGE is returned.
@c
@c The next step is to find the trust anchor (root certificate) and to
@c assemble the chain in memory: Starting with the target certificate,
@c the expiration time is checked against the current date, unknown
@c critical extensions are detected and certificate policies are matched
@c (We only allow 2.289.9.9 but I have no clue about that OID and from
@c where I got it - it does not even seem to be assigned - debug cruft?).
@c
@c Now if this certificate is a self-signed one, we have reached the
@c trust anchor. In this case we check that the signature is good, the
@c certificate is allowed to act as a CA, that it is a trusted one (by
@c checking whether it is has been put into the trusted-certs
@c configuration directory) and finally prepend into to our list
@c representing the certificate chain. This steps ends then.
@c
@c If it is not a self-signed certificate, we check that the chain won't
@c get too long (current limit is 100), if this is the case we terminate
@c with the error GPG_ERR_BAD_CERT_CHAIN.
@c
@c Now the issuer's certificate is looked up: If an
@c authorityKeyIdentifier is available, this one is used to locate the
@c certificate either using issuer and serialnumber or subject DN
@c (i.e. the issuer's DN) and the keyID. The functions
@c @code{find_cert_bysn) and @code{find_cert_bysubject} are used
@c respectively. The have already been described above under the
@c description of @code{crl_cache_insert}. If no certificate was found
@c or with no authorityKeyIdentifier, only the cache is consulted using
@c @code{get_cert_bysubject}. The latter is done under the assumption
@c that a matching certificate has explicitly been put into the
@c certificate cache. If the issuer's certificate could not be found,
@c the validation terminates with the error code @code{GPG_ERR_MISSING_CERT}.
@c
@c If the issuer's certificate has been found, the signature of the
@c actual certificate is checked and in case this fails the error
@c #code{GPG_ERR_BAD_CERT_CHAIN} is returned. If the signature checks out, the
@c maximum chain length of the issuing certificate is checked as well as
@c the capability of the certificate (i.e. whether he may be used for
@c certificate signing). Then the certificate is prepended to our list
@c representing the certificate chain. Finally the loop is continued now
@c with the issuer's certificate as the current certificate.
@c
@c After the end of the loop and if no error as been encountered
@c (i.e. the certificate chain has been assempled correctly), a check is
@c done whether any certificate expired or a critical policy has not been
@c met. In any of these cases the validation terminates with an
@c appropriate error.
@c
@c Finally the function @code{check_revocations} is called to verify no
@c certificate in the assempled chain has been revoked: This is an
@c recursive process because a CRL has to be checked for each certificate
@c in the chain except for the root certificate, of which we already know
@c that it is trusted and we avoid checking a CRL here due to common
@c setup problems and the assumption that a revoked root certificate has
@c been removed from the list of trusted certificates.
@c
@c
@c
@c
@c @section Looking up certificates through LDAP.
@c
@c This describes the LDAP layer to retrieve certificates.
@c the functions @code{ca_cert_fetch} and @code{fetch_next_ksba_cert} are
@c used for this. The first one starts a search and the second one is
@c used to retrieve certificate after certificate.
@c
diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
index 65df9708b..3e8bd894d 100644
--- a/doc/gpg-agent.texi
+++ b/doc/gpg-agent.texi
@@ -1,1589 +1,1592 @@
@c Copyright (C) 2002 Free Software Foundation, Inc.
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@include defs.inc
@node Invoking GPG-AGENT
@chapter Invoking GPG-AGENT
@cindex GPG-AGENT command options
@cindex command options
@cindex options, GPG-AGENT command
@manpage gpg-agent.1
@ifset manverb
.B gpg-agent
\- Secret key management for GnuPG
@end ifset
@mansect synopsis
@ifset manverb
.B gpg-agent
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.br
.B gpg-agent
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-server
.br
.B gpg-agent
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-daemon
.RI [ command_line ]
@end ifset
@mansect description
@command{gpg-agent} is a daemon to manage secret (private) keys
independently from any protocol. It is used as a backend for
@command{gpg} and @command{gpgsm} as well as for a couple of other
utilities.
The agent is automatically started on demand by @command{gpg},
@command{gpgsm}, @command{gpgconf}, or @command{gpg-connect-agent}.
Thus there is no reason to start it manually. In case you want to use
the included Secure Shell Agent you may start the agent using:
@c From dkg on gnupg-devel on 2016-04-21:
@c
@c Here's an attempt at writing a short description of the goals of an
@c isolated cryptographic agent:
@c
@c A cryptographic agent should control access to secret key material.
@c The agent permits use of the secret key material by a supplicant
@c without providing a copy of the secret key material to the supplicant.
@c
@c An isolated cryptographic agent separates the request for use of
@c secret key material from permission for use of secret key material.
@c That is, the system or process requesting use of the key (the
@c "supplicant") can be denied use of the key by the owner/operator of
@c the agent (the "owner"), which the supplicant has no control over.
@c
@c One way of enforcing this split is a per-key or per-session
@c passphrase, known only by the owner, which must be supplied to the
@c agent to permit the use of the secret key material. Another way is
@c with an out-of-band permission mechanism (e.g. a button or GUI
@c interface that the owner has access to, but the supplicant does not).
@c
@c The rationale for this separation is that it allows access to the
@c secret key to be tightly controlled and audited, and it doesn't permit
@c the supplicant to either copy the key or to override the owner's
@c intentions.
@example
gpg-connect-agent /bye
@end example
@noindent
If you want to manually terminate the currently-running agent, you can
safely do so with:
@example
gpgconf --kill gpg-agent
@end example
@noindent
@efindex GPG_TTY
You should always add the following lines to your @code{.bashrc} or
whatever initialization file is used for all shell invocations:
@smallexample
GPG_TTY=$(tty)
export GPG_TTY
@end smallexample
@noindent
It is important that this environment variable always reflects the
output of the @code{tty} command. For W32 systems this option is not
required.
Please make sure that a proper pinentry program has been installed
under the default filename (which is system dependent) or use the
option @option{pinentry-program} to specify the full name of that program.
It is often useful to install a symbolic link from the actual used
pinentry (e.g. @file{@value{BINDIR}/pinentry-gtk}) to the expected
one (e.g. @file{@value{BINDIR}/pinentry}).
@manpause
@noindent
@xref{Option Index}, for an index to @command{GPG-AGENT}'s commands and options.
@mancont
@menu
* Agent Commands:: List of all commands.
* Agent Options:: List of all options.
* Agent Configuration:: Configuration files.
* Agent Signals:: Use of some signals.
* Agent Examples:: Some usage examples.
* Agent Protocol:: The protocol the agent uses.
@end menu
@mansect commands
@node Agent Commands
@section Commands
Commands are not distinguished from options except for the fact that
only one command is allowed.
@table @gnupgtabopt
@item --version
@opindex version
Print the program version and licensing information. Note that you cannot
abbreviate this command.
@item --help
@itemx -h
@opindex help
Print a usage message summarizing the most useful command-line options.
Note that you cannot abbreviate this command.
@item --dump-options
@opindex dump-options
Print a list of all available options and commands. Note that you cannot
abbreviate this command.
@item --server
@opindex server
Run in server mode and wait for commands on the @code{stdin}. The
default mode is to create a socket and listen for commands there.
@item --daemon [@var{command line}]
@opindex daemon
Start the gpg-agent as a daemon; that is, detach it from the console
and run it in the background.
As an alternative you may create a new process as a child of
gpg-agent: @code{gpg-agent --daemon /bin/sh}. This way you get a new
shell with the environment setup properly; after you exit from this
shell, gpg-agent terminates within a few seconds.
@item --supervised
@opindex supervised
Run in the foreground, sending logs by default to stderr, and
listening on provided file descriptors, which must already be bound to
listening sockets. This command is useful when running under systemd
or other similar process supervision schemes. This option is not
supported on Windows.
In --supervised mode, different file descriptors can be provided for
use as different socket types (e.g. ssh, extra) as long as they are
identified in the environment variable @code{LISTEN_FDNAMES} (see
sd_listen_fds(3) on some Linux distributions for more information on
this convention).
@end table
@mansect options
@node Agent Options
@section Option Summary
Options may either be used on the command line or, after stripping off
the two leading dashes, in the configuration file.
@table @gnupgtabopt
@anchor{option --options}
@item --options @var{file}
@opindex options
Reads configuration from @var{file} instead of from the default
per-user configuration file. The default configuration file is named
@file{gpg-agent.conf} and expected in the @file{.gnupg} directory
directly below the home directory of the user. This option is ignored
if used in an options file.
@anchor{option --homedir}
@include opt-homedir.texi
@item -v
@item --verbose
@opindex verbose
Outputs additional information while running.
You can increase the verbosity by giving several
verbose commands to @command{gpg-agent}, such as @samp{-vv}.
@item -q
@item --quiet
@opindex quiet
Try to be as quiet as possible.
@item --batch
@opindex batch
Don't invoke a pinentry or do any other thing requiring human interaction.
@item --faked-system-time @var{epoch}
@opindex faked-system-time
This option is only useful for testing; it sets the system time back or
forth to @var{epoch} which is the number of seconds elapsed since the year
1970.
@item --debug-level @var{level}
@opindex debug-level
Select the debug level for investigating problems. @var{level} may be
a numeric value or a keyword:
@table @code
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
More verbose debug messages. A value between 3 and 5 may be used
instead of the keyword.
@item expert
Even more detailed messages. A value between 6 and 8 may be used
instead of the keyword.
@item guru
All of the debug messages you can get. A value greater than 8 may be
used instead of the keyword. The creation of hash tracing files is
only enabled if the keyword is used.
@end table
How these messages are mapped to the actual debugging flags is not
specified and may change with newer releases of this program. They are
however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
This option is only useful for debugging and the behavior may change at
any time without notice. FLAGS are bit encoded and may be given in
usual C-Syntax. The currently defined bits are:
@table @code
@item 0 (1)
X.509 or OpenPGP protocol related data
@item 1 (2)
values of big number integers
@item 2 (4)
low level crypto operations
@item 5 (32)
memory allocation
@item 6 (64)
caching
@item 7 (128)
show memory statistics
@item 9 (512)
write hashed data to files named @code{dbgmd-000*}
@item 10 (1024)
trace Assuan protocol
@item 12 (4096)
bypass all certificate validation
@end table
@item --debug-all
@opindex debug-all
Same as @code{--debug=0xffffffff}
@item --debug-wait @var{n}
@opindex debug-wait
When running in server mode, wait @var{n} seconds before entering the
actual processing loop and print the pid. This gives time to attach a
debugger.
@item --debug-quick-random
@opindex debug-quick-random
This option inhibits the use of the very secure random quality level
(Libgcrypt’s @code{GCRY_VERY_STRONG_RANDOM}) and degrades all request
down to standard random quality. It is only used for testing and
should not be used for any production quality keys. This option is
only effective when given on the command line.
On GNU/Linux, another way to quickly generate insecure keys is to use
@command{rngd} to fill the kernel's entropy pool with lower quality
random data. @command{rngd} is typically provided by the
@command{rng-tools} package. It can be run as follows: @samp{sudo
rngd -f -r /dev/urandom}.
@item --debug-pinentry
@opindex debug-pinentry
This option enables extra debug information pertaining to the
Pinentry. As of now it is only useful when used along with
@code{--debug 1024}.
@item --no-detach
@opindex no-detach
Don't detach the process from the console. This is mainly useful for
debugging.
@item -s
@itemx --sh
@itemx -c
@itemx --csh
@opindex sh
@opindex csh
@efindex SHELL
Format the info output in daemon mode for use with the standard Bourne
shell or the C-shell respectively. The default is to guess it based on
the environment variable @code{SHELL} which is correct in almost all
cases.
@item --grab
@itemx --no-grab
@opindex grab
@opindex no-grab
Tell the pinentry to grab the keyboard and mouse. This option should
be used on X-Servers to avoid X-sniffing attacks. Any use of the
option @option{--grab} overrides an used option @option{--no-grab}.
The default is @option{--no-grab}.
@anchor{option --log-file}
@item --log-file @var{file}
@opindex log-file
@efindex HKCU\Software\GNU\GnuPG:DefaultLogFile
Append all logging output to @var{file}. This is very helpful in
seeing what the agent actually does. Use @file{socket://} to log to
socket. If neither a log file nor a log file descriptor has been set
on a Windows platform, the Registry entry
@code{HKCU\Software\GNU\GnuPG:DefaultLogFile}, if set, is used to
specify the logging output.
@anchor{option --no-allow-mark-trusted}
@item --no-allow-mark-trusted
@opindex no-allow-mark-trusted
Do not allow clients to mark keys as trusted, i.e. put them into the
@file{trustlist.txt} file. This makes it harder for users to inadvertently
accept Root-CA keys.
@anchor{option --allow-preset-passphrase}
@item --allow-preset-passphrase
@opindex allow-preset-passphrase
This option allows the use of @command{gpg-preset-passphrase} to seed the
internal cache of @command{gpg-agent} with passphrases.
@anchor{option --no-allow-loopback-pinentry}
@item --no-allow-loopback-pinentry
@item --allow-loopback-pinentry
@opindex no-allow-loopback-pinentry
@opindex allow-loopback-pinentry
Disallow or allow clients to use the loopback pinentry features; see
the option @option{pinentry-mode} for details. Allow is the default.
The @option{--force} option of the Assuan command @command{DELETE_KEY}
is also controlled by this option: The option is ignored if a loopback
pinentry is disallowed.
@item --no-allow-external-cache
@opindex no-allow-external-cache
Tell Pinentry not to enable features which use an external cache for
passphrases.
Some desktop environments prefer to unlock all
credentials with one master password and may have installed a Pinentry
which employs an additional external cache to implement such a policy.
By using this option the Pinentry is advised not to make use of such a
cache and instead always ask the user for the requested passphrase.
@item --allow-emacs-pinentry
@opindex allow-emacs-pinentry
Tell Pinentry to allow features to divert the passphrase entry to a
running Emacs instance. How this is exactly handled depends on the
version of the used Pinentry.
@item --ignore-cache-for-signing
@opindex ignore-cache-for-signing
This option will let @command{gpg-agent} bypass the passphrase cache for all
signing operation. Note that there is also a per-session option to
control this behavior but this command line option takes precedence.
@item --default-cache-ttl @var{n}
@opindex default-cache-ttl
Set the time a cache entry is valid to @var{n} seconds. The default
is 600 seconds. Each time a cache entry is accessed, the entry's
timer is reset. To set an entry's maximum lifetime, use
@command{max-cache-ttl}.
@item --default-cache-ttl-ssh @var{n}
@opindex default-cache-ttl
Set the time a cache entry used for SSH keys is valid to @var{n}
seconds. The default is 1800 seconds. Each time a cache entry is
accessed, the entry's timer is reset. To set an entry's maximum
lifetime, use @command{max-cache-ttl-ssh}.
@item --max-cache-ttl @var{n}
@opindex max-cache-ttl
Set the maximum time a cache entry is valid to @var{n} seconds. After
this time a cache entry will be expired even if it has been accessed
recently or has been set using @command{gpg-preset-passphrase}. The
default is 2 hours (7200 seconds).
@item --max-cache-ttl-ssh @var{n}
@opindex max-cache-ttl-ssh
Set the maximum time a cache entry used for SSH keys is valid to
@var{n} seconds. After this time a cache entry will be expired even
if it has been accessed recently or has been set using
@command{gpg-preset-passphrase}. The default is 2 hours (7200
seconds).
@item --enforce-passphrase-constraints
@opindex enforce-passphrase-constraints
Enforce the passphrase constraints by not allowing the user to bypass
them using the ``Take it anyway'' button.
@item --min-passphrase-len @var{n}
@opindex min-passphrase-len
Set the minimal length of a passphrase. When entering a new passphrase
shorter than this value a warning will be displayed. Defaults to 8.
@item --min-passphrase-nonalpha @var{n}
@opindex min-passphrase-nonalpha
Set the minimal number of digits or special characters required in a
passphrase. When entering a new passphrase with less than this number
of digits or special characters a warning will be displayed. Defaults
to 1.
@item --check-passphrase-pattern @var{file}
@opindex check-passphrase-pattern
Check the passphrase against the pattern given in @var{file}. When
entering a new passphrase matching one of these pattern a warning will
be displayed. @var{file} should be an absolute filename. The default is
not to use any pattern file.
Security note: It is known that checking a passphrase against a list of
pattern or even against a complete dictionary is not very effective to
enforce good passphrases. Users will soon figure up ways to bypass such
a policy. A better policy is to educate users on good security
behavior and optionally to run a passphrase cracker regularly on all
users passphrases to catch the very simple ones.
@item --max-passphrase-days @var{n}
@opindex max-passphrase-days
Ask the user to change the passphrase if @var{n} days have passed since
the last change. With @option{--enforce-passphrase-constraints} set the
user may not bypass this check.
@item --enable-passphrase-history
@opindex enable-passphrase-history
This option does nothing yet.
@item --pinentry-invisible-char @var{char}
@opindex pinentry-invisible-char
This option asks the Pinentry to use @var{char} for displaying hidden
characters. @var{char} must be one character UTF-8 string. A
Pinentry may or may not honor this request.
@item --pinentry-timeout @var{n}
@opindex pinentry-timeout
This option asks the Pinentry to timeout after @var{n} seconds with no
user input. The default value of 0 does not ask the pinentry to
timeout, however a Pinentry may use its own default timeout value in
this case. A Pinentry may or may not honor this request.
@item --pinentry-program @var{filename}
@opindex pinentry-program
Use program @var{filename} as the PIN entry. The default is
installation dependent. With the default configuration the name of
the default pinentry is @file{pinentry}; if that file does not exist
but a @file{pinentry-basic} exist the latter is used.
On a Windows platform the default is to use the first existing program
from this list:
@file{bin\pinentry.exe},
@file{..\Gpg4win\bin\pinentry.exe},
@file{..\Gpg4win\pinentry.exe},
@file{..\GNU\GnuPG\pinentry.exe},
@file{..\GNU\bin\pinentry.exe},
@file{bin\pinentry-basic.exe}
where the file names are relative to the GnuPG installation directory.
@item --pinentry-touch-file @var{filename}
@opindex pinentry-touch-file
By default the filename of the socket gpg-agent is listening for
requests is passed to Pinentry, so that it can touch that file before
exiting (it does this only in curses mode). This option changes the
file passed to Pinentry to @var{filename}. The special name
@code{/dev/null} may be used to completely disable this feature. Note
that Pinentry will not create that file, it will only change the
modification and access time.
@item --scdaemon-program @var{filename}
@opindex scdaemon-program
Use program @var{filename} as the Smartcard daemon. The default is
installation dependent and can be shown with the @command{gpgconf}
command.
@item --disable-scdaemon
@opindex disable-scdaemon
Do not make use of the scdaemon tool. This option has the effect of
disabling the ability to do smartcard operations. Note, that enabling
this option at runtime does not kill an already forked scdaemon.
@item --disable-check-own-socket
@opindex disable-check-own-socket
@command{gpg-agent} employs a periodic self-test to detect a stolen
socket. This usually means a second instance of @command{gpg-agent}
has taken over the socket and @command{gpg-agent} will then terminate
itself. This option may be used to disable this self-test for
debugging purposes.
@item --use-standard-socket
@itemx --no-use-standard-socket
@itemx --use-standard-socket-p
@opindex use-standard-socket
@opindex no-use-standard-socket
@opindex use-standard-socket-p
Since GnuPG 2.1 the standard socket is always used. These options
have no more effect. The command @code{gpg-agent
--use-standard-socket-p} will thus always return success.
@item --display @var{string}
@itemx --ttyname @var{string}
@itemx --ttytype @var{string}
@itemx --lc-ctype @var{string}
@itemx --lc-messages @var{string}
@itemx --xauthority @var{string}
@opindex display
@opindex ttyname
@opindex ttytype
@opindex lc-ctype
@opindex lc-messages
@opindex xauthority
These options are used with the server mode to pass localization
information.
@item --keep-tty
@itemx --keep-display
@opindex keep-tty
@opindex keep-display
Ignore requests to change the current @code{tty} or X window system's
@code{DISPLAY} variable respectively. This is useful to lock the
pinentry to pop up at the @code{tty} or display you started the agent.
+@item --listen-backlog @var{n}
+@opindex listen-backlog
+Set the size of the queue for pending connections. The default is 64.
@anchor{option --extra-socket}
@item --extra-socket @var{name}
@opindex extra-socket
The extra socket is created by default, you may use this option to
change the name of the socket. To disable the creation of the socket
use ``none'' or ``/dev/null'' for @var{name}.
Also listen on native gpg-agent connections on the given socket. The
intended use for this extra socket is to setup a Unix domain socket
forwarding from a remote machine to this socket on the local machine.
A @command{gpg} running on the remote machine may then connect to the
local gpg-agent and use its private keys. This enables decrypting or
signing data on a remote machine without exposing the private keys to the
remote machine.
@anchor{option --enable-extended-key-format}
@item --enable-extended-key-format
@opindex enable-extended-key-format
This option creates keys in the extended private key format. Changing
the passphrase of a key will also convert the key to that new format.
Using this option makes the private keys unreadable for gpg-agent
versions before 2.1.12. The advantage of the extended private key
format is that it is text based and can carry additional meta data.
Note that this option also changes the key protection format to use
OCB mode.
@anchor{option --enable-ssh-support}
@item --enable-ssh-support
@itemx --enable-putty-support
@opindex enable-ssh-support
@opindex enable-putty-support
The OpenSSH Agent protocol is always enabled, but @command{gpg-agent}
will only set the @code{SSH_AUTH_SOCK} variable if this flag is given.
In this mode of operation, the agent does not only implement the
gpg-agent protocol, but also the agent protocol used by OpenSSH
(through a separate socket). Consequently, it should be possible to use
the gpg-agent as a drop-in replacement for the well known ssh-agent.
SSH Keys, which are to be used through the agent, need to be added to
the gpg-agent initially through the ssh-add utility. When a key is
added, ssh-add will ask for the password of the provided key file and
send the unprotected key material to the agent; this causes the
gpg-agent to ask for a passphrase, which is to be used for encrypting
the newly received key and storing it in a gpg-agent specific
directory.
Once a key has been added to the gpg-agent this way, the gpg-agent
will be ready to use the key.
Note: in case the gpg-agent receives a signature request, the user might
need to be prompted for a passphrase, which is necessary for decrypting
the stored key. Since the ssh-agent protocol does not contain a
mechanism for telling the agent on which display/terminal it is running,
gpg-agent's ssh-support will use the TTY or X display where gpg-agent
has been started. To switch this display to the current one, the
following command may be used:
@smallexample
gpg-connect-agent updatestartuptty /bye
@end smallexample
Although all GnuPG components try to start the gpg-agent as needed, this
is not possible for the ssh support because ssh does not know about it.
Thus if no GnuPG tool which accesses the agent has been run, there is no
guarantee that ssh is able to use gpg-agent for authentication. To fix
this you may start gpg-agent if needed using this simple command:
@smallexample
gpg-connect-agent /bye
@end smallexample
Adding the @option{--verbose} shows the progress of starting the agent.
The @option{--enable-putty-support} is only available under Windows
and allows the use of gpg-agent with the ssh implementation
@command{putty}. This is similar to the regular ssh-agent support but
makes use of Windows message queue as required by @command{putty}.
@anchor{option --ssh-fingerprint-digest}
@item --ssh-fingerprint-digest
@opindex ssh-fingerprint-digest
Select the digest algorithm used to compute ssh fingerprints that are
communicated to the user, e.g. in pinentry dialogs. OpenSSH has
transitioned from using MD5 to the more secure SHA256.
@item --auto-expand-secmem @var{n}
@opindex auto-expand-secmem
Allow Libgcrypt to expand its secure memory area as required. The
optional value @var{n} is a non-negative integer with a suggested size
in bytes of each additionally allocated secure memory area. The value
is rounded up to the next 32 KiB; usual C style prefixes are allowed.
For an heavy loaded gpg-agent with many concurrent connection this
option avoids sign or decrypt errors due to out of secure memory error
returns.
@item --s2k-count @var{n}
@opindex s2k-count
Specify the iteration count used to protect the passphrase. This
option can be used to override the auto-calibration done by default.
The auto-calibration computes a count which requires 100ms to mangle
a given passphrase.
To view the actually used iteration count and the milliseconds
required for an S2K operation use:
@example
gpg-connect-agent 'GETINFO s2k_count' /bye
gpg-connect-agent 'GETINFO s2k_time' /bye
@end example
To view the auto-calibrated count use:
@example
gpg-connect-agent 'GETINFO s2k_count_cal' /bye
@end example
@end table
@mansect files
@node Agent Configuration
@section Configuration
There are a few configuration files needed for the operation of the
agent. By default they may all be found in the current home directory
(@pxref{option --homedir}).
@table @file
@item gpg-agent.conf
@efindex gpg-agent.conf
This is the standard configuration file read by @command{gpg-agent} on
startup. It may contain any valid long option; the leading
two dashes may not be entered and the option may not be abbreviated.
This file is also read after a @code{SIGHUP} however only a few
options will actually have an effect. This default name may be
changed on the command line (@pxref{option --options}).
You should backup this file.
@item trustlist.txt
@efindex trustlist.txt
This is the list of trusted keys. You should backup this file.
Comment lines, indicated by a leading hash mark, as well as empty
lines are ignored. To mark a key as trusted you need to enter its
fingerprint followed by a space and a capital letter @code{S}. Colons
may optionally be used to separate the bytes of a fingerprint; this
enables cutting and pasting the fingerprint from a key listing output. If
the line is prefixed with a @code{!} the key is explicitly marked as
not trusted.
Here is an example where two keys are marked as ultimately trusted
and one as not trusted:
@cartouche
@smallexample
# CN=Wurzel ZS 3,O=Intevation GmbH,C=DE
A6935DD34EF3087973C706FC311AA2CCF733765B S
# CN=PCA-1-Verwaltung-02/O=PKI-1-Verwaltung/C=DE
DC:BD:69:25:48:BD:BB:7E:31:6E:BB:80:D3:00:80:35:D4:F8:A6:CD S
# CN=Root-CA/O=Schlapphuete/L=Pullach/C=DE
!14:56:98:D3:FE:9C:CA:5A:31:6E:BC:81:D3:11:4E:00:90:A3:44:C2 S
@end smallexample
@end cartouche
Before entering a key into this file, you need to ensure its
authenticity. How to do this depends on your organisation; your
administrator might have already entered those keys which are deemed
trustworthy enough into this file. Places where to look for the
fingerprint of a root certificate are letters received from the CA or
the website of the CA (after making 100% sure that this is indeed the
website of that CA). You may want to consider disallowing interactive
updates of this file by using the @ref{option --no-allow-mark-trusted}.
It might even be advisable to change the permissions to read-only so
that this file can't be changed inadvertently.
As a special feature a line @code{include-default} will include a global
list of trusted certificates (e.g. @file{@value{SYSCONFDIR}/trustlist.txt}).
This global list is also used if the local list is not available.
It is possible to add further flags after the @code{S} for use by the
caller:
@table @code
@item relax
@cindex relax
Relax checking of some root certificate requirements. As of now this
flag allows the use of root certificates with a missing basicConstraints
attribute (despite that it is a MUST for CA certificates) and disables
CRL checking for the root certificate.
@item cm
If validation of a certificate finally issued by a CA with this flag set
fails, try again using the chain validation model.
@end table
@item sshcontrol
@efindex sshcontrol
This file is used when support for the secure shell agent protocol has
been enabled (@pxref{option --enable-ssh-support}). Only keys present in
this file are used in the SSH protocol. You should backup this file.
The @command{ssh-add} tool may be used to add new entries to this file;
you may also add them manually. Comment lines, indicated by a leading
hash mark, as well as empty lines are ignored. An entry starts with
optional whitespace, followed by the keygrip of the key given as 40 hex
digits, optionally followed by the caching TTL in seconds and another
optional field for arbitrary flags. A non-zero TTL overrides the global
default as set by @option{--default-cache-ttl-ssh}.
The only flag support is @code{confirm}. If this flag is found for a
key, each use of the key will pop up a pinentry to confirm the use of
that key. The flag is automatically set if a new key was loaded into
@code{gpg-agent} using the option @option{-c} of the @code{ssh-add}
command.
The keygrip may be prefixed with a @code{!} to disable an entry.
The following example lists exactly one key. Note that keys available
through a OpenPGP smartcard in the active smartcard reader are
implicitly added to this list; i.e. there is no need to list them.
@cartouche
@smallexample
# Key added on: 2011-07-20 20:38:46
# Fingerprint: 5e:8d:c4:ad:e7:af:6e:27:8a:d6:13:e4:79:ad:0b:81
34B62F25E277CF13D3C6BCEBFD3F85D08F0A864B 0 confirm
@end smallexample
@end cartouche
@item private-keys-v1.d/
@efindex private-keys-v1.d
This is the directory where gpg-agent stores the private keys. Each
key is stored in a file with the name made up of the keygrip and the
suffix @file{key}. You should backup all files in this directory
and take great care to keep this backup closed away.
@end table
Note that on larger installations, it is useful to put predefined
files into the directory @file{@value{SYSCONFSKELDIR}} so that newly created
users start up with a working configuration. For existing users the
a small helper script is provided to create these files (@pxref{addgnupghome}).
@c
@c Agent Signals
@c
@mansect signals
@node Agent Signals
@section Use of some signals
A running @command{gpg-agent} may be controlled by signals, i.e. using
the @command{kill} command to send a signal to the process.
Here is a list of supported signals:
@table @gnupgtabopt
@item SIGHUP
@cpindex SIGHUP
This signal flushes all cached passphrases and if the program has been
started with a configuration file, the configuration file is read
again. Only certain options are honored: @code{quiet},
@code{verbose}, @code{debug}, @code{debug-all}, @code{debug-level},
@code{debug-pinentry},
@code{no-grab},
@code{pinentry-program},
@code{pinentry-invisible-char},
@code{default-cache-ttl},
@code{max-cache-ttl}, @code{ignore-cache-for-signing},
@code{s2k-count},
@code{no-allow-external-cache}, @code{allow-emacs-pinentry},
@code{no-allow-mark-trusted}, @code{disable-scdaemon}, and
@code{disable-check-own-socket}. @code{scdaemon-program} is also
supported but due to the current implementation, which calls the
scdaemon only once, it is not of much use unless you manually kill the
scdaemon.
@item SIGTERM
@cpindex SIGTERM
Shuts down the process but waits until all current requests are
fulfilled. If the process has received 3 of these signals and requests
are still pending, a shutdown is forced.
@item SIGINT
@cpindex SIGINT
Shuts down the process immediately.
@item SIGUSR1
@cpindex SIGUSR1
Dump internal information to the log file.
@item SIGUSR2
@cpindex SIGUSR2
This signal is used for internal purposes.
@end table
@c
@c Examples
@c
@mansect examples
@node Agent Examples
@section Examples
It is important to set the environment variable @code{GPG_TTY} in
your login shell, for example in the @file{~/.bashrc} init script:
@cartouche
@example
export GPG_TTY=$(tty)
@end example
@end cartouche
If you enabled the Ssh Agent Support, you also need to tell ssh about
it by adding this to your init script:
@cartouche
@example
unset SSH_AGENT_PID
if [ "$@{gnupg_SSH_AUTH_SOCK_by:-0@}" -ne $$ ]; then
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi
@end example
@end cartouche
@c
@c Assuan Protocol
@c
@manpause
@node Agent Protocol
@section Agent's Assuan Protocol
Note: this section does only document the protocol, which is used by
GnuPG components; it does not deal with the ssh-agent protocol. To
see the full specification of each command, use
@example
gpg-connect-agent 'help COMMAND' /bye
@end example
@noindent
or just 'help' to list all available commands.
@noindent
The @command{gpg-agent} daemon is started on demand by the GnuPG
components.
To identify a key we use a thing called keygrip which is the SHA-1 hash
of an canonical encoded S-Expression of the public key as used in
Libgcrypt. For the purpose of this interface the keygrip is given as a
hex string. The advantage of using this and not the hash of a
certificate is that it will be possible to use the same keypair for
different protocols, thereby saving space on the token used to keep the
secret keys.
The @command{gpg-agent} may send status messages during a command or when
returning from a command to inform a client about the progress or result of an
operation. For example, the @var{INQUIRE_MAXLEN} status message may be sent
during a server inquire to inform the client of the maximum usable length of
the inquired data (which should not be exceeded).
@menu
* Agent PKDECRYPT:: Decrypting a session key
* Agent PKSIGN:: Signing a Hash
* Agent GENKEY:: Generating a Key
* Agent IMPORT:: Importing a Secret Key
* Agent EXPORT:: Exporting a Secret Key
* Agent ISTRUSTED:: Importing a Root Certificate
* Agent GET_PASSPHRASE:: Ask for a passphrase
* Agent CLEAR_PASSPHRASE:: Expire a cached passphrase
* Agent PRESET_PASSPHRASE:: Set a passphrase for a keygrip
* Agent GET_CONFIRMATION:: Ask for confirmation
* Agent HAVEKEY:: Check whether a key is available
* Agent LEARN:: Register a smartcard
* Agent PASSWD:: Change a Passphrase
* Agent UPDATESTARTUPTTY:: Change the Standard Display
* Agent GETEVENTCOUNTER:: Get the Event Counters
* Agent GETINFO:: Return information about the process
* Agent OPTION:: Set options for the session
@end menu
@node Agent PKDECRYPT
@subsection Decrypting a session key
The client asks the server to decrypt a session key. The encrypted
session key should have all information needed to select the
appropriate secret key or to delegate it to a smartcard.
@example
SETKEY
@end example
Tell the server about the key to be used for decryption. If this is
not used, @command{gpg-agent} may try to figure out the key by trying to
decrypt the message with each key available.
@example
PKDECRYPT
@end example
The agent checks whether this command is allowed and then does an
INQUIRY to get the ciphertext the client should then send the cipher
text.
@example
S: INQUIRE CIPHERTEXT
C: D (xxxxxx
C: D xxxx)
C: END
@end example
Please note that the server may send status info lines while reading the
data lines from the client. The data send is a SPKI like S-Exp with
this structure:
@example
(enc-val
(
( )
...
( )))
@end example
Where algo is a string with the name of the algorithm; see the libgcrypt
documentation for a list of valid algorithms. The number and names of
the parameters depend on the algorithm. The agent does return an error
if there is an inconsistency.
If the decryption was successful the decrypted data is returned by
means of "D" lines.
Here is an example session:
@cartouche
@smallexample
C: PKDECRYPT
S: INQUIRE CIPHERTEXT
C: D (enc-val elg (a 349324324)
C: D (b 3F444677CA)))
C: END
S: # session key follows
S: S PADDING 0
S: D (value 1234567890ABCDEF0)
S: OK decryption successful
@end smallexample
@end cartouche
The “PADDING” status line is only send if gpg-agent can tell what kind
of padding is used. As of now only the value 0 is used to indicate
that the padding has been removed.
@node Agent PKSIGN
@subsection Signing a Hash
The client asks the agent to sign a given hash value. A default key
will be chosen if no key has been set. To set a key a client first
uses:
@example
SIGKEY
@end example
This can be used multiple times to create multiple signature, the list
of keys is reset with the next PKSIGN command or a RESET. The server
tests whether the key is a valid key to sign something and responds with
okay.
@example
SETHASH --hash=|
@end example
The client can use this command to tell the server about the data
(which usually is a hash) to be signed. is the decimal encoded hash
algorithm number as used by Libgcrypt. Either or --hash=
must be given. Valid names for are:
@table @code
@item sha1
The SHA-1 hash algorithm
@item sha256
The SHA-256 hash algorithm
@item rmd160
The RIPE-MD160 hash algorithm
@item md5
The old and broken MD5 hash algorithm
@item tls-md5sha1
A combined hash algorithm as used by the TLS protocol.
@end table
@noindent
The actual signing is done using
@example
PKSIGN
@end example
Options are not yet defined, but may later be used to choose among
different algorithms. The agent does then some checks, asks for the
passphrase and as a result the server returns the signature as an SPKI
like S-expression in "D" lines:
@example
(sig-val
(
( )
...
( )))
@end example
The operation is affected by the option
@example
OPTION use-cache-for-signing=0|1
@end example
The default of @code{1} uses the cache. Setting this option to @code{0}
will lead @command{gpg-agent} to ignore the passphrase cache. Note, that there is
also a global command line option for @command{gpg-agent} to globally disable the
caching.
Here is an example session:
@cartouche
@smallexample
C: SIGKEY
S: OK key available
C: SIGKEY
S: OK key available
C: PKSIGN
S: # I did ask the user whether he really wants to sign
S: # I did ask the user for the passphrase
S: INQUIRE HASHVAL
C: D ABCDEF012345678901234
C: END
S: # signature follows
S: D (sig-val rsa (s 45435453654612121212))
S: OK
@end smallexample
@end cartouche
@node Agent GENKEY
@subsection Generating a Key
This is used to create a new keypair and store the secret key inside the
active PSE --- which is in most cases a Soft-PSE. A not-yet-defined
option allows choosing the storage location. To get the secret key out
of the PSE, a special export tool has to be used.
@example
GENKEY [--no-protection] [--preset] []
@end example
Invokes the key generation process and the server will then inquire
on the generation parameters, like:
@example
S: INQUIRE KEYPARM
C: D (genkey (rsa (nbits 1024)))
C: END
@end example
The format of the key parameters which depends on the algorithm is of
the form:
@example
(genkey
(algo
(parameter_name_1 ....)
....
(parameter_name_n ....)))
@end example
If everything succeeds, the server returns the *public key* in a SPKI
like S-Expression like this:
@example
(public-key
(rsa
(n )
(e )))
@end example
Here is an example session:
@cartouche
@smallexample
C: GENKEY
S: INQUIRE KEYPARM
C: D (genkey (rsa (nbits 1024)))
C: END
S: D (public-key
S: D (rsa (n 326487324683264) (e 10001)))
S OK key created
@end smallexample
@end cartouche
The @option{--no-protection} option may be used to prevent prompting for a
passphrase to protect the secret key while leaving the secret key unprotected.
The @option{--preset} option may be used to add the passphrase to the cache
using the default cache parameters.
The @option{--inq-passwd} option may be used to create the key with a
supplied passphrase. When used the agent does an inquiry with the
keyword @code{NEWPASSWD} to retrieve that passphrase. This option
takes precedence over @option{--no-protection}; however if the client
sends a empty (zero-length) passphrase, this is identical to
@option{--no-protection}.
@node Agent IMPORT
@subsection Importing a Secret Key
This operation is not yet supported by GpgAgent. Specialized tools
are to be used for this.
There is no actual need because we can expect that secret keys
created by a 3rd party are stored on a smartcard. If we have
generated the key ourselves, we do not need to import it.
@node Agent EXPORT
@subsection Export a Secret Key
Not implemented.
Should be done by an extra tool.
@node Agent ISTRUSTED
@subsection Importing a Root Certificate
Actually we do not import a Root Cert but provide a way to validate
any piece of data by storing its Hash along with a description and
an identifier in the PSE. Here is the interface description:
@example
ISTRUSTED
@end example
Check whether the OpenPGP primary key or the X.509 certificate with the
given fingerprint is an ultimately trusted key or a trusted Root CA
certificate. The fingerprint should be given as a hexstring (without
any blanks or colons or whatever in between) and may be left padded with
00 in case of an MD5 fingerprint. GPGAgent will answer with:
@example
OK
@end example
The key is in the table of trusted keys.
@example
ERR 304 (Not Trusted)
@end example
The key is not in this table.
Gpg needs the entire list of trusted keys to maintain the web of
trust; the following command is therefore quite helpful:
@example
LISTTRUSTED
@end example
GpgAgent returns a list of trusted keys line by line:
@example
S: D 000000001234454556565656677878AF2F1ECCFF P
S: D 340387563485634856435645634856438576457A P
S: D FEDC6532453745367FD83474357495743757435D S
S: OK
@end example
The first item on a line is the hexified fingerprint where MD5
fingerprints are @code{00} padded to the left and the second item is a
flag to indicate the type of key (so that gpg is able to only take care
of PGP keys). P = OpenPGP, S = S/MIME. A client should ignore the rest
of the line, so that we can extend the format in the future.
Finally a client should be able to mark a key as trusted:
@example
MARKTRUSTED @var{fingerprint} "P"|"S"
@end example
The server will then pop up a window to ask the user whether she
really trusts this key. For this it will probably ask for a text to
be displayed like this:
@example
S: INQUIRE TRUSTDESC
C: D Do you trust the key with the fingerprint @@FPR@@
C: D bla fasel blurb.
C: END
S: OK
@end example
Known sequences with the pattern @@foo@@ are replaced according to this
table:
@table @code
@item @@FPR16@@
Format the fingerprint according to gpg rules for a v3 keys.
@item @@FPR20@@
Format the fingerprint according to gpg rules for a v4 keys.
@item @@FPR@@
Choose an appropriate format to format the fingerprint.
@item @@@@
Replaced by a single @code{@@}.
@end table
@node Agent GET_PASSPHRASE
@subsection Ask for a passphrase
This function is usually used to ask for a passphrase to be used for
symmetric encryption, but may also be used by programs which need
special handling of passphrases. This command uses a syntax which helps
clients to use the agent with minimum effort.
@example
GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]] \
[--qualitybar] @var{cache_id} \
[@var{error_message} @var{prompt} @var{description}]
@end example
@var{cache_id} is expected to be a string used to identify a cached
passphrase. Use a @code{X} to bypass the cache. With no other
arguments the agent returns a cached passphrase or an error. By
convention either the hexified fingerprint of the key shall be used for
@var{cache_id} or an arbitrary string prefixed with the name of the
calling application and a colon: Like @code{gpg:somestring}.
@var{error_message} is either a single @code{X} for no error message or
a string to be shown as an error message like (e.g. "invalid
passphrase"). Blanks must be percent escaped or replaced by @code{+}'.
@var{prompt} is either a single @code{X} for a default prompt or the
text to be shown as the prompt. Blanks must be percent escaped or
replaced by @code{+}.
@var{description} is a text shown above the entry field. Blanks must be
percent escaped or replaced by @code{+}.
The agent either returns with an error or with a OK followed by the hex
encoded passphrase. Note that the length of the strings is implicitly
limited by the maximum length of a command. If the option
@option{--data} is used, the passphrase is not returned on the OK line
but by regular data lines; this is the preferred method.
If the option @option{--check} is used, the standard passphrase
constraints checks are applied. A check is not done if the passphrase
has been found in the cache.
If the option @option{--no-ask} is used and the passphrase is not in the
cache the user will not be asked to enter a passphrase but the error
code @code{GPG_ERR_NO_DATA} is returned.
If the option @option{--qualitybar} is used and a minimum passphrase
length has been configured, a visual indication of the entered
passphrase quality is shown.
@example
CLEAR_PASSPHRASE @var{cache_id}
@end example
may be used to invalidate the cache entry for a passphrase. The
function returns with OK even when there is no cached passphrase.
@node Agent CLEAR_PASSPHRASE
@subsection Remove a cached passphrase
Use this command to remove a cached passphrase.
@example
CLEAR_PASSPHRASE [--mode=normal]
@end example
The @option{--mode=normal} option can be used to clear a @var{cache_id} that
was set by gpg-agent.
@node Agent PRESET_PASSPHRASE
@subsection Set a passphrase for a keygrip
This command adds a passphrase to the cache for the specified @var{keygrip}.
@example
PRESET_PASSPHRASE [--inquire] []
@end example
The passphrase is a hexadecimal string when specified. When not specified, the
passphrase will be retrieved from the pinentry module unless the
@option{--inquire} option was specified in which case the passphrase will be
retrieved from the client.
The @var{timeout} parameter keeps the passphrase cached for the specified
number of seconds. A value of @code{-1} means infinite while @code{0} means
the default (currently only a timeout of -1 is allowed, which means to never
expire it).
@node Agent GET_CONFIRMATION
@subsection Ask for confirmation
This command may be used to ask for a simple confirmation by
presenting a text and 2 buttons: Okay and Cancel.
@example
GET_CONFIRMATION @var{description}
@end example
@var{description}is displayed along with a Okay and Cancel
button. Blanks must be percent escaped or replaced by @code{+}. A
@code{X} may be used to display confirmation dialog with a default
text.
The agent either returns with an error or with a OK. Note, that the
length of @var{description} is implicitly limited by the maximum
length of a command.
@node Agent HAVEKEY
@subsection Check whether a key is available
This can be used to see whether a secret key is available. It does
not return any information on whether the key is somehow protected.
@example
HAVEKEY @var{keygrips}
@end example
The agent answers either with OK or @code{No_Secret_Key} (208). The
caller may want to check for other error codes as well. More than one
keygrip may be given. In this case the command returns success if at
least one of the keygrips corresponds to an available secret key.
@node Agent LEARN
@subsection Register a smartcard
@example
LEARN [--send]
@end example
This command is used to register a smartcard. With the @option{--send}
option given the certificates are sent back.
@node Agent PASSWD
@subsection Change a Passphrase
@example
PASSWD [--cache-nonce=] [--passwd-nonce=] [--preset] @var{keygrip}
@end example
This command is used to interactively change the passphrase of the key
identified by the hex string @var{keygrip}. The @option{--preset}
option may be used to add the new passphrase to the cache using the
default cache parameters.
@node Agent UPDATESTARTUPTTY
@subsection Change the standard display
@example
UPDATESTARTUPTTY
@end example
Set the startup TTY and X-DISPLAY variables to the values of this
session. This command is useful to direct future pinentry invocations
to another screen. It is only required because there is no way in the
ssh-agent protocol to convey this information.
@node Agent GETEVENTCOUNTER
@subsection Get the Event Counters
@example
GETEVENTCOUNTER
@end example
This function return one status line with the current values of the
event counters. The event counters are useful to avoid polling by
delaying a poll until something has changed. The values are decimal
numbers in the range @code{0} to @code{UINT_MAX} and wrapping around to
0. The actual values should not be relied upon; they shall only be used
to detect a change.
The currently defined counters are:
@table @code
@item ANY
Incremented with any change of any of the other counters.
@item KEY
Incremented for added or removed private keys.
@item CARD
Incremented for changes of the card readers stati.
@end table
@node Agent GETINFO
@subsection Return information about the process
This is a multipurpose function to return a variety of information.
@example
GETINFO @var{what}
@end example
The value of @var{what} specifies the kind of information returned:
@table @code
@item version
Return the version of the program.
@item pid
Return the process id of the process.
@item socket_name
Return the name of the socket used to connect the agent.
@item ssh_socket_name
Return the name of the socket used for SSH connections. If SSH support
has not been enabled the error @code{GPG_ERR_NO_DATA} will be returned.
@end table
@node Agent OPTION
@subsection Set options for the session
Here is a list of session options which are not yet described with
other commands. The general syntax for an Assuan option is:
@smallexample
OPTION @var{key}=@var{value}
@end smallexample
@noindent
Supported @var{key}s are:
@table @code
@item agent-awareness
This may be used to tell gpg-agent of which gpg-agent version the
client is aware of. gpg-agent uses this information to enable
features which might break older clients.
@item putenv
Change the session's environment to be used for the
Pinentry. Valid values are:
@table @code
@item @var{name}
Delete envvar @var{name}
@item @var{name}=
Set envvar @var{name} to the empty string
@item @var{name}=@var{value}
Set envvar @var{name} to the string @var{value}.
@end table
@item use-cache-for-signing
See Assuan command @code{PKSIGN}.
@item allow-pinentry-notify
This does not need any value. It is used to enable the
PINENTRY_LAUNCHED inquiry.
@item pinentry-mode
This option is used to change the operation mode of the pinentry. The
following values are defined:
@table @code
@item ask
This is the default mode which pops up a pinentry as needed.
@item cancel
Instead of popping up a pinentry, return the error code
@code{GPG_ERR_CANCELED}.
@item error
Instead of popping up a pinentry, return the error code
@code{GPG_ERR_NO_PIN_ENTRY}.
@item loopback
Use a loopback pinentry. This fakes a pinentry by using inquiries
back to the caller to ask for a passphrase. This option may only be
set if the agent has been configured for that.
To disable this feature use @ref{option --no-allow-loopback-pinentry}.
@end table
@item cache-ttl-opt-preset
This option sets the cache TTL for new entries created by GENKEY and
PASSWD commands when using the @option{--preset} option. It is not
used a default value is used.
@item s2k-count
Instead of using the standard S2K count (which is computed on the
fly), the given S2K count is used for new keys or when changing the
passphrase of a key. Values below 65536 are considered to be 0. This
option is valid for the entire session or until reset to 0. This
option is useful if the key is later used on boxes which are either
much slower or faster than the actual box.
@end table
@mansect see also
@ifset isman
@command{@gpgname}(1),
@command{gpgsm}(1),
@command{gpgconf}(1),
@command{gpg-connect-agent}(1),
@command{scdaemon}(1)
@end ifset
@include see-also-note.texi
diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi
index 4c6bb93b6..a9e6d1e7a 100644
--- a/doc/scdaemon.texi
+++ b/doc/scdaemon.texi
@@ -1,764 +1,770 @@
@c Copyright (C) 2002 Free Software Foundation, Inc.
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@include defs.inc
@node Invoking SCDAEMON
@chapter Invoking the SCDAEMON
@cindex SCDAEMON command options
@cindex command options
@cindex options, SCDAEMON command
@manpage scdaemon.1
@ifset manverb
.B scdaemon
\- Smartcard daemon for the GnuPG system
@end ifset
@mansect synopsis
@ifset manverb
.B scdaemon
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-server
.br
.B scdaemon
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-daemon
.RI [ command_line ]
@end ifset
@mansect description
The @command{scdaemon} is a daemon to manage smartcards. It is usually
invoked by @command{gpg-agent} and in general not used directly.
@manpause
@xref{Option Index}, for an index to @command{scdaemon}'s commands and
options.
@mancont
@menu
* Scdaemon Commands:: List of all commands.
* Scdaemon Options:: List of all options.
* Card applications:: Description of card applications.
* Scdaemon Configuration:: Configuration files.
* Scdaemon Examples:: Some usage examples.
* Scdaemon Protocol:: The protocol the daemon uses.
@end menu
@mansect commands
@node Scdaemon Commands
@section Commands
Commands are not distinguished from options except for the fact that
only one command is allowed.
@table @gnupgtabopt
@item --version
@opindex version
Print the program version and licensing information. Note that you cannot
abbreviate this command.
@item --help, -h
@opindex help
Print a usage message summarizing the most useful command-line options.
Note that you cannot abbreviate this command.
@item --dump-options
@opindex dump-options
Print a list of all available options and commands. Note that you cannot
abbreviate this command.
@item --server
@opindex server
Run in server mode and wait for commands on the @code{stdin}. The
default mode is to create a socket and listen for commands there.
@item --multi-server
@opindex multi-server
Run in server mode and wait for commands on the @code{stdin} as well as
on an additional Unix Domain socket. The server command @code{GETINFO}
may be used to get the name of that extra socket.
@item --daemon
@opindex daemon
Run the program in the background. This option is required to prevent
it from being accidentally running in the background.
@end table
@mansect options
@node Scdaemon Options
@section Option Summary
@table @gnupgtabopt
@item --options @var{file}
@opindex options
Reads configuration from @var{file} instead of from the default
per-user configuration file. The default configuration file is named
@file{scdaemon.conf} and expected in the @file{.gnupg} directory directly
below the home directory of the user.
@include opt-homedir.texi
@item -v
@item --verbose
@opindex v
@opindex verbose
Outputs additional information while running.
You can increase the verbosity by giving several
verbose commands to @command{gpgsm}, such as @samp{-vv}.
@item --debug-level @var{level}
@opindex debug-level
Select the debug level for investigating problems. @var{level} may be
a numeric value or a keyword:
@table @code
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
More verbose debug messages. A value between 3 and 5 may be used
instead of the keyword.
@item expert
Even more detailed messages. A value between 6 and 8 may be used
instead of the keyword.
@item guru
All of the debug messages you can get. A value greater than 8 may be
used instead of the keyword. The creation of hash tracing files is
only enabled if the keyword is used.
@end table
How these messages are mapped to the actual debugging flags is not
specified and may change with newer releases of this program. They are
however carefully selected to best aid in debugging.
@quotation Note
All debugging options are subject to change and thus should not be used
by any application program. As the name says, they are only used as
helpers to debug problems.
@end quotation
@item --debug @var{flags}
@opindex debug
This option is only useful for debugging and the behavior may change at
any time without notice. FLAGS are bit encoded and may be given in
usual C-Syntax. The currently defined bits are:
@table @code
@item 0 (1)
command I/O
@item 1 (2)
values of big number integers
@item 2 (4)
low level crypto operations
@item 5 (32)
memory allocation
@item 6 (64)
caching
@item 7 (128)
show memory statistics
@item 9 (512)
write hashed data to files named @code{dbgmd-000*}
@item 10 (1024)
trace Assuan protocol.
See also option @option{--debug-assuan-log-cats}.
@item 11 (2048)
trace APDU I/O to the card. This may reveal sensitive data.
@item 12 (4096)
trace some card reader related function calls.
@end table
@item --debug-all
@opindex debug-all
Same as @code{--debug=0xffffffff}
@item --debug-wait @var{n}
@opindex debug-wait
When running in server mode, wait @var{n} seconds before entering the
actual processing loop and print the pid. This gives time to attach a
debugger.
@item --debug-ccid-driver
@opindex debug-wait
Enable debug output from the included CCID driver for smartcards.
Using this option twice will also enable some tracing of the T=1
protocol. Note that this option may reveal sensitive data.
@item --debug-disable-ticker
@opindex debug-disable-ticker
This option disables all ticker functions like checking for card
insertions.
@item --debug-allow-core-dump
@opindex debug-allow-core-dump
For security reasons we won't create a core dump when the process
aborts. For debugging purposes it is sometimes better to allow core
dump. This option enables it and also changes the working directory to
@file{/tmp} when running in @option{--server} mode.
@item --debug-log-tid
@opindex debug-log-tid
This option appends a thread ID to the PID in the log output.
@item --debug-assuan-log-cats @var{cats}
@opindex debug-assuan-log-cats
@efindex ASSUAN_DEBUG
Changes the active Libassuan logging categories to @var{cats}. The
value for @var{cats} is an unsigned integer given in usual C-Syntax.
A value of 0 switches to a default category. If this option is not
used the categories are taken from the environment variable
@code{ASSUAN_DEBUG}. Note that this option has only an effect if the
Assuan debug flag has also been with the option @option{--debug}. For
a list of categories see the Libassuan manual.
@item --no-detach
@opindex no-detach
Don't detach the process from the console. This is mainly useful for
debugging.
+@item --listen-backlog @var{n}
+@opindex listen-backlog
+Set the size of the queue for pending connections. The default is 64.
+This option has an effect only if @option{--multi-server} is also
+used.
+
@item --log-file @var{file}
@opindex log-file
Append all logging output to @var{file}. This is very helpful in
seeing what the agent actually does. Use @file{socket://} to log to
socket.
@item --pcsc-driver @var{library}
@opindex pcsc-driver
Use @var{library} to access the smartcard reader. The current default
is @file{libpcsclite.so}. Instead of using this option you might also
want to install a symbolic link to the default file name
(e.g. from @file{libpcsclite.so.1}).
@item --ctapi-driver @var{library}
@opindex ctapi-driver
Use @var{library} to access the smartcard reader. The current default
is @file{libtowitoko.so}. Note that the use of this interface is
deprecated; it may be removed in future releases.
@item --disable-ccid
@opindex disable-ccid
Disable the integrated support for CCID compliant readers. This
allows falling back to one of the other drivers even if the internal
CCID driver can handle the reader. Note, that CCID support is only
available if libusb was available at build time.
@item --reader-port @var{number_or_string}
@opindex reader-port
This option may be used to specify the port of the card terminal. A
value of 0 refers to the first serial device; add 32768 to access USB
devices. The default is 32768 (first USB device). PC/SC or CCID
readers might need a string here; run the program in verbose mode to get
a list of available readers. The default is then the first reader
found.
To get a list of available CCID readers you may use this command:
@cartouche
@smallexample
echo scd getinfo reader_list \
| gpg-connect-agent --decode | awk '/^D/ @{print $2@}'
@end smallexample
@end cartouche
@item --card-timeout @var{n}
@opindex card-timeout
If @var{n} is not 0 and no client is actively using the card, the card
will be powered down after @var{n} seconds. Powering down the card
avoids a potential risk of damaging a card when used with certain
cheap readers. This also allows applications that are not aware of
Scdaemon to access the card. The disadvantage of using a card timeout
is that accessing the card takes longer and that the user needs to
enter the PIN again after the next power up.
Note that with the current version of Scdaemon the card is powered
down immediately at the next timer tick for any value of @var{n} other
than 0.
@item --enable-pinpad-varlen
@opindex enable-pinpad-varlen
Please specify this option when the card reader supports variable
length input for pinpad (default is no). For known readers (listed in
ccid-driver.c and apdu.c), this option is not needed. Note that if
your card reader doesn't supports variable length input but you want
to use it, you need to specify your pinpad request on your card.
@item --disable-pinpad
@opindex disable-pinpad
Even if a card reader features a pinpad, do not try to use it.
@item --deny-admin
@opindex deny-admin
@opindex allow-admin
This option disables the use of admin class commands for card
applications where this is supported. Currently we support it for the
OpenPGP card. This option is useful to inhibit accidental access to
admin class command which could ultimately lock the card through wrong
PIN numbers. Note that GnuPG versions older than 2.0.11 featured an
@option{--allow-admin} option which was required to use such admin
commands. This option has no more effect today because the default is
now to allow admin commands.
@item --disable-application @var{name}
@opindex disable-application
This option disables the use of the card application named
@var{name}. This is mainly useful for debugging or if a application
with lower priority should be used by default.
@end table
All the long options may also be given in the configuration file after
stripping off the two leading dashes.
@mansect card applications
@node Card applications
@section Description of card applications
@command{scdaemon} supports the card applications as described below.
@menu
* OpenPGP Card:: The OpenPGP card application
* NKS Card:: The Telesec NetKey card application
* DINSIG Card:: The DINSIG card application
* PKCS#15 Card:: The PKCS#15 card application
* Geldkarte Card:: The Geldkarte application
* SmartCard-HSM:: The SmartCard-HSM application
* Undefined Card:: The Undefined stub application
@end menu
@node OpenPGP Card
@subsection The OpenPGP card application ``openpgp''
This application is currently only used by @command{gpg} but may in
future also be useful with @command{gpgsm}. Version 1 and version 2 of
the card is supported.
@noindent
The specifications for these cards are available at@*
@uref{http://g10code.com/docs/openpgp-card-1.0.pdf} and@*
@uref{http://g10code.com/docs/openpgp-card-2.0.pdf}.
@node NKS Card
@subsection The Telesec NetKey card ``nks''
This is the main application of the Telesec cards as available in
Germany. It is a superset of the German DINSIG card. The card is
used by @command{gpgsm}.
@node DINSIG Card
@subsection The DINSIG card application ``dinsig''
This is an application as described in the German draft standard
@emph{DIN V 66291-1}. It is intended to be used by cards supporting
the German signature law and its bylaws (SigG and SigV).
@node PKCS#15 Card
@subsection The PKCS#15 card application ``p15''
This is common framework for smart card applications. It is used by
@command{gpgsm}.
@node Geldkarte Card
@subsection The Geldkarte card application ``geldkarte''
This is a simple application to display information of a German
Geldkarte. The Geldkarte is a small amount debit card application which
comes with almost all German banking cards.
@node SmartCard-HSM
@subsection The SmartCard-HSM card application ``sc-hsm''
This application adds read-only support for keys and certificates
stored on a @uref{http://www.smartcard-hsm.com, SmartCard-HSM}.
To generate keys and store certifiates you may use
@uref{https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM, OpenSC} or
the tools from @uref{http://www.openscdp.org, OpenSCDP}.
The SmartCard-HSM cards requires a card reader that supports Extended
Length APDUs.
@node Undefined Card
@subsection The Undefined card application ``undefined''
This is a stub application to allow the use of the APDU command even
if no supported application is found on the card. This application is
not used automatically but must be explicitly requested using the
SERIALNO command.
@c *******************************************
@c *************** ****************
@c *************** FILES ****************
@c *************** ****************
@c *******************************************
@mansect files
@node Scdaemon Configuration
@section Configuration files
There are a few configuration files to control certain aspects of
@command{scdaemons}'s operation. Unless noted, they are expected in the
current home directory (@pxref{option --homedir}).
@table @file
@item scdaemon.conf
@cindex scdaemon.conf
This is the standard configuration file read by @command{scdaemon} on
startup. It may contain any valid long option; the leading two dashes
may not be entered and the option may not be abbreviated. This default
name may be changed on the command line (@pxref{option --options}).
@item scd-event
@cindex scd-event
If this file is present and executable, it will be called on every card
reader's status change. An example of this script is provided with the
distribution
@item reader_@var{n}.status
This file is created by @command{scdaemon} to let other applications now
about reader status changes. Its use is now deprecated in favor of
@file{scd-event}.
@end table
@c
@c Examples
@c
@mansect examples
@node Scdaemon Examples
@section Examples
@c man begin EXAMPLES
@example
$ scdaemon --server -v
@end example
@c man end
@c
@c Assuan Protocol
@c
@manpause
@node Scdaemon Protocol
@section Scdaemon's Assuan Protocol
The SC-Daemon should be started by the system to provide access to
external tokens. Using Smartcards on a multi-user system does not
make much sense except for system services, but in this case no
regular user accounts are hosted on the machine.
A client connects to the SC-Daemon by connecting to the socket named
@file{@value{LOCALRUNDIR}/scdaemon/socket}, configuration information
is read from @var{@value{SYSCONFDIR}/scdaemon.conf}
Each connection acts as one session, SC-Daemon takes care of
synchronizing access to a token between sessions.
@menu
* Scdaemon SERIALNO:: Return the serial number.
* Scdaemon LEARN:: Read all useful information from the card.
* Scdaemon READCERT:: Return a certificate.
* Scdaemon READKEY:: Return a public key.
* Scdaemon PKSIGN:: Signing data with a Smartcard.
* Scdaemon PKDECRYPT:: Decrypting data with a Smartcard.
* Scdaemon GETATTR:: Read an attribute's value.
* Scdaemon SETATTR:: Update an attribute's value.
* Scdaemon WRITEKEY:: Write a key to a card.
* Scdaemon GENKEY:: Generate a new key on-card.
* Scdaemon RANDOM:: Return random bytes generated on-card.
* Scdaemon PASSWD:: Change PINs.
* Scdaemon CHECKPIN:: Perform a VERIFY operation.
* Scdaemon RESTART:: Restart connection
* Scdaemon APDU:: Send a verbatim APDU to the card
@end menu
@node Scdaemon SERIALNO
@subsection Return the serial number
This command should be used to check for the presence of a card. It is
special in that it can be used to reset the card. Most other commands
will return an error when a card change has been detected and the use of
this function is therefore required.
Background: We want to keep the client clear of handling card changes
between operations; i.e. the client can assume that all operations are
done on the same card unless he call this function.
@example
SERIALNO
@end example
Return the serial number of the card using a status response like:
@example
S SERIALNO D27600000000000000000000
@end example
The serial number is the hex encoded value identified by
the @code{0x5A} tag in the GDO file (FIX=0x2F02).
@node Scdaemon LEARN
@subsection Read all useful information from the card
@example
LEARN [--force]
@end example
Learn all useful information of the currently inserted card. When
used without the @option{--force} option, the command might do an INQUIRE
like this:
@example
INQUIRE KNOWNCARDP
@end example
The client should just send an @code{END} if the processing should go on
or a @code{CANCEL} to force the function to terminate with a cancel
error message. The response of this command is a list of status lines
formatted as this:
@example
S KEYPAIRINFO @var{hexstring_with_keygrip} @var{hexstring_with_id}
@end example
If there is no certificate yet stored on the card a single "X" is
returned in @var{hexstring_with_keygrip}.
@node Scdaemon READCERT
@subsection Return a certificate
@example
READCERT @var{hexified_certid}|@var{keyid}
@end example
This function is used to read a certificate identified by
@var{hexified_certid} from the card. With OpenPGP cards the keyid
@code{OpenPGP.3} may be used to read the certificate of version 2 cards.
@node Scdaemon READKEY
@subsection Return a public key
@example
READKEY @var{hexified_certid}
@end example
Return the public key for the given cert or key ID as an standard
S-Expression.
@node Scdaemon PKSIGN
@subsection Signing data with a Smartcard
To sign some data the caller should use the command
@example
SETDATA @var{hexstring}
@end example
to tell @command{scdaemon} about the data to be signed. The data must be given in
hex notation. The actual signing is done using the command
@example
PKSIGN @var{keyid}
@end example
where @var{keyid} is the hexified ID of the key to be used. The key id
may have been retrieved using the command @code{LEARN}. If another
hash algorithm than SHA-1 is used, that algorithm may be given like:
@example
PKSIGN --hash=@var{algoname} @var{keyid}
@end example
With @var{algoname} are one of @code{sha1}, @code{rmd160} or @code{md5}.
@node Scdaemon PKDECRYPT
@subsection Decrypting data with a Smartcard
To decrypt some data the caller should use the command
@example
SETDATA @var{hexstring}
@end example
to tell @command{scdaemon} about the data to be decrypted. The data
must be given in hex notation. The actual decryption is then done
using the command
@example
PKDECRYPT @var{keyid}
@end example
where @var{keyid} is the hexified ID of the key to be used.
If the card is aware of the apdding format a status line with padding
information is send before the plaintext data. The key for this
status line is @code{PADDING} with the only defined value being 0 and
meaning padding has been removed.
@node Scdaemon GETATTR
@subsection Read an attribute's value
TO BE WRITTEN.
@node Scdaemon SETATTR
@subsection Update an attribute's value
TO BE WRITTEN.
@node Scdaemon WRITEKEY
@subsection Write a key to a card
@example
WRITEKEY [--force] @var{keyid}
@end example
This command is used to store a secret key on a smartcard. The
allowed keyids depend on the currently selected smartcard
application. The actual keydata is requested using the inquiry
@code{KEYDATA} and need to be provided without any protection. With
@option{--force} set an existing key under this @var{keyid} will get
overwritten. The key data is expected to be the usual canonical encoded
S-expression.
A PIN will be requested in most cases. This however depends on the
actual card application.
@node Scdaemon GENKEY
@subsection Generate a new key on-card
TO BE WRITTEN.
@node Scdaemon RANDOM
@subsection Return random bytes generated on-card
TO BE WRITTEN.
@node Scdaemon PASSWD
@subsection Change PINs
@example
PASSWD [--reset] [--nullpin] @var{chvno}
@end example
Change the PIN or reset the retry counter of the card holder
verification vector number @var{chvno}. The option @option{--nullpin}
is used to initialize the PIN of TCOS cards (6 byte NullPIN only).
@node Scdaemon CHECKPIN
@subsection Perform a VERIFY operation
@example
CHECKPIN @var{idstr}
@end example
Perform a VERIFY operation without doing anything else. This may be
used to initialize a the PIN cache earlier to long lasting
operations. Its use is highly application dependent:
@table @strong
@item OpenPGP
Perform a simple verify operation for CHV1 and CHV2, so that further
operations won't ask for CHV2 and it is possible to do a cheap check on
the PIN: If there is something wrong with the PIN entry system, only the
regular CHV will get blocked and not the dangerous CHV3. @var{idstr} is
the usual card's serial number in hex notation; an optional fingerprint
part will get ignored.
There is however a special mode if @var{idstr} is suffixed with the
literal string @code{[CHV3]}: In this case the Admin PIN is checked if
and only if the retry counter is still at 3.
@end table
@node Scdaemon RESTART
@subsection Perform a RESTART operation
@example
RESTART
@end example
Restart the current connection; this is a kind of warm reset. It
deletes the context used by this connection but does not actually
reset the card.
This is used by gpg-agent to reuse a primary pipe connection and
may be used by clients to backup from a conflict in the serial
command; i.e. to select another application.
@node Scdaemon APDU
@subsection Send a verbatim APDU to the card
@example
APDU [--atr] [--more] [--exlen[=@var{n}]] [@var{hexstring}]
@end example
Send an APDU to the current reader. This command bypasses the high
level functions and sends the data directly to the card.
@var{hexstring} is expected to be a proper APDU. If @var{hexstring} is
not given no commands are send to the card; However the command will
implicitly check whether the card is ready for use.
Using the option @code{--atr} returns the ATR of the card as a status
message before any data like this:
@example
S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1
@end example
Using the option @code{--more} handles the card status word MORE_DATA
(61xx) and concatenate all responses to one block.
Using the option @code{--exlen} the returned APDU may use extended
length up to N bytes. If N is not given a default value is used
(currently 4096).
@mansect see also
@ifset isman
@command{gpg-agent}(1),
@command{gpgsm}(1),
@command{gpg2}(1)
@end ifset
@include see-also-note.texi
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 0bedb8de2..3ad265781 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -1,1397 +1,1407 @@
/* scdaemon.c - The GnuPG Smartcard Daemon
* Copyright (C) 2001-2002, 2004-2005, 2007-2009 Free Software Foundation, Inc.
* Copyright (C) 2001-2002, 2004-2005, 2007-2014 Werner Koch
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef HAVE_W32_SYSTEM
#include
#include
#endif /*HAVE_W32_SYSTEM*/
#include
#include
#include
#define GNUPG_COMMON_NEED_AFLOCAL
#include "scdaemon.h"
#include
#include
#include /* malloc hooks */
#include "../common/i18n.h"
#include "../common/sysutils.h"
#include "app-common.h"
#include "iso7816.h"
#include "apdu.h"
#include "ccid-driver.h"
#include "../common/gc-opt-flags.h"
#include "../common/asshelp.h"
#include "../common/exechelp.h"
#include "../common/init.h"
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
enum cmd_and_opt_values
{ aNull = 0,
oCsh = 'c',
oQuiet = 'q',
oSh = 's',
oVerbose = 'v',
oNoVerbose = 500,
aGPGConfList,
aGPGConfTest,
oOptions,
oDebug,
oDebugAll,
oDebugLevel,
oDebugWait,
oDebugAllowCoreDump,
oDebugCCIDDriver,
oDebugLogTid,
oDebugAssuanLogCats,
oNoGreeting,
oNoOptions,
oHomedir,
oNoDetach,
oNoGrab,
oLogFile,
oServer,
oMultiServer,
oDaemon,
oBatch,
oReaderPort,
oCardTimeout,
octapiDriver,
opcscDriver,
oDisableCCID,
oDisableOpenSC,
oDisablePinpad,
oAllowAdmin,
oDenyAdmin,
oDisableApplication,
oEnablePinpadVarlen,
+ oListenBacklog
};
static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
ARGPARSE_group (301, N_("@Options:\n ")),
ARGPARSE_s_n (oServer,"server", N_("run in server mode (foreground)")),
ARGPARSE_s_n (oMultiServer, "multi-server",
N_("run in multi server mode (foreground)")),
ARGPARSE_s_n (oDaemon, "daemon", N_("run in daemon mode (background)")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
ARGPARSE_s_n (oSh, "sh", N_("sh-style command output")),
ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level" ,
N_("|LEVEL|set the debugging level to LEVEL")),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
ARGPARSE_s_s (oReaderPort, "reader-port",
N_("|N|connect to reader at port N")),
ARGPARSE_s_s (octapiDriver, "ctapi-driver",
N_("|NAME|use NAME as ct-API driver")),
ARGPARSE_s_s (opcscDriver, "pcsc-driver",
N_("|NAME|use NAME as PC/SC driver")),
ARGPARSE_s_n (oDisableCCID, "disable-ccid",
#ifdef HAVE_LIBUSB
N_("do not use the internal CCID driver")
#else
"@"
#endif
/* end --disable-ccid */),
ARGPARSE_s_u (oCardTimeout, "card-timeout",
N_("|N|disconnect the card after N seconds of inactivity")),
ARGPARSE_s_n (oDisablePinpad, "disable-pinpad",
N_("do not use a reader's pinpad")),
ARGPARSE_ignore (300, "disable-keypad"),
ARGPARSE_s_n (oAllowAdmin, "allow-admin", "@"),
ARGPARSE_s_n (oDenyAdmin, "deny-admin",
N_("deny the use of admin card commands")),
ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
N_("use variable length input for pinpad")),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
+ ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_end ()
};
/* The list of supported debug flags. */
static struct debug_flags_s debug_flags [] =
{
{ DBG_MPI_VALUE , "mpi" },
{ DBG_CRYPTO_VALUE , "crypto" },
{ DBG_MEMORY_VALUE , "memory" },
{ DBG_CACHE_VALUE , "cache" },
{ DBG_MEMSTAT_VALUE, "memstat" },
{ DBG_HASHING_VALUE, "hashing" },
{ DBG_IPC_VALUE , "ipc" },
{ DBG_CARD_IO_VALUE, "cardio" },
{ DBG_READER_VALUE , "reader" },
{ 0, NULL }
};
/* The card driver we use by default for PC/SC. */
#if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__)
#define DEFAULT_PCSC_DRIVER "winscard.dll"
#elif defined(__APPLE__)
#define DEFAULT_PCSC_DRIVER "/System/Library/Frameworks/PCSC.framework/PCSC"
#elif defined(__GLIBC__)
#define DEFAULT_PCSC_DRIVER "libpcsclite.so.1"
#else
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
#endif
/* The timer tick used to check card removal.
We poll every 500ms to let the user immediately know a status
change.
For a card reader with an interrupt endpoint, this timer is not
used with the internal CCID driver.
This is not too good for power saving but given that there is no
easy way to block on card status changes it is the best we can do.
For PC/SC we could in theory use an extra thread to wait for status
changes but that requires a native thread because there is no way
to make the underlying PC/SC card change function block using a Npth
mechanism. Given that a native thread could only be used under W32
we don't do that at all. */
#define TIMERTICK_INTERVAL_SEC (0)
#define TIMERTICK_INTERVAL_USEC (500000)
/* Flag to indicate that a shutdown was requested. */
static int shutdown_pending;
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
/* Flag telling whether we are running as a pipe server. */
static int pipe_server;
/* Name of the communication socket */
static char *socket_name;
/* Name of the redirected socket or NULL. */
static char *redir_socket_name;
/* We need to keep track of the server's nonces (these are dummies for
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
+/* Value for the listen() backlog argument. Change at runtime with
+ * --listen-backlog. */
+static int listen_backlog = 64;
+
#ifdef HAVE_W32_SYSTEM
static HANDLE the_event;
#else
/* PID to notify update of usb devices. */
static pid_t main_thread_pid;
#endif
static char *create_socket_name (char *standard_name);
static gnupg_fd_t create_server_socket (const char *name,
char **r_redir_name,
assuan_sock_nonce_t *nonce);
static void *start_connection_thread (void *arg);
static void handle_connections (int listen_fd);
/* Pth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static int active_connections;
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
const char *s;
char *result;
if (maybe_setuid)
{
gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */
maybe_setuid = 0;
}
s = getfnc (NULL);
result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
strcpy (stpcpy (stpcpy (result, libname), " "), s);
return result;
}
static const char *
my_strusage (int level)
{
static char *ver_gcry, *ver_ksba;
const char *p;
switch (level)
{
case 11: p = "@SCDAEMON@ (@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 20:
if (!ver_gcry)
ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
p = ver_gcry;
break;
case 21:
if (!ver_ksba)
ver_ksba = make_libversion ("libksba", ksba_check_version);
p = ver_ksba;
break;
case 1:
case 40: p = _("Usage: @SCDAEMON@ [options] (-h for help)");
break;
case 41: p = _("Syntax: scdaemon [options] [command [args]]\n"
"Smartcard daemon for @GNUPG@\n");
break;
default: p = NULL;
}
return p;
}
static int
tid_log_callback (unsigned long *rvalue)
{
int len = sizeof (*rvalue);
npth_t thread;
thread = npth_self ();
if (sizeof (thread) < len)
len = sizeof (thread);
memcpy (rvalue, &thread, len);
return 2; /* Use use hex representation. */
}
/* Setup the debugging. With a LEVEL of NULL only the active debug
flags are propagated to the subsystems. With LEVEL set, a specific
set of debug flags is set; thus overriding all flags already
set. */
static void
set_debug (const char *level)
{
int numok = (level && digitp (level));
int numlvl = numok? atoi (level) : 0;
if (!level)
;
else if (!strcmp (level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (level, "basic") || (numok && numlvl <= 2))
opt.debug = DBG_IPC_VALUE;
else if (!strcmp (level, "advanced") || (numok && numlvl <= 5))
opt.debug = DBG_IPC_VALUE;
else if (!strcmp (level, "expert") || (numok && numlvl <= 8))
opt.debug = (DBG_IPC_VALUE|DBG_CACHE_VALUE|DBG_CARD_IO_VALUE);
else if (!strcmp (level, "guru") || numok)
{
opt.debug = ~0;
/* Unless the "guru" string has been used we don't want to allow
hashing debugging. The rationale is that people tend to
select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */
if (numok)
opt.debug &= ~(DBG_HASHING_VALUE);
}
else
{
log_error (_("invalid debug-level '%s' given\n"), level);
scd_exit(2);
}
if (opt.debug && !opt.verbose)
opt.verbose = 1;
if (opt.debug && opt.quiet)
opt.quiet = 0;
if (opt.debug & DBG_MPI_VALUE)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
parse_debug_flag (NULL, &opt.debug, debug_flags);
}
static void
cleanup (void)
{
if (socket_name && *socket_name)
{
char *name;
name = redir_socket_name? redir_socket_name : socket_name;
gnupg_remove (name);
*socket_name = 0;
}
}
int
main (int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int orig_argc;
char **orig_argv;
FILE *configfp = NULL;
char *configname = NULL;
const char *shell;
unsigned int configlineno;
int parse_debug = 0;
const char *debug_level = NULL;
int default_config =1;
int greeting = 0;
int nogreeting = 0;
int multi_server = 0;
int is_daemon = 0;
int nodetach = 0;
int csh_style = 0;
char *logfile = NULL;
int debug_wait = 0;
int gpgconf_list = 0;
const char *config_filename = NULL;
int allow_coredump = 0;
struct assuan_malloc_hooks malloc_hooks;
int res;
npth_t pipecon_handler;
early_system_init ();
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
/* Please note that we may running SUID(ROOT), so be very CAREFUL
when adding any stuff between here and the call to INIT_SECMEM()
somewhere after the option parsing */
log_set_prefix ("scdaemon", GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID);
/* Make sure that our subsystems are ready. */
i18n_init ();
init_common_subsystems (&argc, &argv);
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
assuan_sock_init ();
setup_libassuan_logging (&opt.debug, NULL);
setup_libgcrypt_logging ();
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
disable_core_dumps ();
/* Set default options. */
opt.allow_admin = 1;
opt.pcsc_driver = DEFAULT_PCSC_DRIVER;
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1;
/* Check whether we have a config file on the commandline */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
while (arg_parse( &pargs, opts))
{
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
parse_debug++;
else if (pargs.r_opt == oOptions)
{ /* yes there is one, so we do not try the default one, but
read the option file when it is encountered at the
commandline */
default_config = 0;
}
else if (pargs.r_opt == oNoOptions)
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
gnupg_set_homedir (pargs.r.ret_str);
}
/* initialize the secure memory. */
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
maybe_setuid = 0;
/*
Now we are working under our real uid
*/
if (default_config)
configname = make_filename (gnupg_homedir (), SCDAEMON_NAME EXTSEP_S "conf",
NULL );
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
next_pass:
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if( parse_debug )
log_info (_("Note: no default option file '%s'\n"),
configname );
}
else
{
log_error (_("option file '%s': %s\n"),
configname, strerror(errno) );
exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname )
log_info (_("reading options from '%s'\n"), configname );
default_config = 0;
}
while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
{
switch (pargs.r_opt)
{
case aGPGConfList: gpgconf_list = 1; break;
case aGPGConfTest: gpgconf_list = 2; break;
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
case oBatch: opt.batch=1; break;
case oDebug:
if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
{
pargs.r_opt = ARGPARSE_INVALID_ARG;
pargs.err = ARGPARSE_PRINT_ERROR;
}
break;
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oDebugAllowCoreDump:
enable_core_dumps ();
allow_coredump = 1;
break;
case oDebugCCIDDriver:
#ifdef HAVE_LIBUSB
ccid_set_debug_level (ccid_set_debug_level (-1)+1);
#endif /*HAVE_LIBUSB*/
break;
case oDebugLogTid:
log_set_pid_suffix_cb (tid_log_callback);
break;
case oDebugAssuanLogCats:
set_libassuan_log_cats (pargs.r.ret_ulong);
break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if (!configfp)
{
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoGreeting: nogreeting = 1; break;
case oNoVerbose: opt.verbose = 0; break;
case oNoOptions: break; /* no-options */
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
case oNoDetach: nodetach = 1; break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; break;
case oServer: pipe_server = 1; break;
case oMultiServer: pipe_server = 1; multi_server = 1; break;
case oDaemon: is_daemon = 1; break;
case oReaderPort: opt.reader_port = pargs.r.ret_str; break;
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
case oDisableCCID: opt.disable_ccid = 1; break;
case oDisableOpenSC: break;
case oDisablePinpad: opt.disable_pinpad = 1; break;
case oAllowAdmin: /* Dummy because allow is now the default. */
break;
case oDenyAdmin: opt.allow_admin = 0; break;
case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break;
case oDisableApplication:
add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
break;
case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break;
+ case oListenBacklog:
+ listen_backlog = pargs.r.ret_int;
+ break;
+
default:
pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
break;
}
}
if (configfp)
{
fclose( configfp );
configfp = NULL;
/* Keep a copy of the config name for use by --gpgconf-list. */
config_filename = configname;
configname = NULL;
goto next_pass;
}
xfree (configname);
configname = NULL;
if (log_get_errorcount(0))
exit(2);
if (nogreeting )
greeting = 0;
if (greeting)
{
es_fprintf (es_stderr, "%s %s; %s\n",
strusage(11), strusage(13), strusage(14) );
es_fprintf (es_stderr, "%s\n", strusage(15) );
}
#ifdef IS_DEVELOPMENT_VERSION
log_info ("NOTE: this is a development version!\n");
#endif
/* Print a warning if an argument looks like an option. */
if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
{
int i;
for (i=0; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == '-')
log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
}
if (atexit (cleanup))
{
log_error ("atexit failed\n");
cleanup ();
exit (1);
}
set_debug (debug_level);
if (initialize_module_command ())
{
log_error ("initialization failed\n");
cleanup ();
exit (1);
}
if (gpgconf_list == 2)
scd_exit (0);
if (gpgconf_list)
{
/* List options and default values in the GPG Conf format. */
char *filename = NULL;
char *filename_esc;
if (config_filename)
filename = xstrdup (config_filename);
else
filename = make_filename (gnupg_homedir (),
SCDAEMON_NAME EXTSEP_S "conf", NULL);
filename_esc = percent_escape (filename, NULL);
es_printf ("%s-%s.conf:%lu:\"%s\n",
GPGCONF_NAME, SCDAEMON_NAME,
GC_OPT_FLAG_DEFAULT, filename_esc);
xfree (filename_esc);
xfree (filename);
es_printf ("verbose:%lu:\n"
"quiet:%lu:\n"
"debug-level:%lu:\"none:\n"
"log-file:%lu:\n",
GC_OPT_FLAG_NONE,
GC_OPT_FLAG_NONE,
GC_OPT_FLAG_DEFAULT,
GC_OPT_FLAG_NONE );
es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
es_printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
es_printf ("pcsc-driver:%lu:\"%s:\n",
GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
#ifdef HAVE_LIBUSB
es_printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
#endif
es_printf ("deny-admin:%lu:\n", GC_OPT_FLAG_NONE );
es_printf ("disable-pinpad:%lu:\n", GC_OPT_FLAG_NONE );
es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0);
es_printf ("enable-pinpad-varlen:%lu:\n", GC_OPT_FLAG_NONE );
scd_exit (0);
}
/* Now start with logging to a file if this is desired. */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
}
if (debug_wait && pipe_server)
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}
if (pipe_server)
{
/* This is the simple pipe based server */
ctrl_t ctrl;
npth_attr_t tattr;
int fd = -1;
#ifndef HAVE_W32_SYSTEM
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
}
#endif
npth_init ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* If --debug-allow-core-dump has been given we also need to
switch the working directory to a place where we can actually
write. */
if (allow_coredump)
{
if (chdir("/tmp"))
log_debug ("chdir to '/tmp' failed: %s\n", strerror (errno));
else
log_debug ("changed working directory to '/tmp'\n");
}
/* In multi server mode we need to listen on an additional
socket. Create that socket now before starting the handler
for the pipe connection. This allows that handler to send
back the name of that socket. */
if (multi_server)
{
socket_name = create_socket_name (SCDAEMON_SOCK_NAME);
fd = FD2INT(create_server_socket (socket_name,
&redir_socket_name, &socket_nonce));
}
res = npth_attr_init (&tattr);
if (res)
{
log_error ("error allocating thread attributes: %s\n",
strerror (res));
scd_exit (2);
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
ctrl = xtrycalloc (1, sizeof *ctrl);
if ( !ctrl )
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
scd_exit (2);
}
ctrl->thread_startup.fd = GNUPG_INVALID_FD;
res = npth_create (&pipecon_handler, &tattr, start_connection_thread, ctrl);
if (res)
{
log_error ("error spawning pipe connection handler: %s\n",
strerror (res) );
xfree (ctrl);
scd_exit (2);
}
npth_setname_np (pipecon_handler, "pipe-connection");
npth_attr_destroy (&tattr);
/* We run handle_connection to wait for the shutdown signal and
to run the ticker stuff. */
handle_connections (fd);
if (fd != -1)
close (fd);
}
else if (!is_daemon)
{
log_info (_("please use the option '--daemon'"
" to run the program in the background\n"));
}
else
{ /* Regular server mode */
int fd;
#ifndef HAVE_W32_SYSTEM
pid_t pid;
int i;
#endif
/* Create the socket. */
socket_name = create_socket_name (SCDAEMON_SOCK_NAME);
fd = FD2INT (create_server_socket (socket_name,
&redir_socket_name, &socket_nonce));
fflush (NULL);
#ifdef HAVE_W32_SYSTEM
(void)csh_style;
(void)nodetach;
#else
pid = fork ();
if (pid == (pid_t)-1)
{
log_fatal ("fork failed: %s\n", strerror (errno) );
exit (1);
}
else if (pid)
{ /* we are the parent */
char *infostr;
close (fd);
/* create the info string: :: */
if (gpgrt_asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1",
socket_name, (ulong) pid) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
exit (1);
}
*socket_name = 0; /* don't let cleanup() remove the socket -
the child should do this from now on */
if (argc)
{ /* run the program given on the commandline */
if (putenv (infostr))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
kill (pid, SIGTERM );
exit (1);
}
execvp (argv[0], argv);
log_error ("failed to run the command: %s\n", strerror (errno));
kill (pid, SIGTERM);
exit (1);
}
else
{
/* Print the environment string, so that the caller can use
shell's eval to set it */
if (csh_style)
{
*strchr (infostr, '=') = ' ';
es_printf ( "setenv %s;\n", infostr);
}
else
{
es_printf ( "%s; export SCDAEMON_INFO;\n", infostr);
}
xfree (infostr);
exit (0);
}
/* NOTREACHED */
} /* end parent */
/* This is the child. */
npth_init ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Detach from tty and put process into a new session. */
if (!nodetach )
{
/* Close stdin, stdout and stderr unless it is the log stream. */
for (i=0; i <= 2; i++)
{
if (!log_test_fd (i) && i != fd )
{
if ( !close (i)
&& open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
{
log_error ("failed to open '%s': %s\n",
"/dev/null", strerror (errno));
cleanup ();
exit (1);
}
}
}
if (setsid() == -1)
{
log_error ("setsid() failed: %s\n", strerror(errno) );
cleanup ();
exit (1);
}
}
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
}
#endif /*!HAVE_W32_SYSTEM*/
if (gnupg_chdir (gnupg_daemon_rootdir ()))
{
log_error ("chdir to '%s' failed: %s\n",
gnupg_daemon_rootdir (), strerror (errno));
exit (1);
}
handle_connections (fd);
close (fd);
}
return 0;
}
void
scd_exit (int rc)
{
apdu_prepare_exit ();
#if 0
#warning no update_random_seed_file
update_random_seed_file();
#endif
#if 0
/* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE)
{
gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
#endif
gcry_control (GCRYCTL_TERM_SECMEM );
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit (rc);
}
static void
scd_init_default_ctrl (ctrl_t ctrl)
{
(void)ctrl;
}
static void
scd_deinit_default_ctrl (ctrl_t ctrl)
{
if (!ctrl)
return;
xfree (ctrl->in_data.value);
ctrl->in_data.value = NULL;
ctrl->in_data.valuelen = 0;
}
/* Return the name of the socket to be used to connect to this
process. If no socket is available, return NULL. */
const char *
scd_get_socket_name ()
{
if (socket_name && *socket_name)
return socket_name;
return NULL;
}
#ifndef HAVE_W32_SYSTEM
static void
handle_signal (int signo)
{
switch (signo)
{
case SIGHUP:
log_info ("SIGHUP received - "
"re-reading configuration and resetting cards\n");
/* reread_configuration (); */
break;
case SIGUSR1:
log_info ("SIGUSR1 received - printing internal information:\n");
/* Fixme: We need to see how to integrate pth dumping into our
logging system. */
/* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
app_dump_state ();
break;
case SIGUSR2:
log_info ("SIGUSR2 received - no action defined\n");
break;
case SIGCONT:
/* Nothing. */
log_debug ("SIGCONT received - breaking select\n");
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
log_info ("SIGTERM received - still %i running threads\n",
active_connections);
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info ("shutdown forced\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
scd_exit (0);
}
break;
case SIGINT:
log_info ("SIGINT received - immediate shutdown\n");
log_info( "%s %s stopped\n", strusage(11), strusage(13));
cleanup ();
scd_exit (0);
break;
default:
log_info ("signal %d received - no action defined\n", signo);
}
}
#endif /*!HAVE_W32_SYSTEM*/
/* Create a name for the socket. We check for valid characters as
well as against a maximum allowed length for a unix domain socket
is done. The function terminates the process in case of an error.
Retunrs: Pointer to an allcoated string with the absolute name of
the socket used. */
static char *
create_socket_name (char *standard_name)
{
char *name;
name = make_filename (gnupg_socketdir (), standard_name, NULL);
if (strchr (name, PATHSEP_C))
{
log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
scd_exit (2);
}
return name;
}
/* Create a Unix domain socket with NAME. Returns the file descriptor
or terminates the process in case of an error. If the socket has
been redirected the name of the real socket is stored as a malloced
string at R_REDIR_NAME. */
static gnupg_fd_t
create_server_socket (const char *name, char **r_redir_name,
assuan_sock_nonce_t *nonce)
{
struct sockaddr *addr;
struct sockaddr_un *unaddr;
socklen_t len;
gnupg_fd_t fd;
int rc;
xfree (*r_redir_name);
*r_redir_name = NULL;
fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
if (fd == GNUPG_INVALID_FD)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
scd_exit (2);
}
unaddr = xmalloc (sizeof (*unaddr));
addr = (struct sockaddr*)unaddr;
{
int redirected;
if (assuan_sock_set_sockaddr_un (name, addr, &redirected))
{
if (errno == ENAMETOOLONG)
log_error (_("socket name '%s' is too long\n"), name);
else
log_error ("error preparing socket '%s': %s\n",
name, gpg_strerror (gpg_error_from_syserror ()));
scd_exit (2);
}
if (redirected)
{
*r_redir_name = xstrdup (unaddr->sun_path);
if (opt.verbose)
log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
}
}
len = SUN_LEN (unaddr);
rc = assuan_sock_bind (fd, addr, len);
if (rc == -1 && errno == EADDRINUSE)
{
gnupg_remove (unaddr->sun_path);
rc = assuan_sock_bind (fd, addr, len);
}
if (rc != -1
&& (rc=assuan_sock_get_nonce (addr, len, nonce)))
log_error (_("error getting nonce for the socket\n"));
if (rc == -1)
{
log_error (_("error binding socket to '%s': %s\n"),
unaddr->sun_path,
gpg_strerror (gpg_error_from_syserror ()));
assuan_sock_close (fd);
scd_exit (2);
}
if (gnupg_chmod (unaddr->sun_path, "-rwx"))
log_error (_("can't set permissions of '%s': %s\n"),
unaddr->sun_path, strerror (errno));
- if (listen (FD2INT(fd), 5 ) == -1)
+ if (listen (FD2INT(fd), listen_backlog) == -1)
{
- log_error (_("listen() failed: %s\n"),
- gpg_strerror (gpg_error_from_syserror ()));
+ log_error ("listen(fd, %d) failed: %s\n",
+ listen_backlog, gpg_strerror (gpg_error_from_syserror ()));
assuan_sock_close (fd);
scd_exit (2);
}
if (opt.verbose)
log_info (_("listening on socket '%s'\n"), unaddr->sun_path);
return fd;
}
/* This is the standard connection thread's main function. */
static void *
start_connection_thread (void *arg)
{
ctrl_t ctrl = arg;
if (ctrl->thread_startup.fd != GNUPG_INVALID_FD
&& assuan_sock_check_nonce (ctrl->thread_startup.fd, &socket_nonce))
{
log_info (_("error reading nonce on fd %d: %s\n"),
FD2INT(ctrl->thread_startup.fd), strerror (errno));
assuan_sock_close (ctrl->thread_startup.fd);
xfree (ctrl);
return NULL;
}
active_connections++;
scd_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("handler for fd %d started\n"),
FD2INT(ctrl->thread_startup.fd));
/* If this is a pipe server, we request a shutdown if the command
handler asked for it. With the next ticker event and given that
no other connections are running the shutdown will then
happen. */
if (scd_command_handler (ctrl, FD2INT(ctrl->thread_startup.fd))
&& pipe_server)
shutdown_pending = 1;
if (opt.verbose)
log_info (_("handler for fd %d terminated\n"),
FD2INT (ctrl->thread_startup.fd));
scd_deinit_default_ctrl (ctrl);
xfree (ctrl);
if (--active_connections == 0)
scd_kick_the_loop ();
return NULL;
}
void
scd_kick_the_loop (void)
{
int ret;
/* Kick the select loop. */
#ifdef HAVE_W32_SYSTEM
ret = SetEvent (the_event);
if (ret == 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
w32_strerror (-1));
#else
ret = kill (main_thread_pid, SIGCONT);
if (ret < 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
#endif
}
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. LISTEN_FD is allowed to be -1
in which case this code will only do regular timeouts and handle
signals. */
static void
handle_connections (int listen_fd)
{
npth_attr_t tattr;
struct sockaddr_un paddr;
socklen_t plen;
fd_set fdset, read_fdset;
int nfd;
int ret;
int fd;
struct timespec timeout;
struct timespec *t;
int saved_errno;
#ifdef HAVE_W32_SYSTEM
HANDLE events[2];
unsigned int events_set;
#else
int signo;
#endif
ret = npth_attr_init(&tattr);
if (ret)
{
log_error ("npth_attr_init failed: %s\n", strerror (ret));
return;
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
#ifdef HAVE_W32_SYSTEM
{
HANDLE h, h2;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
events[0] = the_event = INVALID_HANDLE_VALUE;
events[1] = INVALID_HANDLE_VALUE;
h = CreateEvent (&sa, TRUE, FALSE, NULL);
if (!h)
log_error ("can't create scd event: %s\n", w32_strerror (-1) );
else if (!DuplicateHandle (GetCurrentProcess(), h,
GetCurrentProcess(), &h2,
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
{
log_error ("setting synchronize for scd_kick_the_loop failed: %s\n",
w32_strerror (-1) );
CloseHandle (h);
}
else
{
CloseHandle (h);
events[0] = the_event = h2;
}
}
#else
npth_sigev_init ();
npth_sigev_add (SIGHUP);
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
main_thread_pid = getpid ();
#endif
FD_ZERO (&fdset);
nfd = 0;
if (listen_fd != -1)
{
FD_SET (listen_fd, &fdset);
nfd = listen_fd;
}
for (;;)
{
int periodical_check;
if (shutdown_pending)
{
if (active_connections == 0)
break; /* ready */
/* Do not accept anymore connections but wait for existing
connections to terminate. We do this by clearing out all
file descriptors to wait for, so that the select will be
used to just wait on a signal or timeout event. */
FD_ZERO (&fdset);
listen_fd = -1;
}
periodical_check = scd_update_reader_status_file ();
timeout.tv_sec = TIMERTICK_INTERVAL_SEC;
timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000;
if (shutdown_pending || periodical_check)
t = &timeout;
else
t = NULL;
/* POSIX says that fd_set should be implemented as a structure,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
#ifndef HAVE_W32_SYSTEM
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, t,
npth_sigev_sigmask ());
saved_errno = errno;
while (npth_sigev_get_pending(&signo))
handle_signal (signo);
#else
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, t,
events, &events_set);
saved_errno = errno;
if (events_set & 1)
continue;
#endif
if (ret == -1 && saved_errno != EINTR)
{
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
strerror (saved_errno));
npth_sleep (1);
continue;
}
if (ret <= 0)
/* Timeout. Will be handled when calculating the next timeout. */
continue;
if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset))
{
ctrl_t ctrl;
plen = sizeof paddr;
fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
if (fd == -1)
{
log_error ("accept failed: %s\n", strerror (errno));
}
else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
close (fd);
}
else
{
char threadname[50];
npth_t thread;
snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
ctrl->thread_startup.fd = INT2FD (fd);
ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
if (ret)
{
log_error ("error spawning connection handler: %s\n",
strerror (ret));
xfree (ctrl);
close (fd);
}
else
npth_setname_np (thread, threadname);
}
}
}
#ifdef HAVE_W32_SYSTEM
if (the_event != INVALID_HANDLE_VALUE)
CloseHandle (the_event);
#endif
cleanup ();
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
npth_attr_destroy (&tattr);
}
/* Return the number of active connections. */
int
get_active_connection_count (void)
{
return active_connections;
}