Skip to content

Commit

Permalink
Renamed /ExportDescriptor To /SaveSecurity
Browse files Browse the repository at this point in the history
Added /RestoreSecurity
Special /Path Handling For Root Of Drive
  • Loading branch information
NoMoreFood committed Jan 28, 2017
1 parent 08e9526 commit 4e912f7
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 56 deletions.
57 changes: 53 additions & 4 deletions Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void AnalyzeSecurity(ObjectEntry & oEntry)
bool bSaclCleanupRequired = false;
bool bOwnerCleanupRequired = false;
bool bGroupCleanupRequired = false;
bool bDescCleanupRequired = true;

// used for one-shot operations like reset children or inheritance
DWORD iSpecialCommitMergeFlags = 0;
Expand Down Expand Up @@ -130,7 +131,40 @@ void AnalyzeSecurity(ObjectEntry & oEntry)
}
if ((*oOperation)->AppliesToSd)
{
(*oOperation)->ProcessSdAction(oEntry.Name, oEntry, tDesc);
if ((*oOperation)->ProcessSdAction(oEntry.Name, oEntry, tDesc, bDescCleanupRequired))
{
// cleanup previous operations if necessary
if (bDaclCleanupRequired) { LocalFree(tAclDacl); bDaclCleanupRequired = false; };
if (bSaclCleanupRequired) { LocalFree(tAclDacl); bSaclCleanupRequired = false; };
if (bOwnerCleanupRequired) { LocalFree(tAclDacl); bOwnerCleanupRequired = false; };
if (bGroupCleanupRequired) { LocalFree(tAclDacl); bGroupCleanupRequired = false; };
if (bDescCleanupRequired) { LocalFree(tDesc); bDescCleanupRequired = false; };

// extract the elements from the raw security descriptor
BOOL bItemPresent = FALSE;
BOOL bItemDefaulted = FALSE;
GetSecurityDescriptorDacl(tDesc, &bItemPresent, &tAclDacl, &bItemDefaulted);
GetSecurityDescriptorSacl(tDesc, &bItemPresent, &tAclSacl, &bItemDefaulted);
GetSecurityDescriptorOwner(tDesc, &tOwnerSid, &bItemDefaulted);
GetSecurityDescriptorGroup(tDesc, &tGroupSid, &bItemDefaulted);

// extract relevant inheritance bits
DWORD tRevisionInfo;
SECURITY_DESCRIPTOR_CONTROL tControl;
GetSecurityDescriptorControl(tDesc, &tControl, &tRevisionInfo);

// convert inheritance bits to the special flags that control inheritance
iSpecialCommitMergeFlags = CheckBitSet(SE_SACL_PROTECTED, tControl) ?
PROTECTED_SACL_SECURITY_INFORMATION : UNPROTECTED_SACL_SECURITY_INFORMATION;
iSpecialCommitMergeFlags = CheckBitSet(SE_DACL_PROTECTED, tControl) ?
PROTECTED_DACL_SECURITY_INFORMATION : UNPROTECTED_DACL_SECURITY_INFORMATION;

// mark all elements as needing to be updated
bDaclIsDirty = true;
bSaclIsDirty = true;
bOwnerIsDirty = true;
bGroupIsDirty = true;
}
}
}

Expand Down Expand Up @@ -181,7 +215,7 @@ void AnalyzeSecurity(ObjectEntry & oEntry)
if (bSaclCleanupRequired) LocalFree(tAclSacl);
if (bOwnerCleanupRequired) LocalFree(tOwnerSid);
if (bGroupCleanupRequired) LocalFree(tGroupSid);
LocalFree(tDesc);
if (bDescCleanupRequired) LocalFree(tDesc);
}


Expand Down Expand Up @@ -346,13 +380,28 @@ VOID BeginFileScan()
ObjectEntry oEntryFirst;
oEntryFirst.IsRoot = true;

// make a local copy of the path since we may have to alter it
std::wstring sPath = *sScanPath;

// handle special case where a drive root is specified
// we must ensure it takes the form x:\. to resolve correctly
size_t iSemiColon = sPath.rfind(L":");
if (iSemiColon != std::wstring::npos)
{
std::wstring sEnd = sPath.substr(iSemiColon);
if (sEnd == L":" || sEnd == L":\\")
{
sPath = sPath.substr(0, iSemiColon) + L":\\.";
}
}

// convert the path to a long path that is compatible with the other call
UNICODE_STRING tPathU;
RtlDosPathNameToNtPathName_U((*sScanPath).c_str(), &tPathU, NULL, NULL);
RtlDosPathNameToNtPathName_U(sPath.c_str(), &tPathU, NULL, NULL);

// copy it to a null terminated string
oEntryFirst.Name = std::wstring(tPathU.Buffer, tPathU.Length / sizeof(WCHAR));
oEntryFirst.Attributes = GetFileAttributes((*sScanPath).c_str());
oEntryFirst.Attributes = GetFileAttributes(oEntryFirst.Name.c_str());

