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 else
403 {
404 initgroups(token->Username, (gid_t)token->GroupId);
405 }
406 }
407
408 if (token->UserId)
409 {
410 int rc = setuid((uid_t)token->UserId);
411 if (rc != 0)
412 goto finish;
413 }
414 }
415
416 /* TODO: add better cwd handling and error checking */
417 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
418 {
419 int rc = chdir(lpCurrentDirectory);
420 if (rc != 0)
421 goto finish;
422 }
423
424 if (execve(filename, pArgs, envp) < 0)
425 {
426 /* execve failed - end the process */
427 _exit(1);
428 }
429 }
430 else
431 {
432 /* parent process */
433 }
434
435 process = CreateProcessHandle(pid);
436
437 if (!process)
438 {
439 goto finish;
440 }
441
442 thread = CreateNoneHandle();
443
444 if (!thread)
445 {
446 ProcessHandleCloseHandle(process);
447 free(process);
448 goto finish;
449 }
450
451 lpProcessInformation->hProcess = process;
452 lpProcessInformation->hThread = thread;
453 lpProcessInformation->dwProcessId = (DWORD)pid;
454 lpProcessInformation->dwThreadId = (DWORD)pid;
455 ret = TRUE;
456finish:
457
458 /* restore caller's original signal mask */
459 if (restoreSigMask)
460 pthread_sigmask(SIG_SETMASK, &oldSigMask, nullptr);
461
462 free(filename);
463 free((void*)pArgs);
464
465 if (lpszEnvironmentBlock)
466 FreeEnvironmentStrings(lpszEnvironmentBlock);
467
468 if (envp)
469 {
470 int i = 0;
471
472 while (envp[i])
473 {
474 free(envp[i]);
475 i++;
476 }
477
478 free((void*)envp);
479 }
480
481 return ret;
482}
483
484BOOL 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{
490 return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
491 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
492 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
493}
494
495BOOL 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{
505 WINPR_ASSERT(lpStartupInfo);
506 WINPR_ASSERT(lpProcessInformation);
507
508 LPSTR lpApplicationNameA = nullptr;
509 LPSTR lpCommandLineA = nullptr;
510 LPSTR lpCurrentDirectoryA = nullptr;
511 STARTUPINFOA StartupInfoA = { .cb = sizeof(STARTUPINFOA),
512 .lpReserved = nullptr,
513 .lpDesktop = nullptr,
514 .lpTitle = nullptr,
515 .dwX = lpStartupInfo->dwX,
516 .dwY = lpStartupInfo->dwY,
517 .dwXSize = lpStartupInfo->dwXSize,
518 .dwYSize = lpStartupInfo->dwYSize,
519 .dwXCountChars = lpStartupInfo->dwXCountChars,
520 .dwYCountChars = lpStartupInfo->dwYCountChars,
521 .dwFillAttribute = lpStartupInfo->dwFillAttribute,
522 .dwFlags = lpStartupInfo->dwFlags,
523 .wShowWindow = lpStartupInfo->wShowWindow,
524 .cbReserved2 = lpStartupInfo->cbReserved2,
525 .lpReserved2 = lpStartupInfo->lpReserved2,
526 .hStdInput = lpStartupInfo->hStdInput,
527 .hStdOutput = lpStartupInfo->hStdOutput,
528 .hStdError = lpStartupInfo->hStdError };
529
530 BOOL rc = FALSE;
531 if (lpApplicationName)
532 {
533 lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName, nullptr);
534 if (!lpApplicationNameA)
535 goto fail;
536 }
537 if (lpCommandLine)
538 {
539 lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine, nullptr);
540 if (!lpCommandLineA)
541 goto fail;
542 }
543 if (lpCurrentDirectory)
544 {
545 lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory, nullptr);
546 if (!lpCurrentDirectoryA)
547 goto fail;
548 }
549 if (lpStartupInfo->lpReserved)
550 {
551 StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved, nullptr);
552 if (!StartupInfoA.lpReserved)
553 goto fail;
554 }
555 if (lpStartupInfo->lpDesktop)
556 {
557 StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop, nullptr);
558 if (!StartupInfoA.lpDesktop)
559 goto fail;
560 }
561 if (lpStartupInfo->lpTitle)
562 {
563 StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle, nullptr);
564 if (!StartupInfoA.lpTitle)
565 goto fail;
566 }
567
568 rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
569 bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
570 &StartupInfoA, lpProcessInformation);
571fail:
572 free(lpApplicationNameA);
573 free(lpCommandLineA);
574 free(lpCurrentDirectoryA);
575 free(StartupInfoA.lpDesktop);
576 free(StartupInfoA.lpReserved);
577 free(StartupInfoA.lpTitle);
578 return rc;
579}
580
581BOOL 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{
587 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
588 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
589 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
590}
591
592BOOL 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{
604 WLog_ERR("TODO", "TODO: implement");
605 return FALSE;
606}
607
608BOOL 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{
616 WLog_ERR("TODO", "TODO: implement");
617 return FALSE;
618}
619
620BOOL 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{
628 WLog_ERR("TODO", "TODO: implement");
629 return FALSE;
630}
631
632BOOL 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{
638 return CreateProcessExA(nullptr, 0, lpApplicationName, lpCommandLine, nullptr, nullptr, FALSE,
639 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
640 lpProcessInformation);
641}
642
643BOOL 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{
652 WLog_ERR("TODO", "TODO: implement");
653 return FALSE;
654}
655
656VOID ExitProcess(UINT uExitCode)
657{
658 // NOLINTNEXTLINE(concurrency-mt-unsafe)
659 exit((int)uExitCode);
660}
661
662BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
663{
664 WINPR_PROCESS* process = nullptr;
665
666 if (!hProcess)
667 return FALSE;
668
669 if (!lpExitCode)
670 return FALSE;
671
672 process = (WINPR_PROCESS*)hProcess;
673 *lpExitCode = process->dwExitCode;
674 return TRUE;
675}
676
677HANDLE _GetCurrentProcess(VOID)
678{
679 WLog_ERR("TODO", "TODO: implement");
680 return nullptr;
681}
682
683DWORD GetCurrentProcessId(VOID)
684{
685 return ((DWORD)getpid());
686}
687
688BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
689{
690 WINPR_PROCESS* process = nullptr;
691 process = (WINPR_PROCESS*)hProcess;
692
693 if (!process || (process->pid <= 0))
694 return FALSE;
695
696 if (kill(process->pid, SIGTERM))
697 return FALSE;
698
699 return TRUE;
700}
701
702static BOOL ProcessHandleCloseHandle(HANDLE handle)
703{
704 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
705 WINPR_ASSERT(process);
706 if (process->fd >= 0)
707 {
708 close(process->fd);
709 process->fd = -1;
710 }
711 return TRUE;
712}
713
714static BOOL ProcessHandleIsHandle(HANDLE handle)
715{
716 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
717}
718
719static int ProcessGetFd(HANDLE handle)
720{
721 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
722
723 if (!ProcessHandleIsHandle(handle))
724 return -1;
725
726 return process->fd;
727}
728
729static DWORD ProcessCleanupHandle(HANDLE handle)
730{
731 WINPR_PROCESS* process = (WINPR_PROCESS*)handle;
732
733 WINPR_ASSERT(process);
734 if (process->fd > 0)
735 {
736 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
737 {
738 if (WIFEXITED(process->status))
739 process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
740 else if (WIFSIGNALED(process->status))
741 process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
742 else
743 process->dwExitCode = (DWORD)process->status;
744 }
745 }
746 return WAIT_OBJECT_0;
747}
748
749static 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
771static int pidfd_open(pid_t pid)
772{
773#ifdef __linux__
774#if !defined(__NR_pidfd_open)
775#define __NR_pidfd_open 434
776#endif /* __NR_pidfd_open */
777
778#ifndef PIDFD_NONBLOCK
779#define PIDFD_NONBLOCK O_NONBLOCK
780#endif /* PIDFD_NONBLOCK */
781
782 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
783 if (fd < 0 && errno == EINVAL)
784 {
785 /* possibly PIDFD_NONBLOCK is not supported, let's try to create a pidfd and set it
786 * non blocking afterward */
787 int flags = 0;
788 fd = syscall(__NR_pidfd_open, pid, 0);
789 if ((fd < 0) || (fd > INT32_MAX))
790 return -1;
791
792 flags = fcntl((int)fd, F_GETFL);
793 if ((flags < 0) || fcntl((int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
794 {
795 close((int)fd);
796 fd = -1;
797 }
798 }
799 if ((fd < 0) || (fd > INT32_MAX))
800 return -1;
801 return (int)fd;
802#else
803 return -1;
804#endif
805}
806
807HANDLE CreateProcessHandle(pid_t pid)
808{
809 WINPR_PROCESS* process = nullptr;
810 process = (WINPR_PROCESS*)calloc(1, sizeof(WINPR_PROCESS));
811
812 if (!process)
813 return nullptr;
814
815 process->pid = pid;
816 process->common.Type = HANDLE_TYPE_PROCESS;
817 process->common.ops = &ops;
818 process->common.refCount = 1;
819 process->fd = pidfd_open(pid);
820 if (process->fd >= 0)
821 process->common.Mode = WINPR_FD_READ;
822 return (HANDLE)process;
823}
824
825#endif
opaque attribute list built by InitializeProcThreadAttributeList() / UpdateProcThreadAttribute(),...