Click here to Skip to main content
15,896,201 members
Articles / Programming Languages / C++

The Windows Access Control Model Part 4

Rate me:
Please Sign up or sign in to vote.
4.86/5 (29 votes)
7 Sep 200543 min read 229.2K   6.8K   100  
The final article in the access control series presents a guide to the access control editor and its associated ISecurityInformation interface.
/**
*	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.
**/

#ifndef HELPER_H
#define HELPER_H
#pragma once


SECURITY_INFORMATION CompareSDs(const std::basic_string<TCHAR> &SDStr, const std::basic_string<TCHAR> &SDStr1st);
BOOL FixSDs(HWND TheirhWnd, SECURITY_INFORMATION psi, \
	const std::list< const std::basic_string<TCHAR> > &FileNamesCollection);
const BOOL AreAclsEqual(std::basic_string<TCHAR> &FirstAcl, std::basic_string<TCHAR> &SecondAcl);
const std::basic_string<TCHAR>::size_type
	CopyString(const std::basic_string<TCHAR> &OldClass, TCHAR *OutBuffer, size_t Count);
void About_OnHelp(HWND TheirhWnd);
INT_PTR CALLBACK AboutFunc(HWND TheirhWnd, UINT Msg, WPARAM wParam, LPARAM);
const std::basic_string<TCHAR>::size_type \
	CopyString(const std::basic_string<TCHAR> &OldClass, TCHAR *OutBuffer, size_t Count);



/* These are the global variables: */
extern const SI_ACCESS g_siObjAccesses[];
extern const OBJECT_TYPE_LIST g_DefaultOTL[];
extern const SI_INHERIT_TYPE g_InheritTypes[];
extern const ULONG gc_siObjAccesses, gc_DefaultOTL, gc_InheritTypes;
extern const int SILENT, ALLUSERSONLY, MEONLY, HKCRONLY;
extern UINT g_RefCount;
extern HANDLE g_hMutex;


class PrivMgrImpl
{/** This class manages the security privileges (SE_SECURITY_NAME et al.) and allows one to handle the
*	security privileges.
**/
public:
	explicit PrivMgrImpl();
	virtual ~PrivMgrImpl();
	friend class PrivMgr;
private:
	BOOL TrySetPrivilege(LPCTSTR lpszPrivilege = SE_SECURITY_NAME, BOOL bEnablePrivilege = FALSE);
	DWORD DoSetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege = SE_SECURITY_NAME, BOOL bEnablePrivilege = FALSE);
	size_t RefCount;
};

class PrivMgr
{/** This is a wrapper class to encapsulate the reference counting and prvilege name handling problem.
*	BUGBUG: You are responsible for enabling the privilege ONCE, and only once. No more no less.
*	If you enable it more than once, the privilege will be freed twice, and you should know that you
*	can't do that.
*	If you need to enable the privilege more than once, destroy the old handle Then allocate a new handle.
**/
public:
	explicit PrivMgr(const std::basic_string<TCHAR> &sPrivilege, PrivMgrImpl *HandedClass);
	~PrivMgr();
	BOOL TurnOn(void);
	PrivMgr &operator=(const PrivMgr &OldClass)
	{
		this->ObjImplPtr = OldClass.ObjImplPtr;
		this->SecuritySet = OldClass.SecuritySet;
	};
private:
	const std::basic_string<TCHAR> PrivilegeName;
	PrivMgrImpl *ObjImplPtr;
	BOOL SecuritySet;
};





namespace ShellAPI {/* The COMPtr for the IProgressDialog */
_COM_SMARTPTR_TYPEDEF(IProgressDialog, IID_IProgressDialog);
} /* namespace ShellAPI */




class CProgressDialog
{/* A class to manage the IProgressDialogBox */
private:
	HWND hWndOwner;
	ShellAPI::IProgressDialogPtr CProgressImpl;
	size_t Count;
	size_t ProgressCount;
	volatile BOOL Cancelled;
	CRITICAL_SECTION AutoCritSect;
protected:
	void SetLines(DWORD dwLineNum, const std::basic_string<TCHAR> pwzString);

public:
	CProgressDialog (HWND TheirhWnd = NULL, size_t CountIn = 1);
	CProgressDialog &operator=(const CProgressDialog &OldClass);
	virtual ~CProgressDialog();
	void set_Count(const size_t CountIn);
	size_t get_Count(void);
	BOOL get_Cancelled(void);

	void InitProgressDialog(HWND TheirhWnd);
	void IncProgressBar(const std::basic_string<TCHAR> pwzString);
	void Finish(void);
};


