aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--agent/ChangeLog9
-rw-r--r--agent/agent.h4
-rw-r--r--agent/command.c41
-rw-r--r--agent/gpg-agent.c821
-rw-r--r--agent/query.c1
5 files changed, 223 insertions, 653 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 9c66e22f0..95285c347 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,12 @@
+2002-01-19 Werner Koch <[email protected]>
+
+ * gpg-agent.c: Removed unused cruft and implement the socket
+ based server.
+ (my_strusage): Take bug report address from configure.ac.
+ * command.c (start_command_handler): Add an argument to start as
+ regular server.
+ (start_command_handler): Enable Assuan logging.
+
2002-01-15 Werner Koch <[email protected]>
* trustlist.c: New.
diff --git a/agent/agent.h b/agent/agent.h
index 9f2b69cc2..ad0a6e8b7 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -47,12 +47,14 @@ struct {
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
+#define DBG_ASSUAN_VALUE 1024
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
+#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
struct server_local_s;
@@ -87,7 +89,7 @@ void agent_exit (int rc);
const char *trans (const char *text);
/*-- command.c --*/
-void start_command_handler (void);
+void start_command_handler (int);
/*-- findkey.c --*/
GCRY_SEXP agent_key_from_file (const unsigned char *grip);
diff --git a/agent/command.c b/agent/command.c
index 9d9c7a0e8..bde3835ab 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -269,7 +269,7 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
/* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
This function is usually used to ask for a passphrase to be used
- for conventional encryption, but may aslo be used by programs which
+ for conventional encryption, but may also be used by programs which
need specal handling of passphrases. This command uses a syntax
which helps clients to use the agent with minimum effort. The
agent either returns with an error or with a OK followed by the hex
@@ -287,11 +287,12 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
/* FIXME: Parse that stuff */
desc = "We need a passphrase";
prompt = NULL;
- errtext = "try again";
+ errtext = NULL;
rc = agent_get_passphrase (&response, desc, prompt, errtext);
if (!rc)
{
+ assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, response);
xfree (response);
}
@@ -303,7 +304,7 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
/* CLEAR_PASSPHRASE <cache_id>
may be used to invalidate the cache entry for a passphrase. The
- function returns with OK even when ther eis no cached passphrase.
+ function returns with OK even when there is no cached passphrase.
*/
static int
@@ -359,23 +360,30 @@ register_commands (ASSUAN_CONTEXT ctx)
}
-/* Startup the server */
+/* Startup the server. If LISTEN_FD is given as -1, this is simple
+ piper server, otherwise it is a regular server */
void
-start_command_handler (void)
+start_command_handler (int listen_fd)
{
int rc;
- int filedes[2];
ASSUAN_CONTEXT ctx;
struct server_control_s ctrl;
memset (&ctrl, 0, sizeof ctrl);
- /* For now we use a simple pipe based server so that we can work
- from scripts. We will later add options to run as a daemon and
- wait for requests on a Unix domain socket */
- filedes[0] = 0;
- filedes[1] = 1;
- rc = assuan_init_pipe_server (&ctx, filedes);
+
+ if (listen_fd == -1)
+ {
+ int filedes[2];
+
+ filedes[0] = 0;
+ filedes[1] = 1;
+ rc = assuan_init_pipe_server (&ctx, filedes);
+ }
+ else
+ {
+ rc = assuan_init_socket_server (&ctx, listen_fd);
+ }
if (rc)
{
log_error ("failed to initialize the server: %s\n",
@@ -385,7 +393,7 @@ start_command_handler (void)
rc = register_commands (ctx);
if (rc)
{
- log_error ("failed to the register commands with Assuan: %s\n",
+ log_error ("failed to register commands with Assuan: %s\n",
assuan_strerror(rc));
agent_exit (2);
}
@@ -395,6 +403,9 @@ start_command_handler (void)
ctrl.server_local->assuan_ctx = ctx;
ctrl.server_local->message_fd = -1;
+ if (DBG_ASSUAN)
+ assuan_set_log_stream (ctx, log_get_stream ());
+
for (;;)
{
rc = assuan_accept (ctx);
@@ -417,6 +428,8 @@ start_command_handler (void)
}
- assuan_deinit_pipe_server (ctx);
+ assuan_deinit_server (ctx);
}
+
+
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index de33825fd..6dca9631b 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -29,6 +29,8 @@
#include <assert.h>
#include <time.h>
#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#include <signal.h>
@@ -60,9 +62,6 @@ enum cmd_and_opt_values
oHomedir,
oNoDetach,
oNoGrab,
- oClient,
- oShutdown,
- oFlush,
oLogFile,
oServer,
oBatch,
@@ -88,11 +87,7 @@ static ARGPARSE_OPTS opts[] = {
{ oDebugWait,"debug-wait",1, "@"},
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
{ oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")},
- { oClient, "client" ,0, N_("run in client mode for testing")},
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
- { oShutdown, "shutdown" ,0, N_("shutdown the agent")},
- { oFlush , "flush" ,0, N_("flush the cache")},
- { oBatch , "batch" ,0, N_("run without asking a user")},
{ oPinentryProgram, "pinentry-program", 2 , "Path of PIN Entry program" },
@@ -101,64 +96,38 @@ static ARGPARSE_OPTS opts[] = {
};
-
-typedef struct {
- int used;
- char fpr[20];
- char *pw;
- size_t pwlen;
- size_t totlen;
-} CACHE_SLOT;
-
-#define MAX_CACHE_ENTRIES 10
-#define MAX_CACHE_AGE 1000 /* should fit into an integer */
static volatile int caught_fatal_sig = 0;
-static volatile int shut_me_down = 0;
-/* static CACHE_SLOT the_cache[MAX_CACHE_ENTRIES]; */
-static char *socket_name = NULL;
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
-
-#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
- (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
-#define u32tobuf( p, a ) do { \
- ((byte*)p)[0] = (byte)((a) >> 24); \
- ((byte*)p)[1] = (byte)((a) >> 16); \
- ((byte*)p)[2] = (byte)((a) >> 8); \
- ((byte*)p)[3] = (byte)((a) ); \
- } while(0)
-
-
-static int start_listening ( const char *name );
+/* Name of the communication socket */
+static char socket_name[128];
static const char *
-my_strusage( int level )
+my_strusage (int level)
{
- const char *p;
- switch( level ) {
- case 11: p = "gpg-agent (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p =
- _("Please report bugs to <[email protected]>.\n");
- break;
- case 1:
- case 40: p =
- _("Usage: gpg-agent [options] (-h for help)");
- break;
- case 41: p =
- _("Syntax: gpg-agent [options] [command [args]]\n"
- "Secret key management for GnuPG\n");
- break;
-
- default: p = NULL;
+ const char *p;
+ switch (level)
+ {
+ case 11: p = "gpg-agent (GnuPG)";
+ break;
+ case 13: p = VERSION; break;
+ case 17: p = PRINTABLE_OS_NAME; break;
+ case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
+ break;
+ case 1:
+ case 40: p = _("Usage: gpg-agent [options] (-h for help)");
+ break;
+ case 41: p = _("Syntax: gpg-agent [options] [command [args]]\n"
+ "Secret key management for GnuPG\n");
+ break;
+
+ default: p = NULL;
}
- return p;
+ return p;
}
@@ -166,28 +135,17 @@ my_strusage( int level )
static void
i18n_init (void)
{
- #ifdef USE_SIMPLE_GETTEXT
+#ifdef USE_SIMPLE_GETTEXT
set_gettext_file( PACKAGE );
- #else
- #ifdef ENABLE_NLS
+#else
+#ifdef ENABLE_NLS
/* gtk_set_locale (); HMMM: We have not yet called gtk_init */
bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
textdomain( PACKAGE );
- #endif
- #endif
+#endif
+#endif
}
-static void
-cleanup (void)
-{
- if (socket_name)
- {
- char *p = socket_name;
- socket_name = NULL;
- remove ( p );
- gcry_free (p);
- }
-}
/* Use by gcry for logging */
@@ -210,13 +168,32 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
}
+static void
+cleanup (void)
+{
+ if (*socket_name)
+ {
+ char *p;
+
+ remove (socket_name);
+ p = strrchr (socket_name, '/');
+ if (p)
+ {
+ *p = 0;
+ rmdir (socket_name);
+ *p = '/';
+ }
+ *socket_name = 0;
+ }
+}
+
+
static RETSIGTYPE
cleanup_sh (int sig)
{
if (caught_fatal_sig)
raise (sig);
caught_fatal_sig = 1;
- shut_me_down = 1;
/* gcry_control( GCRYCTL_TERM_SECMEM );*/
cleanup ();
@@ -248,10 +225,7 @@ main (int argc, char **argv )
int default_config =1;
int greeting = 0;
int nogreeting = 0;
- int server_mode = 0;
- int client = 0;
- int do_shutdown = 0;
- int do_flush = 0;
+ int pipe_server = 0;
int nodetach = 0;
int grab = 0;
int csh_style = 0;
@@ -280,7 +254,6 @@ main (int argc, char **argv )
may_coredump = 0/* FIXME: disable_core_dumps()*/;
-
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1;
@@ -389,13 +362,10 @@ main (int argc, char **argv )
case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oNoDetach: nodetach = 1; break;
case oNoGrab: grab = 0; break;
- case oClient: client = 1; break;
- case oShutdown: client = 1; do_shutdown = 1; break;
- case oFlush: client = 1; do_flush = 1; break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; break;
- case oServer: server_mode = 1; break;
+ case oServer: pipe_server = 1; break;
case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
@@ -427,183 +397,169 @@ main (int argc, char **argv )
log_info ("NOTE: this is a development version!\n");
#endif
- socket_name = make_filename (opt.homedir, "S.gpg-agent", NULL );
- if (strchr ( socket_name, ':') )
+
+ if (atexit (cleanup))
{
- log_error ("colons are not allowed in the socket name\n");
+ log_error ("atexit failed\n");
+ cleanup ();
exit (1);
}
-
- if (client)
- { /* a client for testing this agent */
-#if 0 /* FIXME: We are going to use assuan here */
- int fd;
- struct sockaddr_un client_addr;
- size_t len;
- char buffer[1000];
- int nread;
-
- if ( strlen (socket_name)+1 >= sizeof client_addr.sun_path ) {
- log_error ("name of socket to long\n");
- exit (1);
- }
-
- if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
- log_fatal("can't create socket: %s\n", strerror(errno) );
- memset( &client_addr, 0, sizeof client_addr );
- client_addr.sun_family = AF_UNIX;
- strcpy( client_addr.sun_path, socket_name );
- len = offsetof (struct sockaddr_un, sun_path)
- + strlen(client_addr.sun_path) + 1;
+ if (debug_wait && pipe_server)
+ {
+ log_debug ("waiting for debugger - my pid is %u .....\n",
+ (unsigned int)getpid());
+ sleep (debug_wait);
+ log_debug ("... okay\n");
+ }
+
+ /* now start with logging to a file if this is desired */
+ if (logfile)
+ {
+ log_set_file (logfile);
+ log_set_prefix (NULL, 1|2|4);
+ }
- if( connect( fd, (struct sockaddr*)&client_addr, len ) == -1 ) {
- log_error ( "connect() failed: %s\n", strerror (errno) );
- exit (1);
- }
- if ( do_shutdown ) {
- u32tobuf (buffer+4, GPGA_PROT_SHUTDOWN );
- nread = 4;
- }
- else if ( do_flush ) {
- u32tobuf (buffer+4, GPGA_PROT_FLUSH );
- nread = 4;
- }
- else {
- nread = fread ( buffer+4, 1, DIM(buffer)-4, stdin );
-
- if ( opt.verbose )
- log_info ( "%d bytes read from stdin\n", nread );
- }
- u32tobuf (buffer, nread );
- writen ( fd, "GPGA\0\0\0\x01", 8 );
- writen ( fd, buffer, nread + 4 );
- /* now read the response */
- readn ( fd, buffer, DIM(buffer), &nread );
- if ( opt.verbose )
- log_info ( "%d bytes got from agent\n", nread );
-
- fwrite ( buffer, 1, nread, stdout );
- close (fd );
-#endif
+ if (pipe_server)
+ { /* this is the simple pipe based server */
+ start_command_handler (-1);
}
- else if (server_mode)
- { /* for now this is the simple pipe based server */
- if (logfile)
+ else
+ { /* regular server mode */
+ int fd;
+ pid_t pid;
+ int i;
+ int len;
+ struct sockaddr_un serv_addr;
+ char *p;
+
+ *socket_name = 0;
+ snprintf (socket_name, DIM(socket_name)-1,
+ "/tmp/gpg-XXXXXX/S.gpg-agent");
+ socket_name[DIM(socket_name)-1] = 0;
+ p = strrchr (socket_name, '/');
+ if (!p)
+ BUG ();
+ *p = 0;;
+ if (!mkdtemp(socket_name))
{
- log_set_file (logfile);
- log_set_prefix (NULL, 1|2|4);
+ log_error ("can't create directory `%s': %s\n",
+ socket_name, strerror(errno) );
+ exit (1);
}
-
- if ( atexit( cleanup ) )
+ *p = '/';
+
+ if (strchr (socket_name, ':') )
{
- log_error ("atexit failed\n");
- cleanup ();
+ log_error ("colons are not allowed in the socket name\n");
exit (1);
}
+ if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
+ {
+ log_error ("name of socket to long\n");
+ exit (1);
+ }
+
- if (debug_wait)
+ fd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1)
{
- log_debug ("waiting for debugger - my pid is %u .....\n",
- (unsigned int)getpid());
- sleep (debug_wait);
- log_debug ("... okay\n");
- }
- start_command_handler ();
- }
- else
- { /* regular server mode */
- int listen_fd;
- pid_t child;
- int i;
-
- listen_fd = start_listening (socket_name);
- if (listen_fd == -1)
+ log_error ("can't create socket: %s\n", strerror(errno) );
+ exit (1);
+ }
+
+ memset (&serv_addr, 0, sizeof serv_addr);
+ serv_addr.sun_family = AF_UNIX;
+ strcpy (serv_addr.sun_path, socket_name);
+ len = (offsetof (struct sockaddr_un, sun_path)
+ + strlen(serv_addr.sun_path) + 1);
+
+ if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
+ {
+ log_error ("error binding socket to `%s': %s\n",
+ serv_addr.sun_path, strerror (errno) );
+ close (fd);
+ exit (1);
+ }
+
+ if (listen (fd, 5 ) == -1)
{
- cleanup ();
+ log_error ("listen() failed: %s\n", strerror (errno));
+ close (fd);
exit (1);
}
+ if (opt.verbose)
+ log_info ("listening on socket `%s'\n", socket_name );
+
fflush (NULL);
- child = fork ();
- if (child == -1)
+ pid = fork ();
+ if (pid == (pid_t)-1)
{
log_fatal ("fork failed: %s\n", strerror (errno) );
- cleanup ();
exit (1);
}
- else if ( child )
- { /* parent */
+ else if (pid)
+ { /* we are the parent */
char *infostr;
- close (listen_fd );
+ close (fd);
- /* create the info string */
- infostr = xmalloc ( 20 + strlen(socket_name) + 30 + 2 );
- sprintf ( infostr, "GPG_AGENT_INFO=%s:%lu",
- socket_name, (ulong)child );
- if ( argc )
+ /* create the info string: <name>:<pid>:<protocol_version> */
+ if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
+ socket_name, (ulong)pid ) < 0)
+ {
+ log_error ("out of core\n");
+ kill (pid, SIGTERM);
+ exit (1);
+ }
+ *socket_name = 0; /* don't let cleanup() remove the socket -
+ the child should do this from now on */
+ if (argc)
{ /* run the program given on the commandline */
if (putenv (infostr))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
- kill (child, SIGTERM );
- cleanup ();
+ kill (pid, SIGTERM );
exit (1);
}
execvp (argv[0], argv);
- log_error ("failed to run the command: %s\n",
- strerror (errno));
- kill (child, SIGTERM);
- cleanup ();
+ log_error ("failed to run the command: %s\n", strerror (errno));
+ kill (pid, SIGTERM);
exit (1);
}
- /* print the environment string, so that the caller can use
- eval to set it */
- if (csh_style)
- {
- *strchr (infostr, '=') = ' ';
- printf ( "setenv %s\n", infostr);
- }
else
{
- printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
- }
- exit (0);
+ /* print the environment string, so that the caller can use
+ shell's eval to set it */
+ if (csh_style)
+ {
+ *strchr (infostr, '=') = ' ';
+ printf ( "setenv %s\n", infostr);
+ }
+ else
+ {
+ printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
+ }
+ free (infostr);
+ exit (0);
+ }
+ /*NEVER REACHED*/
} /* end parent */
+
+ /* this is the child */
- if ( (opt.debug & 1) )
- {
- fprintf (stderr, "... 20 seconds to attach the debugger ...");
- fflush (stderr);
- sleep( 20 ); /* give us some time to attach gdb to the child */
- putc ('\n', stderr);
- }
-
- if (logfile)
- {
- log_set_file (logfile);
- log_set_prefix (NULL, 1|2|4);
- }
-
- if ( atexit( cleanup ) )
- {
- log_error ("atexit failed\n");
- cleanup ();
- exit (1);
- }
-
- if ( !nodetach )
- {
- for (i=0 ; i <= 2; i++ )
+ /* detach from tty and put process into a new session */
+ if (!nodetach )
+ { /* close stdin, stdout and stderr unless it is the log stream */
+ for (i=0; i <= 2; i++)
{
if ( log_get_fd () != i)
- close ( i );
+ close (i);
}
-
if (setsid() == -1)
{
log_error ("setsid() failed: %s\n", strerror(errno) );
@@ -612,52 +568,34 @@ main (int argc, char **argv )
}
}
+ /* setup signals */
{
struct sigaction oact, nact;
nact.sa_handler = cleanup_sh;
- sigemptyset ( &nact.sa_mask );
+ sigemptyset (&nact.sa_mask);
nact.sa_flags = 0;
- sigaction ( SIGHUP, NULL, &oact );
- if ( oact.sa_handler != SIG_IGN )
- sigaction( SIGHUP, &nact, NULL);
+ sigaction (SIGHUP, NULL, &oact);
+ if (oact.sa_handler != SIG_IGN)
+ sigaction (SIGHUP, &nact, NULL);
sigaction( SIGTERM, NULL, &oact );
- if ( oact.sa_handler != SIG_IGN )
- sigaction( SIGTERM, &nact, NULL);
+ if (oact.sa_handler != SIG_IGN)
+ sigaction (SIGTERM, &nact, NULL);
nact.sa_handler = SIG_IGN;
- sigaction( SIGPIPE, &nact, NULL );
- sigaction( SIGINT, &nact, NULL );
+ sigaction (SIGPIPE, &nact, NULL);
+ sigaction (SIGINT, &nact, NULL);
}
- if ( chdir("/") )
+ if (chdir("/"))
{
- log_error ("chdir to / failed: %s\n", strerror (errno) );
+ log_error ("chdir to / failed: %s\n", strerror (errno));
exit (1);
}
- /* for now there is no need for concurrent requests because we
- are asking for passphrases which might pop up a window to get
- the users respond. In future the agent may provide other
- services which won't need a user interaction */
-#if 0
- while (!shut_me_down)
- {
- struct sockaddr_un clnt_addr;
- size_t len = sizeof clnt_addr;
- int fd;
- /* FIXME: convert to assuan */
- fd = accept ( listen_fd, (struct sockaddr*)&clnt_addr, &len );
- if ( fd == -1 )
- log_error ( "accept() failed: %s\n", strerror (errno));
- else
- {
- process_request ( fd );
- close (fd );
- }
- }
-#endif
- close (listen_fd);
+ start_command_handler (fd);
+
+ close (fd);
}
return 0;
@@ -685,396 +623,3 @@ agent_exit (int rc)
exit (rc);
}
-
-static int
-start_listening (const char *name)
-{
-#if 0
- int len;
- int fd;
- struct sockaddr_un serv_addr;
-
- if (opt.verbose)
- log_info ("using socket `%s'\n", socket_name );
-
- if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
- {
- log_error ("name of socket to long\n");
- return -1;
- }
-
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
- log_fatal("can't create socket: %s\n", strerror(errno) );
-
- memset( &serv_addr, 0, sizeof serv_addr );
- serv_addr.sun_family = AF_UNIX;
- strcpy( serv_addr.sun_path, socket_name );
- len = (offsetof (struct sockaddr_un, sun_path)
- + strlen(serv_addr.sun_path) + 1);
-
- remove (socket_name); errno = 0;
- if (bind( fd, (struct sockaddr*)&serv_addr, len ) == -1 )
- {
- log_error ( "error binding address `%s': %m\n", serv_addr.sun_path );
- close (fd );
- return -1;
- }
-
- if (listen (fd, 5 ) == -1)
- {
- log_error ( "listen() failed: %s\n", strerror (errno) );
- close ( fd );
- return -1;
- }
-#endif
- return -1;
-}
-
-#if 0
-/* Look for the passprase as given by the 20 bytes DATA and return it's
- slot number. If this passphrase is not in the cache, return -1 */
-static int
-open_cached_passphrase ( const char *fpr )
-{
- int i;
-
- for (i=0; i < MAX_CACHE_ENTRIES; i++ )
- {
- if (the_cache[i].used && !memcmp (the_cache[i].fpr, fpr, 20))
- {
- if ( the_cache[i].used < MAX_CACHE_AGE )
- the_cache[i].used++;
- return i;
- }
- }
-
- return -1;
-}
-
-/* Get pointers to the cached passphrase and return the real length
- PWLEN as well as the somewhat larger BLOCKLEN */
-static const char *
-read_cached_passphrase (int slot, size_t *pwlen, size_t *blocklen)
-{
- assert (slot >=0 && slot < MAX_CACHE_ENTRIES);
- *pwlen = the_cache[slot].pwlen;
- *blocklen = the_cache[slot].totlen;
- return the_cache[slot].pw;
-}
-
-static const void
-clear_cached_passphrase ( int slot )
-{
- assert ( slot >=0 && slot < MAX_CACHE_ENTRIES );
- xfree (the_cache[slot].pw );
- the_cache[slot].pw = NULL;
- the_cache[slot].used = 0;
-}
-
-static void
-close_cached_passphrase ( int slot )
-{
- /* not yet needed */
-}
-
-
-static void
-set_cached_passphrase ( const char *fpr, const char *pw )
-{
- int i, min_used = MAX_CACHE_AGE, slot = -1;
-
- for (i=0; i < 20 && !fpr[i]; i++ )
- ;
- if (i== 20)
- return; /* never cache an all empty fingerprint */
-
- /* first see whether we have already cached this one */
- for (i=0; i < MAX_CACHE_ENTRIES; i++ )
- {
- if ( the_cache[i].used && !memcmp (the_cache[i].fpr, fpr, 20) )
- {
- slot = i;
- break;
- }
- }
-
- if (slot == -1)
- { /* Find an unused one or reuse one */
- for (i=0; i < MAX_CACHE_ENTRIES; i++ )
- {
- if ( !the_cache[i].used ) {
- slot = i;
- break;
- }
- if ( the_cache[i].used < min_used )
- {
- min_used = the_cache[i].used;
- slot = i;
- }
- }
- assert ( slot != -1 );
- }
- xfree (the_cache[slot].pw);
- /* fixme: Allocate to fixed sizes */
- the_cache[slot].used = 1;
- memcpy (the_cache[slot].fpr, fpr, 20 );
- the_cache[slot].pw = gcry_xstrdup ( pw );
- the_cache[slot].pwlen = strlen ( pw );
- the_cache[slot].totlen = strlen ( pw );
-}
-
-
-
-static int
-passphrase_dialog ( const byte *fpr, const char *user_string )
-{
- /* FIXME: call the PIN-ENtry */
-
- return 0;
-}
-
-
-static int
-writen ( int fd, const void *buf, size_t nbytes )
-{
- size_t nleft = nbytes;
- ssize_t nwritten;
-
- while (nleft > 0)
- {
- nwritten = write( fd, buf, nleft );
- if ( nwritten < 0 )
- {
- log_error ( "writen() failed: %s\n", strerror (errno) );
- return -1;
- }
- nleft -= nwritten;
- buf = (const char*)buf + nwritten;
- }
- return 0;
-}
-
-
-static int
-readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
-{
- size_t nleft = buflen;
- int nread;
- char *p;
-
- p = buf;
- while (nleft > 0 )
- {
- nread = read ( fd, buf, nleft );
- if ( nread < 0 )
- {
- log_error ( "read() error: %s\n", strerror (errno) );
- return -1;
- }
- else if (!nread )
- break; /* EOF */
- nleft -= nread;
- buf = (char*)buf + nread;
- }
- if (ret_nread )
- *ret_nread = buflen - nleft;
- return 0;
-}
-
-
-
-
-static void
-reply_error ( int fd, int x )
-{
- /*FIXME:*/
-}
-
-static void
-reply ( int fd, int x, const char *data, size_t datalen )
-{
- /*FIXME:*/
-}
-
-static void
-req_get_version ( int fd, const char *data, size_t datalen )
-{
- /*FIXME:*/
-}
-
-static void
-req_get_passphrase ( int fd, const char *data, size_t datalen )
-{
-#if 0
- int slot;
- const char *pw;
- size_t pwlen, blocklen;
-
- if (datalen < 20)
- {
- reply_error ( fd, GPGA_PROT_INVALID_DATA );
- return;
- }
-
- slot = open_cached_passphrase ( data );
- if ( slot == -1 )
- {
- int rc;
- char *string;
-
- if ( datalen > 20 )
- {
- string = xmalloc ( datalen - 20 + 1 );
- memcpy (string, data+20, datalen-20 );
- string[datalen-20] = 0;
- }
- else
- {
- string = xstrdup ("[fingerprint]");
- }
- rc = passphrase_dialog ( data, string );
- xfree (string);
- if (rc)
- {
- reply_error ( fd, rc );
- return;
- }
- slot = open_cached_passphrase ( data );
- if (slot < 0)
- BUG ();
- }
-
- pw = read_cached_passphrase ( slot, &pwlen, &blocklen );
- if (!pw || blocklen < pwlen)
- BUG ();
-#if 0 /* FIXME: */
- /* we do a hardcoded reply here to avoid copying of the passphrase
- * from the cache to a temporary buffer */
- {
- byte buf[20];
-
- u32tobuf ( buf+0, (8+blocklen) );
- u32tobuf ( buf+4, GPGA_PROT_GOT_PASSPHRASE );
- u32tobuf ( buf+8, pwlen );
- writen ( fd, buf, 12 );
- writen ( fd, pw, blocklen );
- }
-#endif
- close_cached_passphrase ( slot );
-#endif
-}
-
-static void
-req_clear_passphrase ( int fd, const char *data, size_t datalen )
-{
-#if 0
- int slot;
-
- if ( datalen < 20 )
- {
- reply_error ( fd, GPGA_PROT_INVALID_DATA );
- return;
- }
-
- slot = open_cached_passphrase ( data );
- if ( slot == -1 )
- {
- reply_error ( fd, GPGA_PROT_NO_PASSPHRASE );
- return;
- }
-
- clear_cached_passphrase ( slot );
- close_cached_passphrase ( slot );
- reply_error (fd, GPGA_PROT_OKAY );
-#endif
-}
-
-static void
-req_shutdown ( int fd, const char *data, size_t datalen )
-{
- shut_me_down = 1;
-/* reply ( fd, GPGA_PROT_OKAY, "", 0 ); */
-}
-
-
-static void
-req_flush ( int fd, const char *data, size_t datalen )
-{
- int i;
-
- /* FIXME: when using multiple connections we need to cope with locking */
- for (i=0; i < MAX_CACHE_ENTRIES; i++ )
- {
- if ( the_cache[i].used ) {
- xfree ( the_cache[i].pw );
- the_cache[i].pw = NULL;
- the_cache[i].used = 0;
- }
- }
-/* reply ( fd, GPGA_PROT_OKAY, "", 0 ); */
-}
-
-
-static void
-process_request ( int fd )
-{
-#if 0
- byte buf[3000]; /* Below is a hardcoded max. length check */
- byte *data;
- size_t n, nread;
-
- /* Check the magic and the protocol number */
- if ( readn ( fd, buf, 12, &nread ) )
- goto read_failure;
- if ( nread != 12 || memcmp ( buf, "GPGA\0\0\0\x01", 8 ) ) {
- reply_error ( fd, GPGA_PROT_PROTOCOL_ERROR );
- return;
- }
- n = buftou32 ( buf + 8 ); /* length of following packet */
- if ( n < 4 || n > 2048 ) {
- reply_error ( fd, GPGA_PROT_INVALID_DATA );
- return;
- }
- /* read the request packet */
- if ( readn ( fd, buf, n, &nread ) )
- goto read_failure;
- if ( nread != n ) {
- reply_error ( fd, GPGA_PROT_PROTOCOL_ERROR );
- return;
- }
- /* dispatch the request */
- n -= 4;
- data = buf+4;
- switch ( buftou32 ( buf ) ) {
- case GPGA_PROT_GET_VERSION:
- req_get_version ( fd, data, n );
- break;
- case GPGA_PROT_GET_PASSPHRASE:
- req_get_passphrase (fd, data, n);
- break;
- case GPGA_PROT_CLEAR_PASSPHRASE:
- req_clear_passphrase (fd, data, n );
- break;
- case GPGA_PROT_SHUTDOWN:
- req_shutdown (fd, data, n );
- break;
- case GPGA_PROT_FLUSH:
- req_flush (fd, data, n );
- break;
-
- default:
- reply_error ( fd, GPGA_PROT_INVALID_REQUEST );
- break;
- }
-
- return;
-
- read_failure:
- /* it does not make sense to respond in this case */
- log_error ( "read failure: %s\n", strerror(errno));
- return;
-#endif
-}
-#endif
-
-
diff --git a/agent/query.c b/agent/query.c
index 1b90c49e1..45fcbfd8e 100644
--- a/agent/query.c
+++ b/agent/query.c
@@ -268,6 +268,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
if (!parm.buffer)
return seterr (Out_Of_Core);
+ assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL);
if (rc)
{