/**
* This code is by OShah. all code will have the following licence.
* Copyright Shexec32. All code bears the following licence:
**/
/**
* Copyright Shexec32 2004-2005. All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
**/
#include "SecurityCore.h"
#include "URLCtrl.h"
#include "resource2.h"
/* I moved all the utility classes from SecurityCore.h to here (because they were cluttering up SecurityCore.h. */
const SI_ACCESS g_siObjAccesses[] =
{/** This structure describes each flag in the file access mask. It is constant. ACLUI displays these
* strings in its UI.
**/
{ &GUID_NULL, FILE_ALL_ACCESS, L"Full Control",
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE },
{ &GUID_NULL, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE,
L"Modify", SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE },
{ &GUID_NULL, FILE_GENERIC_EXECUTE,
L"Execute", SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE },
{ &GUID_NULL, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
L"List Folder Contents", SI_ACCESS_CONTAINER | CONTAINER_INHERIT_ACE },
{ &GUID_NULL, FILE_GENERIC_READ,
L"Read", SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE },
{ &GUID_NULL, FILE_GENERIC_WRITE,
L"Write", SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE },
{ &GUID_NULL, FILE_EXECUTE, L"Traverse Folder/Execute File", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_READ_DATA, L"List Folder/Read Data", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_READ_ATTRIBUTES, L"Read Attributes", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_READ_EA, L"Read Extended Attributes", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_WRITE_DATA, L"Create Files/Write Data", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_APPEND_DATA, L"Create Folders/Append Data", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_WRITE_ATTRIBUTES, L"Write Attributes", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_WRITE_EA, L"Write Extended Attributes", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_DELETE_CHILD, L"Delete Children", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, DELETE, L"Delete", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, READ_CONTROL, L"Read Permissions", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WRITE_DAC, L"Set Permissions", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WRITE_OWNER, L"Take Ownership", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, SYNCHRONIZE, L"Synchronize", SI_ACCESS_SPECIFIC },
{ &GUID_NULL, FILE_GENERIC_EXECUTE, L"Traverse/Execute", 0 },
{ &GUID_NULL, FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE, L"Write and Execute", 0 },
{ &GUID_NULL, FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE | FILE_GENERIC_READ,
L"Read Write and Execute", 0 },
{ &GUID_NULL, 0, L"None", 0 }
// { &GUID_NULL, SERVICE, L"Insert Privilege Here", SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }
};
const OBJECT_TYPE_LIST g_DefaultOTL[] =
{/** This empty object list is required by GetEffectivePermission(). This structure is required by ACLUI
* to be a static constant.
**/
{ 0, 0, const_cast<LPGUID>(&GUID_NULL) },
};
const SI_INHERIT_TYPE g_InheritTypes[] =
{/* This gets the inheritance of the file. This structure is constant */
&GUID_NULL, 0, L"This Object",
&GUID_NULL, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, L"This object, inherited object and containers",
&GUID_NULL, CONTAINER_INHERIT_ACE, L"This object and containers",
&GUID_NULL, OBJECT_INHERIT_ACE, L"This object and inherited objects",
&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, L"Inherited containers/objects",
&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, L"Inherited Containers",
&GUID_NULL, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, L"Inherited Objects"
};
const ULONG
gc_siObjAccesses = sizeof(g_siObjAccesses) / sizeof(g_siObjAccesses[0]) ,
gc_DefaultOTL = sizeof(g_DefaultOTL) / sizeof(g_DefaultOTL[0]) ,
gc_InheritTypes = sizeof(g_InheritTypes) / sizeof(g_InheritTypes[0]);
/* These are flags for DllInstallEx() */
const int /* All used by ShellDLL.cpp */
SILENT = (1 << 0) ,
ALLUSERSONLY = (1 << 1) ,
MEONLY = (1 << 2) ,
HKCRONLY = (1 << 3);
HINSTANCE g_hInst; /* Application Constant (set at startup) */
UINT g_RefCount; /* This WORM variable may need interlocked access. */
HANDLE g_hMutex; /* Application Constant (set at startup). */
PrivMgrImpl::PrivMgrImpl()
: RefCount(0)
{
}
PrivMgrImpl::~PrivMgrImpl()
{
if(RefCount > 0)
{/* Clobber the impersonation */
::RevertToSelf();
/* Once called, the impersonation is obliterated and all enabled privileges are finished. */
}
}
BOOL PrivMgrImpl::TrySetPrivilege(LPCTSTR lpszPrivilege /* = SE_SECURITY_NAME */,
BOOL bEnablePrivilege /* = FALSE */)
{
/* This function handles reference counting of the privilege, and also overall impersonation. */
DWORD Result = 0;
HANDLE hToken = NULL;
if(::OpenThreadToken(::GetCurrentThread(), TOKEN_WRITE, TRUE, &hToken) != TRUE
|| hToken == NULL || hToken == INVALID_HANDLE_VALUE)
{
/* ImpersonateSelf Then call OpenThreadToken */
if(::ImpersonateSelf(SecurityImpersonation) != TRUE)
{
throw DWORD(4);
}
if(::OpenThreadToken(::GetCurrentThread(), TOKEN_WRITE, TRUE, &hToken) != TRUE
|| hToken == NULL || hToken == INVALID_HANDLE_VALUE)
{
if( ::OpenProcessToken(::GetCurrentProcess(), TOKEN_WRITE, &hToken) != TRUE
|| hToken == NULL || hToken == INVALID_HANDLE_VALUE)
{/* Whenever something went wrong, do not commit the new reference count. */
throw DWORD(0);
}
}
}
Result = this->DoSetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
if(hToken != NULL && hToken != INVALID_HANDLE_VALUE) ::CloseHandle(hToken); hToken = NULL;
if(Result != 0)
throw DWORD(Result);
/* Increment ref count accordingly */
if(bEnablePrivilege == TRUE) this->RefCount++;
else this->RefCount--;
if(this->RefCount < 1)
{/* Are any other privileges enabled? */
if(::RevertToSelf() != TRUE)
throw DWORD(5);
}
return Result;
}
DWORD PrivMgrImpl::DoSetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege /* = SE_SECURITY_NAME */,
BOOL bEnablePrivilege /*= FALSE */)
{/* Straight out of the Platform SDK, this function. */
TOKEN_PRIVILEGES tp = {0};
LUID luid = {0};
if( ::LookupPrivilegeValue(NULL, lpszPrivilege, &luid) != TRUE )
{
return 1;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if(bEnablePrivilege == TRUE)
{/* On those brain dead systems that define TRUE != 1, disable the privilege (fail securely). */
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
tp.Privileges[0].Attributes = 0;
}
::SetLastError(ERROR_SUCCESS);
if( ::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) != TRUE
&& ::GetLastError() != ERROR_SUCCESS)
{/* AdjustTokenPrivilege doesn't fail in case of non-admin. Just GetLastError() == ERROR_NOT_ALL_ASSIGNED. */
return 2;
}
return 0;
}
PrivMgr::PrivMgr(const std::basic_string<TCHAR> &sPrivilege, PrivMgrImpl *HandedClass)
: PrivilegeName(sPrivilege), ObjImplPtr(HandedClass), SecuritySet(FALSE)
{
}
PrivMgr::~PrivMgr()
{
if(this->SecuritySet == TRUE)
this->ObjImplPtr->TrySetPrivilege(this->PrivilegeName.c_str(), FALSE);
}
BOOL PrivMgr::TurnOn(void)
{
try {
this->ObjImplPtr->TrySetPrivilege(this->PrivilegeName.c_str(), TRUE);
this->SecuritySet = TRUE;
return TRUE;
} catch (DWORD &) {
}
return FALSE;
}
const _bstr_t __stdcall GetLastErrorText(DWORD dwError)
{/** Formats the error message specified and converts it to a string. The return value is a BSTR denoting the
* error string. If the message isn't found, "Unknown Win32 Error" is returned.
* This is an API entry point. Fortunately, it only takes a DWORD, so no input checking is really required.
**/
_bstr_t szMsg;
LPTSTR szMsgBuf = NULL;
/* Let FormatMessage format a buffer for us. */
DWORD dwRes = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, 0, reinterpret_cast<LPTSTR>(&szMsgBuf), 32000, NULL);
if (dwRes == 0) {
szMsg = _T("Unknown Win32 Error.");
}
else szMsg = szMsgBuf;
::LocalFree(szMsgBuf); szMsgBuf = NULL;
return szMsg;
}
void About_OnHelp(HWND TheirhWnd)
{/** This is a generic WM_HELP handler that displays the manual whenever help is needed.
* If help does not exist, this function does nothing but waste some CPU instructions.
* You pass in the parent Window handle,
**/
::sized_array<TCHAR> HelpFileName (FILENAME_MAX);
/* Use FILENAME_MAX as default, so we may not even need a realloc */
TCHAR *lpFilePart = NULL; /* dummy pointer for final parameter for SearchPath */
DWORD len = ::SearchPath(NULL, _T("filepermsbox.txt"), NULL, FILENAME_MAX, HelpFileName.get(), &lpFilePart);
if(len > FILENAME_MAX)
{/* We don't usually reach here. */
HelpFileName.reset(len + 1);
len = ::SearchPath(NULL, _T("filepermsbox.txt"), NULL, len + 1, HelpFileName.get(), &lpFilePart);
}
if(*HelpFileName.get() != _T('\0'))
{/* Test for an empty string. If we didn't find the documentation, do nothing. */
::ShellExecute(TheirhWnd, NULL, HelpFileName.get(), NULL, NULL, SW_SHOWNORMAL);
}
}
INT_PTR CALLBACK AboutFunc(HWND TheirhWnd, UINT Msg, WPARAM wParam, LPARAM)
{/* This is the about dialog box. The resource has done most of the stuff for us. */
switch(Msg)
{
case WM_INITDIALOG:
{
const std::basic_string<TCHAR> &HomePageLink (_T("http://hometown.aol.co.uk/shexec32/"));
::SetDlgItemText(TheirhWnd, IDC_EDIT1,
_T("FilePermsBox. Shows the File Security tab in Windows Explorer, even if it was disabled."));
::SetDlgItemText(TheirhWnd, IDC_HOMEPAGE, HomePageLink.c_str());
/* make the url label clickable. */
::urlctrl_set(::GetDlgItem(TheirhWnd, IDC_HOMEPAGE), HomePageLink);
return TRUE;
}
case WM_COMMAND:
{
switch LOWORD(wParam)
{
case IDCANCEL:
{/* Close */
::PostMessage(TheirhWnd, WM_CLOSE, 0, 0);
return FALSE;
}
default:
break;
}
return FALSE;
}
case WM_HELP:
{/* The help cursor was used. Show the manual. */
About_OnHelp(TheirhWnd);
return FALSE;
}
case WM_CLOSE:
{
EndDialog(TheirhWnd, 0);
return TRUE;
}
default:
break;
}
return FALSE;
}
BOOL __stdcall ShowAbout(HWND TheirhWnd)
{/** This API (implemented in the dll), displays an about dialog box. The about box is modal on TheirhWnd.
* If the HWND is invalid, the dialog will be be modal on the desktop.
**/
if(::IsWindow(TheirhWnd) != TRUE)
TheirhWnd = NULL;
::DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG3), TheirhWnd, AboutFunc, 0);
return TRUE;
}
const std::basic_string<TCHAR>::size_type
CopyString(const std::basic_string<TCHAR> &OldClass, TCHAR *OutBuffer, size_t Count)
{/** A Thin wrapper for basic_string<TCHAR>::copy. Dangerous function! Do not reuse.
* Notice that you have to pass in the Count of OutBuffer to use this function. Since this
* is developer input (or even worse, user input), CopyString shouldn't be used except in the
* most extreme of cases.
*
* OldClass: Which basic_string to copy from
* OutBuffer: The Buffer to copy to. Must be large enough to contain the contaminated string
* Count: the size of OutBuffer. A good choice for this is OldClass.size()
**/
std::basic_string<TCHAR>::size_type Result = 0;
#ifndef _SCL_INSECURE_DEPRECATE
/* I don't trust std::min, especially when windows.h is involved. */
size_t BufSize = (OldClass.size() > Count) ? Count : OldClass.size();
Result = OldClass.copy(OutBuffer, BufSize, 0);
#else
OldClass._Copy_s(OutBuffer, Count, OldClass.size(), 0);
#endif /* _SCL_INSECURE_DEPRECATE */
return Result;
}
BOOL __stdcall CheckVersion(void)
{/** API Entrypoint for FilePermsBoxDLL, takes no input (cool), and returns the major version
* number of the OS. ::_osver should no longer be used.
**/
#pragma warning (push)
#pragma warning (disable:4127) /* Conditional expression is constant */
#pragma warning (disable:6326) /* potential comparison of a constant with another constant */
::OSVERSIONINFOEX osVer = {0};
osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
::GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osVer));
if((osVer.dwMajorVersion < 5) || (FALSE != 0) || (NULL != 0) || (sizeof(BOOL) != sizeof(int)))
{/* Refuse to install in WinNT/9x. */
return FALSE;
}
#pragma warning (pop)
return TRUE;
}
#ifdef _WIN64
ULONG_PTR LONG_PTR2(void *converterNumber)
{/* These functions are API'ed. Due to the fact we do not dereference the pointers, we are safe. */
return reinterpret_cast<ULONG_PTR>(converterNumber);
}
#else /* Set*LongPtr -Wp64 hack. silences the C4244 warning because setclasslongptr does that. */
ULONG LONG_PTR2(void *converterNumber)
{
return PtrToUlong(converterNumber);
}
#endif /* _WIN64 TODO: When Set*LongPtr is fixed, remove this hack. */
BOOL __stdcall GetSDForObject(const std::basic_string<TCHAR> &FileName,
std::basic_string<TCHAR> &SDDLString, const BOOL IncludeInherited)
{/** This function converts a filename into its string security descriptor (in SDDL). IncludeInherited
* means Unprotected acls will be included too. This is an API entry point, so only reference types and
* value types should be used.
**/
DWORD dwErr = 0;
LPTSTR SDDLBuffer = NULL;
PSECURITY_DESCRIPTOR ppSD = NULL;
/* This privilege will be removed upon exit of this function. */
PrivMgrImpl ClassMgrImpl;
{
PrivMgr SecPriv (SE_SECURITY_NAME, &ClassMgrImpl);
if( ::GetFileAttributes(FileName.c_str()) == INVALID_FILE_ATTRIBUTES )
{/* validate inputs */
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SECURITY_INFORMATION psi = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION;
if(IncludeInherited == TRUE)
psi = psi | UNPROTECTED_DACL_SECURITY_INFORMATION;
if(SecPriv.TurnOn())
{
psi = psi | SACL_SECURITY_INFORMATION | PROTECTED_SACL_SECURITY_INFORMATION;
if(IncludeInherited == TRUE)
psi = psi | UNPROTECTED_SACL_SECURITY_INFORMATION;
}
/* Allocate a writable copy of FileName */
sized_array<TCHAR> FNameWritable (FileName);
//sized_array<TCHAR> FNameWritable (FileName.size() + 1);
//FileName.copy(FNameWritable.get(), FileName.size(), 0);
/* And Get its SD. */
dwErr = ::GetNamedSecurityInfo(FNameWritable.get(), SE_FILE_OBJECT, psi, NULL, NULL, NULL, NULL, &ppSD);
if(dwErr != ERROR_SUCCESS) return FALSE;
/* Get this resultant SD in SDDL */
dwErr = ::ConvertSecurityDescriptorToStringSecurityDescriptor(ppSD, SDDL_REVISION_1, psi, &SDDLBuffer, NULL);
/* Cleanup. */
::LocalFree(ppSD); ppSD = NULL;
if(dwErr == TRUE)/* Copy the SDDL into the caller supplied string. */
SDDLString = SDDLBuffer;
::LocalFree(SDDLBuffer); SDDLBuffer = NULL;
}
return TRUE;
}
BOOL FixSDs(HWND TheirhWnd, SECURITY_INFORMATION psi,
const std::list< const std::basic_string<TCHAR> > &FileNamesCollection)
{/* This function creates a temporary CObjSecurity, creates a new repair SD, and passes it to SetSecurity. */
PSECURITY_DESCRIPTOR pSD = NULL;
try {
PrivMgrImpl PrivClassImpl;
{
PrivMgr SecurityPriv(SE_SECURITY_NAME, &PrivClassImpl);
/* Instantiate a CObjSecurity and call its methods to get the security. */
std::auto_ptr<CObjSecurity> SecurityCore ( new CObjSecurity(FileNamesCollection,
SE_FILE_OBJECT, TheirhWnd) );
SecurityPriv.TurnOn();
SecurityCore->MakeWritable(TRUE);
SecurityCore->GetSecurity(psi, &pSD, TRUE);
SecurityCore->SetSecurity(psi, pSD); /* Setsecurity will walk the tree for us. */
::LocalFree(pSD); pSD = NULL;
}
} catch(const std::basic_string<TCHAR> &e) {/* Another problem occurred, show the user. */
MessageBox(TheirhWnd, e.c_str(), _T("Error Setting Security"), MB_OK | MB_ICONERROR);
return FALSE;
}
return TRUE;
}
const BOOL AreAclsEqual(std::basic_string<TCHAR> &FirstAcl, std::basic_string<TCHAR> &SecondAcl)
{/** This procedure determines if the 1stAcl has the same information as 2ndAcl. 1stAcl and
* 2ndAcl are string security descriptors (The D:ARAI part is not included).
* (A;;FA;;;BA)(A;OICIIO;0x001701bf;;;PU)(A;OICIIO;GRGWGX;;;S-1-5-123243273948765-4572369875263-1003)
*
* We don't receive the D:PARAI part (just the brackets in between). Each bracket represents an ACE.
* Get the substring between these brackets, then find this substring in the second ACL. And
* loop for each ACE.
*
* Note: This function should be called IsFirstAclContainedInSecondAcl(). This is because the
* function only tests for containment, not equality. To test for equality, Call this function
* again with IsSecondAclContainedInFirstAcl().
*
* This function was tested in a separate application. It may not have integrated properly into this application.
**/
BOOL result = TRUE;/* Default to true. */
std::basic_string<TCHAR> TempString, ACETemp = FirstAcl;
/* ACETemp will be our work string. */
std::basic_string<TCHAR>::size_type Iter1 = 0, Iter2 = 0;
while(ACETemp.size() > 1)
{
/* Anchor Iter1 and Iter2 between the brackets (inclusive) */
Iter1 = ACETemp.find(_T('('));
/* Anchor Iter1 at the First Bracket. */
if(Iter1 > ACETemp.size())
{/* End of ACLs, return the result. */
return result;
}
/* Anchor Iter2 at the second bracket. */
Iter2 = ACETemp.find(_T(')'), Iter1 + 1);
TempString = ACETemp.substr(Iter1, Iter2 + 1 - Iter1);
/* Now that we have an ACE, find this ACE in SecondAcl. */
if(SecondAcl.find(TempString) > SecondAcl.size())
{/* Not found eh? The acls aren't equal. */
result = FALSE;
return result;
}
/* We must now erase this ACE from ACEAnchor. */
ACETemp = ACETemp.substr(Iter2 + 1, ACETemp.size() - Iter2 - 1);
}
return result;
}
SECURITY_INFORMATION CompareSDs(const std::basic_string<TCHAR> &SDStr, const std::basic_string<TCHAR> &SDStr1st)
{/** This function compares string security descriptor 1 against string security descriptor 2.
* This requires us to tear apart the security descriptor into pieces.
* The return value is either 0 if the SDs are unequal, otherwise, psi returns the information that's wrong.
* The function leaks an exception if there are problems.
**/
std::basic_string<TCHAR> pSD = SDStr, pSD1st = SDStr1st;
std::basic_string<TCHAR>::size_type Iter1 = 0, Iter2 = 0;
std::basic_string<TCHAR>::size_type i = 0, j = 0;
SECURITY_INFORMATION psi = 0;
for(i = 0; i < SDStr.size() && i < SDStr1st.size(); i = j)
{/* Get the next colon. */
Iter1 = SDStr.find(_T(":"), i);
if(Iter1 > SDStr.size()) break;
/* Anchor Iter2 to the next colon. */
Iter2 = SDStr.find(_T(":"), Iter1 + 1) - 1;
/* Place to just before the letter before the colon. */
if(Iter2 > SDStr.size()) Iter2 = pSD.size();
pSD = SDStr.substr(Iter1 + 1, Iter2 - Iter1 - 1);
j = Iter1 + 1;
/* pSD should now contain the value of this part. */
switch(static_cast<TCHAR>(SDStr.at(Iter1 - 1)))
{
case _T('D'):
{/* DACL information. */
Iter1 = SDStr1st.find(_T("D:"));
if(Iter1 > SDStr1st.size())
{/* not found ==> conflict */
psi = psi | DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
break;
}
Iter2 = SDStr1st.find(_T(":"), Iter1 + 2) - 1;
if(Iter2 > SDStr1st.size()) Iter2 = SDStr1st.size();
pSD1st = SDStr1st.substr(Iter1 + 2, Iter2 - Iter1 - 2);
/* check the control flags */
Iter1 = pSD.find(_T('('));
Iter2 = pSD1st.find(_T('('));
if(Iter1 != Iter2)
{/* Wrong control flags. */
psi = psi | DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
break;
}
if(pSD.substr(0, Iter1).compare(pSD1st.substr(0, Iter2)) != 0)
{/* The control flags aren't the same */
psi = psi | DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
break;
}
Iter1 = pSD.find(_T('('));
if(Iter1 < pSD.size())
{/* Only copy ACEs if they are there. */
pSD = pSD.substr(Iter1, pSD.size() - Iter1);/* pSD now points to the bit after the control stuff */
}
/* Repeat for pSD1st */
Iter1 = pSD1st.find(_T('('));
if(Iter1 < pSD.size())
{
pSD1st = pSD1st.substr(Iter1, pSD1st.size() - Iter1);
}
if(pSD.find(_T('(')) > pSD.size() && pSD.find(_T(')')) < pSD1st.size())
{/* One has ACEs, but the other doesn't: they're different. */
psi = psi | DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
break;
}
if(AreAclsEqual(pSD, pSD1st) != TRUE || AreAclsEqual(pSD1st, pSD) != TRUE)
{/* Cause it's so tough, we're sending it to another function to compare the ACLs. */
psi = psi | DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
break;
}
break;
}
case _T('O'):
{/* Owner information. Find the corresponding item in SDStr1st */
Iter1 = SDStr1st.find(_T("O:"));
if(Iter1 > SDStr1st.size())
{/* not found ==> conflict */
psi |= OWNER_SECURITY_INFORMATION;
break;
}
Iter2 = SDStr1st.find(_T(":"), Iter1 + 2) - 1;
if(Iter2 > SDStr1st.size()) Iter2 = SDStr1st.size();
pSD1st = SDStr1st.substr(Iter1 + 2, Iter2 - Iter1 - 2);
if(pSD.compare(pSD1st) != 0)
{/* The SIDs should be equal. */
psi |= OWNER_SECURITY_INFORMATION;
break;
}
break;
}
case _T('G'):
{/* Group information can be tackled in a similar fashion as owner information */
Iter1 = SDStr1st.find(_T("G:"));
if(Iter1 > SDStr1st.size())
{/* not found ==> conflict */
psi |= GROUP_SECURITY_INFORMATION;
break;
}
Iter2 = SDStr1st.find(_T(":"), Iter1 + 2) - 1;
if(Iter2 > SDStr1st.size()) Iter2 = SDStr1st.size();
pSD1st = SDStr1st.substr(Iter1 + 2, Iter2 - Iter1 - 2);
if(pSD.compare(pSD1st) != 0)
{/* The SIDs should be equal. */
psi |= GROUP_SECURITY_INFORMATION;
break;
}
break;
}
case _T('S'):
{/* SACL information. Once DACL is written, then this case is rather easy. */
Iter1 = SDStr1st.find(_T("S:"));
/* 1.08 fix D->S. */
if(Iter1 > SDStr1st.size())
{/* not found ==> conflict */
psi = psi | SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION;
break;
}
Iter2 = SDStr1st.find(_T(":"), Iter1 + 2) - 1;
if(Iter2 > SDStr1st.size()) Iter2 = SDStr1st.size();
pSD1st = SDStr1st.substr(Iter1 + 2, Iter2 - Iter1 - 2);
/* check the control flags */
Iter1 = pSD.find(_T('('));
Iter2 = pSD1st.find(_T('('));
if(Iter1 != Iter2)
{/* Wrong control flags. */
psi = psi | SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION;
break;
}
if(pSD.substr(0, Iter1).compare(pSD1st.substr(0, Iter2)) != 0)
{/* The control flags aren't the same */
psi = psi | SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION;
break;
}
Iter1 = pSD.find(_T('('));
if(Iter1 < pSD.size())
{/* Only copy ACEs if they are there. */
pSD = pSD.substr(Iter1, pSD.size() - Iter1);/* pSD now points to the bit after the control stuff */
}
/* Repeat for pSD1st */
Iter1 = pSD1st.find(_T('('));
if(Iter1 < pSD.size())
{
pSD1st = pSD1st.substr(Iter1, pSD1st.size() - Iter1);
}
if(pSD.find(_T('(')) > pSD.size() && pSD.find(_T(')')) < pSD1st.size())
{/* One has ACEs, but the other doesn't: they're different. */
psi = psi | SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION;
break;
}
if(AreAclsEqual(pSD, pSD1st) != TRUE || AreAclsEqual(pSD1st, pSD) != TRUE)
{/* Cause it's so tough, we're sending it to another function to compare the ACLs. */
psi = psi | SACL_SECURITY_INFORMATION | PROTECTED_SACL_SECURITY_INFORMATION |
UNPROTECTED_SACL_SECURITY_INFORMATION;
break;
}
break;
}
default:
throw STD(_T("Unexpected token found in this security descriptor"));
}
}
return psi;
}
#if 0
void SEFunc(unsigned int ExceptCode, EXCEPTION_POINTERS *ExceptPtrs)
{/* DLLs have little right to hijack the se_translator_function, so this function must be used sparingly. */
DWORD dwErr = ::GetLastError();
::SetLastError(ERROR_SUCCESS);
switch(ExceptCode)
{
case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
{
DelayLoadInfo *dli;
if(! ::IsBadReadPtr(ExceptPtrs->ExceptionRecord->ExceptionInformation[0], sizeof(DelayLoadInfo))
{
dli = ;
}
throw STD(_T(""));
}
default:
throw DWORD(ExceptCode);
}
}
#endif /* SEFunc is not good in a DLL. */