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