windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/applyacl.c
2020-09-26 16:20:57 +08:00

964 lines
20 KiB
C

/*++
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; u<ArrayCount; u++) {
SidLength = GetLengthSid(*(DataTable[u].Sid));
Length = SidLength + sizeof(ACE) + sizeof(ACCESS_MASK)- sizeof(ULONG);
AceSizesArray[u] = Length;
AcesArray[u] = malloc(Length);
if(!AcesArray[u]) {
TearDownAces(AcesArray, ArrayCount);
return(ERROR_NOT_ENOUGH_MEMORY);
}
AcesArray[u]->Header.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<ArrayCount; u++) {
if(AcesArray[u]) {
free(AcesArray[u]);
}
}
}
ULONG
ApplyAclToDirOrFile(
IN PCWSTR FullPath,
IN PULONG AcesToApply,
IN ULONG ArraySize
)
/*++
Routine Description:
Applies an ACL to a specified file or directory.
Arguments:
FullPath - supplies full win32 path to the file or directory
to receive the ACL
AcesIndexArray - Array that contains the index to the ACEs to be used in the ACL.
ArraySize - Number of elements in the array.
Return Value:
--*/
{
DWORD AceCount;
DWORD Ace;
INT AceIndex;
DWORD rc;
SECURITY_DESCRIPTOR SecurityDescriptor;
PACL Acl;
UCHAR AclBuffer[2048];
BOOL b;
PCWSTR AclSection;
ACL_SIZE_INFORMATION AclSizeInfo;
//
// Initialize a security descriptor and an ACL.
// We use a large static buffer to contain the ACL.
//
Acl = (PACL)AclBuffer;
if(!InitializeAcl(Acl,sizeof(AclBuffer),ACL_REVISION2)
|| !InitializeSecurityDescriptor(&SecurityDescriptor,SECURITY_DESCRIPTOR_REVISION)) {
return(GetLastError());
}
//
// Build up the DACL from the indices on the list we just looked up
// in the ACL section.
//
rc = NO_ERROR;
AceCount = ArraySize;
for(Ace=0; Ace < AceCount; Ace++) {
AceIndex = AcesToApply[ Ace ];
if((AceIndex == 0) || (AceIndex >= 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);
}