FreeRDP
Loading...
Searching...
No Matches
process.c
1
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
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
100static char* FindApplicationPath(char* application)
101{
102 LPCSTR pathName = "PATH";
103 char* path = nullptr;
104 char* save = nullptr;
105 DWORD nSize = 0;
106 LPSTR lpSystemPath = nullptr;
107 char* filename = nullptr;
108
109 if (!application)
110 return nullptr;
111
112 if (application[0] == '/')
113 return _strdup(application);
114
115 nSize = GetEnvironmentVariableA(pathName, nullptr, 0);
116
117 if (!nSize)
118 return _strdup(application);
119
120 lpSystemPath = (LPSTR)malloc(nSize);
121
122 if (!lpSystemPath)
123 return nullptr;
124
125 if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
126 {
127 free(lpSystemPath);
128 return nullptr;
129 }
130
131 save = nullptr;
132 path = strtok_s(lpSystemPath, ":", &save);
133
134 while (path)
135 {
136 filename = GetCombinedPath(path, application);
137
138 if (winpr_PathFileExists(filename))
139 {
140 break;
141 }
142
143 free(filename);
144 filename = nullptr;
145 path = strtok_s(nullptr, ":", &save);
146 }
147
148 free(lpSystemPath);
149 return filename;
150}
151
152static HANDLE CreateProcessHandle(pid_t pid);
153static BOOL ProcessHandleCloseHandle(HANDLE handle);
154
155static 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{
163 pid_t pid = 0;
164 int numArgs = 0;
165 LPSTR* pArgs = nullptr;
166 char** envp = nullptr;
167 char* filename = nullptr;
168 HANDLE thread = nullptr;
169 HANDLE process = nullptr;
170 WINPR_ACCESS_TOKEN* token = nullptr;
171 LPTCH lpszEnvironmentBlock = nullptr;
172 BOOL ret = FALSE;
173 sigset_t oldSigMask;
174 sigset_t newSigMask;
175 BOOL restoreSigMask = FALSE;
176 numArgs = 0;
177 lpszEnvironmentBlock = nullptr;
178 /* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
179 */
180
181 if (lpCommandLine && lpApplicationName)
182 {
183 char* str = nullptr;
184 size_t len = 0;
185 winpr_asprintf(&str, &len, "%s %s", lpApplicationName, lpCommandLine);
186 if (!str)
187 return FALSE;
188 pArgs = CommandLineToArgvA(str, &numArgs);
189 free(str);
190 }
191 else if (lpCommandLine)
192 pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
193 else
194 pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);
195
196 if (!pArgs)
197 return FALSE;
198
199 token = (WINPR_ACCESS_TOKEN*)hToken;
200
201 if (lpEnvironment)
202 {
203 envp = EnvironmentBlockToEnvpA(lpEnvironment);
204 }
205 else
206 {
207 lpszEnvironmentBlock = GetEnvironmentStrings();
208
209 if (!lpszEnvironmentBlock)
210 goto finish;
211
212 envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
213 }
214
215 if (!envp)
216 goto finish;
217
218 filename = FindApplicationPath(pArgs[0]);
219
220 if (nullptr == filename)
221 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 if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
228 {
229 const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo;
230 const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList;
231
232 for (DWORD i = 0; list && (i < list->count); i++)
233 {
234 const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i];
235 if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
236 continue;
237
238 const HANDLE* handles = (const HANDLE*)entry->lpValue;
239 const size_t count = entry->cbSize / sizeof(HANDLE);
240 for (size_t h = 0; h < count; h++)
241 {
242 if (winpr_Handle_getFd(handles[h]) < 0)
243 {
244 SetLastError(ERROR_INVALID_PARAMETER);
245 goto finish;
246 }
247 }
248 }
249 }
250
251 /* block all signals so that the child can safely reset the caller's handlers */
252 sigfillset(&newSigMask);
253 restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
254 /* fork and exec */
255 pid = fork();
256
257 if (pid < 0)
258 {
259 /* fork failure */
260 goto finish;
261 }
262
263 if (pid == 0)
264 {
265 /* child process */
266#ifndef __sun
267 int maxfd = 0;
268#endif
269 sigset_t set = WINPR_C_ARRAY_INIT;
270 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#define WINPR_MAX_INHERITED_HANDLES 64
284 int keepFds[WINPR_MAX_INHERITED_HANDLES] = { -1 };
285 size_t nKeepFds = 0;
286 BOOL haveHandleList = FALSE;
287
288 if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
289 {
290 const STARTUPINFOEXA* exInfo = (const STARTUPINFOEXA*)lpStartupInfo;
291 const struct WINPR_PROC_THREAD_ATTRIBUTE_LIST* list = exInfo->lpAttributeList;
292
293 for (DWORD i = 0; list && (i < list->count); i++)
294 {
295 const WINPR_PROC_THREAD_ATTRIBUTE_ENTRY* entry = &list->entries[i];
296 if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
297 continue;
298
299 haveHandleList = TRUE;
300 const HANDLE* handles = (const HANDLE*)entry->lpValue;
301 const size_t count = entry->cbSize / sizeof(HANDLE);
302 for (size_t h = 0; (h < count) && (nKeepFds < WINPR_MAX_INHERITED_HANDLES); h++)
303 {
304 const int fd = winpr_Handle_getFd(handles[h]);
305 if (fd >= 0)
306 keepFds[nKeepFds++] = fd;
307 }
308 }
309 }
310
311 /* set default signal handlers */
312 act.sa_handler = SIG_DFL;
313 act.sa_flags = 0;
314 sigemptyset(&act.sa_mask);
315
316 for (int sig = 1; sig < NSIG; sig++)
317 sigaction(sig, &act, nullptr);
318
319 /* unblock all signals */
320 sigfillset(&set);
321 pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
322
323 if (lpStartupInfo)
324 {
325 int handle_fd = 0;
326 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
327
328 if (handle_fd != -1)
329 dup2(handle_fd, STDOUT_FILENO);
330
331 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
332
333 if (handle_fd != -1)
334 dup2(handle_fd, STDERR_FILENO);
335
336 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
337
338 if (handle_fd != -1)
339 dup2(handle_fd, STDIN_FILENO);
340 }
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 {
353 const long rc = sysconf(_SC_OPEN_MAX);
354 if ((rc < INT32_MIN) || (rc > INT32_MAX))
355 goto finish;
356 maxfd = (int)rc;
357 }
358#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 for (int fd = 3; fd < maxfd; fd++)
364 {
365 BOOL keep = FALSE;
366
367 if (bInheritHandles)
368 {
369 if (haveHandleList)
370 {
371 for (size_t k = 0; k < nKeepFds; k++)
372 {
373 if (keepFds[k] == fd)
374 {
375 keep = TRUE;
376 break;
377 }
378 }
379 }
380 else
381 {
382 const int flags = fcntl(fd, F_GETFD);
383 keep = (flags >= 0) && !(flags & FD_CLOEXEC);
384 }
385 }
386
387 if (!keep)
388 close(fd);
389 }
390
391#endif // __sun
392
393 if (token)
394 {
395 if (token->GroupId)
396 {
397 int rc = setgid((gid_t)token->GroupId);
398
399 if (rc < 0)
400 {
401 }
402#if !defined(__EMSCRIPTEN__)
403 else
404 {
405 initgroups(token->Username, (gid_t)token->GroupId);
406 }
407#endif
408 }
409
410 if (token->UserId)
411 {
412 int rc = setuid((uid_t)token->UserId);
413 if (rc != 0)
414 goto finish;
415 }
416 }
417
418 /* TODO: add better cwd handling and error checking */
419 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
420 {
421 int rc = chdir(lpCurrentDirectory);
422 if (rc != 0)
423 goto finish;
424 }
425
426 if (execve(filename, pArgs, envp) < 0)
427 {
428 /* execve failed - end the process */
429 _exit(1);
430 }
431 }
432 else
433 {
434 /* parent process */
435 }
436
437 process = CreateProcessHandle(pid);
438
439 if (!process)
440 {
441 goto finish;
442 }
443
444 thread = CreateNoneHandle();
445
446 if (!thread)
447 {
448 ProcessHandleCloseHandle(process);
449 free(process);
450 goto finish;
451 }
452
453 lpProcessInformation->hProcess = process;
454 lpProcessInformation->hThread = thread;
455 lpProcessInformation->dwProcessId = (DWORD)pid;
456 lpProcessInformation->dwThreadId = (DWORD)pid;
457 ret = TRUE;
458finish:
459
460 /* restore caller's original signal mask */
461 if (restoreSigMask)
462 pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr);
463
464 free(filename);
465 free((void*)pArgs);
466
467 if (lpszEnvironmentBlock)
468 FreeEnvironmentStrings(lpszEnvironmentBlock);
469
470 if (envp)
471 {
472 int i = 0;
473
474 while (envp[i])
475 {
476 free(envp[i]);
477 i++;
478 }
479
480 free((void*)envp);
481 }
482
483 return ret;
484}
485
486BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
487 LPSECURITY_ATTRIBUTES lpProcessAttributes,
488 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
489 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
490 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
491{
492 return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
493 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
494 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
495}
496
497BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
498 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
499 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
500 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
501 WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
502 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
503 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
504 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
505 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
506{
507 WINPR_ASSERT(lpStartupInfo);
508 WINPR_ASSERT(lpProcessInformation);
509
510 LPSTR lpApplicationNameA = nullptr;
511 LPSTR lpCommandLineA = nullptr;
512 LPSTR lpCurrentDirectoryA = nullptr;
513 STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA),
514 .lpReserved = nullptr,
515 .lpDesktop = nullptr,
516 .lpTitle = nullptr,
517 .dwX = lpStartupInfo->dwX,
518 .dwY = lpStartupInfo->dwY,
519 .dwXSize = lpStartupInfo->dwXSize,
520 .dwYSize = lpStartupInfo->dwYSize,
521 .dwXCountChars = lpStartupInfo->dwXCountChars,
522 .dwYCountChars = lpStartupInfo->dwYCountChars,
523 .dwFillAttribute = lpStartupInfo->dwFillAttribute,
524 .dwFlags = lpStartupInfo->dwFlags,
525 .wShowWindow = lpStartupInfo->wShowWindow,
526 .cbReserved2 = lpStartupInfo->cbReserved2,
527 .lpReserved2 = lpStartupInfo->lpReserved2,
528 .hStdInput = lpStartupInfo->hStdInput,
529 .hStdOutput = lpStartupInfo->hStdOutput,
530 .hStdError = lpStartupInfo->hStdError };
531
532 BOOL rc = FALSE;
533 if (lpApplicationName)
534 {
535 lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr);
536 if (!lpApplicationNameA)
537 goto fail;
538 }
539 if (lpCommandLine)
540 {
541 lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr);
542 if (!lpCommandLineA)
543 goto fail;
544 }
545 if (lpCurrentDirectory)
546 {
547 lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr);
548 if (!lpCurrentDirectoryA)
549 goto fail;
550 }
551 if (lpStartupInfo->lpReserved)
552 {
553 StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr);
554 if (!StartupInfoA.lpReserved)
555 goto fail;
556 }
557 if (lpStartupInfo->lpDesktop)
558 {
559 StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr);
560 if (!StartupInfoA.lpDesktop)
561 goto fail;
562 }
563 if (lpStartupInfo->lpTitle)
564 {
565 StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr);
566 if (!StartupInfoA.lpTitle)
567 goto fail;
568 }
569
570 rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
571 bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
572 &StartupInfoA, lpProcessInformation);
573fail:
574 free(lpApplicationNameA);
575 free(lpCommandLineA);
576 free(lpCurrentDirectoryA);
577 free(StartupInfoA.lpDesktop);
578 free(StartupInfoA.lpReserved);
579 free(StartupInfoA.lpTitle);
580 return rc;
581}
582
583BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
584 LPSECURITY_ATTRIBUTES lpProcessAttributes,
585 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
586 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
587 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
588{
589 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
590 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
591 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
592}
593
594BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
595 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
596 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
597 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
598 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
599 WINPR_ATTR_UNUSED BOOL bInheritHandles,
600 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
601 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
602 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
603 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
604 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
605{
606 WLog_ERR("TODO", "TODO: implement");
607 return FALSE;
608}
609
610BOOL CreateProcessWithLogonA(
611 WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
612 WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
613 WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
614 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
615 WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOA lpStartupInfo,
616 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
617{
618 WLog_ERR("TODO", "TODO: implement");
619 return FALSE;
620}
621
622BOOL CreateProcessWithLogonW(
623 WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
624 WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
625 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
626 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
627 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
628 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
629{
630 WLog_ERR("TODO", "TODO: implement");
631 return FALSE;
632}
633
634BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
635 LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
636 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
637 LPSTARTUPINFOA lpStartupInfo,
638 LPPROCESS_INFORMATION lpProcessInformation)
639{
640 return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE,
641 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
642 lpProcessInformation);
643}
644
645BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
646 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
647 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
648 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
649 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
650 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
651 WINPR_ATTR_UNUSED LPSTARTUPINFOW lpStartupInfo,
652 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
653{
654 WLog_ERR("TODO", "TODO: implement");
655 return FALSE;
656}
657
658VOID ExitProcess(UINT uExitCode)
659{
660 // NOLINTNEXTLINE(concurrency-mt-unsafe)
661 exit((int)uExitCode);
662}
663
664BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
665{
666 WINPR_PROCESS* process = nullptr;
667
668 if (!hProcess)
669 return FALSE;
670
671 if (!lpExitCode)
672 return FALSE;
673
674 process = (WINPR_PROCESS*)hProcess;
675 *lpExitCode = process->dwExitCode;
676 return TRUE;
677}
678
679HANDLE _GetCurrentProcess(VOID)
680{
681 WLog_ERR("TODO", "TODO: implement");
682 return nullptr;
683}
684
685DWORD GetCurrentProcessId(VOID)
686{
687 return ((DWORD)getpid());
688}
689
690BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
691{
692 WINPR_PROCESS* process = nullptr;
693 process = (WINPR_PROCESS*)hProcess;
694
695 if (!process || (process->pid <= 0))
696 return FALSE;
697
698 if (kill(process->pid, SIGTERM))
699 return FALSE;
700
701 return TRUE;
702}
703
704static BOOL ProcessHandleCloseHandle(HANDLE handle)
705{
706 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
707 WINPR_ASSERT(process);
708 if (process->fd >= 0)
709 {
710 close(process->fd);
711 process->fd = -1;
712 }
713 return TRUE;
714}
715
716static BOOL ProcessHandleIsHandle(HANDLE handle)
717{
718 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
719}
720
721static int ProcessGetFd(HANDLE handle)
722{
723 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
724
725 if (!ProcessHandleIsHandle(handle))
726 return -1;
727
728 return process->fd;
729}
730
731static DWORD ProcessCleanupHandle(HANDLE handle)
732{
733 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
734
735 WINPR_ASSERT(process);
736 if (process->fd > 0)
737 {
738 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
739 {
740 if (WIFEXITED(process->status))
741 process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
742 else if (WIFSIGNALED(process->status))
743 process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
744 else
745 process->dwExitCode = (DWORD)process->status;
746 }
747 }
748 return WAIT_OBJECT_0;
749}
750
751static HANDLE_OPS ops = { ProcessHandleIsHandle,
752 ProcessHandleCloseHandle,
753 ProcessGetFd,
754 ProcessCleanupHandle, /* CleanupHandle */
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 nullptr,
771 nullptr };
772
773static int pidfd_open(pid_t pid)
774{
775#ifdef __linux__
776#if !defined(__NR_pidfd_open)
777#define __NR_pidfd_open 434
778#endif /* __NR_pidfd_open */
779
780#ifndef PIDFD_NONBLOCK
781#define PIDFD_NONBLOCK O_NONBLOCK
782#endif /* PIDFD_NONBLOCK */
783
784 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
785 if (fd < 0 && errno == EINVAL)
786 {
787 /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
788 * non blocking afterward */
789 int flags = 0;
790 fd = syscall(__NR_pidfd_open, pid, 0);
791 if ((fd < 0) || (fd > INT32_MAX))
792 return -1;
793
794 flags = fcntl((int)fd, F_GETFL);
795 if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
796 {
797 close((int)fd);
798 fd = -1;
799 }
800 }
801 if ((fd < 0) || (fd > INT32_MAX))
802 return -1;
803 return (int)fd;
804#else
805 return -1;
806#endif
807}
808
809HANDLE CreateProcessHandle(pid_t pid)
810{
811 WINPR_PROCESS* process = nullptr;
812 process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
813
814 if (!process)
815 return nullptr;
816
817 process->pid = pid;
818 process->common.Type = HANDLE_TYPE_PROCESS;
819 process->common.ops = &ops;
820 process->common.refCount = 1;
821 process->fd = pidfd_open(pid);
822 if (process->fd >= 0)
823 process->common.Mode = WINPR_FD_READ;
824 return (HANDLE)process;
825}
826
827#endif
opaque attribute list built by InitializeProcThreadAttributeList() / UpdateProcThreadAttribute(),...