NT4/private/windows/base/server/srvinit.c
2020-09-30 17:12:29 +02:00

1158 lines
36 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) 1990 Microsoft Corporation
Module Name:
srvinit.c
Abstract:
This is the main initialization file for the Windows 32-bit Base API
Server DLL.
Author:
Steve Wood (stevewo) 10-Oct-1990
Revision History:
--*/
#include "basesrv.h"
UNICODE_STRING BaseSrvCSDString;
RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[] = {
{NULL, RTL_QUERY_REGISTRY_DIRECT,
L"CSDVersion", &BaseSrvCSDString,
REG_NONE, NULL, 0},
{NULL, 0,
NULL, NULL,
REG_NONE, NULL, 0}
};
PCSR_API_ROUTINE BaseServerApiDispatchTable[ BasepMaxApiNumber+1 ] = {
BaseSrvCreateProcess,
BaseSrvCreateThread,
BaseSrvGetTempFile,
BaseSrvExitProcess,
BaseSrvDebugProcess,
BaseSrvCheckVDM,
BaseSrvUpdateVDMEntry,
BaseSrvGetNextVDMCommand,
BaseSrvExitVDM,
BaseSrvIsFirstVDM,
BaseSrvGetVDMExitCode,
BaseSrvSetReenterCount,
BaseSrvSetProcessShutdownParam,
BaseSrvGetProcessShutdownParam,
BaseSrvNlsSetUserInfo,
BaseSrvNlsSetMultipleUserInfo,
BaseSrvNlsCreateSortSection,
BaseSrvNlsPreserveSection,
BaseSrvSetVDMCurDirs,
BaseSrvGetVDMCurDirs,
BaseSrvBatNotification,
BaseSrvRegisterWowExec,
BaseSrvSoundSentryNotification,
BaseSrvRefreshIniFileMapping,
BaseSrvDefineDosDevice,
NULL
};
BOOLEAN BaseServerApiServerValidTable[ BasepMaxApiNumber+1 ] = {
TRUE, // SrvCreateProcess,
TRUE, // SrvCreateThread,
TRUE, // SrvGetTempFile,
FALSE, // SrvExitProcess,
FALSE, // SrvDebugProcess,
TRUE, // SrvCheckVDM,
TRUE, // SrvUpdateVDMEntry
TRUE, // SrvGetNextVDMCommand
TRUE, // SrvExitVDM
TRUE, // SrvIsFirstVDM
TRUE, // SrvGetVDMExitCode
TRUE, // SrvSetReenterCount
TRUE, // SrvSetProcessShutdownParam
TRUE, // SrvGetProcessShutdownParam
TRUE, // SrvNlsSetUserInfo
TRUE, // SrvNlsSetMultipleUserInfo
TRUE, // SrvNlsCreateSortSection
TRUE, // SrvNlsPreserveSection
TRUE, // SrvSetVDMCurDirs
TRUE, // SrvGetVDMCurDirs
TRUE, // SrvBatNotification
TRUE, // SrvRegisterWowExec
TRUE, // SrvSoundSentryNotification
TRUE, // SrvRefreshIniFileMapping
TRUE, // SrvDefineDosDevice
FALSE
};
#if DBG
PSZ BaseServerApiNameTable[ BasepMaxApiNumber+1 ] = {
"BaseCreateProcess",
"BaseCreateThread",
"BaseGetTempFile",
"BaseExitProcess",
"BaseDebugProcess",
"BaseCheckVDM",
"BaseUpdateVDMEntry",
"BaseGetNextVDMCommand",
"BaseExitVDM",
"BaseIsFirstVDM",
"BaseGetVDMExitCode",
"BaseSetReenterCount",
"BaseSetProcessShutdownParam",
"BaseGetProcessShutdownParam",
"BaseNlsSetUserInfo",
"BaseNlsSetMultipleUserInfo",
"BaseNlsCreateSortSection",
"BaseNlsPreserveSection",
"BaseSetVDMCurDirs",
"BaseGetVDMCurDirs",
"BaseBatNotification",
"BaseRegisterWowExec",
"BaseSoundSentryNotification",
"BaseSrvRefreshIniFileMapping"
"BaseDefineDosDevice",
NULL
};
#endif // DBG
HANDLE BaseSrvNamedObjectDirectory;
RTL_CRITICAL_SECTION BaseSrvDosDeviceCritSec;
BOOLEAN BaseSrvFirstClient = TRUE;
WORD
ConvertUnicodeToWord( PWSTR s );
NTSTATUS
CreateBaseAcl( PACL *Dacl );
WORD
ConvertUnicodeToWord( PWSTR s )
{
NTSTATUS Status;
ULONG Result;
UNICODE_STRING UnicodeString;
while (*s && *s <= L' ') {
s += 1;
}
RtlInitUnicodeString( &UnicodeString, s );
Status = RtlUnicodeStringToInteger( &UnicodeString,
10,
&Result
);
if (!NT_SUCCESS( Status )) {
Result = 0;
}
return (WORD)Result;
}
#ifdef WX86
PKEY_VALUE_PARTIAL_INFORMATION
Wx86QueryValueKey(
HANDLE KeyHandle,
PWCHAR ValueName
)
{
NTSTATUS Status;
ULONG ResultLength;
UNICODE_STRING UnicodeString;
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation, RetKeyValueInfo;
BYTE ValueBuffer[MAX_PATH*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
RtlInitUnicodeString( &UnicodeString, ValueName);
Status = NtQueryValueKey(KeyHandle,
&UnicodeString,
KeyValuePartialInformation,
KeyValueInformation,
sizeof( ValueBuffer ),
&ResultLength
);
if (NT_SUCCESS(Status)) {
RetKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ResultLength);
if (RetKeyValueInfo) {
RtlMoveMemory(RetKeyValueInfo,
KeyValueInformation,
ResultLength
);
}
}
else if (Status == STATUS_BUFFER_OVERFLOW) {
RetKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ResultLength);
if (RetKeyValueInfo) {
Status = NtQueryValueKey(KeyHandle,
&UnicodeString,
KeyValuePartialInformation,
RetKeyValueInfo,
ResultLength,
&ResultLength
);
if (!NT_SUCCESS(Status)) {
RtlFreeHeap(RtlProcessHeap(), 0, RetKeyValueInfo);
RetKeyValueInfo = NULL;
}
}
}
else {
RetKeyValueInfo = NULL;
}
return RetKeyValueInfo;
}
/*
* Initializes the volatile registry entries for Wx86.
* \Registry\Machine\HARDWARE\DESCRIPTION\System\Wx86FloatingPointProcessor
*/
void
SetupWx86KeyMapping(void)
{
NTSTATUS Status;
ULONG Processors, ProcessorCount;
HANDLE KeyHandle, ParentKeyHandle;
PKEY_VALUE_PARTIAL_INFORMATION Identifier;
PKEY_VALUE_PARTIAL_INFORMATION ConfigurationData;
PKEY_VALUE_PARTIAL_INFORMATION ComponentInformation;
UNICODE_STRING UnicodeString;
UNICODE_STRING ClassUnicode;
OBJECT_ATTRIBUTES Obja;
WCHAR wcProcessor[64];
//
// If the Wx86\\KeyRemapping\\FloatingPointProcessor does not exist
// don't create the Wx86FloatingPointProcessor. So that x86 apps
// will think there isn't any fpu.
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wx86\\KeyRemapping\\FloatingPointProcessor"
);
InitializeObjectAttributes(&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &Obja);
if (!NT_SUCCESS(Status)) {
return;
}
NtClose(KeyHandle);
//
// Create Wx86FloatingPointProcessor key
//
RtlInitUnicodeString(&ClassUnicode, L"Processor");
RtlInitUnicodeString(
&UnicodeString,
L"\\Registry\\Machine\\Hardware\\Description\\System\\Wx86FloatingPointProcessor"
);
InitializeObjectAttributes(&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateKey(&ParentKeyHandle,
KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY,
&Obja,
0, // TitleIndex ?
&ClassUnicode,
REG_OPTION_VOLATILE,
NULL
);
if (!NT_SUCCESS(Status)) {
return;
}
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0"
);
InitializeObjectAttributes(&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey(&KeyHandle, KEY_READ, &Obja);
if (!NT_SUCCESS(Status)) {
NtClose(ParentKeyHandle);
return;
}
Identifier = Wx86QueryValueKey(KeyHandle, L"Identifier");
ConfigurationData = Wx86QueryValueKey(KeyHandle, L"Configuration Data");
ComponentInformation = Wx86QueryValueKey(KeyHandle, L"Component Information");
NtClose(KeyHandle);
KeyHandle = NULL;
Processors = BaseSrvpStaticServerData->SysInfo.NumberOfProcessors;
ProcessorCount = 0;
while (Processors--) {
swprintf(wcProcessor, L"%d", ProcessorCount++);
RtlInitUnicodeString(&UnicodeString, wcProcessor);
InitializeObjectAttributes(&Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle,
NULL
);
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&Obja,
0,
NULL,
REG_OPTION_VOLATILE,
NULL
);
if (!NT_SUCCESS(Status)) {
KeyHandle = NULL;
goto SWMCleanup;
}
if (ComponentInformation) {
RtlInitUnicodeString(&UnicodeString, L"Component Information");
Status = NtSetValueKey(KeyHandle,
&UnicodeString,
0,
ComponentInformation->Type,
ComponentInformation->Data,
ComponentInformation->DataLength
);
if (!NT_SUCCESS(Status)) {
goto SWMCleanup;
}
}
if (ConfigurationData) {
RtlInitUnicodeString(&UnicodeString, L"Configuration Data");
Status = NtSetValueKey(KeyHandle,
&UnicodeString,
0,
ConfigurationData->Type,
ConfigurationData->Data,
ConfigurationData->DataLength
);
if (!NT_SUCCESS(Status)) {
goto SWMCleanup;
}
}
if (Identifier) {
RtlInitUnicodeString(&UnicodeString, L"Identifier");
Status = NtSetValueKey(KeyHandle,
&UnicodeString,
0,
Identifier->Type,
Identifier->Data,
Identifier->DataLength
);
if (!NT_SUCCESS(Status)) {
goto SWMCleanup;
}
}
NtClose(KeyHandle);
KeyHandle = NULL;
}
SWMCleanup:
if (ConfigurationData) {
RtlFreeHeap( RtlProcessHeap(), 0, ConfigurationData);
}
if (ComponentInformation) {
RtlFreeHeap( RtlProcessHeap(), 0, ComponentInformation);
}
if (Identifier) {
RtlFreeHeap( RtlProcessHeap(), 0, Identifier);
}
if (ParentKeyHandle) {
NtClose(ParentKeyHandle);
}
if (KeyHandle) {
NtClose(KeyHandle);
}
return;
}
#endif
NTSTATUS
ServerDllInitialization(
PCSR_SERVER_DLL LoadedServerDll
)
{
NTSTATUS Status;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES Obja;
PSECURITY_DESCRIPTOR PrimarySecurityDescriptor;
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
ULONG ResultLength;
PVOID p;
WCHAR NameBuffer[ MAX_PATH ];
WCHAR ValueBuffer[ 400 ];
UNICODE_STRING NameString, ValueString;
HANDLE KeyHandle;
PWSTR s, s1;
PACL Dacl;
BaseSrvHeap = RtlProcessHeap();
BaseSrvTag = RtlCreateTagHeap( BaseSrvHeap,
0,
L"BASESRV!",
L"TMP\0"
L"VDM\0"
);
BaseSrvSharedHeap = LoadedServerDll->SharedStaticServerData;
BaseSrvSharedTag = RtlCreateTagHeap( BaseSrvSharedHeap,
0,
L"BASESHR!",
L"INIT\0"
L"INI\0"
);
LoadedServerDll->ApiNumberBase = BASESRV_FIRST_API_NUMBER;
LoadedServerDll->MaxApiNumber = BasepMaxApiNumber;
LoadedServerDll->ApiDispatchTable = BaseServerApiDispatchTable;
LoadedServerDll->ApiServerValidTable = BaseServerApiServerValidTable;
#if DBG
LoadedServerDll->ApiNameTable = BaseServerApiNameTable;
#else
LoadedServerDll->ApiNameTable = NULL;
#endif
LoadedServerDll->PerProcessDataLength = 0;
LoadedServerDll->PerThreadDataLength = 0;
LoadedServerDll->ConnectRoutine = BaseClientConnectRoutine;
LoadedServerDll->DisconnectRoutine = BaseClientDisconnectRoutine;
LoadedServerDll->AddThreadRoutine = NULL;
LoadedServerDll->DeleteThreadRoutine = NULL;
RtlInitializeCriticalSection( &BaseSrvDosDeviceCritSec );
wcscpy( NameBuffer, L"%SystemRoot%" );
RtlInitUnicodeString( &NameString, NameBuffer );
ValueString.Buffer = ValueBuffer;
ValueString.MaximumLength = sizeof( ValueBuffer );
Status = RtlExpandEnvironmentStrings_U( NULL,
&NameString,
&ValueString,
NULL
);
ASSERT( NT_SUCCESS( Status ) );
ValueBuffer[ ValueString.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
RtlCreateUnicodeString( &BaseSrvWindowsDirectory, ValueBuffer );
wcscat( NameBuffer, L"\\System32" );
RtlInitUnicodeString( &NameString, NameBuffer );
Status = RtlExpandEnvironmentStrings_U( NULL,
&NameString,
&ValueString,
NULL
);
ASSERT( NT_SUCCESS( Status ) );
ValueBuffer[ ValueString.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
RtlCreateUnicodeString( &BaseSrvWindowsSystemDirectory, ValueBuffer );
//
// need to synch this w/ user's desktop concept
//
RtlInitUnicodeString( &UnicodeString, L"\\BaseNamedObjects" );
//
// initialize base static server data
//
BaseSrvpStaticServerData = RtlAllocateHeap( BaseSrvSharedHeap,
MAKE_SHARED_TAG( INIT_TAG ),
sizeof( BASE_STATIC_SERVER_DATA )
);
if ( !BaseSrvpStaticServerData ) {
return STATUS_NO_MEMORY;
}
LoadedServerDll->SharedStaticServerData = (PVOID)BaseSrvpStaticServerData;
Status = NtQuerySystemInformation(
SystemTimeOfDayInformation,
(PVOID)&BaseSrvpStaticServerData->TimeOfDay,
sizeof(BaseSrvpStaticServerData->TimeOfDay),
NULL
);
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
//
// windows directory
//
BaseSrvpStaticServerData->WindowsDirectory = BaseSrvWindowsDirectory;
p = RtlAllocateHeap( BaseSrvSharedHeap,
MAKE_SHARED_TAG( INIT_TAG ),
BaseSrvWindowsDirectory.MaximumLength
);
if ( !p ) {
return STATUS_NO_MEMORY;
}
RtlMoveMemory(p,BaseSrvpStaticServerData->WindowsDirectory.Buffer,BaseSrvWindowsDirectory.MaximumLength);
BaseSrvpStaticServerData->WindowsDirectory.Buffer = p;
//
// windows system directory
//
BaseSrvpStaticServerData->WindowsSystemDirectory = BaseSrvWindowsSystemDirectory;
p = RtlAllocateHeap( BaseSrvSharedHeap,
MAKE_SHARED_TAG( INIT_TAG ),
BaseSrvWindowsSystemDirectory.MaximumLength
);
if ( !p ) {
return STATUS_NO_MEMORY;
}
RtlMoveMemory(p,BaseSrvpStaticServerData->WindowsSystemDirectory.Buffer,BaseSrvWindowsSystemDirectory.MaximumLength);
BaseSrvpStaticServerData->WindowsSystemDirectory.Buffer = p;
//
// named object directory
//
BaseSrvpStaticServerData->NamedObjectDirectory = UnicodeString;
BaseSrvpStaticServerData->NamedObjectDirectory.MaximumLength = UnicodeString.Length+(USHORT)sizeof(UNICODE_NULL);
p = RtlAllocateHeap( BaseSrvSharedHeap,
MAKE_SHARED_TAG( INIT_TAG ),
UnicodeString.Length + sizeof( UNICODE_NULL )
);
if ( !p ) {
return STATUS_NO_MEMORY;
}
RtlMoveMemory(p,BaseSrvpStaticServerData->NamedObjectDirectory.Buffer,BaseSrvpStaticServerData->NamedObjectDirectory.MaximumLength);
BaseSrvpStaticServerData->NamedObjectDirectory.Buffer = p;
BaseSrvCSDString.Buffer = &ValueBuffer[ 300 ];
BaseSrvCSDString.Length = 0;
BaseSrvCSDString.MaximumLength = 100 * sizeof( WCHAR );
Status = RtlQueryRegistryValues( RTL_REGISTRY_WINDOWS_NT,
L"",
BaseServerRegistryConfigurationTable,
NULL,
NULL
);
if (NT_SUCCESS( Status )) {
wcsncpy( BaseSrvpStaticServerData->CSDVersion,
BaseSrvCSDString.Buffer,
BaseSrvCSDString.Length
);
BaseSrvpStaticServerData->CSDVersion[ BaseSrvCSDString.Length ] = UNICODE_NULL;
}
else {
BaseSrvpStaticServerData->CSDVersion[ 0 ] = UNICODE_NULL;
}
Status = NtQuerySystemInformation( SystemBasicInformation,
(PVOID)&BaseSrvpStaticServerData->SysInfo,
sizeof( BaseSrvpStaticServerData->SysInfo ),
NULL
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = BaseSrvInitializeIniFileMappings( BaseSrvpStaticServerData );
if ( !NT_SUCCESS(Status) ){
return Status;
}
BaseSrvpStaticServerData->DefaultSeparateVDM = FALSE;
RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\WOW" );
InitializeObjectAttributes( &Obja,
&NameString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = NtOpenKey( &KeyHandle,
KEY_READ,
&Obja
);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString( &NameString, L"DefaultSeparateVDM" );
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
Status = NtQueryValueKey( KeyHandle,
&NameString,
KeyValuePartialInformation,
KeyValueInformation,
sizeof( ValueBuffer ),
&ResultLength
);
if (NT_SUCCESS(Status)) {
if (KeyValueInformation->Type == REG_DWORD) {
BaseSrvpStaticServerData->DefaultSeparateVDM = *(PULONG)KeyValueInformation->Data != 0;
}
else
if (KeyValueInformation->Type == REG_SZ) {
if (!_wcsicmp( (PWSTR)KeyValueInformation->Data, L"yes" ) ||
!_wcsicmp( (PWSTR)KeyValueInformation->Data, L"1" )) {
BaseSrvpStaticServerData->DefaultSeparateVDM = TRUE;
}
}
}
NtClose( KeyHandle );
}
#ifdef WX86
BaseSrvpStaticServerData->Wx86Enabled = FALSE;
RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\wx86" );
InitializeObjectAttributes( &Obja,
&NameString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey( &KeyHandle,
KEY_READ,
&Obja
);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString( &NameString, L"cmdline" );
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
Status = NtQueryValueKey( KeyHandle,
&NameString,
KeyValuePartialInformation,
KeyValueInformation,
sizeof( ValueBuffer ),
&ResultLength
);
if (NT_SUCCESS(Status)) {
if (KeyValueInformation->Type == REG_SZ &&
*(PWSTR)KeyValueInformation->Data)
{
BaseSrvpStaticServerData->Wx86Enabled = TRUE;
SetupWx86KeyMapping();
}
}
NtClose( KeyHandle );
}
#endif
//
// Following code is direct from Jimk. Why is there a 1k constant
//
PrimarySecurityDescriptor = RtlAllocateHeap( BaseSrvHeap, MAKE_TAG( TMP_TAG ), 1024 );
if ( !PrimarySecurityDescriptor ) {
return STATUS_NO_MEMORY;
}
Status = RtlCreateSecurityDescriptor (
PrimarySecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION1
);
if ( !NT_SUCCESS(Status) ){
return Status;
}
//
// Create an ACL that allows full access to System and partial access to world
//
Status = CreateBaseAcl( &Dacl );
if ( !NT_SUCCESS(Status) ){
return Status;
}
Status = RtlSetDaclSecurityDescriptor (
PrimarySecurityDescriptor,
TRUE, //DaclPresent,
Dacl, //Dacl
FALSE //DaclDefaulted OPTIONAL
);
if ( !NT_SUCCESS(Status) ){
return Status;
}
InitializeObjectAttributes( &Obja,
&UnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
NULL,
PrimarySecurityDescriptor
);
Status = NtCreateDirectoryObject( &BaseSrvNamedObjectDirectory,
DIRECTORY_ALL_ACCESS,
&Obja
);
if ( !NT_SUCCESS(Status) ){
return Status;
}
RtlFreeHeap( BaseSrvHeap, 0, Dacl );
RtlFreeHeap( BaseSrvHeap, 0,PrimarySecurityDescriptor );
BaseSrvVDMInit();
//
// Initialize the shared heap for the NLS information.
//
BaseSrvNLSInit(BaseSrvpStaticServerData);
return( STATUS_SUCCESS );
}
NTSTATUS
BaseClientConnectRoutine(
IN PCSR_PROCESS Process,
IN OUT PVOID ConnectionInfo,
IN OUT PULONG ConnectionInfoLength
)
{
return ( BaseSrvNlsConnect( Process,
ConnectionInfo,
ConnectionInfoLength ) );
}
VOID
BaseClientDisconnectRoutine(
IN PCSR_PROCESS Process
)
{
BaseSrvCleanupVDMResources (Process);
}
ULONG
BaseSrvDefineDosDevice(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_DEFINEDOSDEVICE_MSG a = (PBASE_DEFINEDOSDEVICE_MSG)&m->u.ApiMessageData;
UNICODE_STRING LinkName;
UNICODE_STRING LinkValue;
HANDLE LinkHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
PWSTR Buffer, s, Src, Dst, pchValue;
ULONG cchBuffer, cch;
ULONG cchName, cchValue, cchSrc, cchSrcStr, cchDst;
BOOLEAN QueryNeeded, MatchFound, RevertToSelfNeeded, DeleteRequest;
ULONG ReturnedLength;
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
SECURITY_DESCRIPTOR SecurityDescriptor;
CHAR Acl[256]; // 256 is more than big enough
ULONG AclLength=256;
PSID WorldSid;
cchBuffer = 4096;
Buffer = RtlAllocateHeap( BaseSrvHeap,
MAKE_TAG( TMP_TAG ),
cchBuffer * sizeof( WCHAR )
);
if (Buffer == NULL) {
return (ULONG)STATUS_NO_MEMORY;
}
Status = RtlEnterCriticalSection( &BaseSrvDosDeviceCritSec );
if (!NT_SUCCESS( Status )) {
RtlFreeHeap( BaseSrvHeap, 0, Buffer );
return (ULONG)Status;
}
if (a->Flags & DDD_REMOVE_DEFINITION) {
DeleteRequest = TRUE;
}
else {
DeleteRequest = FALSE;
}
LinkHandle = NULL;
try {
s = Buffer;
cch = cchBuffer;
cchName = _snwprintf( s,
cch,
L"\\??\\%wZ",
&a->DeviceName
);
s += cchName + 1;
cch -= (cchName + 1);
RtlInitUnicodeString( &LinkName, Buffer );
InitializeObjectAttributes( &ObjectAttributes,
&LinkName,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR)NULL
);
QueryNeeded = TRUE;
RevertToSelfNeeded = CsrImpersonateClient( NULL ); // This stacks client contexts
Status = NtOpenSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_QUERY | DELETE,
&ObjectAttributes
);
if (RevertToSelfNeeded) {
CsrRevertToSelf(); // This unstacks client contexts
}
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
LinkHandle = NULL;
if (DeleteRequest) {
if (a->TargetPath.Length == 0) {
Status = STATUS_SUCCESS;
}
leave;
}
QueryNeeded = FALSE;
Status = STATUS_SUCCESS;
}
else
if (!NT_SUCCESS( Status )) {
LinkHandle = NULL;
leave;
}
if (a->TargetPath.Length != 0) {
cchValue = wcslen( Src = a->TargetPath.Buffer );
if ((cchValue + 1) >= cch) {
Status = STATUS_TOO_MANY_NAMES;
leave;
}
RtlMoveMemory( s, Src, (cchValue + 1) * sizeof( WCHAR ) );
pchValue = s;
s += cchValue + 1;
cch -= (cchValue + 1);
}
else {
pchValue = NULL;
cchValue = 0;
}
if (QueryNeeded) {
LinkValue.Length = 0;
LinkValue.MaximumLength = (USHORT)(cch * sizeof( WCHAR ));
LinkValue.Buffer = s;
ReturnedLength = 0;
Status = NtQuerySymbolicLinkObject( LinkHandle,
&LinkValue,
&ReturnedLength
);
if (ReturnedLength == (ULONG)LinkValue.MaximumLength) {
Status = STATUS_BUFFER_OVERFLOW;
}
if (!NT_SUCCESS( Status )) {
leave;
}
s[ ReturnedLength / sizeof( WCHAR ) ] = UNICODE_NULL;
LinkValue.MaximumLength = (USHORT)(ReturnedLength + sizeof( UNICODE_NULL ));
}
else {
if (DeleteRequest) {
RtlInitUnicodeString( &LinkValue, NULL );
}
else {
RtlInitUnicodeString( &LinkValue, s - (cchValue + 1) );
}
}
if (LinkHandle != NULL) {
Status = NtMakeTemporaryObject( LinkHandle );
NtClose( LinkHandle );
LinkHandle = NULL;
}
if (!NT_SUCCESS( Status )) {
leave;
}
if (DeleteRequest) {
Src = Dst = LinkValue.Buffer;
cchSrc = LinkValue.MaximumLength / sizeof( WCHAR );
cchDst = 0;
MatchFound = FALSE;
while (*Src) {
cchSrcStr = 0;
s = Src;
while (*Src++) {
cchSrcStr++;
}
if (!MatchFound) {
if ((a->Flags & DDD_EXACT_MATCH_ON_REMOVE &&
cchValue == cchSrcStr &&
!_wcsicmp( s, pchValue )
) ||
(!(a->Flags & DDD_EXACT_MATCH_ON_REMOVE) &&
(cchValue == 0 || !_wcsnicmp( s, pchValue, cchValue ))
)
) {
MatchFound = TRUE;
}
else {
goto CopySrc;
}
}
else {
CopySrc:
if (s != Dst) {
RtlMoveMemory( Dst, s, (cchSrcStr + 1) * sizeof( WCHAR ) );
}
Dst += cchSrcStr + 1;
}
}
*Dst++ = UNICODE_NULL;
LinkValue.Length = wcslen( LinkValue.Buffer ) * sizeof( UNICODE_NULL );
if (LinkValue.Length != 0) {
LinkValue.MaximumLength = (USHORT)((PCHAR)Dst - (PCHAR)LinkValue.Buffer);
}
}
else
if (QueryNeeded) {
LinkValue.Buffer -= (cchValue + 1);
LinkValue.Length = (USHORT)(cchValue * sizeof( WCHAR ));
LinkValue.MaximumLength += LinkValue.Length + sizeof( UNICODE_NULL );
}
//
// Create a new value for the link.
//
if (LinkValue.Length != 0) {
//
// Create the new symbolic link object with a security descriptor
// that grants world SYMBOLIC_LINK_QUERY access.
//
Status = RtlAllocateAndInitializeSid( &WorldSidAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&WorldSid
);
if (!NT_SUCCESS( Status )) {
leave;
}
Status = RtlCreateSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
ASSERT(NT_SUCCESS(Status));
Status = RtlCreateAcl( (PACL)Acl,
AclLength,
ACL_REVISION2
);
ASSERT(NT_SUCCESS(Status));
Status = RtlAddAccessAllowedAce( (PACL)Acl,
ACL_REVISION2,
SYMBOLIC_LINK_QUERY | DELETE,
WorldSid
);
ASSERT(NT_SUCCESS(Status));
//
// Sid has been copied into the ACL
//
RtlFreeSid( WorldSid );
Status = RtlSetDaclSecurityDescriptor ( &SecurityDescriptor,
TRUE,
(PACL)Acl,
TRUE // Don't over-ride inherited protection
);
ASSERT(NT_SUCCESS(Status));
ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
ObjectAttributes.Attributes |= OBJ_PERMANENT;
Status = NtCreateSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&LinkValue
);
if (NT_SUCCESS( Status )) {
NtClose( LinkHandle );
if (DeleteRequest && !MatchFound) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
LinkHandle = NULL;
}
}
finally {
if (LinkHandle != NULL) {
NtClose( LinkHandle );
}
RtlFreeHeap( BaseSrvHeap, 0, Buffer );
RtlLeaveCriticalSection( &BaseSrvDosDeviceCritSec );
}
return (ULONG)Status;
ReplyStatus; // get rid of unreferenced parameter warning message
}
NTSTATUS
CreateBaseAcl(
PACL *Dacl
)
/*++
Routine Description:
Creates the ACL for the BaseNamedObjects directory.
Arguments:
Dacl - Supplies a pointer to a PDACL that will be filled in with
the resultant ACL (allocated out of the process heap). The caller
is responsible for freeing this memory.
Return Value:
STATUS_NO_MEMORY or Success
--*/
{
PSID LocalSystemSid;
PSID WorldSid;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
NTSTATUS Status;
ACCESS_MASK WorldAccess;
ACCESS_MASK SystemAccess;
ULONG AclLength;
Status = RtlAllocateAndInitializeSid(
&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&LocalSystemSid
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAllocateAndInitializeSid(
&WorldAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&WorldSid
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
WorldAccess = DIRECTORY_ALL_ACCESS & ~(WRITE_OWNER | WRITE_DAC | DELETE );
SystemAccess = DIRECTORY_ALL_ACCESS;
AclLength = sizeof( ACL ) +
2 * sizeof( ACCESS_ALLOWED_ACE ) +
RtlLengthSid( LocalSystemSid ) +
RtlLengthSid( WorldSid );
*Dacl = RtlAllocateHeap( BaseSrvHeap, MAKE_TAG( TMP_TAG ), AclLength );
if (*Dacl == NULL) {
return( STATUS_NO_MEMORY );
}
Status = RtlCreateAcl (*Dacl, AclLength, ACL_REVISION2 );
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAddAccessAllowedAce ( *Dacl, ACL_REVISION2, WorldAccess, WorldSid );
if (NT_SUCCESS( Status )) {
Status = RtlAddAccessAllowedAce ( *Dacl, ACL_REVISION2, SystemAccess, LocalSystemSid );
}
//
// These have been copied in, free them.
//
RtlFreeHeap( BaseSrvHeap, 0, LocalSystemSid );
RtlFreeHeap( BaseSrvHeap, 0, WorldSid );
return( Status );
}