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);
404 initgroups(token->Username, (gid_t)token->GroupId);
410 int rc = setuid((uid_t)token->UserId);
417 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
419 int rc = chdir(lpCurrentDirectory);
424 if (execve(filename, pArgs, envp) < 0)
435 process = CreateProcessHandle(pid);
442 thread = CreateNoneHandle();
446 ProcessHandleCloseHandle(process);
451 lpProcessInformation->hProcess = process;
452 lpProcessInformation->hThread = thread;
453 lpProcessInformation->dwProcessId = (DWORD)pid;
454 lpProcessInformation->dwThreadId = (DWORD)pid;
460 pthread_sigmask(SIG_SETMASK, &oldSigMask,
nullptr);
465 if (lpszEnvironmentBlock)
466 FreeEnvironmentStrings(lpszEnvironmentBlock);
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)
490 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
491 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
492 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
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,
503 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
505 WINPR_ASSERT(lpStartupInfo);
506 WINPR_ASSERT(lpProcessInformation);
508 LPSTR lpApplicationNameA =
nullptr;
509 LPSTR lpCommandLineA =
nullptr;
510 LPSTR lpCurrentDirectoryA =
nullptr;
512 .lpReserved =
nullptr,
513 .lpDesktop =
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 };
531 if (lpApplicationName)
533 lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName,
nullptr);
534 if (!lpApplicationNameA)
539 lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine,
nullptr);
543 if (lpCurrentDirectory)
545 lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory,
nullptr);
546 if (!lpCurrentDirectoryA)
549 if (lpStartupInfo->lpReserved)
551 StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved,
nullptr);
552 if (!StartupInfoA.lpReserved)
555 if (lpStartupInfo->lpDesktop)
557 StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop,
nullptr);
558 if (!StartupInfoA.lpDesktop)
561 if (lpStartupInfo->lpTitle)
563 StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle,
nullptr);
564 if (!StartupInfoA.lpTitle)
568 rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
569 bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
570 &StartupInfoA, lpProcessInformation);
572 free(lpApplicationNameA);
573 free(lpCommandLineA);
574 free(lpCurrentDirectoryA);
575 free(StartupInfoA.lpDesktop);
576 free(StartupInfoA.lpReserved);
577 free(StartupInfoA.lpTitle);
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)
587 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
588 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
589 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
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,
602 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
604 WLog_ERR(
"TODO",
"TODO: implement");
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)
616 WLog_ERR(
"TODO",
"TODO: implement");
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)
628 WLog_ERR(
"TODO",
"TODO: implement");
632BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
633 LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
634 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
636 LPPROCESS_INFORMATION lpProcessInformation)
638 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine,
nullptr,
nullptr, FALSE,
639 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
640 lpProcessInformation);
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,
650 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
652 WLog_ERR(
"TODO",
"TODO: implement");
656VOID ExitProcess(UINT uExitCode)
659 exit((
int)uExitCode);
662BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
673 *lpExitCode = process->dwExitCode;
677HANDLE _GetCurrentProcess(VOID)
679 WLog_ERR(
"TODO",
"TODO: implement");
683DWORD GetCurrentProcessId(VOID)
685 return ((DWORD)getpid());
688BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
693 if (!process || (process->pid <= 0))
696 if (kill(process->pid, SIGTERM))
702static BOOL ProcessHandleCloseHandle(HANDLE handle)
705 WINPR_ASSERT(process);
706 if (process->fd >= 0)
714static BOOL ProcessHandleIsHandle(HANDLE handle)
716 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
719static int ProcessGetFd(HANDLE handle)
723 if (!ProcessHandleIsHandle(handle))
729static DWORD ProcessCleanupHandle(HANDLE handle)
733 WINPR_ASSERT(process);
736 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
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));
743 process->dwExitCode = (DWORD)process->status;
746 return WAIT_OBJECT_0;
749static HANDLE_OPS ops = { ProcessHandleIsHandle,
750 ProcessHandleCloseHandle,
752 ProcessCleanupHandle,
771static int pidfd_open(pid_t pid)
774#if !defined(__NR_pidfd_open)
775#define __NR_pidfd_open 434
778#ifndef PIDFD_NONBLOCK
779#define PIDFD_NONBLOCK O_NONBLOCK
782 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
783 if (fd < 0 && errno == EINVAL)
788 fd = syscall(__NR_pidfd_open, pid, 0);
789 if ((fd < 0) || (fd > INT32_MAX))
792 flags = fcntl((
int)fd, F_GETFL);
793 if ((flags < 0) || fcntl((
int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
799 if ((fd < 0) || (fd > INT32_MAX))
807HANDLE CreateProcessHandle(pid_t 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;
opaque attribute list built by InitializeProcThreadAttributeList() / UpdateProcThreadAttribute(),...