[w32] gpg-agent is now started automagically by gpgsm.

This commit is contained in:
Werner Koch 2007-06-20 11:16:42 +00:00
parent 540f9164c0
commit 09cc0ee7be
15 changed files with 258 additions and 137 deletions

View File

@ -691,7 +691,7 @@ main (int argc, char **argv )
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
sleep (debug_wait);
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}

View File

@ -1,3 +1,14 @@
2007-06-20 Werner Koch <wk@g10code.com>
* sysutils.c (gnupg_sleep): New.
* sysutils.h [W32]: Remove _sleep wrapper. Changed all callers to
use gnupg_sleep.
* exechelp.c (build_w32_commandline_copy): New.
(build_w32_commandline): Factored some code out to new function
and correctly process a PGMNAME with spaces.
(gnupg_spawn_process_detached) [W32]: Implement.
2007-06-14 Werner Koch <wk@g10code.com>
* simple-pwquery.h (MAP_SPWQ_ERROR_IMPL): New.

View File

@ -80,17 +80,51 @@
#ifdef HAVE_W32_SYSTEM
/* Helper function to build_w32_commandline. */
static char *
build_w32_commandline_copy (char *buffer, const char *string)
{
char *p = buffer;
const char *s;
if (!*string) /* Empty string. */
p = stpcpy (p, "\"\"");
else if (strpbrk (string, " \t\n\v\f\""))
{
/* Need top do some kind of quoting. */
p = stpcpy (p, "\"");
for (s=string; *s; s++)
{
*p++ = *s;
if (*s == '\"')
*p++ = *s;
}
*p++ = '\"';
*p = 0;
}
else
p = stpcpy (p, string);
return p;
}
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
static gpg_error_t
build_w32_commandline (const char *pgmname, const char **argv, char **cmdline)
build_w32_commandline (const char *pgmname, const char * const *argv,
char **cmdline)
{
int i, n;
const char *s;
char *buf, *p;
*cmdline = NULL;
n = strlen (pgmname);
n = 0;
s = pgmname;
n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
for (; *s; s++)
if (*s == '\"')
n++; /* Need to double inner quotes. */
for (i=0; (s=argv[i]); i++)
{
n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
@ -104,26 +138,11 @@ build_w32_commandline (const char *pgmname, const char **argv, char **cmdline)
if (!buf)
return gpg_error_from_syserror ();
/* fixme: PGMNAME may not contain spaces etc. */
p = stpcpy (p, pgmname);
p = build_w32_commandline_copy (p, pgmname);
for (i=0; argv[i]; i++)
{
if (!*argv[i]) /* Empty string. */
p = stpcpy (p, " \"\"");
else if (strpbrk (argv[i], " \t\n\v\f\""))
{
p = stpcpy (p, " \"");
for (s=argv[i]; *s; s++)
{
*p++ = *s;
if (*s == '\"')
*p++ = *s;
}
*p++ = '\"';
*p = 0;
}
else
p = stpcpy (stpcpy (p, " "), argv[i]);
*p++ = ' ';
p = build_w32_commandline_copy (p, argv[i]);
}
*cmdline= buf;
@ -330,7 +349,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
pi.hProcess, pi.hThread,
(int) pi.dwProcessId, (int) pi.dwThreadId);
/* Process ha been created suspended; resume it now. */
/* Process has been created suspended; resume it now. */
ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
@ -525,7 +544,79 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
const char *envp[] )
{
#ifdef HAVE_W32_SYSTEM
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
gpg_error_t err;
SECURITY_ATTRIBUTES sec_attr;
PROCESS_INFORMATION pi =
{
NULL, /* Returns process handle. */
0, /* Returns primary thread handle. */
0, /* Returns pid. */
0 /* Returns tid. */
};
STARTUPINFO si;
int cr_flags;
char *cmdline;
/* FIXME: We don't make use of ENVP yet. It is currently only used
to pass the GPG_AGENT_INFO variable to gpg-agent. As the default
on windows is to use a standard socket, this does not really
matter. */
if (access (pgmname, X_OK))
return gpg_error_from_syserror ();
/* Prepare security attributes. */
memset (&sec_attr, 0, sizeof sec_attr );
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
/* Build the command line. */
err = build_w32_commandline (pgmname, argv, &cmdline);
if (err)
return err;
/* Start the process. */
memset (&si, 0, sizeof si);
si.cb = sizeof (si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
cr_flags = (CREATE_DEFAULT_ERROR_MODE
| GetPriorityClass (GetCurrentProcess ())
| CREATE_NEW_PROCESS_GROUP
| DETACHED_PROCESS);
log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
pgmname, cmdline);
if (!CreateProcess (pgmname, /* Program to start. */
cmdline, /* Command line arguments. */
&sec_attr, /* Process security attributes. */
&sec_attr, /* Thread security attributes. */
FALSE, /* Inherit handles. */
cr_flags, /* Creation flags. */
NULL, /* Environment. */
NULL, /* Use current drive/directory. */
&si, /* Startup information. */
&pi /* Returns process information. */
))
{
log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
xfree (cmdline);
return gpg_error (GPG_ERR_GENERAL);
}
xfree (cmdline);
cmdline = NULL;
log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
" dwProcessID=%d dwThreadId=%d\n",
pi.hProcess, pi.hThread,
(int) pi.dwProcessId, (int) pi.dwThreadId);
CloseHandle (pi.hThread);
return 0;
#else
pid_t pid;
int i;

