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>
67#include <sys/syscall.h>
74#include "../security/security.h"
99static char* FindApplicationPath(
char* application)
101 LPCSTR pathName =
"PATH";
102 char* path =
nullptr;
103 char* save =
nullptr;
105 LPSTR lpSystemPath =
nullptr;
106 char* filename =
nullptr;
111 if (application[0] ==
'/')
112 return _strdup(application);
114 nSize = GetEnvironmentVariableA(pathName,
nullptr, 0);
117 return _strdup(application);
119 lpSystemPath = (LPSTR)malloc(nSize);
124 if (GetEnvironmentVariableA(pathName, lpSystemPath, nSize) != nSize - 1)
131 path = strtok_s(lpSystemPath,
":", &save);
135 filename = GetCombinedPath(path, application);
137 if (winpr_PathFileExists(filename))
144 path = strtok_s(
nullptr,
":", &save);
151static HANDLE CreateProcessHandle(pid_t pid);
152static BOOL ProcessHandleCloseHandle(HANDLE handle);
154static BOOL CreateProcessExA(HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
155 LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
156 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
157 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
158 WINPR_ATTR_UNUSED BOOL bInheritHandles,
159 WINPR_ATTR_UNUSED 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)
224 sigfillset(&newSigMask);
225 restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
241 sigset_t set = WINPR_C_ARRAY_INIT;
242 struct sigaction act = WINPR_C_ARRAY_INIT;
244 act.sa_handler = SIG_DFL;
246 sigemptyset(&act.sa_mask);
248 for (
int sig = 1; sig < NSIG; sig++)
249 sigaction(sig, &act,
nullptr);
253 pthread_sigmask(SIG_UNBLOCK, &set,
nullptr);
258 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
261 dup2(handle_fd, STDOUT_FILENO);
263 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
266 dup2(handle_fd, STDERR_FILENO);
268 handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
271 dup2(handle_fd, STDIN_FILENO);
278 maxfd = fcntl(0, F_MAXFD);
281 const long rc = sysconf(_SC_OPEN_MAX);
282 if ((rc < INT32_MIN) || (rc > INT32_MAX))
288 for (
int fd = 3; fd < maxfd; fd++)
297 int rc = setgid((gid_t)token->GroupId);
304 initgroups(token->Username, (gid_t)token->GroupId);
310 int rc = setuid((uid_t)token->UserId);
317 if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0)
319 int rc = chdir(lpCurrentDirectory);
324 if (execve(filename, pArgs, envp) < 0)
335 process = CreateProcessHandle(pid);
342 thread = CreateNoneHandle();
346 ProcessHandleCloseHandle(process);
350 lpProcessInformation->hProcess = process;
351 lpProcessInformation->hThread = thread;
352 lpProcessInformation->dwProcessId = (DWORD)pid;
353 lpProcessInformation->dwThreadId = (DWORD)pid;
359 pthread_sigmask(SIG_SETMASK, &oldSigMask,
nullptr);
364 if (lpszEnvironmentBlock)
365 FreeEnvironmentStrings(lpszEnvironmentBlock);
383BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
384 LPSECURITY_ATTRIBUTES lpProcessAttributes,
385 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
386 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
387 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
389 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
390 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
391 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
394BOOL CreateProcessW(WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
395 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
396 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
397 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
398 WINPR_ATTR_UNUSED BOOL bInheritHandles, WINPR_ATTR_UNUSED DWORD dwCreationFlags,
399 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
400 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
402 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
404 WINPR_ASSERT(lpStartupInfo);
405 WINPR_ASSERT(lpProcessInformation);
407 LPSTR lpApplicationNameA =
nullptr;
408 LPSTR lpCommandLineA =
nullptr;
409 LPSTR lpCurrentDirectoryA =
nullptr;
411 .lpReserved =
nullptr,
412 .lpDesktop =
nullptr,
414 .dwX = lpStartupInfo->dwX,
415 .dwY = lpStartupInfo->dwY,
416 .dwXSize = lpStartupInfo->dwXSize,
417 .dwYSize = lpStartupInfo->dwYSize,
418 .dwXCountChars = lpStartupInfo->dwXCountChars,
419 .dwYCountChars = lpStartupInfo->dwYCountChars,
420 .dwFillAttribute = lpStartupInfo->dwFillAttribute,
421 .dwFlags = lpStartupInfo->dwFlags,
422 .wShowWindow = lpStartupInfo->wShowWindow,
423 .cbReserved2 = lpStartupInfo->cbReserved2,
424 .lpReserved2 = lpStartupInfo->lpReserved2,
425 .hStdInput = lpStartupInfo->hStdInput,
426 .hStdOutput = lpStartupInfo->hStdOutput,
427 .hStdError = lpStartupInfo->hStdError };
430 if (lpApplicationName)
432 lpApplicationNameA = ConvertWCharToUtf8Alloc(lpApplicationName,
nullptr);
433 if (!lpApplicationNameA)
438 lpCommandLineA = ConvertWCharToUtf8Alloc(lpCommandLine,
nullptr);
442 if (lpCurrentDirectory)
444 lpCurrentDirectoryA = ConvertWCharToUtf8Alloc(lpCurrentDirectory,
nullptr);
445 if (!lpCurrentDirectoryA)
448 if (lpStartupInfo->lpReserved)
450 StartupInfoA.lpReserved = ConvertWCharToUtf8Alloc(lpStartupInfo->lpReserved,
nullptr);
451 if (!StartupInfoA.lpReserved)
454 if (lpStartupInfo->lpDesktop)
456 StartupInfoA.lpDesktop = ConvertWCharToUtf8Alloc(lpStartupInfo->lpDesktop,
nullptr);
457 if (!StartupInfoA.lpDesktop)
460 if (lpStartupInfo->lpTitle)
462 StartupInfoA.lpTitle = ConvertWCharToUtf8Alloc(lpStartupInfo->lpTitle,
nullptr);
463 if (!StartupInfoA.lpTitle)
467 rc = CreateProcessA(lpApplicationNameA, lpCommandLineA, lpProcessAttributes, lpThreadAttributes,
468 bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectoryA,
469 &StartupInfoA, lpProcessInformation);
471 free(lpApplicationNameA);
472 free(lpCommandLineA);
473 free(lpCurrentDirectoryA);
474 free(StartupInfoA.lpDesktop);
475 free(StartupInfoA.lpReserved);
476 free(StartupInfoA.lpTitle);
480BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine,
481 LPSECURITY_ATTRIBUTES lpProcessAttributes,
482 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
483 DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
484 LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
486 return CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes,
487 lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
488 lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
491BOOL CreateProcessAsUserW(WINPR_ATTR_UNUSED HANDLE hToken,
492 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
493 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
494 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpProcessAttributes,
495 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpThreadAttributes,
496 WINPR_ATTR_UNUSED BOOL bInheritHandles,
497 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
498 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
499 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
501 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
503 WLog_ERR(
"TODO",
"TODO: implement");
507BOOL CreateProcessWithLogonA(
508 WINPR_ATTR_UNUSED LPCSTR lpUsername, WINPR_ATTR_UNUSED LPCSTR lpDomain,
509 WINPR_ATTR_UNUSED LPCSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
510 WINPR_ATTR_UNUSED LPCSTR lpApplicationName, WINPR_ATTR_UNUSED LPSTR lpCommandLine,
511 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
512 WINPR_ATTR_UNUSED LPCSTR lpCurrentDirectory, WINPR_ATTR_UNUSED
LPSTARTUPINFOA lpStartupInfo,
513 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
515 WLog_ERR(
"TODO",
"TODO: implement");
519BOOL CreateProcessWithLogonW(
520 WINPR_ATTR_UNUSED LPCWSTR lpUsername, WINPR_ATTR_UNUSED LPCWSTR lpDomain,
521 WINPR_ATTR_UNUSED LPCWSTR lpPassword, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
522 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName, WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
523 WINPR_ATTR_UNUSED DWORD dwCreationFlags, WINPR_ATTR_UNUSED LPVOID lpEnvironment,
524 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory, WINPR_ATTR_UNUSED
LPSTARTUPINFOW lpStartupInfo,
525 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
527 WLog_ERR(
"TODO",
"TODO: implement");
531BOOL CreateProcessWithTokenA(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
532 LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags,
533 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
535 LPPROCESS_INFORMATION lpProcessInformation)
537 return CreateProcessExA(
nullptr, 0, lpApplicationName, lpCommandLine,
nullptr,
nullptr, FALSE,
538 dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
539 lpProcessInformation);
542BOOL CreateProcessWithTokenW(WINPR_ATTR_UNUSED HANDLE hToken, WINPR_ATTR_UNUSED DWORD dwLogonFlags,
543 WINPR_ATTR_UNUSED LPCWSTR lpApplicationName,
544 WINPR_ATTR_UNUSED LPWSTR lpCommandLine,
545 WINPR_ATTR_UNUSED DWORD dwCreationFlags,
546 WINPR_ATTR_UNUSED LPVOID lpEnvironment,
547 WINPR_ATTR_UNUSED LPCWSTR lpCurrentDirectory,
549 WINPR_ATTR_UNUSED LPPROCESS_INFORMATION lpProcessInformation)
551 WLog_ERR(
"TODO",
"TODO: implement");
555VOID ExitProcess(UINT uExitCode)
558 exit((
int)uExitCode);
561BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode)
572 *lpExitCode = process->dwExitCode;
576HANDLE _GetCurrentProcess(VOID)
578 WLog_ERR(
"TODO",
"TODO: implement");
582DWORD GetCurrentProcessId(VOID)
584 return ((DWORD)getpid());
587BOOL TerminateProcess(HANDLE hProcess, WINPR_ATTR_UNUSED UINT uExitCode)
592 if (!process || (process->pid <= 0))
595 if (kill(process->pid, SIGTERM))
601static BOOL ProcessHandleCloseHandle(HANDLE handle)
604 WINPR_ASSERT(process);
605 if (process->fd >= 0)
614static BOOL ProcessHandleIsHandle(HANDLE handle)
616 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_PROCESS, FALSE);
619static int ProcessGetFd(HANDLE handle)
623 if (!ProcessHandleIsHandle(handle))
629static DWORD ProcessCleanupHandle(HANDLE handle)
633 WINPR_ASSERT(process);
636 if (waitpid(process->pid, &process->status, WNOHANG) == process->pid)
638 if (WIFEXITED(process->status))
639 process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
640 else if (WIFSIGNALED(process->status))
641 process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
643 process->dwExitCode = (DWORD)process->status;
646 return WAIT_OBJECT_0;
649static HANDLE_OPS ops = { ProcessHandleIsHandle,
650 ProcessHandleCloseHandle,
652 ProcessCleanupHandle,
671static int pidfd_open(pid_t pid)
674#if !defined(__NR_pidfd_open)
675#define __NR_pidfd_open 434
678#ifndef PIDFD_NONBLOCK
679#define PIDFD_NONBLOCK O_NONBLOCK
682 long fd = syscall(__NR_pidfd_open, pid, PIDFD_NONBLOCK);
683 if (fd < 0 && errno == EINVAL)
688 fd = syscall(__NR_pidfd_open, pid, 0);
689 if ((fd < 0) || (fd > INT32_MAX))
692 flags = fcntl((
int)fd, F_GETFL);
693 if ((flags < 0) || fcntl((
int)fd, F_SETFL, flags | O_NONBLOCK) < 0)
699 if ((fd < 0) || (fd > INT32_MAX))
707HANDLE CreateProcessHandle(pid_t pid)
716 process->common.Type = HANDLE_TYPE_PROCESS;
717 process->common.ops = &ops;
718 process->fd = pidfd_open(pid);
719 if (process->fd >= 0)
720 process->common.Mode = WINPR_FD_READ;
721 return (HANDLE)process;