#ifndef _xbSECURITY_
#define _xbSECURITY_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbSecurity
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbSTRING_
#	include "xbString.h"
#endif

#ifndef _xbDATA_
#	include "xbData.h"
#endif

enum xbSecurityType
{
	xbSecurityNone = 0,
	xbSecurityPrivate = 1,
	xbSecurityAll = 2,
	xbSecurityDflt = 3,
	xbSecurityInherited = 4, // = xbSecurityNone,
};

class xbEXPORT xbSecurity
{
public:
	xbSecurity(const SECURITY_DESCRIPTOR *pSelfRelativeSD)
	{
		Initialize(xbSecurityNone);
		CopyFrom(pSelfRelativeSD);
	}
	xbSecurity(const xbSecurity &sec)
	{
		Initialize(xbSecurityNone);
		CopyFrom(sec);
	}
	xbSecurity(xbSecurityType type = xbSecurityDflt,LPCSTR pRights = NULL);
	~xbSecurity();

	xbSecurity &operator=(const xbSecurity &sec)
	{
		CopyFrom(sec);
		return *this;
	}

	static void regBehaviour(xbSecurityType &type, xbString &strRights,LPCSTR pRights);
	static void rightsStringSecuTypeParse(const xbString &rights,xbSecurityType &type, xbString &strRights);
	void rightsStringParse(const xbString &strRights);
	static ulong rightsAttrStringParse(const xbString &strAttrs);
	static ulong rightsInhStringParse(const xbString &strAttrs);
	xbString rightStrings() const;
	xbString rightStringsAcePart() const;
	static xbString rightsAttr(ulong attr);
	static xbString rightsInhType(ulong attr);
//public:
	void Initialize(xbSecurityType type,LPCSTR pRights = NULL);
	void Empty() {Initialize(xbSecurityNone);}

	void CopyFrom(const SECURITY_DESCRIPTOR *pSelfRelativeSD);
	void CopyFromObject(HANDLE hObject);
	void CopyToObject(HANDLE hObject) const;

	bool CopyFromFSobject(LPCSTR pFileName,xbOpMode opm =xbOp_Required);
	bool CopyToFSobject(LPCSTR pFileName,xbOpMode opm =xbOp_Required) const;

	void SetProcessUserAndGrp(bool bDefaulted = false);
	void SetThreadUserAndGrp(bool bDefaulted = false, bool bIfNoneUseProcess = true);
	void SetUser(PSID pOwnerSid, bool bDefaulted = false);
	bool GetUser(xbTdata<SID> *pOwnerSid,bool *pbDefaulted=NULL,xbOpMode opm =xbOp_Required) const;
	void SetGroup(PSID pGroupSid, bool bDefaulted = false);
	bool GetGroup(xbTdata<SID> *pGroupSid,bool *pbDefaulted=NULL,xbOpMode opm =xbOp_Required) const;

	xbString GetUserName(xbOpMode opm =xbOp_Required) const;
	xbString GetGroupName(xbOpMode opm =xbOp_Required) const;

	void Allow(LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask/*=0*/);
	void Deny(LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask /*=0*/);
	int	 Remove(LPCTSTR pszUserOrGrp);

	// utility functions
	static void SetProcessPrivilege(LPCTSTR Privilege, bool bEnable = true);
	static void SetThreadPrivilege(LPCTSTR Privilege, bool bEnable = true, bool bOpenAsSelf = false);
	static void SetPrivilege(HANDLE hToken, LPCTSTR Privilege, bool bEnable = true);
	static void GetTokenSids(HANDLE hToken, xbTdata<SID>* ppUserSid, xbTdata<SID>* ppGroupSid);
	static bool GetProcessSids(xbTdata<SID>* ppUserSid, xbTdata<SID>* ppGroupSid = NULL,xbOpMode opm =xbOp_Required);
	static bool GetThreadSids(xbTdata<SID>* ppUserSid, xbTdata<SID>* ppGroupSid = NULL, xbOpMode opm =xbOp_Required,bool bOpenAsSelf = false);
	static void CopyACL(PACL pDest, PACL pSrc);
	static void GetCurrentUserSID(xbTdata<SID> *ppSid);
	static void AddAccessAllowedACEToACL(xbTdata<ACL> *ppAcl, LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask);
	static void AddAccessDeniedACEToACL(xbTdata<ACL> *ppAcl, LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask);
	static int RemoveUserOrGrpFromACL(PACL Acl, LPCTSTR pszUserOrGrp);
	static bool GetUserOrGrpSID(LPCTSTR pszUserOrGrp, xbTdata<SID> *ppSid,xbString *pDomain = NULL,PSID_NAME_USE pSidType = NULL,xbOpMode opm =xbOp_Required); //returns domain
	static xbString GetSIDname(PSID pSid, xbString *pDomain=NULL,PSID_NAME_USE pSidType=NULL); //returns user or group name

	operator SECURITY_DESCRIPTOR *()
	{
		return m_sd;
	}
	operator const SECURITY_DESCRIPTOR *() const
	{
		return m_sd;
	}
	
	SECURITY_DESCRIPTOR *Ptr() const {return m_sd.Ptr();}
	bool Check(xbOpMode opm) const;
	bool IsValid() const {return m_sd.IsValid();}
	bool IsEmpty() const {return m_sd.IsEmpty();}

protected:
	xbTdata<SECURITY_DESCRIPTOR>	m_sd;
	mutable xbTdata<SID>			m_user;
	mutable bool					m_userDefaulted,m_userSet;
	mutable xbTdata<SID>			m_group;
	mutable bool					m_groupDefaulted,m_groupSet;
	xbTdata<ACL>					m_dacl;
	xbTdata<ACL>					m_sacl;
};

