1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-29 21:58:04 +02:00

* no-pth.c, Makefile.am: Removed.

* call-scd.c: Seirialized all scdaeom access when using Pth.

* cache.c: Made the cache Pth-thread-safe.
(agent_unlock_cache_entry): New.
* findkey.c (unprotect): Unlock the returned cache value.
* command.c (cmd_get_passphrase): Ditto.

* gpg-agent.c (main): Register pth_read/write with Assuan.
This commit is contained in:
Werner Koch 2002-05-23 09:07:45 +00:00
parent 72f48d9e8a
commit b209c17be9
12 changed files with 416 additions and 162 deletions

View File

@ -1,3 +1,25 @@
2002-05-23 Werner Koch <wk@gnupg.org>
* call-scd.c: Seirialized all scdaeom access when using Pth.
* cache.c: Made the cache Pth-thread-safe.
(agent_unlock_cache_entry): New.
* findkey.c (unprotect): Unlock the returned cache value.
* command.c (cmd_get_passphrase): Ditto.
* gpg-agent.c (main): Register pth_read/write with Assuan.
2002-05-22 Werner Koch <wk@gnupg.org>
* query.c: Serialized all pinentry access when using Pth.
* gpg-agent.c (handle_signal,start_connection_thread)
(handle_connections): New
(main): Use the new Pth stuff to allow concurrent connections.
* command.c (start_command_handler): Add new arg FD so that the
fucntion can also be used for an already connected socket.
* Makefile.am: Link with Pth.
2002-05-14 Werner Koch <wk@gnupg.org> 2002-05-14 Werner Koch <wk@gnupg.org>
* cache.c (housekeeping, agent_put_cache): Use our time() wrapper. * cache.c (housekeeping, agent_put_cache): Use our time() wrapper.

View File

@ -21,7 +21,7 @@
bin_PROGRAMS = gpg-agent bin_PROGRAMS = gpg-agent
noinst_PROGRAMS = protect-tool noinst_PROGRAMS = protect-tool
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) $(PTH_CFLAGS)
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
gpg_agent_SOURCES = \ gpg_agent_SOURCES = \
@ -43,7 +43,7 @@ gpg_agent_SOURCES = \
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a $(LIBGCRYPT_LIBS) ../common/libcommon.a $(LIBGCRYPT_LIBS) $(PTH_LIBS)
protect_tool_SOURCES = \ protect_tool_SOURCES = \
protect-tool.c \ protect-tool.c \

View File

