WindowsXP-SP1/admin/display/proppage/admin/managdby.cxx
2020-09-30 16:53:49 +02:00

1660 lines
46 KiB
C++

//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: managdby.cxx
//
// Contents: Managed-By property page implementation
//
// History: 21-Oct-97 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "proppage.h"
#include "user.h"
#include "managdby.h"
#include <ntsam.h>
#include <aclapi.h>
WCHAR g_wszUserClass[] = L"user";
WCHAR g_wszContactClass[] = L"contact";
extern const GUID GUID_MemberAttribute =
{ 0xbf9679c0, 0x0de6, 0x11d0, { 0xa2, 0x85, 0x00,0xaa, 0x00, 0x30, 0x49, 0xe2}};
CManagedByPage::CManagedByPage(CDsPropPageBase * pPage) :
m_pDsObj(NULL),
m_pPrevDsObj(NULL),
m_pPage(pPage),
m_pwzObjName(NULL),
m_pwzPrevObjName(NULL),
m_fIsUser(FALSE),
m_fWritable(FALSE),
m_fWritableMembership(FALSE),
m_fUpdateListCheckEnable(FALSE),
m_nNameCtlID(0),
m_pOfficeAttrMap(NULL),
m_pStreetAttrMap(NULL),
m_pCityAttrMap(NULL),
m_pStateAttrMap(NULL),
m_pCountryAttrMap(NULL),
m_pPhoneAttrMap(NULL),
m_pFaxAttrMap(NULL)
{
}
CManagedByPage::~CManagedByPage()
{
if (m_pDsObj != m_pPrevDsObj)
{
DO_RELEASE(m_pPrevDsObj);
}
DO_RELEASE(m_pDsObj);
if (m_pwzPrevObjName &&
m_pwzObjName &&
0 != _wcsicmp(m_pwzPrevObjName, m_pwzObjName))
{
delete[] m_pwzPrevObjName;
}
if (m_pwzObjName)
{
delete[] m_pwzObjName;
}
}
//+----------------------------------------------------------------------------
//
// Method: CManagedByPage::SetObj
//
// Synopsis: Initialize the CManagedBy class and set the edit control value.
//
//-----------------------------------------------------------------------------
HRESULT CManagedByPage::SetObj(PWSTR pwzObjDN)
{
HRESULT hr;
PWSTR pwzCanonical = NULL;
Clear();
// Save the Managed-By object DN.
//
if (!AllocWStr(pwzObjDN, &m_pwzObjName))
{
REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
return E_OUTOFMEMORY;
}
//
// Save the name as a previous value if the previous value isn't already set
//
if (!m_pwzPrevObjName)
{
m_pwzPrevObjName = m_pwzObjName;
}
// Put the "friendly" name into the edit control.
//
hr = CrackName(m_pwzObjName, &pwzCanonical, GET_OBJ_CAN_NAME,
m_pPage->GetHWnd());
if (FAILED(hr))
{
return hr;
}
PTSTR ptsz;
if (!UnicodeToTchar(pwzCanonical, &ptsz))
{
REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
LocalFreeStringW(&pwzCanonical);
return E_OUTOFMEMORY;
}
LocalFreeStringW(&pwzCanonical);
SetDlgItemText(m_pPage->GetHWnd(), m_nNameCtlID, ptsz);
delete ptsz;
// Bind to the Managed-By object.
//
CStrW strADsPath;
IDirectoryObject * pObj;
hr = AddLDAPPrefix(m_pPage, m_pwzObjName, strADsPath);
CHECK_HRESULT_REPORT(hr, m_pPage->GetHWnd(), return hr);
hr = ADsOpenObject(const_cast<PWSTR>((LPCWSTR)strADsPath), NULL, NULL,
ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject,
(PVOID *)&pObj);
if (FAILED(hr))
{
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
{
ErrMsg(IDS_ERRMSG_NO_LONGER_EXISTS, m_pPage->GetHWnd());
return S_OK;
}
else
{
REPORT_ERROR(hr, m_pPage->GetHWnd());
return hr;
}
}
m_pDsObj = pObj;
if (m_pPrevDsObj == NULL)
{
m_pPrevDsObj = m_pDsObj;
m_pPrevDsObj->AddRef();
}
// Determine if the Managed-By object is of class user or contact.
//
BSTR bstr;
IADs * pADs;
hr = m_pDsObj->QueryInterface(IID_IADs, (PVOID *)&pADs);
CHECK_HRESULT_REPORT(hr, m_pPage->GetHWnd(), return hr;);
hr = pADs->get_Class(&bstr);
pADs->Release();
CHECK_HRESULT_REPORT(hr, m_pPage->GetHWnd(), return hr;);
m_fIsUser = (_wcsicmp(bstr, g_wszUserClass) == 0 ||
_wcsicmp(bstr, g_wszContactClass) == 0
#ifdef INETORGPERSON
|| _wcsicmp(bstr, g_szInetOrgPerson) == 0
#endif
);
SysFreeString(bstr);
return hr;
}
//+----------------------------------------------------------------------------
//
// Method: CManagedByPage::SetEditCtrl
//
// Synopsis: If a user or contact object, fetch the corresponding value and
// put it in the control. Otherwise, clear the control.
//
//-----------------------------------------------------------------------------
HRESULT
CManagedByPage::SetEditCtrl(PATTR_MAP pAttrMap)
{
HRESULT hr = S_OK;
if (!IsUser())
{
// No user values, so clear the control.
//
SetDlgItemText(m_pPage->GetHWnd(), pAttrMap->nCtrlID, TEXT(""));
return S_OK;
}
PADS_ATTR_INFO pAttr = NULL;
DWORD cAttrs = 0;
hr = m_pDsObj->GetObjectAttributes(&pAttrMap->AttrInfo.pszAttrName, 1,
&pAttr, &cAttrs);
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, m_pPage->GetHWnd()))
{
return hr;
}
if (!cAttrs)
{
// Attribute not present.
//
SetDlgItemText(m_pPage->GetHWnd(), pAttrMap->nCtrlID, TEXT(""));
return S_OK;
}
PTSTR ptsz;
if (!UnicodeToTchar(pAttr->pADsValues->CaseIgnoreString, &ptsz))
{
REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
FreeADsMem(pAttr);
return E_OUTOFMEMORY;
}
SetDlgItemText(m_pPage->GetHWnd(), pAttrMap->nCtrlID, ptsz);
delete ptsz;
FreeADsMem(pAttr);
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Method: CManagedByPage::Clear
//
// Synopsis: Return to the base state.
//
//-----------------------------------------------------------------------------
void CManagedByPage::Clear(void)
{
DO_RELEASE(m_pDsObj);
if (!m_pwzPrevObjName)
{
m_pwzPrevObjName = m_pwzObjName;
}
else
{
if (m_pwzPrevObjName && m_pwzObjName && 0 != _wcsicmp(m_pwzPrevObjName, m_pwzObjName))
{
DO_DEL(m_pwzObjName);
}
m_pwzObjName = NULL;
}
m_fIsUser = FALSE;
SetDlgItemText(m_pPage->GetHWnd(), m_nNameCtlID, TEXT(""));
}
//+----------------------------------------------------------------------------
//
// Method: CManagedByPage::RefreshCtrls
//
// Synopsis: Update the dependent controls.
//
//-----------------------------------------------------------------------------
HRESULT CManagedByPage::RefreshCtrls(void)
{
EnableWindow(GetDlgItem(m_pPage->GetHWnd(), m_nViewBtnID), IsValid());
EnableWindow(GetDlgItem(m_pPage->GetHWnd(), m_nClearBtnID), IsValid() && IsWritable());
HRESULT hr;
hr = UpdateListCheck(m_pPage, NULL, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = OfficeEdit(m_pPage, m_pOfficeAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = StreetEdit(m_pPage, m_pStreetAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = CityEdit(m_pPage, m_pCityAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = StateEdit(m_pPage, m_pStateAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = CountryEdit(m_pPage, m_pCountryAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = PhoneEdit(m_pPage, m_pPhoneAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
hr = FaxEdit(m_pPage, m_pFaxAttrMap, NULL, 0, NULL, fObjChanged);
CHECK_HRESULT(hr, return hr);
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Attr Function: ManagedByEdit
//
// Synopsis: If the Managed-By attribute is non-empty, binds to the named
// object and stores the ADSI pointer in the page object.
//
// WARNING: This MUST be the first ATTR_FCN called because it creates the
// CManagedByPage object.
//-----------------------------------------------------------------------------
HRESULT
ManagedByEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO pAttrInfo, LPARAM lParam, PATTR_DATA pAttrData,
DLG_OP DlgOp)
{
CManagedByPage * pManagedBy;
HRESULT hr = S_OK;
switch (DlgOp)
{
case fInit:
case fObjChanged:
if (DlgOp == fInit)
{
pManagedBy = new CManagedByPage(pPage);
((CDsTableDrivenPage *)pPage)->m_pData = reinterpret_cast<LPARAM>(pManagedBy);
CHECK_NULL_REPORT(pManagedBy, pPage->GetHWnd(), return E_OUTOFMEMORY);
pManagedBy->SetNameCtrlID(pAttrMap->nCtrlID);
pManagedBy->SetWritable(PATTR_DATA_IS_WRITABLE(pAttrData));
}
else
{
pManagedBy = reinterpret_cast<CManagedByPage*>(((CDsTableDrivenPage *)pPage)->m_pData);
if (!pManagedBy)
{
return E_FAIL;
}
}
if (pAttrInfo && pAttrInfo->dwNumValues)
{
hr = pManagedBy->SetObj(pAttrInfo->pADsValues->DNString);
if (FAILED(hr))
{
return hr;
}
}
break;
case fOnCommand:
if (EN_CHANGE == lParam)
{
pPage->SetDirty();
PATTR_DATA_SET_DIRTY(pAttrData); // Attribute has been modified.
}
break;
case fApply:
if (!PATTR_DATA_IS_WRITABLE(pAttrData) || !PATTR_DATA_IS_DIRTY(pAttrData))
{
return ADM_S_SKIP;
}
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
if (pManagedBy)
{
if (pManagedBy->IsValid())
{
PADSVALUE pADsValue;
pADsValue = new ADSVALUE;
CHECK_NULL_REPORT(pADsValue, pPage->GetHWnd(), return E_OUTOFMEMORY);
PWSTR pwz;
if (!AllocWStr(pManagedBy->Name(), &pwz))
{
REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd());
return E_OUTOFMEMORY;
}
pAttrInfo->pADsValues = pADsValue;
pAttrInfo->dwNumValues = 1;
pAttrInfo->dwControlCode = ADS_ATTR_UPDATE;
pADsValue->dwType = pAttrInfo->dwADsType;
pADsValue->DNString = pwz;
}
else
{
pAttrInfo->pADsValues = NULL;
pAttrInfo->dwNumValues = 0;
pAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
}
}
break;
case fOnDestroy:
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
DO_DEL(pManagedBy);
break;
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Attr Function: ChangeButton
//
// Synopsis: Handles the Change Managed-By button.
//
//-----------------------------------------------------------------------------
HRESULT
ChangeButton(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM lParam, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit == DlgOp)
{
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
dspAssert(pManagedBy);
if (!pManagedBy->IsWritable())
{
EnableWindow(GetDlgItem(pPage->GetHWnd(), pAttrMap->nCtrlID), FALSE);
}
}
if (!(DlgOp == fOnCommand && lParam == BN_CLICKED))
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
HRESULT hr = S_OK;
LPWSTR cleanstr = NULL;
CWaitCursor WaitCursor;
IDsObjectPicker * pObjSel;
BOOL fIsObjSelInited;
hr = pPage->GetObjSel(&pObjSel, &fIsObjSelInited);
CHECK_HRESULT(hr, return hr);
if (!fIsObjSelInited)
{
CStrW cstrDC;
CComPtr<IDirectoryObject> spDsObj;
if (pPage->m_pDsObj == NULL)
{
//
// For the retrieval of the DS Object names
//
FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM objMedium;
hr = pPage->m_pWPTDataObj->GetData(&fmte, &objMedium);
CHECK_HRESULT(hr, return hr);
LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
pDsObjectNames->aObjects[0].offsetName);
//
// Bind to the object
//
hr = ADsOpenObject(pwzObjADsPath, NULL, NULL, ADS_SECURE_AUTHENTICATION,
IID_IDirectoryObject, (PVOID*)&spDsObj);
CHECK_HRESULT(hr, return hr);
}
else
{
spDsObj = pPage->m_pDsObj;
}
hr = GetLdapServerName(spDsObj, cstrDC);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
DSOP_SCOPE_INIT_INFO rgScopes[3];
DSOP_INIT_INFO InitInfo;
ZeroMemory(rgScopes, sizeof(rgScopes));
ZeroMemory(&InitInfo, sizeof(InitInfo));
rgScopes[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
rgScopes[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN;
rgScopes[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
rgScopes[0].pwzDcName = cstrDC;
rgScopes[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS |
DSOP_FILTER_CONTACTS;
rgScopes[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
rgScopes[1].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG;
rgScopes[1].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS |
DSOP_FILTER_CONTACTS;
rgScopes[2].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
rgScopes[2].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN;
rgScopes[2].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS |
DSOP_FILTER_CONTACTS;
InitInfo.cbSize = sizeof(DSOP_INIT_INFO);
InitInfo.cDsScopeInfos = 3;
InitInfo.aDsScopeInfos = rgScopes;
InitInfo.pwzTargetComputer = cstrDC;
hr = pObjSel->Initialize(&InitInfo);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
pPage->ObjSelInited();
}
IDataObject * pdoSelections = NULL;
hr = pObjSel->InvokeDialog(pPage->GetHWnd(), &pdoSelections);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
if (hr == S_FALSE || !pdoSelections)
{
return S_OK;
}
FORMATETC fmte = {g_cfDsSelList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium = {TYMED_NULL, NULL, NULL};
hr = pdoSelections->GetData(&fmte, &medium);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
PDS_SELECTION_LIST pSelList = (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);
if (!pSelList || !pSelList->cItems || !pSelList->aDsSelection->pwzADsPath)
{
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
pdoSelections->Release();
return S_OK;
}
WaitCursor.SetWait();
hr = pPage->SkipPrefix(pSelList->aDsSelection->pwzADsPath, &cleanstr);
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
pdoSelections->Release();
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), goto Cleanup);
hr = pManagedBy->SetObj(cleanstr);
CHECK_HRESULT(hr, goto Cleanup);
pPage->SetDirty();
pManagedBy->RefreshCtrls();
Cleanup:
DO_DEL(cleanstr);
return hr;
}
//+----------------------------------------------------------------------------
//
// Attr Function: ViewButton
//
// Synopsis: Handles the View button.
//
//-----------------------------------------------------------------------------
HRESULT
ViewButton(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM lParam, PATTR_DATA,
DLG_OP DlgOp)
{
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
switch (DlgOp)
{
case fInit:
dspAssert(pManagedBy);
//
// Save the control ID.
//
pManagedBy->m_nViewBtnID = pAttrMap->nCtrlID;
// fall through
case fObjChanged:
//
// Enable/Disable as appropriate.
//
EnableWindow(GetDlgItem(pPage->GetHWnd(), pManagedBy->m_nViewBtnID),
pManagedBy->IsValid());
break;
case fOnCommand:
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (lParam == BN_CLICKED && pManagedBy->IsValid())
{
PostPropSheet(pManagedBy->Name(), pPage);
}
break;
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Attr Function: ClearButton
//
// Synopsis: Handles the Clear pushbutton.
//
//-----------------------------------------------------------------------------
HRESULT
ClearButton(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM lParam, PATTR_DATA,
DLG_OP DlgOp)
{
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
switch (DlgOp)
{
case fInit:
dspAssert(pManagedBy);
//
// Save the control ID.
//
pManagedBy->m_nClearBtnID = pAttrMap->nCtrlID;
// fall through
case fObjChanged:
//
// Enable/Disable as appropriate.
//
EnableWindow(GetDlgItem(pPage->GetHWnd(), pManagedBy->m_nClearBtnID),
pManagedBy->IsValid() && pManagedBy->IsWritable());
break;
case fOnCommand:
if (lParam == BN_CLICKED)
{
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
pManagedBy->Clear();
pManagedBy->RefreshCtrls();
pPage->SetDirty();
}
break;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: SetSecurityInfoMask
//
// Synopsis: Reads the security descriptor from the specied DS object
//
// Arguments: [IN punk] -- IUnknown from IDirectoryObject
// [IN si] -- SecurityInformation
//// History: 25-Dec-2000 -- Hiteshr Created
//----------------------------------------------------------------------------
HRESULT
SetSecurityInfoMask(LPUNKNOWN punk, SECURITY_INFORMATION si)
{
HRESULT hr = E_INVALIDARG;
if (punk)
{
IADsObjectOptions *pOptions;
hr = punk->QueryInterface(IID_IADsObjectOptions, (void**)&pOptions);
if (SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_I4;
V_I4(&var) = si;
hr = pOptions->SetOption(ADS_OPTION_SECURITY_MASK, var);
pOptions->Release();
}
}
return hr;
}
WCHAR const c_szSDProperty[] = L"nTSecurityDescriptor";
//+---------------------------------------------------------------------------
//
// Function: DSReadObjectSecurity
//
// Synopsis: Reads the Dacl from the specied DS object
//
// Arguments: [in pDsObject] -- IDirettoryObject for dsobject
// [psdControl] -- Control Setting for SD
// They can be returned when calling
// DSWriteObjectSecurity
// [OUT ppDacl] -- DACL returned here
//
//
// History 25-Oct-2000 -- hiteshr created
//
// Notes: If Object Doesn't have DACL, function will succeed but *ppDacl will
// be NULL.
// Caller must free *ppDacl, if not NULL, by calling LocalFree
//
//----------------------------------------------------------------------------
HRESULT
DSReadObjectSecurity(IN IDirectoryObject *pDsObject,
OUT SECURITY_DESCRIPTOR_CONTROL * psdControl,
OUT PACL *ppDacl)
{
HRESULT hr = S_OK;
PADS_ATTR_INFO pSDAttributeInfo = NULL;
do // false loop
{
LPWSTR pszSDProperty = (LPWSTR)c_szSDProperty;
DWORD dwAttributesReturned;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pAcl = NULL;
if(!pDsObject || !ppDacl)
{
hr = E_INVALIDARG;
break;
}
*ppDacl = NULL;
// Set the SECURITY_INFORMATION mask
hr = SetSecurityInfoMask(pDsObject, DACL_SECURITY_INFORMATION);
if(FAILED(hr))
{
break;
}
//
// Read the security descriptor
//
hr = pDsObject->GetObjectAttributes(&pszSDProperty,
1,
&pSDAttributeInfo,
&dwAttributesReturned);
if (SUCCEEDED(hr) && !pSDAttributeInfo)
hr = E_ACCESSDENIED; // This happens for SACL if no SecurityPrivilege
if(FAILED(hr))
{
break;
}
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->dwADsType);
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->pADsValues->dwType);
pSD = (PSECURITY_DESCRIPTOR)pSDAttributeInfo->pADsValues->SecurityDescriptor.lpValue;
//
//Get the security descriptor control
//
if(psdControl)
{
DWORD dwRevision;
if(!GetSecurityDescriptorControl(pSD, psdControl, &dwRevision))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
}
//
//Get pointer to DACL
//
BOOL bDaclPresent, bDaclDefaulted;
if(!GetSecurityDescriptorDacl(pSD,
&bDaclPresent,
&pAcl,
&bDaclDefaulted))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
if(!bDaclPresent || !pAcl)
break;
dspAssert(IsValidAcl(pAcl));
//
//Make a copy of the DACL
//
*ppDacl = (PACL)LocalAlloc(LPTR,pAcl->AclSize);
if(!*ppDacl)
{
hr = E_OUTOFMEMORY;
break;
}
CopyMemory(*ppDacl,pAcl,pAcl->AclSize);
}while(0);
if (pSDAttributeInfo)
FreeADsMem(pSDAttributeInfo);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: DSWriteObjectSecurity
//
// Synopsis: Writes the Dacl to the specied DS object
//
// Arguments: [in pDsObject] -- IDirettoryObject for dsobject
// [sdControl] -- control for security descriptor
// [IN pDacl] -- The DACL to be written
//
// History 25-Oct-2000 -- hiteshr created
//----------------------------------------------------------------------------
HRESULT
DSWriteObjectSecurity(IN IDirectoryObject *pDsObject,
IN SECURITY_DESCRIPTOR_CONTROL sdControl,
PACL pDacl)
{
HRESULT hr = S_OK;
PISECURITY_DESCRIPTOR pSD = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
do // false loop
{
ADSVALUE attributeValue;
ADS_ATTR_INFO attributeInfo;
DWORD dwAttributesModified;
DWORD dwSDLength;
if(!pDsObject || !pDacl)
{
dspAssert(FALSE);
hr = E_INVALIDARG;
break;
}
dspAssert(IsValidAcl(pDacl));
// Set the SECURITY_INFORMATION mask
hr = SetSecurityInfoMask(pDsObject, DACL_SECURITY_INFORMATION);
if(FAILED(hr))
{
break;
}
//
//Build the Security Descriptor
//
pSD = (PISECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSD == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
//
// Finally, build the security descriptor
//
pSD->Control |= SE_DACL_PRESENT | SE_DACL_AUTO_INHERIT_REQ
| (sdControl & (SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED));
if(pDacl->AclSize)
{
pSD->Dacl = pDacl;
}
//
// Need the total size
//
dwSDLength = GetSecurityDescriptorLength(pSD);
//
// If necessary, make a self-relative copy of the security descriptor
//
psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDLength);
if (psd == NULL ||
!MakeSelfRelativeSD(pSD, psd, &dwSDLength))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
attributeValue.dwType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
attributeValue.SecurityDescriptor.dwLength = dwSDLength;
attributeValue.SecurityDescriptor.lpValue = (LPBYTE)psd;
attributeInfo.pszAttrName = (LPWSTR)c_szSDProperty;
attributeInfo.dwControlCode = ADS_ATTR_UPDATE;
attributeInfo.dwADsType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
attributeInfo.pADsValues = &attributeValue;
attributeInfo.dwNumValues = 1;
// Write the security descriptor
hr = pDsObject->SetObjectAttributes(&attributeInfo,
1,
&dwAttributesModified);
} while (false);
if (psd != NULL)
{
LocalFree(psd);
}
if(pSD != NULL)
{
LocalFree(pSD);
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Helper Attr Function: GetMembershipPermsFor
//
// Synopsis: Checks the ACL for the group to determine if the manager has
// rights to write group membership.
//
//-----------------------------------------------------------------------------
HRESULT
GetMembershipPermsFor(IDirectoryObject* pManagerObject,
IDirectoryObject* pGroupObject,
BOOL* pbHasWritePerms,
BOOL* pbIsSecurityPrinciple)
{
HRESULT hr = S_OK;
//
// Validate parameters
//
if (!pManagerObject ||
!pGroupObject ||
!pbHasWritePerms ||
!pbIsSecurityPrinciple)
{
return E_INVALIDARG;
}
*pbHasWritePerms = FALSE;
*pbIsSecurityPrinciple = FALSE;
//
// Get the SID of the manager
//
static DWORD dwAttrCount = 1;
PWSTR pszAttrs[] = { g_wzObjectSID };
PADS_ATTR_INFO pAttrInfo = NULL;
DWORD dwAttrRet = 0;
hr = pManagerObject->GetObjectAttributes(pszAttrs,
dwAttrCount,
&pAttrInfo,
&dwAttrRet);
if (FAILED(hr))
{
*pbIsSecurityPrinciple = FALSE;
return S_OK;
}
PSID pManagerSID = NULL;
if (pAttrInfo && dwAttrRet == 1)
{
if (_wcsicmp(pAttrInfo->pszAttrName, g_wzObjectSID) == 0 &&
pAttrInfo->pADsValues)
{
pManagerSID = pAttrInfo->pADsValues->OctetString.lpValue;
}
}
if (pManagerSID == NULL)
{
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
*pbIsSecurityPrinciple = FALSE;
return S_FALSE;
}
*pbIsSecurityPrinciple = TRUE;
//
// Now get the Security Descriptor from the group
//
SECURITY_DESCRIPTOR_CONTROL sdControl = {0};
CSimpleAclHolder Dacl;
hr = DSReadObjectSecurity(pGroupObject,
&sdControl,
&(Dacl.m_pAcl));
if (FAILED(hr))
{
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
return hr;
}
ULONG ulCount = 0, j = 0;
PEXPLICIT_ACCESS rgEntries = NULL;
DWORD dwErr = GetExplicitEntriesFromAcl(Dacl.m_pAcl, &ulCount, &rgEntries);
if (ERROR_SUCCESS != dwErr)
{
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
hr = HRESULT_FROM_WIN32(dwErr);
return hr;
}
bool bManagerAllowWrite = false;
//
// Loop through looking for the can change password ACE for the manager SID
//
for (j = 0; j < ulCount; j++)
{
//
// Look for allow ACEs
//
OBJECTS_AND_SID* pObjectsAndSid = NULL;
pObjectsAndSid = (OBJECTS_AND_SID*)rgEntries[j].Trustee.ptstrName;
if (IsEqualGUID(pObjectsAndSid->ObjectTypeGuid,
GUID_MemberAttribute))
{
if ((rgEntries[j].grfAccessPermissions & ACTRL_DS_WRITE_PROP) &&
rgEntries[j].grfAccessMode == GRANT_ACCESS)
{
//
// See if it is for the manager SID
//
if (EqualSid(pObjectsAndSid->pSid, pManagerSID))
{
//
// Allow manager found
//
bManagerAllowWrite = true;
break;
}
}
}
}
*pbHasWritePerms = bManagerAllowWrite;
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
LocalFree(rgEntries);
return hr;
}
//+----------------------------------------------------------------------------
//
// Helper Attr Function: WriteMembershipPermsFor
//
// Synopsis: Updates the ACL for the group to with the manager has
// rights to write group membership.
//
//-----------------------------------------------------------------------------
HRESULT
WriteMembershipPermsFor(IDirectoryObject* pManagerObject,
IDirectoryObject* pGroupObject,
BOOL bGiveWritePerms)
{
HRESULT hr = S_OK;
//
// Validate parameters
//
if (!pManagerObject ||
!pGroupObject)
{
return E_INVALIDARG;
}
//
// Get the SID of the manager
//
static DWORD dwAttrCount = 1;
PWSTR pszAttrs[] = { g_wzObjectSID };
PADS_ATTR_INFO pAttrInfo = NULL;
DWORD dwAttrRet = 0;
hr = pManagerObject->GetObjectAttributes(pszAttrs,
dwAttrCount,
&pAttrInfo,
&dwAttrRet);
if (FAILED(hr))
{
//
// Not a Security principle, just return
//
return S_OK;
}
PSID pManagerSID = NULL;
if (pAttrInfo && dwAttrRet == 1)
{
if (_wcsicmp(pAttrInfo->pszAttrName, g_wzObjectSID) == 0 &&
pAttrInfo->pADsValues)
{
pManagerSID = pAttrInfo->pADsValues->OctetString.lpValue;
}
}
if (pManagerSID == NULL)
{
//
// Not a Security principle, just return
//
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
return S_OK;
}
//
// Now get the Security Descriptor from the group
//
SECURITY_DESCRIPTOR_CONTROL sdControl = {0};
CSimpleAclHolder Dacl;
hr = DSReadObjectSecurity(pGroupObject,
&sdControl,
&(Dacl.m_pAcl));
if (FAILED(hr))
{
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
return hr;
}
ULONG ulCount = 0, j = 0;
PEXPLICIT_ACCESS rgEntries = NULL;
DWORD dwErr = GetExplicitEntriesFromAcl(Dacl.m_pAcl, &ulCount, &rgEntries);
if (ERROR_SUCCESS != dwErr)
{
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
hr = HRESULT_FROM_WIN32(dwErr);
return hr;
}
PEXPLICIT_ACCESS rgNewEntries = NULL;
ULONG ulNewCount = 0;
//
// At the most we will add an Allow ACE so allocate enough space for that
//
rgNewEntries = (PEXPLICIT_ACCESS)LocalAlloc(LPTR, sizeof(EXPLICIT_ACCESS)*(ulCount + 1));
if (!rgNewEntries)
{
if(pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
return E_OUTOFMEMORY;
}
bool bManagerAllowWrite = false;
//
// Loop through looking for the can change password ACE for the manager SID
//
for (j = 0; j < ulCount; j++)
{
bool bCopyACE = true;
//
// Look for allow ACEs
//
OBJECTS_AND_SID* pObjectsAndSid = NULL;
pObjectsAndSid = (OBJECTS_AND_SID*)rgEntries[j].Trustee.ptstrName;
if (IsEqualGUID(pObjectsAndSid->ObjectTypeGuid,
GUID_MemberAttribute))
{
if ((rgEntries[j].grfAccessPermissions & ACTRL_DS_WRITE_PROP) &&
rgEntries[j].grfAccessMode == GRANT_ACCESS)
{
//
// See if it is for the manager SID
//
if (EqualSid(pObjectsAndSid->pSid, pManagerSID))
{
//
// Allow manager found
//
bManagerAllowWrite = true;
if (!bGiveWritePerms)
{
bCopyACE = false;
}
}
}
}
if (bCopyACE)
{
rgNewEntries[ulNewCount] = rgEntries[j];
ulNewCount++;
}
}
//
// If we want the manager to have write perms but we didn't
// find an Allow ACE add one now
//
if (bGiveWritePerms && !bManagerAllowWrite)
{
rgNewEntries[ulNewCount].grfAccessPermissions = ACTRL_DS_WRITE_PROP;
rgNewEntries[ulNewCount].grfAccessMode = GRANT_ACCESS;
rgNewEntries[ulNewCount].grfInheritance = NO_INHERITANCE;
//
// build the trustee structs for change password
//
OBJECTS_AND_SID rgObjectsAndSid = {0};
BuildTrusteeWithObjectsAndSid(&(rgNewEntries[ulNewCount].Trustee),
&rgObjectsAndSid,
const_cast<GUID *>(&GUID_MemberAttribute),
NULL, // inherit guid
pManagerSID);
ulNewCount++;
}
CSimpleAclHolder NewDacl;
dwErr = SetEntriesInAcl(ulNewCount, rgNewEntries, NULL, &(NewDacl.m_pAcl));
dspAssert(IsValidAcl(NewDacl.m_pAcl));
hr = DSWriteObjectSecurity(pGroupObject,
sdControl,
NewDacl.m_pAcl);
if (pAttrInfo)
{
FreeADsMem(pAttrInfo);
pAttrInfo = NULL;
}
LocalFree(rgNewEntries);
LocalFree(rgEntries);
return hr;
}
//+----------------------------------------------------------------------------
//
// Attr Function: UpdateListCheck
//
// Synopsis: Handles the allow manager to update membership list checkbox
//
//-----------------------------------------------------------------------------
HRESULT
UpdateListCheck(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM lParam, PATTR_DATA,
DLG_OP DlgOp)
{
CManagedByPage* pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
switch (DlgOp)
{
case fInit:
dspAssert(pManagedBy);
//
// Save the control ID.
//
pManagedBy->m_nUpdateListChkID = pAttrMap->nCtrlID;
// fall through
case fObjChanged:
{
//
// See if the object is a security principle and if so then see
// if it has permission to write group membership
//
BOOL bHasWritePerms = FALSE;
BOOL bIsSecurityPrinciple = FALSE;
HRESULT hr = GetMembershipPermsFor(pManagedBy->Obj(),
pPage->m_pDsObj,
&bHasWritePerms,
&bIsSecurityPrinciple);
//
// Ignore failures and use the defaults
//
pManagedBy->SetMembershipWritable(bHasWritePerms);
pManagedBy->SetUpdateListCheckEnable(bIsSecurityPrinciple);
hr = S_OK;
//
// Enable/Disable as appropriate.
//
EnableWindow(GetDlgItem(pPage->GetHWnd(), pManagedBy->m_nUpdateListChkID),
pManagedBy->IsUpdateCheckEnable());
SendDlgItemMessage(pPage->GetHWnd(),
pManagedBy->m_nUpdateListChkID,
BM_SETCHECK,
(WPARAM)(pManagedBy->IsMembershipWritable()) ? BST_CHECKED : BST_UNCHECKED,
0);
}
break;
case fOnCommand:
if (lParam == BN_CLICKED)
{
CHECK_NULL(pManagedBy, return ADM_S_SKIP);
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
pPage->SetDirty();
}
break;
case fApply:
if (pManagedBy)
{
//
// Set the ownership of the group to the new manager
//
HRESULT hr = S_OK;
if ((pManagedBy->PreviousName() && pManagedBy->Name() &&
_wcsicmp(pManagedBy->Name(), pManagedBy->PreviousName()) != 0) ||
!pManagedBy->Name())
{
//
// The new name and the old name are different so we need to update
// the ACL
//
//
// First remove the old manager from the ACL
//
hr = WriteMembershipPermsFor(pManagedBy->PreviousObj(),
pPage->m_pDsObj,
FALSE);
}
//
// Now add the new manager to the ACL if checkbox is checked
//
BOOL bAddGrantACE = (SendDlgItemMessage(pPage->GetHWnd(),
pManagedBy->m_nUpdateListChkID,
BM_GETCHECK,
0,
0) == BST_CHECKED);
hr = WriteMembershipPermsFor(pManagedBy->Obj(),
pPage->m_pDsObj,
bAddGrantACE);
DO_RELEASE(pManagedBy->m_pPrevDsObj);
pManagedBy->m_pPrevDsObj = pManagedBy->Obj();
if (pManagedBy->m_pPrevDsObj)
{
pManagedBy->m_pPrevDsObj->AddRef();
}
if (pManagedBy->PreviousName() && pManagedBy->Name() &&
_wcsicmp(pManagedBy->Name(), pManagedBy->PreviousName()) != 0)
{
DO_DEL(pManagedBy->m_pwzPrevObjName);
}
pManagedBy->m_pwzPrevObjName = pManagedBy->Name();
}
break;
}
return ADM_S_SKIP;
}
//+----------------------------------------------------------------------------
//
// Attr Function: OfficeEdit
//
//-----------------------------------------------------------------------------
HRESULT
OfficeEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pOfficeAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pOfficeAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pOfficeAttrMap);
}
//+----------------------------------------------------------------------------
//
// Attr Function: StreetEdit
//
//-----------------------------------------------------------------------------
HRESULT
StreetEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pStreetAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pStreetAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pStreetAttrMap);
}
//+----------------------------------------------------------------------------
//
// Attr Function: CityEdit
//
//-----------------------------------------------------------------------------
HRESULT
CityEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pCityAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pCityAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pCityAttrMap);
}
//+----------------------------------------------------------------------------
//
// Attr Function: StateEdit
//
//-----------------------------------------------------------------------------
HRESULT
StateEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pStateAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pStateAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pStateAttrMap);
}
//+----------------------------------------------------------------------------
//
// Attr Function: CountryEdit
//
//-----------------------------------------------------------------------------
HRESULT
CountryEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM lParam, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pCountryAttrMap == NULL)
{
pManagedBy->m_pCountryAttrMap = pAttrMap;
}
if (pManagedBy->IsUser())
{
HRESULT hr;
PADS_ATTR_INFO pAttr = NULL;
DWORD cAttrs = 0;
hr = pManagedBy->Obj()->GetObjectAttributes(&pManagedBy->m_pCountryAttrMap->AttrInfo.pszAttrName,
1, &pAttr, &cAttrs);
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, pPage->GetHWnd()))
{
return hr;
}
ATTR_DATA AttrData = {0};
hr = CountryName(pPage, pManagedBy->m_pCountryAttrMap, pAttr, lParam,
&AttrData, DlgOp);
if (pAttr)
FreeADsMem(pAttr);
return hr;
}
else
{
SetDlgItemText(pPage->GetHWnd(), pManagedBy->m_pCountryAttrMap->nCtrlID,
TEXT(""));
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Attr Function: PhoneEdit
//
//-----------------------------------------------------------------------------
HRESULT
PhoneEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pPhoneAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pPhoneAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pPhoneAttrMap);
}
//+----------------------------------------------------------------------------
//
// Attr Function: FaxEdit
//
//-----------------------------------------------------------------------------
HRESULT
FaxEdit(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
PADS_ATTR_INFO, LPARAM, PATTR_DATA,
DLG_OP DlgOp)
{
if (fInit != DlgOp && fObjChanged != DlgOp)
{
return S_OK;
}
CManagedByPage * pManagedBy;
pManagedBy = (CManagedByPage *)((CDsTableDrivenPage *)pPage)->m_pData;
CHECK_NULL(pManagedBy, return E_OUTOFMEMORY);
if (pManagedBy->m_pFaxAttrMap == NULL)
{
// Save the attr map pointer so that it can be used later.
//
pManagedBy->m_pFaxAttrMap = pAttrMap;
}
return pManagedBy->SetEditCtrl(pManagedBy->m_pFaxAttrMap);
}