windows-nt/Source/XPSP1/NT/base/subsys/sm/server/smutil.c
2020-09-26 16:20:57 +08:00

426 lines
11 KiB
C

/*++
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;
RtlMoveMemory( 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;
RtlMoveMemory( 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;
WCHAR 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,
VALUE_BUFFER_SIZE,
&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);
}