Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

640 lines
19 KiB

// Copyright (c) 1997-1999 Microsoft Corporation
#include "precomp.h"
#include <winioctl.h>
#include "si.h"
#include "resource.h"
#include <cguid.h>
#include <stdio.h>
//-----------------------------------------------------------------------------
CSecurityInformation::~CSecurityInformation()
{
}
#define HINST_THISDLL _Module.GetModuleInstance()
//-----------------------------------------------------------------------------
HRESULT CSecurityInformation::PropertySheetPageCallback(HWND hwnd,
UINT uMsg,
SI_PAGE_TYPE uPage)
{
return S_OK;
}
//======================================================================
//------------------- ISECURITYINFORMATION follows ---------------------------
//EXTERN_C const GUID IID_ISecurityInformation =
// { 0x965fc360, 0x16ff, 0x11d0, 0x91, 0xcb, 0x0, 0xaa, 0x0, 0xbb, 0xb7, 0x23 };
#define WBEM_ENABLE ( 0x0001 )
#define WBEM_METHOD_EXECUTE ( 0x0002 )
#define WBEM_FULL_WRITE_REP ( 0x001c )
#define WBEM_PARTIAL_WRITE_REP ( 0x0008 )
#define WBEM_WRITE_PROVIDER ( 0x0010 )
#define WBEM_REMOTE_ENABLE ( 0x0020 )
#define WBEM_GENERAL_WRITE (WBEM_FULL_WRITE_REP|WBEM_PARTIAL_WRITE_REP|WBEM_WRITE_PROVIDER)
#define WBEM_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED |\
SYNCHRONIZE |\
WBEM_ENABLE |\
WBEM_METHOD_EXECUTE |\
WBEM_FULL_WRITE_REP |\
WBEM_PARTIAL_WRITE_REP |\
WBEM_WRITE_PROVIDER)
#define WBEM_GENERIC_READ (STANDARD_RIGHTS_READ |\
WBEM_ENABLE)
#define WBEM_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\
WBEM_FULL_WRITE_REP |\
WBEM_PARTIAL_WRITE_REP |\
WBEM_WRITE_PROVIDER)
#define WBEM_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE |\
WBEM_METHOD_EXECUTE)
// The following array defines the permission names for WMI.
SI_ACCESS siWMIAccesses[] =
{
{ &GUID_NULL, WBEM_METHOD_EXECUTE, MAKEINTRESOURCEW(IDS_WBEM_GENERIC_EXECUTE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WBEM_FULL_WRITE_REP, MAKEINTRESOURCEW(IDS_WBEM_FULL_WRITE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WBEM_PARTIAL_WRITE_REP, MAKEINTRESOURCEW(IDS_WBEM_PARTIAL_WRITE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WBEM_WRITE_PROVIDER, MAKEINTRESOURCEW(IDS_WBEM_PROVIDER_WRITE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WBEM_ENABLE, MAKEINTRESOURCEW(IDS_WBEM_ENABLE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WBEM_REMOTE_ENABLE, MAKEINTRESOURCEW(IDS_WBEM_REMOTE_ENABLE), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, READ_CONTROL, MAKEINTRESOURCEW(IDS_WBEM_READ_SECURITY), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, WRITE_DAC, MAKEINTRESOURCEW(IDS_WBEM_EDIT_SECURITY), SI_ACCESS_GENERAL | SI_ACCESS_CONTAINER },
{ &GUID_NULL, 0, MAKEINTRESOURCEW(IDS_NONE), 0 }
};
#define iWMIDefAccess 4 // FILE_GENERAL_READ_EX
SI_ACCESS siWMIAccessesAdvanced[] =
{
{ &GUID_NULL, WBEM_METHOD_EXECUTE, MAKEINTRESOURCEW(IDS_WBEM_GENERIC_EXECUTE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WBEM_FULL_WRITE_REP, MAKEINTRESOURCEW(IDS_WBEM_FULL_WRITE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WBEM_PARTIAL_WRITE_REP, MAKEINTRESOURCEW(IDS_WBEM_PARTIAL_WRITE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WBEM_WRITE_PROVIDER, MAKEINTRESOURCEW(IDS_WBEM_PROVIDER_WRITE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WBEM_ENABLE, MAKEINTRESOURCEW(IDS_WBEM_ENABLE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WBEM_REMOTE_ENABLE, MAKEINTRESOURCEW(IDS_WBEM_REMOTE_ENABLE), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, READ_CONTROL, MAKEINTRESOURCEW(IDS_WBEM_READ_SECURITY), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, WRITE_DAC, MAKEINTRESOURCEW(IDS_WBEM_EDIT_SECURITY), SI_ACCESS_SPECIFIC },
{ &GUID_NULL, 0, MAKEINTRESOURCEW(IDS_NONE), 0 }
};
#define iWMIDefAccessAdvanced 4 // FILE_GENERAL_READ_EX
SI_INHERIT_TYPE siWMIInheritTypes[] =
{
&GUID_NULL, 0, MAKEINTRESOURCEW(IDS_WBEM_NAMESPACE),
&GUID_NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCEW(IDS_WBEM_NAMESPACE_SUBNAMESPACE),
&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, MAKEINTRESOURCEW(IDS_WBEM_SUBNAMESPACE_ONLY),
};
GENERIC_MAPPING WMIMap =
{
WBEM_GENERIC_READ,
WBEM_GENERIC_WRITE,
WBEM_GENERIC_EXECUTE,
WBEM_ALL_ACCESS
};
//---------------------------------------------------------------
CSDSecurity::CSDSecurity(struct NSNODE *nsNode,
_bstr_t server,
bool local)
: m_nsNode(nsNode),
m_server(server),
m_local(local),
m_pSidOwner(NULL),
m_pSidGroup(NULL)
{
}
//------------------ Accessors to the above arrays---------------
//---------------------------------------------------------------
HRESULT CSDSecurity::MapGeneric(const GUID *pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pMask)
{
*pAceFlags &= ~OBJECT_INHERIT_ACE;
MapGenericMask(pMask, &WMIMap);
return S_OK;
}
//-----------------------------------------------------------------------------
HRESULT CSDSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes)
{
*ppInheritTypes = siWMIInheritTypes;
*pcInheritTypes = ARRAYSIZE(siWMIInheritTypes);
return S_OK;
}
//---------------------------------------------------
LPWSTR CSDSecurity::CloneWideString(_bstr_t pszSrc )
{
LPWSTR pszDst = NULL;
pszDst = new WCHAR[(lstrlen(pszSrc) + 1)];
if (pszDst)
{
wcscpy( pszDst, pszSrc );
}
return pszDst;
}
//-----------------------------------------------------------------------------
HRESULT CSDSecurity::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
{
// ATLASSERT(pObjectInfo != NULL &&
// !IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
pObjectInfo->dwFlags = SI_EDIT_PERMS | /*SI_EDIT_OWNER |*/ // dacl, owner pages.
SI_ADVANCED | SI_CONTAINER |
SI_NO_TREE_APPLY | SI_NO_ACL_PROTECT;
USES_CONVERSION;
// NOTE: This weirdness is so nt4sp5+ can put up the
// user browser for Add User.
if(m_local)
{
pObjectInfo->pszServerName = NULL;
}
else
{
// NOTE: NT4 seems to want the "\\" and w2k doesn't care.
bstr_t temp(_T("\\\\"));
temp += m_server;
pObjectInfo->pszServerName = CloneWideString(temp);
}
pObjectInfo->hInstance = HINST_THISDLL;
pObjectInfo->pszObjectName = CloneWideString(m_nsNode->display);
return S_OK;
}
//-----------------------------------------------------------------------------
HRESULT CSDSecurity::GetAccessRights(const GUID *pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess)
{
// dwFlags is zero if the basic security page is being initialized,
// Otherwise, it is a combination of the following values:
// SI_ADVANCED - Advanced sheet is being initialized.
// SI_EDIT_AUDITS - Advanced sheet includes the Audit property page.
// SI_EDIT_PROPERTIES - Advanced sheet enables editing of ACEs that
// apply to object's properties and property sets
// We only currently support '0' or 'SI_ADVANCED'
ATLASSERT(0 == dwFlags || SI_ADVANCED == dwFlags);
if(0 == dwFlags)
{
*ppAccess = siWMIAccesses;
*pcAccesses = ARRAYSIZE(siWMIAccesses);
*piDefaultAccess = iWMIDefAccess;
}
else
{
*ppAccess = siWMIAccessesAdvanced;
*pcAccesses = ARRAYSIZE(siWMIAccessesAdvanced);
*piDefaultAccess = iWMIDefAccessAdvanced;
}
return S_OK;
}
//------------------ Real workers -------------------------------
//---------------------------------------------------------------
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
#define NextAce(Ace) ((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
/* Commenting out since winbase.h makes one available for 0x0500 and above
BOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR psd,
SECURITY_DESCRIPTOR_CONTROL wControlMask,
SECURITY_DESCRIPTOR_CONTROL wControlBits)
{
DWORD dwErr = NOERROR;
PISECURITY_DESCRIPTOR pSD = (PISECURITY_DESCRIPTOR)psd;
if (pSD)
pSD->Control = (pSD->Control & ~wControlMask) | wControlBits;
else
dwErr = ERROR_INVALID_PARAMETER;
return dwErr;
}
*/
void CSDSecurity::ProtectACLs(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
{
SECURITY_DESCRIPTOR_CONTROL wSDControl;
DWORD dwRevision;
PACL pAcl;
BOOL bDefaulted;
BOOL bPresent;
PACE_HEADER pAce;
UINT cAces;
if (0 == si || NULL == pSD)
return; // Nothing to do
// Get the ACL protection control bits
GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
wSDControl &= SE_DACL_PROTECTED | SE_SACL_PROTECTED;
if ((si & DACL_SECURITY_INFORMATION) && !(wSDControl & SE_DACL_PROTECTED))
{
wSDControl |= SE_DACL_PROTECTED;
pAcl = NULL;
GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted);
// Theoretically, modifying the DACL in this way can cause it to be
// no longer canonical. However, the only way this can happen is if
// there is an inherited Deny ACE and a non-inherited Allow ACE.
// Since this function is only called for root objects, this means
// a) the server DACL must have a Deny ACE and b) the DACL on this
// object must have been modified later. But if the DACL was
// modified through the UI, then we would have eliminated all of the
// Inherited ACEs already. Therefore, it must have been modified
// through some other means. Considering that the DACL originally
// inherited from the server never has a Deny ACE, this situation
// should be extrememly rare. If it ever does happen, the ACL
// Editor will just tell the user that the DACL is non-canonical.
//
// Therefore, let's ignore the possibility here.
if (NULL != pAcl)
{
for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
cAces > 0;
--cAces, pAce = (PACE_HEADER)NextAce(pAce))
{
pAce->AceFlags &= ~INHERITED_ACE;
}
}
}
if ((si & SACL_SECURITY_INFORMATION) && !(wSDControl & SE_SACL_PROTECTED))
{
wSDControl |= SE_SACL_PROTECTED;
pAcl = NULL;
GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefaulted);
if (NULL != pAcl)
{
for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
cAces > 0;
--cAces, pAce = (PACE_HEADER)NextAce(pAce))
{
pAce->AceFlags &= ~INHERITED_ACE;
}
}
}
SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED | SE_SACL_PROTECTED, wSDControl);
}
//---------------------------------------------------------------
HRESULT CSDSecurity::GetSecurity(THIS_ SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
BOOL fDefault )
{
// ATLASSERT(ppSecurityDescriptor != NULL);
HRESULT hr = E_FAIL;
*ppSecurityDescriptor = NULL;
if(fDefault)
{
ATLTRACE(_T("Default security descriptor not supported"));
return E_NOTIMPL;
}
// does it want something?
if(RequestedInformation != 0)
{
if(m_pSidOwner != NULL)
{
BYTE *p = (LPBYTE)m_pSidOwner;
delete []p;
m_pSidOwner = NULL;
}
if(m_pSidGroup != NULL)
{
BYTE *p = (LPBYTE)m_pSidGroup;
delete []p;
m_pSidGroup = NULL;
}
switch(m_nsNode->sType)
{
case TYPE_NAMESPACE:
{
CWbemClassObject _in;
CWbemClassObject _out;
hr = m_nsNode->ns->GetMethodSignatures("__SystemSecurity", "GetSD",
_in, _out);
if(SUCCEEDED(hr))
{
hr = m_nsNode->ns->ExecMethod("__SystemSecurity", "GetSD",
_in, _out);
if(SUCCEEDED(hr))
{
HRESULT hr1 = HRESULT_FROM_NT(_out.GetLong("ReturnValue"));
if(FAILED(hr1))
{
hr = hr1;
}
else
{
_out.GetBLOB("SD", (LPBYTE *)ppSecurityDescriptor);
hr = InitializeOwnerandGroup(ppSecurityDescriptor);
}
}
}
break;
}
case TYPE_STATIC_INSTANCE:
{
m_nsNode->pclsObj->GetBLOB("__SD",(LPBYTE *)ppSecurityDescriptor);
hr = InitializeOwnerandGroup(ppSecurityDescriptor);
break;
}
}
}
else
{
*ppSecurityDescriptor = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(*ppSecurityDescriptor)
InitializeSecurityDescriptor(*ppSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION);
else
hr = E_OUTOFMEMORY;
}
//ProtectACLs(RequestedInformation, *ppSecurityDescriptor);
return hr;
}
//-----------------------------------------------------------------------------
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
#define NextAce(Ace) ((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
HRESULT CSDSecurity::SetSecurity(SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
HRESULT hr = E_FAIL;
// dont pass the SI_OWNER_RECURSE bit to wbem.
// SecurityInformation &= ~(OWNER_SECURITY_INFORMATION | SI_OWNER_RECURSE);
// if something was changed...
if(SecurityInformation != 0)
{
// set the CONTAINER_INHERIT_ACE bit.
if(SecurityInformation & DACL_SECURITY_INFORMATION)
{
PACL pAcl = NULL;
BOOL bDefaulted;
BOOL bPresent;
PACE_HEADER pAce;
UINT cAces;
GetSecurityDescriptorDacl(pSecurityDescriptor, &bPresent, &pAcl, &bDefaulted);
if(NULL != pAcl)
{
for(cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
cAces > 0;
--cAces, pAce = (PACE_HEADER)NextAce(pAce))
{
// Make sure we don't get 'object inherit'
// This happens when creating a new ace from advance page
pAce->AceFlags &= ~OBJECT_INHERIT_ACE;
}
}
}
SECURITY_DESCRIPTOR *pSD = NULL;
// ACLUI sends absolute format so change to self-relative so the
// PutBLOB() has contiguous memory to copy.
DWORD srLen = 0;
SetLastError(0);
BOOL bCheck;
if(m_pSidOwner != NULL)
{
bCheck = SetSecurityDescriptorOwner(pSecurityDescriptor,m_pSidOwner,m_bOwnerDefaulted);
if(bCheck == FALSE)
{
return E_FAIL;
}
}
if(m_pSidGroup != NULL)
{
bCheck = SetSecurityDescriptorGroup(pSecurityDescriptor,m_pSidGroup,m_bGroupDefaulted);
if(bCheck == FALSE)
{
return E_FAIL;
}
}
// get the size needed.
BOOL x1 = MakeSelfRelativeSD(pSecurityDescriptor, NULL, &srLen);
DWORD eee = GetLastError();
pSD = (SECURITY_DESCRIPTOR *)LocalAlloc(LPTR, srLen);
if(pSD)
{
BOOL converted = MakeSelfRelativeSD(pSecurityDescriptor, pSD, &srLen);
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
return hr;
}
switch(m_nsNode->sType)
{
case TYPE_NAMESPACE:
{
CWbemClassObject _in;
CWbemClassObject _out;
hr = m_nsNode->ns->GetMethodSignatures("__SystemSecurity", "SetSD",
_in, _out);
if(SUCCEEDED(hr))
{
_in.PutBLOB("SD", (LPBYTE)pSD, GetSecurityDescriptorLength(pSD));
hr = m_nsNode->ns->ExecMethod("__SystemSecurity", "SetSD",
_in, _out);
if(SUCCEEDED(hr))
{
HRESULT hr1 = HRESULT_FROM_NT(_out.GetLong("ReturnValue"));
if(FAILED(hr1))
{
hr = hr1;
}
}
}
// HACK: because of how the core caches/uses security, I have to close &
// reopen my connection because GetSecurity() will be immediately called
// to refresh the UI. If I dont do this, GetSecurity() will return to old
// security settings even though they're really saved.
m_nsNode->ns->DisconnectServer();
CHString1 path;
// if we've got a server, here - append it.
if (((BSTR)m_server != NULL) && wcslen(m_server))
path = CHString1("\\\\") + CHString1((BSTR)m_server) + CHString1("\\") + CHString1((BSTR)m_nsNode->fullPath);
else
path = m_nsNode->fullPath;
m_nsNode->ns->ConnectServer(_bstr_t((const WCHAR*)path));
break;
}
case TYPE_STATIC_INSTANCE:
{
m_nsNode->pclsObj->PutBLOB("__SD",(LPBYTE)pSD, GetSecurityDescriptorLength(pSD));
//Now put the instance back
hr = m_nsNode->ns->PutInstance(*(m_nsNode->pclsObj)/*,flag*/);
delete m_nsNode->pclsObj;
*(m_nsNode->pclsObj) = m_nsNode->ns->GetObject(m_nsNode->relPath/*,flag*/);
break;
}
}
if(m_pSidOwner != NULL)
{
BYTE *p = (LPBYTE)m_pSidOwner;
delete []p;
m_pSidOwner = NULL;
}
if(m_pSidGroup != NULL)
{
BYTE *p = (LPBYTE)m_pSidGroup;
delete []p;
m_pSidGroup = NULL;
}
}
return hr;
}
HRESULT CSDSecurity::InitializeOwnerandGroup(PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
{
SID *pSid;
BOOL bDefaulted;
BOOL bCheck = GetSecurityDescriptorOwner(*ppSecurityDescriptor,
(void **)&pSid,&m_bOwnerDefaulted);
if(bCheck == TRUE)
{
if (pSid != NULL)
{
m_nLengthOwner = GetSidLengthRequired(pSid->SubAuthorityCount);
if(m_pSidOwner != NULL)
{
BYTE *p = (LPBYTE)m_pSidOwner;
delete []p;
m_pSidOwner = NULL;
}
m_pSidOwner = (SID *)new BYTE[m_nLengthOwner];
if(m_pSidOwner == NULL ||
CopySid(m_nLengthOwner,m_pSidOwner,pSid) == FALSE)
{
delete m_pSidOwner;
m_pSidOwner = NULL;
m_nLengthOwner = -1;
return E_FAIL;
}
}
else
{
m_pSidOwner = NULL;
m_nLengthOwner = 0;
}
}
else
{
m_pSidOwner = NULL;
m_nLengthOwner = -1;
return E_FAIL;
}
SID *pGroup;
bCheck = GetSecurityDescriptorGroup(*ppSecurityDescriptor,
(void **)&pGroup,&m_bGroupDefaulted);
if(bCheck == TRUE)
{
if (pGroup != NULL)
{
m_nLengthGroup = GetSidLengthRequired(pGroup->SubAuthorityCount);
if(m_pSidGroup != NULL)
{
BYTE *p = (LPBYTE)m_pSidGroup;
delete []p;
m_pSidGroup = NULL;
}
m_pSidGroup = (SID *)new BYTE[m_nLengthGroup];
if(m_pSidGroup == NULL ||
CopySid(m_nLengthGroup,m_pSidGroup,pGroup) == FALSE)
{
delete m_pSidGroup;
m_pSidGroup = NULL;
m_nLengthGroup = -1;
return E_FAIL;
}
}
else
{
m_pSidGroup = NULL;
m_nLengthGroup = 0;
}
}
else
{
m_pSidGroup = NULL;
m_nLengthGroup = -1;
return E_FAIL;
}
return S_OK;
}