|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: attredit.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#include <SnapBase.h>
#include "resource.h"
#include "common.h"
#include "attredit.h"
#include "connection.h"
#include "attrqry.h"
#ifdef DEBUG_ALLOCATOR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#endif
////////////////////////////////////////////////////////////////////////////
// this is used to fill in the attributes for RootDSE
//
typedef struct tagRootDSEAttr { LPCWSTR lpszAttr; LPCWSTR lpszSyntax; BOOL bMulti; } SYNTAXMAP;
extern SYNTAXMAP g_ldapRootDSESyntax[]; extern LPCWSTR g_lpszGC; extern LPCWSTR g_lpszRootDSE;
#ifdef OLD_ATTRIBUTE_CLASS
///////////////////////////////////////////////////////////////////////////
// CAttrList
// If the property is not found in the attribute list, a NULL position is
// returned.
POSITION CAttrList::FindProperty(LPCWSTR lpszAttr) { CADSIAttr* pAttr; // NOTICE-NTRAID#NTBUG9-556322-2002/05/03-artm Need to validate lpszAttr before using.
// This should never happen, but just in case . . .
if (!lpszAttr) { ASSERT(false); return NULL; }
for (POSITION p = GetHeadPosition(); p != NULL; GetNext(p)) { // I use GetAt here because I don't want to advance the POSITION
// because it is returned if they are equal
//
pAttr = GetAt(p); CString sName; pAttr->GetProperty(sName); // NOTICE-2002/02/25-artm sName should be null terminated
// since already in data structure. Validation for lpszAttr
// should be done before entering for loop.
if (wcscmp(sName, lpszAttr) == 0) { break; } } return p; }
BOOL CAttrList::HasProperty(LPCWSTR lpszAttr) { POSITION pos = FindProperty(lpszAttr); return pos != NULL; }
// Searches through the cache for the attribute
// ppAttr will point to the CADSIAttr if found, NULL if not
//
void CAttrList::GetNextDirty(POSITION& pos, CADSIAttr** ppAttr) { *ppAttr = GetNext(pos); if (pos == NULL && !(*ppAttr)->IsDirty()) { *ppAttr = NULL; return; }
while (!(*ppAttr)->IsDirty() && pos != NULL) { *ppAttr = GetNext(pos); if (!(*ppAttr)->IsDirty() && pos == NULL) { *ppAttr = NULL; break; } } }
BOOL CAttrList::HasDirty() { POSITION pos = GetHeadPosition(); while (pos != NULL) { CADSIAttr* pAttr = GetNext(pos); if (pAttr->IsDirty()) { return TRUE; } } return FALSE; }
#endif
///////////////////////////////////////////////////////////////////////////
// CDNSManageButtonTextHelper
CDNSManageButtonTextHelper::CDNSManageButtonTextHelper(int nStates) { m_nID = 0; m_pParentWnd = NULL; m_nStates = nStates; m_lpszText = NULL; m_lpszArr = (LPWSTR*)malloc(sizeof(LPWSTR*)*m_nStates); if (m_lpszArr != NULL) { memset(m_lpszArr, 0x0, sizeof(LPWSTR*)*m_nStates); } // FUTURE-2002/02/25-artm If memory allocation fails,
// set the number of states to 0 or maybe even an invalid value.
// That way the caller will be able to check to see if things
// were allocated correctly.
}
CDNSManageButtonTextHelper::~CDNSManageButtonTextHelper() { for (int k = 0; k < m_nStates; k++) { if (m_lpszArr[k] != NULL) free(m_lpszArr[k]); }
free(m_lpszArr); }
void CDNSManageButtonTextHelper::SetStateX(int nIndex) { CWnd* pWnd = m_pParentWnd->GetDlgItem(m_nID); ASSERT(pWnd != NULL); ASSERT( (nIndex >0) || (nIndex < m_nStates)); pWnd->SetWindowText(m_lpszArr[nIndex]); }
BOOL CDNSManageButtonTextHelper::Init(CWnd* pParentWnd, UINT nButtonID, UINT* nStrArray) { ASSERT(m_pParentWnd == NULL); ASSERT(pParentWnd != NULL); m_pParentWnd = pParentWnd; m_nID = nButtonID;
CWnd* pWnd = m_pParentWnd->GetDlgItem(m_nID); if (pWnd == NULL) return FALSE;
// get the text for the window
int nSuccessEntries; // Load the resource strings whose ID's are in nStrArray.
LoadStringArrayFromResource(m_lpszArr, nStrArray, m_nStates, &nSuccessEntries); ASSERT(nSuccessEntries == m_nStates); // NTRAID#NTBUG9-554712-2002/02/25-artm No release code backing up assert.
// Release code should validate that the resource strings were all correctly
// loaded.
return TRUE; }
///////////////////////////////////////////////////////////////////////////
// CDNSButtonToggleTextHelper
CDNSButtonToggleTextHelper::CDNSButtonToggleTextHelper() : CDNSManageButtonTextHelper(2) { }
///////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CADSIEditBox, CEdit) ON_CONTROL_REFLECT(EN_CHANGE, OnChange) END_MESSAGE_MAP()
void CADSIEditBox::OnChange() { m_pEditor->OnEditChange(); }
////////////////////////////////////////////////////////////////
// CADSIValueBox
BEGIN_MESSAGE_MAP(CADSIValueBox, CEdit) // ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////
// CADSIValueList
BEGIN_MESSAGE_MAP(CADSIValueList, CListBox) ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelChange) END_MESSAGE_MAP()
void CADSIValueList::OnSelChange() { m_pEditor->OnValueSelChange(); }
////////////////////////////////////////////////////////////////
// CADSIAddButton
BEGIN_MESSAGE_MAP(CADSIAddButton, CButton) ON_CONTROL_REFLECT(BN_CLICKED, OnAdd) END_MESSAGE_MAP()
void CADSIAddButton::OnAdd() { m_pEditor->OnAddValue(); }
////////////////////////////////////////////////////////////////
// CADSIRemoveButton
BEGIN_MESSAGE_MAP(CADSIRemoveButton, CButton) ON_CONTROL_REFLECT(BN_CLICKED, OnRemove) END_MESSAGE_MAP()
void CADSIRemoveButton::OnRemove() { m_pEditor->OnRemoveValue(); }
////////////////////////////////////////////////////////////////
// CAttrEditor
CAttrEditor::CAttrEditor() : m_AttrEditBox(this), m_SyntaxBox(this), m_ValueBox(this), m_ValueList(this), m_AddButton(this), m_RemoveButton(this), m_AddButtonHelper(), m_RemoveButtonHelper() { m_bExisting = TRUE; m_ptouchedAttr = NULL; }
BOOL CAttrEditor::Initialize(CPropertyPageBase* pParentWnd, CTreeNode* pTreeNode, LPCWSTR lpszServer, UINT nIDEdit, UINT nIDSyntax, UINT nIDValueBox, UINT nIDValueList, UINT nIDAddButton, UINT nIDRemoveButton, BOOL bComplete) { ASSERT(pParentWnd != NULL); if (pParentWnd == NULL) return FALSE; m_pParentWnd = pParentWnd;
m_ptouchedAttr = new CAttrList(); ASSERT(m_ptouchedAttr != NULL);
if (pTreeNode == NULL) { m_bExisting = FALSE; } else { m_bExisting = TRUE; }
m_sServer = lpszServer;
if (m_bExisting) { // This gets the CConnectionData from the ConnectionNode by finding a valid treenode and using its
// CADsObject to get the ConnectionNode and then the CConnectionData
//
m_pTreeNode = pTreeNode; CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(m_pTreeNode); if (pContNode == NULL) { CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(m_pTreeNode); ASSERT(pLeafNode != NULL); m_pConnectData = pLeafNode->GetADsObject()->GetConnectionNode()->GetConnectionData(); } else { m_pConnectData = pContNode->GetADsObject()->GetConnectionNode()->GetConnectionData(); } }
// sublclass controls
//
BOOL bRes = m_AttrEditBox.SubclassDlgItem(nIDEdit, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_SyntaxBox.SubclassDlgItem(nIDSyntax, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_ValueBox.SubclassDlgItem(nIDValueBox, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_ValueList.SubclassDlgItem(nIDValueList, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_AddButton.SubclassDlgItem(nIDAddButton, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE; UINT nAddButtonTextIDs[2] = { IDS_BUTTON_TEXT_ADD, IDS_BUTTON_TEXT_SET }; m_AddButtonHelper.Init(m_pParentWnd, nIDAddButton, nAddButtonTextIDs);
bRes = m_RemoveButton.SubclassDlgItem(nIDRemoveButton, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE; UINT nRemoveButtonTextIDs[2] = { IDS_BUTTON_TEXT_REMOVE, IDS_BUTTON_TEXT_CLEAR }; m_RemoveButtonHelper.Init(m_pParentWnd, nIDRemoveButton, nRemoveButtonTextIDs);
// NOTICE-2002/02/27-artm Under low memory environment CString can
// throw out of memory exceptions. ADSI edit prefers to shutdown over
// trying to handle the exception (since no other components depend on
// the tool).
if (!m_sNotSet.LoadString(IDS_NOT_SET)) { return FALSE; }
if ( bComplete) { // Show property values as single and without the ability to set or clear
//
SetPropertyUI(0, FALSE, TRUE); } else { m_AttrEditBox.ShowWindow(SW_HIDE); m_SyntaxBox.ShowWindow(SW_HIDE); m_ValueBox.ShowWindow(SW_HIDE); m_ValueList.ShowWindow(SW_HIDE); m_AddButton.ShowWindow(SW_HIDE); m_RemoveButton.ShowWindow(SW_HIDE); } return bRes; }
BOOL CAttrEditor::Initialize(CPropertyPageBase* pParentWnd, CConnectionData* pConnectData, LPCWSTR lpszServer, UINT nIDEdit, UINT nIDSyntax, UINT nIDValueBox, UINT nIDValueList, UINT nIDAddButton, UINT nIDRemoveButton, BOOL bComplete, CAttrList* pAttrList) { ASSERT(pParentWnd != NULL); if (pParentWnd == NULL) return FALSE; m_pParentWnd = pParentWnd;
m_bExisting = FALSE; m_sServer = lpszServer; m_pConnectData = pConnectData;
ASSERT(pAttrList != NULL); m_ptouchedAttr = pAttrList;
// sublclass controls
//
BOOL bRes = m_AttrEditBox.SubclassDlgItem(nIDEdit, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_SyntaxBox.SubclassDlgItem(nIDSyntax, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_ValueBox.SubclassDlgItem(nIDValueBox, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_ValueList.SubclassDlgItem(nIDValueList, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE;
bRes = m_AddButton.SubclassDlgItem(nIDAddButton, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE; UINT nAddButtonTextIDs[2] = { IDS_BUTTON_TEXT_ADD, IDS_BUTTON_TEXT_SET }; m_AddButtonHelper.Init(m_pParentWnd, nIDAddButton, nAddButtonTextIDs);
bRes = m_RemoveButton.SubclassDlgItem(nIDRemoveButton, m_pParentWnd); ASSERT(bRes); if (!bRes) return FALSE; UINT nRemoveButtonTextIDs[2] = { IDS_BUTTON_TEXT_REMOVE, IDS_BUTTON_TEXT_CLEAR }; m_RemoveButtonHelper.Init(m_pParentWnd, nIDRemoveButton, nRemoveButtonTextIDs);
// NOTICE-2002/02/27-artm Under low memory environment CString can
// throw out of memory exceptions. ADSI edit prefers to shutdown over
// trying to handle the exception (since no other components depend on
// the tool).
if (!m_sNotSet.LoadString(IDS_NOT_SET)) { return FALSE; }
if ( bComplete) { // Show property values as single and without the ability to set or clear
//
SetPropertyUI(0, FALSE, TRUE); } else { m_AttrEditBox.ShowWindow(SW_HIDE); m_SyntaxBox.ShowWindow(SW_HIDE); m_ValueBox.ShowWindow(SW_HIDE); m_ValueList.ShowWindow(SW_HIDE); m_AddButton.ShowWindow(SW_HIDE); m_RemoveButton.ShowWindow(SW_HIDE); } return bRes; } void CAttrEditor::SetAttribute(LPCWSTR lpszAttr, LPCWSTR lpszPath) { m_sAttr = lpszAttr; m_sPath = lpszPath; DisplayAttribute(); }
BOOL CAttrEditor::OnApply() { if (m_bExisting && m_ptouchedAttr->HasDirty() && !m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC()) { CComPtr<IDirectoryObject> pDirObject;
// bind to object with authentication
//
HRESULT hr, hCredResult; hr = OpenObjectWithCredentials( m_pConnectData, m_pConnectData->GetCredentialObject()->UseCredentials(), m_sPath, IID_IDirectoryObject, (LPVOID*) &pDirObject, NULL, hCredResult );
if (FAILED(hr)) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); m_pParentWnd->SetModified(FALSE); } // Need to change the focus or we will not be able to navigate with the keyboard
m_AttrEditBox.SetFocus(); return FALSE; }
// Change or add values to ADSI cache that have changed
//
hr = CADSIAttr::SetValuesInDS(m_ptouchedAttr, pDirObject);
if (FAILED(hr)) { //Format Error message and pop up a dialog
ADSIEditErrorMessage(hr);
m_ptouchedAttr->RemoveAllAttr(); DisplayAttribute();
m_pParentWnd->SetModified(FALSE);
// Need to change the focus or we will not be able to navigate with the keyboard
m_AttrEditBox.SetFocus(); return FALSE; } } m_pParentWnd->SetModified(FALSE); return TRUE; }
void CAttrEditor::OnAddValue() { ASSERT(!m_pConnectData->IsRootDSE()); ASSERT(!m_pConnectData->IsGC()); // NOTICE-2002/02/25-artm Only threat here is that CString will throw out of memory.
CString s; m_AttrEditBox.GetWindowText(s);
CStringList sList; m_pAttr->GetValues(sList);
if (m_pAttr->GetMultivalued()) { // if it is the first value to be added we need to get rid of the "<not set>"
//
CString sNotSet; m_ValueList.GetText(0, sNotSet); if (sNotSet == m_sNotSet) { m_ValueList.ResetContent(); }
// then add the new value
//
sList.AddTail(s); } else { // since it is single valued, remove the old one and add the new one
//
sList.RemoveAll(); sList.AddTail(s); }
HRESULT hr = m_pAttr->SetValues(sList); if (FAILED(hr)) { DisplayFormatError(); } else { if ( m_pAttr->GetMultivalued()) { m_ValueList.AddString(s); } else { m_ValueBox.SetWindowText(s); }
m_AttrEditBox.SetWindowText(_T("")); m_pAttr->SetDirty(TRUE); m_pParentWnd->SetModified(TRUE);
// Make the UI reflect the new data
//
m_AttrEditBox.SetFocus(); SetPropertyUI(~TN_FLAG_ENABLE_ADD, TRUE);
// Enable the clear button if the attribute is not multivalued
//
if ( !m_pAttr->GetMultivalued()) { SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE); } } }
void CAttrEditor::DisplayFormatError() { switch (m_pAttr->GetADsType()) { case ADSTYPE_DN_STRING : case ADSTYPE_CASE_EXACT_STRING : case ADSTYPE_CASE_IGNORE_STRING : case ADSTYPE_PRINTABLE_STRING : case ADSTYPE_NUMERIC_STRING : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
case ADSTYPE_BOOLEAN : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_BOOLEAN, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
case ADSTYPE_INTEGER : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
case ADSTYPE_OCTET_STRING : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_OCTET, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
case ADSTYPE_UTC_TIME : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_TIME, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
case ADSTYPE_LARGE_INTEGER : case ADSTYPE_OBJECT_CLASS : case ADSTYPE_UNKNOWN : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; }
default : { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); if (m_pAttr->GetMultivalued()) { if (m_ValueList.GetCount() < 1) { m_ValueList.AddString(m_sNotSet); } } break; } } }
void CAttrEditor::OnRemoveValue() { if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC()) { CStringList sList; m_pAttr->GetValues(sList);
DWORD dwNumVals = m_pAttr->GetNumValues(); if (m_pAttr->GetMultivalued()) { CString s, sVal; int iCount = m_ValueList.GetCurSel(); m_ValueList.GetText(iCount, sVal); m_AttrEditBox.SetWindowText(sVal); m_ValueList.DeleteString(iCount);
// Add "<not set>" to the UI if this is the last value being removed
//
if (m_ValueList.GetCount() == 0) { m_AttrEditBox.SetFocus(); SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE); m_ValueList.AddString(m_sNotSet); if (!m_bExisting) { m_pAttr->SetDirty(FALSE); } } POSITION pos = sList.FindIndex(iCount);
sList.RemoveAt(pos); HRESULT hr = m_pAttr->SetValues(sList); if (FAILED(hr)) { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); } if (m_bExisting || m_ValueList.GetCount() > 0) { m_pAttr->SetDirty(TRUE); } } else { // NOTICE-2002/02/25-artm Only threat is that CString will throw
// out of memory exception. The input is as safe as can be, coming
// from UI and there is no manipulation.
CString sVal; m_ValueBox.GetWindowText(sVal); m_AttrEditBox.SetWindowText(sVal); m_ValueBox.SetWindowText( m_sNotSet); sList.RemoveAll(); HRESULT hr = m_pAttr->SetValues(sList); if (FAILED(hr)) { ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK); } if (!m_bExisting) { m_pAttr->SetDirty(FALSE); } else { m_pAttr->SetDirty(TRUE); } } m_AttrEditBox.SetFocus(); SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE); dwNumVals--; m_pParentWnd->SetModified(TRUE); } }
void CAttrEditor::OnEditChange() { if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC()) { CString s; // NOTICE-2002/02/25-artm Only threat is that CString can throw
// out of memory exceptions.
m_AttrEditBox.GetWindowText(s); if (s != _T("")) { SetPropertyUI(TN_FLAG_ENABLE_ADD, FALSE); } else { SetPropertyUI(~TN_FLAG_ENABLE_ADD, TRUE); } } }
void CAttrEditor::OnValueSelChange() { if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC()) { SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE); } }
void CAttrEditor::GetAttrFailed() { CString sSyntax;
GetSyntax(m_sAttr, sSyntax); m_SyntaxBox.SetWindowText(sSyntax);
m_ValueList.ResetContent(); m_ValueList.AddString(m_sNotSet); m_ValueBox.SetWindowText(m_sNotSet);
SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE); }
void CAttrEditor::FillWithExisting() { CString s; m_pAttr = m_ptouchedAttr->GetAt(m_ptouchedAttr->FindProperty(m_sAttr)); ASSERT(m_pAttr != NULL);
CStringList slValues; m_pAttr->GetValues(slValues);
if (m_pAttr->GetMultivalued()) { m_ValueList.ResetContent();
POSITION pos; if (slValues.GetCount() == 0) { slValues.AddTail(m_sNotSet); } for (pos = slValues.GetHeadPosition(); pos != NULL; slValues.GetNext(pos) ) { s = slValues.GetAt(pos); m_ValueList.AddString(s); }
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE); } else { if (slValues.GetCount() > 0) { s = slValues.GetAt(slValues.GetHeadPosition()); m_ValueBox.SetWindowText(s);
if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC()) { SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE); } } else { m_ValueBox.SetWindowText(m_sNotSet); SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE); } SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE); } }
void CAttrEditor::DisplayAttribute() { int iCount; HRESULT hr, hCredResult;
if (m_ptouchedAttr->HasProperty(m_sAttr)) { FillWithExisting(); } else {
if (m_pConnectData->IsRootDSE()) { DisplayRootDSE(); } else if (!m_bExisting) { ADS_ATTR_INFO *pAttrInfo = NULL; GetAttrFailed(); m_pAttr = TouchAttr(m_sAttr); ASSERT(m_pAttr != NULL); if (m_pAttr != NULL) { if (m_pAttr->GetMultivalued()) { SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE); } else { SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE); } } return; } else { CComPtr<IDirectoryObject> pDirObject;
hr = OpenObjectWithCredentials( m_pConnectData, m_pConnectData->GetCredentialObject()->UseCredentials(), m_sPath, IID_IDirectoryObject, (LPVOID*) &pDirObject, NULL, hCredResult ); if ( FAILED(hr) ) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); } return; } ASSERT(pDirObject != NULL);
// Get attribute
//
CString szAttrName; szAttrName = m_sAttr + _T(";range=0-*"); CString szFormat = m_sAttr + _T(";range=%ld-*"); DWORD dwReturn = 0; DWORD dwNumAttr = 1; ADS_ATTR_INFO *pAttrInfo;
const WCHAR wcSep = L'-'; const WCHAR wcEnd = L'*'; BOOL fMoreRemain = FALSE;
CStringList sList;
do { LPWSTR lpszAttrs[] = {(LPWSTR)(LPCWSTR)szAttrName}; hr = pDirObject->GetObjectAttributes(lpszAttrs, dwNumAttr, &pAttrInfo, &dwReturn); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return; }
if (pAttrInfo == NULL) { GetAttrFailed(); m_pAttr = TouchAttr(m_sAttr); ASSERT(m_pAttr != NULL); if (m_pAttr != NULL) { if (m_pAttr->GetMultivalued()) { SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE); } else { SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE); } } return; }
if (dwReturn > 0) { GetStringFromADs(pAttrInfo, sList); }
//
// Check to see if there is more data. If the last char of the
// attribute name string is an asterisk, then we have everything.
//
// NOTICE-2002/02/25-artm This is trusting that AD is null
// terminating the name of the attribute. The reasons why this
// trust in service outside the component is allowable are:
// 1) If AD is being spoofed the attacker will 'only' get us to read
// bogus memory. This will AV the client app.
// 2) There is no way to validate the length of the attribute name
// string with the current ADS_ATTR_INFO structure.
int cchEnd = wcslen(pAttrInfo->pszAttrName);
fMoreRemain = pAttrInfo->pszAttrName[cchEnd - 1] != wcEnd;
if (fMoreRemain) { PWSTR pwz = wcsrchr(pAttrInfo->pszAttrName, wcSep); if (!pwz) { ASSERT(FALSE && pAttrInfo->pszAttrName); fMoreRemain = FALSE; } else { pwz++; // move past the hyphen to the range end value.
// NOTICE-2002/02/27-artm Assert does not require release code.
// The assert is a sanity check that the ADSI interface did not return an
// undocumented string format. In other words, there should never be a time
// when this branch is entered and the '-' is the last character in the string.
// The release code does not need this check b/c if it does occur (and it shouldn't),
// there's a bug in ADSI. The tool will crash from reading past pointer and go
// into Dr. Watson (which can be used just as well to track down the bug).
ASSERT(*pwz);
long lEnd = _wtol(pwz); lEnd++; // start with the next value.
szAttrName.Format(szFormat, lEnd); TRACE(L"Range returned is %ws, now asking for %ws\n", pAttrInfo->pszAttrName, szAttrName); } } } while (fMoreRemain);
BOOL bMulti = FALSE; if (m_pConnectData->IsGC()) { bMulti = IsMultiValued(pAttrInfo); } else { bMulti = IsMultiValued(m_sAttr); }
if (pAttrInfo != NULL) { if (bMulti) { SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
m_ValueList.ResetContent();
POSITION pos = sList.GetHeadPosition(); while (pos != NULL) { CString sValue = sList.GetNext(pos); m_ValueList.AddString(sValue); } } else { SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
if (sList.GetCount() > 0) { m_ValueBox.SetWindowText(sList.GetHead()); } if (!m_pConnectData->IsGC()) { SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE); } } } else { GetAttrFailed(); CStringList sTempList; m_pAttr = TouchAttr(pAttrInfo, bMulti); if (bMulti) { SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE); } else { SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE); } return; } m_pAttr = TouchAttr(pAttrInfo, bMulti); } }
CString sSyntax; GetSyntax(m_sAttr, sSyntax); m_SyntaxBox.SetWindowText(sSyntax); }
void CAttrEditor::DisplayRootDSE() { CString s = m_sPath;
CComPtr<IADs> pADs; HRESULT hr, hCredResult; hr = OpenObjectWithCredentials( m_pConnectData, m_pConnectData->GetCredentialObject()->UseCredentials(), s, IID_IADs, (LPVOID*)&pADs, NULL, hCredResult );
if ( FAILED(hr) ) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); } return; }
// This is to insure that the ADSI cache is current
//
hr = pADs->GetInfo();
VARIANT var; hr = pADs->GetEx( CComBSTR(m_sAttr) , &var ); if ( FAILED(hr) ) { GetAttrFailed(); m_pAttr = TouchAttr(m_sAttr); return; }
/////////////////////////////////////////
// Convert and populate
///////////////////////////////////////////
CStringList sList; hr = VariantToStringList( var, sList ); if ( FAILED(hr) ) { GetAttrFailed(); VariantClear(&var); CStringList sTempList; m_pAttr = TouchAttr(m_sAttr); return; } VariantClear( &var );
if ( IsRootDSEAttrMultiValued(m_sAttr) ) { SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE);
m_ValueList.ResetContent();
POSITION pos = sList.GetHeadPosition(); while (pos != NULL) { CString sValue = sList.GetNext(pos); m_ValueList.AddString(sValue); } } else { SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
s = sList.GetHead(); m_ValueBox.SetWindowText(s); }
// m_pAttr = TouchAttr(m_sAttr);
CString sSyntax; GetSyntax(m_sAttr, sSyntax); m_SyntaxBox.SetWindowText(sSyntax);
// REVEIW : this is the only occurrance of "UTCTime", if there
// becomes more we may need to make a global string or something
//
if (sSyntax == _T("UTCTime")) { CString sFormatted, sRemainder; CString sYear, sMonth, sDay, sHour, sMinute, sSecond; int iCount = 0;
sYear = s.Left(4); iCount = s.GetLength(); sRemainder = s.Right(iCount - 4);
sMonth = sRemainder.Left(2); iCount = sRemainder.GetLength(); sRemainder = sRemainder.Right(iCount - 2);
sDay = sRemainder.Left(2); iCount = sRemainder.GetLength(); sRemainder = sRemainder.Right(iCount - 2);
sHour = sRemainder.Left(2); iCount = sRemainder.GetLength(); sRemainder = sRemainder.Right(iCount - 2);
sMinute = sRemainder.Left(2); iCount = sRemainder.GetLength(); sRemainder = sRemainder.Right(iCount - 2);
sSecond = sRemainder.Left(2);
sFormatted = sMonth + _T("/") + sDay + _T("/") + sYear + _T(" ") + sHour + _T(":") + sMinute + _T(":") + sSecond; m_ValueBox.SetWindowText(sFormatted); } }
// Pre: lpszAttr non-NULL and must be null terminated
BOOL CAttrEditor::IsRootDSEAttrMultiValued(LPCWSTR lpszAttr) { int idx=0, iCount = 0;
// NOTICE-2002/02/26-artm This method only called from SetAttribute()
// and is not a public function. If it were public we would need to be
// careful about a NULL lpszAttr and potentially a string that is not
// null terminated.
iCount = wcslen(lpszAttr);
while( g_ldapRootDSESyntax[idx].lpszAttr) { // NOTICE-2002/02/26-artm Comparison well bounded by length
// of lpszAttr.
if ( _wcsnicmp(g_ldapRootDSESyntax[idx].lpszAttr, lpszAttr, iCount) == 0) { return g_ldapRootDSESyntax[idx].bMulti; } idx++; } return FALSE; }
// TODO : This is extremely ugly, redo it
//
void CAttrEditor::SetPropertyUI(DWORD dwFlags, BOOL bAnd, BOOL bReset) { if (bReset) { m_dwMultiFlags = dwFlags; }
if (bAnd) { m_dwMultiFlags &= dwFlags; } else { m_dwMultiFlags |= dwFlags; }
if (m_dwMultiFlags & TN_FLAG_SHOW_MULTI) { m_AddButtonHelper.SetToggleState(TRUE); m_RemoveButtonHelper.SetToggleState(TRUE); m_ValueList.ShowWindow(SW_SHOW); m_ValueBox.ShowWindow(SW_HIDE); } else { m_AddButtonHelper.SetToggleState(FALSE); m_RemoveButtonHelper.SetToggleState(FALSE); m_ValueList.ShowWindow(SW_HIDE); m_ValueBox.ShowWindow(SW_SHOW); }
if (m_dwMultiFlags & TN_FLAG_ENABLE_REMOVE) { m_RemoveButton.EnableWindow(TRUE); } else { m_RemoveButton.EnableWindow(FALSE); }
if (m_dwMultiFlags & TN_FLAG_ENABLE_ADD) { m_AddButton.EnableWindow(TRUE); } else { m_AddButton.EnableWindow(FALSE); }
if (m_bExisting && (m_pConnectData->IsGC() || m_pConnectData->IsRootDSE())) { m_AttrEditBox.EnableWindow(FALSE); } else { m_AttrEditBox.EnableWindow(TRUE); } }
// Pre: lpszProp non-NULL and null terminated string
void CAttrEditor::GetSyntax(LPCWSTR lpszProp, CString& sSyntax) { if (m_bExisting && m_pConnectData->IsRootDSE()) { int idx=0; while( g_ldapRootDSESyntax[idx].lpszAttr ) { // NOTICE-2002/02/26-artm Use of wcscmp() is ok b/c this is
// a protected function. If it were public we would need to
// worry about a NULL pointer and strings that weren't null
// terminated.
if ( wcscmp(lpszProp, g_ldapRootDSESyntax[idx].lpszAttr) == 0 ) { sSyntax = g_ldapRootDSESyntax[idx].lpszSyntax; return; } idx++; } } else { CComPtr<IADsProperty> pProp; HRESULT hr, hCredResult; CString schema; m_pConnectData->GetAbstractSchemaPath(schema); schema = schema + lpszProp;
hr = OpenObjectWithCredentials( m_pConnectData, m_pConnectData->GetCredentialObject()->UseCredentials(), schema, IID_IADsProperty, (LPVOID*) &pProp, NULL, hCredResult );
if ( FAILED(hr) ) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); } return; }
///////////////////////////////////////////////////
// Create a new cached attribute and populate
//////////////////////////////////////////////////
BSTR bstr;
hr = pProp->get_Syntax( &bstr ); if ( SUCCEEDED(hr) ) { sSyntax = bstr; } SysFreeString(bstr); } }
BOOL CAttrEditor::IsMultiValued(ADS_ATTR_INFO* pAttrInfo) { return (pAttrInfo->dwNumValues > 1) ? TRUE : FALSE; }
BOOL CAttrEditor::IsMultiValued(LPCWSTR lpszProp) { CString schema; BOOL bResult = FALSE;
CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(m_pTreeNode); if (pContNode == NULL) { CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(m_pTreeNode); ASSERT(pLeafNode != NULL); bResult = pLeafNode->BuildSchemaPath(schema); } else { bResult = pContNode->BuildSchemaPath(schema); }
if (!bResult) { return FALSE; }
CADSIQueryObject schemaSearch;
// Initialize search object with path, username and password
//
HRESULT hr = schemaSearch.Init(schema, m_pConnectData->GetCredentialObject()); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return FALSE; }
int cCols = 1; LPWSTR pszAttributes[] = {L"isSingleValued"}; LPWSTR pszDesiredAttr = L"attributeSyntax"; ADS_SEARCH_COLUMN ColumnData; hr = schemaSearch.SetSearchPrefs(ADS_SCOPE_ONELEVEL); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return FALSE; }
BOOL bMulti = FALSE;
CString csFilter; csFilter.Format(L"(&(objectClass=attributeSchema)(lDAPDisplayName=%s))", lpszProp); schemaSearch.SetFilterString((LPWSTR)(LPCWSTR)csFilter); schemaSearch.SetAttributeList (pszAttributes, cCols); hr = schemaSearch.DoQuery (); if (SUCCEEDED(hr)) { hr = schemaSearch.GetNextRow(); if (SUCCEEDED(hr)) { hr = schemaSearch.GetColumn(pszAttributes[0], &ColumnData); if (SUCCEEDED(hr)) { TRACE(_T("\t\tisSingleValued: %d\n"), ColumnData.pADsValues->Boolean); bMulti = !ColumnData.pADsValues->Boolean; } } } return bMulti; }
// NOTE : this is only called for the RootDSE or if we failed to get
// values for the attribute. An empty ADS_ATTR_INFO object is
// created but should not be modified. If values are to be changed
// or set for this object a new ADS_ATTR_INFO should be created
// with the desired block of memory allocated for the values
//
CADSIAttr* CAttrEditor::TouchAttr(LPCWSTR lpszAttr) { // NOTICE-NTRAID#NTBUG9-556322-2002/02/26-artm Need to validate lpszAttr before using.
// This should never happen, but just in case . . .
if (!lpszAttr) { ASSERT(false); return NULL; }
POSITION pos = m_ptouchedAttr->FindProperty(lpszAttr);
if (pos == NULL) { ADS_ATTR_INFO* pADsInfo = new ADS_ATTR_INFO; if (!pADsInfo) { return 0; } memset(pADsInfo, 0, sizeof(ADS_ATTR_INFO));
int iLength = wcslen(lpszAttr); pADsInfo->pszAttrName = new WCHAR[iLength + 1]; wcscpy(pADsInfo->pszAttrName, lpszAttr);
CADSIQueryObject schemaSearch;
BOOL bResult; CString schema; CADSIEditContainerNode* pContNode = m_pConnectData->GetConnectionNode(); bResult = pContNode->BuildSchemaPath(schema); if (!bResult) { return NULL; }
// Initialize search object with path, username and password
//
HRESULT hr = schemaSearch.Init(schema, m_pConnectData->GetCredentialObject()); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return NULL; }
int cCols = 3; LPWSTR pszAttributes[] = {L"lDAPDisplayName", L"attributeSyntax", L"isSingleValued"}; LPWSTR pszDesiredAttr = _T("attributeSyntax"); ADS_SEARCH_COLUMN ColumnData; hr = schemaSearch.SetSearchPrefs(ADS_SCOPE_ONELEVEL); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return NULL; }
BOOL bMulti = FALSE; CString szSyntax;
CString csFilter; csFilter.Format(L"(&(objectClass=attributeSchema)(lDAPDisplayName=%s))", lpszAttr); schemaSearch.SetFilterString((LPWSTR)(LPCWSTR)csFilter); schemaSearch.SetAttributeList (pszAttributes, cCols); hr = schemaSearch.DoQuery (); if (SUCCEEDED(hr)) { hr = schemaSearch.GetNextRow(); if (SUCCEEDED(hr)) { hr = schemaSearch.GetColumn(pszDesiredAttr, &ColumnData); if (SUCCEEDED(hr)) { TRACE(_T("\t\tattributeSyntax: %s\n"), ColumnData.pADsValues->CaseIgnoreString);
ADSTYPE dwType; dwType = GetADsTypeFromString(ColumnData.pADsValues->CaseIgnoreString, szSyntax); pADsInfo->dwADsType = dwType; }
hr = schemaSearch.GetColumn(pszAttributes[2], &ColumnData); if (SUCCEEDED(hr)) { TRACE(_T("\t\tisSingleValued: %d\n"), ColumnData.pADsValues->Boolean); pADsInfo->dwNumValues = 0; bMulti = !ColumnData.pADsValues->Boolean; } } }
CADSIAttr* pAttr = new CADSIAttr(pADsInfo, bMulti, szSyntax, FALSE); m_ptouchedAttr->AddTail(pAttr); return pAttr; }
return m_ptouchedAttr->GetAt(pos); }
CADSIAttr* CAttrEditor::TouchAttr(ADS_ATTR_INFO* pADsInfo, BOOL bMulti) { POSITION pos = m_ptouchedAttr->FindProperty(pADsInfo->pszAttrName);
if (pos == NULL) { CADSIAttr* pAttr = new CADSIAttr(pADsInfo, bMulti, L""); m_ptouchedAttr->AddTail(pAttr); return pAttr; }
return m_ptouchedAttr->GetAt(pos); }
|