Skip to content

Commit

Permalink
Added /CanonicalizeAcls Operation
Browse files Browse the repository at this point in the history
- Added /CanonicalizeAcls operation that will reorder access control entries that to do not follow the canonical ordering (i.e., explicit deny, explicit allow, inherited deny, inherited allow).
- Updated and signed binaries for 1.11.0.0.
  • Loading branch information
NoMoreFood committed Mar 6, 2019
1 parent 746027f commit 76b348e
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 18 deletions.
Binary file modified Build/Release/x64/repacls.exe
Binary file not shown.
Binary file modified Build/Release/x86/repacls.exe
Binary file not shown.
Binary file modified Build/Repacls.zip
Binary file not shown.
1 change: 0 additions & 1 deletion Operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ typedef ACCESS_ACE *PACCESS_ACE;
// macros to iterate through access control entries
#define FirstAce(Acl) ((ACCESS_ACE *)((PUCHAR)(Acl) + sizeof(ACL)))
#define NextAce(Ace) ((ACCESS_ACE *)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
#define NextAceWithRestart(Acl,Ace,Restart) ((Restart) ? FirstAce(Acl) : NextAce(Ace))

// define our own version of sid length since its faster
#define GetLengthSid(x) (sizeof(SID) + (((SID *) (x))->SubAuthorityCount - 1) * sizeof(((SID *) (x))->SubAuthority))
Expand Down
69 changes: 69 additions & 0 deletions OperationCanonicalizeAcls.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "OperationCanonicalizeAcls.h"
#include "OperationCheckCanonical.h"
#include "DriverKitPartial.h"
#include "InputOutput.h"
#include "Functions.h"

ClassFactory<OperationCanonicalizeAcls> * OperationCanonicalizeAcls::RegisteredFactory =
new ClassFactory<OperationCanonicalizeAcls>(GetCommand());

OperationCanonicalizeAcls::OperationCanonicalizeAcls(std::queue<std::wstring> & oArgList) : Operation(oArgList)
{
// flag this as being an ace-level action
AppliesToDacl = true;
}

bool OperationCanonicalizeAcls::ProcessAclAction(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PACL & tCurrentAcl, bool & bAclReplacement)
{
// sanity check (null acl is considered valid)
if (tCurrentAcl == NULL) return false;

// use the simpler algorithm to determine if correct
bool bHasProblems = false;
OperationCheckCanonical::AceOrder oOrderOverall = OperationCheckCanonical::Unspecified;
ACCESS_ACE * tCheckAce = FirstAce(tCurrentAcl);
for (ULONG iEntry = 0; iEntry < tCurrentAcl->AceCount; tCheckAce = NextAce(tCheckAce), iEntry++)
{
// determine the overall over type of this ace
OperationCheckCanonical::AceOrder oThisAceOrder = OperationCheckCanonical::DetermineAceOrder(tCheckAce);

// make sure this order is not less then the current order
if (oThisAceOrder < oOrderOverall) break;
{
bHasProblems = true;
break;
}

oOrderOverall = oThisAceOrder;
}

// if no problem, then no need to perform a sort
if (!bHasProblems)
{
return false;
}

BYTE tNewAclBuffer[MAXWORD];
ACCESS_ACE * tNewAce = (ACCESS_ACE *) &tNewAclBuffer;
for (int iAceOrder = 0; iAceOrder < OperationCheckCanonical::MaxAceOrder; iAceOrder++)
{
ACCESS_ACE * tAce = FirstAce(tCurrentAcl);
for (ULONG iEntry = 0; iEntry < tCurrentAcl->AceCount; tAce = NextAce(tAce), iEntry++)
{
// determine the overall over type of this ace
OperationCheckCanonical::AceOrder oThisAceOrder = OperationCheckCanonical::DetermineAceOrder(tAce);

// copy the ace if it matches the sequential order (explicit deny, explicit allow, ...)
if (iAceOrder == oThisAceOrder)
{
memcpy(tNewAce, tAce, tAce->Header.AceSize);
tNewAce = NextAce(tNewAce);
}
}
}

// recopy the updated list back into the original dacl memory space
memcpy(FirstAce(tCurrentAcl), &tNewAclBuffer, (PBYTE) tNewAce - (PBYTE) &tNewAclBuffer);
InputOutput::AddInfo(L"Access control list was canonicalized", sSdPart);
return true;
}
21 changes: 21 additions & 0 deletions OperationCanonicalizeAcls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "Operation.h"

class OperationCanonicalizeAcls : public Operation
{
private:

// statics used by command registration utility
static std::wstring GetCommand() { return L"CanonicalizeAcls"; }
static ClassFactory<OperationCanonicalizeAcls> * RegisteredFactory;

public:

// overrides
bool ProcessAclAction(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PACL & tCurrentAcl, bool & bAclReplacement) override;

// constructors
OperationCanonicalizeAcls(std::queue<std::wstring> & oArgList);
};

