/** * WinPR: Windows Portable Runtime * Process Thread Functions * * Copyright 2012 Marc-Andre Moreau * Copyright 2014 DI (FH) Martin Haimberger * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../handle/nonehandle.h" #include #include /** * CreateProcessA * CreateProcessW * CreateProcessAsUserA * CreateProcessAsUserW * ExitProcess * GetCurrentProcess * GetCurrentProcessId * GetExitCodeProcess * GetProcessHandleCount * GetProcessId * GetProcessIdOfThread * GetProcessMitigationPolicy * GetProcessTimes * GetProcessVersion * OpenProcess * OpenProcessToken * ProcessIdToSessionId * SetProcessAffinityUpdateMode * SetProcessMitigationPolicy * SetProcessShutdownParameters * TerminateProcess */ #ifndef _WIN32 #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "thread.h" #include "../handle/handle.h" #include "../security/security.h" #ifndef NSIG #ifdef SIGMAX #define NSIG SIGMAX #else #define NSIG 64 #endif #endif char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock) { char* p; int index; int count; int length; char** envp = NULL; count = 0; if (!lpszEnvironmentBlock) return NULL; p = (char*) lpszEnvironmentBlock; while (p[0] && p[1]) { length = strlen(p); p += (length + 1); count++; } index = 0; p = (char*) lpszEnvironmentBlock; envp = (char**) calloc(count + 1, sizeof(char*)); if (!envp) return NULL; envp[count] = NULL; while (p[0] && p[1]) { length = strlen(p); envp[index] = _strdup(p); if (!envp[index]) { for (index -= 1; index >= 0; --index) { free(envp[index]); } free(envp); return NULL; } p += (length + 1); index++; } return envp; } /** * If the file name does not contain a directory path, the system searches for the executable file in the following sequence: * * 1) The directory from which the application loaded. * 2) The current directory for the parent process. * 3) The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. * 4) The 16-bit Windows system directory. There is no function that obtains the path of this directory, * but it is searched. The name of this directory is System. * 5) The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. * 6) The directories that are listed in the PATH environment variable. Note that this function * does not search the per-application path specified by the App Paths registry key. To include * this per-application path in the search sequence, use the ShellExecute function. */ char* FindApplicationPath(char* application) { char* path; char* save; DWORD nSize; LPSTR lpSystemPath; char* filename = NULL; if (!application) return NULL; if (application[0] == '/') return _strdup(application); nSize = GetEnvironmentVariableA("PATH", NULL, 0); if (!nSize) return application; lpSystemPath = (LPSTR) malloc(nSize); if (!lpSystemPath) return NULL; nSize = GetEnvironmentVariableA("PATH", lpSystemPath, nSize); save = NULL; path = strtok_s(lpSystemPath, ":", &save); while (path) { filename = GetCombinedPath(path, application); if (PathFileExistsA(filename)) { break; } free(filename); filename = NULL; path = strtok_s(NULL, ":", &save); } free(lpSystemPath); return filename; } static HANDLE CreateProcessHandle(pid_t pid); static BOOL ProcessHandleCloseHandle(HANDLE handle); BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { pid_t pid; int flags; int numArgs; LPSTR* pArgs = NULL; char** envp = NULL; char* filename = NULL; HANDLE thread; HANDLE process; WINPR_ACCESS_TOKEN* token; LPTCH lpszEnvironmentBlock; BOOL ret = FALSE; sigset_t oldSigMask; sigset_t newSigMask; BOOL restoreSigMask = FALSE; pid = 0; numArgs = 0; lpszEnvironmentBlock = NULL; pArgs = CommandLineToArgvA(lpCommandLine, &numArgs); if (!pArgs) return FALSE; flags = 0; token = (WINPR_ACCESS_TOKEN*) hToken; if (lpEnvironment) { envp = EnvironmentBlockToEnvpA(lpEnvironment); } else { lpszEnvironmentBlock = GetEnvironmentStrings(); if (!lpszEnvironmentBlock) goto finish; envp = EnvironmentBlockToEnvpA(lpszEnvironmentBlock); } if (!envp) goto finish; filename = FindApplicationPath(pArgs[0]); if (NULL == filename) goto finish; /* block all signals so that the child can safely reset the caller's handlers */ sigfillset(&newSigMask); restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask); /* fork and exec */ pid = fork(); if (pid < 0) { /* fork failure */ goto finish; } if (pid == 0) { /* child process */ #ifndef __sun int maxfd; #endif int fd; int sig; sigset_t set; struct sigaction act; /* set default signal handlers */ memset(&act, 0, sizeof(act)); act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); for (sig = 1; sig < NSIG; sig++) sigaction(sig, &act, NULL); /* unblock all signals */ sigfillset(&set); pthread_sigmask(SIG_UNBLOCK, &set, NULL); #ifdef __sun closefrom(3); #else #ifdef F_MAXFD // on some BSD derivates maxfd = fcntl(0, F_MAXFD); #else maxfd = sysconf(_SC_OPEN_MAX); #endif for(fd=3; fdGroupId) { int rc = setgid((gid_t) token->GroupId); if (rc < 0) { } else { initgroups(token->Username, (gid_t) token->GroupId); } } if (token->UserId) setuid((uid_t) token->UserId); } /* TODO: add better cwd handling and error checking */ if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0) chdir(lpCurrentDirectory); if (execve(filename, pArgs, envp) < 0) { /* execve failed - end the process */ _exit(1); } } else { /* parent process */ } process = CreateProcessHandle(pid); if (!process) { goto finish; } thread = CreateNoneHandle(); if (!thread) { ProcessHandleCloseHandle(process); goto finish; } lpProcessInformation->hProcess = process; lpProcessInformation->hThread = thread; lpProcessInformation->dwProcessId = (DWORD) pid; lpProcessInformation->dwThreadId = (DWORD) pid; ret = TRUE; finish: /* restore caller's original signal mask */ if (restoreSigMask) pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL); free(filename); if (pArgs) { HeapFree(GetProcessHeap(), 0, pArgs); } if (lpszEnvironmentBlock) FreeEnvironmentStrings(lpszEnvironmentBlock); if (envp) { int i = 0; while (envp[i]) { free(envp[i]); i++; } free(envp); } return ret; } BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); } BOOL CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return TRUE; } BOOL CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return _CreateProcessExA(hToken, 0, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); } BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return TRUE; } BOOL CreateProcessWithLogonA(LPCSTR lpUsername, LPCSTR lpDomain, LPCSTR lpPassword, DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return TRUE; } BOOL CreateProcessWithLogonW(LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return TRUE; } BOOL CreateProcessWithTokenA(HANDLE hToken, DWORD dwLogonFlags, LPCSTR lpApplicationName, LPSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return _CreateProcessExA(NULL, 0, lpApplicationName, lpCommandLine, NULL, NULL, FALSE, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); } BOOL CreateProcessWithTokenW(HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { return TRUE; } VOID ExitProcess(UINT uExitCode) { exit((int) uExitCode); } BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) { WINPR_PROCESS* process; if (!hProcess) return FALSE; if (!lpExitCode) return FALSE; process = (WINPR_PROCESS*) hProcess; *lpExitCode = process->dwExitCode; return TRUE; } HANDLE _GetCurrentProcess(VOID) { return NULL; } DWORD GetCurrentProcessId(VOID) { return ((DWORD) getpid()); } DWORD GetProcessId(HANDLE Process) { WINPR_PROCESS* process; process = (WINPR_PROCESS*) Process; if (!process) return 0; return (DWORD) process->pid; } BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode) { WINPR_PROCESS* process; process = (WINPR_PROCESS*) hProcess; if (!process || (process->pid <= 0)) return FALSE; if (kill(process->pid, SIGTERM)) return FALSE; return TRUE; } BOOL ProcessHandleCloseHandle(HANDLE handle) { WINPR_PROCESS* process = (WINPR_PROCESS*) handle; free(process); return TRUE; } static BOOL ProcessHandleIsHandle(HANDLE handle) { WINPR_PROCESS* process = (WINPR_PROCESS*) handle; if (!process || process->Type != HANDLE_TYPE_PROCESS) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } return TRUE; } static int ProcessGetFd(HANDLE handle) { WINPR_PROCESS *process = (WINPR_PROCESS *)handle; if (!ProcessHandleIsHandle(handle)) return -1; /* TODO: Process does not support fd... */ (void)process; return -1; } static HANDLE_OPS ops = { ProcessHandleIsHandle, ProcessHandleCloseHandle, ProcessGetFd, NULL /* CleanupHandle */ }; HANDLE CreateProcessHandle(pid_t pid) { WINPR_PROCESS* process; process = (WINPR_PROCESS*) calloc(1, sizeof(WINPR_PROCESS)); if (!process) return NULL; process->pid = pid; process->Type = HANDLE_TYPE_PROCESS; process->ops = &ops; return (HANDLE)process; } #endif