652 lines
17 KiB
C
652 lines
17 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Rxconfig.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Redirector configuration routines for DRT
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Balan Sethu Raman -- Created from the workstation service code
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <ntlsa.h>
|
|||
|
|
|||
|
#include <windows.h>
|
|||
|
#include "rxdrt.h"
|
|||
|
#include "rxdevice.h"
|
|||
|
#include "rxconfig.h"
|
|||
|
#include "malloc.h"
|
|||
|
|
|||
|
#define PRIVILEGE_BUF_SIZE 512
|
|||
|
#define WS_LINKAGE_REGISTRY_PATH L"LanmanWorkstation\\Linkage"
|
|||
|
#define WS_BIND_VALUE_NAME L"Bind"
|
|||
|
|
|||
|
extern NTSTATUS
|
|||
|
RxBindATransport(
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN ULONG ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN ULONG ValueLength,
|
|||
|
IN PVOID Context,
|
|||
|
IN PVOID EntryContext
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// For specifying the importance of a transport when binding to it.
|
|||
|
// The higher the number means that the transport will be searched
|
|||
|
// first.
|
|||
|
//
|
|||
|
STATIC DWORD QualityOfService = 65536;
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxGetDomainName(
|
|||
|
IN PULONG pBufferLengthInBytes,
|
|||
|
IN PWCHAR Buffer, // alloc and set ptr (free with NetApiBufferFree)
|
|||
|
OUT PBOOLEAN IsWorkgroupName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the name of the domain or workgroup this machine belongs to.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DomainNamePtr - The name of the domain or workgroup
|
|||
|
|
|||
|
IsWorkgroupName - Returns TRUE if the name is a workgroup name.
|
|||
|
Returns FALSE if the name is a domain name.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NERR_Success - Success.
|
|||
|
NERR_CfgCompNotFound - There was an error determining the domain name
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS ntstatus;
|
|||
|
LSA_HANDLE PolicyHandle;
|
|||
|
PPOLICY_ACCOUNT_DOMAIN_INFO PrimaryDomainInfo;
|
|||
|
OBJECT_ATTRIBUTES ObjAttributes;
|
|||
|
|
|||
|
//
|
|||
|
// Open a handle to the local security policy. Initialize the
|
|||
|
// objects attributes structure first.
|
|||
|
//
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjAttributes,
|
|||
|
NULL,
|
|||
|
0L,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
ntstatus = LsaOpenPolicy(
|
|||
|
NULL,
|
|||
|
&ObjAttributes,
|
|||
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|||
|
&PolicyHandle
|
|||
|
);
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
return ntstatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the name of the primary domain from LSA
|
|||
|
//
|
|||
|
ntstatus = LsaQueryInformationPolicy(
|
|||
|
PolicyHandle,
|
|||
|
PolicyPrimaryDomainInformation,
|
|||
|
(PVOID *) &PrimaryDomainInfo
|
|||
|
);
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
(void) LsaClose(PolicyHandle);
|
|||
|
return ntstatus;
|
|||
|
}
|
|||
|
|
|||
|
(void) LsaClose(PolicyHandle);
|
|||
|
|
|||
|
if (PrimaryDomainInfo->DomainName.Length + sizeof(WCHAR) > *pBufferLengthInBytes) {
|
|||
|
ntstatus = STATUS_BUFFER_OVERFLOW;
|
|||
|
} else {
|
|||
|
*pBufferLengthInBytes = PrimaryDomainInfo->DomainName.Length;
|
|||
|
RtlZeroMemory(
|
|||
|
Buffer,
|
|||
|
PrimaryDomainInfo->DomainName.Length + sizeof(WCHAR)
|
|||
|
);
|
|||
|
|
|||
|
memcpy(
|
|||
|
Buffer,
|
|||
|
PrimaryDomainInfo->DomainName.Buffer,
|
|||
|
PrimaryDomainInfo->DomainName.Length
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
*IsWorkgroupName = (PrimaryDomainInfo->DomainSid == NULL);
|
|||
|
(void) LsaFreeMemory((PVOID) PrimaryDomainInfo);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxStartRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
WCHAR NameBuffer[MAX_PATH];
|
|||
|
ULONG Length;
|
|||
|
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|||
|
ULONG ComputerNameLengthInBytes;
|
|||
|
WCHAR DomainName[DNLEN + 1];
|
|||
|
ULONG DomainNameLengthInBytes;
|
|||
|
DWORD version;
|
|||
|
WKSTA_INFO_502 WkstaInfo;
|
|||
|
UNICODE_STRING InputString;
|
|||
|
UNICODE_STRING OutputString;
|
|||
|
BOOLEAN IsWorkGroup;
|
|||
|
|
|||
|
BYTE Buffer[max(sizeof(LMR_REQUEST_PACKET) + (CNLEN + 1) * sizeof(WCHAR) +
|
|||
|
(DNLEN + 1) * sizeof(WCHAR),
|
|||
|
sizeof(LMDR_REQUEST_PACKET))];
|
|||
|
|
|||
|
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) Buffer;
|
|||
|
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) Buffer;
|
|||
|
|
|||
|
// Obtain the computer name.
|
|||
|
Length = MAX_PATH;
|
|||
|
status = GetComputerName(NameBuffer,&Length);
|
|||
|
|
|||
|
ASSERT(Length <= MAX_COMPUTERNAME_LENGTH);
|
|||
|
|
|||
|
// Canonicalize the name. ( Upcase conversion )
|
|||
|
InputString.Length = InputString.MaximumLength = (USHORT)((Length + 1) * sizeof(WCHAR));
|
|||
|
InputString.Buffer = NameBuffer;
|
|||
|
|
|||
|
OutputString.Length = OutputString.MaximumLength = (USHORT)((Length + 1) * sizeof(WCHAR));
|
|||
|
OutputString.Buffer = ComputerName;
|
|||
|
|
|||
|
ComputerNameLengthInBytes = Length * sizeof(WCHAR);
|
|||
|
|
|||
|
RtlUpcaseUnicodeString(&OutputString,&InputString,FALSE);
|
|||
|
|
|||
|
// Get the primary domain name from the configuration file
|
|||
|
DomainNameLengthInBytes = sizeof(WCHAR) * (DNLEN + 1);
|
|||
|
status = RxGetDomainName(&DomainNameLengthInBytes,DomainName,&IsWorkGroup);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
// Initialize redirector configuration
|
|||
|
Rrp->Type = ConfigInformation;
|
|||
|
Rrp->Version = REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
wcscpy(Rrp->Parameters.Start.RedirectorName,
|
|||
|
ComputerName);
|
|||
|
Rrp->Parameters.Start.RedirectorNameLength = ComputerNameLengthInBytes;
|
|||
|
|
|||
|
Rrp->Parameters.Start.DomainNameLength = DomainNameLengthInBytes;
|
|||
|
wcscpy((Rrp->Parameters.Start.RedirectorName+ComputerNameLengthInBytes),
|
|||
|
DomainName);
|
|||
|
|
|||
|
status = RxRedirFsControl(
|
|||
|
RxRedirDeviceHandle,
|
|||
|
FSCTL_LMR_START,
|
|||
|
Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET) +
|
|||
|
Rrp->Parameters.Start.RedirectorNameLength+
|
|||
|
Rrp->Parameters.Start.DomainNameLength,
|
|||
|
(LPBYTE) &WkstaInfo,
|
|||
|
sizeof(WKSTA_INFO_502),
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxBindToTransports(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function binds the transports specified in the registry to the
|
|||
|
redirector. The order of priority for the transports follows the order
|
|||
|
they are listed by the "Bind=" valuename.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
NTSTATUS tempStatus;
|
|||
|
NTSTATUS ntstatus;
|
|||
|
DWORD transportsBound;
|
|||
|
PRTL_QUERY_REGISTRY_TABLE queryTable;
|
|||
|
LIST_ENTRY header;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
PRX_BIND pBind;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Ask the RTL to call us back for each subvalue in the MULTI_SZ
|
|||
|
// value \LanmanWorkstation\Linkage\Bind.
|
|||
|
//
|
|||
|
queryTable = (PVOID)malloc(sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
|
|||
|
|
|||
|
if (queryTable == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
InitializeListHead( &header);
|
|||
|
|
|||
|
queryTable[0].QueryRoutine = RxBindATransport;
|
|||
|
queryTable[0].Flags = 0;
|
|||
|
queryTable[0].Name = WS_BIND_VALUE_NAME;
|
|||
|
queryTable[0].EntryContext = NULL;
|
|||
|
queryTable[0].DefaultType = REG_NONE;
|
|||
|
queryTable[0].DefaultData = NULL;
|
|||
|
queryTable[0].DefaultLength = 0;
|
|||
|
|
|||
|
queryTable[1].QueryRoutine = NULL;
|
|||
|
queryTable[1].Flags = 0;
|
|||
|
queryTable[1].Name = NULL;
|
|||
|
|
|||
|
ntstatus = RtlQueryRegistryValues(
|
|||
|
RTL_REGISTRY_SERVICES, // path relative to ...
|
|||
|
WS_LINKAGE_REGISTRY_PATH,
|
|||
|
queryTable,
|
|||
|
(PVOID) &header, // context
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// First process all the data, then clean up.
|
|||
|
//
|
|||
|
|
|||
|
for ( pListEntry = header.Flink;
|
|||
|
pListEntry != &header;
|
|||
|
pListEntry = pListEntry->Flink) {
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
RX_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
tempStatus = NO_ERROR;
|
|||
|
|
|||
|
if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
WaitForSingleObject(
|
|||
|
pBind->Redir->EventHandle,
|
|||
|
INFINITE
|
|||
|
);
|
|||
|
pBind->Redir->Bound = (tempStatus == NO_ERROR);
|
|||
|
if (tempStatus == ERROR_DUP_NAME) {
|
|||
|
status = tempStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
WaitForSingleObject(
|
|||
|
pBind->Dgrec->EventHandle,
|
|||
|
INFINITE
|
|||
|
);
|
|||
|
pBind->Dgrec->Bound = (tempStatus == NO_ERROR);
|
|||
|
if (tempStatus == ERROR_DUP_NAME) {
|
|||
|
status = tempStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If one is installed but the other is not, clean up the other.
|
|||
|
//
|
|||
|
|
|||
|
if ( pBind->Dgrec->Bound != pBind->Redir->Bound) {
|
|||
|
RxUnbindTransport2( pBind);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
for ( pListEntry = header.Flink;
|
|||
|
pListEntry != &header;
|
|||
|
pListEntry = pListEntry->Flink) {
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
RX_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
RxUnbindTransport2( pBind);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for ( transportsBound = 0;
|
|||
|
IsListEmpty( &header) == FALSE;
|
|||
|
LocalFree((HLOCAL) pBind)) {
|
|||
|
|
|||
|
pListEntry = RemoveHeadList( &header);
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
RX_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
CloseHandle( pBind->Redir->EventHandle);
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Redir->Bound == TRUE) {
|
|||
|
transportsBound++;
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
CloseHandle( pBind->Dgrec->EventHandle);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
(void) free((HLOCAL) queryTable);
|
|||
|
|
|||
|
if ( RxRedirAsyncDeviceHandle != NULL) {
|
|||
|
(VOID)NtClose( RxRedirAsyncDeviceHandle);
|
|||
|
RxRedirAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( RxDgrecAsyncDeviceHandle != NULL) {
|
|||
|
(VOID)NtClose( RxDgrecAsyncDeviceHandle);
|
|||
|
RxDgrecAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return ntstatus;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxBindATransport(
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN ULONG ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN ULONG ValueLength,
|
|||
|
IN PVOID Context,
|
|||
|
IN PVOID EntryContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
This routine always returns SUCCESS because we want all transports
|
|||
|
to be processed fully.
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
DBG_UNREFERENCED_PARAMETER( ValueName);
|
|||
|
DBG_UNREFERENCED_PARAMETER( ValueLength);
|
|||
|
DBG_UNREFERENCED_PARAMETER( EntryContext);
|
|||
|
|
|||
|
//
|
|||
|
// Bind transport
|
|||
|
//
|
|||
|
|
|||
|
status = RxAsyncBindTransport(
|
|||
|
ValueData, // name of transport device object
|
|||
|
--QualityOfService,
|
|||
|
(PLIST_ENTRY)Context);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
RxGetPrivilege(
|
|||
|
IN DWORD numPrivileges,
|
|||
|
IN PULONG pulPrivileges
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function alters the privilege level for the current thread.
|
|||
|
|
|||
|
It does this by duplicating the token for the current thread, and then
|
|||
|
applying the new privileges to that new token, then the current thread
|
|||
|
impersonates with that new token.
|
|||
|
|
|||
|
Privileges can be relinquished by calling NetpReleasePrivilege().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
numPrivileges - This is a count of the number of privileges in the
|
|||
|
array of privileges.
|
|||
|
|
|||
|
pulPrivileges - This is a pointer to the array of privileges that are
|
|||
|
desired. This is an array of ULONGs.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - If the operation was completely successful.
|
|||
|
|
|||
|
Otherwise, it returns mapped return codes from the various NT
|
|||
|
functions that are called.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
HANDLE ourToken;
|
|||
|
HANDLE newToken;
|
|||
|
OBJECT_ATTRIBUTES Obja;
|
|||
|
SECURITY_QUALITY_OF_SERVICE SecurityQofS;
|
|||
|
ULONG bufLen;
|
|||
|
ULONG returnLen;
|
|||
|
PTOKEN_PRIVILEGES pPreviousState;
|
|||
|
PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the Privileges Structure
|
|||
|
//
|
|||
|
pTokenPrivilege = LocalAlloc(LMEM_FIXED, sizeof(TOKEN_PRIVILEGES) +
|
|||
|
(sizeof(LUID_AND_ATTRIBUTES) * numPrivileges));
|
|||
|
|
|||
|
if (pTokenPrivilege == NULL) {
|
|||
|
status = GetLastError();
|
|||
|
return(status);
|
|||
|
}
|
|||
|
pTokenPrivilege->PrivilegeCount = numPrivileges;
|
|||
|
for (i=0; i<numPrivileges ;i++ ) {
|
|||
|
pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLargeInteger(
|
|||
|
pulPrivileges[i]);
|
|||
|
pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize Object Attribute Structure.
|
|||
|
//
|
|||
|
InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize Security Quality Of Service Structure
|
|||
|
//
|
|||
|
SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|||
|
SecurityQofS.ImpersonationLevel = SecurityImpersonation;
|
|||
|
SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
|
|||
|
SecurityQofS.EffectiveOnly = FALSE;
|
|||
|
|
|||
|
Obja.SecurityQualityOfService = &SecurityQofS;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate storage for the structure that will hold the Previous State
|
|||
|
// information.
|
|||
|
//
|
|||
|
pPreviousState = LocalAlloc(LMEM_FIXED, PRIVILEGE_BUF_SIZE);
|
|||
|
if (pPreviousState == NULL) {
|
|||
|
|
|||
|
status = GetLastError();
|
|||
|
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open our own Token
|
|||
|
//
|
|||
|
ntStatus = NtOpenProcessToken(
|
|||
|
NtCurrentProcess(),
|
|||
|
TOKEN_DUPLICATE,
|
|||
|
&ourToken);
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
LocalFree(pPreviousState);
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
return(RtlNtStatusToDosError(ntStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Duplicate that Token
|
|||
|
//
|
|||
|
ntStatus = NtDuplicateToken(
|
|||
|
ourToken,
|
|||
|
TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|||
|
&Obja,
|
|||
|
FALSE, // Duplicate the entire token
|
|||
|
TokenImpersonation, // TokenType
|
|||
|
&newToken); // Duplicate token
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
LocalFree(pPreviousState);
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
NtClose(ourToken);
|
|||
|
return(RtlNtStatusToDosError(ntStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add new privileges
|
|||
|
//
|
|||
|
bufLen = PRIVILEGE_BUF_SIZE;
|
|||
|
ntStatus = NtAdjustPrivilegesToken(
|
|||
|
newToken, // TokenHandle
|
|||
|
FALSE, // DisableAllPrivileges
|
|||
|
pTokenPrivilege, // NewState
|
|||
|
bufLen, // bufferSize for previous state
|
|||
|
pPreviousState, // pointer to previous state info
|
|||
|
&returnLen); // numBytes required for buffer.
|
|||
|
|
|||
|
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
|
|||
|
|
|||
|
LocalFree(pPreviousState);
|
|||
|
|
|||
|
bufLen = returnLen;
|
|||
|
|
|||
|
pPreviousState = LocalAlloc(LMEM_FIXED, bufLen);
|
|||
|
|
|||
|
|
|||
|
ntStatus = NtAdjustPrivilegesToken(
|
|||
|
newToken, // TokenHandle
|
|||
|
FALSE, // DisableAllPrivileges
|
|||
|
pTokenPrivilege, // NewState
|
|||
|
bufLen, // bufferSize for previous state
|
|||
|
pPreviousState, // pointer to previous state info
|
|||
|
&returnLen); // numBytes required for buffer.
|
|||
|
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
LocalFree(pPreviousState);
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
NtClose(ourToken);
|
|||
|
NtClose(newToken);
|
|||
|
return(RtlNtStatusToDosError(ntStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Begin impersonating with the new token
|
|||
|
//
|
|||
|
ntStatus = NtSetInformationThread(
|
|||
|
NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
(PVOID)&newToken,
|
|||
|
(ULONG)sizeof(HANDLE));
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
LocalFree(pPreviousState);
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
NtClose(ourToken);
|
|||
|
NtClose(newToken);
|
|||
|
return(RtlNtStatusToDosError(ntStatus));
|
|||
|
}
|
|||
|
|
|||
|
LocalFree(pPreviousState);
|
|||
|
LocalFree(pTokenPrivilege);
|
|||
|
NtClose(ourToken);
|
|||
|
NtClose(newToken);
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
RxReleasePrivilege(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function relinquishes privileges obtained by calling NetpGetPrivilege().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - If the operation was completely successful.
|
|||
|
|
|||
|
Otherwise, it returns mapped return codes from the various NT
|
|||
|
functions that are called.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS ntStatus;
|
|||
|
HANDLE NewToken;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Revert To Self.
|
|||
|
//
|
|||
|
NewToken = NULL;
|
|||
|
|
|||
|
ntStatus = NtSetInformationThread(
|
|||
|
NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
(PVOID)&NewToken,
|
|||
|
(ULONG)sizeof(HANDLE));
|
|||
|
|
|||
|
if ( !NT_SUCCESS(ntStatus) ) {
|
|||
|
return(RtlNtStatusToDosError(ntStatus));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|