class xbEXPORT xbSecurityAttr
{
public:
	xbSecurityAttr(xbSecurityType type = xbSecurityDflt,LPCSTR pRights = NULL,bool bInheritHandle = false)
		:m_security(xbIs95os()?xbSecurityNone:type,pRights)
	{
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = bInheritHandle?TRUE:FALSE;
		m_attr.lpSecurityDescriptor = m_security;
	}
	/*explicit xbSecurityAttr(const SECURITY_DESCRIPTOR *pSelfRelativeSD,bool bInheritHandle = false)
		:m_security(pSelfRelativeSD)
	{
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = bInheritHandle?TRUE:FALSE;
		m_attr.lpSecurityDescriptor = m_security;
	}*/
	xbSecurityAttr(const xbSecurity &sec,bool bInheritHandle = false)
		:m_security(sec)
	{
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = bInheritHandle?TRUE:FALSE;
		m_attr.lpSecurityDescriptor = m_security;
	}
	xbSecurityAttr(const xbSecurityAttr &attr)
		:m_security(attr.m_security)
	{
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = attr.m_attr.bInheritHandle;
		m_attr.lpSecurityDescriptor = m_security;
	}
	xbSecurityAttr &operator=(const xbSecurityAttr &attr)
	{
		m_security = attr.m_security;
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = attr.m_attr.bInheritHandle;
		m_attr.lpSecurityDescriptor = m_security;
		return *this;
	}

	void Initialize(xbSecurityType type,LPCSTR pRights = NULL,bool bInheritHandle = false)
	{
		m_security.Initialize(type,pRights);
		memset(&m_attr,0,sizeof(m_attr));
		m_attr.nLength = sizeof(m_attr);
		m_attr.bInheritHandle = bInheritHandle?TRUE:FALSE;
		m_attr.lpSecurityDescriptor = m_security;
	}

	bool GetInherit() {return m_attr.bInheritHandle?true:false;}
	void SetInherit(bool bVal) {m_attr.bInheritHandle = bVal?TRUE:FALSE;}

	void SecurityEmpty() 
	{
		m_security.Initialize(xbSecurityNone);
		m_attr.lpSecurityDescriptor = m_security;
	}

	void CopyFrom(const SECURITY_DESCRIPTOR *pSelfRelativeSD)
	{
		m_security.CopyFrom(pSelfRelativeSD);
		m_attr.lpSecurityDescriptor = m_security;
	}
	void CopyFromObject(HANDLE hObject)
	{
		m_security.CopyFromObject(hObject);
		m_attr.lpSecurityDescriptor = m_security;
	}
	void SetProcessUserAndGrp(bool bDefaulted = false)
	{
		m_security.SetProcessUserAndGrp(bDefaulted);
		m_attr.lpSecurityDescriptor = m_security;
	}
	void SetThreadUserAndGrp(bool bDefaulted = false, bool bIfNoneUseProcess = true)
	{
		m_security.SetThreadUserAndGrp(bDefaulted,bIfNoneUseProcess);
		m_attr.lpSecurityDescriptor = m_security;
	}
	void SetUser(PSID pOwnerSid, bool bDefaulted = false)
	{
		m_security.SetUser(pOwnerSid,bDefaulted);
		m_attr.lpSecurityDescriptor = m_security;
	}
	bool GetUser(xbTdata<SID> *pOwnerSid) const
	{
		return m_security.GetUser(pOwnerSid);
	}
	void SetGroup(PSID pGroupSid, bool bDefaulted = false)
	{
		m_security.SetGroup(pGroupSid,bDefaulted);
		m_attr.lpSecurityDescriptor = m_security;
	}
	bool GetGroup(xbTdata<SID> *pGroupSid) const
	{
		return m_security.GetGroup(pGroupSid);
	}

	void Allow(LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask = 0)
	{
		m_security.Allow(pszUserOrGrp,dwAccessMask,dwInhMask);
		m_attr.lpSecurityDescriptor = m_security;
	}
	void Deny(LPCTSTR pszUserOrGrp, DWORD dwAccessMask, DWORD dwInhMask = 0)
	{
		m_security.Deny(pszUserOrGrp,dwAccessMask,dwInhMask);
		m_attr.lpSecurityDescriptor = m_security;
	}
	int	 Remove(LPCTSTR pszUserOrGrp)
	{
		int ret = m_security.Remove(pszUserOrGrp);
		m_attr.lpSecurityDescriptor = m_security;
		return ret;
	}

	operator SECURITY_DESCRIPTOR *()
	{
		return m_security;
	}
	operator const SECURITY_DESCRIPTOR *() const
	{
		return m_security;
	}
	
	SECURITY_DESCRIPTOR *SecurityPtr() const {return m_security.Ptr();}

	operator SECURITY_ATTRIBUTES *()
	{
		return IsValid()?&m_attr:NULL;
	}
	operator const SECURITY_ATTRIBUTES *() const
	{
		return IsValid()?&m_attr:NULL;
	}
	
	SECURITY_ATTRIBUTES *Ptr() const {return (SECURITY_ATTRIBUTES*)&m_attr;}

	bool IsValid() const 
	{
		return m_attr.lpSecurityDescriptor || m_attr.bInheritHandle;
	}
	bool IsEmpty() const
	{
		return !m_attr.lpSecurityDescriptor && !m_attr.bInheritHandle;
	}

protected:
	SECURITY_ATTRIBUTES	m_attr;
	xbSecurity			m_security;
};

#endif
