Implemented more gpg-agen options to support certain passphrase policies.
[gnupg.git] / common / exechelp.c
1 /* exechelp.c - fork and exec helpers
2  *      Copyright (C) 2004, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <signal.h>
28 #include <unistd.h> 
29 #include <fcntl.h>
30
31 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
32 #undef HAVE_PTH
33 #undef USE_GNU_PTH
34 #endif
35
36 #ifdef USE_GNU_PTH      
37 #include <pth.h>
38 #endif
39 #ifndef HAVE_W32_SYSTEM
40 #include <sys/wait.h>
41 #endif
42
43 #include "util.h"
44 #include "i18n.h"
45 #include "exechelp.h"
46
47 /* Define to 1 do enable debugging.  */
48 #define DEBUG_W32_SPAWN 1
49
50
51 #ifdef _POSIX_OPEN_MAX
52 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
53 #else
54 #define MAX_OPEN_FDS 20
55 #endif
56
57 /* We have the usual problem here: Some modules are linked against pth
58    and some are not.  However we want to use pth_fork and pth_waitpid
59    here. Using a weak symbol works but is not portable - we should
60    provide a an explicit dummy pth module instead of using the
61    pragma.  */ 
62 #ifndef _WIN32
63 #pragma weak pth_fork
64 #pragma weak pth_waitpid
65 #endif
66
67 #ifdef HAVE_W32_SYSTEM
68 /* It seems Vista doesn't grok X_OK and so fails access() tests.
69    Previous versions interpreted X_OK as F_OK anyway, so we'll just
70    use F_OK directly. */
71 #undef X_OK
72 #define X_OK F_OK
73 #endif /* HAVE_W32_SYSTEM */
74
75
76 #ifdef HAVE_W32_SYSTEM
77 /* We assume that a HANDLE can be represented by an int which should
78    be true for all i386 systems (HANDLE is defined as void *) and
79    these are the only systems for which Windows is available.  Further
80    we assume that -1 denotes an invalid handle.  */
81 # define fd_to_handle(a)  ((HANDLE)(a))
82 # define handle_to_fd(a)  ((int)(a))
83 # define pid_to_handle(a) ((HANDLE)(a))
84 # define handle_to_pid(a) ((int)(a))
85 #endif
86
87
88 #ifdef HAVE_W32_SYSTEM
89 /* Helper function to build_w32_commandline. */
90 static char *
91 build_w32_commandline_copy (char *buffer, const char *string)
92 {
93   char *p = buffer;
94   const char *s;
95
96   if (!*string) /* Empty string. */
97     p = stpcpy (p, "\"\"");
98   else if (strpbrk (string, " \t\n\v\f\""))
99     {
100       /* Need top do some kind of quoting.  */
101       p = stpcpy (p, "\"");
102       for (s=string; *s; s++)
103         {
104           *p++ = *s;
105           if (*s == '\"')
106             *p++ = *s;
107         }
108       *p++ = '\"';
109       *p = 0;
110     }
111   else
112     p = stpcpy (p, string);
113
114   return p;
115 }
116
117 /* Build a command line for use with W32's CreateProcess.  On success
118    CMDLINE gets the address of a newly allocated string.  */
119 static gpg_error_t
120 build_w32_commandline (const char *pgmname, const char * const *argv, 
121                        char **cmdline)
122 {
123   int i, n;
124   const char *s;
125   char *buf, *p;
126
127   *cmdline = NULL;
128   n = 0;
129   s = pgmname;
130   n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
131   for (; *s; s++)
132     if (*s == '\"')
133       n++;  /* Need to double inner quotes.  */
134   for (i=0; (s=argv[i]); i++)
135     {
136       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
137       for (; *s; s++)
138         if (*s == '\"')
139           n++;  /* Need to double inner quotes.  */
140     }
141   n++;
142
143   buf = p = xtrymalloc (n);
144   if (!buf)
145     return gpg_error_from_syserror ();
146
147   p = build_w32_commandline_copy (p, pgmname);
148   for (i=0; argv[i]; i++) 
149     {
150       *p++ = ' ';
151       p = build_w32_commandline_copy (p, argv[i]);
152     }
153
154   *cmdline= buf;
155   return 0;
156 }
157 #endif /*HAVE_W32_SYSTEM*/
158
159
160 #ifdef HAVE_W32_SYSTEM
161 /* Create  pipe where the write end is inheritable.  */
162 static int
163 create_inheritable_pipe (int filedes[2])
164 {
165   HANDLE r, w, h;
166   SECURITY_ATTRIBUTES sec_attr;
167
168   memset (&sec_attr, 0, sizeof sec_attr );
169   sec_attr.nLength = sizeof sec_attr;
170   sec_attr.bInheritHandle = FALSE;
171     
172   if (!CreatePipe (&r, &w, &sec_attr, 0))
173     return -1;
174
175   if (!DuplicateHandle (GetCurrentProcess(), w,
176                         GetCurrentProcess(), &h, 0,
177                         TRUE, DUPLICATE_SAME_ACCESS ))
178     {
179       log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
180       CloseHandle (r);
181       CloseHandle (w);
182       return -1;
183     }
184   CloseHandle (w);
185   w = h;
186
187   filedes[0] = handle_to_fd (r);
188   filedes[1] = handle_to_fd (w);
189   return 0;
190 }
191 #endif /*HAVE_W32_SYSTEM*/
192
193
194 #ifdef HAVE_W32_SYSTEM
195 static HANDLE
196 w32_open_null (int for_write)
197 {
198   HANDLE hfile;
199
200   hfile = CreateFile ("nul",
201                       for_write? GENERIC_WRITE : GENERIC_READ,
202                       FILE_SHARE_READ | FILE_SHARE_WRITE,
203                       NULL, OPEN_EXISTING, 0, NULL);
204   if (hfile == INVALID_HANDLE_VALUE)
205     log_debug ("can't open `nul': %s\n", w32_strerror (-1));
206   return hfile;
207 }
208 #endif /*HAVE_W32_SYSTEM*/
209
210
211 #ifndef HAVE_W32_SYSTEM
212 /* The exec core used right after the fork. This will never return. */
213 static void
214 do_exec (const char *pgmname, const char *argv[],
215          int fd_in, int fd_out, int fd_err,
216          void (*preexec)(void) )
217 {
218   char **arg_list;
219   int n, i, j;
220   int fds[3];
221
222   fds[0] = fd_in;
223   fds[1] = fd_out;
224   fds[2] = fd_err;
225
226   /* Create the command line argument array.  */
227   i = 0;
228   if (argv)
229     while (argv[i])
230       i++;
231   arg_list = xcalloc (i+2, sizeof *arg_list);
232   arg_list[0] = strrchr (pgmname, '/');
233   if (arg_list[0])
234     arg_list[0]++;
235   else
236     arg_list[0] = xstrdup (pgmname);
237   if (argv)
238     for (i=0,j=1; argv[i]; i++, j++)
239       arg_list[j] = (char*)argv[i];
240
241   /* Connect the standard files. */
242   for (i=0; i <= 2; i++)
243     {
244       if (fds[i] == -1 )
245         {
246           fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
247           if (fds[i] == -1)
248             log_fatal ("failed to open `%s': %s\n",
249                        "/dev/null", strerror (errno));
250         }
251       else if (fds[i] != i && dup2 (fds[i], i) == -1)
252         log_fatal ("dup2 std%s failed: %s\n",
253                    i==0?"in":i==1?"out":"err", strerror (errno));
254     }
255
256   /* Close all other files. */
257   n = sysconf (_SC_OPEN_MAX);
258   if (n < 0)
259     n = MAX_OPEN_FDS;
260   for (i=3; i < n; i++)
261     close(i);
262   errno = 0;
263   
264   if (preexec)
265     preexec ();
266   execv (pgmname, arg_list);
267   /* No way to print anything, as we have closed all streams. */
268   _exit (127);
269 }
270 #endif /*!HAVE_W32_SYSTEM*/
271
272
273 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
274    stdin, write the output to OUTFILE, return a new stream in
275    STATUSFILE for stderr and the pid of the process in PID. The
276    arguments for the process are expected in the NULL terminated array
277    ARGV.  The program name itself should not be included there.  If
278    PREEXEC is not NULL, that function will be called right before the
279    exec.  Calling gnupg_wait_process is required.
280
281    Returns 0 on success or an error code. */
282 gpg_error_t
283 gnupg_spawn_process (const char *pgmname, const char *argv[],
284                      FILE *infile, FILE *outfile,
285                      void (*preexec)(void),
286                      FILE **statusfile, pid_t *pid)
287 {
288 #ifdef HAVE_W32_SYSTEM
289   gpg_error_t err;
290   SECURITY_ATTRIBUTES sec_attr;
291   PROCESS_INFORMATION pi = 
292     {
293       NULL,      /* Returns process handle.  */
294       0,         /* Returns primary thread handle.  */
295       0,         /* Returns pid.  */
296       0          /* Returns tid.  */
297     };
298   STARTUPINFO si;
299   int cr_flags;
300   char *cmdline;
301   int fd, fdout, rp[2];
302
303   /* Setup return values.  */
304   *statusfile = NULL;
305   *pid = (pid_t)(-1);
306   fflush (infile);
307   rewind (infile);
308   fd = _get_osfhandle (fileno (infile));
309   fdout = _get_osfhandle (fileno (outfile));
310   if (fd == -1 || fdout == -1)
311     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
312
313   /* Prepare security attributes.  */
314   memset (&sec_attr, 0, sizeof sec_attr );
315   sec_attr.nLength = sizeof sec_attr;
316   sec_attr.bInheritHandle = FALSE;
317   
318   /* Build the command line.  */
319   err = build_w32_commandline (pgmname, argv, &cmdline);
320   if (err)
321     return err; 
322
323   /* Create a pipe.  */
324   if (create_inheritable_pipe (rp))
325     {
326       err = gpg_error (GPG_ERR_GENERAL);
327       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
328       xfree (cmdline);
329       return err;
330     }
331   
332   /* Start the process.  Note that we can't run the PREEXEC function
333      because this would change our own environment. */
334   memset (&si, 0, sizeof si);
335   si.cb = sizeof (si);
336   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
337   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
338   si.hStdInput  = fd_to_handle (fd);
339   si.hStdOutput = fd_to_handle (fdout);
340   si.hStdError  = fd_to_handle (rp[1]);
341
342   cr_flags = (CREATE_DEFAULT_ERROR_MODE
343               | GetPriorityClass (GetCurrentProcess ())
344               | CREATE_SUSPENDED); 
345   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
346   if (!CreateProcess (pgmname,       /* Program to start.  */
347                       cmdline,       /* Command line arguments.  */
348                       &sec_attr,     /* Process security attributes.  */
349                       &sec_attr,     /* Thread security attributes.  */
350                       TRUE,          /* Inherit handles.  */
351                       cr_flags,      /* Creation flags.  */
352                       NULL,          /* Environment.  */
353                       NULL,          /* Use current drive/directory.  */
354                       &si,           /* Startup information. */
355                       &pi            /* Returns process information.  */
356                       ))
357     {
358       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
359       xfree (cmdline);
360       CloseHandle (fd_to_handle (rp[0]));
361       CloseHandle (fd_to_handle (rp[1]));
362       return gpg_error (GPG_ERR_GENERAL);
363     }
364   xfree (cmdline);
365   cmdline = NULL;
366
367   /* Close the other end of the pipe.  */
368   CloseHandle (fd_to_handle (rp[1]));
369   
370   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
371              " dwProcessID=%d dwThreadId=%d\n",
372              pi.hProcess, pi.hThread,
373              (int) pi.dwProcessId, (int) pi.dwThreadId);
374
375   /* Process has been created suspended; resume it now. */
376   ResumeThread (pi.hThread);
377   CloseHandle (pi.hThread); 
378
379   {
380     int x;
381
382     x = _open_osfhandle (rp[0], 0);
383     if (x == -1)
384       log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
385     else 
386       *statusfile = fdopen (x, "r");
387   }
388   if (!*statusfile)
389     {
390       err = gpg_error_from_syserror ();
391       log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
392       CloseHandle (pi.hProcess);
393       return err;
394     }
395
396   *pid = handle_to_pid (pi.hProcess);
397   return 0;
398
399 #else /* !HAVE_W32_SYSTEM */
400   gpg_error_t err;
401   int fd, fdout, rp[2];
402
403   *statusfile = NULL;
404   *pid = (pid_t)(-1);
405   fflush (infile);
406   rewind (infile);
407   fd = fileno (infile);
408   fdout = fileno (outfile);
409   if (fd == -1 || fdout == -1)
410     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
411
412   if (pipe (rp) == -1)
413     {
414       err = gpg_error_from_syserror ();
415       log_error (_("error creating a pipe: %s\n"), strerror (errno));
416       return err;
417     }
418
419 #ifdef USE_GNU_PTH      
420   *pid = pth_fork? pth_fork () : fork ();
421 #else
422   *pid = fork ();
423 #endif
424   if (*pid == (pid_t)(-1))
425     {
426       err = gpg_error_from_syserror ();
427       log_error (_("error forking process: %s\n"), strerror (errno));
428       close (rp[0]);
429       close (rp[1]);
430       return err;
431     }
432
433   if (!*pid)
434     { 
435       gcry_control (GCRYCTL_TERM_SECMEM);
436       /* Run child. */
437       do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
438       /*NOTREACHED*/
439     }
440
441   /* Parent. */
442   close (rp[1]);
443
444   *statusfile = fdopen (rp[0], "r");
445   if (!*statusfile)
446     {
447       err = gpg_error_from_syserror ();
448       log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
449       kill (*pid, SIGTERM);
450       *pid = (pid_t)(-1);
451       return err;
452     }
453
454   return 0;
455 #endif /* !HAVE_W32_SYSTEM */
456 }
457
458
459
460 /* Simplified version of gnupg_spawn_process.  This function forks and
461    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
462    and ERRFD to stderr (any of them may be -1 to connect them to
463    /dev/null).  The arguments for the process are expected in the NULL
464    terminated array ARGV.  The program name itself should not be
465    included there.  Calling gnupg_wait_process is required.
466
467    Returns 0 on success or an error code. */
468 gpg_error_t
469 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
470                         int infd, int outfd, int errfd, pid_t *pid)
471 {
472 #ifdef HAVE_W32_SYSTEM
473   gpg_error_t err;
474   SECURITY_ATTRIBUTES sec_attr;
475   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
476   STARTUPINFO si;
477   char *cmdline;
478   int i;
479   HANDLE stdhd[3];
480
481   /* Setup return values.  */
482   *pid = (pid_t)(-1);
483
484   /* Prepare security attributes.  */
485   memset (&sec_attr, 0, sizeof sec_attr );
486   sec_attr.nLength = sizeof sec_attr;
487   sec_attr.bInheritHandle = FALSE;
488   
489   /* Build the command line.  */
490   err = build_w32_commandline (pgmname, argv, &cmdline);
491   if (err)
492     return err; 
493
494   memset (&si, 0, sizeof si);
495   si.cb = sizeof (si);
496   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
497   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
498   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
499   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
500   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
501   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
502   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
503   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
504
505   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
506   if (!CreateProcess (pgmname,       /* Program to start.  */
507                       cmdline,       /* Command line arguments.  */
508                       &sec_attr,     /* Process security attributes.  */
509                       &sec_attr,     /* Thread security attributes.  */
510                       TRUE,          /* Inherit handles.  */
511                       (CREATE_DEFAULT_ERROR_MODE
512                        | GetPriorityClass (GetCurrentProcess ())
513                        | CREATE_SUSPENDED),
514                       NULL,          /* Environment.  */
515                       NULL,          /* Use current drive/directory.  */
516                       &si,           /* Startup information. */
517                       &pi            /* Returns process information.  */
518                       ))
519     {
520       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
521       err = gpg_error (GPG_ERR_GENERAL);
522     }
523   else
524     err = 0;
525   xfree (cmdline);
526   for (i=0; i < 3; i++)
527     if (stdhd[i] != INVALID_HANDLE_VALUE)
528       CloseHandle (stdhd[i]);
529   if (err)
530     return err;
531
532   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
533              " dwProcessID=%d dwThreadId=%d\n",
534              pi.hProcess, pi.hThread,
535              (int) pi.dwProcessId, (int) pi.dwThreadId);
536
537   /* Process has been created suspended; resume it now. */
538   ResumeThread (pi.hThread);
539   CloseHandle (pi.hThread); 
540
541   *pid = handle_to_pid (pi.hProcess);
542   return 0;
543
544 #else /* !HAVE_W32_SYSTEM */
545   gpg_error_t err;
546
547 #ifdef USE_GNU_PTH      
548   *pid = pth_fork? pth_fork () : fork ();
549 #else
550   *pid = fork ();
551 #endif
552   if (*pid == (pid_t)(-1))
553     {
554       err = gpg_error_from_syserror ();
555       log_error (_("error forking process: %s\n"), strerror (errno));
556       return err;
557     }
558
559   if (!*pid)
560     { 
561       gcry_control (GCRYCTL_TERM_SECMEM);
562       /* Run child. */
563       do_exec (pgmname, argv, infd, outfd, errfd, NULL);
564       /*NOTREACHED*/
565     }
566
567   return 0;
568 #endif /* !HAVE_W32_SYSTEM */
569 }
570
571
572 /* Wait for the process identified by PID to terminate. PGMNAME should
573    be the same as suplieed to the spawn fucntion and is only used for
574    diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
575    any failures of the spawned program or other error codes.*/
576 gpg_error_t
577 gnupg_wait_process (const char *pgmname, pid_t pid)
578 {
579   gpg_err_code_t ec;
580
581 #ifdef HAVE_W32_SYSTEM
582   HANDLE proc = fd_to_handle (pid);
583   int code;
584   DWORD exc;
585
586   if (pid == (pid_t)(-1))
587     return gpg_error (GPG_ERR_INV_VALUE);
588
589   /* FIXME: We should do a pth_waitpid here.  However this has not yet
590      been implemented.  A special W32 pth system call would even be
591      better.  */
592   code = WaitForSingleObject (proc, INFINITE);
593   switch (code) 
594     {
595       case WAIT_FAILED:
596         log_error (_("waiting for process %d to terminate failed: %s\n"),
597                    (int)pid, w32_strerror (-1));
598         ec = GPG_ERR_GENERAL;
599         break;
600
601       case WAIT_OBJECT_0:
602         if (!GetExitCodeProcess (proc, &exc))
603           {
604             log_error (_("error getting exit code of process %d: %s\n"),
605                          (int)pid, w32_strerror (-1) );
606             ec = GPG_ERR_GENERAL;
607           }
608         else if (exc)
609           {
610             log_error (_("error running `%s': exit status %d\n"),
611                        pgmname, (int)exc );
612             ec = GPG_ERR_GENERAL;
613           }
614         else
615           ec = 0;
616         CloseHandle (proc);
617         break;
618
619       default:
620         log_error ("WaitForSingleObject returned unexpected "
621                    "code %d for pid %d\n", code, (int)pid );
622         ec = GPG_ERR_GENERAL;
623         break;
624     }
625
626 #else /* !HAVE_W32_SYSTEM */
627   int i, status;
628
629   if (pid == (pid_t)(-1))
630     return gpg_error (GPG_ERR_INV_VALUE);
631
632 #ifdef USE_GNU_PTH
633   i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
634 #else
635   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
636     ;
637 #endif
638   if (i == (pid_t)(-1))
639     {
640       log_error (_("waiting for process %d to terminate failed: %s\n"),
641                  (int)pid, strerror (errno));
642       ec = gpg_err_code_from_errno (errno);
643     }
644   else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
645     {
646       log_error (_("error running `%s': probably not installed\n"), pgmname);
647       ec = GPG_ERR_CONFIGURATION;
648     }
649   else if (WIFEXITED (status) && WEXITSTATUS (status))
650     {
651       log_error (_("error running `%s': exit status %d\n"), pgmname,
652                  WEXITSTATUS (status));
653       ec = GPG_ERR_GENERAL;
654     }
655   else if (!WIFEXITED (status))
656     {
657       log_error (_("error running `%s': terminated\n"), pgmname);
658       ec = GPG_ERR_GENERAL;
659     }
660   else 
661     ec = 0;
662 #endif /* !HAVE_W32_SYSTEM */
663
664   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
665
666 }
667
668
669 /* Spawn a new process and immediatley detach from it.  The name of
670    the program to exec is PGMNAME and its arguments are in ARGV (the
671    programname is automatically passed as first argument).
672    Environment strings in ENVP are set.  An error is returned if
673    pgmname is not executable; to make this work it is necessary to
674    provide an absolute file name.  All standard file descriptors are
675    connected to /dev/null. */
676 gpg_error_t
677 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
678                               const char *envp[] )
679 {
680 #ifdef HAVE_W32_SYSTEM
681   gpg_error_t err;
682   SECURITY_ATTRIBUTES sec_attr;
683   PROCESS_INFORMATION pi = 
684     {
685       NULL,      /* Returns process handle.  */
686       0,         /* Returns primary thread handle.  */
687       0,         /* Returns pid.  */
688       0          /* Returns tid.  */
689     };
690   STARTUPINFO si;
691   int cr_flags;
692   char *cmdline;
693
694
695   /* FIXME: We don't make use of ENVP yet.  It is currently only used
696      to pass the GPG_AGENT_INFO variable to gpg-agent.  As the default
697      on windows is to use a standard socket, this does not really
698      matter.  */
699
700
701   if (access (pgmname, X_OK))
702     return gpg_error_from_syserror ();
703
704   /* Prepare security attributes.  */
705   memset (&sec_attr, 0, sizeof sec_attr );
706   sec_attr.nLength = sizeof sec_attr;
707   sec_attr.bInheritHandle = FALSE;
708   
709   /* Build the command line.  */
710   err = build_w32_commandline (pgmname, argv, &cmdline);
711   if (err)
712     return err; 
713
714   /* Start the process.  */
715   memset (&si, 0, sizeof si);
716   si.cb = sizeof (si);
717   si.dwFlags = STARTF_USESHOWWINDOW;
718   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
719
720   cr_flags = (CREATE_DEFAULT_ERROR_MODE
721               | GetPriorityClass (GetCurrentProcess ())
722               | CREATE_NEW_PROCESS_GROUP
723               | DETACHED_PROCESS); 
724   log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
725              pgmname, cmdline);
726   if (!CreateProcess (pgmname,       /* Program to start.  */
727                       cmdline,       /* Command line arguments.  */
728                       &sec_attr,     /* Process security attributes.  */
729                       &sec_attr,     /* Thread security attributes.  */
730                       FALSE,         /* Inherit handles.  */
731                       cr_flags,      /* Creation flags.  */
732                       NULL,          /* Environment.  */
733                       NULL,          /* Use current drive/directory.  */
734                       &si,           /* Startup information. */
735                       &pi            /* Returns process information.  */
736                       ))
737     {
738       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
739       xfree (cmdline);
740       return gpg_error (GPG_ERR_GENERAL);
741     }
742   xfree (cmdline);
743   cmdline = NULL;
744
745   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
746              " dwProcessID=%d dwThreadId=%d\n",
747              pi.hProcess, pi.hThread,
748              (int) pi.dwProcessId, (int) pi.dwThreadId);
749
750   CloseHandle (pi.hThread); 
751
752   return 0;
753
754 #else
755   pid_t pid;
756   int i;
757
758   if (getuid() != geteuid())
759     return gpg_error (GPG_ERR_BUG);
760
761   if (access (pgmname, X_OK))
762     return gpg_error_from_syserror ();
763
764 #ifdef USE_GNU_PTH      
765   pid = pth_fork? pth_fork () : fork ();
766 #else
767   pid = fork ();
768 #endif
769   if (pid == (pid_t)(-1))
770     {
771       log_error (_("error forking process: %s\n"), strerror (errno));
772       return gpg_error_from_syserror ();
773     }
774   if (!pid)
775     {
776       gcry_control (GCRYCTL_TERM_SECMEM);
777       if (setsid() == -1 || chdir ("/"))
778         _exit (1);
779       pid = fork (); /* Double fork to let init takes over the new child. */
780       if (pid == (pid_t)(-1))
781         _exit (1);
782       if (pid)
783         _exit (0);  /* Let the parent exit immediately. */
784
785       if (envp)
786         for (i=0; envp[i]; i++)
787           putenv (xstrdup (envp[i]));
788       
789       do_exec (pgmname, argv, -1, -1, -1, NULL);
790
791       /*NOTREACHED*/
792     }
793   
794   if (waitpid (pid, NULL, 0) == -1)
795     log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
796                strerror (errno));
797
798   return 0;
799 #endif /* !HAVE_W32_SYSTEM*/
800 }