/*++ Copyright(c) 1995 Microsoft Corporation MODULE NAME impersn.c ABSTRACT Impersonation routines for the automatic connection service. AUTHOR Anthony Discolo (adiscolo) 04-Aug-1995 REVISION HISTORY mquinton 8/2/96 - stole this code to use in remotesp --*/ #define UNICODE #include #include #include //#include #include #include //#include #include "utils.h" #include "imperson.h" // some constant stuff for registry #define SHELL_REGKEY L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon" #define SHELL_REGVAL L"shell" #define DEFAULT_SHELL L"explorer.exe" // for remotesp dbgout #if DBG #define DBGOUT(arg) DbgPrt arg VOID DbgPrt( IN DWORD dwDbgLevel, IN PUCHAR DbgMessage, IN ... ); #else #define DBGOUT(arg) #endif // // The static information we // need to impersonate the currently // logged-in user. // HANDLE ghTokenImpersonation = NULL; // // Security attributes and descriptor // necessary for creating shareable handles. // SECURITY_ATTRIBUTES SecurityAttributeG; SECURITY_DESCRIPTOR SecurityDescriptorG; PSYSTEM_PROCESS_INFORMATION GetSystemProcessInfo() /*++ DESCRIPTION Return a block containing information about all processes currently running in the system. ARGUMENTS None. RETURN VALUE A pointer to the system process information or NULL if it could not be allocated or retrieved. --*/ { NTSTATUS status; PUCHAR pLargeBuffer; ULONG ulcbLargeBuffer = 64 * 1024; // // Get the process list. // for (;;) { pLargeBuffer = VirtualAlloc( NULL, ulcbLargeBuffer, MEM_COMMIT, PAGE_READWRITE); if (pLargeBuffer == NULL) { LOG((TL_ERROR, "GetSystemProcessInfo: VirtualAlloc failed (status=0x%x)", status)); return NULL; } status = NtQuerySystemInformation( SystemProcessInformation, pLargeBuffer, ulcbLargeBuffer, NULL); if (status == STATUS_SUCCESS) break; if (status == STATUS_INFO_LENGTH_MISMATCH) { VirtualFree(pLargeBuffer, 0, MEM_RELEASE); ulcbLargeBuffer += 8192; LOG((TL_INFO, "GetSystemProcesInfo: enlarging buffer to %d", ulcbLargeBuffer)); } } return (PSYSTEM_PROCESS_INFORMATION)pLargeBuffer; } // GetSystemProcessInfo PSYSTEM_PROCESS_INFORMATION FindProcessByName( IN PSYSTEM_PROCESS_INFORMATION pProcessInfo, IN LPTSTR lpExeName ) /*++ DESCRIPTION Given a pointer returned by GetSystemProcessInfo(), find a process by name. ARGUMENTS pProcessInfo: a pointer returned by GetSystemProcessInfo(). lpExeName: a pointer to a Unicode string containing the process to be found. RETURN VALUE A pointer to the process information for the supplied process or NULL if it could not be found. --*/ { PUCHAR pLargeBuffer = (PUCHAR)pProcessInfo; ULONG ulTotalOffset = 0; // // Look in the process list for lpExeName. // for (;;) { if (pProcessInfo->ImageName.Buffer != NULL) { //DBGOUT(( // 3, // "FindProcessByName: process: %S (%d)", // pProcessInfo->ImageName.Buffer, // pProcessInfo->UniqueProcessId // )); if (!_wcsicmp(pProcessInfo->ImageName.Buffer, lpExeName)) { return pProcessInfo; } } // // Increment offset to next process information block. // if (!pProcessInfo->NextEntryOffset) { break; } ulTotalOffset += pProcessInfo->NextEntryOffset; pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pLargeBuffer[ulTotalOffset]; } return NULL; } // FindProcessByName VOID FreeSystemProcessInfo( IN PSYSTEM_PROCESS_INFORMATION pProcessInfo ) /*++ DESCRIPTION Free a buffer returned by GetSystemProcessInfo(). ARGUMENTS pProcessInfo: the pointer returned by GetSystemProcessInfo(). RETURN VALUE None. --*/ { VirtualFree((PUCHAR)pProcessInfo, 0, MEM_RELEASE); } // FreeSystemProcessInfo BOOLEAN SetProcessImpersonationToken( HANDLE hProcess ) { NTSTATUS status; BOOL fDuplicated = FALSE; HANDLE hThread, hToken; static lCookie = 0; // // Open the impersonation token for the // process we want to impersonate. // // Note: we use InterlockedExchange as an inexpensive mutex // while (InterlockedExchange (&lCookie, 1) != 0) { Sleep (50); } if (ghTokenImpersonation == NULL) { if (!OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hToken)) { InterlockedExchange (&lCookie, 0); LOG(( TL_ERROR, "SetProcessImpersonationToken: OpenProcessToken " \ "failed, err=%d", GetLastError() )); return FALSE; } // // Duplicate the impersonation token. // fDuplicated = DuplicateToken( hToken, TokenImpersonation, &ghTokenImpersonation); if (!fDuplicated) { InterlockedExchange (&lCookie, 0); LOG(( TL_ERROR, "SetProcessImpersonationToken: NtSetInformationThread " \ "failed, err=%d", GetLastError() )); return FALSE; } } InterlockedExchange (&lCookie, 0); // // Set the impersonation token on the current // thread. We are now running in the same // security context as the supplied process. // hThread = NtCurrentThread(); status = NtSetInformationThread( hThread, ThreadImpersonationToken, (PVOID)&ghTokenImpersonation, sizeof (ghTokenImpersonation)); if (status != STATUS_SUCCESS) { LOG((TL_ERROR, "SetProcessImpersonationToken: NtSetInformationThread failed (error=%d)", GetLastError())); } if (fDuplicated) { CloseHandle(hToken); CloseHandle(hThread); } return (status == STATUS_SUCCESS); } // SetProcessImpersonationToken VOID ClearImpersonationToken() { // // Clear the impersonation token on the current // thread. We are now running in LocalSystem // security context. // if (!SetThreadToken(NULL, NULL)) { LOG((TL_ERROR, "ClearImpersonationToken: SetThreadToken failed (error=%d)", GetLastError())); } } // ClearImpersonationToken BOOLEAN GetCurrentlyLoggedOnUser( HANDLE *phProcess ) { BOOLEAN fSuccess = FALSE; HKEY hkey; DWORD dwType; DWORD dwDisp; WCHAR szShell[512]; PSYSTEM_PROCESS_INFORMATION pSystemInfo, pProcessInfo; PWCHAR psz; DWORD dwSize = sizeof (szShell); NTSTATUS status; HANDLE hProcess = NULL; // // Get the shell process name. We will look for this // to find out who the currently logged-on user is. // Create a unicode string that describes this name. // wcscpy (szShell, DEFAULT_SHELL); if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, SHELL_REGKEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp) == ERROR_SUCCESS) { if (RegQueryValueEx( hkey, SHELL_REGVAL, NULL, &dwType, (PBYTE)&szShell, &dwSize) == ERROR_SUCCESS) { // // Remove parameters from command line. // psz = szShell; while (*psz != L' ' && *psz != L'\0') psz++; *psz = L'\0'; } RegCloseKey(hkey); } LOG((TL_INFO, "ImpersonateCurrentlyLoggedInUser: shell is %S", &szShell)); // // Get the process list. // pSystemInfo = GetSystemProcessInfo(); // // See if szShell is running. // pProcessInfo = pSystemInfo ? FindProcessByName(pSystemInfo, (LPTSTR)&szShell) : NULL; if (pProcessInfo != NULL) { HANDLE hToken; // // Open the process. // hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, (DWORD) ((ULONG_PTR) pProcessInfo->UniqueProcessId) ); if (hProcess == NULL) { LOG((TL_ERROR, "ImpersonateCurrentlyLoggedInUser: OpenProcess(x%x) failed (dwErr=%d)", pProcessInfo->UniqueProcessId, GetLastError())); } fSuccess = (hProcess != NULL); } // // Free resources. // if (pSystemInfo) { FreeSystemProcessInfo(pSystemInfo); } // // Return process handle. // *phProcess = hProcess; return fSuccess; } // GetCurrentlyLoggedOnUser VOID RevertImpersonation() /*++ DESCRIPTION Close all open handles associated with the logged-in user who has just logged out. ARGUMENTS None. RETURN VALUE None. --*/ { CloseHandle (ghTokenImpersonation); ghTokenImpersonation = NULL; } // RevertImpersonation