38 changes: 23 additions & 15 deletions OperationCheckCanonical.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,12 @@ bool OperationCheckCanonical::ProcessAclAction(WCHAR * const sSdPart, ObjectEntr
// sanity check (null acl is considered valid)
if (tCurrentAcl == NULL) return false;

enum AceOrder : unsigned char
{
Unspecified = 0,
Explicit = 1 << 0,
Deny = 1 << 1,
Allow = 1 << 2,
Inherited = 1 << 3
};

unsigned char oOrderOverall = Unspecified;
AceOrder oOrderOverall = Unspecified;
ACCESS_ACE * tAce = FirstAce(tCurrentAcl);
for (ULONG iEntry = 0; iEntry < tCurrentAcl->AceCount; tAce = NextAce(tAce), iEntry++)
{
// check inheritance bits
unsigned char oThisAceOrder = (IsInherited(tAce)) ? Inherited : Unspecified;

// check allow/deny
oThisAceOrder |= (tAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ? Allow : Unspecified;
oThisAceOrder |= (tAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) ? Deny : Unspecified;
AceOrder oThisAceOrder = DetermineAceOrder(tAce);

// make sure this order is not less then the current order
if (oThisAceOrder < oOrderOverall)
Expand All @@ -49,3 +36,24 @@ bool OperationCheckCanonical::ProcessAclAction(WCHAR * const sSdPart, ObjectEntr
// report the
return false;
}

OperationCheckCanonical::AceOrder OperationCheckCanonical::DetermineAceOrder(ACCESS_ACE * tAce)
{
// determine ace order
if (IsInherited(tAce))
{
if (tAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) return InheritedAllow;
if (tAce->Header.AceType == ACCESS_ALLOWED_CALLBACK_ACE_TYPE) return InheritedAllow;
if (tAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) return InheritedDeny;
if (tAce->Header.AceType == ACCESS_DENIED_CALLBACK_ACE_TYPE) return InheritedDeny;
}
else
{
if (tAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) return ExplicitAllow;
if (tAce->Header.AceType == ACCESS_ALLOWED_CALLBACK_ACE_TYPE) return ExplicitAllow;
if (tAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) return ExplicitDeny;
if (tAce->Header.AceType == ACCESS_DENIED_CALLBACK_ACE_TYPE) return ExplicitDeny;
}

return Unspecified;
}
14 changes: 14 additions & 0 deletions OperationCheckCanonical.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ class OperationCheckCanonical : public Operation

public:

// public enums
enum AceOrder : unsigned char
{
Unspecified = 0,
ExplicitDeny = 1,
ExplicitAllow = 2,
InheritedDeny = 3,
InheritedAllow = 4,
MaxAceOrder
};

// public functions
static AceOrder DetermineAceOrder(ACCESS_ACE * tAce);

// overrides
bool ProcessAclAction(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PACL & tCurrentAcl, bool & bAclReplacement) override;

Expand Down
5 changes: 5 additions & 0 deletions OperationHelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ Commands That Can Alter Security (When /WhatIf Is Not Present)

std::wcout <<
LR"(
/CanonicalizeAcls
This command will look for out-of-order ACEs within the DACL and reorder
them to be canonical. Canonical order is as follows: explicit deny, explicit
allow, inherited deny, inherited allow.
/Compact
This command will look for mergeable entries in the security descriptor and
merge them. For example, running icacls.exe <file> /grant Everyone:R
Expand Down
4 changes: 2 additions & 2 deletions Version.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once

#define VERSION_STRING "1.10.0.3"
#define VERSION_COMMA 1,10,0,3
#define VERSION_STRING "1.11.0.0"
#define VERSION_COMMA 1,11,0,0
2 changes: 2 additions & 0 deletions repacls.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
<ClCompile Include="Main.cpp" />
<ClCompile Include="Operation.cpp" />
<ClCompile Include="OperationAddAccountIfMissing.cpp" />
<ClCompile Include="OperationCanonicalizeAcls.cpp" />
<ClCompile Include="OperationCheckCanonical.cpp" />
<ClCompile Include="OperationCompact.cpp" />
<ClCompile Include="OperationCopyDomain.cpp" />
Expand Down Expand Up @@ -230,6 +231,7 @@
<ClInclude Include="ConcurrentQueue.h" />
<ClInclude Include="DriverKitPartial.h" />
<ClInclude Include="Functions.h" />
<ClInclude Include="OperationCanonicalizeAcls.h" />
<ClInclude Include="OperationLocateShortcut.h" />
<ClInclude Include="InputOutput.h" />
<ClInclude Include="OperationCopyDomain.h" />
Expand Down
6 changes: 6 additions & 0 deletions repacls.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@
<ClCompile Include="OperationLog.cpp">
<Filter>Source\Operations</Filter>
</ClCompile>
<ClCompile Include="OperationCanonicalizeAcls.cpp">
<Filter>Source\Operations</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ConcurrentQueue.h">
Expand Down Expand Up @@ -234,6 +237,9 @@
<ClInclude Include="OperationLog.h">
<Filter>Includes\Operations</Filter>
</ClInclude>
<ClInclude Include="OperationCanonicalizeAcls.h">
<Filter>Includes\Operations</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Includes">
Expand Down

0 comments on commit 76b348e

Please sign in to comment.