Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C++

Using Access Control Lists to secure access to your objects

Rate me:
Please Sign up or sign in to vote.
4.81/5 (23 votes)
30 Nov 2004CPOL11 min read 94.8K   1.4K   51  
How to secure your objects
// AccessAttributes.cpp: implementation of the CAccessAttributes class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "AccessAttributes.h"
#include <lmcons.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAccessAttributes::CAccessAttributes(PACL pAcl)
{
	//	Initialise our security attributes to give access to
	//	anyone (including LocalService).
	memset(&m_sa, 0, sizeof(m_sa));
	m_sa.nLength = sizeof(m_sa);
	InitializeSecurityDescriptor(&m_sd, SECURITY_DESCRIPTOR_REVISION);
	m_pGroupSid = m_pOwnerSid = PSID(NULL);
	SetOwner();
	SetDACL(pAcl);
}

CAccessAttributes::~CAccessAttributes()
{
	delete m_pGroupSid;
	delete m_pOwnerSid;
}

void CAccessAttributes::SetDACL(PACL pAcl)
{
	SetSecurityDescriptorDacl(&m_sd, TRUE, pAcl, FALSE);
	m_sa.lpSecurityDescriptor = &m_sd;
}

void CAccessAttributes::SetSACL(PACL pAcl)
{
	SetSecurityDescriptorSacl(&m_sd, TRUE, pAcl, FALSE);
	m_sa.lpSecurityDescriptor = &m_sd;
}

bool CAccessAttributes::SetOwner(LPCTSTR pszOwner, LPCTSTR pszServer)
{
	TCHAR tszOwner[UNLEN + 1];
	DWORD dwLen = UNLEN;
	PSID  pSid = PSID(NULL);

	if (pszOwner == NULL)
		//	Default setting, make ourselves the owner
		GetUserName(tszOwner, &dwLen);
	else
		_tcsncpy(tszOwner, pszOwner, UNLEN);

	if ((pSid = GetSid(tszOwner, pszServer)) != PSID(NULL))
	{
		delete m_pOwnerSid;
		m_pOwnerSid = pSid;
		SetSecurityDescriptorOwner(&m_sd, m_pOwnerSid, FALSE);
		return true;
	}

	return false;
}

bool CAccessAttributes::SetGroup(LPCTSTR pszGroup, LPCTSTR pszServer)
{
	PSID pSid = PSID(NULL);
	
	if ((pSid = GetSid(pszGroup, pszServer)) != PSID(NULL))
	{
		delete m_pGroupSid;
		m_pGroupSid = pSid;
		SetSecurityDescriptorGroup(&m_sd, m_pGroupSid, FALSE);
		return true;
	}

	return false;
}

//	Global function to get a SID given a name and a server
PSID GetSid(LPCTSTR pszName, LPCTSTR pszServer)
{
	PSID		 pSid = PSID(NULL);
	TCHAR		 ptszDomainName[256];
	DWORD		 dwSIDSize = 0,
				 dwDomainNameSize = sizeof(ptszDomainName);
	SID_NAME_USE snuType = SidTypeUnknown;

	LookupAccountName(pszServer, pszName, NULL, &dwSIDSize, NULL, &dwDomainNameSize, &snuType);

	if (dwSIDSize)
	{
		//	Success, now allocate our buffers
		pSid = (PSID) new BYTE[dwSIDSize];

		if (!LookupAccountName(NULL, pszName, pSid, &dwSIDSize, ptszDomainName, &dwDomainNameSize, &snuType))
		{
			delete pSid;
			pSid = PSID(NULL);
		}
	}

	return pSid;
}

//	Helper class
CAccessControlList::CAccessEntry::CAccessEntry(eAceType type, PSID pSid, UINT uiRights)
{
	m_type = type; 
	m_pSid = pSid;
	m_uiRights = uiRights;
}

CAccessControlList::CAccessEntry::~CAccessEntry()
{
	delete m_pSid;
}

//	The access control list itself
CAccessControlList::CAccessControlList()
{
	m_pAcl = PACL(NULL);
	m_uiAclSize = sizeof(ACL);
}

CAccessControlList::~CAccessControlList()
{
	list<CAccessEntry *>::const_iterator it = m_lAce.begin();
	CAccessEntry						 *ae;

	while (it != m_lAce.end())
	{
		ae = *it++;
		delete ae;
	}

	delete m_pAcl;
}

bool CAccessControlList::Allow(LPCTSTR pszName, UINT uiRights, LPCTSTR pszServer)
{
	assert(pszName);

	PSID pSid = GetSid(pszName, pszServer);

	if (pSid != PSID(NULL) && IsValidSid(pSid))
	{
		m_uiAclSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
		m_lAce.push_back(new CAccessEntry(eAllow, pSid, uiRights));
		return true;
	}

	return false;
}

bool CAccessControlList::Deny(LPCTSTR pszName, UINT uiRights, LPCTSTR pszServer)
{
	assert(pszName);

	PSID pSid = GetSid(pszName, pszServer);

	if (pSid != PSID(NULL) && IsValidSid(pSid))
	{
		m_uiAclSize += sizeof(ACCESS_DENIED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
		m_lAce.push_back(new CAccessEntry(eDeny, pSid, uiRights));
		return true;
	}

	return false;
}

PACL CAccessControlList::operator&()
{
	delete m_pAcl;
	m_pAcl = (PACL) new BYTE[m_uiAclSize];

	//	Change the ACL_REVISION_DS constant to ACL_REVISION if you want to support
	//	Windows NT 4.0 or earlier
	InitializeAcl(m_pAcl, m_uiAclSize, ACL_REVISION_DS);
	AddAces(eDeny);
	AddAces(eAllow);
	return m_pAcl;
}

void CAccessControlList::AddAces(eAceType type)
{
	list<CAccessEntry *>::const_iterator it = m_lAce.begin();
	CAccessEntry						 *ae;

	//	Change the ACL_REVISION_DS constant to ACL_REVISION if you want to support
	//	Windows NT 4.0 or earlier
	while (it != m_lAce.end())
	{
		ae = *it++;

		if (ae->m_type == type)
		{
			switch (type)
			{
			case eDeny:
				AddAccessDeniedAce(m_pAcl, ACL_REVISION_DS, ae->m_uiRights, ae->m_pSid);
				break;

			case eAllow:
				AddAccessAllowedAce(m_pAcl, ACL_REVISION_DS, ae->m_uiRights, ae->m_pSid);
				break;
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I've been programming for 35 years - started in machine language on the National Semiconductor SC/MP chip, moved via the 8080 to the Z80 - graduated through HP Rocky Mountain Basic and HPL - then to C and C++ and now C#.

I used (30 or so years ago when I worked for Hewlett Packard) to repair HP Oscilloscopes and Spectrum Analysers - for a while there I was the one repairing DC to daylight SpecAns in the Asia Pacific area.

Afterward I was the fourth team member added to the Australia Post EPOS project at Unisys Australia. We grew to become an A$400 million project. I wrote a few device drivers for the project under Microsoft OS/2 v 1.3 - did hardware qualification and was part of the rollout team dealing directly with the customer.

Born and bred in Melbourne Australia, now living in Scottsdale Arizona USA, became a US Citizen on September 29th, 2006.

I work for a medical insurance broker, learning how to create ASP.NET websites in VB.Net and C#. It's all good.

Oh, I'm also a Kentucky Colonel. http://www.kycolonels.org

Comments and Discussions