1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-08 23:37:47 +02:00

[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", log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid()); (unsigned int)getpid());
sleep (debug_wait); gnupg_sleep (debug_wait);
log_debug ("... okay\n"); 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> 2007-06-14 Werner Koch <wk@g10code.com>
* simple-pwquery.h (MAP_SPWQ_ERROR_IMPL): New. * simple-pwquery.h (MAP_SPWQ_ERROR_IMPL): New.

View File

@ -80,17 +80,51 @@
#ifdef HAVE_W32_SYSTEM #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 /* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */ CMDLINE gets the address of a newly allocated string. */
static gpg_error_t 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; int i, n;
const char *s; const char *s;
char *buf, *p; char *buf, *p;
*cmdline = NULL; *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++) for (i=0; (s=argv[i]); i++)
{ {
n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ 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) if (!buf)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
/* fixme: PGMNAME may not contain spaces etc. */ p = build_w32_commandline_copy (p, pgmname);
p = stpcpy (p, pgmname);
for (i=0; argv[i]; i++) for (i=0; argv[i]; i++)
{ {
if (!*argv[i]) /* Empty string. */ *p++ = ' ';
p = stpcpy (p, " \"\""); p = build_w32_commandline_copy (p, argv[i]);
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]);
} }
*cmdline= buf; *cmdline= buf;
@ -330,7 +349,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
pi.hProcess, pi.hThread, pi.hProcess, pi.hThread,
(int) pi.dwProcessId, (int) pi.dwThreadId); (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); ResumeThread (pi.hThread);
CloseHandle (pi.hThread); CloseHandle (pi.hThread);
@ -525,7 +544,79 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
const char *envp[] ) const char *envp[] )
{ {
#ifdef HAVE_W32_SYSTEM #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 #else
pid_t pid; pid_t pid;
int i; int i;

View File

@ -20,23 +20,36 @@
*/ */
#include <config.h> #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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#ifdef HAVE_STAT #ifdef HAVE_STAT
#include <sys/stat.h> # include <sys/stat.h>
#endif #endif
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include <asm/sysinfo.h> # include <asm/sysinfo.h>
#include <asm/unistd.h> # include <asm/unistd.h>
#endif #endif
#ifdef HAVE_SETRLIMIT #ifdef HAVE_SETRLIMIT
#include <time.h> # include <time.h>
#include <sys/time.h> # include <sys/time.h>
#include <sys/resource.h> # include <sys/resource.h>
#endif #endif
#ifdef HAVE_W32_SYSTEM
# include <windows.h>
#endif
#ifdef HAVE_PTH
# include <pth.h>
#endif
#include "util.h" #include "util.h"
#include "i18n.h" #include "i18n.h"
@ -229,3 +242,33 @@ check_permissions(const char *path,int extension,int checkonly)
return 0; return 0;
} }
#endif #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); int enable_core_dumps (void);
const unsigned char *get_session_marker (size_t *rlen); const unsigned char *get_session_marker (size_t *rlen);
int check_permissions (const char *path,int extension,int checkonly); int check_permissions (const char *path,int extension,int checkonly);
void gnupg_sleep (unsigned int seconds);
#ifdef HAVE_W32_SYSTEM #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" #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> 2007-06-18 Werner Koch <wk@g10code.com>
* gpg-agent.texi (Agent GETINFO): New. * 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 The @emph{Online Certificate Status Protocol} is used as an
alternative to a @acronym{CRL}. It is described in @code{RFC 2560}. 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 @end table

View File

@ -832,7 +832,7 @@ Here is an example session:
@subsection Generating a Key @subsection Generating a Key
This is used to create a new keypair and store the secret key inside the 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 option allows to choose the storage location. To get the secret key out
of the PSE, a special export tool has to be used. 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> 2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* gpg.c (gpgconf_list): Percent escape output of --gpgconf-list. * 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 /* For the sake of SELinux we want to restrict access through gpg to
certain files we keep under our own control. This function 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)); 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 * Wrapper around the libgcrypt function with additonal checks on
* the OpenPGP contraints for the algo ID. * the OpenPGP contraints for the algo ID.

View File

@ -26,7 +26,6 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> /* need sleep() */
#include "gpg.h" #include "gpg.h"
#include "options.h" #include "options.h"
@ -47,8 +46,6 @@
#ifdef HAVE_DOSISH_SYSTEM #ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n" #define LF "\r\n"
void __stdcall Sleep(ulong);
#define sleep(a) Sleep((a)*1000)
#else #else
#define LF "\n" #define LF "\n"
#endif #endif
@ -1563,7 +1560,7 @@ update_keysig_packet( PKT_signature **ret_sig,
one. */ one. */
while(sig->timestamp<=orig_sig->timestamp) while(sig->timestamp<=orig_sig->timestamp)
{ {
sleep(1); gnupg_sleep (1);
sig->timestamp=make_timestamp(); 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", log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid()); (unsigned int)getpid());
sleep (debug_wait); gnupg_sleep (debug_wait);
log_debug ("... okay\n"); 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> 2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* gpgsm.c (main): Percent escape output of --gpgconf-list. * gpgsm.c (main): Percent escape output of --gpgconf-list.

View File

@ -37,7 +37,8 @@
#include "i18n.h" #include "i18n.h"
#include "asshelp.h" #include "asshelp.h"
#include "keydb.h" /* fixme: Move this to import.c */ #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; 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"); infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
if (!infostr || !*infostr) if (!infostr || !*infostr)
{ {
const char *pgmname;
const char *argv[3];
char *sockname; char *sockname;
int no_close_list[3];
int i;
/* First check whether we can connect at the standard /* First check whether we can connect at the standard
socket. */ socket. */
sockname = make_filename (opt.homedir, "S.gpg-agent", NULL); sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
rc = assuan_socket_connect (&ctx, sockname, 0); 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) if (rc)
{ {
@ -112,30 +104,71 @@ start_agent (ctrl_t ctrl)
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
log_error ("error flushing pending output: %s\n", log_error ("error flushing pending output: %s\n",
strerror (errno)); strerror (errno));
xfree (sockname);
return tmperr; return tmperr;
} }
if (!opt.agent_program || !*opt.agent_program) if (!opt.agent_program || !*opt.agent_program)
opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT); 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; #ifdef HAVE_W32_SYSTEM
argv[1] = "--server"; {
argv[2] = NULL; /* 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; /* The --no-reuse-standard option makes sure that we don't
if (log_get_fd () != -1) start a second instance of a agent in case another
no_close_list[i++] = log_get_fd (); process has started one in the meantime. */
no_close_list[i++] = fileno (stderr); argv[0] = "--daemon";
no_close_list[i] = -1; argv[1] = "--no-reuse-standard-socket";
argv[2] = NULL;
/* Connect to the agent and perform initial handshaking. */ rc = gnupg_spawn_process_detached (opt.agent_program, argv, NULL);
rc = assuan_pipe_connect (&ctx, opt.agent_program, argv, if (rc)
no_close_list); 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 else
{ {

View File

@ -1438,7 +1438,7 @@ main ( int argc, char **argv)
{ {
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); gnupg_sleep (debug_wait);
log_debug ("... okay\n"); log_debug ("... okay\n");
} }
gpgsm_server (recplist); gpgsm_server (recplist);