View File

@ -20,23 +20,36 @@
*/
#include <config.h>
#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
# undef HAVE_PTH
# undef USE_GNU_PTH
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#ifdef HAVE_STAT
#include <sys/stat.h>
# include <sys/stat.h>
#endif
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include <asm/sysinfo.h>
#include <asm/unistd.h>
# include <asm/sysinfo.h>
# include <asm/unistd.h>
#endif
#ifdef HAVE_SETRLIMIT
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
# include <time.h>
# include <sys/time.h>
# include <sys/resource.h>
#endif
#ifdef HAVE_W32_SYSTEM
# include <windows.h>
#endif
#ifdef HAVE_PTH
# include <pth.h>
#endif
#include "util.h"
#include "i18n.h"
@ -229,3 +242,33 @@ check_permissions(const char *path,int extension,int checkonly)
return 0;
}
#endif
/* Wrapper around the usual sleep fucntion. This one won't wake up
before the sleep time has really elapsed. When build with Pth it
merely calls pth_sleep and thus suspends only the current
thread. */
void
gnupg_sleep (unsigned int seconds)
{
#ifdef HAVE_PTH
/* With Pth we force a regular sleep for seconds == 0 so that also
the process will give up its timeslot. */
if (!seconds)
{
# ifdef HAVE_W32_SYSTEM
Sleep (0);
# else
sleep (0);
# endif
}
pth_sleep (seconds);
#else
/* Fixme: make sure that a sleep won't wake up to early. */
# ifdef HAVE_W32_SYSTEM
Sleep (seconds*1000);
# else
sleep (seconds);
# endif
#endif
}

View File

@ -27,11 +27,9 @@ int disable_core_dumps (void);
int enable_core_dumps (void);
const unsigned char *get_session_marker (size_t *rlen);
int check_permissions (const char *path,int extension,int checkonly);
void gnupg_sleep (unsigned int seconds);
#ifdef HAVE_W32_SYSTEM
/* Windows declares sleep as obsolete, but provides a definition for
_sleep but non for the still existing sleep. */
#define sleep(a) _sleep ((a))
#include "../jnlib/w32help.h"

View File

@ -1,3 +1,7 @@
2007-06-19 Werner Koch <wk@g10code.com>
* glossary.texi (Glossary): Describe PSE.
2007-06-18 Werner Koch <wk@g10code.com>
* gpg-agent.texi (Agent GETINFO): New.

View File

@ -26,5 +26,10 @@ entered as a 40 character hexadecimal formatted string.
The @emph{Online Certificate Status Protocol} is used as an
alternative to a @acronym{CRL}. It is described in @code{RFC 2560}.
@item PSE
The @emph{Personal Security Environment} describes a database to
store private keys. This is either a smartcard or a collection of files
on a disk; the latter is often called a Soft-PSE.
@end table

View File

@ -832,7 +832,7 @@ Here is an example session:
@subsection Generating a Key
This is used to create a new keypair and store the secret key inside the
active PSE -w which is in most cases a Soft-PSE. An not yet defined
active PSE --- which is in most cases a Soft-PSE. An not yet defined
option allows to choose the storage location. To get the secret key out
of the PSE, a special export tool has to be used.

View File

@ -1,3 +1,11 @@
2007-06-20 Werner Koch <wk@g10code.com>
* misc.c (setsysinfo, trap_unaligned): Remove. It is also in
common/sysutils.c.
(disable_core_dumps, get_session_marker):
* sign.c (sleep): Remove sleep wrapper.
2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* gpg.c (gpgconf_list): Percent escape output of --gpgconf-list.

View File

