481 lines
9.5 KiB
C
481 lines
9.5 KiB
C
/*++
|
||
|
||
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 <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
//#include <stdlib.h>
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
//#include <npapi.h>
|
||
|
||
#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
|
||
|