ActivePet::~ActivePet() { m_files->ignore(m_requestFolderPath, m_dispatcher); // Kill any stray processes. if (!TerminateJobObject(m_job.get(), -1)) { printf("TerminateJobObject() failed: %d", GetLastError()); } // TODO: Change this algorithm for transient accounts. std::for_each(m_syncers.begin(), m_syncers.end(), delete_element<Syncer*>()); RegKey editables = RegKey::HKCU.open(Constants::registryPets() + L"\\" + m_petname + L"\\" + Constants::editables()); editables.removeSubKeys(); // Unload the profile. UnloadUserProfile(m_session.get(), m_profile); // Undo the changes to the winsta0 and desktop DACLs. auto_buffer<PSID> logon_sid = GetLogonSID(m_session.get()); if (NULL == logon_sid.get()) { return; } auto_close<HWINSTA, &::CloseWindowStation> winsta0(OpenWindowStation(L"winsta0", FALSE, READ_CONTROL | WRITE_DAC)); if (NULL == winsta0.get()) { printf("OpenWindowStation() failed: %d", GetLastError()); return; } if (!RemoveAceFromWindowStation(winsta0.get(), logon_sid.get())) { printf("RemoveAceFromWindowStation() failed: %d", GetLastError()); return; } auto_close<HDESK, &::CloseDesktop> desktop(OpenDesktop(L"default", 0, FALSE, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)); if (NULL == desktop.get()) { printf("OpenDesktop() failed: %d", GetLastError()); return; } if (!RemoveAceFromDesktop(desktop.get(), logon_sid.get())) { printf("AddAceToDesktop() failed: %d", GetLastError()); return; } }
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; }
ActivePet::ActivePet(wchar_t* user_password, std::wstring petname, FileEventLoop* files) : m_petname(petname), m_files(files), m_session(INVALID_HANDLE_VALUE), m_profile(INVALID_HANDLE_VALUE), m_job(CreateJobObject(NULL, NULL)), m_next_editable_name(1), m_ticks_while_invisible(0) { // Create a new logon session for the pet. std::wstring petRegistryPath = Constants::registryPets() + L"\\" + m_petname; RegKey petkey = RegKey::HKCU.open(petRegistryPath); std::wstring accountName = petkey.getValue(L"accountName"); std::wstring accountRegistryPath = Constants::registryAccounts() + L"\\" + accountName; RegKey accountKey = RegKey::HKCU.open(accountRegistryPath); std::wstring password = accountKey.getValue(L"password"); if (!LogonUser(accountName.c_str(), NULL, password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &m_session)) { printf("LogonUser() failed: %d\n", GetLastError()); return; } // Tweak the Winsta0 and desktop ACLs to allow the pet to create windows. auto_buffer<PSID> logon_sid = GetLogonSID(m_session.get()); if (NULL == logon_sid.get()) { return; } auto_close<HWINSTA, &::CloseWindowStation> winsta0(OpenWindowStation(L"winsta0", FALSE, READ_CONTROL | WRITE_DAC)); if (NULL == winsta0.get()) { printf("OpenWindowStation() failed: %d\n", GetLastError()); return; } if (!AddAceToWindowStation(winsta0.get(), logon_sid.get())) { printf("AddAceToWindowStation() failed: %d", GetLastError()); return; } auto_close<HDESK, &::CloseDesktop> desktop(OpenDesktop(L"default", 0, FALSE, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)); if (NULL == desktop.get()) { printf("OpenDesktop() failed: %d\n", GetLastError()); return; } if (!AddAceToDesktop(desktop.get(), logon_sid.get())) { printf("AddAceToDesktop() failed: %d\n", GetLastError()); return; } // Load the pet account's registry hive. wchar_t account[128] = {}; wcsncpy(account, accountName.c_str(), 128); PROFILEINFO profile = { sizeof(PROFILEINFO), 0, account }; if (!LoadUserProfile(m_session.get(), &profile)) { printf("LoadUserProfile() failed: %d\n", GetLastError()); return; } m_profile = profile.hProfile; // Initialize the pet job. if (NULL == m_job.get()) { printf("CreateJobObject() failed: %d\n", GetLastError()); return; } JOBOBJECT_BASIC_UI_RESTRICTIONS buir = { JOB_OBJECT_UILIMIT_HANDLES }; if (!SetInformationJobObject(m_job.get(), JobObjectBasicUIRestrictions, &buir, sizeof buir)) { printf("SetInformationJobObject() failed: %d\n", GetLastError()); } // Some apps fail to launch without access to the desktop window. if (!UserHandleGrantAccess(GetDesktopWindow(), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Give apps access to all the standard cursors. if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_IBEAM), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_WAIT), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_CROSS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_UPARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ICON), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENWSE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENESW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEWE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEALL), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_NO), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HAND), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_APPSTARTING), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HELP), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Setup the use records for the printers. std::set<std::wstring> servers; RegKey printers = RegKey::HKCU.open(L"Printers\\Connections"); for (int i = 0; true; ++i) { RegKey printer = printers.getSubKey(i); if (!printer.isGood()) { break; } std::wstring server = printer.getValue(L"Server"); if (servers.count(server) == 0) { std::wstring resource = server + L"\\IPC$"; auto_array<wchar_t> remote(resource.length() + 1); lstrcpy(remote.get(), resource.c_str()); USE_INFO_2 use = {}; use.ui2_remote = remote.get(); use.ui2_domainname = _wgetenv(L"USERDOMAIN"); use.ui2_username = _wgetenv(L"USERNAME");; use.ui2_password = user_password; use.ui2_asg_type = USE_WILDCARD; auto_impersonation impersonate(m_session.get()); DWORD arg_error; NET_API_STATUS error = NetUseAdd(NULL, 2, (BYTE*)&use, &arg_error); if (error) { printf("NetUseAdd() failed: %d\n", error); } else { servers.insert(server); } } } // Add the message handlers. //m_requestFolderPath = accountKey.getValue(Constants::petDataPathName()) + Constants::requestPath(); m_requestFolderPath = Constants::requestsPath(Constants::polarisDataPath(Constants::userProfilePath(accountName))); m_dispatcher = new MessageDispatcher(m_requestFolderPath); m_files->watch(m_requestFolderPath, m_dispatcher); m_dispatcher->add("sendmail",makeSendMailHandler()); // TODO m_dispatcher->add("GetOpenFileNameA", makeGetOpenFileNameAHandler(this)); m_dispatcher->add("GetOpenFileNameW", makeGetOpenFileNameWHandler(this)); m_dispatcher->add("GetClipboardData", makeGetClipboardDataHandler()); }
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; }