@ -94,51 +94,6 @@ static struct secured_file_item *secured_files;
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
static int
setsysinfo(unsigned long op, void *buffer, unsigned long size,
int *start, void *arg, unsigned long flag)
{
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
}
void
trap_unaligned(void)
{
unsigned int buf[2];
buf[0] = SSIN_UACPROC;
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
}
#else
void
trap_unaligned(void)
{ /* dummy */
}
#endif
int
disable_core_dumps()
{
#ifdef HAVE_DOSISH_SYSTEM
return 0;
#else
#ifdef HAVE_SETRLIMIT
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
if( !setrlimit( RLIMIT_CORE, &limit ) )
return 0;
if( errno != EINVAL && errno != ENOSYS )
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
#endif
return 1;
#endif
}
/* For the sake of SELinux we want to restrict access through gpg to
certain files we keep under our own control. This function
@ -371,34 +326,6 @@ print_digest_algo_note( int algo )
gcry_md_algo_name (algo));
}
/* Return a string which is used as a kind of process ID */
const byte *
get_session_marker( size_t *rlen )
{
static byte marker[SIZEOF_UNSIGNED_LONG*2];
static int initialized;
if ( !initialized )
{
volatile ulong aa, bb; /* We really want the uninitialized value. */
ulong a, b;
initialized = 1;
/* Although this marker is guessable it is not easy to use this
* for a faked control packet because an attacker does not have
* enough control about the time the verification takes place.
* Of course, we could add just more random but than we need the
* random generator even for verification tasks - which does not
* make sense. */
a = aa ^ (ulong)getpid();
b = bb ^ (ulong)time(NULL);
memcpy ( marker, &a, SIZEOF_UNSIGNED_LONG );
memcpy ( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
}
*rlen = sizeof(marker);
return marker;
}
/****************
* Wrapper around the libgcrypt function with additonal checks on
* the OpenPGP contraints for the algo ID.

View File

@ -26,7 +26,6 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h> /* need sleep() */
#include "gpg.h"
#include "options.h"
@ -47,8 +46,6 @@
#ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n"
void __stdcall Sleep(ulong);
#define sleep(a) Sleep((a)*1000)
#else
#define LF "\n"
#endif
@ -1563,7 +1560,7 @@ update_keysig_packet( PKT_signature **ret_sig,
one. */
while(sig->timestamp<=orig_sig->timestamp)
{
sleep(1);
gnupg_sleep (1);
sig->timestamp=make_timestamp();
}

View File

@ -519,7 +519,7 @@ main (int argc, char **argv )
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
sleep (debug_wait);
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}

View File

@ -1,3 +1,7 @@
2007-06-20 Werner Koch <wk@g10code.com>
* call-agent.c (start_agent) [W32]: Start the agent on the fly.
2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* gpgsm.c (main): Percent escape output of --gpgconf-list.

View File

@ -37,7 +37,8 @@
#include "i18n.h"
#include "asshelp.h"
#include "keydb.h" /* fixme: Move this to import.c */
#include "../common/membuf.h"
#include "membuf.h"
#include "exechelp.h"
static assuan_context_t agent_ctx = NULL;
@ -83,21 +84,12 @@ start_agent (ctrl_t ctrl)
infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
if (!infostr || !*infostr)
{
const char *pgmname;
const char *argv[3];
char *sockname;
int no_close_list[3];
int i;
/* First check whether we can connect at the standard
socket. */
sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
rc = assuan_socket_connect (&ctx, sockname, 0);
xfree (sockname);
#ifdef HAVE_W32_SYSTEM
# warning Print a warning if connecting is not possible
/* and offer to fire up the agent. */
#endif
if (rc)
{
@ -112,30 +104,71 @@ start_agent (ctrl_t ctrl)
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
log_error ("error flushing pending output: %s\n",
strerror (errno));
xfree (sockname);
return tmperr;
}
if (!opt.agent_program || !*opt.agent_program)
opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
if ( !(pgmname = strrchr (opt.agent_program, '/')))
pgmname = opt.agent_program;
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--server";
argv[2] = NULL;
#ifdef HAVE_W32_SYSTEM
{
/* Under Windows we start the server in daemon mode. This
is because the default is to use the standard socket
and thus there is no need for the GPG_AGENT_INFO
envvar. This is possible as we don't have a real unix
domain socket but use a plain file and thus there is no
need to care about non-local file systems. */
const char *argv[3];
i=0;
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
no_close_list[i] = -1;
/* The --no-reuse-standard option makes sure that we don't
start a second instance of a agent in case another
process has started one in the meantime. */
argv[0] = "--daemon";
argv[1] = "--no-reuse-standard-socket";
argv[2] = NULL;
/* Connect to the agent and perform initial handshaking. */
rc = assuan_pipe_connect (&ctx, opt.agent_program, argv,
no_close_list);
rc = gnupg_spawn_process_detached (opt.agent_program, argv, NULL);
if (rc)
log_debug ("failed to start agent `%s': %s\n",
opt.agent_program, gpg_strerror (rc));
else
{
/* Give the agent some time to prepare itself. */
gnupg_sleep (3);
/* Now try again to connect the agent. */
rc = assuan_socket_connect (&ctx, sockname, 0);
}
}
#else /*!HAVE_W32_SYSTEM*/
{
const char *pgmname;
const char *argv[3];
int no_close_list[3];
int i;
if ( !(pgmname = strrchr (opt.agent_program, '/')))
pgmname = opt.agent_program;
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--server";
argv[2] = NULL;
i=0;
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
no_close_list[i] = -1;
/* Connect to the agent and perform initial handshaking. */
rc = assuan_pipe_connect (&ctx, opt.agent_program, argv,
no_close_list);
}
#endif /*!HAVE_W32_SYSTEM*/
}
xfree (sockname);
}
else
{

View File

@ -1438,7 +1438,7 @@ main ( int argc, char **argv)
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
sleep (debug_wait);
gnupg_sleep (debug_wait);
log_debug ("... okay\n");
}
gpgsm_server (recplist);