1 /**
2 * WinPR: Windows Portable Runtime
3 * Process Thread Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <winpr/handle.h>
26 #include "../handle/nonehandle.h"
27
28 #include <winpr/thread.h>
29
30 /**
31 * CreateProcessA
32 * CreateProcessW
33 * CreateProcessAsUserA
34 * CreateProcessAsUserW
35 * ExitProcess
36 * GetCurrentProcess
37 * GetCurrentProcessId
38 * GetExitCodeProcess
39 * GetProcessHandleCount
40 * GetProcessId
41 * GetProcessIdOfThread
42 * GetProcessMitigationPolicy
43 * GetProcessTimes
44 * GetProcessVersion
45 * OpenProcess
46 * OpenProcessToken
47 * ProcessIdToSessionId
48 * SetProcessAffinityUpdateMode
49 * SetProcessMitigationPolicy
50 * SetProcessShutdownParameters
51 * TerminateProcess
52 */
53
54 #ifndef _WIN32
55
56 #include <winpr/crt.h>
57 #include <winpr/path.h>
58 #include <winpr/environment.h>
59
60 #include <grp.h>
61
62 #include <signal.h>
63
64 #include "thread.h"
65
66 #include "../security/security.h"
67
68 #ifndef NSIG
69 #ifdef SIGMAX
70 #define NSIG SIGMAX
71 #else
72 #define NSIG 64
73 #endif
74 #endif
75
76 /**
77 * If the file name does not contain a directory path, the system searches for the executable file
78 * in the following sequence:
79 *
80 * 1) The directory from which the application loaded.
81 * 2) The current directory for the parent process.
82 * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of
83 * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the
84 * path of this directory, but it is searched. The name of this directory is System. 5) The Windows
85 * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The
86 * directories that are listed in the PATH environment variable. Note that this function does not
87 * search the per-application path specified by the App Paths registry key. To include this
88 * per-application path in the search sequence, use the ShellExecute function.
89 */
90
FindApplicationPath(char * application)91 static char* FindApplicationPath(char* application)
92 {
93 LPCSTR pathName = "PATH";
94 char* path;
95 char* save;
96 DWORD nSize;
97 LPSTR lpSystemPath;
98 char* filename = NULL;
99
100 if (!application)
101 return NULL;
102
103 if (application[0] == '/')
104 return _strdup(application);
105
106 nSize = GetEnvironmentVariableA(pathName, NULL, 0);
107
108 if (!nSize)
109 return _strdup(application);
110
111 lpSystemPath = (LPSTR)malloc(nSize);
112
113 if (!lpSystemPath)
114 return NULL;
115
116 if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
117 {
118 free(lpSystemPath);
119 return NULL;
120 }
121
122 save = NULL;
123 path = strtok_s(lpSystemPath, ":", &save);
124
125 while (path)
126 {
127 filename = GetCombinedPath(path, application);
128
129 if (winpr_PathFileExists(filename))
130 {
131 break;
132 }
133
134 free(filename);
135 filename = NULL;
136 path = strtok_s(NULL, ":", &save);
137 }
138
139 free(lpSystemPath);
140 return filename;
141 }
142
143 static HANDLE CreateProcessHandle(pid_t pid);
144 static BOOL ProcessHandleCloseHandle(HANDLE handle);
145
_CreateProcessExA(HANDLE hToken,DWORD dwLogonFlags,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)146 static BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,
147 LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
148 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
149 DWORD dwCreationFlags, LPVOID lpEnvironment,
150 LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
151 LPPROCESS_INFORMATION lpProcessInformation)
152 {
153 pid_t pid;
154 int numArgs;
155 LPSTR* pArgs = NULL;
156 char** envp = NULL;
157 char* filename = NULL;
158 HANDLE thread;
159 HANDLE process;
160 WINPR_ACCESS_TOKEN* token;
161 LPTCH lpszEnvironmentBlock;
162 BOOL ret = FALSE;
163 sigset_t oldSigMask;
164 sigset_t newSigMask;
165 BOOL restoreSigMask = FALSE;
166 numArgs = 0;
167 lpszEnvironmentBlock = NULL;
168 pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
169
170 if (!pArgs)
171 return FALSE;
172
173 token = (WINPR_ACCESS_TOKEN*)hToken;
174
175 if (lpEnvironment)
176 {
177 envp = EnvironmentBlockToEnvpA(lpEnvironment);
178 }
179 else
180 {
181 lpszEnvironmentBlock = GetEnvironmentStrings();
182
183 if (!lpszEnvironmentBlock)
184 goto finish;
185
186 envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
187 }
188
189 if (!envp)
190 goto finish;
191
192 filename = FindApplicationPath(pArgs[0]);
193
194 if (NULL == filename)
195 goto finish;
196
197 /* block all signals so that the child can safely reset the caller's handlers */
198 sigfillset(&newSigMask);
199 restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
200 /* fork and exec */
201 pid = fork();
202
203 if (pid < 0)
204 {
205 /* fork failure */
206 goto finish;
207 }
208
209 if (pid == 0)
210 {
211 /* child process */
212 #ifndef __sun
213 int maxfd;
214 #endif
215 int fd;
216 int sig;
217 sigset_t set;
218 struct sigaction act;
219 /* set default signal handlers */
220 memset(&act, 0, sizeof(act));
221 act.sa_handler = SIG_DFL;
222 act.sa_flags = 0;
223 sigemptyset(&act.sa_mask);
224
225 for (sig = 1; sig < NSIG; sig++)
226 sigaction(sig, &act, NULL);
227
228 /* unblock all signals */
229 sigfillset(&set);
230 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
231
232 if (lpStartupInfo)
233 {
234 int handle_fd;
235 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
236
237 if (handle_fd != -1)
238 dup2(handle_fd, STDOUT_FILENO);
239
240 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
241
242 if (handle_fd != -1)
243 dup2(handle_fd, STDERR_FILENO);
244
245 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
246
247 if (handle_fd != -1)
248 dup2(handle_fd, STDIN_FILENO);
249 }
250
251 #ifdef __sun
252 closefrom(3);
253 #else
254 #ifdef F_MAXFD // on some BSD derivates
255 maxfd = fcntl(0, F_MAXFD);
256 #else
257 maxfd = sysconf(_SC_OPEN_MAX);
258 #endif
259
260 for (fd = 3; fd < maxfd; fd++)
261 close(fd);
262
263 #endif // __sun
264
265 if (token)
266 {
267 if (token->GroupId)
268 {
269 int rc = setgid((gid_t)token->GroupId);
270
271 if (rc < 0)
272 {
273 }
274 else
275 {
276 initgroups(token->Username, (gid_t)token->GroupId);
277 }
278 }
279
280 if (token->UserId)
281 setuid((uid_t)token->UserId);
282 }
283
284 /* TODO: add better cwd handling and error checking */
285 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
286 chdir(lpCurrentDirectory);
287
288 if (execve(filename, pArgs, envp) < 0)
289 {
290 /* execve failed - end the process */
291 _exit(1);
292 }
293 }
294 else
295 {
296 /* parent process */
297 }
298
299 process = CreateProcessHandle(pid);
300
301 if (!process)
302 {
303 goto finish;
304 }
305
306 thread = CreateNoneHandle();
307
308 if (!thread)
309 {
310 ProcessHandleCloseHandle(process);
311 goto finish;
312 }
313
314 lpProcessInformation->hProcess = process;
315 lpProcessInformation->hThread = thread;
316 lpProcessInformation->dwProcessId = (DWORD)pid;
317 lpProcessInformation->dwThreadId = (DWORD)pid;
318 ret = TRUE;
319 finish:
320
321 /* restore caller's original signal mask */
322 if (restoreSigMask)
323 pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL);
324
325 free(filename);
326
327 if (pArgs)
328 {
329 HeapFree(GetProcessHeap(), 0, pArgs);
330 }
331
332 if (lpszEnvironmentBlock)
333 FreeEnvironmentStrings(lpszEnvironmentBlock);
334
335 if (envp)
336 {
337 int i = 0;
338
339 while (envp[i])
340 {
341 free(envp[i]);
342 i++;
343 }
344
345 free(envp);
346 }
347
348 return ret;
349 }
350
CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)351 BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
352 LPSECURITY_ATTRIBUTES lpProcessAttributes,
353 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
354 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
355 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
356 {
357 return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
358 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
359 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
360 }
361
CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)362 BOOL CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
363 LPSECURITY_ATTRIBUTES lpProcessAttributes,
364 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
365 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
366 LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
367 {
368 return TRUE;
369 }
370
CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)371 BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
372 LPSECURITY_ATTRIBUTES lpProcessAttributes,
373 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
374 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
375 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
376 {
377 return _CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
378 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
379 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
380 }
381
CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)382 BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
383 LPSECURITY_ATTRIBUTES lpProcessAttributes,
384 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
385 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
386 LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
387 {
388 return TRUE;
389 }
390
CreateProcessWithLogonA(LPCSTR lpUsername,LPCSTR lpDomain,LPCSTR lpPassword,DWORD dwLogonFlags,LPCSTR lpApplicationName,LPSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)391 BOOL CreateProcessWithLogonA(LPCSTR lpUsername, LPCSTR lpDomain, LPCSTR lpPassword,
392 DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine,
393 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
394 LPSTARTUPINFOA lpStartupInfo,
395 LPPROCESS_INFORMATION lpProcessInformation)
396 {
397 return TRUE;
398 }
399
CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)400 BOOL CreateProcessWithLogonW(LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword,
401 DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
402 DWORD dwCreationFlags, LPVOID lpEnvironment,
403 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
404 LPPROCESS_INFORMATION lpProcessInformation)
405 {
406 return TRUE;
407 }
408
CreateProcessWithTokenA(HANDLE hToken,DWORD dwLogonFlags,LPCSTR lpApplicationName,LPSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)409 BOOL CreateProcessWithTokenA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName,
410 LPSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,
411 LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
412 LPPROCESS_INFORMATION lpProcessInformation)
413 {
414 return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, NULL, NULL, FALSE,
415 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
416 lpProcessInformation);
417 }
418
CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)419 BOOL CreateProcessWithTokenW(HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName,
420 LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment,
421 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
422 LPPROCESS_INFORMATION lpProcessInformation)
423 {
424 return TRUE;
425 }
426
ExitProcess(UINT uExitCode)427 VOID ExitProcess(UINT uExitCode)
428 {
429 exit((int)uExitCode);
430 }
431
GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode)432 BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
433 {
434 WINPR_PROCESS* process;
435
436 if (!hProcess)
437 return FALSE;
438
439 if (!lpExitCode)
440 return FALSE;
441
442 process = (WINPR_PROCESS*)hProcess;
443 *lpExitCode = process->dwExitCode;
444 return TRUE;
445 }
446
_GetCurrentProcess(VOID)447 HANDLE _GetCurrentProcess(VOID)
448 {
449 return NULL;
450 }
451
GetCurrentProcessId(VOID)452 DWORD GetCurrentProcessId(VOID)
453 {
454 return ((DWORD)getpid());
455 }
456
TerminateProcess(HANDLE hProcess,UINT uExitCode)457 BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode)
458 {
459 WINPR_PROCESS* process;
460 process = (WINPR_PROCESS*)hProcess;
461
462 if (!process || (process->pid <= 0))
463 return FALSE;
464
465 if (kill(process->pid, SIGTERM))
466 return FALSE;
467
468 return TRUE;
469 }
470
ProcessHandleCloseHandle(HANDLE handle)471 static BOOL ProcessHandleCloseHandle(HANDLE handle)
472 {
473 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
474 free(process);
475 return TRUE;
476 }
477
ProcessHandleIsHandle(HANDLE handle)478 static BOOL ProcessHandleIsHandle(HANDLE handle)
479 {
480 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
481
482 if (!process || process->Type != HANDLE_TYPE_PROCESS)
483 {
484 SetLastError(ERROR_INVALID_HANDLE);
485 return FALSE;
486 }
487
488 return TRUE;
489 }
490
ProcessGetFd(HANDLE handle)491 static int ProcessGetFd(HANDLE handle)
492 {
493 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
494
495 if (!ProcessHandleIsHandle(handle))
496 return -1;
497
498 /* TODO: Process does not support fd... */
499 (void)process;
500 return -1;
501 }
502
503 static HANDLE_OPS ops = { ProcessHandleIsHandle,
504 ProcessHandleCloseHandle,
505 ProcessGetFd,
506 NULL, /* CleanupHandle */
507 NULL,
508 NULL,
509 NULL,
510 NULL,
511 NULL,
512 NULL,
513 NULL,
514 NULL,
515 NULL,
516 NULL,
517 NULL,
518 NULL,
519 NULL,
520 NULL,
521 NULL,
522 NULL };
523
CreateProcessHandle(pid_t pid)524 HANDLE CreateProcessHandle(pid_t pid)
525 {
526 WINPR_PROCESS* process;
527 process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
528
529 if (!process)
530 return NULL;
531
532 process->pid = pid;
533 process->Type = HANDLE_TYPE_PROCESS;
534 process->ops = &ops;
535 return (HANDLE)process;
536 }
537
538 #endif
539