21#include <winpr/config.h>
23#include <winpr/handle.h>
24#include "../handle/nonehandle.h"
26#include <winpr/thread.h>
27#include <winpr/wlog.h>
55#include <winpr/assert.h>
57#include <winpr/path.h>
58#include <winpr/environment.h>
68#include <sys/syscall.h>
74#include "../handle/handle.h"
75#include "../security/security.h"
100static char* FindApplicationPath(
char* application)
102 LPCSTR pathName =
"PATH";
103 char* path =
nullptr;
104 char* save =
nullptr;
106 LPSTR lpSystemPath =
nullptr;
107 char* filename =
nullptr;
112 if (application[0] ==
'/')
113 return _strdup(application);
115 nSize = GetEnvironmentVariableA(pathName,
nullptr, 0);
118 return _strdup(application);
120 lpSystemPath = (LPSTR)malloc(nSize);
125 if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
132 path = strtok_s(lpSystemPath,
":", &save);
136 filename = GetCombinedPath(path, application);
138 if (winpr_PathFileExists(filename))
145 path = strtok_s(
nullptr,
":", &save);
152static HANDLE CreateProcessHandle(pid_t pid);
153static BOOL ProcessHandleCloseHandle(HANDLE handle);
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,
161 LPPROCESS_INFORMATION lpProcessInformation)
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;
175 BOOL restoreSigMask = FALSE;
177 lpszEnvironmentBlock =
nullptr;
181 if (lpCommandLine && lpApplicationName)
185 winpr_asprintf(&str, &len,
"%s %s", lpApplicationName, lpCommandLine);
188 pArgs = CommandLineToArgvA(str, &numArgs);
191 else if (lpCommandLine)
192 pArgs = CommandLineToArgvA(lpCommandLine, &numArgs);
194 pArgs = CommandLineToArgvA(lpApplicationName, &numArgs);
199 token = (WINPR_ACCESS_TOKEN*)hToken;
203 envp = EnvironmentBlockToEnvpA(lpEnvironment);
207 lpszEnvironmentBlock = GetEnvironmentStrings();
209 if (!lpszEnvironmentBlock)
212 envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock);
218 filename = FindApplicationPath(pArgs[0]);
220 if (
nullptr == filename)
227 if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
232 for (DWORD i = 0; list && (i < list->count); i++)
235 if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
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++)
242 if (winpr_Handle_getFd(handles[h]) < 0)
244 SetLastError(ERROR_INVALID_PARAMETER);
252 sigfillset(&newSigMask);
253 restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
269 sigset_t set = WINPR_C_ARRAY_INIT;
270 struct sigaction act = WINPR_C_ARRAY_INIT;
283#define WINPR_MAX_INHERITED_HANDLES 64
284 int keepFds[WINPR_MAX_INHERITED_HANDLES] = { -1 };
286 BOOL haveHandleList = FALSE;
288 if (bInheritHandles && lpStartupInfo && (dwCreationFlags & EXTENDED_STARTUPINFO_PRESENT))
293 for (DWORD i = 0; list && (i < list->count); i++)
296 if (entry->Attribute != PROC_THREAD_ATTRIBUTE_HANDLE_LIST)
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++)
304 const int fd = winpr_Handle_getFd(handles[h]);
306 keepFds[nKeepFds++] = fd;
312 act.sa_handler = SIG_DFL;
314 sigemptyset(&act.sa_mask);
316 for (
int sig = 1; sig < NSIG; sig++)
317 sigaction(sig, &act,
nullptr);
321 pthread_sigmask(SIG_UNBLOCK, &set,
nullptr);
326 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
329 dup2(handle_fd, STDOUT_FILENO);
331 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
334 dup2(handle_fd, STDERR_FILENO);
336 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
339 dup2(handle_fd, STDIN_FILENO);
343 if (!bInheritHandles || !haveHandleList)
350 maxfd = fcntl(0, F_MAXFD);
353 const long rc = sysconf(_SC_OPEN_MAX);
354 if ((rc < INT32_MIN) || (rc > INT32_MAX))
363 for (
int fd = 3; fd < maxfd; fd++)
371 for (
size_t k = 0; k < nKeepFds; k++)
373 if (keepFds[k] == fd)
382 const int flags = fcntl(fd, F_GETFD);
383 keep = (flags >= 0) && !(flags & FD_CLOEXEC);
397 int rc = setgid((gid_t)token->GroupId);
402#if !defined(__EMSCRIPTEN__)
405 initgroups(token->Username, (gid_t)token->GroupId);
412 int rc = setuid((uid_t)token->UserId);
419 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
421 int rc = chdir(lpCurrentDirectory);
426 if (execve(filename, pArgs, envp) < 0)
437 process = CreateProcessHandle(pid);
444 thread = CreateNoneHandle();
448 ProcessHandleCloseHandle(process);
453 lpProcessInformation->hProcess = process;
454 lpProcessInformation->hThread = thread;
455 lpProcessInformation->dwProcessId = (DWORD)pid;
456 lpProcessInformation->dwThreadId = (DWORD)pid;
462 pthread_sigmask(SIG_SETMASK, &oldSigMask,
nullptr);
467 if (lpszEnvironmentBlock)
468 FreeEnvironmentStrings(lpszEnvironmentBlock);
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)
492 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
493 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
494 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
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,
505 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
507 WINPR_ASSERT(lpStartupInfo);
508 WINPR_ASSERT(lpProcessInformation);
510 LPSTR lpApplicationNameA =
nullptr;
511 LPSTR lpCommandLineA =
nullptr;
512 LPSTR lpCurrentDirectoryA =
nullptr;
514 .lpReserved =
nullptr,
515 .lpDesktop =
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 };
533 if (lpApplicationName)
535 lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName,
nullptr);
536 if (!lpApplicationNameA)
541 lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine,
nullptr);
545 if (lpCurrentDirectory)
547 lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory,
nullptr);
548 if (!lpCurrentDirectoryA)
551 if (lpStartupInfo->lpReserved)
553 StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved,
nullptr);
554 if (!StartupInfoA.lpReserved)
557 if (lpStartupInfo->lpDesktop)
559 StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop,
nullptr);
560 if (!StartupInfoA.lpDesktop)
563 if (lpStartupInfo->lpTitle)
565 StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle,
nullptr);
566 if (!StartupInfoA.lpTitle)
570 rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
571 bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
572 &StartupInfoA, lpProcessInformation);
574 free(lpApplicationNameA);
575 free(lpCommandLineA);
576 free(lpCurrentDirectoryA);
577 free(StartupInfoA.lpDesktop);
578 free(StartupInfoA.lpReserved);
579 free(StartupInfoA.lpTitle);
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)
589 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
590 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
591 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
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,
604 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
606 WLog_ERR(
"TODO",
"TODO: implement");
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)
618 WLog_ERR(
"TODO",
"TODO: implement");
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)
630 WLog_ERR(
"TODO",
"TODO: implement");
634BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
635 LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
636 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
638 LPPROCESS_INFORMATION lpProcessInformation)
640 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine,
nullptr,
nullptr, FALSE,
641 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
642 lpProcessInformation);
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,
652 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
654 WLog_ERR(
"TODO",
"TODO: implement");
658VOID ExitProcess(UINT uExitCode)
661 exit((
int)uExitCode);
664BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
675 *lpExitCode = process->dwExitCode;
679HANDLE _GetCurrentProcess(VOID)
681 WLog_ERR(
"TODO",
"TODO: implement");
685DWORD GetCurrentProcessId(VOID)
687 return ((DWORD)getpid());
690BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
695 if (!process || (process->pid <= 0))
698 if (kill(process->pid, SIGTERM))
704static BOOL ProcessHandleCloseHandle(HANDLE handle)
707 WINPR_ASSERT(process);
708 if (process->fd >= 0)
716static BOOL ProcessHandleIsHandle(HANDLE handle)
718 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
721static int ProcessGetFd(HANDLE handle)
725 if (!ProcessHandleIsHandle(handle))
731static DWORD ProcessCleanupHandle(HANDLE handle)
735 WINPR_ASSERT(process);
738 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
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));
745 process->dwExitCode = (DWORD)process->status;
748 return WAIT_OBJECT_0;
751static HANDLE_OPS ops = { ProcessHandleIsHandle,
752 ProcessHandleCloseHandle,
754 ProcessCleanupHandle,
773static int pidfd_open(pid_t pid)
776#if !defined(__NR_pidfd_open)
777#define __NR_pidfd_open 434
780#ifndef PIDFD_NONBLOCK
781#define PIDFD_NONBLOCK O_NONBLOCK
784 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
785 if (fd < 0 && errno == EINVAL)
790 fd = syscall(__NR_pidfd_open, pid, 0);
791 if ((fd < 0) || (fd > INT32_MAX))
794 flags = fcntl((
int)fd, F_GETFL);
795 if ((flags < 0) || fcntl((
int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
801 if ((fd < 0) || (fd > INT32_MAX))
809HANDLE CreateProcessHandle(pid_t 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;
opaque attribute list built by InitializeProcThreadAttributeList() / UpdateProcThreadAttribute(),...