[w32] gpg-agent is now started automagically by gpgsm.
authorWerner Koch <wk@gnupg.org>
Wed, 20 Jun 2007 11:16:42 +0000 (11:16 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 20 Jun 2007 11:16:42 +0000 (11:16 +0000)
15 files changed:
agent/gpg-agent.c
common/ChangeLog
common/exechelp.c
common/sysutils.c
common/sysutils.h
doc/ChangeLog
doc/glossary.texi
doc/gpg-agent.texi
g10/ChangeLog
g10/misc.c
g10/sign.c
scd/scdaemon.c
sm/ChangeLog
sm/call-agent.c
sm/gpgsm.c

index 8907e92..a064692 100644 (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");
     }
   
index f038122..3f8fa41 100644 (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.
index b4700c5..d0be840 100644 (file)
 
 
 #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;
index d044f22..ff1fe1b 100644 (file)
  */
 
 #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
+}
index 7129915..0e295f5 100644 (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"
 
index df1b7d8..a87680b 100644 (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.
index 5ea4a95..6eede19 100644 (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
index a079b30..85ce1ac 100644 (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.
 
index 5e0a290..b49d886 100644 (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.
index c743da6..4cb7191 100644 (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.
index 062fa9f..1a1a80b 100644 (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();
       }
 
index f9a9992..b250894 100644 (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");
     }
   
index c5d342b..896b5c3 100644 (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.
index 1ac5412..b30fe60 100644 (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;
-
-          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);
+
+#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];
+
+            /* 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;  
+
+            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
     {
index f6d2b84..b6a3e69 100644 (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);