// free the buffer returned previously
RtlFreeUnicodeString(&tPathU);
Expand Down
2 changes: 1 addition & 1 deletion Operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Operation
DWORD SpecialCommitFlags = false;
PSID DefaultSidWhenEmpty = NULL;

virtual bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR const tSecurityDescriptor) { return false; }
virtual bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement) { return false; }
virtual bool ProcessAclAction(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PACL & tCurrentAcl, bool & bAclReplacement);
virtual bool ProcessSidAction(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PSID & tCurrentSid, bool & bSidReplacement);
virtual SidActionResult DetermineSid(WCHAR * const sSdPart, ObjectEntry & tObjectEntry, PSID const tCurrentSid, PSID & tResultantSid) { return SidActionResult::Nothing; }
Expand Down
24 changes: 0 additions & 24 deletions OperationExportDescriptor.h

This file was deleted.

25 changes: 17 additions & 8 deletions OperationHelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,18 @@ Commands That Do Not Alter Security
it is recommended to inspect the ACL with icacls.exe or Windows Explorer
to ensure the ACL is not corrupted in a more significant way.
/ExportDescriptor <FileName>
/SaveSecurity <FileName>
Export the security descriptor to the file specified. The file is
outputted in the format of file|descriptor on each line. The security
descriptor is formated as specified in the documentation for
ConvertSecurityDescriptorToStringSecurityDescriptor().
descriptor is formatted as specified in the documentation for
ConvertDescriptorToStringSecurityDescriptor(). This command does
not print informational messages other than errors.
/RestoreSecurity <FileName>
The reverse operation of /SaveSecurity. Takes the file name and security
descriptors specified in the file specified and applies them to the file
system. This command does not print informational messages other than
errors.
/FindAccount <Name|Sid>
Reports any instance of an account specified.
Expand Down Expand Up @@ -160,8 +167,11 @@ Commands That Can Alter Security (When /WhatIf Is Not Present)
are converted to use the new domain. For example,
'OldDomain\Domain Admins' would become 'NewDomain\Domain Admins'. Since
this operation relies on the names being resolvable, specifying a SID
instead of domain name for this command does not work.
instead of domain name for this command does not work.
)";

std::wcout <<
LR"(
/RemoveAccount <Name|Sid>
Will remove <Name> from the security descriptor. If the specified name
is found as the file owner, the owner is replaced by the builtin
Expand All @@ -171,11 +181,8 @@ Commands That Can Alter Security (When /WhatIf Is Not Present)
/RemoveOrphans <Domain|Sid>
Remove any account whose SID is derived from the <Domain> specified
and can no longer be resolved to a valid name.
)";
and can no longer be resolved to a valid name
std::wcout <<
LR"(
/RemoveRedundant
This command will remove any explicit permission that is redundant of
of the permissions its already given through inheritance. This option
Expand Down Expand Up @@ -207,6 +214,8 @@ LR"(
Exclusive Options
=================
Exclusive options cannot be combined with any other security operations.
/Help or /? or /H
Shows this information.
Expand Down
4 changes: 2 additions & 2 deletions OperationPrintDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ OperationPrintDescriptor::OperationPrintDescriptor(std::queue<std::wstring> & oA
AppliesToGroup = true;
}

