aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h3
-rw-r--r--agent/cache.c358
-rw-r--r--agent/call-daemon.c51
-rw-r--r--agent/call-pinentry.c44
-rw-r--r--agent/command-ssh.c4
-rw-r--r--agent/genkey.c18
-rw-r--r--agent/gpg-agent.c453
-rw-r--r--agent/trustlist.c14
8 files changed, 601 insertions, 344 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 531fad210..3bedab121 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -411,6 +411,7 @@ void *get_agent_daemon_notify_event (void);
#endif
void agent_sighup_action (void);
int map_pk_openpgp_to_gcry (int openpgp_algo);
+void agent_kick_the_loop (void);
/*-- command.c --*/
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
@@ -514,7 +515,7 @@ int agent_clear_passphrase (ctrl_t ctrl,
/*-- cache.c --*/
void initialize_module_cache (void);
void deinitialize_module_cache (void);
-void agent_cache_housekeeping (void);
+struct timespec *agent_cache_expiration (void);
void agent_flush_cache (int pincache_only);
int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl);
diff --git a/agent/cache.c b/agent/cache.c
index 7616dafc1..e8544205f 100644
--- a/agent/cache.c
+++ b/agent/cache.c
@@ -53,8 +53,20 @@ struct secret_data_s {
char data[1]; /* A string. */
};
-/* The cache object. */
+/* The type of cache object. */
typedef struct cache_item_s *ITEM;
+
+/* The timer entry in a linked list. */
+struct timer_s {
+ ITEM next;
+ int tv_sec;
+ int reason;
+};
+#define CACHE_EXPIRE_UNUSED 0
+#define CACHE_EXPIRE_LAST_ACCESS 1
+#define CACHE_EXPIRE_CREATION 2
+
+/* The cache object. */
struct cache_item_s {
ITEM next;
time_t created;
@@ -63,12 +75,18 @@ struct cache_item_s {
struct secret_data_s *pw;
cache_mode_t cache_mode;
int restricted; /* The value of ctrl->restricted is part of the key. */
+ struct timer_s t;
char key[1];
};
/* The cache himself. */
static ITEM thecache;
+/* The timer list of expiration, in active. */
+static ITEM the_timer_list;
+/* Newly created entries, to be inserted into the timer list. */
+static ITEM the_timer_list_new;
+
/* NULL or the last cache key stored by agent_store_cache_hit. */
static char *last_stored_cache_key;
@@ -193,100 +211,302 @@ new_data (const char *string, struct secret_data_s **r_data)
}
+static void
+insert_to_timer_list_new (ITEM entry)
+{
+ entry->t.next = the_timer_list_new;
+ the_timer_list_new = entry;
+}
-/* Check whether there are items to expire. */
+/* Insert to the active timer list. */
static void
-housekeeping (void)
+insert_to_timer_list (struct timespec *ts, ITEM entry)
{
- ITEM r, rprev;
- time_t current = gnupg_get_time ();
+ ITEM e, eprev;
- /* First expire the actual data */
- for (r=thecache; r; r = r->next)
+ if (!the_timer_list || ts->tv_sec >= entry->t.tv_sec)
{
- if (r->cache_mode == CACHE_MODE_PIN)
- ; /* Don't let it expire - scdaemon explicitly flushes them. */
- else if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
+ if (the_timer_list)
{
- if (DBG_CACHE)
- log_debug (" expired '%s'.%d (%ds after last access)\n",
- r->key, r->restricted, r->ttl);
- release_data (r->pw);
- r->pw = NULL;
- r->accessed = current;
+ the_timer_list->t.tv_sec += ts->tv_sec - entry->t.tv_sec;
+ if (ts->tv_nsec >= 500000000)
+ the_timer_list->t.tv_sec++;
}
+
+ ts->tv_sec = entry->t.tv_sec;
+ ts->tv_nsec = 0;
+
+ entry->t.tv_sec = 0;
+ entry->t.next = the_timer_list;
+ the_timer_list = entry;
+ return;
}
- /* Second, make sure that we also remove them based on the created
- * stamp so that the user has to enter it from time to time. We
- * don't do this for data items which are used to storage secrets in
- * meory and are not user entered passphrases etc. */
- for (r=thecache; r; r = r->next)
+ entry->t.tv_sec -= ts->tv_sec;
+ eprev = NULL;
+ for (e = the_timer_list; e; e = e->t.next)
{
- unsigned long maxttl;
+ if (e->t.tv_sec > entry->t.tv_sec)
+ break;
- switch (r->cache_mode)
- {
- case CACHE_MODE_DATA:
- case CACHE_MODE_PIN:
- continue; /* No MAX TTL here. */
- case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
- default: maxttl = opt.max_cache_ttl; break;
- }
- if (r->pw && r->created + maxttl < current)
- {
- if (DBG_CACHE)
- log_debug (" expired '%s'.%d (%lus after creation)\n",
- r->key, r->restricted, opt.max_cache_ttl);
- release_data (r->pw);
- r->pw = NULL;
- r->accessed = current;
- }
+ eprev = e;
+ entry->t.tv_sec -= e->t.tv_sec;
+ }
+
+ entry->t.next = e;
+ if (e)
+ e->t.tv_sec -= entry->t.tv_sec;
+
+ if (eprev)
+ eprev->t.next = entry;
+ else
+ the_timer_list = entry;
+}
+
+static void
+remove_from_timer_list (ITEM entry)
+{
+ ITEM e, eprev;
+
+ eprev = NULL;
+ for (e = the_timer_list; e; e = e->t.next)
+ if (e != entry)
+ eprev = e;
+ else
+ {
+ if (e->t.next)
+ e->t.next->t.tv_sec += e->t.tv_sec;
+
+ if (eprev)
+ eprev->t.next = e->t.next;
+ else
+ the_timer_list = e->t.next;
+
+ break;
+ }
+
+ entry->t.next = NULL;
+ entry->t.tv_sec = 0;
+}
+
+static void
+remove_from_timer_list_new (ITEM entry)
+{
+ ITEM e, eprev;
+
+ eprev = NULL;
+ for (e = the_timer_list_new; e; e = e->t.next)
+ if (e != entry)
+ eprev = e;
+ else
+ {
+ if (eprev)
+ eprev->t.next = e->t.next;
+ else
+ the_timer_list_new = e->t.next;
+
+ break;
+ }
+
+ entry->t.next = NULL;
+ entry->t.tv_sec = 0;
+}
+
+static int
+compute_expiration (ITEM r)
+{
+ unsigned long maxttl;
+ time_t current = gnupg_get_time ();
+ time_t next;
+
+ if (r->cache_mode == CACHE_MODE_PIN)
+ return 0; /* Don't let it expire - scdaemon explicitly flushes them. */
+
+ if (!r->pw)
+ {
+ /* Expire an old and unused entry after 30 minutes. */
+ r->t.tv_sec = 60*30;
+ r->t.reason = CACHE_EXPIRE_UNUSED;
+ return 1;
}
- /* Third, make sure that we don't have too many items in the list.
- * Expire old and unused entries after 30 minutes. */
- for (rprev=NULL, r=thecache; r; )
+ switch (r->cache_mode)
{
- if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
- {
- ITEM r2 = r->next;
- if (DBG_CACHE)
- log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
- r->key, r->restricted, r->cache_mode);
- xfree (r);
- if (!rprev)
- thecache = r2;
- else
- rprev->next = r2;
- r = r2;
- }
- else
+ case CACHE_MODE_DATA:
+ case CACHE_MODE_PIN:
+ maxttl = 0; /* No MAX TTL here. */
+ break;
+ case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
+ default: maxttl = opt.max_cache_ttl; break;
+ }
+
+ if (maxttl)
+ {
+ if (r->created + maxttl < current)
{
- rprev = r;
- r = r->next;
+ r->t.tv_sec = 0;
+ r->t.reason = CACHE_EXPIRE_CREATION;
+ return 1;
}
+
+ next = r->created + maxttl - current;
+ }
+ else
+ next = 0;
+
+ if (r->ttl >= 0 && (next == 0 || r->ttl < next))
+ {
+ r->t.tv_sec = r->ttl;
+ r->t.reason = CACHE_EXPIRE_LAST_ACCESS;
+ return 1;
}
+
+ if (next)
+ {
+ r->t.tv_sec = next;
+ r->t.reason = CACHE_EXPIRE_CREATION;
+ return 1;
+ }
+
+ return 0;
}
+static void
+update_expiration (ITEM entry, int is_new_entry)
+{
+ if (!is_new_entry)
+ {
+ remove_from_timer_list (entry);
+ remove_from_timer_list_new (entry);
+ }
-void
-agent_cache_housekeeping (void)
+ if (compute_expiration (entry))
+ {
+ insert_to_timer_list_new (entry);
+ agent_kick_the_loop ();
+ }
+}
+
+
+/* Expire the cache entry. Returns 1 when the entry should be removed
+ * from the cache. */
+static int
+do_expire (ITEM e)
{
- int res;
+ if (!e->pw)
+ /* Unused entry after 30 minutes. */
+ return 1;
- if (DBG_CACHE)
- log_debug ("agent_cache_housekeeping\n");
+ if (e->t.reason == CACHE_EXPIRE_LAST_ACCESS)
+ {
+ if (DBG_CACHE)
+ log_debug (" expired '%s'.%d (%ds after last access)\n",
+ e->key, e->restricted, e->ttl);
+ }
+ else
+ {
+ if (DBG_CACHE)
+ log_debug (" expired '%s'.%d (%lus after creation)\n",
+ e->key, e->restricted, opt.max_cache_ttl);
+ }
+
+ release_data (e->pw);
+ e->pw = NULL;
+ e->accessed = 0;
+
+ if (compute_expiration (e))
+ insert_to_timer_list_new (e);
+
+ return 0;
+}
+
+
+struct timespec *
+agent_cache_expiration (void)
+{
+ static struct timespec abstime;
+ static struct timespec timeout;
+ struct timespec *tp;
+ struct timespec curtime;
+ int res;
+ int expired = 0;
+ ITEM e, enext;
res = npth_mutex_lock (&cache_lock);
if (res)
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
- housekeeping ();
+ npth_clock_gettime (&curtime);
+ if (the_timer_list)
+ {
+ if (npth_timercmp (&abstime, &curtime, <))
+ expired = 1;
+ else
+ npth_timersub (&abstime, &curtime, &timeout);
+ }
+
+ if (expired && (e = the_timer_list) && e->t.tv_sec == 0)
+ {
+ the_timer_list = e->t.next;
+ e->t.next = NULL;
+
+ if (do_expire (e))
+ {
+ ITEM r, rprev;
+
+ if (DBG_CACHE)
+ log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
+ e->key, e->restricted, e->cache_mode);
+
+ rprev = NULL;
+ for (r = thecache; r; r = r->next)
+ if (r == e)
+ {
+ if (!rprev)
+ thecache = r->next;
+ else
+ rprev->next = r->next;
+ break;
+ }
+ else
+ rprev = r;
+
+ remove_from_timer_list_new (e);
+
+ xfree (e);
+ }
+ }
+
+ if (expired || !the_timer_list)
+ timeout.tv_sec = timeout.tv_nsec = 0;
+
+ for (e = the_timer_list_new; e; e = enext)
+ {
+ enext = e->t.next;
+ e->t.next = NULL;
+ insert_to_timer_list (&timeout, e);
+ }
+ the_timer_list_new = NULL;
+
+ if (!the_timer_list)
+ tp = NULL;
+ else
+ {
+ if (the_timer_list->t.tv_sec != 0)
+ {
+ timeout.tv_sec += the_timer_list->t.tv_sec;
+ the_timer_list->t.tv_sec = 0;
+ }
+
+ npth_timeradd (&timeout, &curtime, &abstime);
+ tp = &timeout;
+ }
res = npth_mutex_unlock (&cache_lock);
if (res)
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
+
+ return tp;
}
@@ -314,6 +534,7 @@ agent_flush_cache (int pincache_only)
release_data (r->pw);
r->pw = NULL;
r->accessed = 0;
+ update_expiration (r, 0);
}
}
@@ -358,7 +579,6 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
if (DBG_CACHE)
log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
key, restricted, cache_mode, ttl);
- housekeeping ();
if (!ttl)
{
@@ -410,6 +630,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
err = new_data (data, &r->pw);
if (err)
log_error ("error replacing cache item: %s\n", gpg_strerror (err));
+ update_expiration (r, 0);
}
}
else if (data) /* Insert. */
@@ -431,6 +652,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
{
r->next = thecache;
thecache = r;
+ update_expiration (r, 1);
}
}
if (err)
@@ -478,7 +700,6 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
key, restricted, cache_mode,
last_stored? " (stored cache key)":"");
- housekeeping ();
for (r=thecache; r; r = r->next)
{
@@ -500,7 +721,10 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
* below. Note also that we don't update the accessed time
* for data items. */
if (r->cache_mode != CACHE_MODE_DATA)
- r->accessed = gnupg_get_time ();
+ {
+ r->accessed = gnupg_get_time ();
+ update_expiration (r, 0);
+ }
if (DBG_CACHE)
log_debug ("... hit\n");
if (r->pw->totallen < 32)
diff --git a/agent/call-daemon.c b/agent/call-daemon.c
index e1c5669e9..806ef5dc1 100644
--- a/agent/call-daemon.c
+++ b/agent/call-daemon.c
@@ -98,7 +98,6 @@ static npth_mutex_t start_daemon_lock;
struct wait_child_thread_parm_s
{
enum daemon_type type;
- pid_t pid;
};
@@ -109,54 +108,14 @@ wait_child_thread (void *arg)
int err;
struct wait_child_thread_parm_s *parm = arg;
enum daemon_type type = parm->type;
- pid_t pid = parm->pid;
-#ifndef HAVE_W32_SYSTEM
- int wstatus;
-#endif
const char *name = opt.daemon_program[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 ();
- /* Note that although we use a pid_t here, it is actually a HANDLE. */
- WaitForSingleObject ((HANDLE)pid, INFINITE);
- npth_protect ();
+ assuan_pipe_wait_server_termination (g->primary_ctx, NULL, 0);
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;
- }
-
- assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1);
- }
-#endif /*!HAVE_W32_SYSTEM*/
agent_flush_cache (1); /* Flush the PIN cache. */
@@ -471,8 +430,8 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
char buf[100];
#ifdef HAVE_W32_SYSTEM
- snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
- (unsigned long)get_agent_daemon_notify_event ());
+ snprintf (buf, sizeof buf, "OPTION event-signal=%p",
+ get_agent_daemon_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
@@ -496,7 +455,6 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
}
wctp->type = type;
- wctp->pid = assuan_get_pid (g->primary_ctx);
err = npth_attr_init (&tattr);
if (!err)
{
@@ -561,10 +519,9 @@ agent_daemon_dump_state (void)
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__,
+ log_info ("%s: name %s primary_ctx=%p 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);
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index d236e1107..4a999ca9a 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -128,8 +128,9 @@ initialize_module_call_pinentry (void)
void
agent_query_dump_state (void)
{
- log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
- entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
+ log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%lx\n",
+ entry_ctx, (long)assuan_get_pid (entry_ctx),
+ (unsigned long)popup_tid);
}
/* Called to make sure that a popup window owned by the current
@@ -1288,8 +1289,6 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
static void *
watch_sock (void *arg)
{
- pid_t pid = assuan_get_pid (entry_ctx);
-
while (1)
{
int err;
@@ -1302,7 +1301,7 @@ watch_sock (void *arg)
FD_ZERO (&fdset);
FD_SET (FD2INT (sock), &fdset);
- err = npth_select (FD2INT (sock)+1, &fdset, NULL, NULL, &timeout);
+ err = npth_select (FD2NUM (sock)+1, &fdset, NULL, NULL, &timeout);
if (err < 0)
{
@@ -1317,17 +1316,7 @@ watch_sock (void *arg)
break;
}
- if (pid == (pid_t)(-1))
- ; /* No pid available can't send a kill. */
-#ifdef HAVE_W32_SYSTEM
- /* Older versions of assuan set PID to 0 on Windows to indicate an
- invalid value. */
- else if (pid != (pid_t) INVALID_HANDLE_VALUE && pid != 0)
- TerminateProcess ((HANDLE)pid, 1);
-#else
- else if (pid > 0)
- kill (pid, SIGINT);
-#endif
+ assuan_pipe_kill_server (entry_ctx);
return NULL;
}
@@ -2124,7 +2113,6 @@ void
agent_popup_message_stop (ctrl_t ctrl)
{
int rc;
- pid_t pid;
(void)ctrl;
@@ -2137,26 +2125,10 @@ agent_popup_message_stop (ctrl_t ctrl)
return;
}
- pid = assuan_get_pid (entry_ctx);
- if (pid == (pid_t)(-1))
- ; /* No pid available can't send a kill. */
- else if (popup_finished)
+ if (popup_finished)
; /* Already finished and ready for joining. */
-#ifdef HAVE_W32_SYSTEM
- /* Older versions of assuan set PID to 0 on Windows to indicate an
- invalid value. */
- else if (pid != (pid_t) INVALID_HANDLE_VALUE
- && pid != 0)
- {
- HANDLE process = (HANDLE) pid;
-
- /* Arbitrary error code. */
- TerminateProcess (process, 1);
- }
-#else
- else if (pid > 0)
- kill (pid, SIGINT);
-#endif
+ else
+ assuan_pipe_kill_server (entry_ctx);
/* Now wait for the thread to terminate. */
rc = npth_join (popup_tid, NULL);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index ca3993321..0afa24111 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -3952,7 +3952,11 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
es_syshd_t syshd;
syshd.type = ES_SYSHD_SOCK;
+#ifdef HAVE_SOCKET
+ syshd.u.sock = (SOCKET)sock_client;
+#else
syshd.u.sock = sock_client;
+#endif
get_client_info (sock_client, &peer_info);
ctrl->client_pid = peer_info.pid;
diff --git a/agent/genkey.c b/agent/genkey.c
index 741c05f4f..cf37cdafc 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -100,7 +100,7 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
estream_t stream_to_check_pattern = NULL;
const char *argv[10];
- pid_t pid;
+ gnupg_process_t proc;
int result, i;
const char *pattern;
char *patternfname;
@@ -143,11 +143,17 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
argv[i] = NULL;
log_assert (i < sizeof argv);
- if (gnupg_spawn_process (pgmname, argv, NULL, 0,
- &stream_to_check_pattern, NULL, NULL, &pid))
+ if (gnupg_process_spawn (pgmname, argv,
+ GNUPG_PROCESS_STDIN_PIPE,
+ NULL, NULL, &proc))
result = 1; /* Execute error - assume password should no be used. */
else
{
+ int status;
+
+ gnupg_process_get_streams (proc, 0, &stream_to_check_pattern,
+ NULL, NULL);
+
es_set_binary (stream_to_check_pattern);
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
{
@@ -158,11 +164,13 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
else
es_fflush (stream_to_check_pattern);
es_fclose (stream_to_check_pattern);
- if (gnupg_wait_process (pgmname, pid, 1, NULL))
+ gnupg_process_wait (proc, 1);
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
+ if (status)
result = 1; /* Helper returned an error - probably a match. */
else
result = 0; /* Success; i.e. no match. */
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
xfree (patternfname);
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 1db422737..b7863cbbe 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -341,15 +341,13 @@ static struct debug_flags_s debug_flags [] =
#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.
- * 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. */
-#define TIMERTICK_INTERVAL (4)
+/* 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.
+ * Values is in seconds. */
#define CHECK_OWN_SOCKET_INTERVAL (60)
-
+/* CHECK_PROBLEMS_INTERFAL defines how often we check the existence of
+ * parent process and homedir. Value is in seconds. */
+#define CHECK_PROBLEMS_INTERVAL (4)
/* Flag indicating that the ssh-agent subsystem has been enabled. */
static int ssh_support;
@@ -384,9 +382,6 @@ static int startup_signal_mask_valid;
/* 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;
@@ -396,6 +391,12 @@ static int is_supervised;
/* Flag indicating to start the daemon even if one already runs. */
static int steal_socket;
+/* Flag to monitor problems. */
+static int problem_detected;
+#define AGENT_PROBLEM_SOCKET_TAKEOVER (1 << 0)
+#define AGENT_PROBLEM_PARENT_HAS_GONE (1 << 1)
+#define AGENT_PROBLEM_HOMEDIR_REMOVED (1 << 2)
+
/* Flag to inhibit socket removal in cleanup. */
static int inhibit_socket_removal;
@@ -432,6 +433,17 @@ static assuan_sock_nonce_t socket_nonce_ssh;
* Let's try this as default. Change at runtime with --listen-backlog. */
static int listen_backlog = 64;
+#ifdef HAVE_W32_SYSTEM
+/* The event to break the select call. */
+static HANDLE the_event2;
+#elif defined(HAVE_PSELECT_NO_EINTR)
+/* An FD to break the select call. */
+static int event_pipe_fd;
+#else
+/* PID of the main thread. */
+static pid_t main_thread_pid;
+#endif
+
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@@ -452,9 +464,14 @@ static const char *debug_level;
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. */
+#ifdef HAVE_W32_SYSTEM
+#define HAVE_PARENT_PID_SUPPORT 0
+#else
+#define HAVE_PARENT_PID_SUPPORT 1
+#endif
+/* The check_others_thread() 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
@@ -517,12 +534,11 @@ 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;
-
+#if CHECK_OWN_SOCKET_INTERVAL > 0
+static void *check_own_socket_thread (void *arg);
+#endif
+static void *check_others_thread (void *arg);
/*
Functions.
@@ -1046,6 +1062,7 @@ thread_init_once (void)
* initialized and thus Libgcrypt could not set its system call
* clamp. */
gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
+ assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
}
@@ -1053,7 +1070,6 @@ static void
initialize_modules (void)
{
thread_init_once ();
- assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
initialize_module_cache ();
initialize_module_call_pinentry ();
initialize_module_daemon ();
@@ -1113,7 +1129,6 @@ main (int argc, char **argv)
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 ();
@@ -2134,39 +2149,45 @@ get_agent_active_connection_count (void)
notification event. Calling it the first time creates that
event. */
#if defined(HAVE_W32_SYSTEM)
+static void *
+create_an_event (void)
+{
+ 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 an event: %s\n", w32_strerror (-1) );
+ else if (!DuplicateHandle (GetCurrentProcess(), h,
+ GetCurrentProcess(), &h2,
+ EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
+ {
+ log_error ("setting synchronize for an event failed: %s\n",
+ w32_strerror (-1) );
+ CloseHandle (h);
+ }
+ else
+ {
+ CloseHandle (h);
+ return h2;
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
void *
get_agent_daemon_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 synchronize for scd notify event failed: %s\n",
- w32_strerror (-1) );
- CloseHandle (h);
- }
- else
- {
- CloseHandle (h);
- the_event = h2;
- }
- }
+ the_event = create_an_event ();
return the_event;
}
@@ -2423,57 +2444,6 @@ create_directories (void)
}
-
-/* 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);
-
- /* 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", gpgrt_strusage(11), gpgrt_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
-
- /* Need to check for expired cache entries. */
- agent_cache_housekeeping ();
-
- /* Check whether the homedir is still available. */
- if (!shutdown_pending
- && (!have_homedir_inotify || !reliable_homedir_inotify)
- && gnupg_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
@@ -2532,6 +2502,11 @@ handle_signal (int signo)
agent_sigusr2_action ();
break;
+ case SIGCONT:
+ /* Do nothing, but break the syscall. */
+ log_debug ("SIGCONT received - breaking select\n");
+ break;
+
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
@@ -2569,7 +2544,7 @@ 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));
+ FD_DBG (ctrl->thread_startup.fd), strerror (errno));
assuan_sock_close (ctrl->thread_startup.fd);
xfree (ctrl);
return -1;
@@ -2869,12 +2844,12 @@ do_start_connection_thread (ctrl_t ctrl)
agent_init_default_ctrl (ctrl);
if (opt.verbose > 1 && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d started\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ (unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
if (opt.verbose > 1 && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d terminated\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ (unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -2949,12 +2924,12 @@ start_connection_thread_ssh (void *arg)
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));
+ (unsigned long) npth_self(), FD_DBG (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));
+ (unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -2963,6 +2938,28 @@ start_connection_thread_ssh (void *arg)
}
+void
+agent_kick_the_loop (void)
+{
+ /* Kick the select loop. */
+#ifdef HAVE_W32_SYSTEM
+ int ret = SetEvent (the_event2);
+ if (ret == 0)
+ log_error ("SetEvent for agent_kick_the_loop failed: %s\n",
+ w32_strerror (-1));
+#else
+# ifdef HAVE_PSELECT_NO_EINTR
+ write (event_pipe_fd, "", 1);
+# else
+ int ret = kill (main_thread_pid, SIGCONT);
+ if (ret < 0)
+ log_error ("sending signal for agent_kick_the_loop failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+# endif
+#endif
+}
+
+
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
@@ -2980,12 +2977,15 @@ handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t fd;
int nfd;
int saved_errno;
- struct timespec abstime;
- struct timespec curtime;
- struct timespec timeout;
+ struct timespec *tp;
#ifdef HAVE_W32_SYSTEM
- HANDLE events[2];
+ HANDLE events[3];
unsigned int events_set;
+#else
+ int signo;
+# ifdef HAVE_PSELECT_NO_EINTR
+ int pipe_fd[2];
+# endif
#endif
int sock_inotify_fd = -1;
int home_inotify_fd = -1;
@@ -3013,11 +3013,24 @@ handle_connections (gnupg_fd_t listen_fd,
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
+ npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
+# ifdef HAVE_PSELECT_NO_EINTR
+ ret = gnupg_create_pipe (pipe_fd);
+ if (ret)
+ {
+ log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
+ return;
+ }
+ event_pipe_fd = pipe_fd[1];
+# else
+ main_thread_pid = getpid ();
+# endif
#else
events[0] = get_agent_daemon_notify_event ();
- events[1] = INVALID_HANDLE_VALUE;
+ events[1] = the_event2 = create_an_event ();
+ events[2] = INVALID_HANDLE_VALUE;
#endif
if (disable_check_own_socket)
@@ -3041,6 +3054,27 @@ handle_connections (gnupg_fd_t listen_fd,
else
have_homedir_inotify = 1;
+#if CHECK_OWN_SOCKET_INTERVAL > 0
+ if (!disable_check_own_socket && sock_inotify_fd == -1)
+ {
+ npth_t thread;
+
+ err = npth_create (&thread, &tattr, check_own_socket_thread, NULL);
+ if (err)
+ log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
+ }
+#endif
+
+ if ((HAVE_PARENT_PID_SUPPORT && parent_pid != (pid_t)(-1))
+ || (!have_homedir_inotify || !reliable_homedir_inotify))
+ {
+ npth_t thread;
+
+ err = npth_create (&thread, &tattr, check_others_thread, NULL);
+ if (err)
+ log_error ("error spawning check_others_thread: %s\n", strerror (err));
+ }
+
/* 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). */
@@ -3070,24 +3104,24 @@ handle_connections (gnupg_fd_t listen_fd,
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
- nfd = FD2INT (listen_fd);
+ nfd = FD2NUM (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);
+ nfd = FD2NUM (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);
+ nfd = FD2NUM (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);
+ nfd = FD2NUM (listen_fd_ssh);
}
if (sock_inotify_fd != -1)
{
@@ -3107,15 +3141,12 @@ handle_connections (gnupg_fd_t listen_fd,
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)
+ if (active_connections == 0 || is_supervised)
break; /* ready */
/* Do not accept new connections but keep on running the
@@ -3144,28 +3175,23 @@ handle_connections (gnupg_fd_t listen_fd,
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);
+#ifdef HAVE_PSELECT_NO_EINTR
+ FD_SET (pipe_fd[0], &read_fdset);
+ if (nfd < pipe_fd[0])
+ nfd = pipe_fd[0];
+#endif
+
+ tp = agent_cache_expiration ();
#ifndef HAVE_W32_SYSTEM
- ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+ ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, tp,
npth_sigev_sigmask ());
saved_errno = errno;
- {
- int signo;
- while (npth_sigev_get_pending (&signo))
- handle_signal (signo);
- }
+ while (npth_sigev_get_pending (&signo))
+ handle_signal (signo);
#else
- ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+ ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, tp,
events, &events_set);
saved_errno = errno;
@@ -3181,11 +3207,47 @@ handle_connections (gnupg_fd_t listen_fd,
gnupg_sleep (1);
continue;
}
+
+#ifndef HAVE_W32_SYSTEM
+ if ((problem_detected & AGENT_PROBLEM_PARENT_HAS_GONE))
+ {
+ shutdown_pending = 2;
+ log_info ("parent process died - shutting down\n");
+ log_info ("%s %s stopped\n", gpgrt_strusage(11), gpgrt_strusage(13));
+ cleanup ();
+ agent_exit (0);
+ }
+#endif
+
+ if ((problem_detected & AGENT_PROBLEM_SOCKET_TAKEOVER))
+ {
+ /* 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");
+ }
+
+ if ((problem_detected & AGENT_PROBLEM_HOMEDIR_REMOVED))
+ {
+ shutdown_pending = 1;
+ log_info ("homedir has been removed - shutting down\n");
+ }
+
if (ret <= 0)
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
+#ifdef HAVE_PSELECT_NO_EINTR
+ if (FD_ISSET (pipe_fd[0], &read_fdset))
+ {
+ char buf[256];
+
+ read (pipe_fd[0], buf, sizeof buf);
+ }
+#endif
+
/* 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. */
@@ -3193,7 +3255,10 @@ handle_connections (gnupg_fd_t listen_fd,
&& FD_ISSET (sock_inotify_fd, &read_fdset)
&& gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
{
- shutdown_pending = 1;
+ /* We may not remove the socket (if any), as it may be now
+ in use by another server. */
+ inhibit_socket_removal = 1;
+ shutdown_pending = 2;
close (sock_inotify_fd);
sock_inotify_fd = -1;
log_info ("socket file has been removed - shutting down\n");
@@ -3222,8 +3287,8 @@ handle_connections (gnupg_fd_t listen_fd,
continue;
plen = sizeof paddr;
- fd = INT2FD (npth_accept (FD2INT(listentbl[idx].l_fd),
- (struct sockaddr *)&paddr, &plen));
+ fd = assuan_sock_accept (listentbl[idx].l_fd,
+ (struct sockaddr *)&paddr, &plen);
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed for %s: %s\n",
@@ -3263,13 +3328,21 @@ handle_connections (gnupg_fd_t listen_fd,
close (sock_inotify_fd);
if (home_inotify_fd != -1)
close (home_inotify_fd);
+#ifdef HAVE_W32_SYSTEM
+ if (the_event2 != INVALID_HANDLE_VALUE)
+ CloseHandle (the_event2);
+#endif
+#ifdef HAVE_PSELECT_NO_EINTR
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
+#endif
cleanup ();
log_info (_("%s %s stopped\n"), gpgrt_strusage(11), gpgrt_strusage(13));
npth_attr_destroy (&tattr);
}
-
+#if CHECK_OWN_SOCKET_INTERVAL > 0
/* Helper for check_own_socket. */
static gpg_error_t
check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
@@ -3280,20 +3353,18 @@ check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
}
-/* 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)
+/* 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 int
+do_check_own_socket (const char *sockname)
{
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)
{
@@ -3331,58 +3402,78 @@ check_own_socket_thread (void *arg)
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;
-}
+ return rc;
+}
-/* 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)
+/* The thread running the actual check. */
+static void *
+check_own_socket_thread (void *arg)
{
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. */
+ (void)arg;
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
if (!sockname)
- return; /* Out of memory. */
+ return NULL; /* Out of memory. */
- err = npth_attr_init (&tattr);
- if (err)
+ while (!problem_detected)
{
- xfree (sockname);
- return;
+ if (shutdown_pending)
+ goto leave;
+
+ gnupg_sleep (CHECK_OWN_SOCKET_INTERVAL);
+
+ if (do_check_own_socket (sockname))
+ problem_detected |= AGENT_PROBLEM_SOCKET_TAKEOVER;
}
- 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);
+
+ agent_kick_the_loop ();
+
+ leave:
+ xfree (sockname);
+ return NULL;
}
+#endif
+
+/* The thread running other checks. */
+static void *
+check_others_thread (void *arg)
+{
+ const char *homedir = gnupg_homedir ();
+
+ (void)arg;
+ while (!problem_detected)
+ {
+ struct stat statbuf;
+ if (shutdown_pending)
+ goto leave;
+
+ gnupg_sleep (CHECK_PROBLEMS_INTERVAL);
+
+ /* 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) && kill (parent_pid, 0))
+ problem_detected |= AGENT_PROBLEM_PARENT_HAS_GONE;
+#endif /*HAVE_W32_SYSTEM*/
+
+ /* Check whether the homedir is still available. */
+ if ((!have_homedir_inotify || !reliable_homedir_inotify)
+ && gnupg_stat (homedir, &statbuf) && errno == ENOENT)
+ problem_detected |= AGENT_PROBLEM_HOMEDIR_REMOVED;
+ }
+
+ agent_kick_the_loop ();
+
+ leave:
+ return NULL;
+}
/* Figure out whether an agent is available and running. Prints an
error if not. If SILENT is true, no messages are printed.
diff --git a/agent/trustlist.c b/agent/trustlist.c
index 330f233b8..fce23de15 100644
--- a/agent/trustlist.c
+++ b/agent/trustlist.c
@@ -38,14 +38,14 @@ struct trustitem_s
{
struct
{
- int disabled:1; /* This entry is disabled. */
- int for_pgp:1; /* Set by '*' or 'P' as first flag. */
- int for_smime:1; /* Set by '*' or 'S' as first flag. */
- int relax:1; /* Relax checking of root certificate
+ unsigned int disabled:1; /* This entry is disabled. */
+ unsigned int for_pgp:1; /* Set by '*' or 'P' as first flag. */
+ unsigned int for_smime:1; /* Set by '*' or 'S' as first flag. */
+ unsigned int relax:1; /* Relax checking of root certificate
constraints. */
- int cm:1; /* Use chain model for validation. */
- int qual:1; /* Root CA for qualified signatures. */
- int de_vs:1; /* Root CA for de-vs compliant PKI. */
+ unsigned int cm:1; /* Use chain model for validation. */
+ unsigned int qual:1; /* Root CA for qualified signatures. */
+ unsigned int de_vs:1; /* Root CA for de-vs compliant PKI. */
} flags;
unsigned char fpr[20]; /* The binary fingerprint. */
};