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