1 /* $NetBSD: simple_exec_w32.c,v 1.1.1.2 2014/04/24 12:45:52 pettai Exp $ */
3 /***********************************************************************
4 * Copyright (c) 2009, Secure Endpoints Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
32 **********************************************************************/
36 #include <krb5/roken.h>
40 #error This implementation is Windows specific.
44 * wait_for_process_timed waits for a process to terminate or until a
45 * specified timeout occurs.
47 * @param[in] pid Process id for the monitored process
49 * @param[in] func Timeout callback function. When the wait times out,
50 * the callback function is called. The possible return values
51 * from the callback function are:
53 * - ((time_t) -2) Exit loop without killing child and return SE_E_EXECTIMEOUT.
54 * - ((time_t) -1) Kill child with SIGTERM and wait for child to exit.
55 * - 0 Don't timeout again
56 * - n Seconds to next timeout
58 * @param[in] ptr Optional parameter for func()
60 * @param[in] timeout Seconds to first timeout.
62 * @retval SE_E_UNSPECIFIED Unspecified system error
63 * @retval SE_E_FORKFAILED Fork failure (not applicable for _WIN32 targets)
64 * @retval SE_E_WAITPIDFAILED waitpid errors
65 * @retval SE_E_EXECTIMEOUT exec timeout
66 * @retval 0 <= Return value from subprocess
67 * @retval SE_E_NOTFOUND The program coudln't be found
68 * @retval 128- The signal that killed the subprocess +128.
70 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
71 wait_for_process_timed(pid_t pid
, time_t (*func
)(void *),
72 void *ptr
, time_t timeout
)
79 hProcess
= OpenProcess(SYNCHRONIZE
, FALSE
, pid
);
81 if (hProcess
== NULL
) {
82 return SE_E_WAITPIDFAILED
;
85 dtimeout
= (DWORD
) ((timeout
== 0)? INFINITE
: timeout
* 1000);
88 wrv
= WaitForSingleObject(hProcess
, dtimeout
);
90 if (wrv
== WAIT_OBJECT_0
) {
94 GetExitCodeProcess(hProcess
, &prv
);
98 } else if (wrv
== WAIT_TIMEOUT
) {
103 timeout
= (*func
)(ptr
);
105 if (timeout
== (time_t)-1) {
107 if (TerminateProcess(hProcess
, 128 + 9)) {
111 rv
= SE_E_UNSPECIFIED
;
114 } else if (timeout
== (time_t) -2) {
116 rv
= SE_E_EXECTIMEOUT
;
121 dtimeout
= (DWORD
) ((timeout
== 0)? INFINITE
: timeout
* 1000);
128 rv
= SE_E_UNSPECIFIED
;
135 CloseHandle(hProcess
);
140 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
141 wait_for_process(pid_t pid
)
143 return wait_for_process_timed(pid
, NULL
, NULL
, 0);
147 collect_commandline(const char * fn
, va_list * ap
)
150 size_t alloc_len
= 0;
154 for (s
= fn
; s
; s
= (char *) va_arg(*ap
, char *)) {
156 int need_quote
= FALSE
;
158 if (FAILED(StringCchLength(s
, MAX_PATH
, &cmp_len
))) {
167 if (strchr(s
, ' ') && /* need to quote any component that
168 has embedded spaces, but not if
169 they are already quoted. */
171 s
[cmp_len
- 1] != '"') {
173 cmp_len
+= 2 * sizeof(char);
177 cmp_len
+= 1 * sizeof(char);
179 if (alloc_len
< len
+ cmp_len
+ 1) {
182 alloc_len
+= ((len
+ cmp_len
- alloc_len
) / MAX_PATH
+ 1) * MAX_PATH
;
183 nc
= (char *) realloc(cmd
, alloc_len
* sizeof(char));
198 StringCchPrintf(cmd
+ len
, alloc_len
- len
, "\"%s\"", s
);
200 StringCchCopy(cmd
+ len
, alloc_len
- len
, s
);
209 ROKEN_LIB_FUNCTION pid_t ROKEN_LIB_CALL
210 pipe_execv(FILE **stdin_fd
, FILE **stdout_fd
, FILE **stderr_fd
,
211 const char *file
, ...)
213 HANDLE hOut_r
= NULL
;
214 HANDLE hOut_w
= NULL
;
217 HANDLE hErr_r
= NULL
;
218 HANDLE hErr_w
= NULL
;
220 SECURITY_ATTRIBUTES sa
;
222 PROCESS_INFORMATION pi
;
224 char * commandline
= NULL
;
226 pid_t rv
= (pid_t
) -1;
232 commandline
= collect_commandline(file
, &ap
);
234 if (commandline
== NULL
)
238 ZeroMemory(&si
, sizeof(si
));
239 ZeroMemory(&pi
, sizeof(pi
));
240 ZeroMemory(&sa
, sizeof(sa
));
245 sa
.nLength
= sizeof(sa
);
246 sa
.bInheritHandle
= TRUE
;
247 sa
.lpSecurityDescriptor
= NULL
;
249 if ((stdout_fd
&& !CreatePipe(&hOut_r
, &hOut_w
, &sa
, 0 /* Use default */)) ||
251 (stdin_fd
&& !CreatePipe(&hIn_r
, &hIn_w
, &sa
, 0)) ||
253 (stderr_fd
&& !CreatePipe(&hErr_r
, &hErr_w
, &sa
, 0)) ||
255 (!stdout_fd
&& (hOut_w
= CreateFile("CON", GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
256 &sa
, OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
) ||
258 (!stdin_fd
&& (hIn_r
= CreateFile("CON",GENERIC_READ
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
259 &sa
, OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
) ||
261 (!stderr_fd
&& (hErr_w
= CreateFile("CON", GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
262 &sa
, OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
))
266 /* We don't want the child processes inheriting these */
268 SetHandleInformation(hOut_r
, HANDLE_FLAG_INHERIT
, FALSE
);
271 SetHandleInformation(hIn_w
, HANDLE_FLAG_INHERIT
, FALSE
);
274 SetHandleInformation(hErr_r
, HANDLE_FLAG_INHERIT
, FALSE
);
277 si
.lpReserved
= NULL
;
280 si
.dwFlags
= STARTF_USESTDHANDLES
;
281 si
.hStdInput
= hIn_r
;
282 si
.hStdOutput
= hOut_w
;
283 si
.hStdError
= hErr_w
;
285 if (!CreateProcess(file
, commandline
, NULL
, NULL
,
286 TRUE
, /* bInheritHandles */
287 CREATE_NO_WINDOW
, /* dwCreationFlags */
288 NULL
, /* lpEnvironment */
289 NULL
, /* lpCurrentDirectory */
293 rv
= (pid_t
) (GetLastError() == ERROR_FILE_NOT_FOUND
)? 127 : -1;
298 *stdin_fd
= _fdopen(_open_osfhandle((intptr_t) hIn_w
, 0), "wb");
304 *stdout_fd
= _fdopen(_open_osfhandle((intptr_t) hOut_r
, _O_RDONLY
), "rb");
310 *stderr_fd
= _fdopen(_open_osfhandle((intptr_t) hErr_r
, _O_RDONLY
), "rb");
315 rv
= (pid_t
) pi
.dwProcessId
;
319 if (pi
.hProcess
) CloseHandle(pi
.hProcess
);
321 if (pi
.hThread
) CloseHandle(pi
.hThread
);
323 if (hIn_r
) CloseHandle(hIn_r
);
325 if (hIn_w
) CloseHandle(hIn_w
);
327 if (hOut_r
) CloseHandle(hOut_r
);
329 if (hOut_w
) CloseHandle(hOut_w
);
331 if (hErr_r
) CloseHandle(hErr_r
);
333 if (hErr_w
) CloseHandle(hErr_w
);
339 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
340 simple_execvp_timed(const char *file
, char *const args
[],
341 time_t (*func
)(void *), void *ptr
, time_t timeout
)
346 hp
= spawnvp(_P_NOWAIT
, file
, args
);
349 return (errno
== ENOENT
)? 127: 126;
353 rv
= wait_for_process_timed(GetProcessId((HANDLE
) hp
), func
, ptr
, timeout
);
355 CloseHandle((HANDLE
) hp
);
361 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
362 simple_execvp(const char *file
, char *const args
[])
364 return simple_execvp_timed(file
, args
, NULL
, NULL
, 0);
368 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
369 simple_execve_timed(const char *file
, char *const args
[], char *const envp
[],
370 time_t (*func
)(void *), void *ptr
, time_t timeout
)
375 hp
= spawnve(_P_NOWAIT
, file
, args
, envp
);
378 return (errno
== ENOENT
)? 127: 126;
382 rv
= wait_for_process_timed(GetProcessId((HANDLE
) hp
), func
, ptr
, timeout
);
384 CloseHandle((HANDLE
) hp
);
390 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
391 simple_execve(const char *file
, char *const args
[], char *const envp
[])
393 return simple_execve_timed(file
, args
, envp
, NULL
, NULL
, 0);
397 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
398 simple_execlp(const char *file
, ...)
405 argv
= vstrcollect(&ap
);
408 return SE_E_UNSPECIFIED
;
409 ret
= simple_execvp(file
, argv
);
415 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
416 simple_execle(const char *file
, ... /* ,char *const envp[] */)
424 argv
= vstrcollect(&ap
);
425 envp
= va_arg(ap
, char **);
428 return SE_E_UNSPECIFIED
;
429 ret
= simple_execve(file
, argv
, envp
);