windows-nt/Source/XPSP1/NT/shell/services/hdsrv/lib/users.cpp
2020-09-26 16:20:57 +08:00

513 lines
12 KiB
C++

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include <winsta.h>
#include <dsgetdc.h>
#include <userenv.h>
#include <userenvp.h>
extern "C"
{
#include <syslib.h>
}
#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;
}