* 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>
* cache.c (housekeeping, agent_put_cache): Use our time() wrapper.

View File

@ -21,7 +21,7 @@
bin_PROGRAMS = gpg-agent
noinst_PROGRAMS = protect-tool
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS)
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) $(PTH_CFLAGS)
LDFLAGS = @LDFLAGS@
gpg_agent_SOURCES = \
@ -43,7 +43,7 @@ gpg_agent_SOURCES = \
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.c \

View File

@ -104,7 +104,7 @@ void agent_exit (int rc); /* also implemented in other tools */
const char *trans (const char *text);
/*-- command.c --*/
void start_command_handler (int);
void start_command_handler (int, int);
/*-- findkey.c --*/
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 --*/
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 --*/

View File

@ -40,6 +40,7 @@ struct cache_item_s {
time_t created;
time_t accessed;
int ttl; /* max. lifetime given in seonds */
int lockcount;
struct secret_data_s *pw;
char key[1];
};
@ -87,7 +88,7 @@ housekeeping (void)
/* first expire the actual data */
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)
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
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)
{
if (r->pw && r->created + 60*60 < current)
if (!r->lockcount && r->pw && r->created + 60*60 < current)
{
if (DBG_CACHE)
log_debug (" expired `%s' (1h after creation)\n", r->key);
@ -118,15 +119,27 @@ housekeeping (void)
{
if (!r->pw && r->accessed + 60*30 < current)
{
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;
if (r->lockcount)
{
log_error ("can't remove unused cache entry `%s' due to"
" lockcount=%d\n",
r->key, r->lockcount);
r->accessed += 60*10; /* next error message in 10 minutes */
rprev = r;
r = r->next;
}
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
{
@ -158,7 +171,7 @@ agent_put_cache (const char *key, const char *data, int ttl)
for (r=thecache; r; r = r->next)
{
if ( !strcmp (r->key, key))
if (!r->lockcount && !strcmp (r->key, key))
break;
}
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 */
const char *
agent_get_cache (const char *key)
agent_get_cache (const char *key, void **cache_id)
{
ITEM r;
int count = 0;
if (DBG_CACHE)
log_debug ("agent_get_cache `%s'...\n", key);
housekeeping ();
/* FIXME: Returning pointers is not thread safe - add a reference
counter */
for (r=thecache; r; r = r->next, count++)
/* first try to find one with no locks - this is an updated cache
entry: We might have entries with a lockcount and without a
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
don't need the lengths */
r->accessed = gnupg_get_time ();
if (DBG_CACHE)
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;
}
}
if (DBG_CACHE)
log_debug ("... miss\n");
*cache_id = 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
*/
/* 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 <errno.h>
#include <stdio.h>
@ -27,6 +33,9 @@
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h"
#include "../assuan/assuan.h"
@ -38,6 +47,9 @@
#endif
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 */
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
release and return the buffer. Allocation errors are detected but
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 */
static int
start_scd (void)
@ -131,6 +157,14 @@ start_scd (void)
ASSUAN_CONTEXT ctx;
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)
return 0; /* No need to serialize things because the agent is
expected to tun as a single-thread (or may be in
@ -142,7 +176,7 @@ start_scd (void)
if (fflush (NULL))
{
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 */
@ -163,7 +197,7 @@ start_scd (void)
{
log_error ("can't connect to the SCdaemon: %s\n",
assuan_strerror (rc));
return seterr (No_Scdaemon);
return unlock_scd (seterr (No_Scdaemon));
}
scd_ctx = ctx;
@ -218,9 +252,9 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg)
NULL, NULL, NULL, NULL,
learn_status_cb, &parm);
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 */
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
rc = assuan_transact (scd_ctx, "SERIALNO",
NULL, NULL, NULL, NULL,
@ -282,10 +316,10 @@ agent_card_serialno (char **r_serialno)
if (rc)
{
xfree (serialno);
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
}
*r_serialno = serialno;
return 0;
return unlock_scd (0);
}
@ -354,7 +388,7 @@ agent_card_pksign (const char *keyid,
return rc;
if (indatalen*2 + 50 > DIM(line))
return seterr (General_Error);
return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA ");
p = line + strlen (line);
@ -362,7 +396,7 @@ agent_card_pksign (const char *keyid,
sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024);
inqparm.ctx = scd_ctx;
@ -377,7 +411,7 @@ agent_card_pksign (const char *keyid,
if (rc)
{
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
}
sigbuf = get_membuf (&data, &sigbuflen);
@ -388,7 +422,7 @@ agent_card_pksign (const char *keyid,
if (!*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" );
sprintf (p, "%u:", (unsigned int)sigbuflen);
@ -399,7 +433,7 @@ agent_card_pksign (const char *keyid,
xfree (sigbuf);
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 */
@ -423,7 +457,7 @@ agent_card_pkdecrypt (const char *keyid,
/* FIXME: use secure memory where appropriate */
if (indatalen*2 + 50 > DIM(line))
return seterr (General_Error);
return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA ");
p = line + strlen (line);
@ -431,7 +465,7 @@ agent_card_pkdecrypt (const char *keyid,
sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024);
inqparm.ctx = scd_ctx;
@ -446,13 +480,13 @@ agent_card_pkdecrypt (const char *keyid,
if (rc)
{
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, r_buflen);
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)
{
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, r_buflen);
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)
{
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, &buflen);
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))
{
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 *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
char *p;
void *cache_marker;
/* parse the stuff */
for (p=line; *p == ' '; p++)
@ -417,17 +418,18 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
desc = NULL;
/* 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)
{
assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, pw);
agent_unlock_cache_entry (&cache_marker);
}
else
{
/* Note, that we only need to repalce the + characters and
should leave the other escaping in place becuase the escaped
sting is send verbatim to the pinentry which does the
/* Note, that we only need to replace the + characters and
should leave the other escaping in place because the escaped
string is send verbatim to the pinentry which does the
unescaping (but not the + replacing) */
if (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 */
void
start_command_handler (int listen_fd)
start_command_handler (int listen_fd, int fd)
{
int rc;
ASSUAN_CONTEXT ctx;
struct server_control_s ctrl;
memset (&ctrl, 0, sizeof ctrl);
if (listen_fd == -1)
if (listen_fd == -1 && fd == -1)
{
int filedes[2];
@ -613,10 +614,14 @@ start_command_handler (int listen_fd)
filedes[1] = 1;
rc = assuan_init_pipe_server (&ctx, filedes);
}
else
else if (listen_fd != -1)
{
rc = assuan_init_socket_server (&ctx, listen_fd);
}
else
{
rc = assuan_init_connected_socket_server (&ctx, fd);
}
if (rc)
{
log_error ("failed to initialize the server: %s\n",
@ -664,5 +669,3 @@ start_command_handler (int listen_fd)
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
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)
{
rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
agent_unlock_cache_entry (&cache_marker);
if (!rc)
{
xfree (*keybuf);

View File

@ -33,6 +33,9 @@
#include <sys/un.h>
#include <unistd.h>
#include <signal.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include <gcrypt.h>
@ -113,7 +116,13 @@ static ARGPARSE_OPTS opts[] = {
};
#ifndef USE_GNU_PTH
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 */
static int maybe_setuid = 1;
@ -122,6 +131,11 @@ static int maybe_setuid = 1;
static char socket_name[128];
#ifdef USE_GNU_PTH
static void handle_connections (int listen_fd);
#endif
static const char *
my_strusage (int level)
@ -205,6 +219,7 @@ cleanup (void)
}
#ifndef USE_GNU_PTH
static RETSIGTYPE
cleanup_sh (int sig)
{
@ -226,6 +241,7 @@ cleanup_sh (int sig)
#endif
raise( sig );
}
#endif /*!USE_GNU_PTH*/
int
main (int argc, char **argv )
@ -265,6 +281,9 @@ main (int argc, char **argv )
}
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_control (GCRYCTL_USE_SECURE_RNDPOOL);
@ -447,7 +466,7 @@ main (int argc, char **argv )
if (pipe_server)
{ /* this is the simple pipe based server */
start_command_handler (-1);
start_command_handler (-1, -1);
}
else
{ /* regular server mode */
@ -574,6 +593,7 @@ main (int argc, char **argv )
/*NEVER REACHED*/
} /* end parent */
/* this is the child */
/* 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 */
{
struct sigaction oact, nact;
@ -610,15 +646,8 @@ main (int argc, char **argv )
sigaction (SIGPIPE, &nact, NULL);
sigaction (SIGINT, &nact, NULL);
}
if (chdir("/"))
{
log_error ("chdir to / failed: %s\n", strerror (errno));
exit (1);
}
start_command_handler (fd);
start_command_handler (fd, -1);
#endif /*!USE_GNU_PTH*/
close (fd);
}
@ -628,10 +657,7 @@ main (int argc, char **argv )
void
agent_exit (int rc)
{
#if 0
#warning no update_random_seed_file
update_random_seed_file();
#endif
/*FIXME: update_random_seed_file();*/
#if 0
/* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE)
@ -647,3 +673,144 @@ agent_exit (int 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 <unistd.h>
#include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h"
#include "../assuan/assuan.h"
@ -38,6 +41,9 @@
#endif
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 */
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
start_pinentry (void)
{
@ -58,10 +81,16 @@ start_pinentry (void)
ASSUAN_CONTEXT ctx;
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)
return 0; /* No need to serialize things becuase the agent is
expected to tun as a single-thread (or may be in
future using libpth) */
return 0;
if (opt.verbose)
log_info ("no running PIN Entry - starting it\n");
@ -69,7 +98,7 @@ start_pinentry (void)
if (fflush (NULL))
{
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 */
@ -80,6 +109,7 @@ start_pinentry (void)
else
pgmname++;
/* FIXME: We must do this thread specific */
argv[0] = pgmname;
if (opt.display)
{
@ -96,7 +126,7 @@ start_pinentry (void)
{
log_error ("can't connect to the PIN entry module: %s\n",
assuan_strerror (rc));
return seterr (No_PIN_Entry);
return unlock_pinentry (seterr (No_PIN_Entry));
}
entry_ctx = ctx;
@ -107,47 +137,47 @@ start_pinentry (void)
opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
if (opt.ttyname)
{
char *optstr;
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,
NULL);
free (optstr);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.ttytype)
{
char *optstr;
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,
NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.lc_ctype)
{
char *optstr;
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,
NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.lc_messages)
{
char *optstr;
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,
NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
return 0;
}
@ -213,14 +243,14 @@ agent_askpin (const char *desc_text, const char *start_err_text,
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
rc = assuan_transact (entry_ctx,
pininfo->min_digits? "SETPROMPT PIN:"
: "SETPROMPT Passphrase:",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
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;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
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")
: trans ("Passphrase too long");
else if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
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))
errtext = trans ("Invalid characters in PIN");
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");
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;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
if (errtext)
{
@ -315,28 +346,28 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
memset (&parm, 0, sizeof parm);
parm.size = ASSUAN_LINELENGTH/2 - 5;
parm.buffer = gcry_malloc_secure (parm.size+10);
if (!parm.buffer)
return seterr (Out_Of_Core);
return unlock_pinentry (seterr (Out_Of_Core));
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
if (rc)
{
xfree (parm.buffer);
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
if (!hexstring)
{
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)
@ -344,7 +375,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
xfree (parm.buffer);
*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;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
if (ok)
{
@ -378,7 +409,7 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
return unlock_pinentry (map_assuan_err (rc));
}
if (cancel)
{
@ -386,11 +417,11 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
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);
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>
* 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 \
maperror.c \
sysutils.c sysutils.h \
no-pth.c \
cryptmiss.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*/