int _tmain(int argc, TCHAR* argv[]) { HANDLE hToken; wchar_t wszName[256]; wchar_t wszDomain[256]; STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi = {0}; wchar_t wszTitle[256]; DWORD dwLen,dwErr; if(argc!=2) { fprintf(stderr,"Usage: %S <username>",argv[0]); return -1; } dwLen=sizeof(wszName); GetUserName(wszName,&dwLen); _snwprintf(wszTitle,sizeof(wszTitle),L"%s impersonating %s",wszName,argv[1]); si.lpTitle=wszTitle; si.wShowWindow=SW_SHOW; if(BreakNameIntoParts(argv[1],wszName,wszDomain,NULL)) return -1; switch((dwErr=SuidGetImpersonationTokenW(wszName,wszDomain,LOGON32_LOGON_INTERACTIVE,&hToken))) { case ERROR_SUCCESS: break; case ERROR_PRIVILEGE_NOT_HELD: case ERROR_ACCESS_DENIED: { wchar_t *pw = getpass("Password: "******"%s\n",ErrorToString(dwErr)); return -1; } } } break; default: fprintf(stderr,"%s\n",ErrorToString(dwErr)); return -1; } SetWinstaDesktopSecurity(); wchar_t wszCommand[]=L"cmd.exe"; /* Unicode version of CreateProcess modifies its command parameter... Ansi doesn't. Apparently this is not classed as a bug ???? */ if(!CreateProcessAsUser(hToken,NULL,wszCommand,NULL,NULL,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) { CloseHandle(hToken); fprintf(stderr,"CreateProcess returned error %d\n",GetLastError()); return -1; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hToken); return 0; }
/// Start a task in a slot directory. /// This includes setting up soft links, /// passing preferences, and starting the process. /// /// Current dir is top-level Synecdoche dir. /// /// \post /// - If any error occurs /// - #task_state is #PROCESS_COULDNT_START /// - CLIENT_STATE::report_result_error() is called /// - else /// - #task_state is #PROCESS_EXECUTING /// /// \return 0 on success, nonzero otherwise. int ACTIVE_TASK::start() { char exec_name[256], exec_path[256]; unsigned int i; FILE_REF fref; int retval; // F*** goto, need to define some variables here instead of where they are used! std::ostringstream err_stream; #ifdef _WIN32 std::string cmd_line; std::string slotdirpath; #else // Needs to be defined here because those gotos would skip the // initialization of 'cmdline' and 'argv' if it would be defined later. std::ostringstream cmdline; std::list<std::string> argv; #endif if ((!full_init_done) && (log_flags.task)) { msg_printf(wup->project, MSG_INFO, "Starting %s", result->name ); } if (log_flags.cpu_sched) { msg_printf(wup->project, MSG_INFO, "[cpu_sched] Starting %s%s", result->name, (full_init_done) ? " (resume)" : " (initial)" ); } // Always check if all required files are present. If not, trigger // re-downloads and don't start the science application. FILE_INFO_PSET missing_file_infos; retval = gstate.input_files_available(result, true, &missing_file_infos); if (retval) { for (FILE_INFO_PSET::iterator it = missing_file_infos.begin(); it != missing_file_infos.end(); ++it) { FILE_INFO* fip = *it; if (fip) { err_stream << "Input file " << fip->name << " missing or invalid: " << retval; } else { err_stream << "Input file missing or invalid"; // We can't trigger a new download if we don't have // any file information. Just fail here as before. goto error; } fip->status = FILE_NOT_PRESENT; } } if (!missing_file_infos.empty()) { // Some files are missing and are set for re-transfer. // Update status and return without error. result->set_state(RESULT_FILES_DOWNLOADING, "start"); set_task_state(PROCESS_UNINITIALIZED, "start"); next_scheduler_state = PROCESS_UNINITIALIZED; return 0; } if (!full_init_done) { checkpoint_cpu_time = 0; checkpoint_wall_time = gstate.now; } current_cpu_time = checkpoint_cpu_time; episode_start_cpu_time = checkpoint_cpu_time; debt_interval_start_cpu_time = checkpoint_cpu_time; graphics_request_queue.init(result->name); // reset message queues process_control_queue.init(result->name); if (!app_client_shm.shm) { retval = get_shmem_seg_name(); if (retval) { err_stream << "Can't get shared memory segment name: " << boincerror(retval); goto error; } } // this must go AFTER creating shmem name, // since the shmem name is part of the file // retval = write_app_init_file(); if (retval) { err_stream << "Can't write init file: " << retval; goto error; } // set up applications files // strcpy(exec_name, ""); for (i=0; i<app_version->app_files.size(); i++) { fref = app_version->app_files[i]; FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fip); if (fref.main_program) { if (is_image_file(fip->name)) { err_stream << "Main program " << fip->name << " is an image file"; retval = ERR_NO_SIGNATURE; goto error; } if (!fip->executable && !wup->project->anonymous_platform) { err_stream << "Main program " << fip->name << " is not executable"; retval = ERR_NO_SIGNATURE; goto error; } safe_strcpy(exec_name, fip->name.c_str()); safe_strcpy(exec_path, file_path.c_str()); } // anonymous platform may use different files than // when the result was started, so link files even if not first time if ((!full_init_done) || (wup->project->anonymous_platform)) { retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } } if (!strlen(exec_name)) { err_stream << "No main program specified"; retval = ERR_NOT_FOUND; goto error; } // set up input, output files if (!full_init_done) { for (i=0; i<wup->input_files.size(); i++) { fref = wup->input_files[i]; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } for (i=0; i<result->output_files.size(); i++) { fref = result->output_files[i]; if (fref.copy_file) continue; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, false); if (retval) { err_stream << "Can't link output file"; goto error; } } full_init_done = true; } link_user_files(); if (gstate.exit_before_start) { exit(0); } #ifdef _WIN32 PROCESS_INFORMATION process_info; STARTUPINFO startup_info; LPVOID environment_block = NULL; char error_msg[1024]; char error_msg2[1024]; memset(&process_info, 0, sizeof(process_info)); memset(&startup_info, 0, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); // suppress 2-sec rotating hourglass cursor on startup // startup_info.dwFlags = STARTF_FORCEOFFFEEDBACK; app_client_shm.reset_msgs(); if (config.run_apps_manually) { // fill in core client's PID so we won't think app has exited pid = GetCurrentProcessId(); pid_handle = GetCurrentProcess(); set_task_state(PROCESS_EXECUTING, "start"); return 0; } // NOTE: in Windows, stderr is redirected in boinc_init_diagnostics(); cmd_line = exec_path + std::string(" ") + wup->command_line; if (strlen(app_version->cmdline)) { cmd_line += std::string(" ") + app_version->cmdline; } slotdirpath = relative_to_absolute(slot_dir); bool success = false; for (i=0; i<5; i++) { if (sandbox_account_service_token != NULL) { // Find CreateEnvironmentBlock/DestroyEnvironmentBlock pointers tCEB pCEB = NULL; tDEB pDEB = NULL; HMODULE hUserEnvLib = NULL; hUserEnvLib = LoadLibrary("userenv.dll"); if (hUserEnvLib) { pCEB = (tCEB) GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock"); pDEB = (tDEB) GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock"); } if (!pCEB(&environment_block, sandbox_account_service_token, FALSE)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INFO, "Process environment block creation failed: %s", error_msg ); } } if (CreateProcessAsUser( sandbox_account_service_token, exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS|CREATE_UNICODE_ENVIRONMENT, environment_block, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } if (!pDEB(environment_block)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg2)); msg_printf(wup->project, MSG_INFO, "Process environment block cleanup failed: %s", error_msg2 ); } } if (hUserEnvLib) { pCEB = NULL; pDEB = NULL; FreeLibrary(hUserEnvLib); } } else { if (CreateProcess( exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS, NULL, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } } boinc_sleep(drand()); } if (!success) { err_stream << "CreateProcess() failed - " << error_msg; retval = ERR_EXEC; goto error; } pid = process_info.dwProcessId; pid_handle = process_info.hProcess; CloseHandle(process_info.hThread); // thread handle is not used #else // Unix/Linux/Mac case // Set up core/app shared memory seg if needed // if (!app_client_shm.shm) { if (app_version->api_major_version() >= 6) { // Use mmap() shared memory std::string buf = slot_dir + std::string("/") + std::string(MMAPPED_FILE_NAME); if (g_use_sandbox) { if (!boinc_file_exists(buf.c_str())) { int fd = open(buf.c_str(), O_RDWR | O_CREAT, 0660); if (fd >= 0) { close (fd); #ifdef SANDBOX set_to_project_group(buf.c_str()); #endif } } } retval = create_shmem_mmap( buf.c_str(), sizeof(SHARED_MEM), (void**)&app_client_shm.shm ); } else { // Use shmget() shared memory retval = create_shmem( shmem_seg_name, sizeof(SHARED_MEM), gstate.boinc_project_gid, (void**)&app_client_shm.shm ); if (retval) { needs_shmem = true; destroy_shmem(shmem_seg_name); return retval; } } needs_shmem = false; } app_client_shm.reset_msgs(); #if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__))) // PowerPC apps emulated on i386 Macs crash if running graphics powerpc_emulated_on_i386 = ! is_native_i386_app(exec_path); #endif if (config.run_apps_manually) { pid = getpid(); // use the client's PID set_task_state(PROCESS_EXECUTING, "start"); return 0; } // Prepare command line for the science app: cmdline << wup->command_line; if (strlen(app_version->cmdline)) { cmdline << ' ' << app_version->cmdline; } argv = parse_command_line(cmdline.str().c_str()); if (log_flags.task_debug) { debug_print_argv(argv); } pid = fork(); if (pid == -1) { err_stream << "fork() failed: " << strerror(errno); retval = ERR_FORK; goto error; } if (pid == 0) { // from here on we're running in a new process. // If an error happens, // exit nonzero so that the core client knows there was a problem. // don't pass stdout to the app // int fd = open("/dev/null", O_RDWR); dup2(fd, STDOUT_FILENO); close(fd); // add to library path: // - the project dir (../../projects/X) // - the slot dir (.) // - the Synecdoche dir (../..) // We use relative paths in case higher-level dirs // are not readable to the account under which app runs // std::string pdir = get_project_dir(wup->project); std::ostringstream libpath; const char* env_lib_path = getenv("LD_LIBRARY_PATH"); if (env_lib_path) { libpath << env_lib_path << ':'; } libpath << "../../" << pdir << ":.:../.."; setenv("LD_LIBRARY_PATH", libpath.str().c_str(), 1); retval = chdir(slot_dir.c_str()); if (retval) { perror("chdir"); fflush(NULL); _exit(errno); } #if 0 // set stack size limit to the max. // Some BOINC apps have reported problems with exceeding // small stack limits (e.g. 8 MB) // and it seems like the best thing to raise it as high as possible // struct rlimit rlim; #define MIN_STACK_LIMIT 64000000 getrlimit(RLIMIT_STACK, &rlim); if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur <= MIN_STACK_LIMIT) { if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max > MIN_STACK_LIMIT) { rlim.rlim_cur = MIN_STACK_LIMIT; } else { rlim.rlim_cur = rlim.rlim_max; } setrlimit(RLIMIT_STACK, &rlim); } #endif // hook up stderr to a specially-named file // freopen(STDERR_FILE, "a", stderr); // set idle process priority #ifdef HAVE_SETPRIORITY if (setpriority(PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY)) { perror("setpriority"); } #endif std::string path = std::string("../../") + std::string(exec_path); if (g_use_sandbox) { std::ostringstream switcher_path; switcher_path << "../../" << SWITCHER_DIR << '/' << SWITCHER_FILE_NAME; argv.push_front(exec_name); argv.push_front(path); argv.push_front(SWITCHER_FILE_NAME); // Files written by projects have user boinc_project and group boinc_project, // so they must be world-readable so Synecdoche can read them. umask(2); retval = do_execv(switcher_path.str(), argv); } else { argv.push_front(exec_name); retval = do_execv(path, argv); } msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation (%s) failed: %s, errno=%d\n", path.c_str(), boincerror(retval), errno ); perror("execv"); fflush(NULL); _exit(errno); } if (log_flags.task_debug) { msg_printf(wup->project, MSG_INFO, "[task_debug] ACTIVE_TASK::start(): forked process: pid %d\n", pid ); } #endif set_task_state(PROCESS_EXECUTING, "start"); return 0; // go here on error; "error_msg" contains error message, "retval" is nonzero // error: // if something failed, it's possible that the executable was munged. // Verify it to trigger another download. // gstate.input_files_available(result, true); gstate.report_result_error(*result, "%s", err_stream.str().c_str()); set_task_state(PROCESS_COULDNT_START, "start"); return retval; }
Result<ExitCode> ProcessAsUser::Run(const Settings& settings, ProcessTracker& processTracker) const { Trace trace(settings.GetLogLevel()); trace < L"ProcessAsUser::Attempt to log a user on to the local computer"; StringBuffer userName(settings.GetUserName()); StringBuffer domain(settings.GetDomain()); StringBuffer password(settings.GetPassword()); StringBuffer workingDirectory(settings.GetWorkingDirectory()); StringBuffer commandLine(settings.GetCommandLine()); SecurityManager securityManager; auto setPrivilegesResult = securityManager.SetPrivileges(trace, { SE_TCB_NAME, SE_ASSIGNPRIMARYTOKEN_NAME }, true); if(setPrivilegesResult.HasError()) { return setPrivilegesResult.GetError(); } auto newUserSecurityTokenHandle = Handle(L"New user security token"); unsigned long logonTypeCount = sizeof(allLogonTypes) / sizeof(allLogonTypes[0]); for (unsigned long logonTypeIndex = 0; logonTypeIndex < logonTypeCount; logonTypeIndex++) { auto logonType = allLogonTypes[logonTypeIndex]; trace < L"::LogonUser using logon type "; switch (logonType) { case LOGON32_LOGON_INTERACTIVE: trace << L"LOGON32_LOGON_INTERACTIVE"; break; case LOGON32_LOGON_NETWORK: trace << L"LOGON32_LOGON_NETWORK"; break; case LOGON32_LOGON_BATCH: trace << L"LOGON32_LOGON_BATCH"; break; case LOGON32_LOGON_SERVICE: trace << L"LOGON32_LOGON_SERVICE"; break; } if (LogonUser( userName.GetPointer(), domain.GetPointer(), password.GetPointer(), logonType, LOGON32_PROVIDER_DEFAULT, &newUserSecurityTokenHandle)) { break; } auto error = Error(L"LogonUser"); trace << L" - "; trace << error.GetDescription(); if(logonTypeIndex == logonTypeCount -1) { return error; } } trace < L"ProcessAsUser::InitializeConsoleRedirection a new security descriptor"; trace < L"::InitializeSecurityDescriptor"; SECURITY_DESCRIPTOR securityDescriptor = {}; if (!InitializeSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION)) { return Error(L"InitializeSecurityDescriptor"); } trace < L"::SetSecurityDescriptorDacl"; if (!SetSecurityDescriptorDacl( &securityDescriptor, true, nullptr, false)) { return Error(L"SetSecurityDescriptorDacl"); } trace < L"ProcessAsUser::Creates a new access primary token that duplicates new process's token"; auto primaryNewUserSecurityTokenHandle = Handle(L"Primary new user security token"); SECURITY_ATTRIBUTES processSecAttributes = {}; processSecAttributes.lpSecurityDescriptor = &securityDescriptor; processSecAttributes.nLength = sizeof(SECURITY_DESCRIPTOR); processSecAttributes.bInheritHandle = true; trace < L"::DuplicateTokenEx"; if (!DuplicateTokenEx( newUserSecurityTokenHandle, 0, // MAXIMUM_ALLOWED &processSecAttributes, SecurityImpersonation, TokenPrimary, &primaryNewUserSecurityTokenHandle)) { return Error(L"DuplicateTokenEx"); } SECURITY_ATTRIBUTES threadSecAttributes = {}; threadSecAttributes.lpSecurityDescriptor = nullptr; threadSecAttributes.nLength = 0; threadSecAttributes.bInheritHandle = false; STARTUPINFO startupInfo = {}; trace < L"ProcessTracker::InitializeConsoleRedirection"; auto error = processTracker.InitializeConsoleRedirection(processSecAttributes, startupInfo); if(error.HasError()) { return Result<ExitCode>(error.GetError()); } trace < L"::LoadUserProfile"; PROFILEINFO profileInfo = {}; profileInfo.dwSize = sizeof(PROFILEINFO); profileInfo.lpUserName = userName.GetPointer(); if (!LoadUserProfile(primaryNewUserSecurityTokenHandle, &profileInfo)) { return Error(L"LoadUserProfile"); } auto newProcessEnvironmentResult = GetEnvironment(settings, primaryNewUserSecurityTokenHandle, settings.GetInheritanceMode(), trace); if (newProcessEnvironmentResult.HasError()) { UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return Result<ExitCode>(newProcessEnvironmentResult.GetError()); } auto setIntegrityLevelResult = securityManager.SetIntegrityLevel(settings.GetIntegrityLevel(), primaryNewUserSecurityTokenHandle, trace); if (setIntegrityLevelResult.HasError()) { return Result<ExitCode>(setIntegrityLevelResult.GetError()); } trace < L"ProcessAsUser::Create a new process and its primary thread. The new process runs in the security context of the user represented by the specified token."; PROCESS_INFORMATION processInformation = {}; startupInfo.dwFlags = STARTF_USESHOWWINDOW; startupInfo.wShowWindow = ShowModeConverter::ToShowWindowFlag(settings.GetShowMode()); auto cmdLine = settings.GetCommandLine(); trace < L"::CreateProcessAsUser"; if (!CreateProcessAsUser( primaryNewUserSecurityTokenHandle, nullptr, commandLine.GetPointer(), &processSecAttributes, &threadSecAttributes, true, CREATE_UNICODE_ENVIRONMENT, newProcessEnvironmentResult.GetResultValue().CreateEnvironment(), workingDirectory.GetPointer(), &startupInfo, &processInformation)) { auto result = Error(L"CreateProcessAsUser"); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return result; } // ReSharper disable CppInitializedValueIsAlwaysRewritten // ReSharper disable CppEntityAssignedButNoRead auto processHandle = Handle(L"Service Process"); processHandle = processInformation.hProcess; auto threadHandle = Handle(L"Thread"); threadHandle = processInformation.hThread; auto exitCode = processTracker.WaiteForExit(processInformation.hProcess, trace); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return exitCode; }
DWORD WINAPI Cadthread(LPVOID lpParam) { OSVERSIONINFO OSversion; OSversion.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); GetVersionEx(&OSversion); HDESK desktop=NULL; desktop = OpenInputDesktop(0, FALSE, DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | GENERIC_WRITE ); if (desktop == NULL) vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop Error \n")); else vnclog.Print(LL_INTERR, VNCLOG("OpenInputdesktop OK\n")); HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId()); DWORD dummy; char new_name[256]; if (desktop) { if (!GetUserObjectInformation(desktop, UOI_NAME, &new_name, 256, &dummy)) { vnclog.Print(LL_INTERR, VNCLOG("!GetUserObjectInformation \n")); } vnclog.Print(LL_INTERR, VNCLOG("SelectHDESK to %s (%x) from %x\n"), new_name, desktop, old_desktop); if (!SetThreadDesktop(desktop)) { vnclog.Print(LL_INTERR, VNCLOG("SelectHDESK:!SetThreadDesktop \n")); } } ////// if(OSversion.dwMajorVersion>=6 && vncService::RunningAsService()) { if( vncService::RunningAsService() &&!IsSoftwareCadEnabled()) { DWORD result=MessageBoxSecure(NULL,"UAC is Disable, make registry changes to allow cad","Warning",MB_YESNO); if (result==IDYES) { HANDLE hProcess=NULL,hPToken=NULL; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if (!hProcess) goto error; if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, &hPToken)) { CloseHandle(hProcess); goto error; } char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -softwarecadhelper"); STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; HANDLE Token=NULL; HANDLE process=NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD errorcode=GetLastError(); if (process) CloseHandle(process); if (Token) CloseHandle(Token); if (ProcessInfo.hProcess) CloseHandle(ProcessInfo.hProcess); if (ProcessInfo.hThread) CloseHandle(ProcessInfo.hThread); if (errorcode == 1314) goto error; goto gotome; error: Enable_softwareCAD_elevated(); } } } } gotome: ///////////////////// if(OSversion.dwMajorVersion==6)//&& OSversion.dwMinorVersion>=1) //win7 // test win7 +Vista { if (hShutdownEventcad==NULL ) hShutdownEventcad = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SessionEventUltraCad"); if (hShutdownEventcad!=NULL ) SetEvent(hShutdownEventcad); if (old_desktop) SetThreadDesktop(old_desktop); if (desktop) CloseDesktop(desktop); return 0; } HKEY hKey; DWORD isLUAon = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD LUAbufSize = 4; RegQueryValueEx(hKey, TEXT("EnableLUA"), NULL, NULL, (LPBYTE)&isLUAon, &LUAbufSize); RegCloseKey(hKey); } if (isLUAon != 1 && OSversion.dwMajorVersion==6) { if (hShutdownEventcad==NULL ) hShutdownEventcad = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SessionEventUltraCad"); if (hShutdownEventcad!=NULL ) SetEvent(hShutdownEventcad); if (old_desktop) SetThreadDesktop(old_desktop); if (desktop) CloseDesktop(desktop); return 0; } //Full path needed, sometimes it just default to system32 char WORKDIR[MAX_PATH]; char mycommand[MAX_PATH]; if (GetModuleFileName(NULL, WORKDIR, MAX_PATH)) { char* p = strrchr(WORKDIR, '\\'); if (p == NULL) return 0; *p = '\0'; } strcpy(mycommand,""); strcat(mycommand,WORKDIR);//set the directory strcat(mycommand,"\\"); strcat(mycommand,"cad.exe"); int nr=(LONG_PTR)ShellExecute(GetDesktopWindow(), "open", mycommand, "", 0, SW_SHOWNORMAL); if (nr<=32) { //error // if ( nr==SE_ERR_ACCESSDENIED ) vncTimedMsgBox::Do( sz_ID_CADPERMISSION, sz_ID_ULTRAVNC_WARNING, MB_ICONINFORMATION | MB_OK ); if ( nr==ERROR_PATH_NOT_FOUND || nr==ERROR_FILE_NOT_FOUND) vncTimedMsgBox::Do( sz_ID_CADERRORFILE, sz_ID_ULTRAVNC_WARNING, MB_ICONINFORMATION | MB_OK ); } if (old_desktop) SetThreadDesktop(old_desktop); if (desktop) CloseDesktop(desktop); return 0; }
VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) { #ifdef USE_WINLOGON_EVENT WCHAR szUserW[128] = L""; char szUserA[128] = ""; char szPath[MAX_PATH] = ""; char szLogonId[128] = ""; DWORD count; char filename[MAX_PATH] = ""; char newfilename[MAX_PATH] = ""; char commandline[MAX_PATH+256] = ""; STARTUPINFO startupinfo; PROCESS_INFORMATION procinfo; HANDLE hf = NULL; LUID LogonId = {0, 0}; PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL; HKEY hKey1 = NULL, hKey2 = NULL; DebugEvent0("KFW_Logon_Event - Start"); GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData ); if ( pLogonSessionData ) { LogonId = pLogonSessionData->LogonId; DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart); _snprintf(szLogonId, sizeof(szLogonId), "kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart); LsaFreeReturnBuffer( pLogonSessionData ); } else { DebugEvent0("KFW_Logon_Event - Unable to determine LogonId"); return; } count = GetEnvironmentVariable("TEMP", filename, sizeof(filename)); if ( count > sizeof(filename) || count == 0 ) { GetWindowsDirectory(filename, sizeof(filename)); } if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) { DebugEvent0("KFW_Logon_Event - filename too long"); return; } strcat(filename, "\\"); strcat(filename, szLogonId); hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) { DebugEvent0("KFW_Logon_Event - file cannot be opened"); return; } CloseHandle(hf); if (KFW_set_ccache_dacl(filename, pInfo->hToken)) { DebugEvent0("KFW_Logon_Event - unable to set dacl"); DeleteFile(filename); return; } if (KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) { DebugEvent0("KFW_Logon_Event - unable to obtain temp directory"); return; } if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) { DebugEvent0("KFW_Logon_Event - new filename too long"); return; } strcat(newfilename, "\\"); strcat(newfilename, szLogonId); if (!MoveFileEx(filename, newfilename, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError()); return; } _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", newfilename); GetStartupInfo(&startupinfo); if (CreateProcessAsUser( pInfo->hToken, "kfwcpcc.exe", commandline, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, NULL, NULL, &startupinfo, &procinfo)) { DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); WaitForSingleObject(procinfo.hProcess, 30000); CloseHandle(procinfo.hThread); CloseHandle(procinfo.hProcess); } else { DebugEvent0("KFW_Logon_Event - CreateProcessFailed"); } DeleteFile(newfilename); DebugEvent0("KFW_Logon_Event - End"); #endif /* USE_WINLOGON_EVENT */ }
/* * Create a restricted token and execute the specified process with it. * * Returns restricted token on success and 0 on failure. * * On NT4, or any other system not containing the required functions, will * NOT execute anything. */ HANDLE CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname) { BOOL b; STARTUPINFO si; HANDLE origToken; HANDLE restrictedToken; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_AND_ATTRIBUTES dropSids[2]; __CreateRestrictedToken _CreateRestrictedToken = NULL; HANDLE Advapi32Handle; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); Advapi32Handle = LoadLibrary("ADVAPI32.DLL"); if (Advapi32Handle != NULL) { _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken"); } if (_CreateRestrictedToken == NULL) { fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname); if (Advapi32Handle != NULL) FreeLibrary(Advapi32Handle); return 0; } /* Open the current token to use as a base for the restricted one */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) { fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError()); return 0; } /* Allocate list of SIDs to remove */ ZeroMemory(&dropSids, sizeof(dropSids)); if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) || !AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid)) { fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"), progname, GetLastError()); return 0; } b = _CreateRestrictedToken(origToken, DISABLE_MAX_PRIVILEGE, sizeof(dropSids) / sizeof(dropSids[0]), dropSids, 0, NULL, 0, NULL, &restrictedToken); FreeSid(dropSids[1].Sid); FreeSid(dropSids[0].Sid); CloseHandle(origToken); FreeLibrary(Advapi32Handle); if (!b) { fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"), progname, GetLastError()); return 0; } #ifndef __CYGWIN__ AddUserToTokenDacl(restrictedToken); #endif if (!CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo)) { fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError()); return 0; } ResumeThread(processInfo->hThread); return restrictedToken; }
int newagent::start_process(const char *command,int & error_code,const char * local_dir,const char * user,const char * password) { error_code=0; #ifdef _WIN32 PROCESS_INFORMATION process; STARTUPINFO si; HANDLE res=0; bool ok=false; HANDLE other_user=0; #ifdef _DEBUG if (!strcmp(command,"forceerror")) *((int *)0)=5; #endif memset(&si,0,sizeof(si)); si.cb = sizeof(si); si.lpTitle = (char*)command; si.wShowWindow = SW_SHOWDEFAULT; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWNORMAL; char current_dir[256]=" ;103<;01",c_dir[256]; if (local_dir&&*local_dir) { strcpy(c_dir,local_dir); } else { if (!is_debug_session&&read_key("03",(unsigned char *)current_dir,sizeof(current_dir))) { char * finger=current_dir; int bs=4; while (*finger&&bs) { if (*finger=='\\') bs--; finger++; } if (*finger) sprintf(c_dir,maped_drive"\\%s",finger); else sprintf(c_dir,maped_drive"\\"); } else strcpy(c_dir,"."); } if (is_debug_session) { ok=(bool)CreateProcess(NULL,(char*)command,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,c_dir,&si,&process); if (!ok) error_code=GetLastError(); } else { if (!local_dir&&!drive_maped) do_map_drive(error_code); if(!error_code) { HANDLE uh=server_user; if (user&&*user) { logonu(other_user,unscr((char*)user),unscr((char*)password),error_code); uh=other_user; } if (!error_code) { if (!ImpersonateLoggedOnUser(uh)) error_code=GetLastError(); if (!error_code) { char saved_dir[256]; if (!GetCurrentDirectory(sizeof(saved_dir),saved_dir)) { logfile("GetCurrentDirectory failed\r\n"); error_code=GetLastError(); } else { if (!SetCurrentDirectory(c_dir)) { error_code=GetLastError(); if (error_code==2) error_code=267; logfile ("SetCurrentDirectory failed %s %i\r\n",c_dir,error_code); } else { ok=(bool)CreateProcessAsUser( uh,NULL,(char*)command,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,c_dir,&si,&process); if (!ok) error_code=GetLastError(); if (ok&&!SetCurrentDirectory(saved_dir)) { logfile("restore current dirctory failed %s\r\n",saved_dir); error_code=GetLastError(); } } } RevertToSelf(); } } } } if (ok) { res=process.hProcess; CloseHandle(process.hThread); logfile("Process started: %s\r\n",command); } else { logfile("Process failed: %s error(%i) %s\r\n",command,error_code,c_dir); } if (other_user) CloseHandle(other_user); if (ok) return (int)res; else return 0; #else // if (is_debug_session) { long res; _chdir(cur_dir); pid_t pid; if (invoke_program(command, res, false, NULL, NULL, &pid)) return pid; printf("invoke_program error %d\n", res); error_code=res; logfile("Process failed: %s error(%i) %s\r\n",command,error_code,cur_dir); /* not sure these should be freed here free(user); free(password); */ return 0; } #endif }
BOOL StartProcess(int nIndex) { // start a process with given index STARTUPINFO startUpInfo = { sizeof(STARTUPINFO),NULL,"",NULL,0,0,0,0,0,0,0,STARTF_USESHOWWINDOW,0,0,NULL,0,0,0}; char pItem[nBufferSize+1]; sprintf(pItem,"Process%d\0",nIndex); char pCommandLine[nBufferSize+1]; GetPrivateProfileString(pItem,"CommandLine","",pCommandLine,nBufferSize,pInitFile); if(strlen(pCommandLine)>4) { char pWorkingDir[nBufferSize+1]; GetPrivateProfileString(pItem,"WorkingDir","",pWorkingDir,nBufferSize,pInitFile); char pUserName[nBufferSize+1]; GetPrivateProfileString(pItem,"UserName","",pUserName,nBufferSize,pInitFile); char pPassword[nBufferSize+1]; GetPrivateProfileString(pItem,"Password","",pPassword,nBufferSize,pInitFile); char pDomain[nBufferSize+1]; GetPrivateProfileString(pItem,"Domain","",pDomain,nBufferSize,pInitFile); BOOL bImpersonate = (::strlen(pUserName)>0&&::strlen(pPassword)>0); char pUserInterface[nBufferSize+1]; GetPrivateProfileString(pItem,"UserInterface","N",pUserInterface,nBufferSize,pInitFile); BOOL bUserInterface = (bImpersonate==FALSE)&&(pUserInterface[0]=='y'||pUserInterface[0]=='Y'||pUserInterface[0]=='1')?TRUE:FALSE; char CurrentDesktopName[512]; // set the correct desktop for the process to be started if(bUserInterface) { startUpInfo.wShowWindow = SW_SHOW; startUpInfo.lpDesktop = NULL; } else { HDESK hCurrentDesktop = GetThreadDesktop(GetCurrentThreadId()); DWORD len; GetUserObjectInformation(hCurrentDesktop,UOI_NAME,CurrentDesktopName,MAX_PATH,&len); startUpInfo.wShowWindow = SW_HIDE; startUpInfo.lpDesktop = (bImpersonate==FALSE)?CurrentDesktopName:(CHAR *)""; } if(bImpersonate==FALSE) { // create the process if(CreateProcess(NULL,pCommandLine,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,strlen(pWorkingDir)==0?NULL:pWorkingDir,&startUpInfo,&pProcInfo[nIndex])) { char pPause[nBufferSize+1]; GetPrivateProfileString(pItem,"PauseStart","100",pPause,nBufferSize,pInitFile); Sleep(atoi(pPause)); return TRUE; } else { long nError = GetLastError(); char pTemp[121]; sprintf(pTemp,"Failed to start program '%s', error code = %d", pCommandLine, nError); WriteLog(pTemp); return FALSE; } } else { HANDLE hToken = NULL; if(LogonUser(pUserName,(::strlen(pDomain)==0)?(CHAR *)".":pDomain,pPassword,LOGON32_LOGON_SERVICE,LOGON32_PROVIDER_DEFAULT,&hToken)) { if(CreateProcessAsUser(hToken,NULL,pCommandLine,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,(strlen(pWorkingDir)==0)?NULL:pWorkingDir,&startUpInfo,&pProcInfo[nIndex])) { char pPause[nBufferSize+1]; GetPrivateProfileString(pItem,"PauseStart","100",pPause,nBufferSize,pInitFile); Sleep(atoi(pPause)); return TRUE; } long nError = GetLastError(); char pTemp[121]; sprintf(pTemp,"Failed to start program '%s' as user '%s', error code = %d", pCommandLine, pUserName, nError); WriteLog(pTemp); return FALSE; } long nError = GetLastError(); char pTemp[121]; sprintf(pTemp,"Failed to logon as user '%s', error code = %d", pUserName, nError); WriteLog(pTemp); return FALSE; } } else return FALSE; }
BOOL CProcess::Execute(HANDLE hToken, LPCTSTR lpszDesk, LPCTSTR lpszCommandLine, int nCmdShow ) { BOOL bRet = FALSE; if (m_strFileName.IsEmpty()) { return bRet; } STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); si.dwFlags = STARTF_FORCEOFFFEEDBACK; si.wShowWindow = (WORD)nCmdShow; si.lpDesktop = (LPTSTR)lpszDesk; TCHAR szCommandLine[2048] = {0}; lstrcat(szCommandLine, m_strFileName); lstrcat(szCommandLine, _T(" ")); lstrcat(szCommandLine, lpszCommandLine); if (hToken == NULL) { bRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi); } else { si.lpDesktop = _T("winsta0\\default"); if (ImpersonateLoggedOnUser(hToken)) { bRet = CreateProcessAsUser( hToken, // client's access token NULL, // file to execute szCommandLine, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags NULL, // pointer to new environment block NULL, // name of current directory &si, // pointer to STARTUPINFO structure &pi // receives information about new process ); RevertToSelf(); } } if (bRet) { if (m_hProcess != NULL) { CloseHandle(m_hProcess); } m_hProcess = pi.hProcess; m_dwProcessId = pi.dwProcessId; CloseHandle(pi.hThread); } return bRet; }
bool LaunchProcess(const string16& cmdline, const LaunchOptions& options, ProcessHandle* process_handle) { STARTUPINFO startup_info = {}; startup_info.cb = sizeof(startup_info); if(options.empty_desktop_name) { startup_info.lpDesktop = L""; } startup_info.dwFlags = STARTF_USESHOWWINDOW; startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; PROCESS_INFORMATION process_info; DWORD flags = 0; if(options.job_handle) { flags |= CREATE_SUSPENDED; // If this code is run under a debugger, the launched process is // automatically associated with a job object created by the debugger. // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. flags |= CREATE_BREAKAWAY_FROM_JOB; } if(options.as_user) { flags |= CREATE_UNICODE_ENVIRONMENT; void* enviroment_block = NULL; if(!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { return false; } BOOL launched = CreateProcessAsUser(options.as_user, NULL, const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, options.inherit_handles, flags, enviroment_block, NULL, &startup_info, &process_info); DestroyEnvironmentBlock(enviroment_block); if(!launched) { return false; } } else { if(!CreateProcess(NULL, const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, options.inherit_handles, flags, NULL, NULL, &startup_info, &process_info)) { return false; } } if(options.job_handle) { if(0 == AssignProcessToJobObject(options.job_handle, process_info.hProcess)) { LOG(ERROR) << "Could not AssignProcessToObject."; KillProcess(process_info.hProcess, kProcessKilledExitCode, true); return false; } ResumeThread(process_info.hThread); } // Handles must be closed or they will leak. CloseHandle(process_info.hThread); if(options.wait) { WaitForSingleObject(process_info.hProcess, INFINITE); } // If the caller wants the process handle, we won't close it. if(process_handle) { *process_handle = process_info.hProcess; } else { CloseHandle(process_info.hProcess); } return true; }
int _tmain(int argc, TCHAR *argv[]) { BOOL bResult; NTSTATUS Status; NTSTATUS SubStatus; HANDLE hLsa = NULL; HANDLE hProcess = NULL; HANDLE hToken = NULL; HANDLE hTokenS4U = NULL; LSA_STRING Msv1_0Name = { 0 }; LSA_STRING OriginName = { 0 }; PMSV1_0_S4U_LOGON pS4uLogon = NULL; TOKEN_SOURCE TokenSource; ULONG ulAuthenticationPackage; DWORD dwMessageLength; PBYTE pbPosition; PROCESS_INFORMATION pi = { 0 }; STARTUPINFO si = { 0 }; PTOKEN_GROUPS pGroups = NULL; PSID pLogonSid = NULL; PSID pExtraSid = NULL; PVOID pvProfile = NULL; DWORD dwProfile = 0; LUID logonId = { 0 }; QUOTA_LIMITS quotaLimits; LPTSTR szCommandLine = NULL; LPTSTR szSrcCommandLine = TEXT("%systemroot%\\system32\\cmd.exe"); LPTSTR szDomain = NULL; LPTSTR szUsername = NULL; TCHAR seps[] = TEXT("\\"); TCHAR *next_token = NULL; g_hHeap = GetProcessHeap(); if (argc < 2) { fprintf(stderr, "Usage:\n s4u.exe Domain\\Username [Extra SID]\n\n"); goto End; } // // Get DOMAIN and USERNAME from command line. // szDomain = _tcstok_s(argv[1], seps, &next_token); if (szDomain == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } szUsername = _tcstok_s(NULL, seps, &next_token); if (szUsername == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } // // Activate the TCB privilege // hProcess = GetCurrentProcess(); OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); if (!SetPrivilege(hToken, SE_TCB_NAME, TRUE)) { goto End; } // // Get logon SID // if (!GetLogonSID(hToken, &pLogonSid)) { fprintf(stderr, "Unable to find logon SID.\n"); goto End; } // // Connect (Untrusted) to LSA // Status = LsaConnectUntrusted(&hLsa); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaConnectUntrusted failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Lookup for the MSV1_0 authentication package (NTLMSSP) // InitLsaString(&Msv1_0Name, MSV1_0_PACKAGE_NAME); Status = LsaLookupAuthenticationPackage(hLsa, &Msv1_0Name, &ulAuthenticationPackage); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaLookupAuthenticationPackage failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Create MSV1_0_S4U_LOGON structure // dwMessageLength = sizeof(MSV1_0_S4U_LOGON) + (2 + wcslen(szDomain) + wcslen(szUsername)) * sizeof(WCHAR); pS4uLogon = (PMSV1_0_S4U_LOGON)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, dwMessageLength); if (pS4uLogon == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pS4uLogon->MessageType = MsV1_0S4ULogon; pbPosition = (PBYTE)pS4uLogon + sizeof(MSV1_0_S4U_LOGON); pbPosition = InitUnicodeString(&pS4uLogon->UserPrincipalName, szUsername, pbPosition); pbPosition = InitUnicodeString(&pS4uLogon->DomainName, szDomain, pbPosition); // // Misc // strcpy_s(TokenSource.SourceName, TOKEN_SOURCE_LENGTH, "S4UWin"); InitLsaString(&OriginName, "S4U for Windows"); AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); // // Add extra SID to token. // // If the application needs to connect to a Windows Desktop, Logon SID must be added to the Token. // pGroups = (PTOKEN_GROUPS)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, sizeof(TOKEN_GROUPS) + 2*sizeof(SID_AND_ATTRIBUTES)); if (pGroups == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pGroups->GroupCount = 1; pGroups->Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[0].Sid = pLogonSid; // // If an extra SID is specified to command line, add it to the pGroups structure. // if (argc==3) { bResult = ConvertStringSidToSid(argv[2], &pExtraSid); if (bResult == TRUE) { pGroups->GroupCount = 2; pGroups->Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[1].Sid = pExtraSid; } else { fprintf(stderr, "Unable to convert SID (error %u).", GetLastError()); } } // // Call LSA // Status = LsaLogonUser( hLsa, &OriginName, Network, // Or Batch ulAuthenticationPackage, pS4uLogon, dwMessageLength, pGroups, // LocalGroups &TokenSource, // SourceContext &pvProfile, &dwProfile, &logonId, &hTokenS4U, "aLimits, &SubStatus ); if (Status!=STATUS_SUCCESS) { printf("LsaLogonUser failed (error 0x%x).\n", Status); goto End; } printf("LsaLogonUser: OK, LogonId: 0x%x-0x%x\n", logonId.HighPart, logonId.LowPart); // // Create process with S4U token. // si.cb = sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); // // Warning: szCommandLine parameter of CreateProcessAsUser() must be writable // szCommandLine = (LPTSTR)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, MAX_PATH * sizeof(TCHAR)); if (szCommandLine == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } if (ExpandEnvironmentStrings(szSrcCommandLine, szCommandLine, MAX_PATH) == 0) { fprintf(stderr, "ExpandEnvironmentStrings failed (error %u).", GetLastError()); goto End; } // // CreateProcessAsUser required SeAssignPrimaryTokenPrivilege but no need to be activated. // bResult = CreateProcessAsUser( hTokenS4U, NULL, szCommandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, TEXT("c:\\"), &si, &pi ); if (bResult == FALSE) { printf("CreateProcessAsUser failed (error %u).\n", GetLastError()); goto End; } End: // // Free resources // if (Msv1_0Name.Buffer) HeapFree(g_hHeap, 0, Msv1_0Name.Buffer); if (OriginName.Buffer) HeapFree(g_hHeap, 0, OriginName.Buffer); if (pLogonSid) HeapFree(g_hHeap, 0, pLogonSid); if (pExtraSid) LocalFree(pExtraSid); if (pS4uLogon) HeapFree(g_hHeap, 0, pS4uLogon); if (pGroups) HeapFree(g_hHeap, 0, pGroups); if (pvProfile) LsaFreeReturnBuffer(pvProfile); if (hLsa) LsaClose(hLsa); if (hToken) CloseHandle(hToken); if (hTokenS4U) CloseHandle(hTokenS4U); if (pi.hProcess) CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); return EXIT_SUCCESS; }
BOOL create_process_as_user(IN DWORD session_id, IN LPCWSTR application_name, IN LPWSTR command_line, IN LPSECURITY_ATTRIBUTES process_attributes, IN LPSECURITY_ATTRIBUTES thread_attributes, IN BOOL inherit_handles, IN DWORD creation_flags, IN LPVOID environment, IN LPCWSTR current_directory, IN LPSTARTUPINFOW startup_info, OUT LPPROCESS_INFORMATION process_information) { PROCESSENTRY32 proc_entry; DWORD winlogon_pid = 0; HANDLE winlogon_proc; HANDLE token = NULL; HANDLE token_dup; BOOL ret = FALSE; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snap == INVALID_HANDLE_VALUE) { vd_printf("CreateToolhelp32Snapshot() failed %lu", GetLastError()); return false; } ZeroMemory(&proc_entry, sizeof(proc_entry)); proc_entry.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(snap, &proc_entry)) { vd_printf("Process32First() failed %lu", GetLastError()); CloseHandle(snap); return false; } do { if (_tcsicmp(proc_entry.szExeFile, WINLOGON_FILENAME) == 0) { DWORD winlogon_session_id = 0; if (ProcessIdToSessionId(proc_entry.th32ProcessID, &winlogon_session_id) && winlogon_session_id == session_id) { winlogon_pid = proc_entry.th32ProcessID; break; } } } while (Process32Next(snap, &proc_entry)); CloseHandle(snap); if (winlogon_pid == 0) { vd_printf("Winlogon not found"); return false; } winlogon_proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogon_pid); if (!winlogon_proc) { vd_printf("OpenProcess() failed %lu", GetLastError()); return false; } ret = OpenProcessToken(winlogon_proc, TOKEN_DUPLICATE, &token); CloseHandle(winlogon_proc); if (!ret) { vd_printf("OpenProcessToken() failed %lu", GetLastError()); return false; } ret = DuplicateTokenEx(token, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &token_dup); CloseHandle(token); if (!ret) { vd_printf("DuplicateTokenEx() failed %lu", GetLastError()); return false; } ret = CreateProcessAsUser(token_dup, application_name, command_line, process_attributes, thread_attributes, inherit_handles, creation_flags, environment, current_directory, startup_info, process_information); CloseHandle(token_dup); return ret; }
TStatus SwCreateProcess(SwCreateProcessParm& parm, CAutoHandle& hProc) { TCHAR sExe[0x1000]; sExe[0] = 0; if (parm.isOur) { std::wstring sPath; GetPath(sPath, PATH_TYPE_EXE_NAME, parm.bit); wcscpy_s(sExe, sPath.c_str()); } else { wcscpy_s(sExe, parm.sExe); } TCHAR args[0x1000]; args[0] = 0; if(parm.sCmd) { wcscpy_s(args, L" "); wcscat_s(args, parm.sCmd); } BOOL Res = FALSE; bool selfElevated = IsSelfElevated(); CAutoHandle hToken; if(parm.mode == SW_CREATEPROC_DEFAULT) { if(IsWindowsVistaOrGreater()) { if (parm.admin == SW_ADMIN_ON && !selfElevated) { parm.mode = SW_CREATEPROC_SHELLEXE; } else if (parm.admin == SW_ADMIN_OFF && selfElevated) { TStatus stat = GetUnElevatedToken(hToken); if (SW_SUCCESS(stat)) { parm.hToken = hToken; parm.mode = SW_CREATEPROC_TOKEN; } else { SW_TSTATUS_LOG(stat); } } } } if (parm.mode == SW_CREATEPROC_DEFAULT) { parm.mode = SW_CREATEPROC_NORMAL; } if(parm.mode == SW_CREATEPROC_SHELLEXE) { SHELLEXECUTEINFO shExInfo = { 0 }; shExInfo.cbSize = sizeof(shExInfo); shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExInfo.hwnd = 0; shExInfo.lpVerb = (parm.admin == SW_ADMIN_ON) ? _T("runas") : 0; shExInfo.lpFile = sExe; shExInfo.lpParameters = args; shExInfo.lpDirectory = 0; shExInfo.nShow = parm.isHide ? SW_HIDE : SW_SHOW; shExInfo.hInstApp = 0; SW_WINBOOL_RET(ShellExecuteEx(&shExInfo) == TRUE); hProc = shExInfo.hProcess; } else if(parm.mode == SW_CREATEPROC_NORMAL || parm.mode == SW_CREATEPROC_AS_USER || parm.mode == SW_CREATEPROC_TOKEN) { STARTUPINFO siStartupInfo; PROCESS_INFORMATION piProcessInfo; ZeroMemory(&siStartupInfo, sizeof(siStartupInfo)); ZeroMemory(&piProcessInfo, sizeof(piProcessInfo)); siStartupInfo.cb = sizeof(siStartupInfo); if (parm.mode == SW_CREATEPROC_AS_USER) { Res = CreateProcessAsUser( parm.hToken, sExe, args, 0, 0, FALSE, CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo); } else if(parm.mode == SW_CREATEPROC_NORMAL) { Res = CreateProcess( sExe, args, 0, 0, FALSE, CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo); } else if(parm.mode == SW_CREATEPROC_TOKEN) { Res = ntapi::CreateProcessWithTokenW( parm.hToken, 0, sExe, args, 0, NULL, NULL, &siStartupInfo, &piProcessInfo); } SW_WINBOOL_RET(Res, L"Cant create proc %s %s", sExe, args); CloseHandle(piProcessInfo.hThread); hProc = piProcessInfo.hProcess; } SW_RETURN_SUCCESS; }
UINT CALaunchBOINCManager::OnExecution() { static HMODULE advapi32lib = NULL; static tSCREATEL pSCREATEL = NULL; static tSCTFL pSCTFL = NULL; static tSCLOSEL pSCLOSEL = NULL; PROCESS_INFORMATION process_info; STARTUPINFO startup_info; SAFER_LEVEL_HANDLE hSaferHandle; HANDLE hRestrictedToken; SID_IDENTIFIER_AUTHORITY siaMLA = SECURITY_MANDATORY_LABEL_AUTHORITY; PSID pSidMedium = NULL; TOKEN_MANDATORY_LABEL TIL = {0}; DWORD dwEnableVirtualization = 1; tstring strInstallDirectory; tstring strBuffer; UINT uiReturnValue = -1; FILE* f; memset(&process_info, 0, sizeof(process_info)); memset(&startup_info, 0, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); startup_info.dwFlags = STARTF_USESHOWWINDOW; startup_info.wShowWindow = SW_SHOW; f = fopen("LaunchManager.txt", "w"); if (!advapi32lib) { advapi32lib = LoadLibraryA("advapi32.dll"); if (advapi32lib) { pSCREATEL = (tSCREATEL)GetProcAddress(advapi32lib, "SaferCreateLevel"); pSCTFL = (tSCTFL)GetProcAddress(advapi32lib, "SaferComputeTokenFromLevel"); pSCLOSEL = (tSCLOSEL)GetProcAddress(advapi32lib, "SaferCloseLevel"); } } if (!pSCREATEL || !pSCTFL || !pSCLOSEL) { return ERROR_FILE_NOT_FOUND; } uiReturnValue = GetProperty( _T("INSTALLDIR"), strInstallDirectory ); if ( uiReturnValue ) return uiReturnValue; // Calculate a restricted token from the current token. if (!pSCREATEL( SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &hSaferHandle, NULL )) { fwprintf(f, _T("SaferCreateLevel retval: '%d'\n"), GetLastError()); } if (!pSCTFL( hSaferHandle, NULL, &hRestrictedToken, NULL, NULL )) { fwprintf(f, _T("SaferComputeTokenFromLevel retval: '%d'\n"), GetLastError()); } AllocateAndInitializeSid(&siaMLA, 1, SECURITY_MANDATORY_MEDIUM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidMedium); TIL.Label.Attributes = SE_GROUP_INTEGRITY; TIL.Label.Sid = pSidMedium; if (!SetTokenInformation(hRestrictedToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, &TIL, sizeof(TOKEN_MANDATORY_LABEL))) { fwprintf(f, _T("SaferComputeTokenFromLevel (TokenIntegrityLevel) retval: '%d'\n"), GetLastError()); } if (!SetTokenInformation(hRestrictedToken, (TOKEN_INFORMATION_CLASS)TokenVirtualizationEnabled, &dwEnableVirtualization, sizeof(DWORD))) { fwprintf(f, _T("SaferComputeTokenFromLevel (TokenVirtualizationEnabled) retval: '%d'\n"), GetLastError()); } strBuffer = tstring(_T("\"")) + strInstallDirectory + tstring(_T("boincmgr.exe\"")); fwprintf(f, _T("Attempting to launch boincmgr.exe\n")); fwprintf(f, _T("Launching: '%s'\n"), strBuffer.c_str()); if (CreateProcessAsUser( hRestrictedToken, NULL, (LPWSTR)strBuffer.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info, &process_info )) { fwprintf(f, _T("Success!!!\n")); CloseHandle( process_info.hProcess ); CloseHandle( process_info.hThread ); } else { fwprintf(f, _T("CreateProcessAsUser retval: '%d'\n"), GetLastError()); } strBuffer = tstring(_T("\"")) + strInstallDirectory + tstring(_T("gridrepublic.exe\"")); fwprintf(f, _T("Attempting to launch gridrepublic.exe\n")); fwprintf(f, _T("Launching: '%s'\n"), strBuffer.c_str()); if (CreateProcessAsUser( hRestrictedToken, NULL, (LPWSTR)strBuffer.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info, &process_info )) { fwprintf(f, _T("Success!!!\n")); CloseHandle( process_info.hProcess ); CloseHandle( process_info.hThread ); } else { fwprintf(f, _T("CreateProcessAsUser retval: '%d'\n"), GetLastError()); } strBuffer = tstring(_T("\"")) + strInstallDirectory + tstring(_T("charityengine.exe\"")); fwprintf(f, _T("Attempting to launch charityengine.exe\n")); fwprintf(f, _T("Launching: '%s'\n"), strBuffer.c_str()); if (CreateProcessAsUser( hRestrictedToken, NULL, (LPWSTR)strBuffer.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info, &process_info )) { fwprintf(f, _T("Success!!!\n")); CloseHandle( process_info.hProcess ); CloseHandle( process_info.hThread ); } else { fwprintf(f, _T("CreateProcessAsUser retval: '%d'\n"), GetLastError()); } strBuffer = tstring(_T("\"")) + strInstallDirectory + tstring(_T("progressthruprocessors.exe\"")); fwprintf(f, _T("Attempting to launch progressthruprocessors.exe\n")); fwprintf(f, _T("Launching: '%s'\n"), strBuffer.c_str()); if (CreateProcessAsUser( hRestrictedToken, NULL, (LPWSTR)strBuffer.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info, &process_info )) { fwprintf(f, _T("Success!!!\n")); CloseHandle( process_info.hProcess ); CloseHandle( process_info.hThread ); } else { fwprintf(f, _T("CreateProcessAsUser retval: '%d'\n"), GetLastError()); } fclose(f); CloseHandle( hRestrictedToken ); pSCLOSEL( hSaferHandle ); return ERROR_SUCCESS; }
void CMSWindowsRelauncher::mainLoop(void*) { SendSas sendSasFunc = NULL; HINSTANCE sasLib = LoadLibrary("sas.dll"); if (sasLib) { LOG((CLOG_DEBUG "found sas.dll")); sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); } DWORD sessionId = -1; bool launched = false; SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { throw XArch(new XArchEvalWindows()); } PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); while (m_running) { HANDLE sendSasEvent = 0; if (sasLib && sendSasFunc) { // can't we just create one event? seems weird creating a new // event every second... sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); } DWORD newSessionId = getSessionId(); // only enter here when id changes, and the session isn't -1, which // may mean that there is no active session. if (((newSessionId != sessionId) && (newSessionId != -1)) || m_commandChanged) { m_commandChanged = false; if (launched) { LOG((CLOG_DEBUG "closing existing process to make way for new one")); shutdownProcess(pi, 10); launched = false; } // ok, this is now the active session (forget the old one if any) sessionId = newSessionId; SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); // get the token for the user in active session, which is the // one receiving input from mouse and keyboard. HANDLE userToken = getCurrentUserToken(sessionId, &sa); if (userToken != 0) { LOG((CLOG_DEBUG "got user token to launch new process")); std::string cmd = command(); if (cmd == "") { LOG((CLOG_WARN "nothing to launch, no command specified.")); continue; } // in case reusing process info struct ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = "winsta0\\default"; si.hStdError = m_stdOutWrite; si.hStdOutput = m_stdOutWrite; si.dwFlags |= STARTF_USESTDHANDLES; LPVOID environment; BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); if (!blockRet) { LOG((CLOG_ERR "could not create environment block (error: %i)", GetLastError())); continue; } else { DWORD creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; // re-launch in current active user session BOOL createRet = CreateProcessAsUser( userToken, NULL, LPSTR(cmd.c_str()), &sa, NULL, TRUE, creationFlags, environment, NULL, &si, &pi); DestroyEnvironmentBlock(environment); CloseHandle(userToken); if (!createRet) { LOG((CLOG_ERR "could not launch (error: %i)", GetLastError())); continue; } else { LOG((CLOG_DEBUG "launched in session %i (cmd: %s)", sessionId, cmd.c_str())); launched = true; } } } } if (sendSasEvent) { // use SendSAS event to wait for next session. if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0 && sendSasFunc) { LOG((CLOG_DEBUG "calling SendSAS")); sendSasFunc(FALSE); } CloseHandle(sendSasEvent); } else { // check for session change every second. ARCH->sleep(1); } } if (launched) { LOG((CLOG_DEBUG "terminated running process on exit")); shutdownProcess(pi, 10); } }
/* * Executes a process using the supplied parameters, optionally creating a * channel through which output is filtered. * * req: TLV_TYPE_PROCESS_PATH - The executable to launch * req: TLV_TYPE_PROCESS_ARGUMENTS - The arguments to pass * req: TLV_TYPE_FLAGS - The flags to execute with */ DWORD request_sys_process_execute(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; Tlv inMemoryData; BOOL doInMemory = FALSE; PROCESS_INFORMATION pi; STARTUPINFO si; HANDLE in[2], out[2]; PCHAR path, arguments, commandLine = NULL; DWORD flags = 0, createFlags = 0; BOOL inherit = FALSE; HANDLE token, pToken; char * cpDesktop = NULL; DWORD session = 0; LPVOID pEnvironment = NULL; LPFNCREATEENVIRONMENTBLOCK lpfnCreateEnvironmentBlock = NULL; LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL; HMODULE hUserEnvLib = NULL; ProcessChannelContext * ctx = NULL; dprintf( "[PROCESS] request_sys_process_execute" ); // Initialize the startup information memset( &pi, 0, sizeof(PROCESS_INFORMATION) ); memset( &si, 0, sizeof(STARTUPINFO) ); si.cb = sizeof(STARTUPINFO); // Initialize pipe handles in[0] = NULL; in[1] = NULL; out[0] = NULL; out[1] = NULL; do { // No response? We suck. if (!response) { break; } // Get the execution arguments arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS); path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH); flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS); if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS) { doInMemory = TRUE; createFlags |= CREATE_SUSPENDED; } if (flags & PROCESS_EXECUTE_FLAG_DESKTOP) { do { cpDesktop = (char *)malloc(512); if (!cpDesktop) break; memset(cpDesktop, 0, 512); lock_acquire(remote->lock); _snprintf(cpDesktop, 512, "%s\\%s", remote->curr_station_name, remote->curr_desktop_name); lock_release(remote->lock); si.lpDesktop = cpDesktop; } while (0); } // If the remote endpoint provided arguments, combine them with the // executable to produce a command line if (path && arguments) { size_t commandLineLength = strlen(path) + strlen(arguments) + 2; if (!(commandLine = (PCHAR)malloc(commandLineLength))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } _snprintf(commandLine, commandLineLength, "%s %s", path, arguments); } else if (path) { commandLine = path; } else { result = ERROR_INVALID_PARAMETER; break; } // If the channelized flag is set, create a pipe for stdin/stdout/stderr // such that input can be directed to and from the remote endpoint if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; PoolChannelOps chops; Channel *newChannel; // Allocate the channel context if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext)))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } memset(&chops, 0, sizeof(PoolChannelOps)); // Initialize the channel operations dprintf("[PROCESS] context address 0x%p", ctx); chops.native.context = ctx; chops.native.write = process_channel_write; chops.native.close = process_channel_close; chops.native.interact = process_channel_interact; chops.read = process_channel_read; // Allocate the pool channel if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Set the channel's type to process channel_set_type(newChannel, "process"); // Allocate the stdin and stdout pipes if ((!CreatePipe(&in[0], &in[1], &sa, 0)) || (!CreatePipe(&out[0], &out[1], &sa, 0))) { channel_destroy(newChannel, NULL); newChannel = NULL; free(ctx); result = GetLastError(); break; } // Initialize the startup info to use the pipe handles si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = in[0]; si.hStdOutput = out[1]; si.hStdError = out[1]; inherit = TRUE; createFlags |= CREATE_NEW_CONSOLE; // Set the context to have the write side of stdin and the read side // of stdout ctx->pStdin = in[1]; ctx->pStdout = out[0]; // Add the channel identifier to the response packet packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); } // If the hidden flag is set, create the process hidden if (flags & PROCESS_EXECUTE_FLAG_HIDDEN) { si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; createFlags |= CREATE_NO_WINDOW; } // Should we create the process suspended? if (flags & PROCESS_EXECUTE_FLAG_SUSPENDED) createFlags |= CREATE_SUSPENDED; if (flags & PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN) { // If there is an impersonated token stored, use that one first, otherwise // try to grab the current thread token, then the process token if (remote->thread_token) { token = remote->thread_token; dprintf("[execute] using thread impersonation token"); } else if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &token)) { OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token); } dprintf("[execute] token is 0x%.8x", token); // Duplicate to make primary token (try delegation first) if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &pToken)) { if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &pToken)) { result = GetLastError(); dprintf("[execute] failed to duplicate token 0x%.8x", result); break; } } hUserEnvLib = LoadLibrary("userenv.dll"); if (NULL != hUserEnvLib) { lpfnCreateEnvironmentBlock = (LPFNCREATEENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock"); lpfnDestroyEnvironmentBlock = (LPFNDESTROYENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock"); if (lpfnCreateEnvironmentBlock && lpfnCreateEnvironmentBlock(&pEnvironment, pToken, FALSE)) { createFlags |= CREATE_UNICODE_ENVIRONMENT; dprintf("[execute] created a duplicated environment block"); } else { pEnvironment = NULL; } } // Try to execute the process with duplicated token if (!CreateProcessAsUser(pToken, NULL, commandLine, NULL, NULL, inherit, createFlags, pEnvironment, NULL, &si, &pi)) { LPCREATEPROCESSWITHTOKENW pCreateProcessWithTokenW = NULL; HANDLE hAdvapi32 = NULL; wchar_t * wcmdline = NULL; wchar_t * wdesktop = NULL; size_t size = 0; result = GetLastError(); // sf: If we hit an ERROR_PRIVILEGE_NOT_HELD failure we can fall back to CreateProcessWithTokenW but this is only // available on 2003/Vista/2008/7. CreateProcessAsUser() seems to be just borked on some systems IMHO. if (result == ERROR_PRIVILEGE_NOT_HELD) { do { hAdvapi32 = LoadLibrary("advapi32.dll"); if (!hAdvapi32) { break; } pCreateProcessWithTokenW = (LPCREATEPROCESSWITHTOKENW)GetProcAddress(hAdvapi32, "CreateProcessWithTokenW"); if (!pCreateProcessWithTokenW) { break; } // convert the multibyte inputs to wide strings (No CreateProcessWithTokenA available unfortunatly)... size = mbstowcs(NULL, commandLine, 0); if (size == (size_t)-1) { break; } wcmdline = (wchar_t *)malloc((size + 1) * sizeof(wchar_t)); mbstowcs(wcmdline, commandLine, size); if (si.lpDesktop) { size = mbstowcs(NULL, (char *)si.lpDesktop, 0); if (size != (size_t)-1) { wdesktop = (wchar_t *)malloc((size + 1) * sizeof(wchar_t)); mbstowcs(wdesktop, (char *)si.lpDesktop, size); si.lpDesktop = (LPSTR)wdesktop; } } if (!pCreateProcessWithTokenW(pToken, LOGON_NETCREDENTIALS_ONLY, NULL, wcmdline, createFlags, pEnvironment, NULL, (LPSTARTUPINFOW)&si, &pi)) { result = GetLastError(); dprintf("[execute] failed to create the new process via CreateProcessWithTokenW 0x%.8x", result); break; } result = ERROR_SUCCESS; } while (0); if (hAdvapi32) { FreeLibrary(hAdvapi32); } SAFE_FREE(wdesktop); SAFE_FREE(wcmdline); } else { dprintf("[execute] failed to create the new process via CreateProcessAsUser 0x%.8x", result); break; } } if (lpfnDestroyEnvironmentBlock && pEnvironment) { lpfnDestroyEnvironmentBlock(pEnvironment); } if (NULL != hUserEnvLib) { FreeLibrary(hUserEnvLib); } } else if (flags & PROCESS_EXECUTE_FLAG_SESSION) { typedef BOOL(WINAPI * WTSQUERYUSERTOKEN)(ULONG SessionId, PHANDLE phToken); WTSQUERYUSERTOKEN pWTSQueryUserToken = NULL; HANDLE hToken = NULL; HMODULE hWtsapi32 = NULL; BOOL bSuccess = FALSE; DWORD dwResult = ERROR_SUCCESS; do { // Note: wtsapi32!WTSQueryUserToken is not available on NT4 or 2000 so we dynamically resolve it. hWtsapi32 = LoadLibraryA("wtsapi32.dll"); session = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_SESSION); if (session_id(GetCurrentProcessId()) == session || !hWtsapi32) { if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi)) { BREAK_ON_ERROR("[PROCESS] execute in self session: CreateProcess failed"); } } else { pWTSQueryUserToken = (WTSQUERYUSERTOKEN)GetProcAddress(hWtsapi32, "WTSQueryUserToken"); if (!pWTSQueryUserToken) { BREAK_ON_ERROR("[PROCESS] execute in session: GetProcAdress WTSQueryUserToken failed"); } if (!pWTSQueryUserToken(session, &hToken)) { BREAK_ON_ERROR("[PROCESS] execute in session: WTSQueryUserToken failed"); } if (!CreateProcessAsUser(hToken, NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi)) { BREAK_ON_ERROR("[PROCESS] execute in session: CreateProcessAsUser failed"); } } } while (0); if (hWtsapi32) { FreeLibrary(hWtsapi32); } if (hToken) { CloseHandle(hToken); } result = dwResult; if (result != ERROR_SUCCESS) { break; } } else { // Try to execute the process if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi)) { result = GetLastError(); break; } } // // Do up the in memory exe execution if the user requested it // if (doInMemory) { // // Unmap the dummy executable and map in the new executable into the // target process // if (!MapNewExecutableRegionInProcess(pi.hProcess, pi.hThread, inMemoryData.buffer)) { result = GetLastError(); break; } // // Resume the thread and let it rock... // if (ResumeThread(pi.hThread) == (DWORD)-1) { result = GetLastError(); break; } } // check for failure here otherwise we can get a case where we // failed but return a process id and this will throw off the ruby side. if (result == ERROR_SUCCESS) { // if we managed to successfully create a channelized process, we need to retain // a handle to it so that we can shut it down externally if required. if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED && ctx != NULL) { dprintf("[PROCESS] started process 0x%x", pi.hProcess); ctx->pProcess = pi.hProcess; } // Add the process identifier to the response packet packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId); packet_add_tlv_qword(response, TLV_TYPE_PROCESS_HANDLE, (QWORD)pi.hProcess); CloseHandle(pi.hThread); } } while (0); // Close the read side of stdin and the write side of stdout if (in[0]) { CloseHandle(in[0]); } if (out[1]) { CloseHandle(out[1]); } // Free the command line if necessary if (path && arguments && commandLine) { free(commandLine); } if (cpDesktop) { free(cpDesktop); } packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
void BrowserFactory::InvokeClearCacheUtility(bool use_low_integrity_level) { LOG(TRACE) << "Entering BrowserFactory::InvokeClearCacheUtility"; HRESULT hr = S_OK; std::vector<wchar_t> system_path_buffer(MAX_PATH); std::vector<wchar_t> rundll_exe_path_buffer(MAX_PATH); std::vector<wchar_t> inetcpl_path_buffer(MAX_PATH); std::wstring args = L""; UINT system_path_size = ::GetSystemDirectory(&system_path_buffer[0], MAX_PATH); HANDLE process_token = NULL; HANDLE mic_token = NULL; PSID sid = NULL; bool can_create_process = true; if (!use_low_integrity_level || this->CreateLowIntegrityLevelToken(&process_token, &mic_token, &sid)) { if (0 != system_path_size && system_path_size <= static_cast<int>(system_path_buffer.size())) { if (::PathCombine(&rundll_exe_path_buffer[0], &system_path_buffer[0], RUNDLL_EXE_NAME) && ::PathCombine(&inetcpl_path_buffer[0], &system_path_buffer[0], INTERNET_CONTROL_PANEL_APPLET_NAME)) { // PathCombine will return NULL if the buffer would be exceeded. ::PathQuoteSpaces(&rundll_exe_path_buffer[0]); ::PathQuoteSpaces(&inetcpl_path_buffer[0]); args = StringUtilities::Format(CLEAR_CACHE_COMMAND_LINE_ARGS, &inetcpl_path_buffer[0], CLEAR_CACHE_OPTIONS); } else { LOG(WARN) << "Cannot combine paths to utilities required to clear cache."; can_create_process = false; } } else { LOG(WARN) << "Paths system directory exceeds MAX_PATH."; can_create_process = false; } if (can_create_process) { LOG(DEBUG) << "Launching inetcpl.cpl via rundll32.exe to clear cache"; STARTUPINFO start_info; ::ZeroMemory(&start_info, sizeof(start_info)); start_info.cb = sizeof(start_info); PROCESS_INFORMATION process_info; BOOL is_process_created = FALSE; start_info.dwFlags = STARTF_USESHOWWINDOW; start_info.wShowWindow = SW_SHOWNORMAL; std::vector<wchar_t> args_buffer(0); StringUtilities::ToBuffer(args, &args_buffer); // Create the process to run with low or medium rights if (use_low_integrity_level) { is_process_created = CreateProcessAsUser(mic_token, &rundll_exe_path_buffer[0], &args_buffer[0], NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &process_info); } else { is_process_created = CreateProcess(&rundll_exe_path_buffer[0], &args_buffer[0], NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &process_info); } if (is_process_created) { // Wait for the rundll32.exe process to exit. LOG(DEBUG) << "Waiting for rundll32.exe process to exit."; ::WaitForInputIdle(process_info.hProcess, 5000); ::WaitForSingleObject(process_info.hProcess, 30000); ::CloseHandle(process_info.hProcess); ::CloseHandle(process_info.hThread); LOG(DEBUG) << "Cache clearing complete."; } } // Close the handles opened when creating the // low integrity level token if (use_low_integrity_level) { ::CloseHandle(process_token); ::CloseHandle(mic_token); ::LocalFree(sid); } } }
HANDLE exec_with_args (const char *file_path, const char *args, HANDLE h_user_token, HANDLE *p_output_pipe) { SECURITY_ATTRIBUTES pipe_security; SECURITY_ATTRIBUTES process_security; STARTUPINFO startup_info = { 0 }; PROCESS_INFORMATION process_info = { 0 }; LPTSTR command_line = NULL; HANDLE pipe_read_handle, pipe_write_handle; BOOL success; /* Create I/O pipe - must be inheritable so it can be used by the child * process as stdout. */ pipe_security.nLength = sizeof (SECURITY_ATTRIBUTES); pipe_security.bInheritHandle = TRUE; pipe_security.lpSecurityDescriptor = NULL; success = CreatePipe (&pipe_read_handle, &pipe_write_handle, &pipe_security, 0); if (! success) { printf ("tester: Unable to create pipe: "); rpc_log_error_from_status (GetLastError ()); } process_security.nLength = sizeof (SECURITY_ATTRIBUTES); process_security.bInheritHandle = TRUE; process_security.lpSecurityDescriptor = NULL; startup_info.cb = sizeof (STARTUPINFO); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdOutput = pipe_write_handle; *p_output_pipe = pipe_read_handle; if (args != NULL) { /* Instead of separate file name and args we must use a command-line, * to avoid the C runtime getting a confusing argv[] that doesn't * contain the program filename in argv[0]. */ command_line = malloc (strlen (file_path) + strlen (args) + 2); strcpy (command_line, file_path); strcat (command_line, " "); strcat (command_line, args); file_path = NULL; } if (h_user_token == NULL) { success = CreateProcess (file_path, command_line, &process_security, &process_security, TRUE, 0, NULL, NULL, &startup_info, &process_info); } else { success = ImpersonateLoggedOnUser (h_user_token); if (! success) { printf ("Could not impersonate user: "******"tester: Unable to execute process %s: ", file_path); rpc_log_error_from_status (GetLastError ()); } if (h_user_token != NULL) { success = RevertToSelf (); if (! success) rpc_log_error_from_status (GetLastError ()); } return process_info.hProcess; }
// Process window messages LRESULT CALLBACK vncMenu::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { // This is a static method, so we don't know which instantiation we're // dealing with. We use Allen Hadden's ([email protected]) suggestion // from a newsgroup to get the pseudo-this. vncMenu *_this = helper::SafeGetWindowUserData<vncMenu>(hwnd); // Beep(100,10); // vnclog.Print(LL_INTINFO, VNCLOG("iMsg 0x%x \n"),iMsg); if (iMsg==WM_TASKBARCREATED) { if (_this->m_server->RunningFromExternalService()) { Sleep(1000); vnclog.Print(LL_INTINFO, VNCLOG("WM_TASKBARCREATED \n")); // User has changed! strcpy(_this->m_username, newuser); vnclog.Print(LL_INTINFO, VNCLOG("############## Kill vncMenu thread\n")); // Order impersonation thread killing KillTimer(hwnd,1); PostQuitMessage(0); } } switch (iMsg) { // Every five seconds, a timer message causes the icon to update case WM_TIMER: // sf@2007 - Can't get the WTS_CONSOLE_CONNECT message work properly for now.. // So use a hack instead // jdp reread some ini settings _this->m_properties.ReloadDynamicSettings(); // G_1111==true --> reconnect if (G_1111==true) { if (_this->IsIconSet==true) { vnclog.Print(LL_INTERR, VNCLOG("Add client reconnect from timer\n")); G_1111=false; PostMessage(hwnd,MENU_ADD_CLIENT_MSG,1111,1111); } } vnclog.Print(LL_INTERR, VNCLOG("########### vncMenu::TIMER TrayIcon 5s hack\n")); if (_this->m_server->RunningFromExternalService()) { strcpy(newuser,""); if (vncService::CurrentUser((char *) &newuser, sizeof(newuser))) { // Check whether the user name has changed! if (_stricmp(newuser, _this->m_username) != 0 || _this->IconFaultCounter>2) { Sleep(1000); vnclog.Print(LL_INTINFO, VNCLOG("user name has changed\n")); // User has changed! strcpy(_this->m_username, newuser); vnclog.Print(LL_INTINFO, VNCLOG("############## Kill vncMenu thread\n")); // Order impersonation thread killing PostQuitMessage(0); break; } } } // *** HACK for running servicified if (vncService::RunningAsService()) { vnclog.Print(LL_INTERR, VNCLOG("########### vncMenu::TIMER TrayIcon 5s hack call - Runningasservice\n")); // Attempt to add the icon if it's not already there _this->AddTrayIcon(); // Trigger a check of the current user PostMessage(hwnd, WM_USERCHANGED, 0, 0); } // Update the icon _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); break; // DEAL WITH NOTIFICATIONS FROM THE SERVER: case WM_SRV_CLIENT_AUTHENTICATED: case WM_SRV_CLIENT_DISCONNECT: // Adjust the icon accordingly _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); if (_this->m_server->AuthClientCount() != 0) { if (_this->m_server->RemoveWallpaperEnabled()) KillWallpaper(); if (_this->m_server->RemoveAeroEnabled()) // Moved, redundant if //PGM @ Advantig DisableAero(); // Moved, redundant if //PGM @ Advantig } else { if (_this->m_server->RemoveAeroEnabled()) // Moved, redundant if //PGM @ Advantig ResetAero(); // Moved, redundant if //PGM @ Advantig if (_this->m_server->RemoveWallpaperEnabled()) { // Added { //PGM @ Advantig Sleep(2000); // Added 2 second delay to help wallpaper restore //PGM @ Advantig RestoreWallpaper(); } //PGM @ Advantig } //PGM @ Advantig if (_this->m_server->AuthClientCount() != 0) { //PGM @ Advantig if (_this->m_server->RemoveAeroEnabled()) //PGM @ Advantig DisableAero(); //PGM @ Advantig } else { //PGM @ Advantig if (_this->m_server->RemoveAeroEnabled()) //PGM @ Advantig ResetAero(); //PGM @ Advantig } return 0; // STANDARD MESSAGE HANDLING case WM_CREATE: WM_TASKBARCREATED = RegisterWindowMessage("TaskbarCreated"); return 0; case WM_COMMAND: // User has clicked an item on the tray menu switch (LOWORD(wParam)) { case ID_DEFAULT_PROPERTIES: // Show the default properties dialog, unless it is already displayed vnclog.Print(LL_INTINFO, VNCLOG("show default properties requested\n")); _this->m_properties.ShowAdmin(TRUE, FALSE); _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); break; case ID_PROPERTIES: // Show the properties dialog, unless it is already displayed vnclog.Print(LL_INTINFO, VNCLOG("show user properties requested\n")); _this->m_propertiesPoll.Show(TRUE, TRUE); _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); break; case ID_ADMIN_PROPERTIES: // Show the properties dialog, unless it is already displayed vnclog.Print(LL_INTINFO, VNCLOG("show user properties requested\n")); _this->m_properties.ShowAdmin(TRUE, TRUE); _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); break; case ID_OUTGOING_CONN: // Connect out to a listening VNC viewer { vncConnDialog *newconn = new vncConnDialog(_this->m_server); if (newconn) { newconn->DoDialog(); // delete newconn; // NO ! Already done in vncConnDialog. } } break; case ID_KILLCLIENTS: // Disconnect all currently connected clients vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_KILLCLIENTS \n")); _this->m_server->KillAuthClients(); break; // sf@2002 case ID_LISTCLIENTS: _this->m_ListDlg.Display(); break; case ID_ABOUT: // Show the About box _this->m_about.Show(TRUE); break; case ID_VISITUSONLINE_HOMEPAGE: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) break; char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -openhomepage"); { STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD error=GetLastError(); if (ProcessInfo.hThread) CloseHandle(ProcessInfo.hThread); if (ProcessInfo.hProcess) CloseHandle(ProcessInfo.hProcess); //if (error==1314) // { // Open_homepage(); // } } } } break; case ID_VISITUSONLINE_FORUM: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) break; char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -openforum"); { STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD error=GetLastError(); if (ProcessInfo.hThread) CloseHandle(ProcessInfo.hThread); if (ProcessInfo.hProcess) CloseHandle(ProcessInfo.hProcess); //if (error==1314) // { // Open_forum(); // } } } } break; case ID_CLOSE: // User selected Close from the tray menu fShutdownOrdered=TRUE; Sleep(1000); vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); break; case ID_UNINSTALL_SERVICE: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) break; char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -uninstallhelper"); { STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; HANDLE Token=NULL; HANDLE process=NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD errorcode=GetLastError(); if (process) CloseHandle(process); if (Token) CloseHandle(Token); if (errorcode==1314) { Set_uninstall_service_as_admin(); } } fShutdownOrdered=TRUE; vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); } } break; case ID_RUNASSERVICE: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) break; char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -installhelper"); STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; HANDLE Token=NULL; HANDLE process=NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD error=GetLastError(); if (process) CloseHandle(process); if (Token) CloseHandle(Token); if (error==1314) { Set_install_service_as_admin(); } } fShutdownOrdered=TRUE; Sleep(1000); vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); } break; case ID_CLOSE_SERVICE: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) { CloseHandle(hProcess); break; } char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -stopservicehelper"); STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; HANDLE Token=NULL; HANDLE process=NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD error=GetLastError(); if (process) CloseHandle(process); if (Token) CloseHandle(Token); if (hProcess) CloseHandle(hProcess); if (error==1314) { Set_stop_service_as_admin(); } } } break; case ID_START_SERVICE: { HANDLE hProcess,hPToken; DWORD id=GetExplorerLogonPid(); if (id!=0) { hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,id); if(!OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID |TOKEN_READ|TOKEN_WRITE,&hPToken)) { CloseHandle(hProcess); break; } char dir[MAX_PATH]; char exe_file_name[MAX_PATH]; GetModuleFileName(0, exe_file_name, MAX_PATH); strcpy(dir, exe_file_name); strcat(dir, " -startservicehelper"); STARTUPINFO StartUPInfo; PROCESS_INFORMATION ProcessInfo; HANDLE Token=NULL; HANDLE process=NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); CreateProcessAsUser(hPToken,NULL,dir,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); DWORD error=GetLastError(); if (hPToken) CloseHandle(hPToken); if (process) CloseHandle(process); if (Token) CloseHandle(Token); if (hProcess) CloseHandle(hProcess); if (error==1314) { Set_start_service_as_admin(); } fShutdownOrdered=TRUE; Sleep(1000); vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); } } break; } return 0; case WM_TRAYNOTIFY: // User has clicked on the tray icon or the menu { // Get the submenu to use as a pop-up menu HMENU submenu = GetSubMenu(_this->m_hmenu, 0); // What event are we responding to, RMB click? if (lParam==WM_RBUTTONUP) { if (submenu == NULL) { vnclog.Print(LL_INTERR, VNCLOG("no submenu available\n")); return 0; } // Make the first menu item the default (bold font) SetMenuDefaultItem(submenu, 0, TRUE); // Get the current cursor position, to display the menu at POINT mouse; GetCursorPos(&mouse); // There's a "bug" // (Microsoft calls it a feature) in Windows 95 that requires calling // SetForegroundWindow. To find out more, search for Q135788 in MSDN. // SetForegroundWindow(_this->m_nid.hWnd); // Display the menu at the desired position TrackPopupMenu(submenu, 0, mouse.x, mouse.y, 0, _this->m_nid.hWnd, NULL); PostMessage(hwnd, WM_NULL, 0, 0); return 0; } // Or was there a LMB double click? if (lParam==WM_LBUTTONDBLCLK) { // double click: execute first menu item SendMessage(_this->m_nid.hWnd, WM_COMMAND, GetMenuItemID(submenu, 0), 0); } return 0; } case WM_CLOSE: // Only accept WM_CLOSE if the logged on user has AllowShutdown set if (!_this->m_properties.AllowShutdown()) { return 0; } // tnatsni Wallpaper fix if (_this->m_server->RemoveWallpaperEnabled()) RestoreWallpaper(); if (_this->m_server->RemoveAeroEnabled()) ResetAero(); vnclog.Print(LL_INTERR, VNCLOG("vncMenu WM_CLOSE call - All cleanup done\n")); Sleep(2000); DestroyWindow(hwnd); break; case WM_DESTROY: // The user wants WinVNC to quit cleanly... vnclog.Print(LL_INTINFO, VNCLOG("quitting from WM_DESTROY\n")); PostQuitMessage(0); return 0; case WM_QUERYENDSESSION: { //shutdown or reboot if((lParam & ENDSESSION_LOGOFF) != ENDSESSION_LOGOFF) { fShutdownOrdered=TRUE; Sleep(1000); vnclog.Print(LL_INTERR, VNCLOG("SHUTDOWN OS detected\n")); vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); break; } DWORD SessionID; SessionID=GetCurrentSessionID(); vnclog.Print(LL_INTERR, VNCLOG("Session ID %i\n"),SessionID); if (SessionID!=0) { fShutdownOrdered=TRUE; Sleep(1000); vnclog.Print(LL_INTERR, VNCLOG("WM_QUERYENDSESSION session!=0\n")); vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() ID_CLOSE \n")); _this->m_server->KillAuthClients(); PostMessage(hwnd, WM_CLOSE, 0, 0); } } break; case WM_ENDSESSION: vnclog.Print(LL_INTERR, VNCLOG("WM_ENDSESSION\n")); break; case WM_USERCHANGED: // The current user may have changed. { strcpy(newuser,""); if (vncService::CurrentUser((char *) &newuser, sizeof(newuser))) { vnclog.Print(LL_INTINFO, VNCLOG("############### Usernames change: old=\"%s\", new=\"%s\"\n"), _this->m_username, newuser); // Check whether the user name has changed! if (_stricmp(newuser, _this->m_username) != 0) { vnclog.Print(LL_INTINFO, VNCLOG("user name has changed\n")); // User has changed! strcpy(_this->m_username, newuser); // Redraw the tray icon and set it's state _this->DelTrayIcon(); _this->AddTrayIcon(); _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0); // We should load in the prefs for the new user if (_this->m_properties.m_fUseRegistry) { _this->m_properties.Load(TRUE); _this->m_propertiesPoll.Load(TRUE); } else { _this->m_properties.LoadFromIniFile(); _this->m_propertiesPoll.LoadFromIniFile(); } } } } return 0; // [v1.0.2-jp1 fix] Don't show IME toolbar on right click menu. case WM_INITMENU: case WM_INITMENUPOPUP: SendMessage(ImmGetDefaultIMEWnd(hwnd), WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0); return 0; default: // Deal with any of our custom message types // wa@2005 -- added support for the AutoReconnectId // removed the previous code that used 999,999 if ( iMsg == MENU_AUTO_RECONNECT_MSG ) { char szId[MAX_PATH] = {0}; UINT ret = 0; if ( lParam != NULL ) { ret = GlobalGetAtomName( (ATOM)lParam, szId, sizeof( szId ) ); GlobalDeleteAtom( (ATOM)lParam ); } _this->m_server->AutoReconnect(true); if ( ret > 0 ) _this->m_server->AutoReconnectId(szId); return 0; } if ( iMsg == MENU_REPEATER_ID_MSG ) { char szId[MAX_PATH] = {0}; UINT ret = 0; if ( lParam != NULL ) { ret = GlobalGetAtomName( (ATOM)lParam, szId, sizeof( szId ) ); GlobalDeleteAtom( (ATOM)lParam ); } _this->m_server->IdReconnect(true); if ( ret > 0 ) _this->m_server->AutoReconnectId(szId); return 0; } if (iMsg == MENU_ADD_CLIENT_MSG) { /* // sf@2005 - FTNoUserImpersonation // Dirty trick to avoid to add a new MSG... no time if (lParam == 998) { _this->m_server->FTUserImpersonation(false); return 0; } */ // Add Client message. This message includes an IP address // of a listening client, to which we should connect. //adzm 2009-06-20 - Check for special add repeater client message if (wParam == 0xFFFFFFFF && lParam == 0xFFFFFFFF) { vncConnDialog *newconn = new vncConnDialog(_this->m_server); if (newconn) { if (IDOK != newconn->DoDialog()) { if (SPECIAL_SC_PROMPT && _this->m_server->AuthClientCount() == 0 && _this->m_server->UnauthClientCount() == 0) { PostMessage(hwnd, WM_COMMAND, ID_CLOSE, 0); } } } return 0; } // If there is no IP address then show the connection dialog if (!lParam) { vncConnDialog *newconn = new vncConnDialog(_this->m_server); if (newconn) { newconn->DoDialog(); // winvnc -connect fixed //CHECH memeory leak // delete newconn; } return 0; } unsigned short nport = 0; char *nameDup = 0; char szAdrName[64]; char szId[MAX_PATH] = {0}; // sf@2003 - Values are already converted if ((_this->m_server->AutoReconnect()|| _this->m_server->IdReconnect() )&& strlen(_this->m_server->AutoReconnectAdr()) > 0) { nport = _this->m_server->AutoReconnectPort(); strcpy(szAdrName, _this->m_server->AutoReconnectAdr()); } else { // Get the IP address stringified struct in_addr address; address.S_un.S_addr = lParam; char *name = inet_ntoa(address); if (name == 0) return 0; nameDup = _strdup(name); if (nameDup == 0) return 0; strcpy(szAdrName, nameDup); // Free the duplicate name if (nameDup != 0) free(nameDup); // Get the port number nport = (unsigned short)wParam; if (nport == 0) nport = INCOMING_PORT_OFFSET; } // wa@2005 -- added support for the AutoReconnectId // (but it's not required) bool bId = ( strlen(_this->m_server->AutoReconnectId() ) > 0); if ( bId ) strcpy( szId, _this->m_server->AutoReconnectId() ); // sf@2003 // Stores the client adr/ports the first time we try to connect // This way we can call this message again later to reconnect with the same values if ((_this->m_server->AutoReconnect() || _this->m_server->IdReconnect())&& strlen(_this->m_server->AutoReconnectAdr()) == 0) { _this->m_server->AutoReconnectAdr(szAdrName); _this->m_server->AutoReconnectPort(nport); } // Attempt to create a new socket VSocket *tmpsock; tmpsock = new VSocket; if (tmpsock) { // Connect out to the specified host on the VNCviewer listen port tmpsock->Create(); if (tmpsock->Connect(szAdrName, nport)) { if ( bId ) { // wa@2005 -- added support for the AutoReconnectId // Set the ID for this client -- code taken from vncconndialog.cpp (ln:142) tmpsock->Send(szId,250); tmpsock->SetTimeout(0); // adzm 2009-07-05 - repeater IDs // Add the new client to this server // adzm 2009-08-02 _this->m_server->AddClient(tmpsock, TRUE, TRUE, 0, NULL, szId, szAdrName, nport); } else { // Add the new client to this server // adzm 2009-08-02 _this->m_server->AddClient(tmpsock, TRUE, TRUE, 0, NULL, NULL, szAdrName, nport); } } else { delete tmpsock; _this->m_server->AutoConnectRetry(); } } return 0; } // Process FileTransfer asynchronous Send Packet Message if (iMsg == FileTransferSendPacketMessage) { vncClient* pClient = (vncClient*) wParam; if (_this->m_server->IsClient(pClient)) pClient->SendFileChunk(); } // adzm 2009-07-05 - Tray icon balloon tips if (iMsg == MENU_TRAYICON_BALLOON_MSG) { omni_mutex_lock sync(_this->m_mutexTrayIcon); // adzm 2009-07-05 - Tray icon balloon tips if (_this->m_BalloonInfo) { free(_this->m_BalloonInfo); _this->m_BalloonInfo = NULL; } if (_this->m_BalloonTitle) { free(_this->m_BalloonTitle); _this->m_BalloonTitle = NULL; } char* szInfo = (char*)wParam; char* szTitle = (char*)lParam; if (szInfo && (strlen(szInfo) > 0) ) { _this->m_BalloonInfo = _strdup(szInfo); } if (szTitle && (strlen(szTitle) > 0) ) { _this->m_BalloonTitle = _strdup(szTitle); } if (szInfo) { free(szInfo); } if (szTitle) { free(szTitle); } if (_this->IsIconSet) { _this->SendTrayMsg(NIM_MODIFY, _this->m_nid.hIcon == _this->m_winvnc_icon ? FALSE : TRUE); } } } // Message not recognised return DefWindowProc(hwnd, iMsg, wParam, lParam); }
void ExecuteProcess(char *filename/*process name to execute*/) { PROCESS_INFORMATION pInfo; STARTUPINFO sInfo; ZeroMemory(&sInfo,sizeof(sInfo)); ZeroMemory(&pInfo,sizeof(pInfo)); sInfo.cb=sizeof(STARTUPINFO); sInfo.cbReserved2=0; sInfo.dwFillAttribute=0; sInfo.dwFlags=STARTF_USESHOWWINDOW; //sInfo.wShowWindow=SW_HIDE; sInfo.wShowWindow=SW_SHOW; sInfo.lpDesktop = "winsta0\\default"; sInfo.lpDesktop=NULL; sInfo.lpReserved=NULL; sInfo.lpReserved2=NULL; sInfo.lpTitle = NULL; sInfo.dwX = 0; sInfo.dwY = 0; sInfo.dwFillAttribute = 0; HANDLE hToken=NULL; HMODULE hmod = LoadLibrary("kernel32.dll"); if(hmod==NULL) { return; } WTSGETACTIVECONSOLESESSIONID lpfnWTSGetActiveConsoleSessionId = (WTSGETACTIVECONSOLESESSIONID)GetProcAddress(hmod,"WTSGetActiveConsoleSessionId"); DWORD dwSessionId=-1; // Get the Session ID of active user using // API - WTSGetActiveConsoleSessionId dwSessionId = lpfnWTSGetActiveConsoleSessionId(); FreeLibrary(hmod); hModWTS = LoadLibrary("wtsapi32.dll"); if(hModWTS !=NULL) { WTSProc = (WTSQUERYUSERTOKEN) GetProcAddress(hModWTS,"WTSQueryUserToken"); if(WTSProc!=NULL) { if(WTSProc(dwSessionId,&hToken)!=0) { if(CreateProcessAsUser(hToken,NULL,filename,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,NULL,NULL,&sInfo,&pInfo)) { CloseHandle(pInfo.hThread); CloseHandle(pInfo.hProcess); } else { //Fail } CloseHandle(hToken); } } FreeLibrary(hModWTS); hModWTS = NULL; } return; }
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env) { FILE *stream = NULL; int fno, type_len, read, mode; STARTUPINFO startup; PROCESS_INFORMATION process; SECURITY_ATTRIBUTES security; HANDLE in, out; DWORD dwCreateFlags = 0; BOOL res; process_pair *proc; char *cmd; int i; char *ptype = (char *)type; HANDLE thread_token = NULL; HANDLE token_user = NULL; BOOL asuser = TRUE; if (!type) { return NULL; } /*The following two checks can be removed once we drop XP support */ type_len = (int)strlen(type); if (type_len <1 || type_len > 2) { return NULL; } for (i=0; i < type_len; i++) { if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) { return NULL; } ptype++; } security.nLength = sizeof(SECURITY_ATTRIBUTES); security.bInheritHandle = TRUE; security.lpSecurityDescriptor = NULL; if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) { return NULL; } memset(&startup, 0, sizeof(STARTUPINFO)); memset(&process, 0, sizeof(PROCESS_INFORMATION)); startup.cb = sizeof(STARTUPINFO); startup.dwFlags = STARTF_USESTDHANDLES; startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); read = (type[0] == 'r') ? TRUE : FALSE; mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT; if (read) { in = dupHandle(in, FALSE); startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); startup.hStdOutput = out; } else { out = dupHandle(out, FALSE); startup.hStdInput = in; startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } dwCreateFlags = NORMAL_PRIORITY_CLASS; if (strcmp(sapi_module.name, "cli") != 0) { dwCreateFlags |= CREATE_NO_WINDOW; } /* Get a token with the impersonated user. */ if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) { DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user); } else { DWORD err = GetLastError(); if (err == ERROR_NO_TOKEN) { asuser = FALSE; } } cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2); if (!cmd) { return NULL; } sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command); if (asuser) { res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process); CloseHandle(token_user); } else { res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process); } free(cmd); if (!res) { return NULL; } CloseHandle(process.hThread); proc = process_get(NULL); if (read) { fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode); CloseHandle(out); } else { fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode); CloseHandle(in); } stream = _fdopen(fno, type); proc->prochnd = process.hProcess; proc->stream = stream; return stream; }
BOOL CreateInteractiveProcess(DWORD dwSessionId, PWSTR pszCommandLine, BOOL fWait, DWORD dwTimeout, DWORD *pExitCode) { DWORD dwError = ERROR_SUCCESS; HANDLE hToken = NULL; LPVOID lpvEnv = NULL; wchar_t szUserProfileDir[MAX_PATH]; DWORD cchUserProfileDir = ARRAYSIZE(szUserProfileDir); STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; DWORD dwWaitResult; // Obtain the primary access token of the logged-on user specified by the // session ID. if (!WTSQueryUserToken(dwSessionId, &hToken)) { dwError = GetLastError(); goto Cleanup; } // Run the command line in the session that we found by using the default // values for working directory and desktop. // This creates the default environment block for the user. if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) { dwError = GetLastError(); goto Cleanup; } // Retrieve the path to the root directory of the user's profile. if (!GetUserProfileDirectory(hToken, szUserProfileDir, &cchUserProfileDir)) { dwError = GetLastError(); goto Cleanup; } // Specify that the process runs in the interactive desktop. si.lpDesktop = L"winsta0\\default"; // Launch the process. if (!CreateProcessAsUser(hToken, NULL, pszCommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfileDir, &si, &pi)) { dwError = GetLastError(); goto Cleanup; } if (fWait) { // Wait for the exit of the process. dwWaitResult = WaitForSingleObject(pi.hProcess, dwTimeout); if (dwWaitResult == WAIT_OBJECT_0) { // If the process exits before timeout, get the exit code. GetExitCodeProcess(pi.hProcess, pExitCode); } else if (dwWaitResult == WAIT_TIMEOUT) { // If it times out, terminiate the process. TerminateProcess(pi.hProcess, IDTIMEOUT); *pExitCode = IDTIMEOUT; } else { dwError = GetLastError(); goto Cleanup; } } else { *pExitCode = IDASYNC; } Cleanup: // Centralized cleanup for all allocated resources. if (hToken) { CloseHandle(hToken); hToken = NULL; } if (lpvEnv) { DestroyEnvironmentBlock(lpvEnv); lpvEnv = NULL; } if (pi.hProcess) { CloseHandle(pi.hProcess); pi.hProcess = NULL; } if (pi.hThread) { CloseHandle(pi.hThread); pi.hThread = NULL; } // Set the last error if something failed in the function. if (dwError != ERROR_SUCCESS) { SetLastError(dwError); return FALSE; } else { return TRUE; } }
////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // START the app as system BOOL LaunchProcessWin(DWORD dwSessionId,bool preconnect) { BOOL bReturn = FALSE; HANDLE hToken; STARTUPINFO StartUPInfo; PVOID lpEnvironment = NULL; ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION)); StartUPInfo.wShowWindow = SW_SHOW; //StartUPInfo.lpDesktop = "Winsta0\\Winlogon"; StartUPInfo.lpDesktop = "Winsta0\\Default"; StartUPInfo.cb = sizeof(STARTUPINFO); SetTBCPrivileges(); pad2(preconnect); if ( GetSessionUserTokenWin(&hToken,dwSessionId) ) { if ( CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE) ) { SetLastError(0); if (CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo)) { counter=0; bReturn = TRUE; DWORD error=GetLastError(); #ifdef _DEBUG char szText[256]; sprintf(szText," ++++++ CreateProcessAsUser winlogon %d\n",error); OutputDebugString(szText); #endif } else { DWORD error=GetLastError(); #ifdef _DEBUG char szText[256]; sprintf(szText," ++++++ CreateProcessAsUser failed %d %d %d\n",error,kickrdp,counter); OutputDebugString(szText); #endif if (error==233 && kickrdp==1) { counter++; if (counter>3) { #ifdef _DEBUG DWORD error=GetLastError(); sprintf(szText," ++++++ error==233 win\n"); SetLastError(0); OutputDebugString(szText); #endif typedef BOOLEAN (WINAPI * pWinStationConnect) (HANDLE,ULONG,ULONG,PCWSTR,ULONG); typedef BOOL (WINAPI * pLockWorkStation)(); HMODULE hlibwinsta = LoadLibrary("winsta.dll"); HMODULE hlibuser32 = LoadLibrary("user32.dll"); pWinStationConnect WinStationConnectF=NULL; pLockWorkStation LockWorkStationF=NULL; if (hlibwinsta) { WinStationConnectF=(pWinStationConnect)GetProcAddress(hlibwinsta, "WinStationConnectW"); } if (hlibuser32) { LockWorkStationF=(pLockWorkStation)GetProcAddress(hlibuser32, "LockWorkStation"); } if (WinStationConnectF!=NULL && LockWorkStationF!=NULL) { DWORD ID=0; if (lpfnWTSGetActiveConsoleSessionId.isValid()) ID=(*lpfnWTSGetActiveConsoleSessionId)(); WinStationConnectF(0, 0, ID, L"", 0); LockWorkStationF(); } Sleep(3000); } } else if (error==233) { CreateRemoteSessionProcess(dwSessionId,true,hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo); counter=0; bReturn = TRUE; } } if (lpEnvironment) { DestroyEnvironmentBlock(lpEnvironment); } }//createenv else { SetLastError(0); if (CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo)) { counter=0; bReturn = TRUE; DWORD error=GetLastError(); #ifdef _DEBUG char szText[256]; sprintf(szText," ++++++ CreateProcessAsUser winlogon %d\n",error); OutputDebugString(szText); #endif } else { DWORD error=GetLastError(); #ifdef _DEBUG char szText[256]; sprintf(szText," ++++++ CreateProcessAsUser no env failed %d\n",error); OutputDebugString(szText); #endif //Little trick needed, FUS sometimes has an unreachable logon session. //Switch to USER B, logout user B //The logon session is then unreachable //We force the logon session on the console if (error==233 && kickrdp==1) { counter++; if (counter>3) { #ifdef _DEBUG DWORD error=GetLastError(); sprintf(szText," ++++++ error==233 win\n"); SetLastError(0); OutputDebugString(szText); #endif typedef BOOLEAN (WINAPI * pWinStationConnect) (HANDLE,ULONG,ULONG,PCWSTR,ULONG); typedef BOOL (WINAPI * pLockWorkStation)(); HMODULE hlibwinsta = LoadLibrary("winsta.dll"); HMODULE hlibuser32 = LoadLibrary("user32.dll"); pWinStationConnect WinStationConnectF=NULL; pLockWorkStation LockWorkStationF=NULL; if (hlibwinsta) { WinStationConnectF=(pWinStationConnect)GetProcAddress(hlibwinsta, "WinStationConnectW"); } if (hlibuser32) { LockWorkStationF=(pLockWorkStation)GetProcAddress(hlibuser32, "LockWorkStation"); } if (WinStationConnectF!=NULL && LockWorkStationF!=NULL) { DWORD ID=0; if (lpfnWTSGetActiveConsoleSessionId.isValid()) ID=(*lpfnWTSGetActiveConsoleSessionId)(); WinStationConnectF(0, 0, ID, L"", 0); LockWorkStationF(); } Sleep(3000); } } else if (error==233) { CreateRemoteSessionProcess(dwSessionId,true,hToken,NULL,app_path,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartUPInfo,&ProcessInfo); counter=0; bReturn = TRUE; } } } //getsession CloseHandle(hToken); } else { #ifdef _DEBUG char szText[256]; DWORD error=GetLastError(); sprintf(szText," ++++++ Getsessionusertokenwin failed %d\n",error); OutputDebugString(szText); #endif } return bReturn; }
/* * Executes a process using the supplied parameters, optionally creating a * channel through which output is filtered. * * req: TLV_TYPE_PROCESS_PATH - The executable to launch * req: TLV_TYPE_PROCESS_ARGUMENTS - The arguments to pass * req: TLV_TYPE_FLAGS - The flags to execute with */ DWORD request_sys_process_execute(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; Tlv inMemoryData; BOOL doInMemory = FALSE; #ifdef _WIN32 PROCESS_INFORMATION pi; STARTUPINFO si; HANDLE in[2], out[2]; PCHAR path, arguments, commandLine = NULL; DWORD flags = 0, createFlags = 0; BOOL inherit = FALSE; HANDLE token, pToken; char * cpDesktop = NULL; DWORD session = 0; LPVOID pEnvironment = NULL; LPFNCREATEENVIRONMENTBLOCK lpfnCreateEnvironmentBlock = NULL; LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL; HMODULE hUserEnvLib = NULL; dprintf( "[PROCESS] request_sys_process_execute" ); // Initialize the startup information memset( &pi, 0, sizeof(PROCESS_INFORMATION) ); memset( &si, 0, sizeof(STARTUPINFO) ); si.cb = sizeof(STARTUPINFO); // Initialize pipe handles in[0] = NULL; in[1] = NULL; out[0] = NULL; out[1] = NULL; do { // No response? We suck. if (!response) break; // Get the execution arguments arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS); path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH); flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS); if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS) { doInMemory = TRUE; createFlags |= CREATE_SUSPENDED; } if( flags & PROCESS_EXECUTE_FLAG_DESKTOP ) { do { cpDesktop = (char *)malloc( 512 ); if( !cpDesktop ) break; memset( cpDesktop, 0, 512 ); lock_acquire( remote->lock ); _snprintf( cpDesktop, 512, "%s\\%s", remote->cpCurrentStationName, remote->cpCurrentDesktopName ); lock_release( remote->lock ); si.lpDesktop = cpDesktop; } while( 0 ); } // If the remote endpoint provided arguments, combine them with the // executable to produce a command line if (path && arguments) { DWORD commandLineLength = strlen(path) + strlen(arguments) + 2; if (!(commandLine = (PCHAR)malloc(commandLineLength))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } _snprintf(commandLine, commandLineLength, "%s %s", path, arguments); } else if (path) commandLine = path; else { result = ERROR_INVALID_PARAMETER; break; } // If the channelized flag is set, create a pipe for stdin/stdout/stderr // such that input can be directed to and from the remote endpoint if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; ProcessChannelContext * ctx = NULL; PoolChannelOps chops; Channel *newChannel; // Allocate the channel context if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext)))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } memset(&chops, 0, sizeof(PoolChannelOps)); // Initialize the channel operations chops.native.context = ctx; chops.native.write = process_channel_write; chops.native.close = process_channel_close; chops.native.interact = process_channel_interact; chops.read = process_channel_read; // Allocate the pool channel if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Set the channel's type to process channel_set_type(newChannel, "process"); // Allocate the stdin and stdout pipes if ((!CreatePipe(&in[0], &in[1], &sa, 0)) || (!CreatePipe(&out[0], &out[1], &sa, 0))) { channel_destroy(newChannel, NULL); newChannel = NULL; free(ctx); result = GetLastError(); break; } // Initialize the startup info to use the pipe handles si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = in[0]; si.hStdOutput = out[1]; si.hStdError = out[1]; inherit = TRUE; createFlags |= CREATE_NEW_CONSOLE; // Set the context to have the write side of stdin and the read side // of stdout ctx->pStdin = in[1]; ctx->pStdout = out[0]; // Add the channel identifier to the response packet packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,channel_get_id(newChannel)); } // If the hidden flag is set, create the process hidden if (flags & PROCESS_EXECUTE_FLAG_HIDDEN) { si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; createFlags |= CREATE_NO_WINDOW; } // Should we create the process suspended? if (flags & PROCESS_EXECUTE_FLAG_SUSPENDED) createFlags |= CREATE_SUSPENDED; if (flags & PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN) { // If there is an impersonated token stored, use that one first, otherwise // try to grab the current thread token, then the process token if (remote->hThreadToken){ token = remote->hThreadToken; dprintf("[execute] using thread impersonation token"); } else if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &token)) OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token); dprintf("[execute] token is 0x%.8x", token); // Duplicate to make primary token (try delegation first) if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &pToken)) { if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &pToken)) { result = GetLastError(); dprintf("[execute] failed to duplicate token 0x%.8x", result); break; } } hUserEnvLib = LoadLibrary("userenv.dll"); if ( NULL != hUserEnvLib ) { lpfnCreateEnvironmentBlock = (LPFNCREATEENVIRONMENTBLOCK) GetProcAddress( hUserEnvLib, "CreateEnvironmentBlock" ); lpfnDestroyEnvironmentBlock = (LPFNDESTROYENVIRONMENTBLOCK) GetProcAddress( hUserEnvLib, "DestroyEnvironmentBlock" ); if (lpfnCreateEnvironmentBlock && lpfnCreateEnvironmentBlock( &pEnvironment, pToken, FALSE)) { createFlags |= CREATE_UNICODE_ENVIRONMENT; dprintf("[execute] created a duplicated environment block"); } else { pEnvironment = NULL; } } // Try to execute the process with duplicated token if( !CreateProcessAsUser( pToken, NULL, commandLine, NULL, NULL, inherit, createFlags, pEnvironment, NULL, &si, &pi ) ) { LPCREATEPROCESSWITHTOKENW pCreateProcessWithTokenW = NULL; HANDLE hAdvapi32 = NULL; wchar_t * wcmdline = NULL; wchar_t * wdesktop = NULL; int size = 0; result = GetLastError(); // sf: If we hit an ERROR_PRIVILEGE_NOT_HELD failure we can fall back to CreateProcessWithTokenW but this is only // available on 2003/Vista/2008/7. CreateProcessAsUser() seems to be just borked on some systems IMHO. if( result == ERROR_PRIVILEGE_NOT_HELD ) { do { hAdvapi32 = LoadLibrary( "advapi32.dll" ); if( !hAdvapi32 ) break; pCreateProcessWithTokenW = (LPCREATEPROCESSWITHTOKENW)GetProcAddress( hAdvapi32, "CreateProcessWithTokenW" ); if( !pCreateProcessWithTokenW ) break; // convert the multibyte inputs to wide strings (No CreateProcessWithTokenA available unfortunatly)... size = mbstowcs( NULL, commandLine, 0 ); if( size < 0 ) break; wcmdline = (wchar_t *)malloc( (size+1) * sizeof(wchar_t) ); mbstowcs( wcmdline, commandLine, size ); if( si.lpDesktop ) { size = mbstowcs( NULL, (char *)si.lpDesktop, 0 ); if( size > 0 ) { wdesktop = (wchar_t *)malloc( (size+1) * sizeof(wchar_t) ); mbstowcs( wdesktop, (char *)si.lpDesktop, size ); si.lpDesktop = (LPSTR)wdesktop; } } if( !pCreateProcessWithTokenW( pToken, LOGON_NETCREDENTIALS_ONLY, NULL, wcmdline, createFlags, pEnvironment, NULL, (LPSTARTUPINFOW)&si, &pi ) ) { result = GetLastError(); dprintf("[execute] failed to create the new process via CreateProcessWithTokenW 0x%.8x", result); break; } result = ERROR_SUCCESS; } while( 0 ); if( hAdvapi32 ) FreeLibrary( hAdvapi32 ); if( wdesktop ) free( wdesktop ); if( wcmdline ) free( wcmdline ); } else { dprintf("[execute] failed to create the new process via CreateProcessAsUser 0x%.8x", result); break; } } if( lpfnDestroyEnvironmentBlock && pEnvironment ) lpfnDestroyEnvironmentBlock( pEnvironment ); if( NULL != hUserEnvLib ) FreeLibrary( hUserEnvLib ); } else if( flags & PROCESS_EXECUTE_FLAG_SESSION ) { typedef BOOL (WINAPI * WTSQUERYUSERTOKEN)( ULONG SessionId, PHANDLE phToken ); WTSQUERYUSERTOKEN pWTSQueryUserToken = NULL; HANDLE hToken = NULL; HMODULE hWtsapi32 = NULL; BOOL bSuccess = FALSE; DWORD dwResult = ERROR_SUCCESS; do { // Note: wtsapi32!WTSQueryUserToken is not available on NT4 or 2000 so we dynamically resolve it. hWtsapi32 = LoadLibraryA( "wtsapi32.dll" ); session = packet_get_tlv_value_uint( packet, TLV_TYPE_PROCESS_SESSION ); if( session_id( GetCurrentProcessId() ) == session || !hWtsapi32 ) { if( !CreateProcess( NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi ) ) BREAK_ON_ERROR( "[PROCESS] execute in self session: CreateProcess failed" ); } else { pWTSQueryUserToken = (WTSQUERYUSERTOKEN)GetProcAddress( hWtsapi32, "WTSQueryUserToken" ); if( !pWTSQueryUserToken ) BREAK_ON_ERROR( "[PROCESS] execute in session: GetProcAdress WTSQueryUserToken failed" ); if( !pWTSQueryUserToken( session, &hToken ) ) BREAK_ON_ERROR( "[PROCESS] execute in session: WTSQueryUserToken failed" ); if( !CreateProcessAsUser( hToken, NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi ) ) BREAK_ON_ERROR( "[PROCESS] execute in session: CreateProcessAsUser failed" ); } } while( 0 ); if( hWtsapi32 ) FreeLibrary( hWtsapi32 ); if( hToken ) CloseHandle( hToken ); result = dwResult; if( result != ERROR_SUCCESS ) break; } else { // Try to execute the process if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, &si, &pi)) { result = GetLastError(); break; } } // // Do up the in memory exe execution if the user requested it // if (doInMemory) { // // Unmap the dummy executable and map in the new executable into the // target process // if (!MapNewExecutableRegionInProcess( pi.hProcess, pi.hThread, inMemoryData.buffer)) { result = GetLastError(); break; } // // Resume the thread and let it rock... // if (ResumeThread(pi.hThread) == (DWORD)-1) { result = GetLastError(); break; } } // check for failure here otherwise we can get a case where we // failed but return a process id and this will throw off the ruby side. if( result == ERROR_SUCCESS ) { // Add the process identifier to the response packet packet_add_tlv_uint(response, TLV_TYPE_PID, pi.dwProcessId); packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE,(DWORD)pi.hProcess); CloseHandle(pi.hThread); } } while (0); // Close the read side of stdin and the write side of stdout if (in[0]) CloseHandle(in[0]); if (out[1]) CloseHandle(out[1]); // Free the command line if necessary if (path && arguments && commandLine) free(commandLine); if( cpDesktop ) free( cpDesktop ); #else PCHAR path, arguments;; DWORD flags; char *argv[8], *command_line; int cl_len = 0; int in[2] = { -1, -1 }, out[2] = {-1, -1}; // file descriptors int master = -1, slave = -1; int devnull = -1; int idx, i; pid_t pid; int have_pty = -1; int hidden = (flags & PROCESS_EXECUTE_FLAG_HIDDEN); dprintf( "[PROCESS] request_sys_process_execute" ); do { // Get the execution arguments arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS); path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH); flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS); dprintf("path: %s, arguments: %s\n", path ? path : "(null)", arguments ? arguments : "(null)"); if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS) { doInMemory = TRUE; } // how to handle a single string argument line? we don't have a lexer/parser to // correctly handle stuff like quotes, etc. could dumbly parse on white space to // build arguments for execve. revert to /bin/sh -c style execution? // XXX.. don't feel like messing with it atm idx = 0; if(arguments) { // Add one for the null, one for the space cl_len = strlen(path) + strlen(arguments) + 2; command_line = malloc(cl_len); memset(command_line, 0, cl_len); strcat(command_line, path); strcat(command_line, " "); strcat(command_line, arguments); argv[idx++] = "sh"; argv[idx++] = "-c"; argv[idx++] = command_line; path = "/bin/sh"; } else { argv[idx++] = path; } argv[idx++] = NULL; //for (i = 0; i < idx; i++) { // dprintf(" argv[%d] = %s", i, argv[i]); //} // If the channelized flag is set, create a pipe for stdin/stdout/stderr // such that input can be directed to and from the remote endpoint if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { ProcessChannelContext * ctx = NULL; PoolChannelOps chops; Channel *newChannel; // Allocate the channel context if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext)))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } memset(&chops, 0, sizeof(PoolChannelOps)); // Initialize the channel operations chops.native.context = ctx; chops.native.write = process_channel_write; chops.native.close = process_channel_close; chops.native.interact = process_channel_interact; chops.read = process_channel_read; // Allocate the pool channel if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Set the channel's type to process channel_set_type(newChannel, "process"); have_pty = !try_open_pty(&master, &slave); if(have_pty) { ctx->pStdin = master; ctx->pStdout = master; } else { // fall back to pipes if there is no tty // Allocate the stdin and stdout pipes if(pipe(&in) || pipe(&out)) { channel_destroy(newChannel, NULL); newChannel = NULL; free(ctx); result = GetLastError(); break; } // Set the context to have the write side of stdin and the read side // of stdout ctx->pStdin = in[1]; ctx->pStdout = out[0]; } fcntl(ctx->pStdin, F_SETFD, fcntl(ctx->pStdin, F_GETFD) | O_NONBLOCK); fcntl(ctx->pStdout, F_SETFD, fcntl(ctx->pStdout, F_GETFD) | O_NONBLOCK); // Add the channel identifier to the response packet packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,channel_get_id(newChannel)); } else { // need to /dev/null it all if( (devnull = open("/dev/null", O_RDONLY) ) == -1) { // XXX This is possible, due to chroots etc. We could close // fd 0/1/2 and hope the program isn't buggy. result = GetLastError(); break; } } /* * We can create "hidden" processes via clone() instead of fork() * clone(child_stack, flags = CLONE_THREAD) should do the trick. Probably worth while as well. * memory / fd's etc won't be shared. linux specific syscall though. */ pid = fork(); switch(pid) { case -1: result = errno; break; case 0: if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { if(have_pty) { dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); } else { dup2(in[0], 0); dup2(out[1], 1); dup2(out[1], 2); } } else { dup2(devnull, 0); dup2(devnull, 1); dup2(devnull, 2); } for(i = 3; i < 1024; i++) close(i); if(doInMemory) { int found; Elf32_Ehdr *ehdr = (Elf32_Ehdr *)inMemoryData.buffer; Elf32_Phdr *phdr = (Elf32_Phdr *)(inMemoryData.buffer + ehdr->e_phoff); for(found = 0, i = 0; i < ehdr->e_phnum; i++, phdr++) { if(phdr->p_type == PT_LOAD) { found = 1; break; } } if(! found) return; // XXX, not too much we can do in this case ? perform_in_mem_exe(argv, environ, inMemoryData.buffer, inMemoryData.header.length, phdr->p_vaddr & ~4095, ehdr->e_entry); } else { execve(path, argv, environ); } dprintf("failed to execute program, exit(EXIT_FAILURE) time"); dprintf("doInMemory = %d, hidden = %d", doInMemory, hidden); exit(EXIT_FAILURE); default: dprintf("child pid is %d\n", pid); packet_add_tlv_uint(response, TLV_TYPE_PID, (DWORD)pid); packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE, (DWORD)pid); if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { if(have_pty) { dprintf("child channelized\n"); close(slave); } else { close(in[0]); close(out[1]); close(out[2]); } } break; } } while(0); #endif packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
HRESULT CBkServiceCallImp::Execute( const CString& strExePath, const CString& strCmdline, BOOL bShow ) { HRESULT hr = S_OK; PROCESS_INFORMATION pi; STARTUPINFO si; CProcPrivilege pri; CString strCmdLineDuplicate; LPVOID pvEnvironment = NULL; BOOL bRet = FALSE; // if ( !VerifyExePath( strExePath ) ) // { // hr = E_ACCESSDENIED; // goto Exit0; // } #ifdef ENABLE_SIGN_CHECK hr = CSignVerifer::Instance().VerifyFile( strExePath ); if ( FAILED ( hr ) ) { goto Exit0; } #endif if ( NULL == m_hToken ) { hr = E_HANDLE; goto Exit0; } memset( &si, 0, sizeof( si ) ); memset( &pi, 0, sizeof( pi ) ); si.cb = sizeof( STARTUPINFO ); si.lpDesktop = L"winsta0\\default"; hr = pri.SetPri( TRUE, SE_ASSIGNPRIMARYTOKEN_NAME ); if ( FAILED( hr ) ) { goto Exit0; } hr = pri.SetPri( TRUE, SE_INCREASE_QUOTA_NAME ); if ( FAILED( hr ) ) { goto Exit0; } hr = ::CreateEnvironmentBlock( &pvEnvironment, m_hToken, FALSE ); if ( FAILED( hr ) ) { pvEnvironment = NULL; } if ( strCmdline == L"" ) { strCmdLineDuplicate = strExePath; } else { strCmdLineDuplicate.Format(L"\"%s\" %s", strExePath, strCmdline); } bRet = CreateProcessAsUser( m_hToken, NULL, ( LPWSTR )( LPCWSTR )strCmdLineDuplicate, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, pvEnvironment, NULL, &si, &pi ); if ( !bRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); } Exit0: if ( pvEnvironment ) { ::DestroyEnvironmentBlock(pvEnvironment); pvEnvironment = NULL; } if ( bRet ) { if ( pi.hThread ) { CloseHandle( pi.hThread ); } if ( pi.hProcess ) { CloseHandle( pi.hProcess ); } } return hr; }
BOOL StartInteractiveClientProcess ( LPTSTR lpszUsername, // client to log on LPTSTR lpszDomain, // domain of client's account LPTSTR lpszPassword, // client's password LPTSTR lpCommandLine // command line to execute ) { HANDLE hToken; HDESK hdesk = NULL; HWINSTA hwinsta = NULL, hwinstaSave = NULL; PROCESS_INFORMATION pi; PSID pSid = NULL; STARTUPINFO si; BOOL bResult = FALSE; // Log the client on to the local computer. if (!LogonUser( lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken) ) { goto Cleanup; } // Save a handle to the caller's current window station. if ( (hwinstaSave = GetProcessWindowStation() ) == NULL) goto Cleanup; // Get a handle to the interactive window station. hwinsta = OpenWindowStation( _T("winsta0"), // the interactive window station FALSE, // handle is not inheritable READ_CONTROL | WRITE_DAC); // rights to read/write the DACL if (hwinsta == NULL) goto Cleanup; // To get the correct default desktop, set the caller's // window station to the interactive window station. if (!SetProcessWindowStation(hwinsta)) goto Cleanup; // Get a handle to the interactive desktop. hdesk = OpenDesktop( _T("default"), // the interactive window station 0, // no interaction with other desktop processes FALSE, // handle is not inheritable READ_CONTROL | // request the rights to read and write the DACL WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS); // Restore the caller's window station. if (!SetProcessWindowStation(hwinstaSave)) goto Cleanup; if (hdesk == NULL) goto Cleanup; // Get the SID for the client's logon session. if (!GetLogonSID(hToken, &pSid)) goto Cleanup; // Allow logon SID full access to interactive window station. if (! AddAceToWindowStation(hwinsta, pSid) ) goto Cleanup; // Allow logon SID full access to interactive desktop. if (! AddAceToDesktop(hdesk, pSid) ) goto Cleanup; // Impersonate client to ensure access to executable file. if (! ImpersonateLoggedOnUser(hToken) ) goto Cleanup; // Initialize the STARTUPINFO structure. // Specify that the process runs in the interactive desktop. ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb= sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); // Launch the process in the client's logon session. bResult = CreateProcessAsUser( hToken, // client's access token NULL, // file to execute lpCommandLine, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags NULL, // pointer to new environment block NULL, // name of current directory &si, // pointer to STARTUPINFO structure &pi // receives information about new process ); // End impersonation of client. RevertToSelf(); if (bResult && pi.hProcess != INVALID_HANDLE_VALUE) { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } if (pi.hThread != INVALID_HANDLE_VALUE) CloseHandle(pi.hThread); Cleanup: if (hwinstaSave != NULL) SetProcessWindowStation (hwinstaSave); // Free the buffer for the logon SID. if (pSid) FreeLogonSID(&pSid); // Close the handles to the interactive window station and desktop. if (hwinsta) CloseWindowStation(hwinsta); if (hdesk) CloseDesktop(hdesk); // Close the handle to the client's access token. if (hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); return bResult; }
void CMSWindowsRelauncher::mainLoop(void*) { shutdownExistingProcesses(); SendSas sendSasFunc = NULL; HINSTANCE sasLib = LoadLibrary("sas.dll"); if (sasLib) { LOG((CLOG_DEBUG "found sas.dll")); sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); } DWORD sessionId = -1; bool launched = false; SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { throw XArch(new XArchEvalWindows()); } PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); int failures = 0; while (m_running) { HANDLE sendSasEvent = 0; if (sasLib && sendSasFunc) { // can't we just create one event? seems weird creating a new // event every second... sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); } DWORD newSessionId = getSessionId(); bool running = false; if (launched) { DWORD exitCode; GetExitCodeProcess(pi.hProcess, &exitCode); running = (exitCode == STILL_ACTIVE); if (!running) { failures++; LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures)); // increasing backoff period, maximum of 10 seconds. int timeout = (failures * 2) < 10 ? (failures * 2) : 10; LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout)); ARCH->sleep(timeout); // double check, in case process started after we waited. GetExitCodeProcess(pi.hProcess, &exitCode); running = (exitCode == STILL_ACTIVE); } else { // reset failures when running. failures = 0; } } // only enter here when id changes, and the session isn't -1, which // may mean that there is no active session. bool sessionChanged = ((newSessionId != sessionId) && (newSessionId != -1)); // relaunch if it was running but has stopped unexpectedly. bool stoppedRunning = (launched && !running); if (stoppedRunning || sessionChanged || m_commandChanged) { m_commandChanged = false; if (launched) { LOG((CLOG_DEBUG "closing existing process to make way for new one")); shutdownProcess(pi.hProcess, pi.dwProcessId, 20); launched = false; } // ok, this is now the active session (forget the old one if any) sessionId = newSessionId; SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); // get the token for the user in active session, which is the // one receiving input from mouse and keyboard. HANDLE userToken = getCurrentUserToken(sessionId, &sa); if (userToken != 0) { LOG((CLOG_DEBUG "got user token to launch new process")); std::string cmd = command(); if (cmd == "") { // this appears on first launch when the user hasn't configured // anything yet, so don't show it as a warning, only show it as // debug to devs to let them know why nothing happened. LOG((CLOG_DEBUG "nothing to launch, no command specified.")); continue; } // in case reusing process info struct ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = "winsta0\\default"; si.hStdError = m_stdOutWrite; si.hStdOutput = m_stdOutWrite; si.dwFlags |= STARTF_USESTDHANDLES; LPVOID environment; BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); if (!blockRet) { LOG((CLOG_ERR "could not create environment block (error: %i)", GetLastError())); continue; } else { DWORD creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; // re-launch in current active user session LOG((CLOG_INFO "starting new process")); BOOL createRet = CreateProcessAsUser( userToken, NULL, LPSTR(cmd.c_str()), &sa, NULL, TRUE, creationFlags, environment, NULL, &si, &pi); DestroyEnvironmentBlock(environment); CloseHandle(userToken); if (!createRet) { LOG((CLOG_ERR "could not launch (error: %i)", GetLastError())); continue; } else { LOG((CLOG_DEBUG "launched in session %i (cmd: %s)", sessionId, cmd.c_str())); launched = true; } } } } if (sendSasEvent) { // use SendSAS event to wait for next session. if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0 && sendSasFunc) { LOG((CLOG_DEBUG "calling SendSAS")); sendSasFunc(FALSE); } CloseHandle(sendSasEvent); } else { // check for session change every second. ARCH->sleep(1); } } if (launched) { LOG((CLOG_DEBUG "terminated running process on exit")); shutdownProcess(pi.hProcess, pi.dwProcessId, 20); } LOG((CLOG_DEBUG "relauncher main thread finished")); }
bool StartProcess(Settings& settings, HANDLE hCmdPipe) { //Launching as one of: //1. System Account //2. Specified account (or limited account) //3. As current process DWORD gle = 0; BOOL bLoadedProfile = FALSE; PROFILEINFO profile = {0}; profile.dwSize = sizeof(profile); profile.lpUserName = (LPWSTR)(LPCWSTR)settings.user; profile.dwFlags = PI_NOUI; if(false == GetUserHandle(settings, bLoadedProfile, profile, hCmdPipe)) return false; PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; if(!BAD_HANDLE(settings.hStdErr)) { si.hStdError = settings.hStdErr; si.hStdInput = settings.hStdIn; si.hStdOutput = settings.hStdOut; si.dwFlags |= STARTF_USESTDHANDLES; #ifdef _DEBUG Log(L"DEBUG: Using redirected handles", false); #endif } #ifdef _DEBUG else Log(L"DEBUG: Not using redirected IO", false); #endif CString path = StrFormat(L"\"%s\"", settings.app); if(FALSE == settings.appArgs.IsEmpty()) { path += L" "; path += settings.appArgs; } LPCWSTR startingDir = NULL; if(FALSE == settings.workingDir.IsEmpty()) startingDir = settings.workingDir; DWORD launchGLE = 0; CleanupInteractive ci = {0}; if(settings.bInteractive || settings.bShowUIOnWinLogon) { BOOL b = PrepForInteractiveProcess(settings, &ci, settings.sessionToInteractWith); if(FALSE == b) Log(L"Failed to PrepForInteractiveProcess", true); if(NULL == si.lpDesktop) si.lpDesktop = L"WinSta0\\Default"; if(settings.bShowUIOnWinLogon) si.lpDesktop = L"winsta0\\Winlogon"; //Log(StrFormat(L"Using desktop: %s", si.lpDesktop), false); //http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in-windows-vista-and-later.aspx //indicates desktop names are case sensitive } #ifdef _DEBUG Log(StrFormat(L"DEBUG: PAExec using desktop %s", si.lpDesktop == NULL ? L"{default}" : si.lpDesktop), false); #endif DWORD dwFlags = CREATE_SUSPENDED | CREATE_NEW_CONSOLE; LPVOID pEnvironment = NULL; VERIFY(CreateEnvironmentBlock(&pEnvironment, settings.hUser, TRUE)); if(NULL != pEnvironment) dwFlags |= CREATE_UNICODE_ENVIRONMENT; #ifdef _DEBUG gle = GetLastError(); Log(L"DEBUG: CreateEnvironmentBlock", gle); #endif if(settings.bDisableFileRedirection) DisableFileRedirection(); if(settings.bRunLimited) if(false == LimitRights(settings.hUser)) return false; if(settings.bRunElevated) if(false == ElevateUserToken(settings.hUser)) return false; CString user, domain; GetUserDomain(settings.user, user, domain); #ifdef _DEBUG Log(StrFormat(L"DEBUG: U:%s D:%s P:%s bP:%d Env:%s WD:%s", user, domain, settings.password, settings.bDontLoadProfile, pEnvironment ? L"true" : L"null", startingDir ? startingDir : L"null"), false); #endif BOOL bLaunched = FALSE; if(settings.bUseSystemAccount) { Log(StrFormat(L"PAExec starting process [%s] as Local System", path), false); if(BAD_HANDLE(settings.hUser)) Log(L"Have bad user handle", true); EnablePrivilege(SE_IMPERSONATE_NAME); BOOL bImpersonated = ImpersonateLoggedOnUser(settings.hUser); if(FALSE == bImpersonated) { Log(L"Failed to impersonate", GetLastError()); _ASSERT(bImpersonated); } EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[x%X] path=[%s] flags=[x%X], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, (DWORD)settings.hUser, path, dwFlags, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif RevertToSelf(); } else { if(FALSE == settings.user.IsEmpty()) //launching as a specific user { Log(StrFormat(L"PAExec starting process [%s] as %s", path, settings.user), false); if(false == settings.bRunLimited) { bLaunched = CreateProcessWithLogonW(user, domain.IsEmpty() ? NULL : domain, settings.password, settings.bDontLoadProfile ? 0 : LOGON_WITH_PROFILE, NULL, path.LockBuffer(), dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[%s] domain=[%s] prof=[x%X] path=[%s] flags=[x%X], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, user, domain, settings.bDontLoadProfile ? 0 : LOGON_WITH_PROFILE, path, dwFlags, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif } else bLaunched = FALSE; //force to run with CreateProcessAsUser so rights can be limited //CreateProcessWithLogonW can't be called from LocalSystem on Win2003 and earlier, so LogonUser/CreateProcessAsUser must be used. Might as well try for everyone if((FALSE == bLaunched) && !BAD_HANDLE(settings.hUser)) { #ifdef _DEBUG Log(L"DEBUG: Failed CreateProcessWithLogonW - trying CreateProcessAsUser", GetLastError()); #endif EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); EnablePrivilege(SE_IMPERSONATE_NAME); BOOL bImpersonated = ImpersonateLoggedOnUser(settings.hUser); if(FALSE == bImpersonated) { Log(L"Failed to impersonate", GetLastError()); _ASSERT(bImpersonated); } bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, pEnvironment, startingDir, &si, &pi); if(0 == GetLastError()) launchGLE = 0; //mark as successful, otherwise return our original error path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[x%X] path=[%s] pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, (DWORD)settings.hUser, path, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif RevertToSelf(); } } else { Log(StrFormat(L"PAExec starting process [%s] as current user", path), false); EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); EnablePrivilege(SE_IMPERSONATE_NAME); if(NULL != settings.hUser) bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); if(FALSE == bLaunched) bLaunched = CreateProcess(NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); //#ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: path=[%s] user=[%s], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, path, settings.hUser ? L"{non-null}" : L"{null}", pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); //#endif path.UnlockBuffer(); } } if(bLaunched) { if(gbInService) Log(L"Successfully launched", false); settings.hProcess = pi.hProcess; settings.processID = pi.dwProcessId; if(false == settings.allowedProcessors.empty()) { DWORD sysMask = 0, procMask = 0; VERIFY(GetProcessAffinityMask(pi.hProcess, &procMask, &sysMask)); procMask = 0; for(std::vector<WORD>::iterator itr = settings.allowedProcessors.begin(); settings.allowedProcessors.end() != itr; itr++) { DWORD bit = 1; bit = bit << (*itr - 1); procMask |= bit & sysMask; } VERIFY(SetProcessAffinityMask(pi.hProcess, procMask)); } VERIFY(SetPriorityClass(pi.hProcess, settings.priority)); ResumeThread(pi.hThread); VERIFY(CloseHandle(pi.hThread)); } else { Log(StrFormat(L"Failed to start %s.", path), launchGLE); if((ERROR_ELEVATION_REQUIRED == launchGLE) && (false == gbInService)) Log(L"HINT: PAExec probably needs to be \"Run As Administrator\"", false); } if(ci.bPreped) CleanUpInteractiveProcess(&ci); if(settings.bDisableFileRedirection) RevertFileRedirection(); if(NULL != pEnvironment) DestroyEnvironmentBlock(pEnvironment); pEnvironment = NULL; if(bLoadedProfile) UnloadUserProfile(settings.hUser, profile.hProfile); if(!BAD_HANDLE(settings.hUser)) { CloseHandle(settings.hUser); settings.hUser = NULL; } return bLaunched ? true : false; }
eResult CSecRunAsUser::RestartAsRestricted(){ if (m_bRunningRestricted || m_bRunningAsEmule) return RES_OK; if (!LoadAPI()) return RES_FAILED; HANDLE hProcessToken = NULL; HANDLE hRestrictedToken = NULL; PTOKEN_USER pstructUserToken = NULL; try{ // get our access token from the process if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_READ, &hProcessToken)){ throw(CString(_T("Failed to retrieve access token from process"))); } // there is no easy way to check if we have already restircted token when not using the restricted sid list // so just check if we set the SANDBOX_INERT flag and hope noone else did // (which isunlikely tho because afaik you would only set it when using CreateRestirctedToken) :) DWORD dwLen = 0; DWORD dwInertFlag; if (!GetTokenInformation(hProcessToken, TokenSandBoxInert, &dwInertFlag, sizeof(dwInertFlag), &dwLen)){ throw(CString(_T("Failed to Flag-Status from AccessToken"))); } if (dwInertFlag != 0){ m_bRunningRestricted = true; throw(CString(_T("Already using a restricted Token it seems (everything is fine!)"))); } // get the user account SID to disable it in our new token dwLen = 0; while (!GetTokenInformation(hProcessToken, TokenUser, pstructUserToken, dwLen, &dwLen)){ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && pstructUserToken == NULL){ pstructUserToken = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen); continue; } throw(CString(_T("Failed to retrieve UserSID from AccessToken"))); } if (pstructUserToken == NULL) throw(CString(_T("Failed to retrieve UserSID from AccessToken"))); // disabling our primary token would make sense from an Security POV, but this would cause file acces conflicts // in the default settings (since we cannot access files we created ourself if they don't have the write flag for the group "users") // so it stays enabled for now and we only reduce privileges // create the new token if(!CreateRestrictedToken(hProcessToken, DISABLE_MAX_PRIVILEGE | SANDBOX_INERT, 0 /*disabled*/, &pstructUserToken->User, 0, NULL, 0, NULL, &hRestrictedToken ) ){ throw(CString(_T("Failed to create Restricted Token"))); } // do the starting job PROCESS_INFORMATION ProcessInfo = {0}; TCHAR szAppPath[MAX_PATH]; DWORD dwModPathLen = GetModuleFileName(NULL, szAppPath, _countof(szAppPath)); if (dwModPathLen == 0 || dwModPathLen == _countof(szAppPath)) throw CString(_T("Failed to get module file path")); CString strAppName; strAppName.Format(_T("\"%s\""),szAppPath); STARTUPINFO StartInf = {0}; StartInf.cb = sizeof(StartInf); StartInf.dwFlags = STARTF_USESHOWWINDOW; StartInf.wShowWindow = SW_NORMAL; // remove the current mutex, so that the restart emule can create its own without problems // in the rare case CreateProcessWithLogonW fails, this will allow mult. instances, but if that function fails we have other problems anyway ::CloseHandle(theApp.m_hMutexOneInstance); if(!CreateProcessAsUser(hRestrictedToken, NULL, strAppName.GetBuffer(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartInf, &ProcessInfo) ){ CString e; GetErrorMessage(GetLastError(), e, 0); throw(CString(_T("CreateProcessAsUser failed"))); } strAppName.ReleaseBuffer(); CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); // cleanup HeapFree(GetProcessHeap(), 0, (LPVOID)pstructUserToken); pstructUserToken = NULL; CloseHandle(hRestrictedToken); CloseHandle(hProcessToken); } catch(CString strError){ if (hProcessToken != NULL) CloseHandle(hProcessToken); if (hRestrictedToken != NULL) CloseHandle(hRestrictedToken); if (pstructUserToken != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pstructUserToken); theApp.QueueDebugLogLine(false, _T("SecureShellExecute exception: %s!"), strError); if (m_bRunningRestricted) return RES_OK; else return RES_FAILED; } return RES_OK_NEED_RESTART; }
/* * Create a restricted token, a job object sandbox, and execute the specified * process with it. * * Returns 0 on success, non-zero on failure, same as CreateProcess(). * * On NT4, or any other system not containing the required functions, will * launch the process under the current token without doing any modifications. * * NOTE! Job object will only work when running as a service, because it's * automatically destroyed when pg_ctl exits. */ static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service) { int r; BOOL b; STARTUPINFO si; HANDLE origToken; HANDLE restrictedToken; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_AND_ATTRIBUTES dropSids[2]; /* Functions loaded dynamically */ __CreateRestrictedToken _CreateRestrictedToken = NULL; __IsProcessInJob _IsProcessInJob = NULL; __CreateJobObject _CreateJobObject = NULL; __SetInformationJobObject _SetInformationJobObject = NULL; __AssignProcessToJobObject _AssignProcessToJobObject = NULL; __QueryInformationJobObject _QueryInformationJobObject = NULL; HANDLE Kernel32Handle; HANDLE Advapi32Handle; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); Advapi32Handle = LoadLibrary("ADVAPI32.DLL"); if (Advapi32Handle != NULL) { _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken"); } if (_CreateRestrictedToken == NULL) { /* * NT4 doesn't have CreateRestrictedToken, so just call ordinary * CreateProcess */ write_stderr("WARNING: cannot create restricted tokens on this platform\n"); if (Advapi32Handle != NULL) FreeLibrary(Advapi32Handle); return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo); } /* Open the current token to use as a base for the restricted one */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) { write_stderr("Failed to open process token: %lu\n", GetLastError()); return 0; } /* Allocate list of SIDs to remove */ ZeroMemory(&dropSids, sizeof(dropSids)); if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) || !AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid)) { write_stderr("Failed to allocate SIDs: %lu\n", GetLastError()); return 0; } b = _CreateRestrictedToken(origToken, DISABLE_MAX_PRIVILEGE, sizeof(dropSids) / sizeof(dropSids[0]), dropSids, 0, NULL, 0, NULL, &restrictedToken); FreeSid(dropSids[1].Sid); FreeSid(dropSids[0].Sid); CloseHandle(origToken); FreeLibrary(Advapi32Handle); if (!b) { write_stderr("Failed to create restricted token: %lu\n", GetLastError()); return 0; } #ifndef __CYGWIN__ AddUserToTokenDacl(restrictedToken); #endif r = CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo); Kernel32Handle = LoadLibrary("KERNEL32.DLL"); if (Kernel32Handle != NULL) { _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob"); _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA"); _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject"); _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject"); _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject"); } /* Verify that we found all functions */ if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL) { /* * IsProcessInJob() is not available on < WinXP, so there is no need * to log the error every time in that case */ OSVERSIONINFO osv; osv.dwOSVersionInfoSize = sizeof(osv); if (!GetVersionEx(&osv) || /* could not get version */ (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) || /* 5.1=xp, 5.2=2003, etc */ osv.dwMajorVersion > 5) /* anything newer should have the API */ /* * Log error if we can't get version, or if we're on WinXP/2003 or * newer */ write_stderr("WARNING: could not locate all job object functions in system API\n"); } else { BOOL inJob; if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob)) { if (!inJob) { /* * Job objects are working, and the new process isn't in one, * so we can create one safely. If any problems show up when * setting it, we're going to ignore them. */ HANDLE job; char jobname[128]; sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId); job = _CreateJobObject(NULL, jobname); if (job) { JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit; JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions; JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit; OSVERSIONINFO osv; ZeroMemory(&basicLimit, sizeof(basicLimit)); ZeroMemory(&uiRestrictions, sizeof(uiRestrictions)); ZeroMemory(&securityLimit, sizeof(securityLimit)); basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS; basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS; _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit)); uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS | JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD | JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD; if (as_service) { osv.dwOSVersionInfoSize = sizeof(osv); if (!GetVersionEx(&osv) || osv.dwMajorVersion < 6 || (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0)) { /* * On Windows 7 (and presumably later), * JOB_OBJECT_UILIMIT_HANDLES prevents us from * starting as a service. So we only enable it on * Vista and earlier (version <= 6.0) */ uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES; } } _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions)); securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN; securityLimit.JobToken = restrictedToken; _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit)); _AssignProcessToJobObject(job, processInfo->hProcess); } } } } CloseHandle(restrictedToken); ResumeThread(processInfo->hThread); FreeLibrary(Kernel32Handle); /* * We intentionally don't close the job object handle, because we want the * object to live on until pg_ctl shuts down. */ return r; }