@ -104,7 +104,7 @@ void agent_exit (int rc); /* also implemented in other tools */
const char *trans (const char *text); const char *trans (const char *text);
/*-- command.c --*/ /*-- command.c --*/
void start_command_handler (int); void start_command_handler (int, int);
/*-- findkey.c --*/ /*-- findkey.c --*/
int agent_write_private_key (const unsigned char *grip, int agent_write_private_key (const unsigned char *grip,
@ -124,8 +124,8 @@ int agent_get_confirmation (const char *desc, const char *ok,
/*-- cache.c --*/ /*-- cache.c --*/
int agent_put_cache (const char *key, const char *data, int ttl); int agent_put_cache (const char *key, const char *data, int ttl);
const char *agent_get_cache (const char *key); const char *agent_get_cache (const char *key, void **cache_id);
void agent_unlock_cache_entry (void **cache_id);
/*-- pksign.c --*/ /*-- pksign.c --*/

View File

@ -40,6 +40,7 @@ struct cache_item_s {
time_t created; time_t created;
time_t accessed; time_t accessed;
int ttl; /* max. lifetime given in seonds */ int ttl; /* max. lifetime given in seonds */
int lockcount;
struct secret_data_s *pw; struct secret_data_s *pw;
char key[1]; char key[1];
}; };
@ -87,7 +88,7 @@ housekeeping (void)
/* first expire the actual data */ /* first expire the actual data */
for (r=thecache; r; r = r->next) for (r=thecache; r; r = r->next)
{ {
if (r->pw && r->accessed + r->ttl < current) if (!r->lockcount && r->pw && r->accessed + r->ttl < current)
{ {
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" expired `%s' (%ds after last access)\n", log_debug (" expired `%s' (%ds after last access)\n",
@ -99,10 +100,10 @@ housekeeping (void)
} }
/* second, make sure that we also remove them based on the created stamp so /* second, make sure that we also remove them based on the created stamp so
that the used has to enter it from time to time. We do this every hour */ that the user has to enter it from time to time. We do this every hour */
for (r=thecache; r; r = r->next) for (r=thecache; r; r = r->next)
{ {
if (r->pw && r->created + 60*60 < current) if (!r->lockcount && r->pw && r->created + 60*60 < current)
{ {
if (DBG_CACHE) if (DBG_CACHE)
log_debug (" expired `%s' (1h after creation)\n", r->key); log_debug (" expired `%s' (1h after creation)\n", r->key);
@ -118,15 +119,27 @@ housekeeping (void)
{ {
if (!r->pw && r->accessed + 60*30 < current) if (!r->pw && r->accessed + 60*30 < current)
{ {
ITEM r2 = r->next; if (r->lockcount)
if (DBG_CACHE) {
log_debug (" removed `%s' (slot not used for 30m)\n", r->key); log_error ("can't remove unused cache entry `%s' due to"
xfree (r); " lockcount=%d\n",
if (!rprev) r->key, r->lockcount);
thecache = r2; r->accessed += 60*10; /* next error message in 10 minutes */
rprev = r;
r = r->next;
}
else else
rprev->next = r2; {
r = r2; ITEM r2 = r->next;
if (DBG_CACHE)
log_debug (" removed `%s' (slot not used for 30m)\n", r->key);
xfree (r);
if (!rprev)
thecache = r2;
else
rprev->next = r2;
r = r2;
}
} }
else else
{ {
@ -158,7 +171,7 @@ agent_put_cache (const char *key, const char *data, int ttl)
for (r=thecache; r; r = r->next) for (r=thecache; r; r = r->next)
{ {
if ( !strcmp (r->key, key)) if (!r->lockcount && !strcmp (r->key, key))
break; break;
} }
if (r) if (r)
@ -206,34 +219,67 @@ agent_put_cache (const char *key, const char *data, int ttl)
/* Try to find an item in the cache */ /* Try to find an item in the cache */
const char * const char *
agent_get_cache (const char *key) agent_get_cache (const char *key, void **cache_id)
{ {
ITEM r; ITEM r;
int count = 0;
if (DBG_CACHE) if (DBG_CACHE)
log_debug ("agent_get_cache `%s'...\n", key); log_debug ("agent_get_cache `%s'...\n", key);
housekeeping (); housekeeping ();
/* FIXME: Returning pointers is not thread safe - add a reference /* first try to find one with no locks - this is an updated cache
counter */ entry: We might have entries with a lockcount and without a
for (r=thecache; r; r = r->next, count++) lockcount. */
for (r=thecache; r; r = r->next)
{ {
if (r->pw && !strcmp (r->key, key)) if (!r->lockcount && r->pw && !strcmp (r->key, key))
{ {
/* put_cache does only put strings into the cache, so we /* put_cache does only put strings into the cache, so we
don't need the lengths */ don't need the lengths */
r->accessed = gnupg_get_time (); r->accessed = gnupg_get_time ();
if (DBG_CACHE) if (DBG_CACHE)
log_debug ("... hit\n"); log_debug ("... hit\n");
r->lockcount++;
*cache_id = r;
return r->pw->data;
}
}
/* again, but this time get even one with a lockcount set */
for (r=thecache; r; r = r->next)
{
if (r->pw && !strcmp (r->key, key))
{
r->accessed = gnupg_get_time ();
if (DBG_CACHE)
log_debug ("... hit (locked)\n");
r->lockcount++;
*cache_id = r;
return r->pw->data; return r->pw->data;
} }
} }
if (DBG_CACHE) if (DBG_CACHE)
log_debug ("... miss\n"); log_debug ("... miss\n");
*cache_id = NULL;
return NULL; return NULL;
} }
void
agent_unlock_cache_entry (void **cache_id)
{
ITEM r;
for (r=thecache; r; r = r->next)
{
if (r == *cache_id)
{
if (!r->lockcount)
log_error ("trying to unlock non-locked cache entry `%s'\n",
r->key);
else
r->lockcount--;
return;
}
}
}

View File

@ -18,6 +18,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
/* Fixme: For now we have serialized all access to the scdaemon which
make sense becuase the scdaemon can't handle concurrent connections
right now. We should however keep a list of connections and lock
just that connection - it migth make sense to implemtn parts of
this in Assuan.*/
#include <config.h> #include <config.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -27,6 +33,9 @@
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h" #include "agent.h"
#include "../assuan/assuan.h" #include "../assuan/assuan.h"
@ -38,6 +47,9 @@
#endif #endif
static ASSUAN_CONTEXT scd_ctx = NULL; static ASSUAN_CONTEXT scd_ctx = NULL;
#ifdef USE_GNU_PTH
static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
#endif
/* callback parameter for learn card */ /* callback parameter for learn card */
struct learn_parm_s { struct learn_parm_s {
@ -60,7 +72,7 @@ struct membuf {
/* A simple implemnation of a dynamic buffer. Use init_membuf() to /* A simple implementation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter only returned at the final get_membuf(), this helps not to clutter
@ -122,6 +134,20 @@ get_membuf (struct membuf *mb, size_t *len)
static int
unlock_scd (int rc)
{
#ifdef USE_GNU_PTH
if (!pth_mutex_release (&scd_lock))
{
log_error ("failed to release the SCD lock\n");
if (!rc)
rc = GNUPG_Internal_Error;
}
#endif
return rc;
}
/* Fork off the SCdaemon if this has not already been done */ /* Fork off the SCdaemon if this has not already been done */
static int static int
start_scd (void) start_scd (void)
@ -131,6 +157,14 @@ start_scd (void)
ASSUAN_CONTEXT ctx; ASSUAN_CONTEXT ctx;
const char *argv[3]; const char *argv[3];
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&scd_lock, 0, NULL))
{
log_error ("failed to acquire the SCD lock\n");
return GNUPG_Internal_Error;
}
#endif
if (scd_ctx) if (scd_ctx)
return 0; /* No need to serialize things because the agent is return 0; /* No need to serialize things because the agent is
expected to tun as a single-thread (or may be in expected to tun as a single-thread (or may be in
@ -142,7 +176,7 @@ start_scd (void)
if (fflush (NULL)) if (fflush (NULL))
{ {
log_error ("error flushing pending output: %s\n", strerror (errno)); log_error ("error flushing pending output: %s\n", strerror (errno));
return seterr (Write_Error); return unlock_scd (seterr (Write_Error));
} }
/* FIXME: change the default location of the program */ /* FIXME: change the default location of the program */
@ -163,7 +197,7 @@ start_scd (void)
{ {
log_error ("can't connect to the SCdaemon: %s\n", log_error ("can't connect to the SCdaemon: %s\n",
assuan_strerror (rc)); assuan_strerror (rc));
return seterr (No_Scdaemon); return unlock_scd (seterr (No_Scdaemon));
} }
scd_ctx = ctx; scd_ctx = ctx;
@ -218,9 +252,9 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
learn_status_cb, &parm); learn_status_cb, &parm);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
return 0; return unlock_scd (0);
} }
@ -274,7 +308,7 @@ agent_card_serialno (char **r_serialno)
this is really SCdaemon's duty */ this is really SCdaemon's duty */
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
rc = assuan_transact (scd_ctx, "SERIALNO", rc = assuan_transact (scd_ctx, "SERIALNO",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -282,10 +316,10 @@ agent_card_serialno (char **r_serialno)
if (rc) if (rc)
{ {
xfree (serialno); xfree (serialno);
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
} }
*r_serialno = serialno; *r_serialno = serialno;
return 0; return unlock_scd (0);
} }
@ -354,7 +388,7 @@ agent_card_pksign (const char *keyid,
return rc; return rc;
if (indatalen*2 + 50 > DIM(line)) if (indatalen*2 + 50 > DIM(line))
return seterr (General_Error); return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA "); sprintf (line, "SETDATA ");
p = line + strlen (line); p = line + strlen (line);
@ -362,7 +396,7 @@ agent_card_pksign (const char *keyid,
sprintf (p, "%02X", indata[i]); sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024); init_membuf (&data, 1024);
inqparm.ctx = scd_ctx; inqparm.ctx = scd_ctx;
@ -377,7 +411,7 @@ agent_card_pksign (const char *keyid,
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
} }
sigbuf = get_membuf (&data, &sigbuflen); sigbuf = get_membuf (&data, &sigbuflen);
@ -388,7 +422,7 @@ agent_card_pksign (const char *keyid,
if (!*r_buf) if (!*r_buf)
{ {
xfree (*r_buf); xfree (*r_buf);
return GNUPG_Out_Of_Core; return unlock_scd (GNUPG_Out_Of_Core);
} }
p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" ); p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" );
sprintf (p, "%u:", (unsigned int)sigbuflen); sprintf (p, "%u:", (unsigned int)sigbuflen);
@ -399,7 +433,7 @@ agent_card_pksign (const char *keyid,
xfree (sigbuf); xfree (sigbuf);
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL)); assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
return 0; return unlock_scd (0);
} }
/* Decipher INDATA using the current card. Note that the returned value is */ /* Decipher INDATA using the current card. Note that the returned value is */
@ -423,7 +457,7 @@ agent_card_pkdecrypt (const char *keyid,
/* FIXME: use secure memory where appropriate */ /* FIXME: use secure memory where appropriate */
if (indatalen*2 + 50 > DIM(line)) if (indatalen*2 + 50 > DIM(line))
return seterr (General_Error); return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA "); sprintf (line, "SETDATA ");
p = line + strlen (line); p = line + strlen (line);
@ -431,7 +465,7 @@ agent_card_pkdecrypt (const char *keyid,
sprintf (p, "%02X", indata[i]); sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024); init_membuf (&data, 1024);
inqparm.ctx = scd_ctx; inqparm.ctx = scd_ctx;
@ -446,13 +480,13 @@ agent_card_pkdecrypt (const char *keyid,
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
} }
*r_buf = get_membuf (&data, r_buflen); *r_buf = get_membuf (&data, r_buflen);
if (!*r_buf) if (!*r_buf)
return GNUPG_Out_Of_Core; return unlock_scd (GNUPG_Out_Of_Core);
return 0; return unlock_scd (0);
} }
@ -481,13 +515,13 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
} }
*r_buf = get_membuf (&data, r_buflen); *r_buf = get_membuf (&data, r_buflen);
if (!*r_buf) if (!*r_buf)
return GNUPG_Out_Of_Core; return unlock_scd (GNUPG_Out_Of_Core);
return 0; return unlock_scd (0);
} }
@ -517,19 +551,19 @@ agent_card_readkey (const char *id, unsigned char **r_buf)
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
return map_assuan_err (rc); return unlock_scd (map_assuan_err (rc));
} }
*r_buf = get_membuf (&data, &buflen); *r_buf = get_membuf (&data, &buflen);
if (!*r_buf) if (!*r_buf)
return GNUPG_Out_Of_Core; return unlock_scd (GNUPG_Out_Of_Core);
if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL)) if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
{ {
xfree (*r_buf); *r_buf = NULL; xfree (*r_buf); *r_buf = NULL;
return GNUPG_Invalid_Value; return unlock_scd (GNUPG_Invalid_Value);
} }
return 0; return unlock_scd (0);
} }

