1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-03 12:11:33 +01:00

* 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.
This commit is contained in:
Werner Koch 2002-01-19 18:19:47 +00:00
parent a9979e26a5
commit 6af684c118
5 changed files with 227 additions and 657 deletions

View File

@ -1,3 +1,12 @@
2002-01-19 Werner Koch <wk@gnupg.org>
* 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 <wk@gnupg.org> 2002-01-15 Werner Koch <wk@gnupg.org>
* trustlist.c: New. * trustlist.c: New.

View File

@ -47,12 +47,14 @@ struct {
#define DBG_CACHE_VALUE 64 /* debug the caching */ #define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ #define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */ #define DBG_HASHING_VALUE 512 /* debug hashing operations */
#define DBG_ASSUAN_VALUE 1024
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE) #define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE) #define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
struct server_local_s; struct server_local_s;
@ -87,7 +89,7 @@ void agent_exit (int rc);
const char *trans (const char *text); const char *trans (const char *text);
/*-- command.c --*/ /*-- command.c --*/
void start_command_handler (void); void start_command_handler (int);
/*-- findkey.c --*/ /*-- findkey.c --*/
GCRY_SEXP agent_key_from_file (const unsigned char *grip); GCRY_SEXP agent_key_from_file (const unsigned char *grip);

View File

@ -269,7 +269,7 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
/* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>] /* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
This function is usually used to ask for a passphrase to be used 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 need specal handling of passphrases. This command uses a syntax
which helps clients to use the agent with minimum effort. The 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 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 */ /* FIXME: Parse that stuff */
desc = "We need a passphrase"; desc = "We need a passphrase";
prompt = NULL; prompt = NULL;
errtext = "try again"; errtext = NULL;
rc = agent_get_passphrase (&response, desc, prompt, errtext); rc = agent_get_passphrase (&response, desc, prompt, errtext);
if (!rc) if (!rc)
{ {
assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, response); rc = assuan_set_okay_line (ctx, response);
xfree (response); xfree (response);
} }
@ -303,7 +304,7 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
/* CLEAR_PASSPHRASE <cache_id> /* CLEAR_PASSPHRASE <cache_id>
may be used to invalidate the cache entry for a passphrase. The 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 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 void
start_command_handler (void) start_command_handler (int listen_fd)
{ {
int rc; int rc;
int filedes[2];
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);
/* 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 if (listen_fd == -1)
wait for requests on a Unix domain socket */ {
int filedes[2];
filedes[0] = 0; filedes[0] = 0;
filedes[1] = 1; filedes[1] = 1;
rc = assuan_init_pipe_server (&ctx, filedes); rc = assuan_init_pipe_server (&ctx, filedes);
}
else
{
rc = assuan_init_socket_server (&ctx, listen_fd);
}
if (rc) if (rc)
{ {
log_error ("failed to initialize the server: %s\n", log_error ("failed to initialize the server: %s\n",
@ -385,7 +393,7 @@ start_command_handler (void)
rc = register_commands (ctx); rc = register_commands (ctx);
if (rc) 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)); assuan_strerror(rc));
agent_exit (2); agent_exit (2);
} }
@ -395,6 +403,9 @@ start_command_handler (void)
ctrl.server_local->assuan_ctx = ctx; ctrl.server_local->assuan_ctx = ctx;
ctrl.server_local->message_fd = -1; ctrl.server_local->message_fd = -1;
if (DBG_ASSUAN)
assuan_set_log_stream (ctx, log_get_stream ());
for (;;) for (;;)
{ {
rc = assuan_accept (ctx); rc = assuan_accept (ctx);
@ -417,6 +428,8 @@ start_command_handler (void)
} }
assuan_deinit_pipe_server (ctx); assuan_deinit_server (ctx);
} }

View File

