1 /* exechelp-w32.c - Fork and exec helpers for W32CE.
2 * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
3 * Copyright (C) 2010-2012, 2014-2016 g10 Code GmbH
5 * This file is part of GnuPG.
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of either
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.
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.
20 * or both in parallel, as here.
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.
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 * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+)
34 #if !defined(HAVE_W32_SYSTEM) && !defined (HAVE_W32CE_SYSTEM)
35 #error This code is only used on W32CE.
49 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
59 # include <sys/stat.h>
70 /* It seems Vista doesn't grok X_OK and so fails access() tests.
71 Previous versions interpreted X_OK as F_OK anyway, so we'll just
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))
88 /* The data passed to the feeder_thread. */
89 struct feeder_thread_parms
92 volatile int stream_valid;
98 /* The thread started by start_feede3. */
100 feeder_thread (void *arg)
102 struct feeder_thread_parms *parm = arg;
111 log_debug ("feeder_thread estream->pipe: stream=%p pipe=%p\n",
112 parm->stream, parm->hd);
113 while (parm->stream_valid
114 && !es_read (parm->stream, buffer, sizeof buffer, &nread))
119 rc = WriteFile (parm->hd, buffer, nread, &nwritten, NULL);
123 log_debug ("feeder(%p): WriteFile error: rc=%d\n",
124 parm->hd, (int)GetLastError ());
131 if (!parm->stream_valid)
132 log_debug ("feeder(%p): closed by other thread\n", parm->hd);
134 log_debug ("feeder(%p): es_read error: %s\n",
135 parm->hd, strerror (errno));
142 log_debug ("feeder_thread pipe->estream: stream=%p pipe=%p\n",
143 parm->stream, parm->hd);
144 while ( (pth_enter (),
145 (rc = ReadFile (parm->hd, buffer, sizeof buffer, &nread, NULL)),
149 log_debug ("feeder_thread pipe->estream: read %d bytes\n",
153 if (parm->stream_valid
154 && es_write (parm->stream, buffer, nread, &nwritten))
156 log_debug ("feeder(%p): es_write error: %s\n",
157 parm->hd, strerror (errno));
160 log_debug ("feeder_thread pipe->estream: es_wrote %d bytes\n",
164 while (nread && parm->stream_valid);
166 if (!parm->stream_valid)
167 log_debug ("feeder(%p): closed by other thread\n", parm->hd);
169 log_debug ("feeder(%p): ReadFile error: rc=%d\n",
170 parm->hd, (int)GetLastError ());
172 log_debug ("feeder(%p): eof\n", parm->hd);
176 log_debug ("feeder(%p): waiting for es_fclose\n", parm->hd);
177 while (parm->stream_valid)
179 log_debug ("feeder(%p): about to close the pipe handle\n", parm->hd);
180 CloseHandle (parm->hd);
181 log_debug ("feeder(%p): pipe handle closed\n", parm->hd);
189 feeder_onclose_notification (estream_t stream, void *opaque)
191 struct feeder_thread_parms *parm = opaque;
193 log_debug ("feeder(%p): received onclose note\n", parm->hd);
194 parm->stream_valid = 0;
198 /* Fire up a thread to copy data between STREAM and a pipe's
199 descriptor FD. With DIRECTION set to true the copy takes place
200 from the stream to the pipe, otherwise from the pipe to the
203 start_feeder (estream_t stream, HANDLE hd, int direction)
207 struct feeder_thread_parms *parm;
210 parm = xtrymalloc (sizeof *parm);
212 return gpg_error_from_syserror ();
213 parm->stream = stream;
214 parm->stream_valid = 1;
216 parm->direction = direction;
218 if (es_onclose (stream, 1, feeder_onclose_notification, parm))
220 err = gpg_error_from_syserror ();
225 tattr = pth_attr_new ();
226 pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
227 pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
228 pth_attr_set (tattr, PTH_ATTR_NAME, "exec-feeder");
230 log_debug ("spawning new feeder(%p, %p, %d)\n", stream, hd, direction);
231 if(!pth_spawn (tattr, feeder_thread, parm))
233 err = gpg_error_from_syserror ();
234 es_onclose (stream, 0, feeder_onclose_notification, parm);
239 pth_attr_destroy (tattr);
246 return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* No Pth. */
252 /* Return the maximum number of currently allowed open file
253 descriptors. Only useful on POSIX systems but returns a value on
254 other systems too. */
266 max_fds = 256; /* Arbitrary limit. */
272 /* Under Windows this is a dummy function. */
274 close_all_fds (int first, int *except)
281 /* Returns an array with all currently open file descriptors. The end
282 of the array is marked by -1. The caller needs to release this
283 array using the *standard free* and not with xfree. This allow the
284 use of this function right at startup even before libgcrypt has
285 been initialized. Returns NULL on error and sets ERRNO
288 get_all_open_fds (void)
294 array = calloc (1, sizeof *array);
300 max_fd = get_max_fds ();
301 narray = 32; /* If you change this change also t-exechelp.c. */
302 array = calloc (narray, sizeof *array);
306 /* Note: The list we return is ordered. */
307 for (idx=0, fd=0; fd < max_fd; fd++)
308 if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
314 narray += (narray < 256)? 32:256;
315 tmp = realloc (array, narray * sizeof *array);
333 copy_quoted (char *p, const char *string)
337 if (!*string) /* Empty string. */
338 p = stpcpy (p, "\"\"");
339 else if (strpbrk (string, " \t\n\v\f\"")) /* Need quotes. */
341 p = stpcpy (p, "\"");
342 for (s = string; *s; s++)
351 else /* Copy verbatim. */
352 p = stpcpy (p, string);
358 /* Build a command line for use with W32's CreateProcess. On success
359 CMDLINE gets the address of a newly allocated string. */
361 build_w32_commandline (const char * const *argv,
362 int rvid0, int rvid1, int rvid2,
374 snprintf (p, 25, "-&S0=%d ", rvid0);
376 strcpy (p, "-&S0=null ");
380 snprintf (p, 25, "-&S1=%d ", rvid1);
382 strcpy (p, "-&S1=null ");
386 snprintf (p, 25, "-&S2=%d ", rvid2);
388 strcpy (p, "-&S2=null ");
393 for (i=0; (s = argv[i]); i++)
395 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
398 n++; /* Need to double inner quotes. */
402 buf = p = xtrymalloc (n);
406 p = stpcpy (p, fdbuf);
407 for (i = 0; argv[i]; i++)
410 p = copy_quoted (p, argv[i]);
418 /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
419 the read end is inheritable, with 1 the write end is inheritable.
420 Note that the inheritable ends are rendezvous ids and no file
421 descriptors or handles. */
423 create_inheritable_pipe (int filedes[2], int inherit_idx)
428 filedes[0] = filedes[1] = -1;
429 hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
430 if (hd == INVALID_HANDLE_VALUE)
432 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n", w32_strerror (-1));
433 gpg_err_set_errno (EIO);
434 return gpg_error_from_syserror ();
439 filedes[0] = handle_to_fd (hd);
445 filedes[1] = handle_to_fd (hd);
451 /* Portable function to create a pipe. Under Windows the write end is
452 inheritable (i.e. an rendezvous id). */
454 gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
457 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
459 return create_inheritable_pipe (filedes, 1);
463 /* Portable function to create a pipe. Under Windows the read end is
464 inheritable (i.e. an rendezvous id). */
466 gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
469 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
471 return create_inheritable_pipe (filedes, 0);
475 /* Portable function to create a pipe. Under Windows both ends are
478 gnupg_create_pipe (int filedes[2])
480 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
485 create_process (const char *pgmname, const char *cmdline,
486 PROCESS_INFORMATION *pi)
489 wchar_t *wpgmname, *wcmdline;
491 wpgmname = utf8_to_wchar (pgmname);
494 wcmdline = utf8_to_wchar (cmdline);
500 res = CreateProcess (wpgmname, /* Program to start. */
501 wcmdline, /* Command line arguments. */
502 NULL, /* Process security attributes. */
503 NULL, /* Thread security attributes. */
504 FALSE, /* Inherit handles. */
505 CREATE_SUSPENDED, /* Creation flags. */
506 NULL, /* Environment. */
507 NULL, /* Use current drive/directory. */
508 NULL, /* Startup information. */
509 pi); /* Returns process information. */
516 /* Fork and exec the PGMNAME, see exechelp.h for details. */
518 gnupg_spawn_process (const char *pgmname, const char *argv[],
519 int *except, void (*preexec)(void), unsigned int flags,
526 PROCESS_INFORMATION pi = {NULL };
532 } inpipe = {INVALID_HANDLE_VALUE, 0};
536 } outpipe = {INVALID_HANDLE_VALUE, 0};
540 } errpipe = {INVALID_HANDLE_VALUE, 0};
541 estream_t outfp = NULL;
542 estream_t errfp = NULL;
543 gpg_err_source_t errsource = default_errsource;
545 (void)except; /* Not yet used. */
549 /* Setup return values. */
554 *pid = (pid_t)(-1); /* Always required. */
556 log_debug ("%s: enter\n", __func__);
562 /* Create a pipe to copy our infile to the stdin of the child
563 process. On success inpipe.hd is owned by the feeder. */
564 inpipe.hd = _assuan_w32ce_prepare_pipe (&inpipe.rvid, 1);
565 if (inpipe.hd == INVALID_HANDLE_VALUE)
567 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
569 gpg_err_set_errno (EIO);
570 return gpg_error_from_syserror ();
572 log_debug ("%s: inpipe %p created; hd=%p rvid=%d\n", __func__,
573 infp, inpipe.hd, inpipe.rvid);
574 err = start_feeder (infp, inpipe.hd, 1);
577 log_error ("error spawning feeder: %s\n", gpg_strerror (err));
578 CloseHandle (inpipe.hd);
581 inpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the feeder. */
582 log_debug ("%s: inpipe %p created; feeder started\n", __func__,
588 /* Create a pipe to make the stdout of the child process
589 available as a stream. */
590 outpipe.hd = _assuan_w32ce_prepare_pipe (&outpipe.rvid, 0);
591 if (outpipe.hd == INVALID_HANDLE_VALUE)
593 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
595 gpg_err_set_errno (EIO);
596 /* Fixme release other stuff/kill feeder. */
597 return gpg_error_from_syserror ();
599 syshd.type = ES_SYSHD_HANDLE;
600 syshd.u.handle = outpipe.hd;
602 outfp = es_sysopen (&syshd, "r");
605 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
606 log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
607 CloseHandle (outpipe.hd);
610 log_debug ("%s: outpipe %p created; hd=%p rvid=%d\n", __func__,
611 outfp, outpipe.hd, outpipe.rvid);
612 outpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the OUTFP. */
617 /* Create a pipe to make the stderr of the child process
618 available as a stream. */
619 errpipe.hd = _assuan_w32ce_prepare_pipe (&errpipe.rvid, 0);
620 if (errpipe.hd == INVALID_HANDLE_VALUE)
622 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
624 gpg_err_set_errno (EIO);
625 /* Fixme release other stuff/kill feeder. */
626 return gpg_error_from_syserror ();
628 syshd.type = ES_SYSHD_HANDLE;
629 syshd.u.handle = errpipe.hd;
631 errfp = es_sysopen (&syshd, "r");
634 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
635 log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
636 CloseHandle (errpipe.hd);
639 log_debug ("%s: errpipe %p created; hd=%p rvid=%d\n", __func__,
640 errfp, errpipe.hd, errpipe.rvid);
641 errpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the ERRFP. */
646 /* Build the command line. */
647 err = build_w32_commandline (argv, inpipe.rvid, outpipe.rvid, errpipe.rvid,
651 /* Fixme release other stuff/kill feeder. */
652 CloseHandle (errpipe.hd);
656 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
657 if (!create_process (pgmname, cmdline, &pi))
659 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
661 /* Fixme release other stuff/kill feeder. */
662 CloseHandle (errpipe.hd);
663 return gpg_error (GPG_ERR_GENERAL);
668 /* Note: The other end of the pipe is a rendezvous id and thus there
669 is no need for a close. */
671 log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
672 " dwProcessID=%d dwThreadId=%d\n",
673 pi.hProcess, pi.hThread,
674 (int) pi.dwProcessId, (int) pi.dwThreadId);
677 /* Process has been created suspended; resume it now. */
678 ResumeThread (pi.hThread);
679 CloseHandle (pi.hThread);
685 *pid = handle_to_pid (pi.hProcess);
691 /* Simplified version of gnupg_spawn_process. This function forks and
692 then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
693 and ERRFD to stderr (any of them may be -1 to connect them to
694 /dev/null). The arguments for the process are expected in the NULL
695 terminated array ARGV. The program name itself should not be
696 included there. Calling gnupg_wait_process is required.
698 Returns 0 on success or an error code. */
700 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
701 int infd, int outfd, int errfd, pid_t *pid)
704 PROCESS_INFORMATION pi = {NULL};
707 /* Setup return values. */
710 if (infd != -1 || outfd != -1 || errfd != -1)
711 return gpg_error (GPG_ERR_NOT_SUPPORTED);
713 /* Build the command line. */
714 err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
718 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
719 if (!create_process (pgmname, cmdline, &pi))
721 log_error ("CreateProcess(fd) failed: %s\n", w32_strerror (-1));
723 return gpg_error (GPG_ERR_GENERAL);
728 log_debug ("CreateProcess(fd) ready: hProcess=%p hThread=%p"
729 " dwProcessID=%d dwThreadId=%d\n",
730 pi.hProcess, pi.hThread,
731 (int) pi.dwProcessId, (int) pi.dwThreadId);
733 /* Process has been created suspended; resume it now. */
734 ResumeThread (pi.hThread);
735 CloseHandle (pi.hThread);
737 *pid = handle_to_pid (pi.hProcess);
742 /* See exechelp.h for a description. */
744 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode)
747 HANDLE proc = fd_to_handle (pid);
754 if (pid == (pid_t)(-1))
755 return gpg_error (GPG_ERR_INV_VALUE);
757 /* FIXME: We should do a pth_waitpid here. However this has not yet
758 been implemented. A special W32 pth system call would even be
760 code = WaitForSingleObject (proc, hang? INFINITE : 0);
764 ec = GPG_ERR_TIMEOUT;
768 log_error (_("waiting for process %d to terminate failed: %s\n"),
769 (int)pid, w32_strerror (-1));
770 ec = GPG_ERR_GENERAL;
774 if (!GetExitCodeProcess (proc, &exc))
776 log_error (_("error getting exit code of process %d: %s\n"),
777 (int)pid, w32_strerror (-1) );
778 ec = GPG_ERR_GENERAL;
782 log_error (_("error running '%s': exit status %d\n"),
785 *exitcode = (int)exc;
786 ec = GPG_ERR_GENERAL;
797 log_error ("WaitForSingleObject returned unexpected "
798 "code %d for pid %d\n", code, (int)pid );
799 ec = GPG_ERR_GENERAL;
803 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
807 /* See exechelp.h for a description. */
809 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
810 int hang, int *r_exitcodes)
812 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
817 gnupg_release_process (pid_t pid)
819 if (pid != (pid_t)INVALID_HANDLE_VALUE)
821 HANDLE process = (HANDLE)pid;
823 CloseHandle (process);
828 /* Spawn a new process and immediately detach from it. The name of
829 the program to exec is PGMNAME and its arguments are in ARGV (the
830 programname is automatically passed as first argument).
831 Environment strings in ENVP are set. An error is returned if
832 pgmname is not executable; to make this work it is necessary to
833 provide an absolute file name. All standard file descriptors are
834 connected to /dev/null. */
836 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
841 PROCESS_INFORMATION pi = {NULL };
845 /* Build the command line. */
846 err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
850 /* Note: There is no detached flag under CE. */
851 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
852 if (!create_process (pgmname, cmdline, &pi))
854 log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
856 return gpg_error (GPG_ERR_GENERAL);
861 log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
862 " dwProcessID=%d dwThreadId=%d\n",
863 pi.hProcess, pi.hThread,
864 (int) pi.dwProcessId, (int) pi.dwThreadId);
866 /* Process has been created suspended; resume it now. */
867 ResumeThread (pi.hThread);
868 CloseHandle (pi.hThread);
874 /* Kill a process; that is send an appropriate signal to the process.
875 gnupg_wait_process must be called to actually remove the process
876 from the system. An invalid PID is ignored. */
878 gnupg_kill_process (pid_t pid)
880 if (pid != (pid_t) INVALID_HANDLE_VALUE)
882 HANDLE process = (HANDLE) pid;
884 /* Arbitrary error code. */
885 TerminateProcess (process, 1);