aboutsummaryrefslogtreecommitdiffstats
path: root/kbx
diff options
context:
space:
mode:
Diffstat (limited to 'kbx')
-rw-r--r--kbx/kbx-client-util.c54
-rw-r--r--kbx/kbxserver.c26
-rw-r--r--kbx/kbxutil.c1
-rw-r--r--kbx/keybox-blob.c2
-rw-r--r--kbx/keybox-openpgp.c46
-rw-r--r--kbx/keybox-search.c53
-rw-r--r--kbx/keyboxd.c381
7 files changed, 349 insertions, 214 deletions
diff --git a/kbx/kbx-client-util.c b/kbx/kbx-client-util.c
index f6456a508..b900586c8 100644
--- a/kbx/kbx-client-util.c
+++ b/kbx/kbx-client-util.c
@@ -53,6 +53,7 @@ struct kbx_client_data_s
/* Condition variable to sync the datastream with the command. */
npth_mutex_t mutex;
npth_cond_t cond;
+ npth_t thd;
/* The data received from the keyboxd and an error code if there was
* a problem (in which case DATA is also set to NULL. This is only
@@ -103,7 +104,6 @@ prepare_data_pipe (kbx_client_data_t kcd)
int rc;
int inpipe[2];
estream_t infp;
- npth_t thread;
npth_attr_t tattr;
kcd->fp = NULL;
@@ -118,14 +118,18 @@ prepare_data_pipe (kbx_client_data_t kcd)
return err; /* That should not happen. */
}
- err = assuan_sendfd (kcd->ctx, INT2FD (inpipe[1]));
+#ifdef HAVE_W32_SYSTEM
+ err = assuan_sendfd (kcd->ctx, (HANDLE)_get_osfhandle (inpipe[1]));
+#else
+ err = assuan_sendfd (kcd->ctx, inpipe[1]);
+#endif
if (err)
{
- log_error ("sending sending fd %d to keyboxd: %s <%s>\n",
+ log_error ("sending fd %d to keyboxd: %s <%s>\n",
inpipe[1], gpg_strerror (err), gpg_strsource (err));
es_fclose (infp);
gnupg_close_pipe (inpipe[1]);
- return 0; /* Server may not support fd-passing. */
+ return err;
}
err = assuan_transact (kcd->ctx, "OUTPUT FD",
@@ -135,12 +139,12 @@ prepare_data_pipe (kbx_client_data_t kcd)
log_info ("keyboxd does not accept our fd: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
es_fclose (infp);
- return 0;
+ return err;
}
+ close (inpipe[1]);
kcd->fp = infp;
-
rc = npth_attr_init (&tattr);
if (rc)
{
@@ -150,8 +154,8 @@ prepare_data_pipe (kbx_client_data_t kcd)
kcd->fp = NULL;
return err;
}
- npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
- rc = npth_create (&thread, &tattr, datastream_thread, kcd);
+ npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+ rc = npth_create (&kcd->thd, &tattr, datastream_thread, kcd);
if (rc)
{
err = gpg_error_from_errno (rc);
@@ -162,6 +166,7 @@ prepare_data_pipe (kbx_client_data_t kcd)
return err;
}
+ npth_attr_destroy (&tattr);
return 0;
}
@@ -193,13 +198,8 @@ datastream_thread (void *arg)
gnupg_sleep (1);
continue;
}
- if (nread != 4)
- {
- err = gpg_error (GPG_ERR_EIO);
- log_error ("error reading data length from keyboxd: %s\n",
- "short read");
- continue;
- }
+ if (nread < 4)
+ break;
datalen = buf32_to_size_t (lenbuf);
/* log_debug ("keyboxd announced %zu bytes\n", datalen); */
@@ -294,8 +294,7 @@ kbx_client_data_new (kbx_client_data_t *r_kcd, assuan_context_t ctx,
{
err = gpg_error_from_errno (rc);
log_error ("error initializing mutex: %s\n", gpg_strerror (err));
- xfree (kcd);
- return err;
+ goto leave; /* Use D-lines. */
}
rc = npth_cond_init (&kcd->cond, NULL);
if (rc)
@@ -303,8 +302,7 @@ kbx_client_data_new (kbx_client_data_t *r_kcd, assuan_context_t ctx,
err = gpg_error_from_errno (rc);
log_error ("error initializing condition: %s\n", gpg_strerror (err));
npth_mutex_destroy (&kcd->mutex);
- xfree (kcd);
- return err;
+ goto leave; /* Use D-lines. */
}
err = prepare_data_pipe (kcd);
@@ -312,8 +310,7 @@ kbx_client_data_new (kbx_client_data_t *r_kcd, assuan_context_t ctx,
{
npth_cond_destroy (&kcd->cond);
npth_mutex_destroy (&kcd->mutex);
- xfree (kcd);
- return err;
+ /* Use D-lines. */
}
leave:
@@ -329,11 +326,20 @@ kbx_client_data_release (kbx_client_data_t kcd)
if (!kcd)
return;
+
fp = kcd->fp;
+ if (!fp)
+ {
+ xfree (kcd);
+ return;
+ }
+
+ if (npth_join (kcd->thd, NULL))
+ log_error ("kbx_client_data_release failed on npth_join");
+
kcd->fp = NULL;
- es_fclose (fp); /* That close should let the thread run into an error. */
- /* FIXME: Make thread killing explicit. Otherwise we run in a
- * log_fatal due to the destroyed mutex. */
+ es_fclose (fp);
+
npth_cond_destroy (&kcd->cond);
npth_mutex_destroy (&kcd->mutex);
xfree (kcd);
diff --git a/kbx/kbxserver.c b/kbx/kbxserver.c
index ae9ae5c75..d09a8f8eb 100644
--- a/kbx/kbxserver.c
+++ b/kbx/kbxserver.c
@@ -131,21 +131,25 @@ get_assuan_ctx_from_ctrl (ctrl_t ctrl)
static gpg_error_t
prepare_outstream (ctrl_t ctrl)
{
- int fd;
+ gnupg_fd_t fd;
+ estream_t out_fp = NULL;
log_assert (ctrl && ctrl->server_local);
if (ctrl->server_local->outstream)
return 0; /* Already enabled. */
- fd = translate_sys2libc_fd
- (assuan_get_output_fd (get_assuan_ctx_from_ctrl (ctrl)), 1);
- if (fd == -1)
+ fd = assuan_get_output_fd (get_assuan_ctx_from_ctrl (ctrl));
+ if (fd == GNUPG_INVALID_FD)
return 0; /* No Output command active. */
+ else
+ {
+ out_fp = open_stream_nc (fd, "w");
+ if (!out_fp)
+ return gpg_err_code_from_syserror ();
+ }
- ctrl->server_local->outstream = es_fdopen_nc (fd, "w");
- if (!ctrl->server_local->outstream)
- return gpg_err_code_from_syserror ();
+ ctrl->server_local->outstream = out_fp;
return 0;
}
@@ -946,15 +950,9 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
}
else
{
- /* The fd-passing does not work reliable on Windows, and even it
- * it is not used by gpg and gpgsm the current libassuan slows
- * down things if it is allowed for the server.*/
rc = assuan_init_socket_server (ctx, fd,
(ASSUAN_SOCKET_SERVER_ACCEPTED
-#ifndef HAVE_W32_SYSTEM
- |ASSUAN_SOCKET_SERVER_FDPASSING
-#endif
- ));
+ |ASSUAN_SOCKET_SERVER_FDPASSING));
}
if (rc)
diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c
index 935dbc735..c7ac5b852 100644
--- a/kbx/kbxutil.c
+++ b/kbx/kbxutil.c
@@ -132,7 +132,6 @@ my_strusage( int level )
}
-
/* static void */
/* wrong_args( const char *text ) */
/* { */
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index 2564d1f48..7d0670d9f 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -96,7 +96,7 @@
bit 0 = qualified signature (not yet implemented}
bit 7 = 32 byte fingerprint in use.
- u16 RFU
- - b20 keygrip
+ - b20 keygrip FIXME: Support a second grip.
- bN Optional filler up to the specified length of this
structure.
- u16 Size of the serial number (may be zero)
diff --git a/kbx/keybox-openpgp.c b/kbx/keybox-openpgp.c
index f5bd1b641..c91885b32 100644
--- a/kbx/keybox-openpgp.c
+++ b/kbx/keybox-openpgp.c
@@ -233,6 +233,26 @@ keygrip_from_keyparm (int algo, struct keyparm_s *kp, unsigned char *grip)
}
break;
+ case PUBKEY_ALGO_KYBER:
+ /* There is no space in the BLOB for a second grip, thus for now
+ * we store only the ECC keygrip. */
+ {
+ char *curve = openpgp_oidbuf_to_str (kp[0].mpi, kp[0].len);
+ if (!curve)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = gcry_sexp_build
+ (&s_pkey, NULL,
+ openpgp_oidbuf_is_cv25519 (kp[0].mpi, kp[0].len)
+ ?"(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))"
+ : "(public-key(ecc(curve%s)(q%b)))",
+ curve, kp[1].len, kp[1].mpi);
+ xfree (curve);
+ }
+ }
+ break;
+
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
@@ -273,6 +293,7 @@ parse_key (const unsigned char *data, size_t datalen,
unsigned char hashbuffer[768];
gcry_md_hd_t md;
int is_ecc = 0;
+ int is_kyber = 0;
int is_v5;
/* unsigned int pkbytes; for v5: # of octets of the public key params. */
struct keyparm_s keyparm[OPENPGP_MAX_NPKEY];
@@ -331,6 +352,10 @@ parse_key (const unsigned char *data, size_t datalen,
npkey = 2;
is_ecc = 1;
break;
+ case PUBKEY_ALGO_KYBER:
+ npkey = 3;
+ is_kyber = 1;
+ break;
default: /* Unknown algorithm. */
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
}
@@ -345,7 +370,8 @@ parse_key (const unsigned char *data, size_t datalen,
if (datalen < 2)
return gpg_error (GPG_ERR_INV_PACKET);
- if (is_ecc && (i == 0 || i == 2))
+ if ((is_ecc && (i == 0 || i == 2))
+ || (is_kyber && i == 0 ))
{
nbytes = data[0];
if (nbytes < 2 || nbytes > 254)
@@ -357,6 +383,20 @@ parse_key (const unsigned char *data, size_t datalen,
keyparm[i].mpi = data;
keyparm[i].len = nbytes;
}
+ else if (is_kyber && i == 2)
+ {
+ if (datalen < 4)
+ return gpg_error (GPG_ERR_INV_PACKET);
+ nbytes = ((data[0]<<24)|(data[1]<<16)|(data[2]<<8)|(data[3]));
+ data += 4;
+ datalen -= 4;
+ /* (for the limit see also MAX_EXTERN_MPI_BITS in g10/gpg.h) */
+ if (datalen < nbytes || nbytes > (32768*8))
+ return gpg_error (GPG_ERR_INV_PACKET);
+
+ keyparm[i].mpi = data;
+ keyparm[i].len = nbytes;
+ }
else
{
nbits = ((data[0]<<8)|(data[1]));
@@ -378,7 +418,7 @@ parse_key (const unsigned char *data, size_t datalen,
/* Note: Starting here we need to jump to leave on error. */
/* For non-ECC, make sure the MPIs are unsigned. */
- if (!is_ecc)
+ if (!is_ecc && !is_kyber)
for (i=0; i < npkey; i++)
{
if (!keyparm[i].len || (keyparm[i].mpi[0] & 0x80))
@@ -438,7 +478,7 @@ parse_key (const unsigned char *data, size_t datalen,
*/
if (version == 5)
{
- if ( 5 + n < sizeof hashbuffer )
+ if (5 + n < sizeof hashbuffer )
{
hashbuffer[0] = 0x9a; /* CTB */
hashbuffer[1] = (n >> 24);/* 4 byte length header. */
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index 31ea0ba60..303c19b79 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -279,7 +279,8 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen)
}
-/* Helper for has_short_kid and has_long_kid. */
+/* Helper for has_short_kid and has_long_kid. This function is called
+ * with FPROFF 12 and FPRLEN 4 or with FPROFF 12 and FPRLEN 8. */
static int
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
int fproff, int fprlen)
@@ -288,7 +289,8 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
size_t length;
size_t pos, off;
size_t nkeys, keyinfolen;
- int idx, fpr32, storedfprlen;
+ int idx;
+ int fpr32; /* Set if this blob stores all fingerprints as 32 bytes. */
buffer = _keybox_get_blob_image (blob, &length);
if (length < 40)
@@ -307,13 +309,24 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
for (idx=0; idx < nkeys; idx++)
{
off = pos + idx*keyinfolen;
- if (fpr32)
- storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20;
+ if (!fpr32)
+ {
+ /* Blob has only 20 fingerprints - use the FPROFF. */
+ if (!memcmp (buffer + off + fproff, fpr, fprlen))
+ return idx+1; /* found */
+ }
+ else if ((buffer[off + 32 + 1] & 0x80))
+ {
+ /* This (sub)key has a 32 byte fpr -> use 0 as offset. */
+ if (!memcmp (buffer + off, fpr, fprlen))
+ return idx+1; /* found */
+ }
else
- storedfprlen = 20;
- if ((fpr32 || storedfprlen == fproff + fprlen)
- && !memcmp (buffer + off + fproff, fpr, fprlen))
- return idx+1; /* found */
+ {
+ /* This (sub)key has a 20 byte fpr -> use the FPROFF */
+ if (!memcmp (buffer + off + fproff, fpr, fprlen))
+ return idx+1; /* found */
+ }
}
return 0; /* not found */
}
@@ -683,43 +696,30 @@ blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
static inline int
has_short_kid (KEYBOXBLOB blob, u32 lkid)
{
- const unsigned char *buffer;
size_t length;
- int fpr32;
unsigned char buf[4];
- buffer = _keybox_get_blob_image (blob, &length);
+ _keybox_get_blob_image (blob, &length);
if (length < 48)
return 0; /* blob too short */
- fpr32 = buffer[5] == 2;
- if (fpr32 && length < 56)
- return 0; /* blob to short */
buf[0] = lkid >> 24;
buf[1] = lkid >> 16;
buf[2] = lkid >> 8;
buf[3] = lkid;
- if (fpr32 && (get16 (buffer + 20 + 32) & 0x80))
- return blob_cmp_fpr_part (blob, buf, 0, 4);
- else
- return blob_cmp_fpr_part (blob, buf, 16, 4);
+ return blob_cmp_fpr_part (blob, buf, 16, 4);
}
static inline int
has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid)
{
- const unsigned char *buffer;
size_t length;
- int fpr32;
unsigned char buf[8];
- buffer = _keybox_get_blob_image (blob, &length);
+ _keybox_get_blob_image (blob, &length);
if (length < 48)
return 0; /* blob too short */
- fpr32 = buffer[5] == 2;
- if (fpr32 && length < 56)
- return 0; /* blob to short */
buf[0] = mkid >> 24;
buf[1] = mkid >> 16;
@@ -730,10 +730,7 @@ has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid)
buf[6] = lkid >> 8;
buf[7] = lkid;
- if (fpr32 && (get16 (buffer + 20 + 32) & 0x80))
- return blob_cmp_fpr_part (blob, buf, 0, 8);
- else
- return blob_cmp_fpr_part (blob, buf, 12, 8);
+ return blob_cmp_fpr_part (blob, buf, 12, 8);
}
static inline int
diff --git a/kbx/keyboxd.c b/kbx/keyboxd.c
index f875e115d..73905eb7d 100644
--- a/kbx/keyboxd.c
+++ b/kbx/keyboxd.c
@@ -144,14 +144,13 @@ static struct debug_flags_s debug_flags [] =
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
};
-/* 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)
-# define CHECK_OWN_SOCKET_INTERVAL (60)
+/* 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_INTERVAL defines how often we check the existence of
+ * homedir. Value is in seconds. */
+#define CHECK_PROBLEMS_INTERVAL (4)
/* The list of open file descriptors at startup. Note that this list
* has been allocated using the standard malloc. */
@@ -171,8 +170,10 @@ static int shutdown_pending;
/* Flag indicating to start the daemon even if one already runs. */
static int steal_socket;
-/* Counter for the currently running own socket checks. */
-static int check_own_socket_running;
+/* Flag to monitor problems. */
+static int problem_detected;
+#define KEYBOXD_PROBLEM_SOCKET_TAKEOVER (1 << 0)
+#define KEYBOXD_PROBLEM_HOMEDIR_REMOVED (1 << 1)
/* Flag to indicate that we shall not watch our own socket. */
static int disable_check_own_socket;
@@ -192,6 +193,17 @@ static assuan_sock_nonce_t socket_nonce;
* 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
+
/* Name of a config file, which will be reread on a HUP if it is not NULL. */
static char *config_filename;
@@ -199,16 +211,6 @@ static char *config_filename;
* the log file after a SIGHUP if it didn't changed. Malloced. */
static char *current_logfile;
-/* 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 keyboxd 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;
@@ -255,12 +257,11 @@ static void kbxd_init_default_ctrl (ctrl_t ctrl);
static void kbxd_deinit_default_ctrl (ctrl_t ctrl);
static void handle_connections (gnupg_fd_t listen_fd);
-static void check_own_socket (void);
static int check_for_running_kbxd (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.
@@ -440,6 +441,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);
}
@@ -447,7 +449,6 @@ static void
initialize_modules (void)
{
thread_init_once ();
- assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
}
@@ -497,7 +498,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, kbxd_assuan_log_monitor);
setup_libgcrypt_logging ();
@@ -809,11 +809,6 @@ main (int argc, char **argv )
log_get_prefix (&oldflags);
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
opt.running_detached = 1;
-
- /* Because we don't support running a program on the command
- * line we can assume that the inotify things works and thus
- * we can avoid the regular stat calls. */
- reliable_homedir_inotify = 1;
}
{
@@ -1070,6 +1065,44 @@ get_kbxd_active_connection_count (void)
}
+/* 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)
+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;
+}
+#endif /*HAVE_W32_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.
@@ -1282,38 +1315,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);
-
- /* 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)
- && 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
@@ -1359,6 +1360,11 @@ handle_signal (int signo)
kbxd_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");
@@ -1396,7 +1402,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;
@@ -1416,7 +1422,7 @@ do_start_connection_thread (ctrl_t ctrl)
kbxd_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));
+ (unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
session_id = ++last_session_id;
if (!session_id)
@@ -1424,7 +1430,7 @@ do_start_connection_thread (ctrl_t ctrl)
kbxd_start_command_handler (ctrl, ctrl->thread_startup.fd, session_id);
if (opt.verbose && !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));
kbxd_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -1450,6 +1456,28 @@ start_connection_thread (void *arg)
}
+static void
+keyboxd_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
@@ -1464,12 +1492,14 @@ 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;
#ifdef HAVE_W32_SYSTEM
HANDLE events[2];
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;
@@ -1480,7 +1510,7 @@ handle_connections (gnupg_fd_t listen_fd)
} listentbl[] = {
{ "std", start_connection_thread },
};
-
+ int have_homedir_inotify = 0;
ret = npth_attr_init(&tattr);
if (ret)
@@ -1493,10 +1523,23 @@ 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] = INVALID_HANDLE_VALUE;
+ events[0] = the_event2 = create_an_event ();
+ events[1] = INVALID_HANDLE_VALUE;
#endif
if (disable_check_own_socket)
@@ -1508,10 +1551,8 @@ handle_connections (gnupg_fd_t listen_fd)
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 ((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",
@@ -1520,9 +1561,29 @@ 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_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));
+ }
+
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
- nfd = FD2INT (listen_fd);
+ nfd = FD2NUM (listen_fd);
if (sock_inotify_fd != -1)
{
FD_SET (sock_inotify_fd, &fdset);
@@ -1538,9 +1599,6 @@ handle_connections (gnupg_fd_t listen_fd)
listentbl[0].l_fd = listen_fd;
- npth_clock_gettime (&abstime);
- abstime.tv_sec += TIMERTICK_INTERVAL;
-
for (;;)
{
/* Shutdown test. */
@@ -1573,28 +1631,21 @@ handle_connections (gnupg_fd_t listen_fd)
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
#ifndef HAVE_W32_SYSTEM
- ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+ ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, NULL,
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, NULL,
events, &events_set);
saved_errno = errno;
@@ -1610,6 +1661,22 @@ handle_connections (gnupg_fd_t listen_fd)
gnupg_sleep (1);
continue;
}
+
+ if ((problem_detected & KEYBOXD_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 & KEYBOXD_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
@@ -1617,6 +1684,15 @@ handle_connections (gnupg_fd_t listen_fd)
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. */
@@ -1653,8 +1729,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",
@@ -1687,13 +1763,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)
@@ -1704,20 +1788,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)
{
@@ -1755,57 +1837,70 @@ 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 keyboxd 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 (), KEYBOXD_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 |= KEYBOXD_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);
+
+ keyboxd_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);
+
+ /* Check whether the homedir is still available. */
+ if (gnupg_stat (homedir, &statbuf) && errno == ENOENT)
+ problem_detected |= KEYBOXD_PROBLEM_HOMEDIR_REMOVED;
+ }
+
+ keyboxd_kick_the_loop ();
+
+ leave:
+ return NULL;
+}
/* Figure out whether a keyboxd is available and running. Prints an