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