You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
9.5 KiB
447 lines
9.5 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1998.
|
|
//
|
|
// File: isacl.cxx
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
|
|
#include "pch.cxx"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Maximum number of ACE descriptions used in one ACL.
|
|
//
|
|
#define ACE_COUNT 3
|
|
|
|
// NOTE: Portions of the code below were borrowed from
|
|
// \nt\private\windows\setup\syssetup\applyacl.c.
|
|
|
|
typedef struct _ACE_DATA {
|
|
ACCESS_MASK AccessMask;
|
|
SID_IDENTIFIER_AUTHORITY SidIdAuth;
|
|
DWORD dwSubAuth0, dwSubAuth1;
|
|
BYTE cSubAuthorities;
|
|
UCHAR AceType;
|
|
UCHAR AceFlags;
|
|
} ACE_DATA, *PACE_DATA;
|
|
|
|
BOOL
|
|
ApplyAcl(
|
|
WCHAR const *pwcDir,
|
|
unsigned cAces,
|
|
ACE_DATA *pAceData
|
|
);
|
|
|
|
DWORD
|
|
ApplyAclToDirOrFile(
|
|
IN WCHAR const * FullPath,
|
|
unsigned cAces,
|
|
PACCESS_ALLOWED_ACE Aces[]
|
|
);
|
|
|
|
DWORD
|
|
InitializeSids(
|
|
unsigned cAces,
|
|
ACE_DATA *pAceData,
|
|
PSID apSid[]
|
|
);
|
|
|
|
VOID
|
|
TearDownSids(
|
|
unsigned cAces,
|
|
PSID apSid[]
|
|
);
|
|
|
|
DWORD
|
|
InitializeAces(
|
|
unsigned cAces,
|
|
ACE_DATA const *pAceData,
|
|
PACCESS_ALLOWED_ACE Aces[],
|
|
PSID apSid[]
|
|
);
|
|
|
|
VOID
|
|
TearDownAces(
|
|
unsigned cAces,
|
|
PACCESS_ALLOWED_ACE Aces[]
|
|
);
|
|
|
|
//
|
|
// 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;
|
|
|
|
|
|
//
|
|
// Table describing the data to put into each ACE.
|
|
//
|
|
// NOTE: The order of the table is significant because it is used to
|
|
// create two different ACLs. ACE 0 is used by itself for one ACL,
|
|
// and all three ACEs are used for the other ACL.
|
|
//
|
|
ACE_DATA AceDataTable[ACE_COUNT] = {
|
|
|
|
//
|
|
// ACE 0 - Full access, System account
|
|
//
|
|
{
|
|
GENERIC_ALL,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_LOCAL_SYSTEM_RID, 0,
|
|
1,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
|
},
|
|
|
|
//
|
|
// ACE 1 - Full access, Administrators group
|
|
//
|
|
{
|
|
GENERIC_ALL,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
2,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
|
},
|
|
|
|
//
|
|
// ACE 2 - Full access, Creator/owner
|
|
//
|
|
{
|
|
GENERIC_ALL,
|
|
SECURITY_CREATOR_SID_AUTHORITY,
|
|
SECURITY_CREATOR_OWNER_RID, 0,
|
|
1,
|
|
ACCESS_ALLOWED_ACE_TYPE,
|
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
|
},
|
|
|
|
};
|
|
|
|
|
|
//
|
|
// arg0 = Filename
|
|
|
|
BOOL ApplySystemAcl( WCHAR const *pwcDir )
|
|
{
|
|
return ApplyAcl( pwcDir, ACE_COUNT, AceDataTable );
|
|
}
|
|
|
|
BOOL ApplySystemOnlyAcl( WCHAR const *pwcDir )
|
|
{
|
|
return ApplyAcl( pwcDir, 1, AceDataTable );
|
|
}
|
|
|
|
BOOL ApplyAcl( WCHAR const *pwcDir, unsigned cAces, ACE_DATA *pAceData )
|
|
{
|
|
WCHAR achDrive[4];
|
|
for (unsigned i = 0; i < 3; i++)
|
|
achDrive[i] = pwcDir[i];
|
|
achDrive[3] = 0;
|
|
|
|
DWORD dwFsFlags;
|
|
BOOL b = GetVolumeInformation( achDrive, NULL, 0, NULL, NULL, &dwFsFlags, NULL, 0);
|
|
if (!b || ! (dwFsFlags & FS_PERSISTENT_ACLS))
|
|
{
|
|
// NOTE: We could return a different result here and warn about
|
|
// the lack of ACLs, but it isn't worth the trouble of
|
|
// explaining to (and worrying) the user.
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Array of SID pointers used in the ACL. They are
|
|
// initialized based on the data in the AceDataTable.
|
|
//
|
|
PSID apSids[ACE_COUNT];
|
|
|
|
if (InitializeSids(cAces, pAceData, apSids) != NO_ERROR)
|
|
return FALSE;
|
|
|
|
//
|
|
// Array of ACEs to be applied to the objects. They are
|
|
// initialized based on the data in the AceDataTable.
|
|
//
|
|
PACCESS_ALLOWED_ACE aAces[ACE_COUNT];
|
|
|
|
if (InitializeAces(cAces, pAceData, aAces, apSids) != NO_ERROR)
|
|
{
|
|
TearDownSids(cAces, apSids);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fOK = ( ApplyAclToDirOrFile( pwcDir, cAces, aAces ) == NO_ERROR );
|
|
|
|
TearDownAces(cAces, aAces);
|
|
TearDownSids(cAces, apSids);
|
|
return fOK;
|
|
} //ApplySystemAcl
|
|
|
|
|
|
DWORD
|
|
ApplyAclToDirOrFile(
|
|
IN WCHAR const * FullPath,
|
|
unsigned cAces,
|
|
PACCESS_ALLOWED_ACE Aces[]
|
|
)
|
|
|
|
/*++
|
|
|
|
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
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
PACL Acl;
|
|
UCHAR AclBuffer[2048];
|
|
BOOL b;
|
|
|
|
//
|
|
// Initialize a security descriptor and an ACL.
|
|
// We use a large buffer on the stack 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.
|
|
//
|
|
|
|
DWORD rc = NO_ERROR;
|
|
for ( unsigned AceIndex = 0;
|
|
(rc == NO_ERROR) && (AceIndex < cAces);
|
|
AceIndex++ )
|
|
{
|
|
b = AddAce( Acl,
|
|
ACL_REVISION2,
|
|
0xFFFFFFFF,
|
|
Aces[AceIndex],
|
|
Aces[AceIndex]->Header.AceSize
|
|
);
|
|
|
|
//
|
|
// Track first error we encounter.
|
|
//
|
|
if (!b && (rc == NO_ERROR)) {
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
|
|
if (rc != NO_ERROR)
|
|
return rc;
|
|
|
|
//
|
|
// Add the ACL to the security descriptor as the DACL
|
|
//
|
|
rc = SetSecurityDescriptorDacl(&SecurityDescriptor,TRUE,Acl,FALSE)
|
|
? NO_ERROR
|
|
: GetLastError();
|
|
|
|
if (rc != NO_ERROR)
|
|
return rc;
|
|
|
|
//
|
|
// Finally, apply the security descriptor.
|
|
//
|
|
rc = SetFileSecurity(FullPath,DACL_SECURITY_INFORMATION,&SecurityDescriptor)
|
|
? NO_ERROR
|
|
: GetLastError();
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InitializeSids(
|
|
unsigned cAces,
|
|
ACE_DATA *pAceData,
|
|
PSID apSids[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the global variables used by and exposed
|
|
by security.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Win32 error indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Ensure the SIDs are in a well-known state
|
|
//
|
|
|
|
for (unsigned i=0; i<cAces; i++)
|
|
{
|
|
apSids[i] = 0;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize the universal SIDs
|
|
//
|
|
for (i=0; i<cAces; i++)
|
|
{
|
|
BOOL b = AllocateAndInitializeSid( &pAceData[i].SidIdAuth,
|
|
pAceData[i].cSubAuthorities,
|
|
pAceData[i].dwSubAuth0,
|
|
pAceData[i].dwSubAuth1,
|
|
0,0,0,0,0,0,
|
|
&apSids[i] );
|
|
if (!b)
|
|
{
|
|
DWORD rc = GetLastError();
|
|
TearDownSids(cAces, apSids);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
TearDownSids(
|
|
unsigned cAces,
|
|
PSID apSids[]
|
|
)
|
|
{
|
|
for (unsigned i=0; i<cAces; i++)
|
|
if (apSids[i])
|
|
FreeSid(apSids[i]);
|
|
}
|
|
|
|
#define MyMalloc(cb) GlobalAlloc( 0, cb )
|
|
#define MyFree(pv) GlobalFree( pv )
|
|
|
|
DWORD
|
|
InitializeAces(
|
|
unsigned cAces,
|
|
ACE_DATA const *pAceData,
|
|
PACCESS_ALLOWED_ACE Aces[],
|
|
PSID apSids[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the array of ACEs as described in the pAceData table
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Win32 error code indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Initialize to a known state.
|
|
//
|
|
ZeroMemory(Aces, cAces*sizeof Aces[0]);
|
|
|
|
//
|
|
// 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 (unsigned u=0; u<cAces; u++) {
|
|
|
|
ULONG cbSid = GetLengthSid( apSids[u] );
|
|
DWORD Length = cbSid + sizeof(ACCESS_ALLOWED_ACE) - sizeof DWORD;
|
|
|
|
Aces[u] = (PACCESS_ALLOWED_ACE) MyMalloc(Length);
|
|
if (!Aces[u]) {
|
|
TearDownAces(cAces, Aces);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Aces[u]->Header.AceType = pAceData[u].AceType;
|
|
Aces[u]->Header.AceFlags = pAceData[u].AceFlags;
|
|
Aces[u]->Header.AceSize = (WORD)Length;
|
|
|
|
Aces[u]->Mask = pAceData[u].AccessMask;
|
|
|
|
BOOL b = CopySid( cbSid,
|
|
(PUCHAR) &(Aces[u]->SidStart),
|
|
apSids[u] );
|
|
|
|
if (!b) {
|
|
DWORD rc = GetLastError();
|
|
TearDownAces(cAces, Aces);
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
TearDownAces(
|
|
unsigned cAces,
|
|
PACCESS_ALLOWED_ACE Aces[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys the array of ACEs as described in the AceDataTable
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
for (unsigned u=0; u<cAces; u++) {
|
|
|
|
if (Aces[u]) {
|
|
MyFree(Aces[u]);
|
|
}
|
|
}
|
|
}
|
|
|