/*++ Copyright (c) 1996 Microsoft Corporation Module Name: applyacl.c Abstract: Routines to apply default ACLs to system files and directories during setup. Author: Ted Miller (tedm) 16-Feb-1996 Revision History: --*/ #include "setupp.h" #pragma hdrstop #define MAXULONG 0xffffffff // // Universal well known SIDs // PSID NullSid; PSID WorldSid; PSID LocalSid; PSID CreatorOwnerSid; PSID CreatorGroupSid; // // SIDs defined by NT // PSID DialupSid; PSID NetworkSid; PSID BatchSid; PSID InteractiveSid; PSID ServiceSid; PSID LocalSystemSid; PSID AliasAdminsSid; PSID AliasUsersSid; PSID AliasGuestsSid; PSID AliasPowerUsersSid; PSID AliasAccountOpsSid; PSID AliasSystemOpsSid; PSID AliasPrintOpsSid; PSID AliasBackupOpsSid; PSID AliasReplicatorSid; typedef struct _ACE_DATA { ACCESS_MASK AccessMask; PSID *Sid; UCHAR AceType; UCHAR AceFlags; } ACE_DATA, *PACE_DATA; // // This structure is valid for access allowed, access denied, audit, // and alarm ACEs. // typedef struct _ACE { ACE_HEADER Header; ACCESS_MASK Mask; // // The SID follows in the buffer // } ACE, *PACE; // // Number of ACEs currently defined for files and directories. // #define DIRS_AND_FILES_ACE_COUNT 19 // // Table describing the data to put into each ACE. // // This table will be read during initialization and used to construct a // series of ACEs. The index of each ACE in the Aces array defined below // corresponds to the ordinals used in the ACL section of perms.inf // ACE_DATA AceDataTableForDirsAndFiles[DIRS_AND_FILES_ACE_COUNT] = { // // Index 0 is unused // { 0,NULL,0,0 }, // // ACE 1 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &AliasAccountOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 2 // (for files and directories) // { GENERIC_ALL, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 3 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 4 // (for files and directories) // { GENERIC_ALL, &CreatorOwnerSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 5 // (for files and directories) // { GENERIC_ALL, &NetworkSid, ACCESS_DENIED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 6 // (for files and directories) // { GENERIC_ALL, &AliasPrintOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 7 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &AliasReplicatorSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 8 // (for files and directories) // { GENERIC_READ | GENERIC_EXECUTE, &AliasReplicatorSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 9 // (for files and directories) // { GENERIC_ALL, &AliasSystemOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 10 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &AliasSystemOpsSid, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE }, // // ACE 11 // (for files and directories) // { GENERIC_ALL, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 12 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 13 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE }, // // ACE 14 // (for files and directories) // { GENERIC_READ | GENERIC_EXECUTE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 15 // (for files and directories) // { GENERIC_READ | GENERIC_EXECUTE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE }, // // ACE 16 // (for files and directories) // { GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE }, // // ACE 17 // (for files and directories) // { GENERIC_ALL, &LocalSystemSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE }, // // ACE 18 // (for files and directories) // { GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, &AliasPowerUsersSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE } }; // // Array of ACEs to be applied to the objects (files and directories). // They will be initialized during program startup based on the data in the // AceDataTable. The index of each element corresponds to the // ordinals used in the [ACL] section of perms.inf. // PACE AcesForDirsAndFiles[DIRS_AND_FILES_ACE_COUNT]; // // Array that contains the size of each ACE in the // array AcesForDirsAndFiles. These sizes are needed // in order to allocate a buffer of the right size // when we build an ACL. // ULONG AceSizesForDirsAndFiles[DIRS_AND_FILES_ACE_COUNT]; VOID TearDownAces( IN OUT PACE* AcesArray, IN ULONG ArrayCount ); VOID TearDownSids( VOID ); DWORD InitializeSids( VOID ) /*++ Routine Description: This function initializes the global variables used by and exposed by security. Arguments: None. Return Value: Win32 error indicating outcome. --*/ { SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; BOOL b = TRUE; // // Ensure the SIDs are in a well-known state // NullSid = NULL; WorldSid = NULL; LocalSid = NULL; CreatorOwnerSid = NULL; CreatorGroupSid = NULL; DialupSid = NULL; NetworkSid = NULL; BatchSid = NULL; InteractiveSid = NULL; ServiceSid = NULL; LocalSystemSid = NULL; AliasAdminsSid = NULL; AliasUsersSid = NULL; AliasGuestsSid = NULL; AliasPowerUsersSid = NULL; AliasAccountOpsSid = NULL; AliasSystemOpsSid = NULL; AliasPrintOpsSid = NULL; AliasBackupOpsSid = NULL; AliasReplicatorSid = NULL; // // Allocate and initialize the universal SIDs // b = b && AllocateAndInitializeSid( &NullSidAuthority, 1, SECURITY_NULL_RID, 0,0,0,0,0,0,0, &NullSid ); b = b && AllocateAndInitializeSid( &WorldSidAuthority, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &WorldSid ); b = b && AllocateAndInitializeSid( &LocalSidAuthority, 1, SECURITY_LOCAL_RID, 0,0,0,0,0,0,0, &LocalSid ); b = b && AllocateAndInitializeSid( &CreatorSidAuthority, 1, SECURITY_CREATOR_OWNER_RID, 0,0,0,0,0,0,0, &CreatorOwnerSid ); b = b && AllocateAndInitializeSid( &CreatorSidAuthority, 1, SECURITY_CREATOR_GROUP_RID, 0,0,0,0,0,0,0, &CreatorGroupSid ); // // Allocate and initialize the NT defined SIDs // b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_DIALUP_RID, 0,0,0,0,0,0,0, &DialupSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_NETWORK_RID, 0,0,0,0,0,0,0, &NetworkSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_BATCH_RID, 0,0,0,0,0,0,0, &BatchSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_INTERACTIVE_RID, 0,0,0,0,0,0,0, &InteractiveSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_SERVICE_RID, 0,0,0,0,0,0,0, &ServiceSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &LocalSystemSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &AliasAdminsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0,0,0,0,0,0, &AliasUsersSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0,0,0,0,0,0, &AliasGuestsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0,0,0,0,0,0, &AliasPowerUsersSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS, 0,0,0,0,0,0, &AliasAccountOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS, 0,0,0,0,0,0, &AliasSystemOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS, 0,0,0,0,0,0, &AliasPrintOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS, 0,0,0,0,0,0, &AliasBackupOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR, 0,0,0,0,0,0, &AliasReplicatorSid ); if(!b) { TearDownSids(); } return(b ? NO_ERROR : GetLastError()); } VOID TearDownSids( VOID ) { if(NullSid) { FreeSid(NullSid); } if(WorldSid) { FreeSid(WorldSid); } if(LocalSid) { FreeSid(LocalSid); } if(CreatorOwnerSid) { FreeSid(CreatorOwnerSid); } if(CreatorGroupSid) { FreeSid(CreatorGroupSid); } if(DialupSid) { FreeSid(DialupSid); } if(NetworkSid) { FreeSid(NetworkSid); } if(BatchSid) { FreeSid(BatchSid); } if(InteractiveSid) { FreeSid(InteractiveSid); } if(ServiceSid) { FreeSid(ServiceSid); } if(LocalSystemSid) { FreeSid(LocalSystemSid); } if(AliasAdminsSid) { FreeSid(AliasAdminsSid); } if(AliasUsersSid) { FreeSid(AliasUsersSid); } if(AliasGuestsSid) { FreeSid(AliasGuestsSid); } if(AliasPowerUsersSid) { FreeSid(AliasPowerUsersSid); } if(AliasAccountOpsSid) { FreeSid(AliasAccountOpsSid); } if(AliasSystemOpsSid) { FreeSid(AliasSystemOpsSid); } if(AliasPrintOpsSid) { FreeSid(AliasPrintOpsSid); } if(AliasBackupOpsSid) { FreeSid(AliasBackupOpsSid); } if(AliasReplicatorSid) { FreeSid(AliasReplicatorSid); } } DWORD InitializeAces( IN OUT PACE_DATA DataTable, IN OUT PACE* AcesArray, IN OUT PULONG AceSizesArray, IN ULONG ArrayCount ) /*++ Routine Description: Initializes the array of ACEs as described in the DataTable Arguments: DataTable - Pointer to the array that contains the data describing each ACE. AcesArray - Array that will contain the ACEs. AceSizesArray - Array that contains the sizes for each ACE. ArrayCount - Number of elements in each array. Return Value: Win32 error code indicating outcome. --*/ { unsigned u; DWORD Length; DWORD rc; BOOL b; DWORD SidLength; // // Initialize to a known state. // ZeroMemory(AcesArray,ArrayCount*sizeof(PACE)); // // Create ACEs for each item in the data table. // This involves merging the ace data with the SID data, which // are initialized in an earlier step. // for(u=1; uHeader.AceType = DataTable[u].AceType; AcesArray[u]->Header.AceFlags = DataTable[u].AceFlags; AcesArray[u]->Header.AceSize = (WORD)Length; AcesArray[u]->Mask = DataTable[u].AccessMask; b = CopySid( SidLength, // Length - sizeof(ACE) + sizeof(ULONG), (PUCHAR)AcesArray[u] + sizeof(ACE), *(DataTable[u].Sid) ); if(!b) { rc = GetLastError(); TearDownAces(AcesArray, ArrayCount); return(rc); } } return(NO_ERROR); } VOID TearDownAces( IN OUT PACE* AcesArray, IN ULONG ArrayCount ) /*++ Routine Description: Destroys the array of ACEs as described in the DataTable Arguments: None Return Value: None --*/ { unsigned u; for(u=1; u= DIRS_AND_FILES_ACE_COUNT)) { return(ERROR_INVALID_DATA); } b = AddAce( Acl, ACL_REVISION2, MAXULONG, AcesForDirsAndFiles[AceIndex], AcesForDirsAndFiles[AceIndex]->Header.AceSize ); // // Track first error we encounter. // if(!b) { rc = GetLastError(); } } if(rc != NO_ERROR) { return(rc); } // // Truncate the ACL, since only a fraction of the size we originally // allocated for it is likely to be in use. // if(!GetAclInformation(Acl,&AclSizeInfo,sizeof(ACL_SIZE_INFORMATION),AclSizeInformation)) { return(GetLastError()); } Acl->AclSize = (WORD)AclSizeInfo.AclBytesInUse; // // Add the ACL to the security descriptor as the DACL // if(!SetSecurityDescriptorDacl(&SecurityDescriptor,TRUE,Acl,FALSE)) { return(GetLastError()); } // // Finally, apply the security descriptor. // rc = SetFileSecurity(FullPath,DACL_SECURITY_INFORMATION,&SecurityDescriptor) ? NO_ERROR : GetLastError(); return(rc); } DWORD ApplySecurityToRepairInfo( ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD d, TempError; WCHAR Directory[MAX_PATH]; BOOL SetAclsNt; DWORD FsFlags; DWORD Result; BOOL b; ULONG Count; PWSTR Files[] = { L"sam", L"security", L"software", L"system", L"default", L"ntuser.dat", L"sam._", L"security._", L"software._", L"system._", L"default._", L"ntuser.da_" }; // // Get the file system of the system drive. // On x86 get the file system of the system partition. // d = NO_ERROR; SetAclsNt = FALSE; Result = GetWindowsDirectory(Directory,MAX_PATH); if(Result == 0) { MYASSERT(FALSE); return( GetLastError()); } Directory[3] = 0; // // ApplySecurity to directories and files, if needed // b = GetVolumeInformation(Directory,NULL,0,NULL,NULL,&FsFlags,NULL,0); if(b && (FsFlags & FS_PERSISTENT_ACLS)) { SetAclsNt = TRUE; } if(SetAclsNt) { // // Initialize SIDs // d = InitializeSids(); if(d != NO_ERROR) { return(d); } // // Initialize ACEs // d = InitializeAces(AceDataTableForDirsAndFiles, AcesForDirsAndFiles, AceSizesForDirsAndFiles, DIRS_AND_FILES_ACE_COUNT); if(d != NO_ERROR) { TearDownSids(); return(d); } // // Go do the real work. // for( Count = 0; Count < sizeof( Files ) / sizeof( PWSTR ); Count++ ) { ULONG AcesToApply[] = { 2, 17 }; GetWindowsDirectory(Directory,MAX_PATH); wcscat( Directory, L"\\repair\\" ); wcscat( Directory, Files[ Count ] ); TempError = ApplyAclToDirOrFile( Directory, AcesToApply, sizeof( AcesToApply) / sizeof( ULONG ) ); if( TempError != NO_ERROR ) { if( d == NO_ERROR ) { d = TempError; } } } // // Clean up. // TearDownAces(AcesForDirsAndFiles, DIRS_AND_FILES_ACE_COUNT); TearDownSids(); } return(d); }