/*++ Copyright (c) 1991 Microsoft Corporation Module Name: Predefh.c Abstract: This module contains routines for opening the Win32 Registry API's predefined handles. A predefined handle is used as a root to an absolute or relative sub-tree in the real Nt Registry. An absolute predefined handle maps to a specific key within the Registry. A relative predefined handle maps to a key relative to some additional information such as the current user. Predefined handles are strictly part of the Win32 Registry API. The Nt Registry API knows nothing about them. A predefined handle can be used anywhere that a non-predefined handle (i.e. one returned from RegCreateKey(), RegOpenKey() or RegConnectRegistry()) can be used. Author: David J. Gilman (davegi) 15-Nov-1991 --*/ #include #include "regrpc.h" #include "localreg.h" #include "regclass.h" #include "ntconreg.h" #include "regsec.h" #ifdef LOCAL #include "tsappcmp.h" #if defined(LEAK_TRACK) #include "regleak.h" #endif // LEAK_TRACK #endif // // Determine the length of a Unicode string w/o the trailing NULL. // #define LENGTH( str ) ( sizeof( str ) - sizeof( UNICODE_NULL )) // // Nt Registry name space. // #define MACHINE L"\\REGISTRY\\MACHINE" #define USER L"\\REGISTRY\\USER" #define CLASSES L"\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" #define CURRENTCONFIG L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT" extern const UNICODE_STRING MachineStringKey = { LENGTH( MACHINE ), LENGTH( MACHINE ), MACHINE }; extern const UNICODE_STRING UserStringKey = { LENGTH( USER ), LENGTH( USER ), USER }; extern const UNICODE_STRING ClassesStringKey = { LENGTH( CLASSES ), LENGTH( CLASSES ), CLASSES }; extern const UNICODE_STRING CurrentConfigStringKey = { LENGTH( CURRENTCONFIG ), LENGTH( CURRENTCONFIG ), CURRENTCONFIG }; HANDLE RestrictedMachineHandle = NULL; NTSTATUS InitSecurityAcls(PSECURITY_DESCRIPTOR *SecurityDescriptor) /*++ Routine Description: Gives GENERIC_ALL to admins and denies WRITE_OWNER | WRITE_DAC from everyone Arguments: Return Value: --*/ { SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY; PSID BuiltInAdministrators = NULL; PSID Everyone = NULL; NTSTATUS Status; ULONG AclSize; ACL *Acl; *SecurityDescriptor = NULL; Status = RtlAllocateAndInitializeSid( &WorldAuthority, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &Everyone ); if( !NT_SUCCESS(Status) ) { goto Exit; } Status = RtlAllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &BuiltInAdministrators ); if( !NT_SUCCESS(Status) ) { goto Exit; } AclSize = sizeof (ACL) + (2 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) + GetLengthSid(BuiltInAdministrators) + GetLengthSid(Everyone); *SecurityDescriptor = (PSECURITY_DESCRIPTOR)RtlAllocateHeap( RtlProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize); if (!*SecurityDescriptor) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } Acl = (ACL *)((BYTE *)(*SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH); Status = RtlCreateAcl( Acl, AclSize, ACL_REVISION); if( !NT_SUCCESS(Status) ) { goto Exit; } Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, (KEY_ALL_ACCESS & ~(WRITE_OWNER | WRITE_DAC)), Everyone); if( !NT_SUCCESS(Status) ) { goto Exit; } Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, GENERIC_ALL, BuiltInAdministrators); if( !NT_SUCCESS(Status) ) { goto Exit; } Status = RtlCreateSecurityDescriptor( *SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if( !NT_SUCCESS(Status) ) { goto Exit; } Status = RtlSetDaclSecurityDescriptor( *SecurityDescriptor, TRUE, Acl, FALSE); Exit: if( Everyone ) { RtlFreeSid( Everyone ); } if( BuiltInAdministrators ) { RtlFreeSid( BuiltInAdministrators ); } return Status; } error_status_t OpenClassesRoot( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_CLASSES_ROOT predefined handle. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key \REGISTRY\MACHINE\SOFTWARE\CLASSES. Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; OBJECT_ATTRIBUTES Obja; NTSTATUS Status; UNICODE_STRING UsersHive; UNICODE_STRING UsersMergedHive; UNREFERENCED_PARAMETER( ServerName ); // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); #ifdef LOCAL // // Multiuser CLASSES key so each user has their own key. If opening // CLASSES in execute mode - open it under HKEY_CURRENT_USER else // just let it fall thru here and open the global one. // if (gpfnTermsrvOpenUserClasses) { Status = gpfnTermsrvOpenUserClasses(samDesired,phKey); } else { *phKey = NULL; } if (!(*phKey)) { #endif // LOCAL // // Initialize the SECURITY_DESCRIPTOR. // Status = InitSecurityAcls(&SecurityDescriptor); if( ! NT_SUCCESS( Status )) { goto error_exit; } #ifdef LOCAL if (gbCombinedClasses) { // first try for a per-user HKCR Status = OpenCombinedClassesRoot( samDesired, phKey ); if ( NT_SUCCESS( Status ) ) { goto error_exit; } } #endif // // Initialize the OBJECT_ATTRIBUTES structure so that it creates // (opens) the key "\REGISTRY\MACHINE\SOFTWARE\CLASSES" with a Security // Descriptor that allows everyone complete access. // InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&ClassesStringKey, OBJ_CASE_INSENSITIVE, NULL, SecurityDescriptor ); Status = NtCreateKey( phKey, samDesired, // MAXIMUM_ALLOWED, &Obja, 0, NULL, REG_OPTION_NON_VOLATILE, NULL ); #ifdef LOCAL } #endif // LOCAL #if DBG if( ! NT_SUCCESS( Status )) { DbgPrint( "Winreg Server: " "Creating HKEY_CLASSES_ROOT failed, status = 0x%x\n", Status ); } #endif error_exit: if( SecurityDescriptor != NULL ) { RtlFreeHeap( RtlProcessHeap(), 0, SecurityDescriptor ); } RPC_REVERT_TO_SELF(); return (error_status_t)RtlNtStatusToDosError( Status ); } error_status_t OpenCurrentUser( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_CURRENT_USER predefined handle. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key \REGISTRY\USER\*. Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER( ServerName ); // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); // // Open the registry key. // Status = RtlOpenCurrentUser( samDesired, /* MAXIMUM_ALLOWED, */ phKey ); RPC_REVERT_TO_SELF(); // // Map the returned status // return (error_status_t)RtlNtStatusToDosError( Status ); } error_status_t OpenLocalMachine( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempt to open the the HKEY_LOCAL_MACHINE predefined handle. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key \REGISTRY\MACHINE. Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { OBJECT_ATTRIBUTES Obja; NTSTATUS Status; UNREFERENCED_PARAMETER( ServerName ); // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&MachineStringKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( phKey, samDesired, // MAXIMUM_ALLOWED, &Obja ); #if DBG if( ! NT_SUCCESS( Status )) { DbgPrint( "Winreg Server: " "Opening HKEY_LOCAL_MACHINE failed, status = 0x%x\n", Status ); } #endif if ( NT_SUCCESS( Status ) ) { if (! REGSEC_CHECK_REMOTE( phKey ) ) { ASSERT( RestrictedMachineHandle != NULL ); NtClose(*phKey); *phKey = REGSEC_FLAG_HANDLE( RestrictedMachineHandle, CHECK_MACHINE_PATHS ); } } RPC_REVERT_TO_SELF(); return (error_status_t)RtlNtStatusToDosError( Status ); } error_status_t OpenUsers( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_USERS predefined handle. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key \REGISTRY\USER. Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { OBJECT_ATTRIBUTES Obja; NTSTATUS Status; UNREFERENCED_PARAMETER( ServerName ); // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&UserStringKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( phKey, samDesired, // MAXIMUM_ALLOWED, &Obja ); #if DBG if( ! NT_SUCCESS( Status )) { DbgPrint( "Winreg Server: " "Opening HKEY_USERS failed, status = 0x%x\n", Status ); } #endif /* if ( NT_SUCCESS( Status ) ) { if (! REGSEC_CHECK_REMOTE( phKey ) ) { *phKey = REGSEC_FLAG_HANDLE( *phKey, CHECK_USER_PATHS ); } } */ RPC_REVERT_TO_SELF(); return (error_status_t)RtlNtStatusToDosError( Status ); } error_status_t OpenCurrentConfig( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_CURRENT_CONFIG predefined handle. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key \REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\HARDWARE PROFILES\CURRENT Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { OBJECT_ATTRIBUTES Obja; NTSTATUS Status; UNREFERENCED_PARAMETER( ServerName ); // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&CurrentConfigStringKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( phKey, samDesired, // MAXIMUM_ALLOWED, &Obja ); #if DBG if( ! NT_SUCCESS( Status )) { DbgPrint( "Winreg Server: " "Opening HKEY_CURRENT_CONFIG failed, status = 0x%x\n", Status ); } #endif RPC_REVERT_TO_SELF(); return (error_status_t)RtlNtStatusToDosError( Status ); } error_status_t OpenPerformanceData( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_PERFORMANCE_DATA predefined handle. Arguments: ServerName - Not used. samDesired - Not used. phKey - Returns a the predefined handle HKEY_PERFORMANCE_DATA. Return Value: Returns ERROR_SUCCESS (0) for success; or a DOS (not NT) error-code for failure. --*/ { NTSTATUS status; if ( 0 ) { DBG_UNREFERENCED_PARAMETER(ServerName); DBG_UNREFERENCED_PARAMETER(samDesired); } // // Impersonate the client. // RPC_IMPERSONATE_CLIENT( NULL ); if ( ! REGSEC_CHECK_PERF( phKey ) ) { RPC_REVERT_TO_SELF(); return( ERROR_ACCESS_DENIED ); } // Move lodctr/unlodctr access check to part of PerfOpenKey() status = PerfOpenKey( HKEY_PERFORMANCE_DATA ); RPC_REVERT_TO_SELF(); *phKey = (RPC_HKEY) HKEY_PERFORMANCE_DATA; return ERROR_SUCCESS; } error_status_t OpenPerformanceText( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_PERFORMANCE_TEXT predefined handle. Arguments: ServerName - Not used. samDesired - Not used. phKey - Returns the predefined handle HKEY_PERFORMANCE_TEXT. Return Value: Returns ERROR_SUCCESS (0) for success; or a DOS (not NT) error-code for failure. --*/ { error_status_t Status = ERROR_SUCCESS; // No need to call OpenPerformanceData for getting text (HWC 4/1994) // Status = OpenPerformanceData(ServerName, samDesired, phKey); // if (Status==ERROR_SUCCESS) { *phKey = HKEY_PERFORMANCE_TEXT; // } return(Status); } error_status_t OpenPerformanceNlsText( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_PERFORMANCE_TEXT predefined handle. Arguments: ServerName - Not used. samDesired - Not used. phKey - Returns the predefined handle HKEY_PERFORMANCE_NLSTEXT. Return Value: Returns ERROR_SUCCESS (0) for success; or a DOS (not NT) error-code for failure. --*/ { error_status_t Status = ERROR_SUCCESS; // No need to call OpenPerformanceData for getting text (HWC 4/1994) // Status = OpenPerformanceData(ServerName, samDesired, phKey); // if (Status==ERROR_SUCCESS) { *phKey = HKEY_PERFORMANCE_NLSTEXT; // } return(Status); } error_status_t OpenDynData( IN PREGISTRY_SERVER_NAME ServerName, IN REGSAM samDesired, OUT PRPC_HKEY phKey ) /*++ Routine Description: Attempts to open the the HKEY_DYN_DATA predefined handle. There is currently no HKEY_DYN_DATA on NT, thus this function always returns ERROR_CALL_NOT_IMPLEMENTED. Arguments: ServerName - Not used. samDesired - This access mask describes the desired security access for the key. phKey - Returns a handle to the key HKEY_DYN_DATA Return Value: Returns ERROR_SUCCESS (0) for success; error-code for failure. --*/ { return((error_status_t)ERROR_CALL_NOT_IMPLEMENTED); } // // Default ("fake") handle returned to all check_machine_paths-like connections // NTSTATUS OpenMachineKey(PHANDLE phKey) { OBJECT_ATTRIBUTES Obja; NTSTATUS Status; InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&MachineStringKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( phKey, MAXIMUM_ALLOWED, &Obja ); return Status; } NTSTATUS InitRestrictedMachineHandle() { return OpenMachineKey(&RestrictedMachineHandle); } VOID CleanupRestrictedMachineHandle() { if( RestrictedMachineHandle != NULL ) { NtClose(RestrictedMachineHandle); RestrictedMachineHandle = NULL; } }