unsigned __stdcall CProgressThread_ThreadFunc(void *ThisPtr);
LRESULT CALLBACK CProgressThread_WndProc(HWND ThishWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

class CProgressThread
{
	friend unsigned __stdcall CProgressThread_ThreadFunc(void *ThisPtr);
	friend LRESULT CALLBACK CProgressThread_WndProc(HWND ThishWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

protected:
	/* This is the IPC handle */
	HWND hWndProgress;
	/* Changed in our thread. Only to be used in our thread. */
	HANDLE hThread;
	/* IPC Mutex for Inter-Thread synchronisation */
	HANDLE hStartupMutex;
	/* Changed in our thread. Only to be used in our thread. */
	unsigned ThrdID;
	/* Changed in their thread. Must only be used in their thread. */
	std::auto_ptr<CProgressDialog> CProgressImpl;
	/* Thread priority. */
	int ThrdPriority;

	/* The WM_APP messages for our Windows class. */
	enum OurWindowMessages
	{
		WM_Initialise = WM_USER + 1,	/* wParam = ParenthWnd, lParam = CountIn */
		WM_Finish, /* wParam = 0; lParam = 0 */
		WM_Count,	/* wParam == 0 ? Increment : SetToThisNumber (0 to return number); */
		WM_Increment	/* wParam = countIn */
	};
public:
	CProgressThread ();
	virtual ~CProgressThread();

	void DoCleanup(void);
	void InitProgressDialog(HWND TheirhWnd = NULL);
	void set_Count(const size_t CountIn);
	size_t get_Count(void) const;
	BOOL IncProgressBar(const std::basic_string<TCHAR> &CountIn);
	void Initialize(void);
	void Finish(void);

	
	CProgressThread &operator=(const CProgressThread &OldClass)
	{
		if(this == &OldClass) return *this;
		this->hWndProgress = OldClass.hWndProgress;
		this->hStartupMutex = OldClass.hStartupMutex;
		this->ThrdID = OldClass.ThrdID;
		this->hThread = OldClass.hThread;
		this->ThrdPriority = OldClass.ThrdPriority;
		if(OldClass.CProgressImpl.get() != NULL)
		{
			/* create our own ProgressDialog */
			this->CProgressImpl.reset(new CProgressDialog);
		}
		return *this;
	};

};


INT_PTR CALLBACK TreeErrorFunc(HWND TheirhWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
VOID WINAPI TreeCallBackFunc(wchar_t *pObjectName, DWORD Status, PROG_INVOKE_SETTING *pInvokeSetting, \
	void *PtrToThis, BOOL SecuritySet);

class CObjSecurity : public ISecurityInformation, public ISecurityObjectTypeInfo, public IEffectivePermission
{/** This class is the heart of FilePermsBox. The class is based on the one from QueryServiceConfig (hey look,
*	same name!), which in turn is based on one of the Platform SDK samples.
**/
protected:
    volatile LONG					m_cRef;				/* Warning, this variable requires locking. */
    DWORD							m_dwSIFlags;		/* Tells ACLUI what to show. */
	std::list<sized_array<TCHAR> >	m_pszObjectName;	/* Store object names in here. */
	HWND							ClasshWnd;			/* The list of windows and sheets used. */
	sized_array<TCHAR>				ServerName;			/* Holds the computer name. */
	BOOL							KeepExplicit;		/* For SI_RECURSE and ShowOnce stuff. */
	CProgressThread					CProgressObj;		/* For the Progress Dialog box */
	const SE_OBJECT_TYPE			SeObjectType;		/* Contains the object type */
	PROG_INVOKE_SETTING				pInvokeSetting;		/* Displays the user choice for setting security. */
	PrivMgrImpl						PrivClassImpl;		/* Holds the Privilege Manager (scoped to the class) */
	HMODULE							hAdvApi32;			/* These last two members are for runtime linking to an API */
	DWORD				(WINAPI *	pfnTreeResetNamedSecurityInfo)(LPTSTR, SE_OBJECT_TYPE, \
		SECURITY_INFORMATION, PSID, PSID, PACL, PACL, BOOL, FN_PROGRESS, PROG_INVOKE_SETTING, PVOID);
public:

	friend VOID WINAPI TreeCallBackFunc(wchar_t *pObjectName, DWORD Status, PROG_INVOKE_SETTING *pInvokeSetting, \
		void *PtrToThis, BOOL SecuritySet);
	/* TreeCallBackFunc Should be here, but TreeResetNamedSecurityInfo does not accept the methods as function pointers. */


	/* Constructors */
	CObjSecurity(const std::list< const std::basic_string<TCHAR> > &ObjName, \
		SE_OBJECT_TYPE seObj = SE_FILE_OBJECT, HWND TheirhWnd = NULL);
	CObjSecurity &operator=(const CObjSecurity &);
    virtual ~CObjSecurity();

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID, LPVOID *);
    STDMETHOD_(ULONG, AddRef)(void);
    STDMETHOD_(ULONG, Release)(void);

	/* ISecurityObjectTypeInfo methods */
	STDMETHOD(GetInheritSource)(SECURITY_INFORMATION psi, PACL pAcl, PINHERITED_FROM *ppInheritArray);

	/* IEffectivePermission methods */
	STDMETHOD(GetEffectivePermission)( const GUID *, PSID, LPCWSTR, PSECURITY_DESCRIPTOR, \
		POBJECT_TYPE_LIST *, ULONG *, PACCESS_MASK *, ULONG * );

	/* ISecurityInformation2 methods. E_NOTIMPL */
	STDMETHOD(LookupSids)(ULONG, PSID *, LPDATAOBJECT *);
	virtual BOOL STDMETHODCALLTYPE IsDaclCanonical(PACL);

	/* ISecurityInformation methods */
	STDMETHOD(GetObjectInformation)(PSI_OBJECT_INFO pObjectInfo);
	STDMETHOD(GetSecurity)(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD, BOOL fDefault);
    STDMETHOD(SetSecurity)(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD);	/* Locked to a single process. */
    STDMETHOD(GetAccessRights)(const GUID* pguidObjectType, DWORD dwFlags, PSI_ACCESS *ppAccess, \
		ULONG *pcAccesses, ULONG *piDefaultAccess);
    STDMETHOD(MapGeneric)(const GUID *pguidObjectType, UCHAR *pAceFlags, ACCESS_MASK *pmask);
    STDMETHOD(GetInheritTypes)(PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes);
    STDMETHOD(PropertySheetPageCallback)(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage);

	/* Our methods */
	BOOL GetTokenOwner(std::basic_string<TCHAR> &PrimaryUser);
	HWND get_currenthWnd(void);
	BOOL GetListOfFiles(std::list< const std::basic_string<TCHAR> > &DirectoryCollection, BOOL fRecurse);
	DWORD_PTR CloseCurrenthWnd(void);
	STDMETHOD(DisableSacl)(void);
	STDMETHOD(MakeWritable)(BOOL);

	/* refactored methods */
	STDMETHOD(SetSecurityForObject)(TCHAR *m_ObjectName, \
		const SECURITY_INFORMATION psi2, const PSECURITY_DESCRIPTOR pSD);
	void GetDefaultSecurity(const std::basic_string<TCHAR> &ObjName, std::basic_string<TCHAR> &PrimaryUser);
	virtual BOOL IsContainer(const std::basic_string<TCHAR> &ObjName);
	virtual DWORD RefreshShell(BOOL IsContainer);
	virtual DWORD SetSecurityForCollection(const std::list<const std::basic_string<TCHAR> > &DirectoryCollection, \
		SECURITY_INFORMATION psi, PSECURITY_DESCRIPTOR pSD);
	virtual DWORD TreeResetWin2k(TCHAR *m_ObjectName, PSECURITY_DESCRIPTOR ppSD, SECURITY_INFORMATION psi);

	BOOL IsDuplicate(const std::basic_string<TCHAR> &Iter, \
		const std::list< const std::basic_string<TCHAR> > &Collection);
	virtual BOOL GetServerNameForFile(const std::basic_string<TCHAR> &FileNameIn);

};


#endif /* HELPER_H */

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Mr. Shah is a reclusive C++/C# developer lurking somewhere in the depths of the city of London. He learnt physics at Kings' College London and obtained a Master in Science there. Having earned an MCAD, he teeters on the brink of transitioning from C++ to C#, unsure of which language to jump to. Fortunately, he also knows how to use .NET interop to merge code between the two languages (which means he won't have to make the choice anytime soon).

His interests (apart from programming) are walking, football (the real one!), philosophy, history, retro-gaming, strategy gaming, and any good game in general.

He maintains a website / blog / FAQ / junk at shexec32.serveftp.net, where he places the best answers he's written to the questions you've asked. If you can find him, maybe you can hire Mr. Shah to help you with anything C++[/CLI]/C#/.NET related Smile | :) .

Comments and Discussions