Windows-Server-2003/net/tapi/sp/remotesp/imperson.c

481 lines
9.5 KiB
C
Raw Normal View History

2024-08-04 01:28:15 +02:00
/*++
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