windows-nt/Source/XPSP1/NT/base/fs/rdr2/drt/daytona/rxconfig.c
2020-09-26 16:20:57 +08:00

652 lines
17 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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);
}