agent: separate out daemon handling infrastructure for reuse

* agent/call-scd.c: Factor re-usable code out to ...
* agent/call-daemon.c: new.  Store infos in an array to allow for
other backend daemons.
* agent/Makefile.am (gpg_agent_SOURCES): Add new file.
* agent/agent.h: Include assuan.h.
(enum daemon_type): New.
(opt): Replace scdaemon_program by daemon_program array.  Replace
scd_local by a array d_local.  Change users accordingly.
--

The model I'm using for a TPM daemon is the current scdaemon.  That
includes start and stop handlers plus liveness checks and an assuan
socket generator.  To avoid massive code duplication (and save me a
lot of effort), I've elected to strip this code out of call-scd.c into
a generic framework which can then be reused as is by the TPM handling
daemon.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Co-authored-by: Werner Koch <wk@gnupg.org>

Modified original patch for 2.2 heavily to fit the new framework used
in master (gnupg 2.3)

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
James Bottomley 2020-06-24 12:44:02 +02:00 committed by Werner Koch
parent 2d8f060679
commit f541e1d95a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
7 changed files with 759 additions and 583 deletions

View File

@ -54,6 +54,7 @@ gpg_agent_SOURCES = \
divert-scd.c \
cvt-openpgp.c cvt-openpgp.h \
call-scd.c \
call-daemon.c \
learncard.c
common_libs = $(libcommon)

View File

@ -29,6 +29,7 @@
#define map_assuan_err(a) \
map_assuan_err_with_source (GPG_ERR_SOURCE_DEFAULT, (a))
#include <errno.h>
#include <assuan.h>
#include <gcrypt.h>
#include "../common/util.h"
@ -53,6 +54,13 @@
this shouldn't be a problem in practice. */
#define MAX_PASSPHRASE_LEN 255
/* The daemons we support. When you add a new daemon, add to
both the daemon_type and the daemon_modules array in call-daemon.c */
enum daemon_type
{
DAEMON_SCD,
DAEMON_MAX_TYPE
};
/* A large struct name "opt" to keep global flags */
EXTERN_UNLESS_MAIN_MODULE
@ -79,10 +87,10 @@ struct
/* Filename of the program to start as pinentry. */
const char *pinentry_program;
/* Filename of the program to handle smartcard tasks. */
const char *scdaemon_program;
/* Filename of the program to handle daemon tasks. */
const char *daemon_program[DAEMON_MAX_TYPE];
int disable_scdaemon; /* Never use the SCdaemon. */
int disable_daemon[DAEMON_MAX_TYPE]; /* Never use the daemon. */
int no_grab; /* Don't let the pinentry grab the keyboard */
@ -207,7 +215,7 @@ struct ssh_control_file_s;
typedef struct ssh_control_file_s *ssh_control_file_t;
/* Forward reference for local definitions in call-scd.c. */
struct scd_local_s;
struct daemon_local_s;
/* Collection of data per session (aka connection). */
struct server_control_s
@ -227,8 +235,8 @@ struct server_control_s
/* Private data of the server (command.c). */
struct server_local_s *server_local;
/* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local;
/* Private data of the daemon (call-XXX.c). */
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
/* Environment settings for the connection. */
session_env_t session_env;
@ -386,7 +394,7 @@ const char *get_agent_socket_name (void);
const char *get_agent_ssh_socket_name (void);
int get_agent_active_connection_count (void);
#ifdef HAVE_W32_SYSTEM
void *get_agent_scd_notify_event (void);
void *get_agent_daemon_notify_event (void);
#endif
void agent_sighup_action (void);
int map_pk_openpgp_to_gcry (int openpgp_algo);
@ -583,12 +591,18 @@ gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno,
const char *keyref,
const char *keydata, size_t keydatalen);
/*-- call-daemon.c --*/
gpg_error_t daemon_start (enum daemon_type type, ctrl_t ctrl);
assuan_context_t daemon_type_ctx (enum daemon_type type, ctrl_t ctrl);
gpg_error_t daemon_unlock (enum daemon_type type, ctrl_t ctrl, gpg_error_t rc);
void initialize_module_daemon (void);
void agent_daemon_dump_state (void);
int agent_daemon_check_running (enum daemon_type type);
void agent_daemon_check_aliveness (void);
void agent_reset_daemon (ctrl_t ctrl);
void agent_kill_daemon (enum daemon_type type);
/*-- call-scd.c --*/
void initialize_module_call_scd (void);
void agent_scd_dump_state (void);
int agent_scd_check_running (void);
int agent_reset_scd (ctrl_t ctrl);
int agent_card_learn (ctrl_t ctrl,
void (*kpinfo_cb)(void*, const char *),
void *kpinfo_cb_arg,
@ -631,10 +645,10 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *,
const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context);
void agent_card_free_keyinfo (struct card_key_info_s *l);
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
int cap, struct card_key_info_s **result);
void agent_card_killscd (void);
/*-- learncard.c --*/

688
agent/call-daemon.c Normal file
View File