View File

@ -370,6 +370,7 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
char *response; char *response;
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL; char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
char *p; char *p;
void *cache_marker;
/* parse the stuff */ /* parse the stuff */
for (p=line; *p == ' '; p++) for (p=line; *p == ' '; p++)
@ -417,17 +418,18 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
desc = NULL; desc = NULL;
/* Note: we store the hexified versions in the cache. */ /* Note: we store the hexified versions in the cache. */
pw = cacheid ? agent_get_cache (cacheid) : NULL; pw = cacheid ? agent_get_cache (cacheid, &cache_marker) : NULL;
if (pw) if (pw)
{ {
assuan_begin_confidential (ctx); assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, pw); rc = assuan_set_okay_line (ctx, pw);
agent_unlock_cache_entry (&cache_marker);
} }
else else
{ {
/* Note, that we only need to repalce the + characters and /* Note, that we only need to replace the + characters and
should leave the other escaping in place becuase the escaped should leave the other escaping in place because the escaped
sting is send verbatim to the pinentry which does the string is send verbatim to the pinentry which does the
unescaping (but not the + replacing) */ unescaping (but not the + replacing) */
if (errtext) if (errtext)
plus_to_blank (errtext); plus_to_blank (errtext);
@ -593,19 +595,18 @@ register_commands (ASSUAN_CONTEXT ctx)
} }
/* Startup the server. If LISTEN_FD is given as -1, this is a simple /* Startup the server. If LISTEN_FD and FD is given as -1, this is a simple
piper server, otherwise it is a regular server */ piper server, otherwise it is a regular server */
void void
start_command_handler (int listen_fd) start_command_handler (int listen_fd, int fd)
{ {
int rc; int rc;
ASSUAN_CONTEXT ctx; ASSUAN_CONTEXT ctx;
struct server_control_s ctrl; struct server_control_s ctrl;
memset (&ctrl, 0, sizeof ctrl); memset (&ctrl, 0, sizeof ctrl);
if (listen_fd == -1) if (listen_fd == -1 && fd == -1)
{ {
int filedes[2]; int filedes[2];
@ -613,10 +614,14 @@ start_command_handler (int listen_fd)
filedes[1] = 1; filedes[1] = 1;
rc = assuan_init_pipe_server (&ctx, filedes); rc = assuan_init_pipe_server (&ctx, filedes);
} }
else else if (listen_fd != -1)
{ {
rc = assuan_init_socket_server (&ctx, listen_fd); rc = assuan_init_socket_server (&ctx, listen_fd);
} }
else
{
rc = assuan_init_connected_socket_server (&ctx, fd);
}
if (rc) if (rc)
{ {
log_error ("failed to initialize the server: %s\n", log_error ("failed to initialize the server: %s\n",
@ -664,5 +669,3 @@ start_command_handler (int listen_fd)
assuan_deinit_server (ctx); assuan_deinit_server (ctx);
} }

View File

@ -106,10 +106,12 @@ unprotect (unsigned char **keybuf, const unsigned char *grip)
/* first try to get it from the cache - if there is none or we can't /* first try to get it from the cache - if there is none or we can't
unprotect it, we fall back to ask the user */ unprotect it, we fall back to ask the user */
{ {
const char *pw = agent_get_cache (hexgrip); void *cache_marker;
const char *pw = agent_get_cache (hexgrip, &cache_marker);
if (pw) if (pw)
{ {
rc = agent_unprotect (*keybuf, pw, &result, &resultlen); rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
agent_unlock_cache_entry (&cache_marker);
if (!rc) if (!rc)
{ {
xfree (*keybuf); xfree (*keybuf);

View File

@ -33,6 +33,9 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include <gcrypt.h> #include <gcrypt.h>
@ -113,7 +116,13 @@ static ARGPARSE_OPTS opts[] = {
}; };
#ifndef USE_GNU_PTH
static volatile int caught_fatal_sig = 0; static volatile int caught_fatal_sig = 0;
#endif /*!USE_GNU_PTH*/
/* flag to indicate that a shutdown was requested */
static int shutdown_pending;
/* It is possible that we are currently running under setuid permissions */ /* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1; static int maybe_setuid = 1;
@ -122,6 +131,11 @@ static int maybe_setuid = 1;
static char socket_name[128]; static char socket_name[128];
#ifdef USE_GNU_PTH
static void handle_connections (int listen_fd);
#endif
static const char * static const char *
my_strusage (int level) my_strusage (int level)
@ -205,6 +219,7 @@ cleanup (void)
} }
#ifndef USE_GNU_PTH
static RETSIGTYPE static RETSIGTYPE
cleanup_sh (int sig) cleanup_sh (int sig)
{ {
@ -226,6 +241,7 @@ cleanup_sh (int sig)
#endif #endif
raise( sig ); raise( sig );
} }
#endif /*!USE_GNU_PTH*/
int int
main (int argc, char **argv ) main (int argc, char **argv )
@ -265,6 +281,9 @@ main (int argc, char **argv )
} }
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
#ifdef USE_GNU_PTH
assuan_set_io_func (pth_read, pth_write);
#endif
gcry_set_log_handler (my_gcry_logger, NULL); gcry_set_log_handler (my_gcry_logger, NULL);
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
@ -447,7 +466,7 @@ main (int argc, char **argv )
if (pipe_server) if (pipe_server)
{ /* this is the simple pipe based server */ { /* this is the simple pipe based server */
start_command_handler (-1); start_command_handler (-1, -1);
} }
else else
{ /* regular server mode */ { /* regular server mode */
@ -574,6 +593,7 @@ main (int argc, char **argv )
/*NEVER REACHED*/ /*NEVER REACHED*/
} /* end parent */ } /* end parent */
/* this is the child */ /* this is the child */
/* detach from tty and put process into a new session */ /* detach from tty and put process into a new session */
@ -592,6 +612,22 @@ main (int argc, char **argv )
} }
} }
if (chdir("/"))
{
log_error ("chdir to / failed: %s\n", strerror (errno));
exit (1);
}
#ifdef USE_GNU_PTH
if (!pth_init ())
{
log_error ("failed to initialize the Pth library\n");
exit (1);
}
signal (SIGPIPE, SIG_IGN);
handle_connections (fd);
#else /*!USE_GNU_PTH*/
/* setup signals */ /* setup signals */
{ {
struct sigaction oact, nact; struct sigaction oact, nact;
@ -610,15 +646,8 @@ main (int argc, char **argv )
sigaction (SIGPIPE, &nact, NULL); sigaction (SIGPIPE, &nact, NULL);
sigaction (SIGINT, &nact, NULL); sigaction (SIGINT, &nact, NULL);
} }
start_command_handler (fd, -1);
if (chdir("/")) #endif /*!USE_GNU_PTH*/
{
log_error ("chdir to / failed: %s\n", strerror (errno));
exit (1);
}
start_command_handler (fd);
close (fd); close (fd);
} }
@ -628,10 +657,7 @@ main (int argc, char **argv )
void void
agent_exit (int rc) agent_exit (int rc)
{ {
#if 0 /*FIXME: update_random_seed_file();*/
#warning no update_random_seed_file
update_random_seed_file();
#endif
#if 0 #if 0
/* at this time a bit annoying */ /* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE) if (opt.debug & DBG_MEMSTAT_VALUE)
@ -647,3 +673,144 @@ agent_exit (int rc)
exit (rc); exit (rc);
} }
static void
reread_configuration (void)
{
/* FIXME: Move parts of the option parsing to here. */
}
#ifdef USE_GNU_PTH
static void
handle_signal (int signo)
{
switch (signo)
{
case SIGHUP:
log_info ("SIGHUP received - re-reading configuration\n");
reread_configuration ();
break;
case SIGUSR1:
if (opt.verbose < 5)
opt.verbose++;
log_info ("SIGUSR1 received - verbosity set to %d\n", opt.verbose);
break;
case SIGUSR2:
if (opt.verbose)
opt.verbose--;
log_info ("SIGUSR2 received - verbosity set to %d\n", opt.verbose );
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
log_info ("SIGTERM received - still %ld running threads\n",
pth_ctrl( PTH_CTRL_GETTHREADS ));
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info ("shutdown forced\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
agent_exit (0);
}
break;
case SIGINT:
log_info ("SIGINT received - immediate shutdown\n");
log_info( "%s %s stopped\n", strusage(11), strusage(13));
cleanup ();
agent_exit (0);
break;
default:
log_info ("signal %d received - no action defined\n", signo);
}
}
static void *
start_connection_thread (void *arg)
{
int fd = (int)arg;
if (opt.verbose)
log_info ("handler for fd %d started\n", fd);
start_command_handler (-1, fd);
if (opt.verbose)
log_info ("handler for fd %d terminated\n", fd);
return NULL;
}
static void
handle_connections (int listen_fd)
{
pth_attr_t tattr;
pth_event_t ev;
sigset_t sigs;
int signo;
struct sockaddr_un paddr;
socklen_t plen = sizeof( paddr );
int fd;
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
sigemptyset (&sigs );
sigaddset (&sigs, SIGHUP);
sigaddset (&sigs, SIGUSR1);
sigaddset (&sigs, SIGUSR2);
sigaddset (&sigs, SIGINT);
sigaddset (&sigs, SIGTERM);
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
for (;;)
{
if (shutdown_pending)
{
if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
break; /* ready */
/* Do not accept anymore connections and wait for existing
connections to terminate */
signo = 0;
pth_wait (ev);
if (pth_event_occurred (ev) && signo)
handle_signal (signo);
continue;
}
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
if (fd == -1)
{
if (pth_event_occurred (ev))
{
handle_signal (signo);
continue;
}
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
pth_sleep(1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
close (fd);
}
}
pth_event_free (ev, PTH_FREE_ALL);
cleanup ();
log_info ("%s %s stopped\n", strusage(11), strusage(13));
}
#endif /*USE_GNU_PTH*/

View File

@ -27,6 +27,9 @@
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h" #include "agent.h"
#include "../assuan/assuan.h" #include "../assuan/assuan.h"
@ -38,6 +41,9 @@
#endif #endif
static ASSUAN_CONTEXT entry_ctx = NULL; static ASSUAN_CONTEXT entry_ctx = NULL;
#ifdef USE_GNU_PTH
static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
#endif
/* data to be passed to our callbacks */ /* data to be passed to our callbacks */
struct entry_parm_s { struct entry_parm_s {
@ -49,7 +55,24 @@ struct entry_parm_s {
/* Fork off the pin entry if this has not already been done */ static int
unlock_pinentry (int rc)
{
#ifdef USE_GNU_PTH
if (!pth_mutex_release (&entry_lock))
{
log_error ("failed to release the entry lock\n");
if (!rc)
rc = GNUPG_Internal_Error;
}
#endif
return rc;
}
/* Fork off the pin entry if this has not already been done. Note,
that this function must always be used to aquire the lock for the
pinentry - we will serialize _all_ pinentry calls.
*/
static int static int
start_pinentry (void) start_pinentry (void)
{ {
@ -58,10 +81,16 @@ start_pinentry (void)
ASSUAN_CONTEXT ctx; ASSUAN_CONTEXT ctx;
const char *argv[5]; const char *argv[5];
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&entry_lock, 0, NULL))
{
log_error ("failed to acquire the entry lock\n");
return GNUPG_Internal_Error;
}
#endif
if (entry_ctx) if (entry_ctx)
return 0; /* No need to serialize things becuase the agent is return 0;
expected to tun as a single-thread (or may be in
future using libpth) */
if (opt.verbose) if (opt.verbose)
log_info ("no running PIN Entry - starting it\n"); log_info ("no running PIN Entry - starting it\n");
@ -69,7 +98,7 @@ start_pinentry (void)
if (fflush (NULL)) if (fflush (NULL))
{ {
log_error ("error flushing pending output: %s\n", strerror (errno)); log_error ("error flushing pending output: %s\n", strerror (errno));
return seterr (Write_Error); return unlock_pinentry (seterr (Write_Error));
} }
/* FIXME: change the default location of the program */ /* FIXME: change the default location of the program */
@ -80,6 +109,7 @@ start_pinentry (void)
else else
pgmname++; pgmname++;
/* FIXME: We must do this thread specific */
argv[0] = pgmname; argv[0] = pgmname;
if (opt.display) if (opt.display)
{ {
@ -96,7 +126,7 @@ start_pinentry (void)
{ {
log_error ("can't connect to the PIN entry module: %s\n", log_error ("can't connect to the PIN entry module: %s\n",
assuan_strerror (rc)); assuan_strerror (rc));
return seterr (No_PIN_Entry); return unlock_pinentry (seterr (No_PIN_Entry));
} }
entry_ctx = ctx; entry_ctx = ctx;
@ -107,47 +137,47 @@ start_pinentry (void)
opt.no_grab? "OPTION no-grab":"OPTION grab", opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
if (opt.ttyname) if (opt.ttyname)
{ {
char *optstr; char *optstr;
if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 ) if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 )
return GNUPG_Out_Of_Core; return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL); NULL);
free (optstr); free (optstr);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
if (opt.ttytype) if (opt.ttytype)
{ {
char *optstr; char *optstr;
if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 ) if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 )
return GNUPG_Out_Of_Core; return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL); NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
if (opt.lc_ctype) if (opt.lc_ctype)
{ {
char *optstr; char *optstr;
if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 ) if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 )
return GNUPG_Out_Of_Core; return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL); NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
if (opt.lc_messages) if (opt.lc_messages)
{ {
char *optstr; char *optstr;
if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 ) if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 )
return GNUPG_Out_Of_Core; return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL); NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
return 0; return 0;
} }
@ -213,14 +243,14 @@ agent_askpin (const char *desc_text, const char *start_err_text,
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
rc = assuan_transact (entry_ctx, rc = assuan_transact (entry_ctx,
pininfo->min_digits? "SETPROMPT PIN:" pininfo->min_digits? "SETPROMPT PIN:"
: "SETPROMPT Passphrase:", : "SETPROMPT Passphrase:",
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
{ {
@ -242,7 +272,7 @@ agent_askpin (const char *desc_text, const char *start_err_text,
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
errtext = NULL; errtext = NULL;
} }
@ -251,9 +281,9 @@ agent_askpin (const char *desc_text, const char *start_err_text,
errtext = pininfo->min_digits? trans ("PIN too long") errtext = pininfo->min_digits? trans ("PIN too long")
: trans ("Passphrase too long"); : trans ("Passphrase too long");
else if (rc) else if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
if (!errtext && !pininfo->min_digits) if (!errtext && !pininfo->min_digits)
return 0; /* okay, got a passphrase */ return unlock_pinentry (0); /* okay, got a passphrase */
if (!errtext && !all_digitsp (pininfo->pin)) if (!errtext && !all_digitsp (pininfo->pin))
errtext = trans ("Invalid characters in PIN"); errtext = trans ("Invalid characters in PIN");
if (!errtext && pininfo->max_digits if (!errtext && pininfo->max_digits
@ -264,10 +294,11 @@ agent_askpin (const char *desc_text, const char *start_err_text,
errtext = trans ("PIN too short"); errtext = trans ("PIN too short");
if (!errtext) if (!errtext)
return 0; /* okay, got a PIN */ return unlock_pinentry (0); /* okay, got a PIN */
} }
return pininfo->min_digits? GNUPG_Bad_PIN : GNUPG_Bad_Passphrase; return unlock_pinentry (pininfo->min_digits? GNUPG_Bad_PIN
: GNUPG_Bad_Passphrase);
} }
@ -301,13 +332,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase"); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
if (errtext) if (errtext)
{ {
@ -315,28 +346,28 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
memset (&parm, 0, sizeof parm); memset (&parm, 0, sizeof parm);
parm.size = ASSUAN_LINELENGTH/2 - 5; parm.size = ASSUAN_LINELENGTH/2 - 5;
parm.buffer = gcry_malloc_secure (parm.size+10); parm.buffer = gcry_malloc_secure (parm.size+10);
if (!parm.buffer) if (!parm.buffer)
return seterr (Out_Of_Core); return unlock_pinentry (seterr (Out_Of_Core));
assuan_begin_confidential (entry_ctx); assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
if (rc) if (rc)
{ {
xfree (parm.buffer); xfree (parm.buffer);
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1); hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
if (!hexstring) if (!hexstring)
{ {
xfree (parm.buffer); xfree (parm.buffer);
return seterr (Out_Of_Core); return unlock_pinentry (seterr (Out_Of_Core));
} }
for (i=0, p=parm.buffer; *p; p++, i += 2) for (i=0, p=parm.buffer; *p; p++, i += 2)
@ -344,7 +375,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
xfree (parm.buffer); xfree (parm.buffer);
*retpass = hexstring; *retpass = hexstring;
return 0; return unlock_pinentry (0);
} }
@ -370,7 +401,7 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
if (ok) if (ok)
{ {
@ -378,7 +409,7 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
if (cancel) if (cancel)
{ {
@ -386,11 +417,11 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc); return unlock_pinentry (map_assuan_err (rc));
} }

View File

@ -1,3 +1,7 @@
2002-05-23 Werner Koch <wk@gnupg.org>
* no-pth.c, Makefile.am: Removed.
2002-05-22 Werner Koch <wk@gnupg.org> 2002-05-22 Werner Koch <wk@gnupg.org>
* mkdtemp.c: Replaced byte by unsigned char because it is no longer * mkdtemp.c: Replaced byte by unsigned char because it is no longer

View File

@ -32,7 +32,6 @@ libcommon_a_SOURCES = \
errors.c errors.h \ errors.c errors.h \
maperror.c \ maperror.c \
sysutils.c sysutils.h \ sysutils.c sysutils.h \
no-pth.c \
cryptmiss.c \ cryptmiss.c \
gettime.c gettime.c

View File

@ -1,54 +0,0 @@
/* no-pth.c - stubs to avoid linking against PTH
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#ifdef USE_GNU_PTH /*we need the stubs only in this case */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pth.h>
#if PTH_SYSCALL_SOFT
# error this file cannot be used with PTH syscall divertion
#endif
ssize_t
pth_read (int a, void *b , size_t c)
{
return read (a, b, c);
}
ssize_t
pth_write (int a, const void *b, size_t c)
{
return write (a, b, c);
}
int
pth_accept (int a, struct sockaddr *b, socklen_t *c)
{
return accept (a, b, c);
}
#endif /*USE_GNU_PTH*/