You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
11 KiB
424 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smutil.c
|
|
|
|
Abstract:
|
|
|
|
Session Manager Utility Functions
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 04-Oct-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "smsrvp.h"
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SmpSaveRegistryValue(
|
|
IN OUT PLIST_ENTRY ListHead,
|
|
IN PWSTR Name,
|
|
IN PWSTR Value OPTIONAL,
|
|
IN BOOLEAN CheckForDuplicate
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING UnicodeName;
|
|
UNICODE_STRING UnicodeValue;
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlInitUnicodeString( &UnicodeName, Name );
|
|
RtlInitUnicodeString( &UnicodeValue, Value );
|
|
if (CheckForDuplicate) {
|
|
Next = ListHead->Flink;
|
|
p = NULL;
|
|
while ( Next != ListHead ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) {
|
|
if ((!ARGUMENT_PRESENT( Value ) && p->Value.Buffer == NULL) ||
|
|
(ARGUMENT_PRESENT( Value ) &&
|
|
!RtlCompareUnicodeString( &p->Value, &UnicodeValue, TRUE )
|
|
)
|
|
) {
|
|
return( STATUS_OBJECT_NAME_EXISTS );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
p = NULL;
|
|
}
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
|
|
if (p == NULL) {
|
|
p = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), sizeof( *p ) + UnicodeName.MaximumLength );
|
|
if (p == NULL) {
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
InitializeListHead( &p->Entry );
|
|
p->Name.Buffer = (PWSTR)(p+1);
|
|
p->Name.Length = UnicodeName.Length;
|
|
p->Name.MaximumLength = UnicodeName.MaximumLength;
|
|
p->AnsiValue = NULL;
|
|
RtlCopyMemory( p->Name.Buffer,
|
|
UnicodeName.Buffer,
|
|
UnicodeName.MaximumLength
|
|
);
|
|
p->Value.Buffer = NULL;
|
|
InsertTailList( ListHead, &p->Entry );
|
|
}
|
|
|
|
if (p->Value.Buffer != NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer );
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( Value )) {
|
|
p->Value.Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
UnicodeValue.MaximumLength
|
|
);
|
|
if (p->Value.Buffer == NULL) {
|
|
RemoveEntryList( &p->Entry );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
p->Value.Length = UnicodeValue.Length;
|
|
p->Value.MaximumLength = UnicodeValue.MaximumLength;
|
|
RtlCopyMemory( p->Value.Buffer,
|
|
UnicodeValue.Buffer,
|
|
UnicodeValue.MaximumLength
|
|
);
|
|
p->AnsiValue = (LPSTR)RtlAllocateHeap( RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
(UnicodeValue.Length / sizeof( WCHAR )) + 1
|
|
);
|
|
if (p->AnsiValue == NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer );
|
|
RemoveEntryList( &p->Entry );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
AnsiString.Buffer = p->AnsiValue;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = (UnicodeValue.Length / sizeof( WCHAR )) + 1;
|
|
RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeValue, FALSE );
|
|
} else {
|
|
RtlInitUnicodeString( &p->Value, NULL );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
PSMP_REGISTRY_VALUE
|
|
SmpFindRegistryValue(
|
|
IN PLIST_ENTRY ListHead,
|
|
IN PWSTR Name
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING UnicodeName;
|
|
|
|
RtlInitUnicodeString( &UnicodeName, Name );
|
|
Next = ListHead->Flink;
|
|
while ( Next != ListHead ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) {
|
|
return( p );
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
typedef struct _SMP_ACQUIRE_STATE {
|
|
HANDLE Token;
|
|
PTOKEN_PRIVILEGES OldPrivileges;
|
|
PTOKEN_PRIVILEGES NewPrivileges;
|
|
UCHAR OldPrivBuffer[ 1024 ];
|
|
} SMP_ACQUIRE_STATE, *PSMP_ACQUIRE_STATE;
|
|
|
|
NTSTATUS
|
|
SmpAcquirePrivilege(
|
|
ULONG Privilege,
|
|
PVOID *ReturnedState
|
|
)
|
|
{
|
|
PSMP_ACQUIRE_STATE State;
|
|
ULONG cbNeeded;
|
|
LUID LuidPrivilege;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Make sure we have access to adjust and to get the old token privileges.
|
|
//
|
|
|
|
*ReturnedState = NULL;
|
|
State = RtlAllocateHeap( RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
sizeof(SMP_ACQUIRE_STATE) +
|
|
sizeof(TOKEN_PRIVILEGES) +
|
|
(1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)
|
|
);
|
|
if (State == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
Status = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&State->Token
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return Status;
|
|
}
|
|
|
|
State->NewPrivileges = (PTOKEN_PRIVILEGES)(State+1);
|
|
State->OldPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer);
|
|
|
|
//
|
|
// Initialize the privilege adjustment structure.
|
|
//
|
|
|
|
LuidPrivilege = RtlConvertUlongToLuid(Privilege);
|
|
State->NewPrivileges->PrivilegeCount = 1;
|
|
State->NewPrivileges->Privileges[0].Luid = LuidPrivilege;
|
|
State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
//
|
|
// Enable the privilege.
|
|
//
|
|
|
|
cbNeeded = sizeof( State->OldPrivBuffer );
|
|
Status = NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->NewPrivileges,
|
|
cbNeeded,
|
|
State->OldPrivileges,
|
|
&cbNeeded
|
|
);
|
|
|
|
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
State->OldPrivileges = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cbNeeded );
|
|
if (State->OldPrivileges == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
else {
|
|
Status = NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->NewPrivileges,
|
|
cbNeeded,
|
|
State->OldPrivileges,
|
|
&cbNeeded
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// STATUS_NOT_ALL_ASSIGNED means that the privilege isn't
|
|
// in the token, so we can't proceed.
|
|
//
|
|
// This is a warning level status, so map it to an error status.
|
|
//
|
|
|
|
if (Status == STATUS_NOT_ALL_ASSIGNED) {
|
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
|
|
}
|
|
|
|
NtClose( State->Token );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return Status;
|
|
}
|
|
|
|
*ReturnedState = State;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpReleasePrivilege(
|
|
PVOID StatePointer
|
|
)
|
|
{
|
|
PSMP_ACQUIRE_STATE State = (PSMP_ACQUIRE_STATE)StatePointer;
|
|
|
|
NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->OldPrivileges,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
|
|
}
|
|
|
|
NtClose( State->Token );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return;
|
|
}
|
|
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
VOID
|
|
SmpDumpQuery(
|
|
IN PWSTR ModId,
|
|
IN PCHAR RoutineName,
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength
|
|
)
|
|
{
|
|
PWSTR s;
|
|
|
|
if (ValueName == NULL) {
|
|
DbgPrint( "%ws: SmpConfigure%s( %ws )\n", ModId, RoutineName );
|
|
return;
|
|
}
|
|
|
|
if (ValueData == NULL) {
|
|
DbgPrint( "%ws: SmpConfigure%s( %ws, %ws NULL ValueData )\n", ModId, RoutineName, ValueName );
|
|
return;
|
|
}
|
|
|
|
s = (PWSTR)ValueData;
|
|
DbgPrint( "%ws: SmpConfigure%s( %ws, %u, (%u) ", ModId, RoutineName, ValueName, ValueType, ValueLength );
|
|
if (ValueType == REG_SZ || ValueType == REG_EXPAND_SZ || ValueType == REG_MULTI_SZ) {
|
|
while (*s) {
|
|
if (s != (PWSTR)ValueData) {
|
|
DbgPrint( ", " );
|
|
}
|
|
DbgPrint( "'%ws'", s );
|
|
while(*s++) {
|
|
}
|
|
if (ValueType != REG_MULTI_SZ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DbgPrint( "*** non-string data (%08lx)", *(PULONG)ValueData );
|
|
}
|
|
|
|
DbgPrint( "\n" );
|
|
}
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
SmpQueryNtGlobalFlag(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries the registry to get the current NtGlobalFlag value.
|
|
|
|
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager:GlobalFlag
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Global flag value or zero.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Key;
|
|
UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
ULONG ValueLength;
|
|
|
|
//
|
|
// Open the registry key.
|
|
//
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't open session manager key: 0x%x\n", Status));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Query the key value.
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, L"GlobalFlag");
|
|
Status = NtQueryValueKey(
|
|
Key,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
sizeof (ValueBuffer),
|
|
&ValueLength
|
|
);
|
|
|
|
ASSERT(ValueLength < VALUE_BUFFER_SIZE);
|
|
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't query value key: 0x%x\n", Status));
|
|
return 0;
|
|
}
|
|
|
|
return *((PULONG)&KeyValueInfo->Data);
|
|
}
|