/src/FreeRDP/winpr/libwinpr/thread/process.c
Line | Count | Source |
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 | | #include <winpr/config.h> |
22 | | |
23 | | #include <winpr/handle.h> |
24 | | #include "../handle/nonehandle.h" |
25 | | |
26 | | #include <winpr/thread.h> |
27 | | #include <winpr/wlog.h> |
28 | | |
29 | | /** |
30 | | * CreateProcessA |
31 | | * CreateProcessW |
32 | | * CreateProcessAsUserA |
33 | | * CreateProcessAsUserW |
34 | | * ExitProcess |
35 | | * GetCurrentProcess |
36 | | * GetCurrentProcessId |
37 | | * GetExitCodeProcess |
38 | | * GetProcessHandleCount |
39 | | * GetProcessId |
40 | | * GetProcessIdOfThread |
41 | | * GetProcessMitigationPolicy |
42 | | * GetProcessTimes |
43 | | * GetProcessVersion |
44 | | * OpenProcess |
45 | | * OpenProcessToken |
46 | | * ProcessIdToSessionId |
47 | | * SetProcessAffinityUpdateMode |
48 | | * SetProcessMitigationPolicy |
49 | | * SetProcessShutdownParameters |
50 | | * TerminateProcess |
51 | | */ |
52 | | |
53 | | #ifndef _WIN32 |
54 | | |
55 | | #include <winpr/assert.h> |
56 | | #include <winpr/crt.h> |
57 | | #include <winpr/path.h> |
58 | | #include <winpr/environment.h> |
59 | | |
60 | | #include <grp.h> |
61 | | |
62 | | #include <fcntl.h> |
63 | | #include <signal.h> |
64 | | #include <sys/types.h> |
65 | | #include <sys/wait.h> |
66 | | |
67 | | #ifdef __linux__ |
68 | | #include <sys/syscall.h> |
69 | | #include <errno.h> |
70 | | #endif /* __linux__ */ |
71 | | |
72 | | #include "thread.h" |
73 | | |
74 | | #include "../handle/handle.h" |
75 | | #include "../security/security.h" |
76 | | |
77 | | #ifndef NSIG |
78 | | #ifdef SIGMAX |
79 | | #define NSIG SIGMAX |
80 | | #else |
81 | | #define NSIG 64 |
82 | | #endif |
83 | | #endif |
84 | | |
85 | | /** |
86 | | * If the file name does not contain a directory path, the system searches for the executable file |
87 | | * in the following sequence: |
88 | | * |
89 | | * 1) The directory from which the application loaded. |
90 | | * 2) The current directory for the parent process. |
91 | | * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of |
92 | | * this directory. 4) The 16-bit Windows system directory. There is no function that obtains the |
93 | | * path of this directory, but it is searched. The name of this directory is System. 5) The Windows |
94 | | * directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The |
95 | | * directories that are listed in the PATH environment variable. Note that this function does not |
96 | | * search the per-application path specified by the App Paths registry key. To include this |
97 | | * per-application path in the search sequence, use the ShellExecute function. |
98 | | */ |
99 | | |
100 | | static char* FindApplicationPath(char* application) |
101 | 0 | { |
102 | 0 | LPCSTR pathName = "PATH"; |
103 | 0 | char* path = nullptr; |
104 | 0 | char* save = nullptr; |
105 | 0 | DWORD nSize = 0; |
106 | 0 | LPSTR lpSystemPath = nullptr; |
107 | 0 | char* filename = nullptr; |
108 | |
|
109 | 0 | if (!application) |
110 | 0 | return nullptr; |
111 | | |
112 | 0 | if (application[0] == '/') |
113 | 0 | return _strdup(application); |
114 | | |
115 | 0 | nSize = GetEnvironmentVariableA(pathName, nullptr, 0); |
116 | |
|
117 | 0 | if (!nSize) |
118 | 0 | return _strdup(application); |
119 | | |
120 | 0 | lpSystemPath = (LPSTR)malloc(nSize); |
121 | |
|
122 | 0 | if (!lpSystemPath) |
123 | 0 | return nullptr; |
124 | | |
125 | 0 | if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1) |
126 | 0 | { |
127 | 0 | free(lpSystemPath); |
128 | 0 | return nullptr; |
129 | 0 | } |
130 | | |
131 | 0 | save = nullptr; |
132 | 0 | path = strtok_s(lpSystemPath, ":", &save); |
133 | |
|
134 | 0 | while (path) |
135 | 0 | { |
136 | 0 | filename = GetCombinedPath(path, application); |
137 | |
|
138 | 0 | if (winpr_PathFileExists(filename)) |
139 | 0 | { |
140 | 0 | break; |
141 | 0 | } |
142 | | |
143 | 0 | free(filename); |
144 | 0 | filename = nullptr; |
145 | 0 | path = strtok_s(nullptr, ":", &save); |
146 | 0 | } |
147 | |
|
148 | 0 | free(lpSystemPath); |
149 | 0 | return filename; |
150 | 0 | } |
151 | | |
152 | | static HANDLE CreateProcessHandle(pid_t pid); |
153 | | static BOOL ProcessHandleCloseHandle(HANDLE handle); |
154 | | |
155 | | static BOOL CreateProcessExA(HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags, |
156 | | LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine, |
157 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes, |
158 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes, |
159 | | BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, |
160 | | LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, |
161 | | LPPROCESS_INFORMATION lpProcessInformation) |
162 | 0 | { |
163 | 0 | pid_t pid = 0; |
164 | 0 | int numArgs = 0; |
165 | 0 | LPSTR* pArgs = nullptr; |
166 | 0 | char** envp = nullptr; |
167 | 0 | char* filename = nullptr; |
168 | 0 | HANDLE thread = nullptr; |
169 | 0 | HANDLE process = nullptr; |
170 | 0 | WINPR_ACCESS_TOKEN* token = nullptr; |
171 | 0 | LPTCH lpszEnvironmentBlock = nullptr; |
172 | 0 | BOOL ret = FALSE; |
173 | 0 | sigset_t oldSigMask; |
174 | 0 | sigset_t newSigMask; |
175 | 0 | BOOL restoreSigMask = FALSE; |
176 | 0 | numArgs = 0; |
177 | 0 | lpszEnvironmentBlock = nullptr; |
178 | | /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa |
179 | | */ |
180 | |
|
181 | 0 | if (lpCommandLine && lpApplicationName) |
182 | 0 | { |
183 | 0 | char* str = nullptr; |
184 | 0 | size_t len = 0; |
185 | 0 | winpr_asprintf(&str, &len, "%s %s", lpApplicationName, lpCommandLine); |
186 | 0 | if (!str) |
187 | 0 | return FALSE; |
188 | 0 | pArgs = CommandLineToArgvA(str, &numArgs); |
189 | 0 | free(str); |
190 | 0 | } |
191 | 0 | else if (lpCommandLine) |
192 | 0 | pArgs = CommandLineToArgvA(lpCommandLine, &numArgs); |
193 | 0 | else |
194 | 0 | pArgs = CommandLineToArgvA(lpApplicationName, &numArgs); |
195 | | |
196 | 0 | if (!pArgs) |
197 | 0 | return FALSE; |
198 | | |
199 | 0 | token = (WINPR_ACCESS_TOKEN*)hToken; |
200 | |
|
201 | 0 | if (lpEnvironment) |
202 | 0 | { |
203 | 0 | envp = EnvironmentBlockToEnvpA(lpEnvironment); |
204 | 0 | } |
205 | 0 | else |
206 | 0 | { |
207 | 0 | lpszEnvironmentBlock = GetEnvironmentStrings(); |
208 | |
|
209 | 0 | if (!lpszEnvironmentBlock) |
210 | 0 | goto finish; |
211 | | |
212 | 0 | envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock); |
213 | 0 | } |
214 | | |
215 | 0 | if (!envp) |
216 | 0 | goto finish; |
217 | | |
218 | 0 | filename = FindApplicationPath(pArgs[0]); |
219 | |
|
220 | 0 | if (nullptr == filename) |
221 | 0 | goto finish; |
222 | | |
223 | | /* Windows validates a PROC_THREAD_ATTRIBUTE_HANDLE_LIST's handles are still open before |
224 | | * creating the process at all, failing the whole call with ERROR_INVALID_PARAMETER if one |
225 | | * isn't (confirmed empirically: a handle CloseHandle()'d before this call, still listed here, |
226 | | * makes real CreateProcess fail this way rather than silently omitting it) */ |
227 | 0 | if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT)) |
228 | 0 | { |
229 | 0 | const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo; |
230 | 0 | const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList; |
231 | |
|
232 | 0 | for (DWORD i = 0; list && (i < list->count); i++) |
233 | 0 | { |
234 | 0 | const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i]; |
235 | 0 | if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST) |
236 | 0 | continue; |
237 | | |
238 | 0 | const HANDLE* handles = (const HANDLE*)entry->lpValue; |
239 | 0 | const size_t count = entry->cbSize / sizeof(HANDLE); |
240 | 0 | for (size_t h = 0; h < count; h++) |
241 | 0 | { |
242 | 0 | if (winpr_Handle_getFd(handles[h]) < 0) |
243 | 0 | { |
244 | 0 | SetLastError(ERROR_INVALID_PARAMETER); |
245 | 0 | goto finish; |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | /* block all signals so that the child can safely reset the caller's handlers */ |
252 | 0 | sigfillset(&newSigMask); |
253 | 0 | restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask); |
254 | | /* fork and exec */ |
255 | 0 | pid = fork(); |
256 | |
|
257 | 0 | if (pid < 0) |
258 | 0 | { |
259 | | /* fork failure */ |
260 | 0 | goto finish; |
261 | 0 | } |
262 | | |
263 | 0 | if (pid == 0) |
264 | 0 | { |
265 | | /* child process */ |
266 | 0 | #ifndef __sun |
267 | 0 | int maxfd = 0; |
268 | 0 | #endif |
269 | 0 | sigset_t set = WINPR_C_ARRAY_INIT; |
270 | 0 | struct sigaction act = WINPR_C_ARRAY_INIT; |
271 | | |
272 | | /* resolve an explicit PROC_THREAD_ATTRIBUTE_HANDLE_LIST, if the caller opted into one |
273 | | * via a STARTUPINFOEX + EXTENDED_STARTUPINFO_PRESENT. Per documented Windows behavior: |
274 | | * - bInheritHandles == FALSE: nothing is inherited, full stop - a handle list (if any) |
275 | | * is ignored too, it can only narrow inheritance, never expand it. |
276 | | * - bInheritHandles == TRUE and a handle list is present: it becomes the *exclusive* |
277 | | * source of truth for which extra fds survive into this child - only the listed |
278 | | * handles are inherited, even other handles independently marked inheritable are not. |
279 | | * - bInheritHandles == TRUE and no handle list: every fd not marked close-on-exec is |
280 | | * inherited, exactly like real Windows inheriting every handle marked inheritable - |
281 | | * including ones WinPR doesn't know about (e.g. opened by a linked library), since |
282 | | * Windows itself has no concept of "handles the runtime knows about" either. */ |
283 | 0 | #define WINPR_MAX_INHERITED_HANDLES 64 |
284 | 0 | int keepFds[WINPR_MAX_INHERITED_HANDLES] = { -1 }; |
285 | 0 | size_t nKeepFds = 0; |
286 | 0 | BOOL haveHandleList = FALSE; |
287 | |
|
288 | 0 | if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT)) |
289 | 0 | { |
290 | 0 | const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo; |
291 | 0 | const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList; |
292 | |
|
293 | 0 | for (DWORD i = 0; list && (i < list->count); i++) |
294 | 0 | { |
295 | 0 | const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i]; |
296 | 0 | if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST) |
297 | 0 | continue; |
298 | | |
299 | 0 | haveHandleList = TRUE; |
300 | 0 | const HANDLE* handles = (const HANDLE*)entry->lpValue; |
301 | 0 | const size_t count = entry->cbSize / sizeof(HANDLE); |
302 | 0 | for (size_t h = 0; (h < count) && (nKeepFds < WINPR_MAX_INHERITED_HANDLES); h++) |
303 | 0 | { |
304 | 0 | const int fd = winpr_Handle_getFd(handles[h]); |
305 | 0 | if (fd >= 0) |
306 | 0 | keepFds[nKeepFds++] = fd; |
307 | 0 | } |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | /* set default signal handlers */ |
312 | 0 | act.sa_handler = SIG_DFL; |
313 | 0 | act.sa_flags = 0; |
314 | 0 | sigemptyset(&act.sa_mask); |
315 | |
|
316 | 0 | for (int sig = 1; sig < NSIG; sig++) |
317 | 0 | sigaction(sig, &act, nullptr); |
318 | | |
319 | | /* unblock all signals */ |
320 | 0 | sigfillset(&set); |
321 | 0 | pthread_sigmask(SIG_UNBLOCK, &set, nullptr); |
322 | |
|
323 | 0 | if (lpStartupInfo) |
324 | 0 | { |
325 | 0 | int handle_fd = 0; |
326 | 0 | handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput); |
327 | |
|
328 | 0 | if (handle_fd != -1) |
329 | 0 | dup2(handle_fd, STDOUT_FILENO); |
330 | |
|
331 | 0 | handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError); |
332 | |
|
333 | 0 | if (handle_fd != -1) |
334 | 0 | dup2(handle_fd, STDERR_FILENO); |
335 | |
|
336 | 0 | handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput); |
337 | |
|
338 | 0 | if (handle_fd != -1) |
339 | 0 | dup2(handle_fd, STDIN_FILENO); |
340 | 0 | } |
341 | |
|
342 | | #ifdef __sun |
343 | | if (!bInheritHandles || !haveHandleList) |
344 | | closefrom(3); |
345 | | /* else: Solaris has no per-fd enumeration primitive as cheap as the loop below, and a |
346 | | * handle list is a narrow/rare case there - fall through without closing anything |
347 | | * rather than silently ignoring the caller's explicit allowlist. */ |
348 | | #else |
349 | | #ifdef F_MAXFD // on some BSD derivates |
350 | | maxfd = fcntl(0, F_MAXFD); |
351 | | #else |
352 | 0 | { |
353 | 0 | const long rc = sysconf(_SC_OPEN_MAX); |
354 | 0 | if ((rc < INT32_MIN) || (rc > INT32_MAX)) |
355 | 0 | goto finish; |
356 | 0 | maxfd = (int)rc; |
357 | 0 | } |
358 | 0 | #endif |
359 | | |
360 | | /* - bInheritHandles == FALSE: keep stays FALSE for every fd, close everything. |
361 | | * - bInheritHandles == TRUE, handle list present: exclusive allowlist (see above). |
362 | | * - bInheritHandles == TRUE, no handle list: inherit everything not close-on-exec. */ |
363 | 0 | for (int fd = 3; fd < maxfd; fd++) |
364 | 0 | { |
365 | 0 | BOOL keep = FALSE; |
366 | |
|
367 | 0 | if (bInheritHandles) |
368 | 0 | { |
369 | 0 | if (haveHandleList) |
370 | 0 | { |
371 | 0 | for (size_t k = 0; k < nKeepFds; k++) |
372 | 0 | { |
373 | 0 | if (keepFds[k] == fd) |
374 | 0 | { |
375 | 0 | keep = TRUE; |
376 | 0 | break; |
377 | 0 | } |
378 | 0 | } |
379 | 0 | } |
380 | 0 | else |
381 | 0 | { |
382 | 0 | const int flags = fcntl(fd, F_GETFD); |
383 | 0 | keep = (flags >= 0) && !(flags & FD_CLOEXEC); |
384 | 0 | } |
385 | 0 | } |
386 | |
|
387 | 0 | if (!keep) |
388 | 0 | close(fd); |
389 | 0 | } |
390 | |
|
391 | 0 | #endif // __sun |
392 | |
|
393 | 0 | if (token) |
394 | 0 | { |
395 | 0 | if (token->GroupId) |
396 | 0 | { |
397 | 0 | int rc = setgid((gid_t)token->GroupId); |
398 | |
|
399 | 0 | if (rc < 0) |
400 | 0 | { |
401 | 0 | } |
402 | 0 | else |
403 | 0 | { |
404 | 0 | initgroups(token->Username, (gid_t)token->GroupId); |
405 | 0 | } |
406 | 0 | } |
407 | |
|
408 | 0 | if (token->UserId) |
409 | 0 | { |
410 | 0 | int rc = setuid((uid_t)token->UserId); |
411 | 0 | if (rc != 0) |
412 | 0 | goto finish; |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | /* TODO: add better cwd handling and error checking */ |
417 | 0 | if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0) |
418 | 0 | { |
419 | 0 | int rc = chdir(lpCurrentDirectory); |
420 | 0 | if (rc != 0) |
421 | 0 | goto finish; |
422 | 0 | } |
423 | | |
424 | 0 | if (execve(filename, pArgs, envp) < 0) |
425 | 0 | { |
426 | | /* execve failed - end the process */ |
427 | 0 | _exit(1); |
428 | 0 | } |
429 | 0 | } |
430 | 0 | else |
431 | 0 | { |
432 | | /* parent process */ |
433 | 0 | } |
434 | | |
435 | 0 | process = CreateProcessHandle(pid); |
436 | |
|
437 | 0 | if (!process) |
438 | 0 | { |
439 | 0 | goto finish; |
440 | 0 | } |
441 | | |
442 | 0 | thread = CreateNoneHandle(); |
443 | |
|
444 | 0 | if (!thread) |
445 | 0 | { |
446 | 0 | ProcessHandleCloseHandle(process); |
447 | 0 | free(process); |
448 | 0 | goto finish; |
449 | 0 | } |
450 | | |
451 | 0 | lpProcessInformation->hProcess = process; |
452 | 0 | lpProcessInformation->hThread = thread; |
453 | 0 | lpProcessInformation->dwProcessId = (DWORD)pid; |
454 | 0 | lpProcessInformation->dwThreadId = (DWORD)pid; |
455 | 0 | ret = TRUE; |
456 | 0 | finish: |
457 | | |
458 | | /* restore caller's original signal mask */ |
459 | 0 | if (restoreSigMask) |
460 | 0 | pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr); |
461 | |
|
462 | 0 | free(filename); |
463 | 0 | free((void*)pArgs); |
464 | |
|
465 | 0 | if (lpszEnvironmentBlock) |
466 | 0 | FreeEnvironmentStrings(lpszEnvironmentBlock); |
467 | |
|
468 | 0 | if (envp) |
469 | 0 | { |
470 | 0 | int i = 0; |
471 | |
|
472 | 0 | while (envp[i]) |
473 | 0 | { |
474 | 0 | free(envp[i]); |
475 | 0 | i++; |
476 | 0 | } |
477 | |
|
478 | 0 | free((void*)envp); |
479 | 0 | } |
480 | |
|
481 | 0 | return ret; |
482 | 0 | } |
483 | | |
484 | | BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, |
485 | | LPSECURITY_ATTRIBUTES lpProcessAttributes, |
486 | | LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, |
487 | | DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, |
488 | | LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) |
489 | 0 | { |
490 | 0 | return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes, |
491 | 0 | lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, |
492 | 0 | lpCurrentDirectory, lpStartupInfo, lpProcessInformation); |
493 | 0 | } |
494 | | |
495 | | BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, |
496 | | WINPR_ATTR_UNUSED LPWSTR lpCommandLine, |
497 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes, |
498 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes, |
499 | | WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags, |
500 | | WINPR_ATTR_UNUSED LPVOID lpEnvironment, |
501 | | WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, |
502 | | WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo, |
503 | | WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation) |
504 | 0 | { |
505 | 0 | WINPR_ASSERT(lpStartupInfo); |
506 | 0 | WINPR_ASSERT(lpProcessInformation); |
507 | |
|
508 | 0 | LPSTR lpApplicationNameA = nullptr; |
509 | 0 | LPSTR lpCommandLineA = nullptr; |
510 | 0 | LPSTR lpCurrentDirectoryA = nullptr; |
511 | 0 | STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA), |
512 | 0 | .lpReserved = nullptr, |
513 | 0 | .lpDesktop = nullptr, |
514 | 0 | .lpTitle = nullptr, |
515 | 0 | .dwX = lpStartupInfo->dwX, |
516 | 0 | .dwY = lpStartupInfo->dwY, |
517 | 0 | .dwXSize = lpStartupInfo->dwXSize, |
518 | 0 | .dwYSize = lpStartupInfo->dwYSize, |
519 | 0 | .dwXCountChars = lpStartupInfo->dwXCountChars, |
520 | 0 | .dwYCountChars = lpStartupInfo->dwYCountChars, |
521 | 0 | .dwFillAttribute = lpStartupInfo->dwFillAttribute, |
522 | 0 | .dwFlags = lpStartupInfo->dwFlags, |
523 | 0 | .wShowWindow = lpStartupInfo->wShowWindow, |
524 | 0 | .cbReserved2 = lpStartupInfo->cbReserved2, |
525 | 0 | .lpReserved2 = lpStartupInfo->lpReserved2, |
526 | 0 | .hStdInput = lpStartupInfo->hStdInput, |
527 | 0 | .hStdOutput = lpStartupInfo->hStdOutput, |
528 | 0 | .hStdError = lpStartupInfo->hStdError }; |
529 | |
|
530 | 0 | BOOL rc = FALSE; |
531 | 0 | if (lpApplicationName) |
532 | 0 | { |
533 | 0 | lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr); |
534 | 0 | if (!lpApplicationNameA) |
535 | 0 | goto fail; |
536 | 0 | } |
537 | 0 | if (lpCommandLine) |
538 | 0 | { |
539 | 0 | lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr); |
540 | 0 | if (!lpCommandLineA) |
541 | 0 | goto fail; |
542 | 0 | } |
543 | 0 | if (lpCurrentDirectory) |
544 | 0 | { |
545 | 0 | lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr); |
546 | 0 | if (!lpCurrentDirectoryA) |
547 | 0 | goto fail; |
548 | 0 | } |
549 | 0 | if (lpStartupInfo->lpReserved) |
550 | 0 | { |
551 | 0 | StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr); |
552 | 0 | if (!StartupInfoA.lpReserved) |
553 | 0 | goto fail; |
554 | 0 | } |
555 | 0 | if (lpStartupInfo->lpDesktop) |
556 | 0 | { |
557 | 0 | StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr); |
558 | 0 | if (!StartupInfoA.lpDesktop) |
559 | 0 | goto fail; |
560 | 0 | } |
561 | 0 | if (lpStartupInfo->lpTitle) |
562 | 0 | { |
563 | 0 | StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr); |
564 | 0 | if (!StartupInfoA.lpTitle) |
565 | 0 | goto fail; |
566 | 0 | } |
567 | | |
568 | 0 | rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes, |
569 | 0 | bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA, |
570 | 0 | &StartupInfoA, lpProcessInformation); |
571 | 0 | fail: |
572 | 0 | free(lpApplicationNameA); |
573 | 0 | free(lpCommandLineA); |
574 | 0 | free(lpCurrentDirectoryA); |
575 | 0 | free(StartupInfoA.lpDesktop); |
576 | 0 | free(StartupInfoA.lpReserved); |
577 | 0 | free(StartupInfoA.lpTitle); |
578 | 0 | return rc; |
579 | 0 | } |
580 | | |
581 | | BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, |
582 | | LPSECURITY_ATTRIBUTES lpProcessAttributes, |
583 | | LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, |
584 | | DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, |
585 | | LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) |
586 | 0 | { |
587 | 0 | return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes, |
588 | 0 | lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, |
589 | 0 | lpCurrentDirectory, lpStartupInfo, lpProcessInformation); |
590 | 0 | } |
591 | | |
592 | | BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken, |
593 | | WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, |
594 | | WINPR_ATTR_UNUSED LPWSTR lpCommandLine, |
595 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes, |
596 | | WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes, |
597 | | WINPR_ATTR_UNUSED BOOL bInheritHandles, |
598 | | WINPR_ATTR_UNUSED DWORD dwCreationFlags, |
599 | | WINPR_ATTR_UNUSED LPVOID lpEnvironment, |
600 | | WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, |
601 | | WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo, |
602 | | WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation) |
603 | 0 | { |
604 | 0 | WLog_ERR("TODO", "TODO: implement"); |
605 | 0 | return FALSE; |
606 | 0 | } |
607 | | |
608 | | BOOL CreateProcessWithLogonA( |
609 | | WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain, |
610 | | WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags, |
611 | | WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine, |
612 | | WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment, |
613 | | WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo, |
614 | | WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation) |
615 | 0 | { |
616 | 0 | WLog_ERR("TODO", "TODO: implement"); |
617 | 0 | return FALSE; |
618 | 0 | } |
619 | | |
620 | | BOOL CreateProcessWithLogonW( |
621 | | WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain, |
622 | | WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags, |
623 | | WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine, |
624 | | WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment, |
625 | | WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo, |
626 | | WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation) |
627 | 0 | { |
628 | 0 | WLog_ERR("TODO", "TODO: implement"); |
629 | 0 | return FALSE; |
630 | 0 | } |
631 | | |
632 | | BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags, |
633 | | LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags, |
634 | | LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, |
635 | | LPSTARTUPINFOA lpStartupInfo, |
636 | | LPPROCESS_INFORMATION lpProcessInformation) |
637 | 0 | { |
638 | 0 | return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE, |
639 | 0 | dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, |
640 | 0 | lpProcessInformation); |
641 | 0 | } |
642 | | |
643 | | BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags, |
644 | | WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, |
645 | | WINPR_ATTR_UNUSED LPWSTR lpCommandLine, |
646 | | WINPR_ATTR_UNUSED DWORD dwCreationFlags, |
647 | | WINPR_ATTR_UNUSED LPVOID lpEnvironment, |
648 | | WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, |
649 | | WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo, |
650 | | WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation) |
651 | 0 | { |
652 | 0 | WLog_ERR("TODO", "TODO: implement"); |
653 | 0 | return FALSE; |
654 | 0 | } |
655 | | |
656 | | VOID ExitProcess(UINT uExitCode) |
657 | 0 | { |
658 | | // NOLINTNEXTLINE(concurrency-mt-unsafe) |
659 | 0 | exit((int)uExitCode); |
660 | 0 | } |
661 | | |
662 | | BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) |
663 | 0 | { |
664 | 0 | WINPR_PROCESS* process = nullptr; |
665 | |
|
666 | 0 | if (!hProcess) |
667 | 0 | return FALSE; |
668 | | |
669 | 0 | if (!lpExitCode) |
670 | 0 | return FALSE; |
671 | | |
672 | 0 | process = (WINPR_PROCESS*)hProcess; |
673 | 0 | *lpExitCode = process->dwExitCode; |
674 | 0 | return TRUE; |
675 | 0 | } |
676 | | |
677 | | HANDLE _GetCurrentProcess(VOID) |
678 | 0 | { |
679 | 0 | WLog_ERR("TODO", "TODO: implement"); |
680 | 0 | return nullptr; |
681 | 0 | } |
682 | | |
683 | | DWORD GetCurrentProcessId(VOID) |
684 | 3.70k | { |
685 | 3.70k | return ((DWORD)getpid()); |
686 | 3.70k | } |
687 | | |
688 | | BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode) |
689 | 0 | { |
690 | 0 | WINPR_PROCESS* process = nullptr; |
691 | 0 | process = (WINPR_PROCESS*)hProcess; |
692 | |
|
693 | 0 | if (!process || (process->pid <= 0)) |
694 | 0 | return FALSE; |
695 | | |
696 | 0 | if (kill(process->pid, SIGTERM)) |
697 | 0 | return FALSE; |
698 | | |
699 | 0 | return TRUE; |
700 | 0 | } |
701 | | |
702 | | static BOOL ProcessHandleCloseHandle(HANDLE handle) |
703 | 0 | { |
704 | 0 | WINPR_PROCESS* process = (WINPR_PROCESS*)handle; |
705 | 0 | WINPR_ASSERT(process); |
706 | 0 | if (process->fd >= 0) |
707 | 0 | { |
708 | 0 | close(process->fd); |
709 | 0 | process->fd = -1; |
710 | 0 | } |
711 | 0 | return TRUE; |
712 | 0 | } |
713 | | |
714 | | static BOOL ProcessHandleIsHandle(HANDLE handle) |
715 | 0 | { |
716 | 0 | return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE); |
717 | 0 | } |
718 | | |
719 | | static int ProcessGetFd(HANDLE handle) |
720 | 0 | { |
721 | 0 | WINPR_PROCESS* process = (WINPR_PROCESS*)handle; |
722 | |
|
723 | 0 | if (!ProcessHandleIsHandle(handle)) |
724 | 0 | return -1; |
725 | | |
726 | 0 | return process->fd; |
727 | 0 | } |
728 | | |
729 | | static DWORD ProcessCleanupHandle(HANDLE handle) |
730 | 0 | { |
731 | 0 | WINPR_PROCESS* process = (WINPR_PROCESS*)handle; |
732 | |
|
733 | 0 | WINPR_ASSERT(process); |
734 | 0 | if (process->fd > 0) |
735 | 0 | { |
736 | 0 | if (waitpid(process->pid, &process->status, WNOHANG) == process->pid) |
737 | 0 | { |
738 | 0 | if (WIFEXITED(process->status)) |
739 | 0 | process->dwExitCode = (DWORD)WEXITSTATUS(process->status); |
740 | 0 | else if (WIFSIGNALED(process->status)) |
741 | 0 | process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status)); |
742 | 0 | else |
743 | 0 | process->dwExitCode = (DWORD)process->status; |
744 | 0 | } |
745 | 0 | } |
746 | 0 | return WAIT_OBJECT_0; |
747 | 0 | } |
748 | | |
749 | | static HANDLE_OPS ops = { ProcessHandleIsHandle, |
750 | | ProcessHandleCloseHandle, |
751 | | ProcessGetFd, |
752 | | ProcessCleanupHandle, /* CleanupHandle */ |
753 | | nullptr, |
754 | | nullptr, |
755 | | nullptr, |
756 | | nullptr, |
757 | | nullptr, |
758 | | nullptr, |
759 | | nullptr, |
760 | | nullptr, |
761 | | nullptr, |
762 | | nullptr, |
763 | | nullptr, |
764 | | nullptr, |
765 | | nullptr, |
766 | | nullptr, |
767 | | nullptr, |
768 | | nullptr, |
769 | | nullptr }; |
770 | | |
771 | | static int pidfd_open(pid_t pid) |
772 | 0 | { |
773 | 0 | #ifdef __linux__ |
774 | | #if !defined(__NR_pidfd_open) |
775 | | #define __NR_pidfd_open 434 |
776 | | #endif /* __NR_pidfd_open */ |
777 | |
|
778 | 0 | #ifndef PIDFD_NONBLOCK |
779 | 0 | #define PIDFD_NONBLOCK O_NONBLOCK |
780 | 0 | #endif /* PIDFD_NONBLOCK */ |
781 | |
|
782 | 0 | long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK); |
783 | 0 | if (fd < 0 && errno == EINVAL) |
784 | 0 | { |
785 | | /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it |
786 | | * non blocking afterward */ |
787 | 0 | int flags = 0; |
788 | 0 | fd = syscall(__NR_pidfd_open, pid, 0); |
789 | 0 | if ((fd < 0) || (fd > INT32_MAX)) |
790 | 0 | return -1; |
791 | | |
792 | 0 | flags = fcntl((int)fd, F_GETFL); |
793 | 0 | if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0) |
794 | 0 | { |
795 | 0 | close((int)fd); |
796 | 0 | fd = -1; |
797 | 0 | } |
798 | 0 | } |
799 | 0 | if ((fd < 0) || (fd > INT32_MAX)) |
800 | 0 | return -1; |
801 | 0 | return (int)fd; |
802 | | #else |
803 | | return -1; |
804 | | #endif |
805 | 0 | } |
806 | | |
807 | | HANDLE CreateProcessHandle(pid_t pid) |
808 | 0 | { |
809 | 0 | WINPR_PROCESS* process = nullptr; |
810 | 0 | process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS)); |
811 | |
|
812 | 0 | if (!process) |
813 | 0 | return nullptr; |
814 | | |
815 | 0 | process->pid = pid; |
816 | 0 | process->common.Type = HANDLE_TYPE_PROCESS; |
817 | 0 | process->common.ops = &ops; |
818 | 0 | process->common.refCount = 1; |
819 | 0 | process->fd = pidfd_open(pid); |
820 | 0 | if (process->fd >= 0) |
821 | 0 | process->common.Mode = WINPR_FD_READ; |
822 | 0 | return (HANDLE)process; |
823 | 0 | } |
824 | | |
825 | | #endif |