bool OperationPrintDescriptor::ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR const tSecurityDescriptor)
bool OperationPrintDescriptor::ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement)
{
// convert the current security descriptor to a string
WCHAR * sInfo = NULL;
if (ConvertSecurityDescriptorToStringSecurityDescriptor(tSecurityDescriptor, SDDL_REVISION_1,
if (ConvertSecurityDescriptorToStringSecurityDescriptor(tDescriptor, SDDL_REVISION_1,
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
&sInfo, NULL) == 0)
{
Expand Down
2 changes: 1 addition & 1 deletion OperationPrintDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class OperationPrintDescriptor : public Operation
public:

// overrides
bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR const tSecurityDescriptor) override;
bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement) override;

// constructors
OperationPrintDescriptor(std::queue<std::wstring> & oArgList);
Expand Down
10 changes: 9 additions & 1 deletion OperationReport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,16 @@ OperationReport::OperationReport(std::queue<std::wstring> & oArgList) : Operatio
// if this is the first handle using this file, write out a header
if (hFile == hReportFile)
{
// write out the header
// write out the file type marker
USHORT hHeader = 0xFEFF;
DWORD iBytes = 0;
if (WriteFile(hFile, &hHeader, sizeof(USHORT), &iBytes, NULL) == 0)
{
wprintf(L"ERROR: Could not write out report file type marker '%s'.\n", GetCommand().c_str());
exit(-1);
}

// write out the header
std::wstring sToWrite = std::wstring(L"") + Q(L"Path") + L"," + Q(L"Descriptor Part") + L"," +
Q(L"Account Name") + L"," + Q(L"Permissions") + L"," + Q(L"Inheritance") + L"\r\n";
if (WriteFile(hReportFile, sToWrite.c_str(), (DWORD)sToWrite.size() * sizeof(WCHAR), &iBytes, NULL) == 0)
Expand Down
74 changes: 74 additions & 0 deletions OperationRestoreSecurity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "OperationRestoreSecurity.h"
#include "InputOutput.h"
#include "Functions.h"

#include <fstream>
#include <iostream>
#include <locale>
#include <codecvt>

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

OperationRestoreSecurity::OperationRestoreSecurity(std::queue<std::wstring> & oArgList) : Operation(oArgList)
{
// exit if there are not enough arguments to part
std::vector<std::wstring> sSubArgs = ProcessAndCheckArgs(1, oArgList, L"\\0");

// open the file
std::wifstream fFile(sSubArgs[0].c_str());

// adapt the stream to read windows unicode files
fFile.imbue(std::locale(fFile.getloc(), new std::codecvt_utf16<wchar_t,
0x10ffff, std::consume_header>));

// read the file line-by-line
std::wstring sLine;
while (std::getline(fFile, sLine))
{
// parse the file name and descriptor which are separated by a '|' character
std::vector<std::wstring> oLineItems = SplitArgs(sLine, L"\\|");

// convert the long string descriptor its binary equivalent
PSECURITY_DESCRIPTOR tDesc;
if (ConvertStringSecurityDescriptorToSecurityDescriptor(oLineItems.at(1).c_str(),
SDDL_REVISION_1, &tDesc, NULL) == 0)
{
InputOutput::AddError(L"ERROR: Unable to parse string security descriptor.");
exit(-1);
}

// update the map
oImportMap[oLineItems.at(0)] = tDesc;
}

// cleanup
fFile.close();

// flag this as being an ace-level action
AppliesToSd = true;
AppliesToDacl = true;
AppliesToSacl = true;
AppliesToOwner = true;
AppliesToGroup = true;
}

bool OperationRestoreSecurity::ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement)
{
std::map<std::wstring, PSECURITY_DESCRIPTOR>::iterator oSecInfo = oImportMap.find(sFileName);
if (oSecInfo != oImportMap.end())
{
// lookup the string in the map
if (bDescReplacement) LocalFree(tDescriptor);
tDescriptor = oSecInfo->second;
bDescReplacement = true;
}
else
{
// update the sid in the ace
InputOutput::AddError(L"Import File Did Not Contain Descriptor");
}

// cleanup
return true;
}
24 changes: 24 additions & 0 deletions OperationRestoreSecurity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "Operation.h"

class OperationRestoreSecurity : public Operation
{
private:

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

std::map<std::wstring, PSECURITY_DESCRIPTOR> oImportMap;
std::wstring sFile = L"";

public:

// overrides
bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement) override;

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

21 changes: 15 additions & 6 deletions OperationExportDescriptor.cpp → OperationSaveSecurity.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "OperationExportDescriptor.h"
#include "OperationSaveSecurity.h"
#include "InputOutput.h"
#include "Functions.h"

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

OperationExportDescriptor::OperationExportDescriptor(std::queue<std::wstring> & oArgList) : Operation(oArgList)
OperationSaveSecurity::OperationSaveSecurity(std::queue<std::wstring> & oArgList) : Operation(oArgList)
{
// exit if there are not enough arguments to part
std::vector<std::wstring> sSubArgs = ProcessAndCheckArgs(1, oArgList, L"\\0");
Expand All @@ -22,6 +22,15 @@ OperationExportDescriptor::OperationExportDescriptor(std::queue<std::wstring> &
exit(-1);
}

// write out the file type marker
USHORT hHeader = 0xFEFF;
DWORD iBytes = 0;
if (WriteFile(hFile, &hHeader, sizeof(USHORT), &iBytes, NULL) == 0)
{
wprintf(L"ERROR: Could not write out report file type marker '%s'.\n", GetCommand().c_str());
exit(-1);
}

// flag this as being an ace-level action
AppliesToSd = true;
AppliesToDacl = true;
Expand All @@ -30,11 +39,11 @@ OperationExportDescriptor::OperationExportDescriptor(std::queue<std::wstring> &
AppliesToGroup = true;
}

bool OperationExportDescriptor::ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR const tSecurityDescriptor)
bool OperationSaveSecurity::ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement)
{
// convert the current security descriptor to a string
WCHAR * sInfo = NULL;
if (ConvertSecurityDescriptorToStringSecurityDescriptor(tSecurityDescriptor, SDDL_REVISION_1,
if (ConvertSecurityDescriptorToStringSecurityDescriptor(tDescriptor, SDDL_REVISION_1,
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
&sInfo, NULL) == 0)
{
Expand Down
24 changes: 24 additions & 0 deletions OperationSaveSecurity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "Operation.h"

class OperationSaveSecurity : public Operation
{
private:

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

HANDLE hFile = INVALID_HANDLE_VALUE;
std::wstring sFile = L"";

public:

// overrides
bool ProcessSdAction(std::wstring & sFileName, ObjectEntry & tObjectEntry, PSECURITY_DESCRIPTOR & tDescriptor, bool & bDescReplacement) override;

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

2 changes: 1 addition & 1 deletion Version.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once

#define VERSION_STRING "1.7.0.3"
#define VERSION_STRING "1.8.0.0"
Loading

0 comments on commit 4e912f7

Please sign in to comment.