#include #include #include #include #include #include #include #include #include #include extern "C" { #include } #ifdef ASSERT #undef ASSERT #endif #include "users.h" #include "sfstr.h" #include "str.h" #include "mischlpr.h" #include "dbg.h" #include "tfids.h" #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0])) HRESULT _GetUserHKCU(HANDLE hThreadToken, LPCWSTR pszUserName, HKEY* phkey) { HRESULT hr; PROFILEINFO profileinfo = {0}; *phkey = NULL; profileinfo.dwSize = sizeof(profileinfo); profileinfo.dwFlags = PI_NOUI | PI_LITELOAD; profileinfo.lpUserName = (LPWSTR)pszUserName; if (LoadUserProfile(hThreadToken, &profileinfo)) { *phkey = (HKEY)(profileinfo.hProfile); hr = S_OK; TRACE(TF_USERS, TEXT("Loaded user profile")); } else { hr = S_FALSE; TRACE(TF_USERS, TEXT("FAILED to load user profile: GLE = 0x%08X"), GetLastError()); } return hr; } HRESULT _GetThreadTokenAndUserName(HANDLE* phThreadToken, LPWSTR pszUserName, DWORD cchUserName) { HRESULT hr = E_FAIL; if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, phThreadToken)) { #ifdef DEBUG // For information only DWORD dwImp = 0; DWORD dwBytesReturned; if (GetTokenInformation(*phThreadToken, TokenImpersonationLevel, &dwImp, sizeof(DWORD), &dwBytesReturned)) { switch (dwImp) { case SecurityAnonymous: TRACE(TF_USERS, TEXT("SecurityAnonymous")); break; case SecurityIdentification: TRACE(TF_USERS, TEXT("SecurityIdentification")); break; case SecurityImpersonation: TRACE(TF_USERS, TEXT("SecurityImpersonation")); break; case SecurityDelegation: TRACE(TF_USERS, TEXT("SecurityDelegation")); break; default: TRACE(TF_USERS, TEXT("Error. Unable to determine impersonation level")); break; } } else { TRACE(TF_USERS, TEXT("Unable to read impersonation level")); } #endif if (GetUserName(pszUserName, &cchUserName)) { TRACE(TF_USERS, TEXT("UserName: %s"), pszUserName); hr = S_OK; } else { TRACE(TF_USERS, TEXT("Failed to get username")); } } else { TRACE(TF_USERS, TEXT("Unable to read thread token (%d)"), GetLastError()); } return hr; } HRESULT _GetCurrentUserHKCU(HANDLE* phThreadToken, HKEY* phkey) { HRESULT hr = E_INVALIDARG; if (phkey && phThreadToken) { CImpersonateConsoleSessionUser icsu; hr = icsu.Impersonate(); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szUserName[UNLEN + 1]; hr = _GetThreadTokenAndUserName(phThreadToken, szUserName, ARRAYSIZE(szUserName)); icsu.RevertToSelf(); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _GetUserHKCU(*phThreadToken, szUserName, phkey); } } else { TRACE(TF_USERS, TEXT("WinStationQueryInformation FAILED")); } } if (FAILED(hr) || (S_FALSE == hr)) { TRACE(TF_USERS, TEXT("_GetCurrentUserHKCU FAILED or S_FALSE'D: 0x%08X"), hr); } else { TRACE(TF_USERS, TEXT("_GetCurrentUserHKCU SUCCEEDED")); } return hr; } HRESULT _CloseCurrentUserHKCU(HANDLE hThreadToken, HKEY hkey) { UnloadUserProfile(hThreadToken, hkey); CloseHandle(hThreadToken); return S_OK; } HRESULT _CoGetCallingUserHKCU(HANDLE* phThreadToken, HKEY* phkey) { HRESULT hr = E_INVALIDARG; if (phkey && phThreadToken) { CImpersonateCOMCaller icc; // You must call this before trying to open a thread token! hr = icc.Impersonate(); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szUserName[UNLEN + 1]; hr = _GetThreadTokenAndUserName(phThreadToken, szUserName, ARRAYSIZE(szUserName)); icc.RevertToSelf(); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _GetUserHKCU(*phThreadToken, szUserName, phkey); } } else { TRACE(TF_USERS, TEXT("CoImpersonateClient failed: 0x%08X"), hr); } } if (FAILED(hr) || (S_FALSE == hr)) { TRACE(TF_USERS, TEXT("_CoGetCallingUserHKCU FAILED or S_FALSE'D: 0x%08X"), hr); } else { TRACE(TF_USERS, TEXT("_CoGetCallingUserHKCU SUCCEEDED")); } return hr; } HRESULT _CoCloseCallingUserHKCU(HANDLE hThreadToken, HKEY hkey) { UnloadUserProfile(hThreadToken, hkey); CloseHandle(hThreadToken); return S_OK; } #define SESSION_MONIKER TEXT("Session:Console!clsid:") HRESULT _CoCreateInstanceInConsoleSession(REFCLSID rclsid, IUnknown* punkOuter, DWORD /*dwClsContext*/, REFIID riid, void** ppv) { IBindCtx* pbc; HRESULT hr = CreateBindCtx(0, &pbc); *ppv = NULL; if (SUCCEEDED(hr)) { WCHAR szCLSID[39]; hr = _StringFromGUID(&rclsid, szCLSID, ARRAYSIZE(szCLSID)); if (SUCCEEDED(hr)) { ULONG ulEaten; IMoniker* pmoniker; WCHAR szDisplayName[ARRAYSIZE(SESSION_MONIKER) + ARRAYSIZE(szCLSID)] = SESSION_MONIKER; // We want something like: "Session:Console!clsid:760befd0-5b0b-44d7-957e-969af35ce954" szCLSID[ARRAYSIZE(szCLSID) - 2] = 0; // Form display name string hr = SafeStrCatN(szDisplayName, szCLSID + 1, ARRAYSIZE(szDisplayName)); if (SUCCEEDED(hr)) { // Parse the name and get a moniker: hr = MkParseDisplayName(pbc, szDisplayName, &ulEaten, &pmoniker); if (SUCCEEDED(hr)) { IClassFactory* pcf; hr = pmoniker->BindToObject(pbc, NULL, IID_IClassFactory, (void**)&pcf); if (SUCCEEDED(hr)) { hr = pcf->CreateInstance(punkOuter, riid, ppv); TRACE(TF_USERS, TEXT("pcf->CreateInstance returned: hr = 0x%08X"), hr); pcf->Release(); } else { TRACE(TF_USERS, TEXT("pmoniker->BindToObject returned: hr = 0x%08X"), hr); } pmoniker->Release(); } } } else { TRACE(TF_USERS, TEXT("MkParseDisplayName returned: hr = 0x%08X"), hr); } pbc->Release(); } else { TRACE(TF_USERS, TEXT("CreateBindCtxt returned: hr = 0x%08X"), hr); } return hr; } HRESULT CImpersonateTokenBased::Impersonate() { HRESULT hr = S_FALSE; if (!_hToken) { hr = _GetToken(&_hToken); } if (SUCCEEDED(hr) && (S_FALSE != hr)) { if (ImpersonateLoggedOnUser(_hToken)) { hr = S_OK; } else { TRACE(TF_USERS, TEXT("Impersonate FAILED")); } } return hr; } HRESULT CImpersonateTokenBased::RevertToSelf() { return _RevertToSelf(); } HRESULT CImpersonateTokenBased::_RevertToSelf() { if (_hToken) { ::RevertToSelf(); CloseHandle(_hToken); _hToken = NULL; } return S_OK; } CImpersonateTokenBased::CImpersonateTokenBased() { _hToken = NULL; } CImpersonateTokenBased::~CImpersonateTokenBased() { _RevertToSelf(); } HRESULT CImpersonateConsoleSessionUser::_GetToken(HANDLE* phToken) { HRESULT hr; ULONG ulReturnLength; WINSTATIONUSERTOKEN wsUserToken = {0}; // Yep, the next casts are intentional... wsUserToken.ProcessId = (HANDLE)(DWORD_PTR)GetCurrentProcessId(); wsUserToken.ThreadId = (HANDLE)(DWORD_PTR)GetCurrentThreadId(); wsUserToken.UserToken = NULL; BOOL fActiveConsole = WinStationQueryInformation(SERVERNAME_CURRENT, USER_SHARED_DATA->ActiveConsoleId, WinStationUserToken, &wsUserToken, sizeof(wsUserToken), &ulReturnLength); if (fActiveConsole) { *phToken = wsUserToken.UserToken; hr = S_OK; } else { hr = S_FALSE; } return hr; } HRESULT CImpersonateEveryone::_GetToken(HANDLE* phToken) { HRESULT hr = S_FALSE; PSID gAdminSid; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; NTSTATUS ntstatus = RtlAllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &gAdminSid); if (NT_SUCCESS(ntstatus)) { HANDLE hTokenProcess; ntstatus = NtOpenProcessToken( NtCurrentProcess(), TOKEN_ALL_ACCESS, &hTokenProcess); if (NT_SUCCESS(ntstatus)) { TOKEN_GROUPS TokenGroups = {0}; TokenGroups.GroupCount = 1 ; TokenGroups.Groups[0].Attributes = 0 ; TokenGroups.Groups[0].Sid = gAdminSid ; ntstatus = NtFilterToken( hTokenProcess, DISABLE_MAX_PRIVILEGE, &TokenGroups, NULL, NULL, phToken); NtClose(hTokenProcess); hr = S_OK; } RtlFreeSid(gAdminSid); } return hr; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// HRESULT CImpersonateCOMCaller::Impersonate() { HRESULT hr = CoImpersonateClient(); if (SUCCEEDED(hr)) { _fImpersonating = TRUE; } else { hr = S_FALSE; } return hr; } HRESULT CImpersonateCOMCaller::RevertToSelf() { return _RevertToSelf(); } HRESULT CImpersonateCOMCaller::_RevertToSelf() { if (_fImpersonating) { CoRevertToSelf(); _fImpersonating = FALSE; } return S_OK; } CImpersonateCOMCaller::CImpersonateCOMCaller() : _fImpersonating(FALSE) {} CImpersonateCOMCaller::~CImpersonateCOMCaller() { _RevertToSelf(); } HRESULT _GiveAllowForegroundToConsoleShell() { HANDLE hImpersonationToken; DWORD dwSessionID = USER_SHARED_DATA->ActiveConsoleId; if (GetWinStationUserToken(dwSessionID, &hImpersonationToken)) { HANDLE hUserToken; if (DuplicateTokenEx(hImpersonationToken, 0, NULL, SecurityImpersonation, TokenPrimary, &hUserToken)) { STARTUPINFO StartupInfo = {0}; PROCESS_INFORMATION ProcessInfo = {0}; WCHAR szCommand[] = TEXT("rundll32.exe shell32.dll,Activate_RunDLL"); StartupInfo.cb = sizeof(StartupInfo); StartupInfo.wShowWindow = SW_SHOW; StartupInfo.lpDesktop = L"WinSta0\\Default"; if (CreateProcessAsUser(hUserToken, NULL, szCommand, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &StartupInfo, &ProcessInfo)) { CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); } CloseHandle(hUserToken); } CloseHandle(hImpersonationToken); } return S_OK; }