@ -29,6 +29,8 @@
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
@ -60,9 +62,6 @@ enum cmd_and_opt_values
oHomedir, oHomedir,
oNoDetach, oNoDetach,
oNoGrab, oNoGrab,
oClient,
oShutdown,
oFlush,
oLogFile, oLogFile,
oServer, oServer,
oBatch, oBatch,
@ -88,11 +87,7 @@ static ARGPARSE_OPTS opts[] = {
{ oDebugWait,"debug-wait",1, "@"}, { oDebugWait,"debug-wait",1, "@"},
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
{ oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")}, { 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")}, { 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" }, { oPinentryProgram, "pinentry-program", 2 , "Path of PIN Entry program" },
@ -101,58 +96,32 @@ 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 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 */ /* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1; static int maybe_setuid = 1;
/* Name of the communication socket */
#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ static char socket_name[128];
(*((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 );
static const char * static const char *
my_strusage( int level ) my_strusage (int level)
{ {
const char *p; const char *p;
switch( level ) { switch (level)
{
case 11: p = "gpg-agent (GnuPG)"; case 11: p = "gpg-agent (GnuPG)";
break; break;
case 13: p = VERSION; break; case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break; case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
_("Please report bugs to <bug-gnupg@gnu.org>.\n");
break; break;
case 1: case 1:
case 40: p = case 40: p = _("Usage: gpg-agent [options] (-h for help)");
_("Usage: gpg-agent [options] (-h for help)");
break; break;
case 41: p = case 41: p = _("Syntax: gpg-agent [options] [command [args]]\n"
_("Syntax: gpg-agent [options] [command [args]]\n"
"Secret key management for GnuPG\n"); "Secret key management for GnuPG\n");
break; break;
@ -166,28 +135,17 @@ my_strusage( int level )
static void static void
i18n_init (void) i18n_init (void)
{ {
#ifdef USE_SIMPLE_GETTEXT #ifdef USE_SIMPLE_GETTEXT
set_gettext_file( PACKAGE ); set_gettext_file( PACKAGE );
#else #else
#ifdef ENABLE_NLS #ifdef ENABLE_NLS
/* gtk_set_locale (); HMMM: We have not yet called gtk_init */ /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
bindtextdomain( PACKAGE, GNUPG_LOCALEDIR ); bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
textdomain( PACKAGE ); 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 */ /* 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 static RETSIGTYPE
cleanup_sh (int sig) cleanup_sh (int sig)
{ {
if (caught_fatal_sig) if (caught_fatal_sig)
raise (sig); raise (sig);
caught_fatal_sig = 1; caught_fatal_sig = 1;
shut_me_down = 1;
/* gcry_control( GCRYCTL_TERM_SECMEM );*/ /* gcry_control( GCRYCTL_TERM_SECMEM );*/
cleanup (); cleanup ();
@ -248,10 +225,7 @@ main (int argc, char **argv )
int default_config =1; int default_config =1;
int greeting = 0; int greeting = 0;
int nogreeting = 0; int nogreeting = 0;
int server_mode = 0; int pipe_server = 0;
int client = 0;
int do_shutdown = 0;
int do_flush = 0;
int nodetach = 0; int nodetach = 0;
int grab = 0; int grab = 0;
int csh_style = 0; int csh_style = 0;
@ -280,7 +254,6 @@ main (int argc, char **argv )
may_coredump = 0/* FIXME: disable_core_dumps()*/; may_coredump = 0/* FIXME: disable_core_dumps()*/;
shell = getenv ("SHELL"); shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") ) if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1; csh_style = 1;
@ -389,13 +362,10 @@ main (int argc, char **argv )
case oHomedir: opt.homedir = pargs.r.ret_str; break; case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oNoDetach: nodetach = 1; break; case oNoDetach: nodetach = 1; break;
case oNoGrab: grab = 0; 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 oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break; case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; 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; case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
@ -427,142 +397,144 @@ main (int argc, char **argv )
log_info ("NOTE: this is a development version!\n"); log_info ("NOTE: this is a development version!\n");
#endif #endif
socket_name = make_filename (opt.homedir, "S.gpg-agent", NULL );
if (strchr ( socket_name, ':') )
{
log_error ("colons are not allowed in the socket name\n");
exit (1);
}
if (client) if (atexit (cleanup))
{ /* 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( 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
}
else if (server_mode)
{ /* for now this is the simple pipe based server */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, 1|2|4);
}
if ( atexit( cleanup ) )
{ {
log_error ("atexit failed\n"); log_error ("atexit failed\n");
cleanup (); cleanup ();
exit (1); exit (1);
} }
if (debug_wait) if (debug_wait && pipe_server)
{ {
log_debug ("waiting for debugger - my pid is %u .....\n", log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid()); (unsigned int)getpid());
sleep (debug_wait); sleep (debug_wait);
log_debug ("... okay\n"); log_debug ("... okay\n");
} }
start_command_handler ();
/* 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 (pipe_server)
{ /* this is the simple pipe based server */
start_command_handler (-1);
} }
else else
{ /* regular server mode */ { /* regular server mode */
int listen_fd; int fd;
pid_t child; pid_t pid;
int i; int i;
int len;
struct sockaddr_un serv_addr;
char *p;
listen_fd = start_listening (socket_name); *socket_name = 0;
if (listen_fd == -1) 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))
{ {
cleanup (); log_error ("can't create directory `%s': %s\n",
socket_name, strerror(errno) );
exit (1); exit (1);
} }
*p = '/';
if (strchr (socket_name, ':') )
{
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);
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (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)
{
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); fflush (NULL);
child = fork (); pid = fork ();
if (child == -1) if (pid == (pid_t)-1)
{ {
log_fatal ("fork failed: %s\n", strerror (errno) ); log_fatal ("fork failed: %s\n", strerror (errno) );
cleanup ();
exit (1); exit (1);
} }
else if ( child ) else if (pid)
{ /* parent */ { /* we are the parent */
char *infostr; char *infostr;
close (listen_fd ); close (fd);
/* create the info string */ /* create the info string: <name>:<pid>:<protocol_version> */
infostr = xmalloc ( 20 + strlen(socket_name) + 30 + 2 ); if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
sprintf ( infostr, "GPG_AGENT_INFO=%s:%lu", socket_name, (ulong)pid ) < 0)
socket_name, (ulong)child ); {
if ( argc ) 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 */ { /* run the program given on the commandline */
if (putenv (infostr)) if (putenv (infostr))
{ {
log_error ("failed to set environment: %s\n", log_error ("failed to set environment: %s\n",
strerror (errno) ); strerror (errno) );
kill (child, SIGTERM ); kill (pid, SIGTERM );
cleanup ();
exit (1); exit (1);
} }
execvp (argv[0], argv); execvp (argv[0], argv);
log_error ("failed to run the command: %s\n", log_error ("failed to run the command: %s\n", strerror (errno));
strerror (errno)); kill (pid, SIGTERM);
kill (child, SIGTERM);
cleanup ();
exit (1); exit (1);
} }
else
{
/* print the environment string, so that the caller can use /* print the environment string, so that the caller can use
eval to set it */ shell's eval to set it */
if (csh_style) if (csh_style)
{ {
*strchr (infostr, '=') = ' '; *strchr (infostr, '=') = ' ';
@ -572,38 +544,22 @@ main (int argc, char **argv )
{ {
printf ( "%s; export GPG_AGENT_INFO;\n", infostr); printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
} }
free (infostr);
exit (0); exit (0);
}
/*NEVER REACHED*/
} /* end parent */ } /* end parent */
if ( (opt.debug & 1) ) /* this is the child */
{
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) /* detach from tty and put process into a new session */
{ if (!nodetach )
log_set_file (logfile); { /* close stdin, stdout and stderr unless it is the log stream */
log_set_prefix (NULL, 1|2|4); for (i=0; i <= 2; i++)
}
if ( atexit( cleanup ) )
{
log_error ("atexit failed\n");
cleanup ();
exit (1);
}
if ( !nodetach )
{
for (i=0 ; i <= 2; i++ )
{ {
if ( log_get_fd () != i) if ( log_get_fd () != i)
close ( i ); close (i);
} }
if (setsid() == -1) if (setsid() == -1)
{ {
log_error ("setsid() failed: %s\n", strerror(errno) ); log_error ("setsid() failed: %s\n", strerror(errno) );
@ -612,52 +568,34 @@ main (int argc, char **argv )
} }
} }
/* setup signals */
{ {
struct sigaction oact, nact; struct sigaction oact, nact;
nact.sa_handler = cleanup_sh; nact.sa_handler = cleanup_sh;
sigemptyset ( &nact.sa_mask ); sigemptyset (&nact.sa_mask);
nact.sa_flags = 0; nact.sa_flags = 0;
sigaction ( SIGHUP, NULL, &oact ); sigaction (SIGHUP, NULL, &oact);
if ( oact.sa_handler != SIG_IGN ) if (oact.sa_handler != SIG_IGN)
sigaction( SIGHUP, &nact, NULL); sigaction (SIGHUP, &nact, NULL);
sigaction( SIGTERM, NULL, &oact ); sigaction( SIGTERM, NULL, &oact );
if ( oact.sa_handler != SIG_IGN ) if (oact.sa_handler != SIG_IGN)
sigaction( SIGTERM, &nact, NULL); sigaction (SIGTERM, &nact, NULL);
nact.sa_handler = SIG_IGN; nact.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &nact, NULL ); sigaction (SIGPIPE, &nact, NULL);
sigaction( SIGINT, &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); exit (1);
} }
/* for now there is no need for concurrent requests because we start_command_handler (fd);
are asking for passphrases which might pop up a window to get
the users respond. In future the agent may provide other close (fd);
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);
} }
return 0; return 0;
@ -685,396 +623,3 @@ agent_exit (int rc)
exit (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

View File

@ -268,6 +268,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
if (!parm.buffer) if (!parm.buffer)
return seterr (Out_Of_Core); return seterr (Out_Of_Core);
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL);
if (rc) if (rc)
{ {