#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _WIN32_WINNT 0x400
#define _CRTDBG_MAP_ALLOC
#include<aclapi.h>
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<crtdbg.h>
#include<tchar.h>
//***********************************************
BOOL GetTextualSid(PSID pSid, LPTSTR TextualSid, LPDWORD lpdwBufferLen)
{/* This is a helper function from http://www.codeproject.com/system/sid.asp */
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwSidRev=SID_REVISION;
DWORD dwCounter;
DWORD dwSidSize;
// Validate the binary SID.
if(!IsValidSid(pSid)) return FALSE;
// Get the identifier authority value from the SID.
psia = GetSidIdentifierAuthority(pSid);
// Get the number of subauthorities in the SID.
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
// Compute the buffer length.
// S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
// Check input buffer length.
// If too small, indicate the proper size and set the last error.
if (*lpdwBufferLen < dwSidSize || TextualSid == NULL)
{
*lpdwBufferLen = dwSidSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Add 'S' prefix and revision number to the string.
dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
// Add a SID identifier authority to the string.
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
}
else
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("%lu"),
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
}
// Add SID subauthorities to the string.
//
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
{
dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
*GetSidSubAuthority(pSid, dwCounter) );
}
return TRUE;
}
int WellKnownSid2Trustee(void)
{/* Q1. */
const TCHAR SystemSid[] = _T("SYSTEM"); /* SYSTEM */
PSID SidUser = NULL; /* This is where the resultant SID is returned */
DWORD cchName = 0, cchReferencedDomainName = 0; /* Will hold buffer sizes */
LPTSTR SidText = NULL; /* Will hold the final SID */
LPTSTR ReferencedDomainName = NULL; /* Dummy variable */
SID_NAME_USE peUse = SidTypeUser; /* Dummy variable */
/* First Call LookupAccountName() */
LookupAccountName(NULL, SystemSid, SidUser, &cchName, NULL, &cchReferencedDomainName, &peUse);
/* This was expected to fail. We should have allocated large enough buffers */
SidUser = (PSID)calloc(cchName, 1);
if(SidUser == NULL)
{
return 1;
}
ReferencedDomainName = (LPTSTR)calloc(cchReferencedDomainName, sizeof(TCHAR));
if(ReferencedDomainName == NULL)
{
free(SidUser); SidUser = NULL;
return 1;
}
/* Now let's try that again. */
if(!LookupAccountName(NULL, SystemSid, SidUser, &cchName, ReferencedDomainName, &cchReferencedDomainName, &peUse))
{
free(SidUser); SidUser = NULL;
free(ReferencedDomainName); ReferencedDomainName = NULL;
return 1;
}
free(ReferencedDomainName); ReferencedDomainName = NULL;
/* Now we have the SID: return the textual representation of that. */
GetTextualSid(SidUser, NULL, &cchName);
/* Did we forget something? */
SidText = (TCHAR *)calloc(cchName, sizeof(TCHAR));
if(SidText == NULL)
{
free(SidUser); SidUser = NULL;
return 1;
}
GetTextualSid(SidUser, SidText, &cchName);
/* Why would you need a TRUSTEE structure? It's rather useless to you. */
{
TRUSTEE TrusteeSid = {0};
TrusteeSid.pMultipleTrustee = NULL;
TrusteeSid.ptstrName = (LPTSTR)(SidUser);
TrusteeSid.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
TrusteeSid.TrusteeForm = TRUSTEE_IS_SID;
TrusteeSid.TrusteeType = TRUSTEE_IS_UNKNOWN;
}
free(SidUser); SidUser = NULL;
/* That should be it. */
_tprintf(_T("%s"), SidText);
free(SidText); SidText = NULL;
return 0;
}
#define MAX_USERNAME_LENGTH 256
int Sid2UserName(const PSID UserSid, OUT LPTSTR ReferencedDomainName, OUT LPTSTR UserName)
{
DWORD cchName = MAX_USERNAME_LENGTH, cchReferencedDomainName = MAX_USERNAME_LENGTH;
SID_NAME_USE peUse = SidTypeUser;
if(UserName==NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 1;
}
/* Get the username */
LookupAccountSid(NULL, UserSid, UserName, &cchName, ReferencedDomainName, &cchReferencedDomainName, &peUse);
return 0;
}
int Sid2UserNamePrepare(void)
{
/* Setup the current thread token. */
HANDLE hToken = NULL;
DWORD TokenInformationLength = 0, ReturnLength = 0;
TOKEN_USER *TokenInformation = NULL;
TCHAR UserName[MAX_USERNAME_LENGTH] = _T("");
if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken))
{
OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
}
/* Get the current user from GetTokenInformation(TokenUser) */
GetTokenInformation(hToken, TokenUser, NULL, TokenInformationLength, &ReturnLength);
TokenInformation = (TOKEN_USER *)calloc(ReturnLength, 1);
if(TokenInformation == NULL)
{
CloseHandle(hToken); hToken = NULL;
return 1;
}
TokenInformationLength = ReturnLength;
if(GetTokenInformation(hToken, TokenUser, TokenInformation, TokenInformationLength, &ReturnLength))
{/* Now that we have the SID, convert it to a user name */
TCHAR ReferencedDomainName[MAX_USERNAME_LENGTH] = _T("");
Sid2UserName(TokenInformation->User.Sid, ReferencedDomainName, UserName);
_tprintf(_T("%s\\%s"), ReferencedDomainName, UserName);
}
free(TokenInformation); TokenInformation = NULL;
CloseHandle(hToken); hToken = NULL;
return 0;
}
BOOL IsAdminRunning(void)
{
BOOL IsMember = FALSE;
size_t i = 0;
SID_IDENTIFIER_AUTHORITY peUse = SECURITY_NT_AUTHORITY;
PSID SidUser = NULL;
HANDLE ProcToken = NULL;
LPVOID TokenInformation = NULL;
TOKEN_GROUPS *TokenGroupList = NULL;
DWORD TokenInformationLength = 0, ReturnLength = 0;
/* Create a SID with the Admins RID */
if(!AllocateAndInitializeSid(&peUse, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,
0, 0, 0, 0, 0, &SidUser))
{
return FALSE;
}
if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_DUPLICATE, TRUE, &ProcToken))
{
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_DUPLICATE, &ProcToken))
{
FreeSid(SidUser); SidUser = NULL;
return FALSE;
}
}
// DuplicateToken(ProcToken, SecurityImpersonation, &ImpersonationToken);
/* Call GetTokenInformation(TokenGroups) */
GetTokenInformation(ProcToken, TokenGroups, TokenInformation, TokenInformationLength, &ReturnLength);
TokenInformationLength = ReturnLength;
TokenInformation = calloc(TokenInformationLength, sizeof(BYTE));
if(TokenInformation == NULL)
{
FreeSid(SidUser); SidUser = NULL;
CloseHandle(ProcToken); ProcToken = NULL;
return FALSE;
}
GetTokenInformation(ProcToken, TokenGroups, TokenInformation, TokenInformationLength, &ReturnLength);
TokenGroupList = (TOKEN_GROUPS *)(TokenInformation);
for(i = 0; i < TokenGroupList->GroupCount ; i++)
{/* Search for the SID in the Groups Array */
if(EqualSid(TokenGroupList->Groups[i].Sid, SidUser))
{/* If found, and is enabled, we are an admin */
if(TokenGroupList->Groups[i].Attributes & SE_GROUP_ENABLED ||
TokenGroupList->Groups[i].Attributes & SE_GROUP_ENABLED_BY_DEFAULT )
{
IsMember = TRUE;
break;
}
}
}
FreeSid(SidUser); SidUser = NULL;
CloseHandle(ProcToken); ProcToken = NULL;
free(TokenInformation); TokenInformation = NULL;
return IsMember;
}
BOOL DoWhoAmI(void)
{
/* returns false on failure */
// BOOL bResult = FALSE;
size_t i = 0;
HANDLE ProcToken = NULL;
TOKEN_GROUPS_AND_PRIVILEGES *tp = NULL;
DWORD ReturnLength = 0, TokenInformationLength = 0;
TCHAR *PrivilegeName = NULL;
if( !OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, TRUE, &ProcToken) &&
!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &ProcToken))
{
return FALSE;
}
/* Call GetTokenInformation(TokenGroupsAndPrivileges) */
GetTokenInformation(ProcToken, TokenGroupsAndPrivileges, tp, TokenInformationLength, &ReturnLength);
tp = (TOKEN_GROUPS_AND_PRIVILEGES *)(calloc(ReturnLength, 1));
if(!tp)
{
CloseHandle(ProcToken); ProcToken = NULL;
return FALSE;
}
TokenInformationLength = ReturnLength;
GetTokenInformation(ProcToken, TokenGroupsAndPrivileges, tp, TokenInformationLength, &ReturnLength);
/* Start off with AuthenticationId */
_tprintf(_T("\r\nAuthentication ID:%d%d\r\n"), (tp->AuthenticationId.HighPart), (tp->AuthenticationId.LowPart));
_tprintf(_T("\r\nPrivileges\r\n"));
for(i = 0; i < tp->SidCount; i++)
{/* Groups */
TCHAR UserName[MAX_USERNAME_LENGTH] = _T("");
TCHAR ReferencedDomainName[MAX_USERNAME_LENGTH] = _T("");
Sid2UserName(tp->Sids[i].Sid, ReferencedDomainName, UserName);
_tprintf(_T("\r\n%s\\%s: %d"), ReferencedDomainName, UserName, tp->Sids[i].Attributes);
}
_tprintf(_T("\r\nRestricted Sids\r\n"));
for(i = 0; i < tp->RestrictedSidCount; i++)
{/* Restricted Sids */
TCHAR UserName[MAX_USERNAME_LENGTH] = _T("");
TCHAR ReferencedDomainName[MAX_USERNAME_LENGTH] = _T("");
Sid2UserName(tp->Sids[i].Sid, ReferencedDomainName, UserName);
_tprintf(_T("\r\n%s\\%s: %d"), UserName, ReferencedDomainName, tp->RestrictedSids[i].Attributes);
}
_tprintf(_T("\r\nPrivileges\r\n"));
for(i = 0; i < tp->PrivilegeCount; i++)
{/* Privileges */
ReturnLength = 0;
LookupPrivilegeName(NULL, &tp->Privileges[i].Luid, NULL, &ReturnLength);
ReturnLength++;
/* Docs are rather unclear on the null terminator ambiguity. Better safe than sorry. */
PrivilegeName = (TCHAR *)calloc(ReturnLength, sizeof(TCHAR));
if(PrivilegeName == NULL)
break;
LookupPrivilegeName(NULL, &tp->Privileges[i].Luid, PrivilegeName, &ReturnLength);
_tprintf(_T("\r\n%s: %d"), PrivilegeName, tp->Privileges[i].Attributes);
free(PrivilegeName); PrivilegeName = NULL;
}
CloseHandle(ProcToken); ProcToken = NULL;
free(tp); tp = NULL;
return TRUE;
}
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
/* returns false on failure */
BOOL bResult = FALSE;
HANDLE ProcToken = NULL;
TOKEN_PRIVILEGES tp = {0};
LUID luid = {0};
if( !OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, TRUE, &ProcToken) &&
!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &ProcToken))
{
return FALSE;
}
if(!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
{
CloseHandle(ProcToken); ProcToken = NULL;
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : 0;
/* Enable the privilege or disable all privileges. */
SetLastError(ERROR_SUCCESS);
bResult = (!AdjustTokenPrivileges(ProcToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) ||
GetLastError() != ERROR_SUCCESS) ;
CloseHandle(ProcToken); ProcToken = NULL;
return bResult;
}
PSECURITY_DESCRIPTOR GetSecurityDesc(LPCTSTR FileName)
{
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD LengthNeeded = 0;
/* Find the length needed for the security descriptor */
GetFileSecurity(FileName, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION, NULL, 0, &LengthNeeded);
pSecurityDescriptor = (PSECURITY_DESCRIPTOR)(LocalAlloc(LPTR, LengthNeeded));
if(pSecurityDescriptor == NULL)
{
return NULL;
}
SetLastError(ERROR_SUCCESS);
GetFileSecurity(FileName, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION, pSecurityDescriptor, LengthNeeded, &LengthNeeded);
return pSecurityDescriptor;
}
PSECURITY_DESCRIPTOR ConvertSecurityDescriptor(PSECURITY_DESCRIPTOR *ppSDIn)
{
PACL AbsDAcl = NULL, AbsSAcl = NULL ;
PSID AbsOwner = NULL, AbsGroup = NULL ;
DWORD dwSize = 0, dwSizes[5] = {0} ;
size_t i = 0 ;
PSECURITY_DESCRIPTOR ppSDOut = *ppSDIn;
/* Transfer ppSD into this variable. */
if(ppSDOut == NULL || !(((SECURITY_DESCRIPTOR*)ppSDOut)->Control & SE_SELF_RELATIVE))
{/* What do you mean? An African or European swallow? */
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
MakeAbsoluteSD(*ppSDIn, NULL, &dwSizes[0], NULL, &dwSizes[4], NULL, &dwSizes[3],
NULL, &dwSizes[2], NULL, &dwSizes[1]) ;
for(i = 0 ; i < 5 ; i++)
dwSize += dwSizes[i] ;
ppSDOut = (PSECURITY_DESCRIPTOR)
(LocalAlloc(LPTR, 2 * sizeof(ACL) + 2 * sizeof(SID) + dwSize)) ;
if(ppSDOut == NULL)
{/* HACKHACK: Allocate a 2D array with one LocalAlloc */
LocalFree(*ppSDIn); *ppSDIn = NULL;
return NULL;
}
/* Now set the pointers to the appropriate offsets. */
dwSize = dwSizes[0] ;
AbsOwner = (PSID)((BYTE *)(ppSDOut) + dwSize) ;
dwSize += sizeof(SID) + dwSizes[1] ;
AbsGroup = (PSID)((BYTE *)(ppSDOut) + dwSize) ;
dwSize += sizeof(SID) + dwSizes[2] ;
AbsSAcl = (PACL)((BYTE *)(ppSDOut) + dwSize) ;
dwSize += sizeof(ACL) + dwSizes[3] ;
AbsDAcl = (PACL)((BYTE *)(ppSDOut) + dwSize) ;
SetLastError(ERROR_SUCCESS) ;
MakeAbsoluteSD(*ppSDIn, ppSDOut, &dwSizes[0], AbsDAcl, &dwSizes[4], AbsSAcl,
&dwSizes[3], AbsOwner, &dwSizes[2], AbsGroup, &dwSizes[1]) ;
LocalFree(*ppSDIn); *ppSDIn = NULL;
return ppSDOut;
}
int PrintSecurityDescriptor(SECURITY_DESCRIPTOR *ppSD)
{
DWORD i = 0;
PACL pDacl = NULL;
ACE_HEADER *pAce = NULL;
TCHAR *UserName = NULL, *ReferencedDomainName = NULL;
if(ppSD == NULL || ppSD->Revision < SECURITY_DESCRIPTOR_REVISION || ppSD->Control & SE_SELF_RELATIVE)
{/* Assume that the security descriptor is in absolute form. (the compiler will warn if this isn't the case). */
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
ReferencedDomainName = (TCHAR *)calloc(MAX_USERNAME_LENGTH, sizeof(TCHAR));
UserName = (TCHAR *)calloc(MAX_USERNAME_LENGTH, sizeof(TCHAR));
if(!UserName || !ReferencedDomainName)
{
free(UserName); UserName = NULL;
free(ReferencedDomainName); ReferencedDomainName = NULL;
}
if(ppSD->Control & SE_DACL_PRESENT)
{
pDacl = ppSD->Dacl;
_tprintf(_T("DACL:"));
for(i = 0; i < pDacl->AceCount; i++)
{
GetAce(pDacl, i, &pAce);
_tprintf(_T("\r\n"));
switch(pAce->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
{
ACCESS_ALLOWED_ACE *TypedAce = (ACCESS_ALLOWED_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("allow: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_DENIED_ACE_TYPE:
{
ACCESS_DENIED_ACE *TypedAce = (ACCESS_DENIED_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("deny: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_AUDIT_ACE_TYPE:
{
SYSTEM_AUDIT_ACE *TypedAce = (SYSTEM_AUDIT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("audit: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_ALARM_ACE_TYPE:
{
SYSTEM_ALARM_ACE *TypedAce = (SYSTEM_ALARM_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("alarm: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
{
ACCESS_ALLOWED_OBJECT_ACE *TypedAce = (ACCESS_ALLOWED_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object allow: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
ACCESS_DENIED_OBJECT_ACE *TypedAce = (ACCESS_DENIED_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object deny: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
SYSTEM_AUDIT_OBJECT_ACE *TypedAce = (SYSTEM_AUDIT_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object audit: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
{
SYSTEM_ALARM_OBJECT_ACE *TypedAce = (SYSTEM_ALARM_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object alarm: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
{
ACCESS_ALLOWED_CALLBACK_ACE *TypedAce = (ACCESS_ALLOWED_CALLBACK_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("allow with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
{
ACCESS_DENIED_CALLBACK_ACE *TypedAce = (ACCESS_DENIED_CALLBACK_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("deny with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
{
SYSTEM_AUDIT_CALLBACK_ACE *TypedAce = (SYSTEM_AUDIT_CALLBACK_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("audit with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_ALARM_CALLBACK_ACE_TYPE:
{
SYSTEM_ALARM_CALLBACK_ACE *TypedAce = (SYSTEM_ALARM_CALLBACK_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("alarm with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
{
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE *TypedAce = (ACCESS_ALLOWED_CALLBACK_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object allow with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
{
ACCESS_DENIED_CALLBACK_OBJECT_ACE *TypedAce = (ACCESS_DENIED_CALLBACK_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object deny with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
{
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE *TypedAce = (SYSTEM_AUDIT_CALLBACK_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object audit with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:
{
SYSTEM_ALARM_CALLBACK_OBJECT_ACE *TypedAce = (SYSTEM_ALARM_CALLBACK_OBJECT_ACE *)pAce;
Sid2UserName((PSID)&TypedAce->SidStart, ReferencedDomainName, UserName);
_tprintf(_T("object alarm with callback: %s\\%s to %8x"), ReferencedDomainName, UserName, TypedAce->Mask);
break;
}
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
default:
{
_tprintf(_T("Unknown ACE"));
break;
}
}
}
}
free(UserName); UserName = NULL ;
free(ReferencedDomainName); ReferencedDomainName = NULL ;
return 1;
}
PACL RebuildAclFromScratch(SECURITY_DESCRIPTOR *pSecurityDescriptor, void *pAceAdd)
{/** Return a carbon copy of the pSecurityDescriptor's DACL, in LocalAlloc()'ed memory.
* And we're not allowed to use memcpy().
**/
PSID SidStart = NULL;
PACL pOldDacl = pSecurityDescriptor->Dacl, pNewDacl = NULL;
ACE_HEADER *pAce = NULL;
DWORD i = 0, n = pSecurityDescriptor->Dacl->AceCount, m = 0, TotalSize = sizeof(ACL);
/* You should know how many ACEs your DACL contains, otherwise you should reread part 1. */
/** First calculate how large your ACE is going to be. Note! We're making this unnecessarily
* hard for ourselves! We can just use pSecurityDescriptor->Dacl->AclSize as an alternative.
**/
for(i = 0; i < n; i++)
{
GetAce(pOldDacl, i, &pAce);
if( pAce->AceType > ACCESS_MIN_MS_OBJECT_ACE_TYPE &&
pAce->AceType < ACCESS_MAX_MS_OBJECT_ACE_TYPE)
{/** HACKHACK: the ACCESS_*_OBJECT_ACEs structures have the same signatures, therefore we can assume that
* the ACEs are of the same size. We can use this to simplify the calculations a bit. Don't rely on this
* being the case with later Windows versions.
**/
SidStart = &((ACCESS_ALLOWED_OBJECT_ACE *)pAce)->SidStart;
if(!IsValidSid(SidStart))
{/* skip the entry if the SID is invalid. */
continue;
}
TotalSize += sizeof(ACCESS_ALLOWED_OBJECT_ACE) - sizeof(DWORD);
TotalSize += GetLengthSid(SidStart);
m++; /* increment the object ace count */
}
else
{/** HACKHACK: We're also assuming that the other structures are of the same size.
* This is even less likely to be true
**/
SidStart = &((ACCESS_ALLOWED_ACE *)pAce)->SidStart;
if(!IsValidSid(SidStart))
{/* skip the entry if the SID is invalid. */
continue;
}
TotalSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
TotalSize += GetLengthSid(SidStart);
}
}
/* Add one more ACE type */
TotalSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(SidStart) - sizeof(DWORD);
/* Phew!! And all we did was just calculate the length of the ACL! */
pNewDacl = (PACL)LocalAlloc(LPTR, TotalSize);
if(pNewDacl == NULL)
{/* Allocate and initialize a buffer for the ACL. */
return FALSE;
}
InitializeAcl(pNewDacl, TotalSize, ACL_REVISION);
for(i = 0; i < n; i++)
{/* look up the deny ACEs */
GetAce(pOldDacl, i, &pAce);
switch(pAce->AceType)
{
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
{ /* For each deny ace found, add it to the end of the list */
AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, sizeof(pAce->AceSize));
break;
}
default:
break;
}
}
for(i = 0; i < n; i++)
{/* look up the allow ACEs */
GetAce(pOldDacl, i, &pAce);
switch(pAce->AceType)
{
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
break;
default:
{ /* This time add the ACE to the end if it ISN'T a deny ACE */
AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, pAce->AceSize);
break;
}
}
}
/* Finally, append the last ACE onto the end of this ACL */
AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAceAdd, pAce->AceSize);
/* This is a nightmare... you should seriously consider one of the other techniques. */
return pNewDacl;
}
ACCESS_ALLOWED_ACE *MakeAceToAdd(void)
{
PSID SidStart = NULL;
SID_IDENTIFIER_AUTHORITY peUse = SECURITY_NT_AUTHORITY;
ACCESS_ALLOWED_ACE *pAceAdd = NULL;
/* You should know how many ACEs your DACL contains, otherwise you should reread part 1. */
if(!AllocateAndInitializeSid(&peUse, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,
0, 0, 0, 0, 0, &SidStart))
{/* We're going to need a Builtin Admins SID */
return NULL;
}
/* We intend to add this ACE to the end of the list. Build up a low level ACE: Admins Full Control. */
pAceAdd = (ACCESS_ALLOWED_ACE *)calloc(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(SidStart), 1);
if(!pAceAdd)
{
FreeSid(SidStart); SidStart = NULL;
return NULL;
}
pAceAdd->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pAceAdd->Header.AceSize = (WORD)(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(SidStart));
pAceAdd->Header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE ;
pAceAdd->Mask = FILE_GENERIC_READ;
CopySid(GetLengthSid(SidStart), &pAceAdd->SidStart, SidStart);
FreeSid(SidStart); SidStart = NULL;
return pAceAdd;
}
int DoAccessCheck(PSECURITY_DESCRIPTOR OutSecDesc)
{
HANDLE ProcToken = NULL, ImpersonationToken = NULL;
PRIVILEGE_SET *PrivilegeSet = NULL;
BOOL AccessStatus = FALSE;
DWORD GrantedAccess = 0, PrivilegeSetLength = 0, DesiredAccess = FILE_GENERIC_WRITE;
GENERIC_MAPPING GenericMapping =
{
READ_CONTROL | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA | FILE_APPEND_DATA,
READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_EXECUTE,
FILE_ALL_ACCESS
} ;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &ProcToken))
{
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &ProcToken))
{
return 1;
}
}
if(!DuplicateToken(ProcToken, SecurityImpersonation, &ImpersonationToken))
{
CloseHandle(ProcToken); ProcToken = NULL;
return 1;
}
AccessCheck(OutSecDesc, ImpersonationToken, DesiredAccess, &GenericMapping, NULL, &PrivilegeSetLength,
&GrantedAccess, &AccessStatus);
PrivilegeSet = (PPRIVILEGE_SET)calloc(PrivilegeSetLength, 1);
if(PrivilegeSet == NULL)
{
CloseHandle(ProcToken); ProcToken = NULL;
CloseHandle(ImpersonationToken); ImpersonationToken = NULL;
return 1;
}
AccessCheck(OutSecDesc, ImpersonationToken, DesiredAccess, &GenericMapping, PrivilegeSet, &PrivilegeSetLength,
&GrantedAccess, &AccessStatus);
if(AccessStatus == TRUE)
{
_tprintf(_T("%x"), GrantedAccess==DesiredAccess);
}
free(PrivilegeSet); PrivilegeSet = NULL;
CloseHandle(ProcToken); ProcToken = NULL;
CloseHandle(ImpersonationToken); ImpersonationToken = NULL;
return 0;
}
int _tmain(void)
{
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PACL pDacl = NULL;
ACCESS_ALLOWED_ACE *pAceAdd = NULL;
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF |
_CRTDBG_ALLOC_MEM_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) ;
#endif /* _DEBUG. This detects memory leaks */
WellKnownSid2Trustee();
_tprintf(_T("\r\n"));
Sid2UserNamePrepare();
_tprintf(_T("\r\n"));
_tprintf(_T("%d\r\n"), IsAdminRunning());
DoWhoAmI();
_tprintf(_T("\r\n"));
SetPrivilege(SE_SECURITY_NAME, TRUE);
{
pSecurityDescriptor = GetSecurityDesc(_T("G:\\Documents and Settings"));
pSecurityDescriptor = ConvertSecurityDescriptor(&pSecurityDescriptor);
PrintSecurityDescriptor(pSecurityDescriptor);
_tprintf(_T("\r\n"));
pAceAdd = MakeAceToAdd();
_tprintf(_T("\r\n"));
pDacl = RebuildAclFromScratch(pSecurityDescriptor, pAceAdd);
_tprintf(_T("\r\n"));
DoAccessCheck(pSecurityDescriptor);
_tprintf(_T("\r\n"));
/* Free the buffers */
free(pAceAdd) ; pAceAdd = NULL;
LocalFree(pDacl); pDacl = NULL;
LocalFree(pSecurityDescriptor); pSecurityDescriptor = NULL;
}
SetPrivilege(SE_SECURITY_NAME, FALSE);
return 0;
}