mirror of https://github.com/tongzx/nt5src
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.
1361 lines
38 KiB
1361 lines
38 KiB
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Win9xSecurity.cpp
|
|
|
|
Abstract:
|
|
|
|
This class handles the importing of Win9x security data that was extracted from an old MMF format repository.
|
|
|
|
History:
|
|
|
|
03/17/2001 shbrown - created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <wbemcomn.h>
|
|
#include "Win9xSecurity.h"
|
|
#include <oahelp.inl>
|
|
|
|
bool CWin9xSecurity::Win9xBlobFileExists()
|
|
{
|
|
wchar_t wszFilePath[MAX_PATH+1];
|
|
if (!GetRepositoryDirectory(wszFilePath))
|
|
return false;
|
|
|
|
wcscat(wszFilePath, BLOB9X_FILENAME);
|
|
DWORD dwAttributes = GetFileAttributesW(wszFilePath);
|
|
if (dwAttributes != -1)
|
|
{
|
|
DWORD dwMask = FILE_ATTRIBUTE_DEVICE |
|
|
FILE_ATTRIBUTE_DIRECTORY |
|
|
FILE_ATTRIBUTE_OFFLINE |
|
|
FILE_ATTRIBUTE_REPARSE_POINT |
|
|
FILE_ATTRIBUTE_SPARSE_FILE;
|
|
|
|
if (!(dwAttributes & dwMask))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
HRESULT CWin9xSecurity::ImportWin9xSecurity()
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
wchar_t wszFilePath[MAX_PATH+1];
|
|
if (GetRepositoryDirectory(wszFilePath))
|
|
{
|
|
wcscat(wszFilePath, BLOB9X_FILENAME);
|
|
m_h9xBlobFile = CreateFileW(wszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
|
|
// get a session and begin a transaction
|
|
CSession* pSession = new CSession(m_pControl);
|
|
if (pSession == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pSession->AddRef();
|
|
CReleaseMe relMe(pSession);
|
|
|
|
hRes = pSession->BeginWriteTransaction(0);
|
|
if (FAILED(hRes))
|
|
{
|
|
return hRes;
|
|
}
|
|
|
|
// process the file
|
|
if (m_h9xBlobFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
try
|
|
{
|
|
hRes = DecodeWin9xBlobFile();
|
|
}
|
|
catch (...)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Traversal of Win9x security data import file failed\n"));
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
CloseHandle(m_h9xBlobFile);
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Could not open the Win9x security data import file for reading\n"));
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
if (DeleteWin9xBlobFile())
|
|
hRes = pSession->CommitTransaction(0);
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Win9x security data import completed but failed to delete import file\n"));
|
|
pSession->AbortTransaction(0);
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Win9x security data import failed to complete\n"));
|
|
pSession->AbortTransaction(0);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::DecodeWin9xBlobFile()
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// read the file header
|
|
if (!ReadWin9xHeader())
|
|
return WBEM_E_FAILED;
|
|
|
|
// import the file
|
|
BLOB9X_SPACER header;
|
|
DWORD dwSize;
|
|
while (hRes == WBEM_S_NO_ERROR)
|
|
{
|
|
// this loop will be exited when we either...
|
|
// - successfully process the whole import file, or
|
|
// - encounter an error
|
|
|
|
dwSize = 0;
|
|
if ((ReadFile(m_h9xBlobFile, &header, sizeof(header), &dwSize, NULL) == 0) || (dwSize != sizeof(header)))
|
|
{
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
else if ((header.dwSpacerType == BLOB9X_TYPE_SECURITY_INSTANCE) ||
|
|
(header.dwSpacerType == BLOB9X_TYPE_SECURITY_BLOB))
|
|
{
|
|
hRes = ProcessWin9xBlob(&header);
|
|
}
|
|
else if (header.dwSpacerType == BLOB9X_TYPE_END_OF_FILE)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hRes = WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
hRes = RecursiveInheritSecurity(NULL, L"root"); // force namespaces to inherit their inheritable security settings
|
|
|
|
return hRes;
|
|
}
|
|
|
|
bool CWin9xSecurity::ReadWin9xHeader()
|
|
{
|
|
BLOB9X_HEADER header;
|
|
DWORD dwSize = 0;
|
|
if ((ReadFile(m_h9xBlobFile, &header, sizeof(header), &dwSize, NULL) == 0) || (dwSize != sizeof(header)))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to retrieve the Win9x import file header information\n"));
|
|
return false;
|
|
}
|
|
|
|
if (strncmp(header.szSignature, BLOB9X_SIGNATURE, 9) != 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "The import file is not a Win9x import file\n"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::ProcessWin9xBlob(BLOB9X_SPACER* pHeader)
|
|
{
|
|
if (pHeader->dwNamespaceNameSize == 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Namespace name size is zero in Win9x import blob\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
if (pHeader->dwBlobSize == 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Blob size is zero in Win9x import blob\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
// read the namespace name
|
|
wchar_t* wszNamespaceName = new wchar_t[pHeader->dwNamespaceNameSize];
|
|
if (!wszNamespaceName)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
CVectorDeleteMe<wchar_t> delMe1(wszNamespaceName);
|
|
DWORD dwSize = 0;
|
|
if ((ReadFile(m_h9xBlobFile, wszNamespaceName, pHeader->dwNamespaceNameSize, &dwSize, NULL) == 0) || (dwSize != pHeader->dwNamespaceNameSize))
|
|
return WBEM_E_FAILED;
|
|
|
|
// read the parent namespace name if it exists
|
|
wchar_t* wszParentClass = NULL;
|
|
if (pHeader->dwParentClassNameSize)
|
|
{
|
|
wszParentClass = new wchar_t[pHeader->dwParentClassNameSize];
|
|
if (!wszParentClass)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
dwSize = 0;
|
|
if ((ReadFile(m_h9xBlobFile, wszParentClass, pHeader->dwParentClassNameSize, &dwSize, NULL) == 0) || (dwSize != pHeader->dwParentClassNameSize))
|
|
{
|
|
delete [] wszParentClass;
|
|
return WBEM_E_FAILED;
|
|
}
|
|
}
|
|
CVectorDeleteMe<wchar_t> delMe2(wszParentClass);
|
|
|
|
// read in the blob
|
|
char* pObjectBlob = new char[pHeader->dwBlobSize];
|
|
if (!pObjectBlob)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
CVectorDeleteMe<char> delMe3(pObjectBlob);
|
|
dwSize = 0;
|
|
if ((ReadFile(m_h9xBlobFile, pObjectBlob, pHeader->dwBlobSize, &dwSize, NULL) == 0) || (dwSize != pHeader->dwBlobSize))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to read Win9x security blob for namespace %S\n", wszNamespaceName));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
// get handle to the namespace so it can be used below
|
|
CNamespaceHandle* pNamespaceHandle = new CNamespaceHandle(m_pControl, m_pRepository);
|
|
if (!pNamespaceHandle)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pNamespaceHandle->AddRef();
|
|
CReleaseMe relme(pNamespaceHandle);
|
|
|
|
HRESULT hRes = pNamespaceHandle->Initialize(wszNamespaceName);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// process the blob according to its type
|
|
if (pHeader->dwSpacerType == BLOB9X_TYPE_SECURITY_INSTANCE)
|
|
hRes = ProcessWin9xSecurityInstance(pNamespaceHandle, wszParentClass, pObjectBlob, pHeader->dwBlobSize);
|
|
else // (pHeader->dwSpacerType == BLOB9X_TYPE_SECURITY_BLOB)
|
|
hRes = ProcessWin9xSecurityBlob(pNamespaceHandle, wszNamespaceName, pObjectBlob);
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::ProcessWin9xSecurityInstance(CNamespaceHandle* pNamespaceHandle, wchar_t* wszParentClass, char* pObjectBlob, DWORD dwBlobSize)
|
|
{
|
|
// get parent class from the repository
|
|
_IWmiObject* pParentClass = 0;
|
|
HRESULT hRes = pNamespaceHandle->GetObjectByPath(wszParentClass, 0, IID_IWbemClassObject, (LPVOID*)&pParentClass);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to retrieve class %S from the repository; HRESULT = %#lx\n", wszParentClass, hRes));
|
|
return hRes;
|
|
}
|
|
CReleaseMe relMe1(pParentClass);
|
|
|
|
// merge object blob with parent class to produce instance
|
|
_IWmiObject* pInstance = 0;
|
|
hRes = pParentClass->Merge(WMIOBJECT_MERGE_FLAG_INSTANCE, dwBlobSize, pObjectBlob, &pInstance);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Unable to merge instance; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
CReleaseMe relMe2(pInstance);
|
|
|
|
// convert security class instance to ACE
|
|
bool bGroup = false;
|
|
if(wbem_wcsicmp(L"__ntlmgroup", wszParentClass) == 0)
|
|
bGroup = true;
|
|
|
|
CNtAce* pAce = ConvertOldObjectToAce(pInstance, bGroup);
|
|
if(!pAce)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Unable to convert old security instance to ACE"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
CDeleteMe<CNtAce> delMe(pAce);
|
|
|
|
// store the ACE
|
|
hRes = StoreAce(pAce);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Unable to store ACE; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
// this function was stolen from coredll\secure.cpp with minor modifications to remove calls to IsNT()
|
|
CNtAce* CWin9xSecurity::ConvertOldObjectToAce(_IWmiObject* pObj, bool bGroup)
|
|
{
|
|
// Get the properties out of the old object
|
|
|
|
CVARIANT vName;
|
|
pObj->Get(L"Name", 0, &vName, 0, 0);
|
|
LPWSTR pName = NULL;
|
|
if(vName.GetType() != VT_BSTR)
|
|
return NULL; // ignore this one.
|
|
pName = LPWSTR(vName);
|
|
|
|
CVARIANT vDomain;
|
|
LPWSTR pDomain = L".";
|
|
pObj->Get(L"Authority", 0, &vDomain, 0, 0);
|
|
if(vDomain.GetType() == VT_BSTR)
|
|
pDomain = LPWSTR(vDomain);
|
|
|
|
bool bEditSecurity = false;
|
|
bool bEnabled = false;
|
|
bool bExecMethods = false;
|
|
|
|
DWORD dwMask = 0;
|
|
CVARIANT vEnabled;
|
|
CVARIANT vEditSecurity;
|
|
CVARIANT vExecMethods;
|
|
CVARIANT vPermission;
|
|
|
|
pObj->Get(L"Enabled", 0, &vEnabled, 0, 0);
|
|
pObj->Get(L"EditSecurity", 0, &vEditSecurity, 0, 0);
|
|
pObj->Get(L"ExecuteMethods", 0, &vExecMethods, 0, 0);
|
|
pObj->Get(L"Permissions", 0, &vPermission, 0, 0);
|
|
|
|
if (vEnabled.GetType() != VT_NULL && vEnabled.GetBool())
|
|
bEnabled = true;
|
|
|
|
if (vEditSecurity.GetType() != VT_NULL && vEditSecurity.GetBool())
|
|
bEditSecurity = true;
|
|
|
|
if (vExecMethods.GetType() != VT_NULL && vExecMethods.GetBool())
|
|
bExecMethods = true;
|
|
|
|
DWORD dwPermission = 0;
|
|
if (vPermission.GetType() != VT_NULL && vPermission.GetLONG() > dwPermission)
|
|
dwPermission = vPermission.GetLONG();
|
|
|
|
// Now translate the old settings into new ones
|
|
if(bEnabled)
|
|
dwMask = WBEM_ENABLE | WBEM_REMOTE_ACCESS | WBEM_WRITE_PROVIDER;
|
|
|
|
if(bEditSecurity)
|
|
dwMask |= READ_CONTROL;
|
|
|
|
if(bEditSecurity && dwPermission > 0)
|
|
dwMask |= WRITE_DAC;
|
|
|
|
if(bExecMethods)
|
|
dwMask |= WBEM_METHOD_EXECUTE;
|
|
|
|
if(dwPermission >= 1)
|
|
dwMask |= WBEM_PARTIAL_WRITE_REP;
|
|
|
|
if(dwPermission >= 2)
|
|
dwMask |= WBEM_FULL_WRITE_REP | WBEM_PARTIAL_WRITE_REP | WBEM_WRITE_PROVIDER;
|
|
|
|
|
|
// By default, CNtSid will look up the group name from either the local machine,
|
|
// the domain, or a trusted domain. So we need to be explicit
|
|
|
|
WString wc;
|
|
if(pDomain)
|
|
if(_wcsicmp(pDomain, L"."))
|
|
{
|
|
wc = pDomain;
|
|
wc += L"\\";
|
|
}
|
|
wc += pName;
|
|
|
|
// under m1, groups that were not enabled were just ignored. Therefore the bits
|
|
// cannot be transfer over since m3 has allows and denies, but no noops. Also,
|
|
// win9x doesnt have denies, do we want to noop those users also.
|
|
|
|
if(!bEnabled && bGroup)
|
|
dwMask = 0;
|
|
|
|
// In general, m1 just supported allows. However, a user entry that was not enabled was
|
|
// treated as a deny. Note that win9x does not allow actual denies.
|
|
|
|
DWORD dwType = ACCESS_ALLOWED_ACE_TYPE;
|
|
if(!bGroup && !bEnabled)
|
|
{
|
|
dwMask |= (WBEM_ENABLE | WBEM_REMOTE_ACCESS | WBEM_WRITE_PROVIDER);
|
|
dwType = ACCESS_DENIED_ACE_TYPE;
|
|
}
|
|
|
|
CNtSid Sid(wc, NULL);
|
|
if(Sid.GetStatus() != CNtSid::NoError)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Error converting m1 security ace, name = %S, error = 0x%x", wc, Sid.GetStatus()));
|
|
return NULL;
|
|
}
|
|
CNtAce * pace = new CNtAce(dwMask, dwType, CONTAINER_INHERIT_ACE, Sid);
|
|
return pace;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::StoreAce(CNtAce* pAce)
|
|
{
|
|
// get handle to the root namespace
|
|
CNamespaceHandle* pRootNamespaceHandle = new CNamespaceHandle(m_pControl, m_pRepository);
|
|
if (!pRootNamespaceHandle)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pRootNamespaceHandle->AddRef();
|
|
CReleaseMe relme1(pRootNamespaceHandle);
|
|
HRESULT hRes = pRootNamespaceHandle->Initialize(L"root");
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to connect to namespace; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
// get root namespace SD
|
|
CNtSecurityDescriptor sdRoot;
|
|
hRes = GetSDFromNamespace(pRootNamespaceHandle, sdRoot);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
// Delete all entries in the SD with the same name
|
|
wchar_t* wszAccountName;
|
|
hRes = pAce->GetFullUserName2(&wszAccountName);
|
|
if(FAILED(hRes))
|
|
return hRes;
|
|
CVectorDeleteMe<wchar_t> delMe(wszAccountName);
|
|
|
|
if (!StripMatchingEntries(sdRoot, wszAccountName))
|
|
return WBEM_E_FAILED;
|
|
|
|
// add in the new security
|
|
if (!AddAceToSD(sdRoot, pAce))
|
|
return WBEM_E_FAILED;
|
|
|
|
// set the security
|
|
hRes = SetNamespaceSecurity(pRootNamespaceHandle, sdRoot);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
bool CWin9xSecurity::StripMatchingEntries(CNtSecurityDescriptor& sd, const wchar_t* wszAccountName)
|
|
{
|
|
// Get the DACL
|
|
CNtAcl* pAcl;
|
|
pAcl = sd.GetDacl();
|
|
if(!pAcl)
|
|
return false;
|
|
CDeleteMe<CNtAcl> dm(pAcl);
|
|
|
|
// enumerate through the aces
|
|
DWORD dwNumAces = pAcl->GetNumAces();
|
|
BOOL bChanged = FALSE;
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
for(long nIndex = (long)dwNumAces-1; nIndex >= 0; nIndex--)
|
|
{
|
|
CNtAce* pAce = pAcl->GetAce(nIndex);
|
|
if(pAce)
|
|
{
|
|
wchar_t* wszAceListUserName;
|
|
hRes = pAce->GetFullUserName2(&wszAceListUserName);
|
|
if(FAILED(hRes))
|
|
return false;
|
|
CVectorDeleteMe<wchar_t> delMe(wszAceListUserName);
|
|
|
|
if(wbem_wcsicmp(wszAceListUserName, wszAccountName) == 0)
|
|
{
|
|
if (!pAcl->DeleteAce(nIndex))
|
|
return false;
|
|
bChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bChanged)
|
|
{
|
|
if (!sd.SetDacl(pAcl))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWin9xSecurity::AddAceToSD(CNtSecurityDescriptor& sd, CNtAce* pAce)
|
|
{
|
|
CNtAcl* pacl = sd.GetDacl();
|
|
if(!pacl)
|
|
return false;
|
|
CDeleteMe<CNtAcl> delMe(pacl);
|
|
|
|
if (!pacl->AddAce(pAce))
|
|
return false;
|
|
|
|
if (!sd.SetDacl(pacl))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::ProcessWin9xSecurityBlob(CNamespaceHandle* pNamespaceHandle, const wchar_t* wszNamespaceName, const char* pObjectBlob)
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// convert the Win9x security blob into a more proper NT security blob
|
|
char* pNsSecurity = NULL;
|
|
if (!ConvertSecurityBlob(pObjectBlob, &pNsSecurity))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to convert Win9x security blob for namespace %S\n", wszNamespaceName));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
CVectorDeleteMe<char> delMe1(pNsSecurity);
|
|
|
|
// get the parent namespace name, and if a parent exists, get a pointer to it so it can be used below
|
|
CNamespaceHandle* pParentNamespaceHandle = new CNamespaceHandle(m_pControl, m_pRepository);
|
|
if (!pParentNamespaceHandle)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pParentNamespaceHandle->AddRef();
|
|
CReleaseMe relme(pParentNamespaceHandle);
|
|
|
|
wchar_t* wszParentNamespaceName = new wchar_t[wcslen(wszNamespaceName)+1];
|
|
if (!wszParentNamespaceName)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
CVectorDeleteMe<wchar_t> delMe2(wszParentNamespaceName);
|
|
|
|
wcscpy(wszParentNamespaceName, wszNamespaceName);
|
|
wchar_t* pSlash = wcsrchr(wszParentNamespaceName, '\\');
|
|
bool bRoot = true;
|
|
if (pSlash)
|
|
{
|
|
bRoot = false;
|
|
*pSlash = L'\0';
|
|
hRes = pParentNamespaceHandle->Initialize(wszParentNamespaceName);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
}
|
|
|
|
// now transform the old security blob that consisted of a header and array of ACE's
|
|
// into a proper Security Descriptor that can be stored in the property
|
|
CNtSecurityDescriptor mmfNsSD;
|
|
hRes = TransformBlobToSD(bRoot, pParentNamespaceHandle, pNsSecurity, 0, mmfNsSD);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to convert security blob to SD for namespace %S\n", wszNamespaceName));
|
|
return hRes;
|
|
}
|
|
|
|
// now set the security
|
|
hRes = SetNamespaceSecurity(pNamespaceHandle, mmfNsSD);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to set namespace security for namespace %S\n", wszNamespaceName));
|
|
return hRes;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
bool CWin9xSecurity::ConvertSecurityBlob(const char* pOrgNsSecurity, char** ppNewNsSecurity)
|
|
{
|
|
// convert an old Win9x pseudo-blob into a blob with NT-style ACE's
|
|
|
|
if (!pOrgNsSecurity || !ppNewNsSecurity)
|
|
return false;
|
|
|
|
DWORD* pdwData = (DWORD*)pOrgNsSecurity;
|
|
DWORD dwSize = *pdwData;
|
|
|
|
pdwData++;
|
|
DWORD dwVersion = *pdwData;
|
|
|
|
if(dwVersion != 1 || dwSize == 0 || dwSize > 64000)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Invalid security blob header\n"));
|
|
return false;
|
|
}
|
|
|
|
pdwData++;
|
|
DWORD dwStoredAsNT = *pdwData;
|
|
if (dwStoredAsNT)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "NT security blob detected; should be Win9x\n"));
|
|
return false;
|
|
}
|
|
|
|
CFlexAceArray AceList;
|
|
if (!AceList.DeserializeWin9xSecurityBlob(pOrgNsSecurity))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to deserialize a Win9x security blob\n"));
|
|
return false;
|
|
}
|
|
|
|
// serialize the new WinNT blob
|
|
if (!AceList.SerializeWinNTSecurityBlob(ppNewNsSecurity))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to serialize a WinNT security blob\n"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::TransformBlobToSD(bool bRoot, CNamespaceHandle* pParentNamespaceHandle, const char* pNsSecurity, DWORD dwStoredAsNT, CNtSecurityDescriptor& mmfNsSD)
|
|
{
|
|
// now transform the old security blob that consisted of a header and array of ACE's
|
|
// into a proper Security Descriptor that can be stored in the property
|
|
|
|
// build up an ACL from our blob, if we have one
|
|
CNtAcl acl;
|
|
|
|
if (pNsSecurity)
|
|
{
|
|
DWORD* pdwData = (DWORD*) pNsSecurity;
|
|
pdwData += 3;
|
|
int iAceCount = (int)*pdwData;
|
|
pdwData += 2;
|
|
BYTE* pAceData = (BYTE*)pdwData;
|
|
|
|
PGENERIC_ACE pAce = NULL;
|
|
for (int iCnt = 0; iCnt < iAceCount; iCnt++)
|
|
{
|
|
pAce = (PGENERIC_ACE)pAceData;
|
|
if (!pAce)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to access GENERIC_ACE within security blob\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
CNtAce ace(pAce);
|
|
if(ace.GetStatus() != 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to construct CNtAce from GENERIC_ACE\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
acl.AddAce(&ace);
|
|
if (acl.GetStatus() != 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to add ACE to ACL\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
pAceData += ace.GetSize();
|
|
}
|
|
}
|
|
|
|
// for Win9x, the security blob for ROOT would not have had any default
|
|
// root aces for administrators and everyone, so create them
|
|
if (bRoot)
|
|
{
|
|
if (!AddDefaultRootAces(&acl))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to create default root ACE's\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
// a real SD was constructed and passed in by reference, now set it up properly
|
|
SetOwnerAndGroup(mmfNsSD);
|
|
mmfNsSD.SetDacl(&acl);
|
|
if (mmfNsSD.GetStatus() != 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to convert namespace security blob to SD\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
// add in the parent's inheritable aces, if this is not ROOT
|
|
if (!bRoot)
|
|
{
|
|
HRESULT hRes = GetParentsInheritableAces(pParentNamespaceHandle, mmfNsSD);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to inherit parent's inheritable ACE's; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::SetNamespaceSecurity(CNamespaceHandle* pNamespaceHandle, CNtSecurityDescriptor& mmfNsSD)
|
|
{
|
|
if (!pNamespaceHandle)
|
|
return WBEM_E_FAILED;
|
|
|
|
// get the singleton object
|
|
IWbemClassObject* pThisNamespace = NULL;
|
|
wchar_t* wszThisNamespace = new wchar_t[wcslen(L"__thisnamespace=@")+1];
|
|
wcscpy(wszThisNamespace, L"__thisnamespace=@");
|
|
HRESULT hRes = pNamespaceHandle->GetObjectByPath(wszThisNamespace, 0, IID_IWbemClassObject, (LPVOID*)&pThisNamespace);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to get singleton namespace object; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
CReleaseMe relMe(pThisNamespace);
|
|
|
|
// copy SD data into a safearray
|
|
SAFEARRAY FAR* psa;
|
|
SAFEARRAYBOUND rgsabound[1];
|
|
rgsabound[0].lLbound = 0;
|
|
rgsabound[0].cElements = mmfNsSD.GetSize();
|
|
psa = SafeArrayCreate( VT_UI1, 1 , rgsabound );
|
|
if (!psa)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
char* pData = NULL;
|
|
hRes = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pData);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed SafeArrayAccessData; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
memcpy(pData, mmfNsSD.GetPtr(), mmfNsSD.GetSize());
|
|
hRes = SafeArrayUnaccessData(psa);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed SafeArrayUnaccessData; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
pData = NULL;
|
|
|
|
// put the safearray into a variant and set the property on the instance
|
|
VARIANT var;
|
|
var.vt = VT_UI1|VT_ARRAY;
|
|
var.parray = psa;
|
|
hRes = pThisNamespace->Put(L"SECURITY_DESCRIPTOR" , 0, &var, 0);
|
|
VariantClear(&var);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to put SECURITY_DESCRIPTOR property; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
// put back the instance
|
|
CEventCollector eventCollector;
|
|
hRes = pNamespaceHandle->PutObject(IID_IWbemClassObject, pThisNamespace, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL, eventCollector);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to put back singleton instance; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
bool CWin9xSecurity::AddDefaultRootAces(CNtAcl * pacl )
|
|
{
|
|
if (!pacl)
|
|
return false;
|
|
|
|
PSID pRawSid;
|
|
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
|
|
|
|
//
|
|
// Add ACE's for NETWORK_SERVICE ACCOUNT. These accounts have the following rights:
|
|
// 1. WBEM_ENABLE
|
|
// 2. WBEM_METHOD_EXECUTE
|
|
// 3. WBEM_WRITE_PROVIDER
|
|
//
|
|
DWORD dwAccessMaskNetworkLocalService = WBEM_ENABLE | WBEM_METHOD_EXECUTE | WBEM_WRITE_PROVIDER ;
|
|
|
|
if(AllocateAndInitializeSid( &id, 1,
|
|
SECURITY_NETWORK_SERVICE_RID,0,0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
CNtSid SidUsers(pRawSid);
|
|
FreeSid(pRawSid);
|
|
CNtAce * pace = new CNtAce(dwAccessMaskNetworkLocalService, ACCESS_ALLOWED_ACE_TYPE,
|
|
CONTAINER_INHERIT_ACE, SidUsers);
|
|
if ( NULL == pace )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CDeleteMe<CNtAce> dm(pace);
|
|
pacl->AddAce(pace);
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "ERROR: Unable to add default root aces (SECURITY_NETWORK_SERVICE_RID)\n"));
|
|
}
|
|
|
|
|
|
//
|
|
// Add ACE's for NETWORK_SERVICE ACCOUNT. These accounts have the following rights:
|
|
// 1. WBEM_ENABLE
|
|
// 2. WBEM_METHOD_EXECUTE
|
|
// 3. WBEM_WRITE_PROVIDER
|
|
//
|
|
if(AllocateAndInitializeSid( &id, 1,
|
|
SECURITY_LOCAL_SERVICE_RID,0,0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
CNtSid SidUsers(pRawSid);
|
|
FreeSid(pRawSid);
|
|
CNtAce * pace = new CNtAce(dwAccessMaskNetworkLocalService, ACCESS_ALLOWED_ACE_TYPE,
|
|
CONTAINER_INHERIT_ACE, SidUsers);
|
|
if ( NULL == pace )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CDeleteMe<CNtAce> dm(pace);
|
|
pacl->AddAce(pace);
|
|
}
|
|
else
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "ERROR: Unable to add default root aces (SECURITY_LOCAL_SERVICE_RID)\n"));
|
|
}
|
|
|
|
|
|
|
|
// add Administrator
|
|
if(AllocateAndInitializeSid( &id, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
CNtSid SidAdmin(pRawSid);
|
|
FreeSid(pRawSid);
|
|
DWORD dwMask = FULL_RIGHTS;
|
|
CNtAce * pace = new CNtAce(dwMask, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, SidAdmin);
|
|
if ( NULL == pace )
|
|
return false;
|
|
|
|
CDeleteMe<CNtAce> dm(pace);
|
|
pacl->AddAce(pace);
|
|
if (pacl->GetStatus() != 0)
|
|
return false;
|
|
}
|
|
|
|
// add Everyone
|
|
SID_IDENTIFIER_AUTHORITY id2 = SECURITY_WORLD_SID_AUTHORITY;
|
|
if(AllocateAndInitializeSid( &id2, 1,
|
|
0,0,0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
CNtSid SidUsers(pRawSid);
|
|
FreeSid(pRawSid);
|
|
DWORD dwMask = WBEM_ENABLE | WBEM_METHOD_EXECUTE | WBEM_WRITE_PROVIDER;
|
|
CNtAce * pace = new CNtAce(dwMask, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, SidUsers);
|
|
if ( NULL == pace )
|
|
return false;
|
|
|
|
CDeleteMe<CNtAce> dm(pace);
|
|
pacl->AddAce(pace);
|
|
if (pacl->GetStatus() != 0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::GetParentsInheritableAces(CNamespaceHandle* pParentNamespaceHandle, CNtSecurityDescriptor &sd)
|
|
{
|
|
if (!pParentNamespaceHandle)
|
|
return WBEM_E_FAILED;
|
|
|
|
// Get the parent namespace's SD
|
|
CNtSecurityDescriptor sdParent;
|
|
HRESULT hRes = GetSDFromNamespace(pParentNamespaceHandle, sdParent);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
// strip out the inherited aces so we have a consistent SD
|
|
if (!StripOutInheritedAces(sd))
|
|
return WBEM_E_FAILED;
|
|
|
|
// Go through the parents dacl and add any inheritable aces to ours.
|
|
if (!CopyInheritAces(sd, sdParent))
|
|
return WBEM_E_FAILED;
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT CWin9xSecurity::GetSDFromNamespace(CNamespaceHandle* pNamespaceHandle, CNtSecurityDescriptor& sd)
|
|
{
|
|
if (!pNamespaceHandle)
|
|
return WBEM_E_FAILED;
|
|
|
|
// get the singleton object
|
|
IWbemClassObject* pThisNamespace = NULL;
|
|
wchar_t* wszThisNamespace = new wchar_t[wcslen(L"__thisnamespace=@")+1];
|
|
wcscpy(wszThisNamespace, L"__thisnamespace=@");
|
|
HRESULT hRes = pNamespaceHandle->GetObjectByPath(wszThisNamespace, 0, IID_IWbemClassObject, (LPVOID*)&pThisNamespace);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to get singleton namespace object; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
CReleaseMe relMe(pThisNamespace);
|
|
|
|
// Get the security descriptor argument
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
hRes = pThisNamespace->Get(L"SECURITY_DESCRIPTOR", 0, &var, NULL, NULL);
|
|
if (FAILED(hRes))
|
|
{
|
|
VariantClear(&var);
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to get SECURITY_DESCRIPTOR property; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
if(var.vt != (VT_ARRAY | VT_UI1))
|
|
{
|
|
VariantClear(&var);
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to get SECURITY_DESCRIPTOR property due to incorrect variant type\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
SAFEARRAY* psa = var.parray;
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
hRes = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pSD);
|
|
if (FAILED(hRes))
|
|
{
|
|
VariantClear(&var);
|
|
ERRORTRACE((LOG_WBEMCORE, "GetSDFromNamespace failed SafeArrayAccessData; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
BOOL bValid = IsValidSecurityDescriptor(pSD);
|
|
if (!bValid)
|
|
{
|
|
VariantClear(&var);
|
|
ERRORTRACE((LOG_WBEMCORE, "GetSDFromNamespace retrieved an invalid security descriptor\n"));
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
CNtSecurityDescriptor sdNew(pSD);
|
|
|
|
// Check to make sure the owner and group is not NULL!!!!
|
|
CNtSid *pTmpSid = sdNew.GetOwner();
|
|
if (pTmpSid == NULL)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Security descriptor was retrieved and it had no owner\n"));
|
|
}
|
|
delete pTmpSid;
|
|
|
|
pTmpSid = sdNew.GetGroup();
|
|
if (pTmpSid == NULL)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Security descriptor was retrieved and it had no group\n"));
|
|
}
|
|
delete pTmpSid;
|
|
|
|
sd = sdNew;
|
|
SafeArrayUnaccessData(psa);
|
|
VariantClear(&var);
|
|
return hRes;
|
|
}
|
|
|
|
bool CWin9xSecurity::StripOutInheritedAces(CNtSecurityDescriptor& sd)
|
|
{
|
|
// Get the DACL
|
|
CNtAcl* pAcl;
|
|
pAcl = sd.GetDacl();
|
|
if(!pAcl)
|
|
return false;
|
|
CDeleteMe<CNtAcl> dm(pAcl);
|
|
|
|
// enumerate through the aces
|
|
DWORD dwNumAces = pAcl->GetNumAces();
|
|
BOOL bChanged = FALSE;
|
|
for(long nIndex = (long)dwNumAces-1; nIndex >= 0; nIndex--)
|
|
{
|
|
CNtAce *pAce = pAcl->GetAce(nIndex);
|
|
CDeleteMe<CNtAce> dm2(pAce);
|
|
if(pAce)
|
|
{
|
|
long lFlags = pAce->GetFlags();
|
|
if(lFlags & INHERITED_ACE)
|
|
{
|
|
pAcl->DeleteAce(nIndex);
|
|
bChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if(bChanged)
|
|
sd.SetDacl(pAcl);
|
|
return true;
|
|
}
|
|
|
|
bool CWin9xSecurity::CopyInheritAces(CNtSecurityDescriptor& sd, CNtSecurityDescriptor& sdParent)
|
|
{
|
|
// Get the acl list for both SDs
|
|
|
|
CNtAcl * pacl = sd.GetDacl();
|
|
if(pacl == NULL)
|
|
return false;
|
|
CDeleteMe<CNtAcl> dm0(pacl);
|
|
|
|
CNtAcl * paclParent = sdParent.GetDacl();
|
|
if(paclParent == NULL)
|
|
return false;
|
|
CDeleteMe<CNtAcl> dm1(paclParent);
|
|
|
|
//
|
|
// If parent SD is protected from ACE inheritance only add Local/Network service.
|
|
// This can happen during following conditions:
|
|
// If an upgrade is done from Win9x and we've stored away the namespace security
|
|
// into a temporary file another WMI client can create a namespace and set NS security
|
|
// with SE_DACL_PROTECTED AFTER we've stored the file (can you say RSOP??). Now, at the
|
|
// point of reboot, we scan the file and populate security for each namespace. Since we
|
|
// dont have any namespace security stored for this 'new' namespace, we let it simply inherit
|
|
// from parent which is bad since they explicitly set the SE_DACL_PROTECTED control bit. To
|
|
// remedy this, we check to see if the SD is protected and if so, do not inherit anything.
|
|
//
|
|
if ( IsProtected ( sd ) == true )
|
|
{
|
|
return true ;
|
|
}
|
|
|
|
int iNumParent = paclParent->GetNumAces();
|
|
for(int iCnt = 0; iCnt < iNumParent; iCnt++)
|
|
{
|
|
CNtAce *pParentAce = paclParent->GetAce(iCnt);
|
|
CDeleteMe<CNtAce> dm2(pParentAce);
|
|
|
|
long lFlags = pParentAce->GetFlags();
|
|
if(lFlags & CONTAINER_INHERIT_ACE)
|
|
{
|
|
|
|
if(lFlags & NO_PROPAGATE_INHERIT_ACE)
|
|
lFlags ^= CONTAINER_INHERIT_ACE;
|
|
lFlags |= INHERITED_ACE;
|
|
|
|
// If this is an inherit only ace we need to clear this
|
|
// in the children.
|
|
// NT RAID: 161761 [marioh]
|
|
if ( lFlags & INHERIT_ONLY_ACE )
|
|
lFlags ^= INHERIT_ONLY_ACE;
|
|
|
|
pParentAce->SetFlags(lFlags);
|
|
pacl->AddAce(pParentAce);
|
|
}
|
|
}
|
|
sd.SetDacl(pacl);
|
|
return true;
|
|
}
|
|
|
|
BOOL CWin9xSecurity::SetOwnerAndGroup(CNtSecurityDescriptor &sd)
|
|
{
|
|
PSID pRawSid;
|
|
BOOL bRet = FALSE;
|
|
|
|
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
|
|
if(AllocateAndInitializeSid( &id, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,&pRawSid))
|
|
{
|
|
CNtSid SidAdmins(pRawSid);
|
|
bRet = sd.SetGroup(&SidAdmins); // Access check doesn't really care what you put,
|
|
// so long as you put something for the owner
|
|
if(bRet)
|
|
bRet = sd.SetOwner(&SidAdmins);
|
|
FreeSid(pRawSid);
|
|
return bRet;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// CNamespaceListSink is used by the query in RecursiveInheritSecurity below
|
|
//
|
|
class CNamespaceListSink : public CUnkBase<IWbemObjectSink, &IID_IWbemObjectSink>
|
|
{
|
|
CWStringArray &m_aNamespaceList;
|
|
public:
|
|
CNamespaceListSink(CWStringArray &aNamespaceList)
|
|
: m_aNamespaceList(aNamespaceList)
|
|
{
|
|
}
|
|
~CNamespaceListSink()
|
|
{
|
|
}
|
|
STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects)
|
|
{
|
|
HRESULT hRes;
|
|
for (int i = 0; i != lNumObjects; i++)
|
|
{
|
|
if (apObjects[i] != NULL)
|
|
{
|
|
_IWmiObject *pInst = NULL;
|
|
hRes = apObjects[i]->QueryInterface(IID__IWmiObject, (void**)&pInst);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
CReleaseMe rm(pInst);
|
|
|
|
BSTR strKey = NULL;
|
|
hRes = pInst->GetKeyString(0, &strKey);
|
|
if(FAILED(hRes))
|
|
return hRes;
|
|
CSysFreeMe sfm(strKey);
|
|
if (m_aNamespaceList.Add(strKey) != CWStringArray::no_error)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
STDMETHOD(SetStatus)(long lFlags, HRESULT hresResult, BSTR, IWbemClassObject*)
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
};
|
|
|
|
HRESULT CWin9xSecurity::RecursiveInheritSecurity(CNamespaceHandle* pParentNamespaceHandle, const wchar_t *wszNamespace)
|
|
{
|
|
// force namespaces to inherit their inheritable security settings
|
|
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// get handle to the namespace
|
|
CNamespaceHandle* pNamespaceHandle = new CNamespaceHandle(m_pControl, m_pRepository);
|
|
if (!pNamespaceHandle)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pNamespaceHandle->AddRef();
|
|
CReleaseMe relme1(pNamespaceHandle);
|
|
hRes = pNamespaceHandle->Initialize(wszNamespace);
|
|
if (FAILED(hRes))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Failed to connect to namespace; HRESULT = %#lx\n", hRes));
|
|
return hRes;
|
|
}
|
|
|
|
// inherit parent's inheritable security if there is a parent
|
|
if (pParentNamespaceHandle)
|
|
{
|
|
CNtSecurityDescriptor sdNamespace;
|
|
hRes = GetSDFromNamespace(pNamespaceHandle, sdNamespace);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
hRes = GetParentsInheritableAces(pParentNamespaceHandle, sdNamespace);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
hRes = SetNamespaceSecurity(pNamespaceHandle, sdNamespace);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
}
|
|
|
|
//Enumerate child namespaces
|
|
CWStringArray aListNamespaces;
|
|
CNamespaceListSink* pSink = new CNamespaceListSink(aListNamespaces);
|
|
if (!pSink)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pSink->AddRef();
|
|
CReleaseMe relme2(pSink);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
IWbemQuery *pQuery = NULL;
|
|
hRes = CoCreateInstance(CLSID_WbemQuery, NULL, CLSCTX_INPROC_SERVER, IID_IWbemQuery, (void **)&pQuery);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
CReleaseMe relme3(pQuery);
|
|
|
|
hRes = pQuery->Parse(L"SQL", L"select * from __namespace", 0);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
hRes = pNamespaceHandle->ExecQuerySink(pQuery, 0, 0, pSink, NULL);
|
|
}
|
|
|
|
//Work through list and call ourselves with that namespace name
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
for (int i = 0; i != aListNamespaces.Size(); i++)
|
|
{
|
|
//Build the full name of this namespace
|
|
wchar_t *wszChildNamespace = new wchar_t[wcslen(wszNamespace) + wcslen(aListNamespaces[i]) + wcslen(L"\\") + 1];
|
|
if (wszChildNamespace == NULL)
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
CVectorDeleteMe<wchar_t> delMe(wszChildNamespace);
|
|
|
|
wcscpy(wszChildNamespace, wszNamespace);
|
|
wcscat(wszChildNamespace, L"\\");
|
|
wcscat(wszChildNamespace, aListNamespaces[i]);
|
|
|
|
// Do the inherit
|
|
hRes = RecursiveInheritSecurity(pNamespaceHandle, wszChildNamespace);
|
|
if (FAILED(hRes))
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
BOOL CWin9xSecurity::DeleteWin9xBlobFile()
|
|
{
|
|
// delete the file
|
|
wchar_t wszFilePath[MAX_PATH+1];
|
|
if (!GetRepositoryDirectory(wszFilePath))
|
|
return FALSE;
|
|
|
|
wcscat(wszFilePath, BLOB9X_FILENAME);
|
|
return DeleteFileW(wszFilePath);
|
|
}
|
|
|
|
bool CWin9xSecurity::GetRepositoryDirectory(wchar_t wszRepositoryDirectory[MAX_PATH+1])
|
|
{
|
|
HKEY hKey;
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\WBEM\\CIMOM", 0, KEY_READ, &hKey))
|
|
return false;
|
|
|
|
wchar_t wszTmp[MAX_PATH + 1];
|
|
DWORD dwLen = MAX_PATH + 1;
|
|
long lRes = RegQueryValueExW(hKey, L"Repository Directory", NULL, NULL, (LPBYTE)wszTmp, &dwLen);
|
|
RegCloseKey(hKey);
|
|
if(lRes)
|
|
return false;
|
|
|
|
if (ExpandEnvironmentStringsW(wszTmp,wszRepositoryDirectory, MAX_PATH + 1) == 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CFlexAceArray::~CFlexAceArray()
|
|
//
|
|
// Cleans up safe array entries.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CFlexAceArray::~CFlexAceArray()
|
|
{
|
|
for(int iCnt = 0; iCnt < Size(); iCnt++)
|
|
{
|
|
CBaseAce* pAce = (CBaseAce*)GetAt(iCnt);
|
|
if(pAce)
|
|
delete pAce;
|
|
}
|
|
Empty();
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CFlexAceArray::DeserializeWin9xSecurityBlob()
|
|
//
|
|
// Description. Deserializes the Win9x pseudo-aces out of a blob.
|
|
// The blob starts off with 5 dwords preceding the aces themselves:
|
|
// <TOTAL SIZE><VERSION><ISNT><ACE_COUNT><RESERVED><ACE> ... <ACE>
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CFlexAceArray::DeserializeWin9xSecurityBlob(const char* pData)
|
|
{
|
|
if (!pData)
|
|
return false;
|
|
|
|
DWORD* pdwData = (DWORD*)pData;
|
|
pdwData += 3;
|
|
int iAceCount = (int)*pdwData;
|
|
pdwData += 2;
|
|
|
|
// Set the ace data
|
|
BYTE* pAceData = (BYTE*)pdwData;
|
|
DWORD dwAceSize = 0;
|
|
CBaseAce* pAce = NULL;
|
|
for (int iCnt = 0; iCnt < iAceCount; iCnt++)
|
|
{
|
|
// if the user is preceeded by a ".\" advance the pointer past it
|
|
if (_wcsnicmp((WCHAR*)pAceData, L".\\", 2) == 0)
|
|
pAceData += 4;
|
|
|
|
dwAceSize = 2*(wcslen((WCHAR*)pAceData) + 1) + 12;
|
|
pAce = new CNtAce();
|
|
if (!pAce)
|
|
return false;
|
|
|
|
// Deserialize Win9x pseudo ace into NT ace
|
|
pAce->Deserialize(pAceData);
|
|
|
|
// only add ACE's that we were successful in creating
|
|
if (pAce->GetStatus() == 0)
|
|
Add(pAce);
|
|
|
|
pAceData += dwAceSize;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CFlexAceArray::SerializeWinNTSecurityBlob()
|
|
//
|
|
// Description. Serializes the WinNT aces into a blob.
|
|
// The blob starts off with 5 dwords preceding the aces themselves:
|
|
// <TOTAL SIZE><VERSION><ISNT><ACE_COUNT><RESERVED><ACE> ... <ACE>
|
|
//
|
|
// "version" should be 1.
|
|
// "ISNT" should be 1
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CFlexAceArray::SerializeWinNTSecurityBlob(char** ppData)
|
|
{
|
|
// Start by determining the total size needed
|
|
DWORD dwSize = 5 * sizeof(DWORD); // for the header stuff
|
|
int iAceCount = Size(); // get count of aces stored in array
|
|
CBaseAce* pAce = NULL;
|
|
for (int iCnt = 0; iCnt < iAceCount; iCnt++) // add each of the ace sizes
|
|
{
|
|
pAce = (CBaseAce*)GetAt(iCnt);
|
|
if (!pAce)
|
|
return false;
|
|
|
|
dwSize += pAce->GetSerializedSize();
|
|
}
|
|
|
|
// Allocate the blob, set the pointer from the caller;
|
|
BYTE* pData = new BYTE[dwSize];
|
|
if (!pData)
|
|
return false;
|
|
|
|
*ppData = (char*)pData;
|
|
|
|
// Set the header info
|
|
DWORD* pdwData = (DWORD *)pData;
|
|
*pdwData = dwSize;
|
|
pdwData++;
|
|
*pdwData = 1; // version
|
|
pdwData++;
|
|
*pdwData = 1; // ISNT
|
|
pdwData++;
|
|
*pdwData = iAceCount;
|
|
pdwData++;
|
|
*pdwData = 0; // reserved
|
|
pdwData++;
|
|
|
|
// Set the ace data
|
|
BYTE* pAceData = (BYTE*)pdwData;
|
|
for(iCnt = 0; iCnt < iAceCount; iCnt++)
|
|
{
|
|
pAce = (CBaseAce*)GetAt(iCnt);
|
|
pAce->Serialize(pAceData);
|
|
pAceData += pAce->GetSerializedSize();;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
--------------------------------------------------------------------------
|
|
|
|
|
| Checks to see if the Acl contains an ACE with the specified SID.
|
|
| The characteristics of the ACE is irrelevant. Only SID comparison applies.
|
|
|
|
|
--------------------------------------------------------------------------
|
|
*/
|
|
bool CWin9xSecurity::IsProtected(CNtSecurityDescriptor & sd)
|
|
{
|
|
PSECURITY_DESCRIPTOR pActual = sd.GetPtr();
|
|
if(pActual == NULL)
|
|
return false;
|
|
|
|
SECURITY_DESCRIPTOR_CONTROL Control;
|
|
DWORD dwRevision;
|
|
BOOL bRet = GetSecurityDescriptorControl(pActual, &Control, &dwRevision);
|
|
if(bRet == false)
|
|
return false;
|
|
|
|
if(Control & SE_DACL_PROTECTED)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
}
|