You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1169 lines
28 KiB
1169 lines
28 KiB
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <npapi.h>
|
|
#include <acd.h>
|
|
#include <debug.h>
|
|
|
|
#include "reg.h"
|
|
#include "misc.h"
|
|
#include "process.h"
|
|
#include "imperson.h"
|
|
#include "mprlog.h"
|
|
#include "rtutils.h"
|
|
#include "rasman.h"
|
|
|
|
extern HANDLE g_hLogEvent;
|
|
|
|
extern DWORD g_dwCritSecFlags;
|
|
|
|
DWORD
|
|
LoadGroupMemberships();
|
|
|
|
//
|
|
// The static information we
|
|
// need to impersonate the currently
|
|
// logged-in user.
|
|
//
|
|
IMPERSONATION_INFO ImpersonationInfoG;
|
|
|
|
//
|
|
// TRUE if ImpersonationInfoG has been initialized
|
|
//
|
|
|
|
BOOLEAN ImpersonationInfoInitializedG = FALSE;
|
|
|
|
//
|
|
// Security attributes and descriptor
|
|
// necessary for creating shareable handles.
|
|
//
|
|
SECURITY_ATTRIBUTES SecurityAttributeG;
|
|
SECURITY_DESCRIPTOR SecurityDescriptorG;
|
|
|
|
HKEY hkeyCUG = NULL;
|
|
|
|
#ifdef notdef
|
|
|
|
BOOLEAN
|
|
InteractiveSession()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Determine whether the active process is owned by the
|
|
currently logged-in user.
|
|
|
|
ARGUMENTS
|
|
None.
|
|
|
|
RETURNS
|
|
TRUE if it is, FALSE if it isn't.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE hToken;
|
|
BOOLEAN bStatus;
|
|
ULONG ulInfoLength;
|
|
PTOKEN_GROUPS pTokenGroupList;
|
|
PTOKEN_USER pTokenUser;
|
|
ULONG ulGroupIndex;
|
|
BOOLEAN bFoundInteractive = FALSE;
|
|
PSID InteractiveSid;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
static BOOLEAN fIsInteractiveSession = 0xffff;
|
|
|
|
#if 0
|
|
//
|
|
// Return the previous value of this function
|
|
// if we're called multiple times?! Doesn't
|
|
// GetCurrentProcess() return different values?
|
|
//
|
|
if (fIsInteractiveSession != 0xffff) {
|
|
return fIsInteractiveSession;
|
|
}
|
|
#endif
|
|
|
|
bStatus = AllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
1,
|
|
SECURITY_INTERACTIVE_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&InteractiveSid);
|
|
if (!bStatus) {
|
|
RASAUTO_TRACE("InteractiveSession: AllocateAndInitializeSid failed");
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
|
|
RASAUTO_TRACE("InteractiveSession: OpenProcessToken failed");
|
|
FreeSid(InteractiveSid);
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
//
|
|
// Get a list of groups in the token.
|
|
//
|
|
GetTokenInformation(
|
|
hToken,
|
|
TokenGroups,
|
|
NULL,
|
|
0,
|
|
&ulInfoLength);
|
|
pTokenGroupList = (PTOKEN_GROUPS)LocalAlloc(LPTR, ulInfoLength);
|
|
if (pTokenGroupList == NULL) {
|
|
RASAUTO_TRACE("InteractiveSession: LocalAlloc failed");
|
|
FreeSid(InteractiveSid);
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
bStatus = GetTokenInformation(
|
|
hToken,
|
|
TokenGroups,
|
|
pTokenGroupList,
|
|
ulInfoLength,
|
|
&ulInfoLength);
|
|
if (!bStatus) {
|
|
RASAUTO_TRACE("InteractiveSession: GetTokenInformation failed");
|
|
FreeSid(InteractiveSid);
|
|
LocalFree(pTokenGroupList);
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
//
|
|
// Search group list for admin alias. If we
|
|
// find a match, it most certainly is an
|
|
// interactive process.
|
|
//
|
|
bFoundInteractive = FALSE;
|
|
for (ulGroupIndex=0; ulGroupIndex < pTokenGroupList->GroupCount;
|
|
ulGroupIndex++)
|
|
{
|
|
if (EqualSid(
|
|
pTokenGroupList->Groups[ulGroupIndex].Sid,
|
|
InteractiveSid))
|
|
{
|
|
bFoundInteractive = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFoundInteractive) {
|
|
//
|
|
// If we haven't found a match,
|
|
// query and check the user ID.
|
|
//
|
|
GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&ulInfoLength);
|
|
pTokenUser = LocalAlloc(LPTR, ulInfoLength);
|
|
if (pTokenUser == NULL) {
|
|
RASAUTO_TRACE("InteractiveSession: LocalAlloc failed");
|
|
FreeSid(InteractiveSid);
|
|
LocalFree(pTokenGroupList);
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
bStatus = GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
pTokenUser,
|
|
ulInfoLength,
|
|
&ulInfoLength);
|
|
if (!bStatus) {
|
|
RASAUTO_TRACE("InteractiveSession: GetTokenInformation failed");
|
|
FreeSid(InteractiveSid);
|
|
LocalFree(pTokenGroupList);
|
|
LocalFree(pTokenUser);
|
|
return (fIsInteractiveSession = FALSE);
|
|
}
|
|
if (EqualSid(pTokenUser->User.Sid, InteractiveSid))
|
|
fIsInteractiveSession = TRUE;
|
|
LocalFree(pTokenUser);
|
|
}
|
|
FreeSid(InteractiveSid);
|
|
LocalFree(pTokenGroupList);
|
|
|
|
return (fIsInteractiveSession = bFoundInteractive);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SetProcessImpersonationToken(
|
|
HANDLE hProcess
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE hThread,
|
|
hToken = NULL;
|
|
|
|
|
|
//
|
|
// Open the impersonation token for the
|
|
// process we want to impersonate.
|
|
//
|
|
if (ImpersonationInfoG.hTokenImpersonation == NULL)
|
|
{
|
|
if (!OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_ALL_ACCESS,
|
|
&hToken))
|
|
{
|
|
RASAUTO_TRACE1(
|
|
"SetProcessImpersonationToken: OpenProcessToken failed (dwErr=%d)",
|
|
GetLastError());
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Duplicate the impersonation token.
|
|
//
|
|
if(!DuplicateToken(
|
|
hToken,
|
|
TokenImpersonation,
|
|
&ImpersonationInfoG.hTokenImpersonation))
|
|
{
|
|
RASAUTO_TRACE1(
|
|
"SetProcessImpersonationToken: NtSetInformationThread failed (error=%d)",
|
|
GetLastError());
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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)&ImpersonationInfoG.hTokenImpersonation,
|
|
sizeof (ImpersonationInfoG.hTokenImpersonation));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
RASAUTO_TRACE1(
|
|
"SetProcessImpersonationToken: NtSetInformationThread failed (error=%d)",
|
|
GetLastError());
|
|
}
|
|
|
|
if(NULL != hToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
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)) {
|
|
DWORD retcode = GetLastError();
|
|
|
|
RASAUTO_TRACE1(
|
|
"ClearImpersonationToken: SetThreadToken failed (error=%d)",
|
|
retcode);
|
|
|
|
//
|
|
// Event log that thread failed to revert.
|
|
//
|
|
RouterLogWarning(
|
|
g_hLogEvent,
|
|
ROUTERLOG_CANNOT_REVERT_IMPERSONATION,
|
|
0, NULL, retcode) ;
|
|
}
|
|
} // ClearImpersonationToken
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SetPrivilege(
|
|
HANDLE hToken,
|
|
LPCTSTR Privilege,
|
|
BOOLEAN fEnable
|
|
)
|
|
{
|
|
TOKEN_PRIVILEGES tp;
|
|
LUID luid;
|
|
TOKEN_PRIVILEGES tpPrevious;
|
|
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
|
|
|
|
if (!LookupPrivilegeValue(NULL, Privilege, &luid))
|
|
return FALSE;
|
|
|
|
//
|
|
// First pass. Get current privilege setting.
|
|
//
|
|
tp.PrivilegeCount = 1;
|
|
tp.Privileges[0].Luid = luid;
|
|
tp.Privileges[0].Attributes = 0;
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tp,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
&tpPrevious,
|
|
&cbPrevious);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
//
|
|
// Second pass. Set privilege based on previous setting
|
|
//
|
|
tpPrevious.PrivilegeCount = 1;
|
|
tpPrevious.Privileges[0].Luid = luid;
|
|
|
|
if (fEnable)
|
|
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
|
|
else {
|
|
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
|
|
tpPrevious.Privileges[0].Attributes);
|
|
}
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tpPrevious,
|
|
cbPrevious,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
} // SetPrivilege
|
|
|
|
|
|
|
|
BOOLEAN
|
|
GetCurrentlyLoggedOnUser(
|
|
HANDLE *phProcess
|
|
)
|
|
{
|
|
BOOLEAN fSuccess = FALSE;
|
|
HKEY hkey;
|
|
DWORD dwErr, dwType;
|
|
DWORD dwDisp;
|
|
WCHAR *pszShell = NULL, **pszShellArray = NULL;
|
|
PSYSTEM_PROCESS_INFORMATION pSystemInfo, pProcessInfo;
|
|
PWCHAR psz, pszStart;
|
|
DWORD i, dwSize, dwcCommands;
|
|
NTSTATUS status;
|
|
HANDLE hProcess = NULL;
|
|
DWORD dwPid = 0;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
if (RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
SHELL_REGKEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hkey,
|
|
&dwDisp) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = 0;
|
|
if (RegQueryValueEx(
|
|
hkey,
|
|
SHELL_REGVAL,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize) == ERROR_SUCCESS)
|
|
{
|
|
pszShell = (PWCHAR)LocalAlloc(LPTR, dwSize + sizeof (WCHAR));
|
|
if (pszShell == NULL) {
|
|
RegCloseKey(hkey);
|
|
return FALSE;
|
|
}
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
SHELL_REGVAL,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pszShell,
|
|
&dwSize);
|
|
RegCloseKey(hkey);
|
|
if (dwErr != ERROR_SUCCESS || dwType != REG_SZ) {
|
|
LocalFree(pszShell);
|
|
pszShell = NULL;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// If no shell was found, use DEFAULT_SHELL.
|
|
//
|
|
if (pszShell == NULL) {
|
|
pszShell = (PWCHAR)LocalAlloc(
|
|
LPTR,
|
|
(lstrlen(DEFAULT_SHELL) + 1) * sizeof (WCHAR));
|
|
if (pszShell == NULL)
|
|
return FALSE;
|
|
lstrcpy(pszShell, DEFAULT_SHELL);
|
|
}
|
|
RASAUTO_TRACE1("ImpersonateCurrentlyLoggedInUser: pszShell is %S", pszShell);
|
|
//
|
|
// This string can be a comma separated list,
|
|
// so we need to parse it into a list of commands.
|
|
//
|
|
dwcCommands = 1;
|
|
for (psz = pszShell; *psz != L'\0'; psz++) {
|
|
if (*psz == L',')
|
|
dwcCommands++;
|
|
}
|
|
//
|
|
// Allocate the list of string pointers.
|
|
//
|
|
pszShellArray = LocalAlloc(LPTR, sizeof (PWCHAR) * dwcCommands);
|
|
if (pszShellArray == NULL) {
|
|
LocalFree(pszShell);
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Ignore any arguments from the command line.
|
|
//
|
|
dwcCommands = 0;
|
|
psz = pszShell;
|
|
pszStart = NULL;
|
|
for (;;) {
|
|
if (*psz == L'\0') {
|
|
if (pszStart != NULL)
|
|
pszShellArray[dwcCommands++] = pszStart;
|
|
break;
|
|
}
|
|
else if (*psz == L',') {
|
|
if (pszStart != NULL)
|
|
pszShellArray[dwcCommands++] = pszStart;
|
|
*psz = L'\0';
|
|
pszStart = NULL;
|
|
}
|
|
else if (*psz == L' ') {
|
|
if (pszStart != NULL)
|
|
*psz = L'\0';
|
|
}
|
|
else {
|
|
if (pszStart == NULL)
|
|
pszStart = psz;
|
|
}
|
|
psz++;
|
|
}
|
|
for (i = 0; i < dwcCommands; i++) {
|
|
RASAUTO_TRACE2(
|
|
"ImpersonateCurrentlyLoggedInUser: pszShellArray[%d] is %S",
|
|
i,
|
|
pszShellArray[i]);
|
|
}
|
|
//
|
|
// Get the process list.
|
|
//
|
|
pSystemInfo = GetSystemProcessInfo();
|
|
|
|
if(NULL == pSystemInfo)
|
|
{
|
|
LocalFree(pszShell);
|
|
LocalFree(pszShellArray);
|
|
return FALSE;
|
|
}
|
|
|
|
while(TRUE)
|
|
{
|
|
//
|
|
// See if any of the processes are running.
|
|
//
|
|
pProcessInfo =
|
|
FindProcessByNameList(
|
|
pSystemInfo,
|
|
pszShellArray,
|
|
dwcCommands,
|
|
dwPid,
|
|
ImpersonationInfoG.fSessionInitialized,
|
|
ImpersonationInfoG.dwCurSessionId);
|
|
//
|
|
// Open the process token if we've found a match.
|
|
//
|
|
if (pProcessInfo != NULL)
|
|
{
|
|
HANDLE hToken;
|
|
|
|
//
|
|
// Open the process.
|
|
//
|
|
hProcess = OpenProcess(
|
|
PROCESS_ALL_ACCESS,
|
|
FALSE,
|
|
PtrToUlong(pProcessInfo->UniqueProcessId));
|
|
if (hProcess == NULL)
|
|
{
|
|
RASAUTO_TRACE2(
|
|
"ImpersonateCurrentlyLoggedInUser: OpenProcess(%d) failed (dwErr=%d)",
|
|
PtrToUlong(pProcessInfo->UniqueProcessId),
|
|
GetLastError());
|
|
|
|
dwPid = PtrToUlong(pProcessInfo->UniqueProcessId);
|
|
}
|
|
else
|
|
{
|
|
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef notdef
|
|
done:
|
|
#endif
|
|
//
|
|
// Free resources.
|
|
//
|
|
FreeSystemProcessInfo(pSystemInfo);
|
|
if (pszShell != NULL)
|
|
LocalFree(pszShell);
|
|
if (pszShellArray != NULL)
|
|
LocalFree(pszShellArray);
|
|
//
|
|
// Return process handle.
|
|
//
|
|
*phProcess = hProcess;
|
|
|
|
return fSuccess;
|
|
} // GetCurrentlyLoggedOnUser
|
|
|
|
DWORD
|
|
SetCurrentLoginSession(
|
|
IN DWORD dwSessionId)
|
|
{
|
|
RASAUTO_TRACE1("SetCurrentLoginSession %d", dwSessionId);
|
|
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
ImpersonationInfoG.dwCurSessionId = dwSessionId;
|
|
ImpersonationInfoG.fSessionInitialized = TRUE;
|
|
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HANDLE
|
|
RefreshImpersonation(
|
|
HANDLE hProcess
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
//
|
|
// If the process still exists,
|
|
// we can return.
|
|
//
|
|
if (ImpersonationInfoG.hProcess != NULL &&
|
|
hProcess == ImpersonationInfoG.hProcess)
|
|
{
|
|
RASAUTO_TRACE1("RefreshImpersonation: hProcess=0x%x no change", hProcess);
|
|
goto done;
|
|
}
|
|
//
|
|
// Otherwise recalcuate the current information.
|
|
// We have to clear the previous impersonation token,
|
|
// if any.
|
|
//
|
|
if (hProcess != NULL)
|
|
ClearImpersonationToken();
|
|
if (ImpersonationInfoG.hProcess == NULL) {
|
|
RASAUTO_TRACE("RefreshImpersonation: recalcuating token");
|
|
if (!GetCurrentlyLoggedOnUser(&ImpersonationInfoG.hProcess)) {
|
|
RASAUTO_TRACE("RefreshImpersonation: GetCurrentlyLoggedOnUser failed");
|
|
goto done;
|
|
}
|
|
RASAUTO_TRACE("RefreshImpersonation: new user logged in");
|
|
}
|
|
//
|
|
// Impersonate the currently logged-in user.
|
|
//
|
|
if (!SetProcessImpersonationToken(ImpersonationInfoG.hProcess))
|
|
{
|
|
RASAUTO_TRACE(
|
|
"RefreshImpersonation: SetProcessImpersonationToken failed");
|
|
goto done;
|
|
}
|
|
#ifdef notdef // imperson
|
|
//
|
|
// Reset HKEY_CURRENT_USER to get the
|
|
// correct value with the new impersonation
|
|
// token.
|
|
//
|
|
RegCloseKey(HKEY_CURRENT_USER);
|
|
#endif
|
|
RASAUTO_TRACE1(
|
|
"RefreshImpersonation: new hProcess=0x%x",
|
|
ImpersonationInfoG.hProcess);
|
|
TraceCurrentUser();
|
|
|
|
//
|
|
// Open the currently logged on users hive and store it in a global
|
|
//
|
|
if(NULL != hkeyCUG)
|
|
{
|
|
NtClose(hkeyCUG);
|
|
hkeyCUG = NULL;
|
|
}
|
|
|
|
if(STATUS_SUCCESS != RtlOpenCurrentUser(KEY_ALL_ACCESS, &hkeyCUG))
|
|
{
|
|
RASAUTO_TRACE("Failed to open HKCU for the current user");
|
|
}
|
|
|
|
done:
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
return ImpersonationInfoG.hProcess;
|
|
} // RefreshImpersonation
|
|
|
|
|
|
|
|
VOID
|
|
RevertImpersonation()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Close all open handles associated with the
|
|
logged-in user who has just logged out.
|
|
|
|
ARGUMENTS
|
|
None.
|
|
|
|
RETURN VALUE
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
if(ImpersonationInfoG.hToken != NULL)
|
|
{
|
|
CloseHandle(ImpersonationInfoG.hToken);
|
|
ImpersonationInfoG.hToken = NULL;
|
|
}
|
|
|
|
if(ImpersonationInfoG.hTokenImpersonation != NULL)
|
|
{
|
|
CloseHandle(ImpersonationInfoG.hTokenImpersonation);
|
|
ImpersonationInfoG.hTokenImpersonation = NULL;
|
|
}
|
|
|
|
if(ImpersonationInfoG.hProcess != NULL)
|
|
{
|
|
CloseHandle(ImpersonationInfoG.hProcess);
|
|
ImpersonationInfoG.hProcess = NULL;
|
|
}
|
|
|
|
ImpersonationInfoG.fGroupsLoaded = FALSE;
|
|
|
|
if(NULL != hkeyCUG)
|
|
{
|
|
NtClose(hkeyCUG);
|
|
hkeyCUG = NULL;
|
|
}
|
|
|
|
//
|
|
// Clear the thread's impersonation
|
|
// token, or it won't be able to open
|
|
// another user's process the next
|
|
// time around.
|
|
//
|
|
ClearImpersonationToken();
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
} // RevertImpersonation
|
|
|
|
|
|
|
|
DWORD
|
|
InitSecurityDescriptor(
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Initialize a security descriptor allowing administrator
|
|
access for the sharing of handles between rasman.dll.
|
|
|
|
This code courtesy of Gurdeep. You need to ask him
|
|
exactly what it does.
|
|
|
|
ARGUMENTS
|
|
pSecurityDescriptor: a pointer to the security descriptor
|
|
to be initialized.
|
|
|
|
RETURN VALUE
|
|
Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwErr = 0;
|
|
DWORD cbDaclSize;
|
|
PULONG pSubAuthority;
|
|
PSID pObjSid = NULL;
|
|
PACL pDacl = NULL;
|
|
SID_IDENTIFIER_AUTHORITY sidIdentifierWorldAuth =
|
|
SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
DWORD dwAcls;
|
|
|
|
//
|
|
// Set up the SID for the adminstrators that
|
|
// will be allowed access. This SID will have
|
|
// 1 sub-authorities: SECURITY_BUILTIN_DOMAIN_RID.
|
|
//
|
|
pObjSid = (PSID)LocalAlloc(LPTR, GetSidLengthRequired(1));
|
|
if (pObjSid == NULL) {
|
|
RASAUTO_TRACE("InitSecurityDescriptor: LocalAlloc failed");
|
|
return GetLastError();
|
|
}
|
|
if (!InitializeSid(pObjSid, &sidIdentifierWorldAuth, 1)) {
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: InitializeSid failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
//
|
|
// Set the sub-authorities.
|
|
//
|
|
pSubAuthority = GetSidSubAuthority(pObjSid, 0);
|
|
*pSubAuthority = SECURITY_WORLD_RID;
|
|
//
|
|
// Set up the DACL that will allow
|
|
// all processes with the above SID all
|
|
// access. It should be large enough to
|
|
// hold all ACEs.
|
|
//
|
|
cbDaclSize = sizeof(ACCESS_ALLOWED_ACE) +
|
|
GetLengthSid(pObjSid) +
|
|
sizeof (ACL);
|
|
pDacl = (PACL)LocalAlloc(LPTR, cbDaclSize);
|
|
if (pDacl == NULL ) {
|
|
RASAUTO_TRACE("InitSecurityDescriptor: LocalAlloc failed");
|
|
dwErr = GetLastError();
|
|
goto done;
|
|
}
|
|
if (!InitializeAcl(pDacl, cbDaclSize, ACL_REVISION2)) {
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: InitializeAcl failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
dwAcls = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
|
|
|
|
dwAcls &= ~(WRITE_DAC | WRITE_OWNER);
|
|
|
|
//
|
|
// Add the ACE to the DACL
|
|
//
|
|
if (!AddAccessAllowedAce(
|
|
pDacl,
|
|
ACL_REVISION2,
|
|
dwAcls,
|
|
pObjSid))
|
|
{
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: AddAccessAllowedAce failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
//
|
|
// Create the security descriptor an put
|
|
// the DACL in it.
|
|
//
|
|
if (!InitializeSecurityDescriptor(pSecurityDescriptor, 1)) {
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: InitializeSecurityDescriptor failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
if (!SetSecurityDescriptorDacl(
|
|
pSecurityDescriptor,
|
|
TRUE,
|
|
pDacl,
|
|
FALSE))
|
|
{
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: SetSecurityDescriptorDacl failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
//
|
|
// Set owner for the descriptor.
|
|
//
|
|
if (!SetSecurityDescriptorOwner(pSecurityDescriptor, NULL, FALSE)) {
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: SetSecurityDescriptorOwner failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
//
|
|
// Set group for the descriptor.
|
|
//
|
|
if (!SetSecurityDescriptorGroup(pSecurityDescriptor, NULL, FALSE)) {
|
|
dwErr = GetLastError();
|
|
RASAUTO_TRACE1("InitSecurityDescriptor: SetSecurityDescriptorGroup failed (dwErr=0x%x)", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
//
|
|
// Cleanup if necessary.
|
|
//
|
|
if (dwErr) {
|
|
if (pObjSid != NULL)
|
|
LocalFree(pObjSid);
|
|
if (pDacl != NULL)
|
|
LocalFree(pDacl);
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
InitSecurityAttribute()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Initializes the global security attribute used in
|
|
creating shareable handles.
|
|
|
|
This code courtesy of Gurdeep. You need to ask him
|
|
exactly what it does.
|
|
|
|
ARGUMENTS
|
|
None.
|
|
|
|
RETURN VALUE
|
|
Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// Initialize the security descriptor.
|
|
//
|
|
dwErr = InitSecurityDescriptor(&SecurityDescriptorG);
|
|
if (dwErr)
|
|
return dwErr;
|
|
//
|
|
// Initialize the security attributes.
|
|
//
|
|
SecurityAttributeG.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
SecurityAttributeG.lpSecurityDescriptor = &SecurityDescriptorG;
|
|
SecurityAttributeG.bInheritHandle = TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TraceCurrentUser(VOID)
|
|
{
|
|
//WCHAR szUserName[512];
|
|
//DWORD dwSize = sizeof (szUserName) - 1;
|
|
|
|
//GetUserName(szUserName, &dwSize);
|
|
RASAUTO_TRACE1(
|
|
"TraceCurrentUser: impersonating Current User %d",
|
|
ImpersonationInfoG.dwCurSessionId);
|
|
} // TraceCurrentUser
|
|
|
|
DWORD
|
|
DwGetHkcu()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if(NULL == hkeyCUG)
|
|
{
|
|
dwErr = RtlOpenCurrentUser(
|
|
KEY_ALL_ACCESS,
|
|
&hkeyCUG);
|
|
|
|
if(ERROR_SUCCESS != dwErr)
|
|
{
|
|
RASAUTO_TRACE1("DwGetHhcu: failed to open current user. 0x%x",
|
|
dwErr);
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
InitializeImpersonation()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Initializes the global structures used for impersonation
|
|
|
|
ARGUMENTS
|
|
None
|
|
|
|
RETURN VALUE
|
|
Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if (!ImpersonationInfoInitializedG)
|
|
{
|
|
ZeroMemory(&ImpersonationInfoG, sizeof(ImpersonationInfoG));
|
|
RasInitializeCriticalSection(&ImpersonationInfoG.csLock, &dwError);
|
|
|
|
if(dwError != ERROR_SUCCESS)
|
|
{
|
|
return dwError;
|
|
}
|
|
|
|
g_dwCritSecFlags |= RASAUTO_CRITSEC_IMPERSON;
|
|
|
|
ImpersonationInfoInitializedG = TRUE;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
VOID
|
|
CleanupImpersonation()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Cleans up the global structures used for impersonation
|
|
|
|
ARGUMENTS
|
|
None
|
|
|
|
RETURN VALUE
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ImpersonationInfoInitializedG)
|
|
{
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
if (NULL != ImpersonationInfoG.pGuestSid)
|
|
{
|
|
FreeSid(ImpersonationInfoG.pGuestSid);
|
|
ImpersonationInfoG.pGuestSid = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
DeleteCriticalSection(&ImpersonationInfoG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_IMPERSON);
|
|
ImpersonationInfoInitializedG = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ImpersonatingGuest()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Returns whether or not the user that is currently being impersonating
|
|
is a member of the local guests group
|
|
|
|
ARGUMENTS
|
|
None
|
|
|
|
RETURN VALUE
|
|
BOOLEAN -- TRUE if currently impersonating a guests, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN fIsGuest = FALSE;
|
|
|
|
ASSERT(ImpersonationInfoInitializedG);
|
|
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
if (ERROR_SUCCESS == LoadGroupMemberships())
|
|
{
|
|
fIsGuest = ImpersonationInfoG.fGuest;
|
|
}
|
|
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
return fIsGuest;
|
|
}
|
|
|
|
|
|
DWORD
|
|
LoadGroupMemberships()
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Caches the group membership information for the impersonated user.
|
|
|
|
ARGUMENTS
|
|
None
|
|
|
|
RETURN VALUE
|
|
Win32 error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
|
|
BOOL fIsGuest;
|
|
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
do
|
|
{
|
|
if (ImpersonationInfoG.fGroupsLoaded)
|
|
{
|
|
//
|
|
// Information already loaded
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
if (NULL == ImpersonationInfoG.hTokenImpersonation)
|
|
{
|
|
//
|
|
// There isn't an impersonated user.
|
|
//
|
|
|
|
dwError = ERROR_CAN_NOT_COMPLETE;
|
|
break;
|
|
}
|
|
|
|
if (NULL == ImpersonationInfoG.pGuestSid)
|
|
{
|
|
//
|
|
// Allocate the SID for the local guests group;
|
|
//
|
|
|
|
if (!AllocateAndInitializeSid(
|
|
&IdentifierAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_GUESTS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&ImpersonationInfoG.pGuestSid
|
|
))
|
|
{
|
|
dwError = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!CheckTokenMembership(
|
|
ImpersonationInfoG.hTokenImpersonation,
|
|
ImpersonationInfoG.pGuestSid,
|
|
&fIsGuest
|
|
))
|
|
{
|
|
dwError = GetLastError();
|
|
break;
|
|
}
|
|
|
|
ImpersonationInfoG.fGuest = !!fIsGuest;
|
|
|
|
} while (FALSE);
|
|
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
VOID
|
|
LockImpersonation()
|
|
{
|
|
ASSERT(ImpersonationInfoInitializedG);
|
|
|
|
if(ImpersonationInfoInitializedG)
|
|
{
|
|
EnterCriticalSection(&ImpersonationInfoG.csLock);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UnlockImpersonation()
|
|
{
|
|
ASSERT(ImpersonationInfoInitializedG);
|
|
|
|
if(ImpersonationInfoInitializedG)
|
|
{
|
|
LeaveCriticalSection(&ImpersonationInfoG.csLock);
|
|
}
|
|
}
|