chiark / gitweb /
dirmngr: New option --no-use-tor and internal changes.
[gnupg2.git] / common / exechelp-w32.c
1 /* exechelp-w32.c - Fork and exec helpers for W32.
2  * Copyright (C) 2004, 2007, 2008, 2009,
3  *               2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * This file is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, see <https://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32
33 #if !defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
34 #error This code is only used on W32.
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <assert.h>
42 #ifdef HAVE_SIGNAL_H
43 # include <signal.h>
44 #endif
45 #include <unistd.h>
46 #include <fcntl.h>
47
48 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
49 #undef HAVE_NPTH
50 #undef USE_NPTH
51 #endif
52
53 #ifdef HAVE_NPTH
54 #include <npth.h>
55 #endif
56
57 #ifdef HAVE_STAT
58 # include <sys/stat.h>
59 #endif
60
61
62 #include "util.h"
63 #include "i18n.h"
64 #include "sysutils.h"
65 #include "exechelp.h"
66
67 /* Define to 1 do enable debugging.  */
68 #define DEBUG_W32_SPAWN 0
69
70
71 /* It seems Vista doesn't grok X_OK and so fails access() tests.
72    Previous versions interpreted X_OK as F_OK anyway, so we'll just
73    use F_OK directly. */
74 #undef X_OK
75 #define X_OK F_OK
76
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
86
87 /* Helper */
88 static inline gpg_error_t
89 my_error_from_syserror (void)
90 {
91   return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
92 }
93
94 static inline gpg_error_t
95 my_error (int errcode)
96 {
97   return gpg_err_make (default_errsource, errcode);
98 }
99
100
101 /* Return the maximum number of currently allowed open file
102    descriptors.  Only useful on POSIX systems but returns a value on
103    other systems too.  */
104 int
105 get_max_fds (void)
106 {
107   int max_fds = -1;
108
109 #ifdef OPEN_MAX
110   if (max_fds == -1)
111     max_fds = OPEN_MAX;
112 #endif
113
114   if (max_fds == -1)
115     max_fds = 256;  /* Arbitrary limit.  */
116
117   return max_fds;
118 }
119
120
121 /* Under Windows this is a dummy function.  */
122 void
123 close_all_fds (int first, int *except)
124 {
125   (void)first;
126   (void)except;
127 }
128
129
130 /* Returns an array with all currently open file descriptors.  The end
131  * of the array is marked by -1.  The caller needs to release this
132  * array using the *standard free* and not with xfree.  This allow the
133  * use of this function right at startup even before libgcrypt has
134  * been initialized.  Returns NULL on error and sets ERRNO
135  * accordingly.  Note that fstat prints a warning to DebugView for all
136  * invalid fds which is a bit annoying.  We actually do not need this
137  * function in real code (close_all_fds is a dummy anyway) but we keep
138  * it for use by t-exechelp.c.  */
139 int *
140 get_all_open_fds (void)
141 {
142   int *array;
143   size_t narray;
144   int fd, max_fd, idx;
145 #ifndef HAVE_STAT
146   array = calloc (1, sizeof *array);
147   if (array)
148     array[0] = -1;
149 #else /*HAVE_STAT*/
150   struct stat statbuf;
151
152   max_fd = get_max_fds ();
153   narray = 32;  /* If you change this change also t-exechelp.c.  */
154   array = calloc (narray, sizeof *array);
155   if (!array)
156     return NULL;
157
158   /* Note:  The list we return is ordered.  */
159   for (idx=0, fd=0; fd < max_fd; fd++)
160     if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
161       {
162         if (idx+1 >= narray)
163           {
164             int *tmp;
165
166             narray += (narray < 256)? 32:256;
167             tmp = realloc (array, narray * sizeof *array);
168             if (!tmp)
169               {
170                 free (array);
171                 return NULL;
172               }
173             array = tmp;
174           }
175         array[idx++] = fd;
176       }
177   array[idx] = -1;
178 #endif /*HAVE_STAT*/
179   return array;
180 }
181
182
183 /* Helper function to build_w32_commandline. */
184 static char *
185 build_w32_commandline_copy (char *buffer, const char *string)
186 {
187   char *p = buffer;
188   const char *s;
189
190   if (!*string) /* Empty string. */
191     p = stpcpy (p, "\"\"");
192   else if (strpbrk (string, " \t\n\v\f\""))
193     {
194       /* Need to do some kind of quoting.  */
195       p = stpcpy (p, "\"");
196       for (s=string; *s; s++)
197         {
198           *p++ = *s;
199           if (*s == '\"')
200             *p++ = *s;
201         }
202       *p++ = '\"';
203       *p = 0;
204     }
205   else
206     p = stpcpy (p, string);
207
208   return p;
209 }
210
211 /* Build a command line for use with W32's CreateProcess.  On success
212    CMDLINE gets the address of a newly allocated string.  */
213 static gpg_error_t
214 build_w32_commandline (const char *pgmname, const char * const *argv,
215                        char **cmdline)
216 {
217   int i, n;
218   const char *s;
219   char *buf, *p;
220
221   *cmdline = NULL;
222   n = 0;
223   s = pgmname;
224   n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
225   for (; *s; s++)
226     if (*s == '\"')
227       n++;  /* Need to double inner quotes.  */
228   for (i=0; (s=argv[i]); i++)
229     {
230       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
231       for (; *s; s++)
232         if (*s == '\"')
233           n++;  /* Need to double inner quotes.  */
234     }
235   n++;
236
237   buf = p = xtrymalloc (n);
238   if (!buf)
239     return my_error_from_syserror ();
240
241   p = build_w32_commandline_copy (p, pgmname);
242   for (i=0; argv[i]; i++)
243     {
244       *p++ = ' ';
245       p = build_w32_commandline_copy (p, argv[i]);
246     }
247
248   *cmdline= buf;
249   return 0;
250 }
251
252
253 #define INHERIT_READ    1
254 #define INHERIT_WRITE   2
255 #define INHERIT_BOTH    (INHERIT_READ|INHERIT_WRITE)
256
257 /* Create pipe.  FLAGS indicates which ends are inheritable.  */
258 static int
259 create_inheritable_pipe (HANDLE filedes[2], int flags)
260 {
261   HANDLE r, w;
262   SECURITY_ATTRIBUTES sec_attr;
263
264   memset (&sec_attr, 0, sizeof sec_attr );
265   sec_attr.nLength = sizeof sec_attr;
266   sec_attr.bInheritHandle = TRUE;
267
268   if (!CreatePipe (&r, &w, &sec_attr, 0))
269     return -1;
270
271   if ((flags & INHERIT_READ) == 0)
272     if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
273       goto fail;
274
275   if ((flags & INHERIT_WRITE) == 0)
276     if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
277       goto fail;
278
279   filedes[0] = r;
280   filedes[1] = w;
281   return 0;
282
283  fail:
284   log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
285   CloseHandle (r);
286   CloseHandle (w);
287   return -1;
288 }
289
290
291 static HANDLE
292 w32_open_null (int for_write)
293 {
294   HANDLE hfile;
295
296   hfile = CreateFileW (L"nul",
297                        for_write? GENERIC_WRITE : GENERIC_READ,
298                        FILE_SHARE_READ | FILE_SHARE_WRITE,
299                        NULL, OPEN_EXISTING, 0, NULL);
300   if (hfile == INVALID_HANDLE_VALUE)
301     log_debug ("can't open 'nul': %s\n", w32_strerror (-1));
302   return hfile;
303 }
304
305
306 static gpg_error_t
307 create_pipe_and_estream (int filedes[2], int flags,
308                          estream_t *r_fp, int outbound, int nonblock)
309 {
310   gpg_error_t err = 0;
311   HANDLE fds[2];
312
313   filedes[0] = filedes[1] = -1;
314   err = my_error (GPG_ERR_GENERAL);
315   if (!create_inheritable_pipe (fds, flags))
316     {
317       filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
318       if (filedes[0] == -1)
319         {
320           log_error ("failed to translate osfhandle %p\n", fds[0]);
321           CloseHandle (fds[1]);
322         }
323       else
324         {
325           filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
326           if (filedes[1] == -1)
327             {
328               log_error ("failed to translate osfhandle %p\n", fds[1]);
329               close (filedes[0]);
330               filedes[0] = -1;
331               CloseHandle (fds[1]);
332             }
333           else
334             err = 0;
335         }
336     }
337
338   if (! err && r_fp)
339     {
340       if (!outbound)
341         *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r");
342       else
343         *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w");
344       if (!*r_fp)
345         {
346           err = my_error_from_syserror ();
347           log_error (_("error creating a stream for a pipe: %s\n"),
348                      gpg_strerror (err));
349           close (filedes[0]);
350           close (filedes[1]);
351           filedes[0] = filedes[1] = -1;
352           return err;
353         }
354     }
355
356   return err;
357 }
358
359 /* Portable function to create a pipe.  Under Windows the write end is
360    inheritable.  If R_FP is not NULL, an estream is created for the
361    read end and stored at R_FP.  */
362 gpg_error_t
363 gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
364 {
365   return create_pipe_and_estream (filedes, INHERIT_WRITE,
366                                   r_fp, 0, nonblock);
367 }
368
369
370 /* Portable function to create a pipe.  Under Windows the read end is
371    inheritable.  If R_FP is not NULL, an estream is created for the
372    write end and stored at R_FP.  */
373 gpg_error_t
374 gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
375 {
376   return create_pipe_and_estream (filedes, INHERIT_READ,
377                                   r_fp, 1, nonblock);
378 }
379
380
381 /* Portable function to create a pipe.  Under Windows both ends are
382    inheritable.  */
383 gpg_error_t
384 gnupg_create_pipe (int filedes[2])
385 {
386   return create_pipe_and_estream (filedes, INHERIT_BOTH,
387                                   NULL, 0, 0);
388 }
389
390
391 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
392 gpg_error_t
393 gnupg_spawn_process (const char *pgmname, const char *argv[],
394                      int *except, void (*preexec)(void), unsigned int flags,
395                      estream_t *r_infp,
396                      estream_t *r_outfp,
397                      estream_t *r_errfp,
398                      pid_t *pid)
399 {
400   gpg_error_t err;
401   SECURITY_ATTRIBUTES sec_attr;
402   PROCESS_INFORMATION pi =
403     {
404       NULL,      /* Returns process handle.  */
405       0,         /* Returns primary thread handle.  */
406       0,         /* Returns pid.  */
407       0          /* Returns tid.  */
408     };
409   STARTUPINFO si;
410   int cr_flags;
411   char *cmdline;
412   HANDLE inpipe[2]  = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
413   HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
414   HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
415   estream_t infp = NULL;
416   estream_t outfp = NULL;
417   estream_t errfp = NULL;
418   HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
419                       INVALID_HANDLE_VALUE,
420                       INVALID_HANDLE_VALUE};
421   int i;
422   es_syshd_t syshd;
423   gpg_err_source_t errsource = default_errsource;
424   int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
425
426   (void)except; /* Not yet used.  */
427
428   if (r_infp)
429     *r_infp = NULL;
430   if (r_outfp)
431     *r_outfp = NULL;
432   if (r_errfp)
433     *r_errfp = NULL;
434   *pid = (pid_t)(-1); /* Always required.  */
435
436   if (r_infp)
437     {
438       if (create_inheritable_pipe (inpipe, INHERIT_READ))
439         {
440           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
441           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
442           return err;
443         }
444
445       syshd.type = ES_SYSHD_HANDLE;
446       syshd.u.handle = inpipe[1];
447       infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
448       if (!infp)
449         {
450           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
451           log_error (_("error creating a stream for a pipe: %s\n"),
452                      gpg_strerror (err));
453           CloseHandle (inpipe[0]);
454           CloseHandle (inpipe[1]);
455           inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
456           return err;
457         }
458     }
459
460   if (r_outfp)
461     {
462       if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
463         {
464           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
465           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
466           return err;
467         }
468
469       syshd.type = ES_SYSHD_HANDLE;
470       syshd.u.handle = outpipe[0];
471       outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
472       if (!outfp)
473         {
474           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
475           log_error (_("error creating a stream for a pipe: %s\n"),
476                      gpg_strerror (err));
477           CloseHandle (outpipe[0]);
478           CloseHandle (outpipe[1]);
479           outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
480           if (infp)
481             es_fclose (infp);
482           else if (inpipe[1] != INVALID_HANDLE_VALUE)
483             CloseHandle (inpipe[1]);
484           if (inpipe[0] != INVALID_HANDLE_VALUE)
485             CloseHandle (inpipe[0]);
486           return err;
487         }
488     }
489
490   if (r_errfp)
491     {
492       if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
493         {
494           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
495           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
496           return err;
497         }
498
499       syshd.type = ES_SYSHD_HANDLE;
500       syshd.u.handle = errpipe[0];
501       errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
502       if (!errfp)
503         {
504           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
505           log_error (_("error creating a stream for a pipe: %s\n"),
506                      gpg_strerror (err));
507           CloseHandle (errpipe[0]);
508           CloseHandle (errpipe[1]);
509           errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
510           if (outfp)
511             es_fclose (outfp);
512           else if (outpipe[0] != INVALID_HANDLE_VALUE)
513             CloseHandle (outpipe[0]);
514           if (outpipe[1] != INVALID_HANDLE_VALUE)
515             CloseHandle (outpipe[1]);
516           if (infp)
517             es_fclose (infp);
518           else if (inpipe[1] != INVALID_HANDLE_VALUE)
519             CloseHandle (inpipe[1]);
520           if (inpipe[0] != INVALID_HANDLE_VALUE)
521             CloseHandle (inpipe[0]);
522           return err;
523         }
524     }
525
526   /* Prepare security attributes.  */
527   memset (&sec_attr, 0, sizeof sec_attr );
528   sec_attr.nLength = sizeof sec_attr;
529   sec_attr.bInheritHandle = FALSE;
530
531   /* Build the command line.  */
532   err = build_w32_commandline (pgmname, argv, &cmdline);
533   if (err)
534     return err;
535
536   if (inpipe[0] == INVALID_HANDLE_VALUE)
537     nullhd[0] = w32_open_null (0);
538   if (outpipe[1] == INVALID_HANDLE_VALUE)
539     nullhd[1] = w32_open_null (1);
540   if (errpipe[1] == INVALID_HANDLE_VALUE)
541     nullhd[2] = w32_open_null (1);
542
543   /* Start the process.  Note that we can't run the PREEXEC function
544      because this might change our own environment. */
545   (void)preexec;
546
547   memset (&si, 0, sizeof si);
548   si.cb = sizeof (si);
549   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
550   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
551   si.hStdInput  = inpipe[0]  == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
552   si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
553   si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
554
555   cr_flags = (CREATE_DEFAULT_ERROR_MODE
556               | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
557               | GetPriorityClass (GetCurrentProcess ())
558               | CREATE_SUSPENDED);
559 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
560   if (!CreateProcess (pgmname,       /* Program to start.  */
561                       cmdline,       /* Command line arguments.  */
562                       &sec_attr,     /* Process security attributes.  */
563                       &sec_attr,     /* Thread security attributes.  */
564                       TRUE,          /* Inherit handles.  */
565                       cr_flags,      /* Creation flags.  */
566                       NULL,          /* Environment.  */
567                       NULL,          /* Use current drive/directory.  */
568                       &si,           /* Startup information. */
569                       &pi            /* Returns process information.  */
570                       ))
571     {
572       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
573       xfree (cmdline);
574       if (infp)
575         es_fclose (infp);
576       else if (inpipe[1] != INVALID_HANDLE_VALUE)
577         CloseHandle (outpipe[1]);
578       if (inpipe[0] != INVALID_HANDLE_VALUE)
579         CloseHandle (inpipe[0]);
580       if (outfp)
581         es_fclose (outfp);
582       else if (outpipe[0] != INVALID_HANDLE_VALUE)
583         CloseHandle (outpipe[0]);
584       if (outpipe[1] != INVALID_HANDLE_VALUE)
585         CloseHandle (outpipe[1]);
586       if (errfp)
587         es_fclose (errfp);
588       else if (errpipe[0] != INVALID_HANDLE_VALUE)
589         CloseHandle (errpipe[0]);
590       if (errpipe[1] != INVALID_HANDLE_VALUE)
591         CloseHandle (errpipe[1]);
592       return gpg_err_make (errsource, GPG_ERR_GENERAL);
593     }
594   xfree (cmdline);
595   cmdline = NULL;
596
597   /* Close the inherited handles to /dev/null.  */
598   for (i=0; i < DIM (nullhd); i++)
599     if (nullhd[i] != INVALID_HANDLE_VALUE)
600       CloseHandle (nullhd[i]);
601
602   /* Close the inherited ends of the pipes.  */
603   if (inpipe[0] != INVALID_HANDLE_VALUE)
604     CloseHandle (inpipe[0]);
605   if (outpipe[1] != INVALID_HANDLE_VALUE)
606     CloseHandle (outpipe[1]);
607   if (errpipe[1] != INVALID_HANDLE_VALUE)
608     CloseHandle (errpipe[1]);
609
610   /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
611   /*            " dwProcessID=%d dwThreadId=%d\n", */
612   /*            pi.hProcess, pi.hThread, */
613   /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
614   /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */
615
616   /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
617      invalid argument error if we pass it the correct processID.  As a
618      workaround we use -1 (ASFW_ANY).  */
619   if ((flags & GNUPG_SPAWN_RUN_ASFW))
620     gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
621
622   /* Process has been created suspended; resume it now. */
623   ResumeThread (pi.hThread);
624   CloseHandle (pi.hThread);
625
626   if (r_infp)
627     *r_infp = infp;
628   if (r_outfp)
629     *r_outfp = outfp;
630   if (r_errfp)
631     *r_errfp = errfp;
632
633   *pid = handle_to_pid (pi.hProcess);
634   return 0;
635
636 }
637
638
639
640 /* Simplified version of gnupg_spawn_process.  This function forks and
641    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
642    and ERRFD to stderr (any of them may be -1 to connect them to
643    /dev/null).  The arguments for the process are expected in the NULL
644    terminated array ARGV.  The program name itself should not be
645    included there.  Calling gnupg_wait_process is required.
646
647    Returns 0 on success or an error code. */
648 gpg_error_t
649 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
650                         int infd, int outfd, int errfd, pid_t *pid)
651 {
652   gpg_error_t err;
653   SECURITY_ATTRIBUTES sec_attr;
654   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
655   STARTUPINFO si;
656   char *cmdline;
657   int i;
658   HANDLE stdhd[3];
659
660   /* Setup return values.  */
661   *pid = (pid_t)(-1);
662
663   /* Prepare security attributes.  */
664   memset (&sec_attr, 0, sizeof sec_attr );
665   sec_attr.nLength = sizeof sec_attr;
666   sec_attr.bInheritHandle = FALSE;
667
668   /* Build the command line.  */
669   err = build_w32_commandline (pgmname, argv, &cmdline);
670   if (err)
671     return err;
672
673   memset (&si, 0, sizeof si);
674   si.cb = sizeof (si);
675   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
676   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
677   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
678   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
679   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
680   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
681   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
682   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
683
684 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
685   if (!CreateProcess (pgmname,       /* Program to start.  */
686                       cmdline,       /* Command line arguments.  */
687                       &sec_attr,     /* Process security attributes.  */
688                       &sec_attr,     /* Thread security attributes.  */
689                       TRUE,          /* Inherit handles.  */
690                       (CREATE_DEFAULT_ERROR_MODE
691                        | GetPriorityClass (GetCurrentProcess ())
692                        | CREATE_SUSPENDED | DETACHED_PROCESS),
693                       NULL,          /* Environment.  */
694                       NULL,          /* Use current drive/directory.  */
695                       &si,           /* Startup information. */
696                       &pi            /* Returns process information.  */
697                       ))
698     {
699       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
700       err = my_error (GPG_ERR_GENERAL);
701     }
702   else
703     err = 0;
704   xfree (cmdline);
705   for (i=0; i < 3; i++)
706     if (stdhd[i] != INVALID_HANDLE_VALUE)
707       CloseHandle (stdhd[i]);
708   if (err)
709     return err;
710
711 /*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
712 /*              " dwProcessID=%d dwThreadId=%d\n", */
713 /*              pi.hProcess, pi.hThread, */
714 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
715
716   /* Process has been created suspended; resume it now. */
717   ResumeThread (pi.hThread);
718   CloseHandle (pi.hThread);
719
720   *pid = handle_to_pid (pi.hProcess);
721   return 0;
722
723 }
724
725
726 /* See exechelp.h for a description.  */
727 gpg_error_t
728 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
729 {
730   return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
731 }
732
733 /* See exechelp.h for a description.  */
734 gpg_error_t
735 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
736                       int hang, int *r_exitcodes)
737 {
738   gpg_err_code_t ec = 0;
739   size_t i;
740   HANDLE *procs;
741   int code;
742
743   procs = xtrycalloc (count, sizeof *procs);
744   if (procs == NULL)
745     return my_error_from_syserror ();
746
747   for (i = 0; i < count; i++)
748     {
749       if (r_exitcodes)
750         r_exitcodes[i] = -1;
751
752       if (pids[i] == (pid_t)(-1))
753         return my_error (GPG_ERR_INV_VALUE);
754
755       procs[i] = fd_to_handle (pids[i]);
756     }
757
758   /* FIXME: We should do a pth_waitpid here.  However this has not yet
759      been implemented.  A special W32 pth system call would even be
760      better.  */
761   code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
762   switch (code)
763     {
764     case WAIT_TIMEOUT:
765       ec = GPG_ERR_TIMEOUT;
766       goto leave;
767
768     case WAIT_FAILED:
769       log_error (_("waiting for processes to terminate failed: %s\n"),
770                  w32_strerror (-1));
771       ec = GPG_ERR_GENERAL;
772       goto leave;
773
774     case WAIT_OBJECT_0:
775       for (i = 0; i < count; i++)
776         {
777           DWORD exc;
778
779           if (! GetExitCodeProcess (procs[i], &exc))
780             {
781               log_error (_("error getting exit code of process %d: %s\n"),
782                          (int) pids[i], w32_strerror (-1) );
783               ec = GPG_ERR_GENERAL;
784             }
785           else if (exc)
786             {
787               if (!r_exitcodes)
788                 log_error (_("error running '%s': exit status %d\n"),
789                            pgmnames[i], (int)exc);
790               else
791                 r_exitcodes[i] = (int)exc;
792               ec = GPG_ERR_GENERAL;
793             }
794           else
795             {
796               if (r_exitcodes)
797                 r_exitcodes[i] = 0;
798             }
799         }
800       break;
801
802     default:
803       log_error ("WaitForMultipleObjects returned unexpected "
804                  "code %d\n", code);
805       ec = GPG_ERR_GENERAL;
806       break;
807     }
808
809  leave:
810   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
811 }
812
813
814
815 void
816 gnupg_release_process (pid_t pid)
817 {
818   if (pid != (pid_t)INVALID_HANDLE_VALUE)
819     {
820       HANDLE process = (HANDLE)pid;
821
822       CloseHandle (process);
823     }
824 }
825
826
827 /* Spawn a new process and immediately detach from it.  The name of
828    the program to exec is PGMNAME and its arguments are in ARGV (the
829    programname is automatically passed as first argument).
830    Environment strings in ENVP are set.  An error is returned if
831    pgmname is not executable; to make this work it is necessary to
832    provide an absolute file name.  All standard file descriptors are
833    connected to /dev/null. */
834 gpg_error_t
835 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
836                               const char *envp[] )
837 {
838   gpg_error_t err;
839   SECURITY_ATTRIBUTES sec_attr;
840   PROCESS_INFORMATION pi =
841     {
842       NULL,      /* Returns process handle.  */
843       0,         /* Returns primary thread handle.  */
844       0,         /* Returns pid.  */
845       0          /* Returns tid.  */
846     };
847   STARTUPINFO si;
848   int cr_flags;
849   char *cmdline;
850
851
852   /* We don't use ENVP.  */
853   (void)envp;
854
855   if (access (pgmname, X_OK))
856     return my_error_from_syserror ();
857
858   /* Prepare security attributes.  */
859   memset (&sec_attr, 0, sizeof sec_attr );
860   sec_attr.nLength = sizeof sec_attr;
861   sec_attr.bInheritHandle = FALSE;
862
863   /* Build the command line.  */
864   err = build_w32_commandline (pgmname, argv, &cmdline);
865   if (err)
866     return err;
867
868   /* Start the process.  */
869   memset (&si, 0, sizeof si);
870   si.cb = sizeof (si);
871   si.dwFlags = STARTF_USESHOWWINDOW;
872   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
873
874   cr_flags = (CREATE_DEFAULT_ERROR_MODE
875               | GetPriorityClass (GetCurrentProcess ())
876               | CREATE_NEW_PROCESS_GROUP
877               | DETACHED_PROCESS);
878 /*   log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
879 /*              pgmname, cmdline); */
880   if (!CreateProcess (pgmname,       /* Program to start.  */
881                       cmdline,       /* Command line arguments.  */
882                       &sec_attr,     /* Process security attributes.  */
883                       &sec_attr,     /* Thread security attributes.  */
884                       FALSE,         /* Inherit handles.  */
885                       cr_flags,      /* Creation flags.  */
886                       NULL,          /* Environment.  */
887                       NULL,          /* Use current drive/directory.  */
888                       &si,           /* Startup information. */
889                       &pi            /* Returns process information.  */
890                       ))
891     {
892       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
893       xfree (cmdline);
894       return my_error (GPG_ERR_GENERAL);
895     }
896   xfree (cmdline);
897   cmdline = NULL;
898
899 /*   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
900 /*              " dwProcessID=%d dwThreadId=%d\n", */
901 /*              pi.hProcess, pi.hThread, */
902 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
903
904   CloseHandle (pi.hThread);
905   CloseHandle (pi.hProcess);
906
907   return 0;
908 }
909
910
911 /* Kill a process; that is send an appropriate signal to the process.
912    gnupg_wait_process must be called to actually remove the process
913    from the system.  An invalid PID is ignored.  */
914 void
915 gnupg_kill_process (pid_t pid)
916 {
917   if (pid != (pid_t) INVALID_HANDLE_VALUE)
918     {
919       HANDLE process = (HANDLE) pid;
920
921       /* Arbitrary error code.  */
922       TerminateProcess (process, 1);
923     }
924 }