@ -0,0 +1,688 @@
/* call-daemon - Common code for the call-XXX.c modules
* Copyright (C) 2001, 2002, 2005, 2007, 2010,
* 2011 Free Software Foundation, Inc.
* Copyright (C) 2013 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/wait.h>
#endif
#include <npth.h>
#include "agent.h"
#include <assuan.h>
#include "../common/strlist.h"
/* Daemon type to module mapping. Make sure that they are added in the
* same order as given by the daemon_type enum. */
static const int daemon_modules[DAEMON_MAX_TYPE] =
{
GNUPG_MODULE_NAME_SCDAEMON
};
/* Definition of module local data of the CTRL structure. */
struct daemon_local_s
{
/* We keep a list of all allocated context with an anchor at
DAEMON_LOCAL_LIST (see below). */
struct daemon_local_s *next_local;
/* Link back to the global structure. */
struct daemon_global_s *g;
assuan_context_t ctx; /* NULL or session context for the daemon
used with this connection. */
unsigned int in_use: 1; /* CTX is in use. */
unsigned int invalid:1; /* CTX is invalid, should be released. */
};
/* Primary holder of all the started daemons */
struct daemon_global_s
{
/* To keep track of all active daemon contexts, we keep a linked list
anchored at this variable. */
struct daemon_local_s *local_list;
/* A malloced string with the name of the socket to be used for
additional connections. May be NULL if not provided by
daemon. */
char *socket_name;
/* The context of the primary connection. This is also used as a flag
to indicate whether the daemon has been started. */
assuan_context_t primary_ctx;
/* To allow reuse of the primary connection, the following flag is set
to true if the primary context has been reset and is not in use by
any connection. */
int primary_ctx_reusable;
};
static struct daemon_global_s daemon_global[DAEMON_MAX_TYPE];
/* A Mutex used inside the start_daemon function. */
static npth_mutex_t start_daemon_lock;
/* Communication object for wait_child_thread. */
struct wait_child_thread_parm_s
{
enum daemon_type type;
#ifdef HAVE_W32_SYSTEM
HANDLE pid;
#else
pid_t pid;
#endif
};
/* Thread to wait for daemon termination and cleanup of resources. */
static void *
wait_child_thread (void *arg)
{
int err;
struct wait_child_thread_parm_s *parm = arg;
enum daemon_type type = parm->type;
#ifdef HAVE_W32_SYSTEM
HANDLE pid = parm->pid;
#else
pid_t pid = parm->pid;
int wstatus;
#endif
const char *name = gnupg_module_name (daemon_modules[type]);
struct daemon_global_s *g = &daemon_global[type];
struct daemon_local_s *sl;
xfree (parm); /* We have copied all data to the stack. */
#ifdef HAVE_W32_SYSTEM
npth_unprotect ();
WaitForSingleObject ((HANDLE)pid, INFINITE);
npth_protect ();
log_info ("daemon %s finished\n", name);
#else /* !HAVE_W32_SYSTEM*/
again:
npth_unprotect ();
err = waitpid (pid, &wstatus, 0);
npth_protect ();
if (err < 0)
{
if (errno == EINTR)
goto again;
log_error ("waitpid for %s failed: %s\n", name, strerror (errno));
return NULL;
}
else
{
if (WIFEXITED (wstatus))
log_info ("daemon %s finished (status %d)\n",
name, WEXITSTATUS (wstatus));
else if (WIFSIGNALED (wstatus))
log_info ("daemon %s killed by signal %d\n", name, WTERMSIG (wstatus));
else
{
if (WIFSTOPPED (wstatus))
log_info ("daemon %s stopped by signal %d\n",
name, WSTOPSIG (wstatus));
goto again;
}
}
#endif /*!HAVE_W32_SYSTEM*/
agent_flush_cache (1); /* Flush the PIN cache. */
err = npth_mutex_lock (&start_daemon_lock);
if (err)
{
log_error ("failed to acquire the start_daemon lock: %s\n",
strerror (err));
}
else
{
assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1);
for (sl = g->local_list; sl; sl = sl->next_local)
{
sl->invalid = 1;
if (!sl->in_use && sl->ctx)
{
assuan_release (sl->ctx);
sl->ctx = NULL;
}
}
g->primary_ctx = NULL;
g->primary_ctx_reusable = 0;
xfree (g->socket_name);
g->socket_name = NULL;
err = npth_mutex_unlock (&start_daemon_lock);
if (err)
log_error ("failed to release the start_daemon lock"
" after waitpid for %s: %s\n", name, strerror (err));
}
return NULL;
}
/* This function shall be called after having accessed the daemon. It
* is currently not very useful but gives an opportunity to keep track
* of connections currently calling daemon. Note that the "lock"
* operation is done by the daemon_start function which must be called
* and error checked before any daemon operation. CTRL is the usual
* connection context and RC the error code to be passed through the
* function. */
gpg_error_t
daemon_unlock (enum daemon_type type, ctrl_t ctrl, gpg_error_t rc)
{
gpg_error_t err;
if (ctrl->d_local[type]->in_use == 0)
{
log_error ("%s: CTX for type %d is not in use\n", __func__, (int)type);
if (!rc)
rc = gpg_error (GPG_ERR_INTERNAL);
}
err = npth_mutex_lock (&start_daemon_lock);
if (err)
{
log_error ("failed to acquire the start_daemon lock: %s\n",
strerror (err));
return gpg_error (GPG_ERR_INTERNAL);
}
ctrl->d_local[type]->in_use = 0;
if (ctrl->d_local[type]->invalid)
{
assuan_release (ctrl->d_local[type]->ctx);
ctrl->d_local[type]->ctx = NULL;
ctrl->d_local[type]->invalid = 0;
}
err = npth_mutex_unlock (&start_daemon_lock);
if (err)
{
log_error ("failed to release the start_daemon lock: %s\n",
strerror (err));
return gpg_error (GPG_ERR_INTERNAL);
}
return rc;
}
/* To make sure we leave no secrets in our image after forking of the
daemon, we use this callback. */
static void
atfork_cb (void *opaque, int where)
{
(void)opaque;
if (!where)
gcry_control (GCRYCTL_TERM_SECMEM);
}
/* Fork off the daemon if this has not already been done. Lock the
* daemon and make sure that a proper context has been setup in CTRL.
* This function might also lock the daemon, which means that the
* caller must call unlock_daemon after this function has returned
* success and the actual Assuan transaction been done. */
gpg_error_t
daemon_start (enum daemon_type type, ctrl_t ctrl)
{
gpg_error_t err = 0;
const char *pgmname;
assuan_context_t ctx = NULL;
const char *argv[5];
assuan_fd_t no_close_list[3];
int i;
int rc;
char *abs_homedir = NULL;
struct daemon_global_s *g = &daemon_global[type];
const char *name = gnupg_module_name (daemon_modules[type]);
log_assert (type < DAEMON_MAX_TYPE);
/* if this fails, you forgot to add your new type to daemon_modules */
log_assert (DAEMON_MAX_TYPE == DIM (daemon_modules));
if (opt.disable_daemon[type])
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (ctrl->d_local[type] && ctrl->d_local[type]->ctx)
{
ctrl->d_local[type]->in_use = 1;
return 0; /* Okay, the context is fine. */
}
if (ctrl->d_local[type] && ctrl->d_local[type]->in_use)
{
log_error ("%s: CTX of type %d is in use\n", __func__, type);
return gpg_error (GPG_ERR_INTERNAL);
}
/* We need to serialize the access to scd_local_list and primary_scd_ctx. */
rc = npth_mutex_lock (&start_daemon_lock);
if (rc)
{
log_error ("failed to acquire the start_daemon lock: %s\n",
strerror (rc));
return gpg_error (GPG_ERR_INTERNAL);
}
/* If this is the first call for this session, setup the local data
structure. */
if (!ctrl->d_local[type])
{
ctrl->d_local[type] = xtrycalloc (1, sizeof *ctrl->d_local[type]);
if (!ctrl->d_local[type])
{
err = gpg_error_from_syserror ();
rc = npth_mutex_unlock (&start_daemon_lock);
if (rc)
log_error ("failed to release the start_daemon lock: %s\n",
strerror (rc));
return err;
}
ctrl->d_local[type]->g = g;
ctrl->d_local[type]->next_local = g->local_list;
g->local_list = ctrl->d_local[type]; /* FIXME: CHECK the G thing */
}
ctrl->d_local[type]->in_use = 1;
/* Check whether the pipe server has already been started and in
this case either reuse a lingering pipe connection or establish a
new socket based one. */
if (g->primary_ctx && g->primary_ctx_reusable)
{
ctx = g->primary_ctx;
g->primary_ctx_reusable = 0;
if (opt.verbose)
log_info ("new connection to %s daemon established (reusing)\n",
name);
goto leave;
}
rc = assuan_new (&ctx);
if (rc)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
err = rc;
goto leave;
}
if (g->socket_name)
{
rc = assuan_socket_connect (ctx, g->socket_name, 0, 0);
if (rc)
{
log_error ("can't connect to socket '%s': %s\n",
g->socket_name, gpg_strerror (rc));
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
if (opt.verbose)
log_info ("new connection to %s daemon established\n",
name);
goto leave;
}
if (g->primary_ctx)
{
log_info ("%s daemon is running but won't accept further connections\n",
name);
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
/* Nope, it has not been started. Fire it up now. */
if (opt.verbose)
log_info ("no running %s daemon - starting it\n", name);
agent_flush_cache (1); /* Make sure the PIN cache is flushed. */
if (fflush (NULL))
{
#ifndef HAVE_W32_SYSTEM
err = gpg_error_from_syserror ();
#endif
log_error ("error flushing pending output: %s\n", strerror (errno));
/* At least Windows XP fails here with EBADF. According to docs
and Wine an fflush(NULL) is the same as _flushall. However
the Wime implementation does not flush stdin,stdout and stderr
- see above. Lets try to ignore the error. */
#ifndef HAVE_W32_SYSTEM
goto leave;
#endif
}
if (!opt.daemon_program[type] || !*opt.daemon_program[type])
opt.daemon_program[type] = gnupg_module_name (daemon_modules[type]);
if ( !(pgmname = strrchr (opt.daemon_program[type], '/')))
pgmname = opt.daemon_program[type];
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--multi-server";
if (gnupg_default_homedir_p ())
argv[2] = NULL;
else
{
abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
if (!abs_homedir)
{
log_error ("error building filename: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
goto leave;
}
argv[2] = "--homedir";
argv[3] = abs_homedir;
argv[4] = NULL;
}
i=0;
if (!opt.running_detached)
{
if (log_get_fd () != -1)
no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
}
no_close_list[i] = ASSUAN_INVALID_FD;
/* Connect to the daemon and perform initial handshaking. Use
detached flag so that under Windows DAEMON does not show up a
new window. */
rc = assuan_pipe_connect (ctx, opt.daemon_program[type], argv,
no_close_list, atfork_cb, NULL,
ASSUAN_PIPE_CONNECT_DETACHED);
if (rc)
{
log_error ("can't connect to the daemon %s: %s\n",
name, gpg_strerror (rc));
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
if (opt.verbose)
log_info ("first connection to daemon %s established\n", name);
/* Get the name of the additional socket opened by daemon. */
{
membuf_t data;
unsigned char *databuf;
size_t datalen;
xfree (g->socket_name);
g->socket_name = NULL;
init_membuf (&data, 256);
assuan_transact (ctx, "GETINFO socket_name",
put_membuf_cb, &data, NULL, NULL, NULL, NULL);
databuf = get_membuf (&data, &datalen);
if (databuf && datalen)
{
g->socket_name = xtrymalloc (datalen + 1);
if (!g->socket_name)
log_error ("warning: can't store socket name: %s\n",
strerror (errno));
else
{
memcpy (g->socket_name, databuf, datalen);
g->socket_name[datalen] = 0;
if (DBG_IPC)
log_debug ("additional connections at '%s'\n", g->socket_name);
}
}
xfree (databuf);
}
/* Tell the daemon we want him to send us an event signal. We
don't support this for W32CE. */
#ifndef HAVE_W32CE_SYSTEM
if (opt.sigusr2_enabled)
{
char buf[100];
#ifdef HAVE_W32_SYSTEM
snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
(unsigned long)get_agent_daemon_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
assuan_transact (ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL);
}
#endif /*HAVE_W32CE_SYSTEM*/
g->primary_ctx = ctx;
g->primary_ctx_reusable = 0;
{
npth_t thread;
npth_attr_t tattr;
struct wait_child_thread_parm_s *wctp;
wctp = xtrymalloc (sizeof *wctp);
if (!wctp)
{
err = gpg_error_from_syserror ();
log_error ("error preparing wait_child_thread: %s\n", strerror (err));
goto leave;
}
wctp->type = type;
wctp->pid = assuan_get_pid (g->primary_ctx);
err = npth_attr_init (&tattr);
if (!err)
{
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
err = npth_create (&thread, &tattr, wait_child_thread, wctp);
if (err)
log_error ("error spawning wait_child_thread: %s\n", strerror (err));
npth_attr_destroy (&tattr);
}
}
leave:
rc = npth_mutex_unlock (&start_daemon_lock);
if (rc)
log_error ("failed to release the start_daemon lock: %s\n", strerror (rc));
xfree (abs_homedir);
if (err)
{
daemon_unlock (type, ctrl, err);
if (ctx)
assuan_release (ctx);
}
else
{
ctrl->d_local[type]->ctx = ctx;
ctrl->d_local[type]->invalid = 0;
}
return err;
}
/* This function must be called once to initialize this module. This
has to be done before a second thread is spawned. We can't do the
static initialization because NPth emulation code might not be able
to do a static init; in particular, it is not possible for W32. */
void
initialize_module_daemon (void)
{
static int initialized;
int err;
if (!initialized)
{
err = npth_mutex_init (&start_daemon_lock, NULL);
if (err)
log_fatal ("error initializing mutex: %s\n", strerror (err));
initialized = 1;
}
}
/* This function may be called to print information pertaining to the
current state of this module to the log. */
void
agent_daemon_dump_state (void)
{
int i;
for (i = 0; i < DAEMON_MAX_TYPE; i++) {
struct daemon_global_s *g = &daemon_global[i];
log_info ("%s: name %s primary_ctx=%p pid=%ld reusable=%d\n", __func__,
gnupg_module_name (daemon_modules[i]),
g->primary_ctx,
(long)assuan_get_pid (g->primary_ctx),
g->primary_ctx_reusable);
if (g->socket_name)
log_info ("%s: socket='%s'\n", __func__, g->socket_name);
}
}
/* Check whether the daemon is active. This is a fast check without
* any locking and might give a wrong result if another thread is
* about to start the daemon or the daemon is about to be stopped. */
int
agent_daemon_check_running (enum daemon_type type)
{
return !!daemon_global[type].primary_ctx;
}
/* Send a kill command to the daemon of TYPE */
void
agent_kill_daemon (enum daemon_type type)
{
struct daemon_global_s *g = &daemon_global[type];
if (g->primary_ctx == NULL)
return;
/* FIXME: This assumes SCdaemon; we should add a new command
* (e.g. SHUTDOWN) so that there is no need to have a daemon
* specific command. */
assuan_transact (g->primary_ctx, "KILLSCD",
NULL, NULL, NULL, NULL, NULL, NULL);
agent_flush_cache (1); /* 1 := Flush the PIN cache. */
}
/* Reset the daemons if they have been used. Actually it is not a
reset but a cleanup of resources used by the current connection. */
void
agent_reset_daemon (ctrl_t ctrl)
{
int i;
int rc;
rc = npth_mutex_lock (&start_daemon_lock);
if (rc)
{
log_error ("failed to acquire the start_daemon lock: %s\n",
strerror (rc));
return;
}
for (i = 0; i < DAEMON_MAX_TYPE; i++)
if (ctrl->d_local[i])
{
struct daemon_global_s *g = ctrl->d_local[i]->g;
if (ctrl->d_local[i]->ctx)
{
/* For the primary connection we send a reset and keep
* that connection open for reuse. */
if (ctrl->d_local[i]->ctx == g->primary_ctx)
{
/* Send a RESTART to the daemon. This is required for the
primary connection as a kind of virtual EOF; we don't
have another way to tell it that the next command
should be viewed as if a new connection has been
made. For the non-primary connections this is not
needed as we simply close the socket. We don't check
for an error here because the RESTART may fail for
example if the daemon has already been terminated.
Anyway, we need to set the reusable flag to make sure
that the aliveness check can clean it up. */
assuan_transact (g->primary_ctx, "RESTART",
NULL, NULL, NULL, NULL, NULL, NULL);
g->primary_ctx_reusable = 1;
}
else /* Secondary connections. */
assuan_release (ctrl->d_local[i]->ctx);
ctrl->d_local[i]->ctx = NULL;
}
/* Remove the local context from our list and release it. */
if (!g->local_list)
BUG ();
else if (g->local_list == ctrl->d_local[i])
g->local_list = ctrl->d_local[i]->next_local;
else
{
struct daemon_local_s *sl;
for (sl=g->local_list; sl->next_local; sl = sl->next_local)
if (sl->next_local == ctrl->d_local[i])
break;
if (!sl->next_local)
BUG ();
sl->next_local = ctrl->d_local[i]->next_local;
}
xfree (ctrl->d_local[i]);
ctrl->d_local[i] = NULL;
}
rc = npth_mutex_unlock (&start_daemon_lock);
if (rc)
log_error ("failed to release the start_daemon lock: %s\n", strerror (rc));
}
assuan_context_t
daemon_type_ctx (enum daemon_type type, ctrl_t ctrl)
{
return ctrl->d_local[type]->ctx;
}

View File

@ -17,6 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
@ -88,544 +89,26 @@ struct inq_needpin_parm_s
};
/* To keep track of all active SCD contexts, we keep a linked list
anchored at this variable. */
static struct scd_local_s *scd_local_list;
/* A Mutex used inside the start_scd function. */
static npth_mutex_t start_scd_lock;
/* A malloced string with the name of the socket to be used for
additional connections. May be NULL if not provided by
SCdaemon. */
static char *socket_name;
/* The context of the primary connection. This is also used as a flag
to indicate whether the scdaemon has been started. */
static assuan_context_t primary_scd_ctx;
/* To allow reuse of the primary connection, the following flag is set
to true if the primary context has been reset and is not in use by
any connection. */
static int primary_scd_ctx_reusable;
/* Local prototypes. */
/* This function must be called once to initialize this module. This
has to be done before a second thread is spawned. We can't do the
static initialization because NPth emulation code might not be able
to do a static init; in particular, it is not possible for W32. */
void
initialize_module_call_scd (void)
{
static int initialized;
int err;
if (!initialized)
{
err = npth_mutex_init (&start_scd_lock, NULL);
if (err)
log_fatal ("error initializing mutex: %s\n", strerror (err));
initialized = 1;
}
}
/* This function may be called to print information pertaining to the
current state of this module to the log. */
void
agent_scd_dump_state (void)
{
log_info ("agent_scd_dump_state: primary_scd_ctx=%p pid=%ld reusable=%d\n",
primary_scd_ctx,
(long)assuan_get_pid (primary_scd_ctx),
primary_scd_ctx_reusable);
if (socket_name)
log_info ("agent_scd_dump_state: socket='%s'\n", socket_name);
}
/* The unlock_scd function shall be called after having accessed the
SCD. It is currently not very useful but gives an opportunity to
keep track of connections currently calling SCD. Note that the
"lock" operation is done by the start_scd() function which must be
called and error checked before any SCD operation. CTRL is the
usual connection context and RC the error code to be passed trhough
the function. */
static int
unlock_scd (ctrl_t ctrl, int rc)
{
int err;
if (ctrl->scd_local->in_use == 0)
{
log_error ("unlock_scd: CTX is not in use\n");
if (!rc)
rc = gpg_error (GPG_ERR_INTERNAL);
}
err = npth_mutex_lock (&start_scd_lock);
if (err)
{
log_error ("failed to acquire the start_scd lock: %s\n", strerror (err));
return gpg_error (GPG_ERR_INTERNAL);
}
ctrl->scd_local->in_use = 0;
if (ctrl->scd_local->invalid)
{
assuan_release (ctrl->scd_local->ctx);
ctrl->scd_local->ctx = NULL;
ctrl->scd_local->invalid = 0;
}
err = npth_mutex_unlock (&start_scd_lock);
if (err)
{
log_error ("failed to release the start_scd lock: %s\n", strerror (err));
return gpg_error (GPG_ERR_INTERNAL);
}
return rc;
}
/* To make sure we leave no secrets in our image after forking of the
scdaemon, we use this callback. */
static void
atfork_cb (void *opaque, int where)
{
(void)opaque;
if (!where)
gcry_control (GCRYCTL_TERM_SECMEM);
}
static void *
wait_child_thread (void *arg)
{
int err;
struct scd_local_s *sl;
#ifdef HAVE_W32_SYSTEM
HANDLE pid = (HANDLE)arg;
npth_unprotect ();
WaitForSingleObject ((HANDLE)pid, INFINITE);
npth_protect ();
log_info ("scdaemon finished\n");
#else
int wstatus;
pid_t pid = (pid_t)(uintptr_t)arg;
again:
npth_unprotect ();
err = waitpid (pid, &wstatus, 0);
npth_protect ();
if (err < 0)
{
if (errno == EINTR)
goto again;
log_error ("waitpid failed: %s\n", strerror (errno));
return NULL;
}
else
{
if (WIFEXITED (wstatus))
log_info ("scdaemon finished (status %d)\n", WEXITSTATUS (wstatus));
else if (WIFSIGNALED (wstatus))
log_info ("scdaemon killed by signal %d\n", WTERMSIG (wstatus));
else
{
if (WIFSTOPPED (wstatus))
log_info ("scdaemon stopped by signal %d\n", WSTOPSIG (wstatus));
goto again;
}
}
#endif
agent_flush_cache (1); /* Flush the PIN cache. */
err = npth_mutex_lock (&start_scd_lock);
if (err)
{
log_error ("failed to acquire the start_scd lock: %s\n",
strerror (err));
}
else
{
assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1);
for (sl = scd_local_list; sl; sl = sl->next_local)
{
sl->invalid = 1;
if (!sl->in_use && sl->ctx)
{
assuan_release (sl->ctx);
sl->ctx = NULL;
}
}
primary_scd_ctx = NULL;
primary_scd_ctx_reusable = 0;
xfree (socket_name);
socket_name = NULL;
err = npth_mutex_unlock (&start_scd_lock);
if (err)
log_error ("failed to release the start_scd lock after waitpid: %s\n",
strerror (err));
}
return NULL;
}
/* Fork off the SCdaemon if this has not already been done. Lock the
daemon and make sure that a proper context has been setup in CTRL.
This function might also lock the daemon, which means that the
caller must call unlock_scd after this function has returned
success and the actual Assuan transaction been done. */
static int
start_scd (ctrl_t ctrl)
{
gpg_error_t err = 0;
const char *pgmname;
assuan_context_t ctx = NULL;
const char *argv[5];
assuan_fd_t no_close_list[3];
int i;
int rc;
char *abs_homedir = NULL;
if (opt.disable_scdaemon)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (ctrl->scd_local && ctrl->scd_local->ctx)
{
ctrl->scd_local->in_use = 1;
return 0; /* Okay, the context is fine. */
}
if (ctrl->scd_local && ctrl->scd_local->in_use)
{
log_error ("start_scd: CTX is in use\n");
return gpg_error (GPG_ERR_INTERNAL);
}
/* We need to serialize the access to scd_local_list and primary_scd_ctx. */
rc = npth_mutex_lock (&start_scd_lock);
if (rc)
{
log_error ("failed to acquire the start_scd lock: %s\n",
strerror (rc));
return gpg_error (GPG_ERR_INTERNAL);
}
/* If this is the first call for this session, setup the local data
structure. */
if (!ctrl->scd_local)
{
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
if (!ctrl->scd_local)
{
err = gpg_error_from_syserror ();
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
return err;
}
ctrl->scd_local->next_local = scd_local_list;
scd_local_list = ctrl->scd_local;
}
ctrl->scd_local->in_use = 1;
/* Check whether the pipe server has already been started and in
this case either reuse a lingering pipe connection or establish a
new socket based one. */
if (primary_scd_ctx && primary_scd_ctx_reusable)
{
ctx = primary_scd_ctx;
primary_scd_ctx_reusable = 0;
if (opt.verbose)
log_info ("new connection to SCdaemon established (reusing)\n");
goto leave;
}
rc = assuan_new (&ctx);
if (rc)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
err = rc;
goto leave;
}
if (socket_name)
{
rc = assuan_socket_connect (ctx, socket_name, 0, 0);
if (rc)
{
log_error ("can't connect to socket '%s': %s\n",
socket_name, gpg_strerror (rc));
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
if (opt.verbose)
log_info ("new connection to SCdaemon established\n");
goto leave;
}
if (primary_scd_ctx)
{
log_info ("SCdaemon is running but won't accept further connections\n");
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
/* Nope, it has not been started. Fire it up now. */
if (opt.verbose)
log_info ("no running SCdaemon - starting it\n");
agent_flush_cache (1); /* Make sure the PIN cache is flushed. */
if (fflush (NULL))
{
#ifndef HAVE_W32_SYSTEM
err = gpg_error_from_syserror ();
#endif
log_error ("error flushing pending output: %s\n", strerror (errno));
/* At least Windows XP fails here with EBADF. According to docs
and Wine an fflush(NULL) is the same as _flushall. However
the Wime implementation does not flush stdin,stdout and stderr
- see above. Lets try to ignore the error. */
#ifndef HAVE_W32_SYSTEM
goto leave;
#endif
}
if (!opt.scdaemon_program || !*opt.scdaemon_program)
opt.scdaemon_program = gnupg_module_name (GNUPG_MODULE_NAME_SCDAEMON);
if ( !(pgmname = strrchr (opt.scdaemon_program, '/')))
pgmname = opt.scdaemon_program;
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--multi-server";
if (gnupg_default_homedir_p ())
argv[2] = NULL;
else
{
abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
if (!abs_homedir)
{
log_error ("error building filename: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
goto leave;
}
argv[2] = "--homedir";
argv[3] = abs_homedir;
argv[4] = NULL;
}
i=0;
if (!opt.running_detached)
{
if (log_get_fd () != -1)
no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
}
no_close_list[i] = ASSUAN_INVALID_FD;
/* Connect to the scdaemon and perform initial handshaking. Use
detached flag so that under Windows SCDAEMON does not show up a
new window. */
rc = assuan_pipe_connect (ctx, opt.scdaemon_program, argv,
no_close_list, atfork_cb, NULL,
ASSUAN_PIPE_CONNECT_DETACHED);
if (rc)
{
log_error ("can't connect to the SCdaemon: %s\n",
gpg_strerror (rc));
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
}
if (opt.verbose)
log_debug ("first connection to SCdaemon established\n");
/* Get the name of the additional socket opened by scdaemon. */
{
membuf_t data;
unsigned char *databuf;
size_t datalen;
xfree (socket_name);
socket_name = NULL;
init_membuf (&data, 256);
assuan_transact (ctx, "GETINFO socket_name",
put_membuf_cb, &data, NULL, NULL, NULL, NULL);
databuf = get_membuf (&data, &datalen);
if (databuf && datalen)
{
socket_name = xtrymalloc (datalen + 1);
if (!socket_name)
log_error ("warning: can't store socket name: %s\n",
strerror (errno));
else
{
memcpy (socket_name, databuf, datalen);
socket_name[datalen] = 0;
if (DBG_IPC)
log_debug ("additional connections at '%s'\n", socket_name);
}
}
xfree (databuf);
}
/* Tell the scdaemon we want him to send us an event signal. We
don't support this for W32CE. */
#ifndef HAVE_W32CE_SYSTEM
if (opt.sigusr2_enabled)
{
char buf[100];
#ifdef HAVE_W32_SYSTEM
snprintf (buf, sizeof buf, "OPTION event-signal=%p",
get_agent_scd_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
assuan_transact (ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL);
}
#endif /*HAVE_W32CE_SYSTEM*/
primary_scd_ctx = ctx;
primary_scd_ctx_reusable = 0;
{
npth_t thread;
npth_attr_t tattr;
pid_t pid;
pid = assuan_get_pid (primary_scd_ctx);
err = npth_attr_init (&tattr);
if (!err)
{
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
err = npth_create (&thread, &tattr, wait_child_thread,
(void *)(uintptr_t)pid);
if (err)
log_error ("error spawning wait_child_thread: %s\n", strerror (err));
npth_attr_destroy (&tattr);
}
}
leave:
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
xfree (abs_homedir);
if (err)
{
unlock_scd (ctrl, err);
if (ctx)
assuan_release (ctx);
}
else
{
ctrl->scd_local->invalid = 0;
ctrl->scd_local->ctx = ctx;
}
return err;
return daemon_start (DAEMON_SCD, ctrl);
}
/* Check whether the SCdaemon is active. This is a fast check without
any locking and might give a wrong result if another thread is about
to start the daemon or the daemon is about to be stopped.. */
int
agent_scd_check_running (void)
static gpg_error_t
unlock_scd (ctrl_t ctrl, gpg_error_t err)
{
return !!primary_scd_ctx;
return daemon_unlock (DAEMON_SCD, ctrl, err);
}
/* Reset the SCD if it has been used. Actually it is not a reset but
a cleanup of resources used by the current connection. */
int
agent_reset_scd (ctrl_t ctrl)
static assuan_context_t
daemon_ctx (ctrl_t ctrl)
{
int err = npth_mutex_lock (&start_scd_lock);
if (err)
{
log_error ("failed to acquire the start_scd lock: %s\n",
strerror (err));
}
else
{
if (ctrl->scd_local)
{
if (ctrl->scd_local->ctx)
{
/* We send a reset and keep that connection for reuse. */
if (ctrl->scd_local->ctx == primary_scd_ctx)
{
/* Send a RESTART to the SCD. This is required for the
primary connection as a kind of virtual EOF; we don't
have another way to tell it that the next command
should be viewed as if a new connection has been
made. For the non-primary connections this is not
needed as we simply close the socket. We don't check
for an error here because the RESTART may fail for
example if the scdaemon has already been terminated.
Anyway, we need to set the reusable flag to make sure
that the aliveness check can clean it up. */
assuan_transact (primary_scd_ctx, "RESTART",
NULL, NULL, NULL, NULL, NULL, NULL);
primary_scd_ctx_reusable = 1;
}
else
assuan_release (ctrl->scd_local->ctx);
ctrl->scd_local->ctx = NULL;
}
/* Remove the local context from our list and release it. */
if (!scd_local_list)
BUG ();
else if (scd_local_list == ctrl->scd_local)
scd_local_list = ctrl->scd_local->next_local;
else
{
struct scd_local_s *sl;
for (sl=scd_local_list; sl->next_local; sl = sl->next_local)
if (sl->next_local == ctrl->scd_local)
break;
if (!sl->next_local)
BUG ();
sl->next_local = ctrl->scd_local->next_local;
}
xfree (ctrl->scd_local);
ctrl->scd_local = NULL;
}
err = npth_mutex_unlock (&start_scd_lock);
if (err)
log_error ("failed to release the start_scd lock: %s\n", strerror (err));
}
return 0;
return daemon_type_ctx (DAEMON_SCD, ctrl);
}
@ -796,7 +279,7 @@ agent_card_learn (ctrl_t ctrl,
parm.certinfo_cb_arg = certinfo_cb_arg;
parm.sinfo_cb = sinfo_cb;
parm.sinfo_cb_arg = sinfo_cb_arg;
rc = assuan_transact (ctrl->scd_local->ctx, "LEARN --force",
rc = assuan_transact (daemon_ctx (ctrl), "LEARN --force",
NULL, NULL, NULL, NULL,
learn_status_cb, &parm);
if (rc)
@ -862,7 +345,7 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno, const char *demand)
else
snprintf (line, DIM(line), "SERIALNO --demand=%s", demand);
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
NULL, NULL, NULL, NULL,
get_serialno_cb, &serialno);
if (rc)
@ -1011,13 +494,13 @@ agent_card_pksign (ctrl_t ctrl,
bin2hex (indata, indatalen, stpcpy (line, "SETDATA "));
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
NULL, NULL, NULL, NULL, pincache_put_cb, NULL);
if (rc)
return unlock_scd (ctrl, rc);
init_membuf (&data, 1024);
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.ctx = daemon_ctx (ctrl);
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.getpin_cb_desc = desc_text;
@ -1030,7 +513,7 @@ agent_card_pksign (ctrl_t ctrl,
else
snprintf (line, sizeof line, "PKSIGN %s %s",
hash_algo_option (mdalgo), keyid);
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
put_membuf_cb, &data,
inq_needpin, &inqparm,
pincache_put_cb, NULL);
@ -1108,14 +591,14 @@ agent_card_pkdecrypt (ctrl_t ctrl,
sprintf (p, "%02X", indata[len]);
p += 2;
}
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_scd (ctrl, rc);
}
init_membuf (&data, 1024);
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.ctx = daemon_ctx (ctrl);
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.getpin_cb_desc = desc_text;
@ -1123,7 +606,7 @@ agent_card_pkdecrypt (ctrl_t ctrl,
inqparm.keydata = NULL;
inqparm.keydatalen = 0;
snprintf (line, DIM(line), "PKDECRYPT %s", keyid);
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
put_membuf_cb, &data,
inq_needpin, &inqparm,
padding_info_cb, r_padding);
@ -1159,7 +642,7 @@ agent_card_readcert (ctrl_t ctrl,
init_membuf (&data, 1024);
snprintf (line, DIM(line), "READCERT %s", id);
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
put_membuf_cb, &data,
NULL, NULL,
pincache_put_cb, NULL);
@ -1251,7 +734,7 @@ agent_card_readkey (ctrl_t ctrl, const char *id,
init_membuf (&data, 1024);
snprintf (line, DIM(line), "READKEY%s -- %s",
r_keyref? " --info":"", id);
rc = assuan_transact (ctrl->scd_local->ctx, line,
rc = assuan_transact (daemon_ctx (ctrl), line,
put_membuf_cb, &data,
NULL, NULL,
readkey_status_cb, &parm);
@ -1318,7 +801,7 @@ agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
return err;
snprintf (line, DIM(line), "WRITEKEY %s%s", force ? "--force " : "", keyref);
parms.ctx = ctrl->scd_local->ctx;
parms.ctx = daemon_ctx (ctrl);
parms.getpin_cb = getpin_cb;
parms.getpin_cb_arg = getpin_cb_arg;
parms.getpin_cb_desc= NULL;
@ -1326,7 +809,7 @@ agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
parms.keydata = keydata;
parms.keydatalen = keydatalen;
err = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
err = assuan_transact (daemon_ctx (ctrl), line, NULL, NULL,
inq_writekey_parms, &parms,
pincache_put_cb, NULL);
return unlock_scd (ctrl, err);
@ -1406,7 +889,7 @@ agent_card_getattr (ctrl_t ctrl, const char *name, char **result,
if (err)
return err;
err = assuan_transact (ctrl->scd_local->ctx, line,
err = assuan_transact (daemon_ctx (ctrl), line,
NULL, NULL, NULL, NULL,
card_getattr_cb, &parm);
if (!err && parm.error)
@ -1577,7 +1060,7 @@ agent_card_keyinfo (ctrl_t ctrl, const char *keygrip, int cap,
if (err)
return err;
err = assuan_transact (ctrl->scd_local->ctx, line,
err = assuan_transact (daemon_ctx (ctrl), line,
NULL, NULL, NULL, NULL,
card_keyinfo_cb, &parm);
if (!err && parm.error)
@ -1656,7 +1139,7 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
if (rc)
return rc;
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.ctx = daemon_ctx (ctrl);
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.getpin_cb_desc = NULL;
@ -1664,14 +1147,14 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
inqparm.keydata = NULL;
inqparm.keydatalen = 0;
saveflag = assuan_get_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS);
assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, 1);
rc = assuan_transact (ctrl->scd_local->ctx, cmdline,
saveflag = assuan_get_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS);
assuan_set_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS, 1);
rc = assuan_transact (daemon_ctx (ctrl), cmdline,
pass_data_thru, assuan_context,
inq_needpin, &inqparm,
pass_status_thru, assuan_context);
assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, saveflag);
assuan_set_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS, saveflag);
if (rc)
{
return unlock_scd (ctrl, rc);
@ -1679,13 +1162,3 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
return unlock_scd (ctrl, 0);
}
void
agent_card_killscd (void)
{
if (primary_scd_ctx == NULL)
return;
assuan_transact (primary_scd_ctx, "KILLSCD",
NULL, NULL, NULL, NULL, NULL, NULL);
agent_flush_cache (1); /* Flush the PIN cache. */
}

View File

@ -2476,7 +2476,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
reader - this should be allowed even without being listed in
sshcontrol. */
if (!opt.disable_scdaemon)
if (!opt.disable_daemon[DAEMON_SCD])
{
char *serialno;
struct card_key_info_s *keyinfo_list;
@ -3610,8 +3610,8 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
es_ungetc (c, stream_sock);
}
/* Reset the SCD in case it has been used. */
agent_reset_scd (ctrl);
/* Reset the daemon in case it has been used. */
agent_reset_daemon (ctrl);
out:
@ -3758,8 +3758,8 @@ serve_mmapped_ssh_request (ctrl_t ctrl,
valid_response = 1;
}
/* Reset the SCD in case it has been used. */
agent_reset_scd (ctrl);
/* Reset the daemon in case it has been used. */
agent_reset_daemon (ctrl);
return valid_response? 0 : -1;
}

View File

@ -3257,7 +3257,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
}
else if (!strcmp (line, "scd_running"))
{
rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_FALSE);
rc = agent_daemon_check_running (DAEMON_SCD)? 0:gpg_error (GPG_ERR_FALSE);
}
else if (!strcmp (line, "std_env_names"))
{
@ -3747,7 +3747,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
clear_nonce_cache (ctrl);
/* Reset the SCD if needed. */
agent_reset_scd (ctrl);
agent_reset_daemon (ctrl);
/* Reset the pinentry (in case of popup messages). */
agent_reset_query (ctrl);

View File

@ -845,7 +845,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
xfree (opt.pinentry_invisible_char);
opt.pinentry_invisible_char = NULL;
opt.pinentry_timeout = 0;
opt.scdaemon_program = NULL;
memset (opt.daemon_program, 0, sizeof opt.daemon_program);
opt.def_cache_ttl = DEFAULT_CACHE_TTL;
opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
opt.max_cache_ttl = MAX_CACHE_TTL;
@ -862,7 +862,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.allow_external_cache = 1;
opt.allow_loopback_pinentry = 1;
opt.allow_emacs_pinentry = 0;
opt.disable_scdaemon = 0;
memset (opt.disable_daemon, 0, sizeof opt.disable_daemon);
disable_check_own_socket = 0;
/* Note: When changing the next line, change also gpgconf_list. */
opt.ssh_fingerprint_digest = GCRY_MD_MD5;
@ -905,8 +905,8 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
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 oScdaemonProgram: opt.daemon_program[DAEMON_SCD] = pargs->r.ret_str; break;
case oDisableScdaemon: opt.disable_daemon[DAEMON_SCD] = 1; break;
case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
@ -1020,7 +1020,7 @@ initialize_modules (void)
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
initialize_module_cache ();
initialize_module_call_pinentry ();
initialize_module_call_scd ();
initialize_module_daemon ();
initialize_module_trustlist ();
}
@ -2064,7 +2064,7 @@ get_agent_active_connection_count (void)
event. */
#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
void *
get_agent_scd_notify_event (void)
get_agent_daemon_notify_event (void)
{
static HANDLE the_event = INVALID_HANDLE_VALUE;
@ -2403,8 +2403,8 @@ agent_sighup_action (void)
"pinentry-basic" fallback was in use. */
gnupg_module_name_flush_some ();
if (opt.disable_scdaemon)
agent_card_killscd ();
if (opt.disable_daemon[DAEMON_SCD])
agent_kill_daemon (DAEMON_SCD);
}
@ -2438,7 +2438,7 @@ handle_signal (int signo)
logging system. */
/* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
agent_query_dump_state ();
agent_scd_dump_state ();
agent_daemon_dump_state ();
break;
case SIGUSR2:
@ -2841,7 +2841,7 @@ handle_connections (gnupg_fd_t listen_fd,
sigs = 0;
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
# else
events[0] = get_agent_scd_notify_event ();
events[0] = get_agent_daemon_notify_event ();
events[1] = INVALID_HANDLE_VALUE;
# endif
#endif