// UserFun.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int WellKnownSid2Trustee(void)
{
/* Wrap up the object in a CSid */
ATL::CSid SidUser(ATL::Sids::System());
std::wcout << SidUser.Sid();
TRUSTEE TrusteeSid = {0};
::BuildTrusteeWithSid(&TrusteeSid, const_cast<SID *>(SidUser.GetPSID()));
return 0;
}
void Sid2UserName(const SID *UserSid)
{
ATL::CSid UserCSid(UserSid /*, Domain */);
/* This line would be unnecessary if we passed in a CSid rather than an unwrapped SID */
std::wcout << UserCSid.AccountName();
}
int Sid2UserNamePrepare(void)
{
try {
ATL::CAccessToken ProcToken;
/* Get the user SID from the token. */
ATL::CSid UserResult;
ProcToken.GetEffectiveToken(TOKEN_READ);
ProcToken.GetUser(&UserResult);
Sid2UserName(UserResult);
} catch (CAtlException &ex) {
std::wcout << _T("Error: ") << static_cast<HRESULT>(ex);
}
return 0;
}
int IsAdminRunning(void)
{
/** BUGBUG: Only works if the admins group exists.
* Then again this entire function is a bug.
**/
bool IsMember = FALSE;
ATL::CAccessToken ProcToken;
ATL::CAccessToken ImpersonationToken;
ATL::CSid UserSid(Sids::Admins());
ProcToken.GetEffectiveToken(TOKEN_READ | TOKEN_DUPLICATE);
ProcToken.CreateImpersonationToken(&ImpersonationToken);
ImpersonationToken.CheckTokenMembership(UserSid, &IsMember);
return IsMember;
}
void SetPrivilege(const ATL::CStringT<TCHAR, ATL::StrTraitATL<TCHAR> > &lpszPrivilege, bool bEnablePrivilege)
{
/* Enables the specified privilege */
ATL::CAccessToken ProcToken;
ProcToken.GetEffectiveToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES);
if(bEnablePrivilege) ProcToken.EnablePrivilege(lpszPrivilege);
else ProcToken.DisablePrivilege(lpszPrivilege);
}
void LowerMyRights(ATL::CStringT<TCHAR, ATL::StrTraitATL<TCHAR> > lpCmdLine)
{
ATL::CTokenGroups SidsToRestrict, SidsToDisable;
ATL::CSid SidUser(ATL::Sids::Admins());
ATL::CTokenPrivileges PrivArray;
ATL::CAccessToken ProcToken, RestrictedToken;
ProcToken.GetEffectiveToken(TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_PRIVILEGES);
ProcToken.GetPrivileges(&PrivArray);
PrivArray.Delete(SE_CHANGE_NOTIFY_NAME);
/** Caution: this restricted token can get a little too restrictive. So you might want to choose the
* safer class instead.
**/
SidsToDisable.Add(SidUser, SE_GROUP_USE_FOR_DENY_ONLY | SE_GROUP_LOGON_ID);
ProcToken.CreateRestrictedToken(&RestrictedToken, SidsToDisable, SidsToRestrict, PrivArray);
{
PROCESS_INFORMATION piInfo = {0};
STARTUPINFO StartupInfo = {0};
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.lpDesktop = NULL;
RestrictedToken.CreateProcessAsUser(NULL, lpCmdLine.GetBuffer(), &piInfo, &StartupInfo, CREATE_NEW_CONSOLE);
}
}
void DoWhoAmI(void)
{
size_t i = 0;
ATL::CAccessToken ProcToken;
ATL::CSid SidUser;
ProcToken.GetEffectiveToken(TOKEN_QUERY);
/* First print off the user. */
ProcToken.GetUser(&SidUser);
std::wcout << _T("Owner: ") << SidUser.AccountName() << _T("\r\n");
/* Now print the groups */
ATL::CTokenGroups pGroups;
ProcToken.GetGroups(&pGroups);
ATL::CSid::CSidArray pSids;
ATL::CAtlArray<DWORD> pAttributes;
pGroups.GetSidsAndAttributes(&pSids, &pAttributes);
/* Iterate both pSids and pAttributes simultaneously */
std::wcout << _T("\r\nGroups\r\n");
for(i = 0; i < pGroups.GetCount() ; i++)
std::wcout << pSids[i].AccountName() << _T(": ") << pAttributes.GetAt(i) << _T("\r\n");
/* Get the list of Privileges */
ATL::CTokenPrivileges pPrivileges;
ProcToken.GetPrivileges(&pPrivileges);
ATL::CTokenPrivileges::CNames pNames;
ATL::CTokenPrivileges::CAttributes pGroupAttributes;
pPrivileges.GetNamesAndAttributes(&pNames, &pGroupAttributes);
std::wcout << _T("\r\nPrivileges\r\n");
for(i = 0; i < pGroups.GetCount() ; i++)
std::wcout << static_cast<LPCTSTR>(pNames.GetAt(i)) << _T(": ") << pGroupAttributes.GetAt(i) << _T("\r\n");
}
void ReadDacl(const ATL::CDacl &pDacl)
{
/* Prints a DACL */
UINT i = 0;
for(i = 0; i < pDacl.GetAceCount(); i++)
{
ATL::CSid pSid;
ACCESS_MASK pMask = 0;
BYTE pType = 0, pFlags = 0;
/* Get the ith ACL */
const_cast<ATL::CDacl &>(pDacl).GetAclEntry(i, &pSid, &pMask, &pType, &pFlags);
/* Now print out the results */
std::wcout << pSid.AccountName() << _T(": ");
switch (pType)
{
case ACCESS_ALLOWED_ACE_TYPE:
std::wcout << _T("allow");
break;
case ACCESS_DENIED_ACE_TYPE:
std::wcout << _T("deny");
break;
case SYSTEM_AUDIT_ACE_TYPE:
std::wcout << _T("audit");
break;
case SYSTEM_ALARM_ACE_TYPE:
std::wcout << _T("alarm");
break;
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
std::wcout << _T("complex allow");
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
std::wcout << _T("object allow");
break;
case ACCESS_DENIED_OBJECT_ACE_TYPE:
std::wcout << _T("object deny");
break;
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
std::wcout << _T("object audit");
break;
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
std::wcout << _T("object alarm");
break;
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
std::wcout << _T("callback allow");
break;
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
std::wcout << _T("callback deny");
break;
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
std::wcout << _T("callback object allow");
break;
case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
std::wcout << _T("callback object deny");
break;
case SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
std::wcout << _T("callback audit");
break;
case SYSTEM_ALARM_CALLBACK_ACE_TYPE:
std::wcout << _T("callback alarm");
break;
case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
std::wcout << _T("callback object audit");
break;
case SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:
std::wcout << _T("callback object alarm");
break;
default:
std::wcout << _T("Unknown");
break;
}
std::wcout << _T(": ");
if(pFlags & INHERITED_ACE)
std::wcout << _T("Inherited: ");
std::wcout << std::hex << pMask << std::dec << std::endl;
}
std::wcout << std::endl;
}
void PrintSecDesc(const ATL::CSecurityDesc &OutSecDesc)
{
/* SDDL: so just use ToString() */
ATL::CString pstr = _T("");
OutSecDesc.ToString(&pstr);
std::wcout << static_cast<LPCTSTR>(pstr);
}
void AddAccessAllowedToFile(const CStringT<TCHAR, ATL::StrTraitATL<TCHAR> > &FileName, ATL::CSecurityDesc &OutSecDesc)
{
bool pbPresent = 0;
ATL::CDacl pDacl;
OutSecDesc.GetDacl(&pDacl, &pbPresent);
if(pbPresent)
{
std::wcout << _T("\r\n\r\nDiscretionary Access Control List\r\n");
ReadDacl(pDacl);
}
pDacl.AddAllowedAce(ATL::Sids::Users(), FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
OutSecDesc.SetOwner(ATL::Sids::Admins(), false);
OutSecDesc.SetGroup(ATL::Sids::Admins(), false);
//OutSecDesc.SetSacl(Sacl);
OutSecDesc.SetControl(SE_DACL_AUTO_INHERITED | SE_DACL_PROTECTED, SE_DACL_AUTO_INHERITED);
if(::GetFileAttributes(FileName) == INVALID_FILE_ATTRIBUTES)
{/* The file exists */
SECURITY_ATTRIBUTES lpSecurityAttributes =
{sizeof(SECURITY_ATTRIBUTES), const_cast<SECURITY_DESCRIPTOR *>(OutSecDesc.GetPSECURITY_DESCRIPTOR()), FALSE};
::SetLastError(ERROR_SUCCESS);
/* We're going to use the low level Win32 APIs instead of ATL::CAtlFile */
ATL::CHandle FileHandle (::CreateFile(FileName, GENERIC_ALL | READ_CONTROL | WRITE_DAC,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &lpSecurityAttributes,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL));
if(static_cast<HANDLE>(FileHandle) == NULL || static_cast<HANDLE>(FileHandle) == INVALID_HANDLE_VALUE)
{
throw ATL::CAtlException(HRESULT_FROM_WIN32(::GetLastError()));
}
}
else
{/* It already exists */
ATL::AtlSetDacl(FileName, SE_FILE_OBJECT, pDacl);
ATL::CSacl pSacl;
/* We've already set the Dacl. Now set the SACL. */
OutSecDesc.GetSacl(&pSacl, &pbPresent);
if(pbPresent)
{
ATL::AtlSetSacl(FileName, SE_FILE_OBJECT, pSacl);
}
ATL::CSid pOwner, pGroup;
/* Owner */
if(OutSecDesc.GetOwner(&pOwner))
{
ATL::AtlSetOwnerSid(FileName, SE_FILE_OBJECT, pOwner);
}
/* Group */
if(OutSecDesc.GetGroup(&pGroup))
{
ATL::AtlSetGroupSid(FileName, SE_FILE_OBJECT, pGroup);
}
}
}
void CheckForAccess(ATL::CSecurityDesc &OutSecDesc)
{
/* Prepare and perform an access check on the security descriptor. */
ATL::CAccessToken ProcToken, ImpersonationToken;
ProcToken.GetEffectiveToken(TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE);
ProcToken.CreateImpersonationToken(&ImpersonationToken);
{/* We need an impersonation token, access mask, token handle, and generic mapping */
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
} ;
::AccessCheck(const_cast<SECURITY_DESCRIPTOR *>(OutSecDesc.GetPSECURITY_DESCRIPTOR()),
ImpersonationToken.GetHandle(), DesiredAccess, &GenericMapping, NULL, &PrivilegeSetLength,
&GrantedAccess, &AccessStatus);
ATL::CAutoVectorPtr<BYTE> PrivilegeSet(new BYTE[PrivilegeSetLength]);
::AccessCheck(const_cast<SECURITY_DESCRIPTOR *>(OutSecDesc.GetPSECURITY_DESCRIPTOR()),
ImpersonationToken.GetHandle(), DesiredAccess, &GenericMapping,
reinterpret_cast<PPRIVILEGE_SET>(static_cast<BYTE *>(PrivilegeSet)), &PrivilegeSetLength,
&GrantedAccess, &AccessStatus);
if(AccessStatus == TRUE)
{
std::wcout << std::hex << GrantedAccess << std::dec;
}
}
}
int GetFolderSecDesc(const CStringT<TCHAR, ATL::StrTraitATL<TCHAR> > &FileName)
{
/* AtlGetSecurityDescriptor gives us all we need. */
ATL::CSecurityDesc OutSecDesc;
ATL::AtlGetSecurityDescriptor(FileName, SE_FILE_OBJECT, &OutSecDesc);
OutSecDesc.MakeAbsolute();
PrintSecDesc(OutSecDesc);
AddAccessAllowedToFile(FileName, OutSecDesc);
CheckForAccess(OutSecDesc);
return 0;
}
int _tmain(void)
{
/* Tests program for the functions presented above. */
#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 */
/* Create a well known sid and print a trustee. */
WellKnownSid2Trustee();
std::wcout << std::endl;
/* Get the current user sid and print out a user name */
Sid2UserNamePrepare();
std::wcout << std::endl;
/* Check if the user is a member of the administrators group */
IsAdminRunning();
std::wcout << std::endl;
/* Obtain information from an access token. */
DoWhoAmI();
std::wcout << std::endl;
/* Open a program as a restricted user. */
LowerMyRights(IEXPLORE_PATH);
std::wcout << std::endl;
/* Enable the SeSecurityDescriptorPrivilege */
SetPrivilege(SE_SECURITY_NAME, TRUE);
{
/* Read, create and apply a security descriptor. */
GetFolderSecDesc(TESTSECUREFILE);
}
SetPrivilege(SE_SECURITY_NAME, FALSE);
std::wcout << std::endl;
try
{/* Privately Secure Object */
std::wcout << _T("\r\nCreating class");
ATL::SecureClass secObj1(ATL::SecureClass::ReadLen | ATL::SecureClass::CopyClass, CHandle(::GetCurrentThread()));
std::wcout << _T("\r\nlen is: ") << secObj1.get_len();
std::wcout << _T("\r\nCopying class");
ATL::SecureClass secObj2 = secObj1;
std::wcout << _T("\r\nAttempting to write class");
secObj2.set_len(5.) ; /* This should throw. */
} catch(ATL::CAtlException &e) {
std::wcout << _T("\r\nError: 0x") << std::hex << static_cast<HRESULT>(e) << std::dec;
}
/* end of program. */
std::wcout << std::endl;
return 0;
}