|
|
//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: group.cxx
//
// Contents: CDsGroupGenObjPage, the class that implements the group object
// general property page, CDsGrpMembersPage for the group
// membership page, and CDsGrpShlGenPage for the shell group
// general page.
//
// History: 10-April-97 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "proppage.h"
#include "group.h"
#include "qrybase.h"
#define BULK_ADD 1
#ifdef DSADMIN
#define DESCR_IDX 0
#define SAMNAME_IDX 1
#define EMAIL_IDX 2
#define COMMENT_IDX 3
//+----------------------------------------------------------------------------
//
// Member: CDsGroupGenObjPage::CDsGroupGenObjPage
//
//-----------------------------------------------------------------------------
CDsGroupGenObjPage::CDsGroupGenObjPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, HWND hNotifyObj, DWORD dwFlags) : m_pCIcon(NULL), m_fMixed(TRUE), m_dwType(0), m_fTypeWritable(FALSE), m_fDescrWritable(FALSE), m_fSamNameWritable(FALSE), m_fEmailWritable(FALSE), m_fCommentWritable(FALSE), m_fTypeDirty(FALSE), m_fDescrDirty(FALSE), m_fSamNameDirty(FALSE), m_fEmailDirty(FALSE), m_fCommentDirty(FALSE), CDsPropPageBase(pDsPage, pDataObj, hNotifyObj, dwFlags) { TRACE(CDsGroupGenObjPage,CDsGroupGenObjPage); #ifdef _DEBUG
strcpy(szClass, "CDsGroupGenObjPage"); #endif
}
//+----------------------------------------------------------------------------
//
// Member: CDsGroupGenObjPage::~CDsGroupGenObjPage
//
//-----------------------------------------------------------------------------
CDsGroupGenObjPage::~CDsGroupGenObjPage() { TRACE(CDsGroupGenObjPage,~CDsGroupGenObjPage); }
//+----------------------------------------------------------------------------
//
// Function: CreateGroupGenObjPage
//
// Synopsis: Creates an instance of a page window.
//
//-----------------------------------------------------------------------------
HRESULT CreateGroupGenObjPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, PWSTR pwzADsPath, PWSTR pwzClass, HWND hNotifyObj, DWORD dwFlags, CDSBasePathsInfo* pBasePathsInfo, HPROPSHEETPAGE * phPage) { TRACE_FUNCTION(CreateGroupGenObjPage);
CDsGroupGenObjPage * pPageObj = new CDsGroupGenObjPage(pDsPage, pDataObj, hNotifyObj, dwFlags); CHECK_NULL(pPageObj, return E_OUTOFMEMORY);
pPageObj->Init(pwzADsPath, pwzClass, pBasePathsInfo);
return pPageObj->CreatePage(phPage); }
//+----------------------------------------------------------------------------
//
// Method: CDsPropPageBase::DlgProc
//
// Synopsis: per-instance dialog proc
//
//-----------------------------------------------------------------------------
LRESULT CDsGroupGenObjPage::DlgProc(HWND, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == g_uChangeMsg) { OnAttrChanged(wParam); return TRUE; }
switch (uMsg) { case WM_INITDIALOG: return InitDlg(lParam);
case WM_NOTIFY: return OnNotify(wParam, lParam);
case PSM_QUERYSIBLINGS: OnQuerySiblings(wParam, lParam); break;
case WM_SHOWWINDOW: return OnShowWindow();
case WM_SETFOCUS: return OnSetFocus((HWND)wParam);
case WM_HELP: return OnHelp((LPHELPINFO)lParam);
case WM_COMMAND: if (m_fInInit) { return TRUE; } return(OnCommand(GET_WM_COMMAND_ID(wParam, lParam), GET_WM_COMMAND_HWND(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam))); case WM_DESTROY: return OnDestroy();
default: return FALSE; }
return TRUE; }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnInitDialog
//
// Synopsis: Set the initial control values from the corresponding DS
// attributes.
//
//-----------------------------------------------------------------------------
HRESULT CDsGroupGenObjPage::OnInitDialog(LPARAM) { TRACE(CDsGroupGenObjPage,OnInitDialog); HRESULT hr; PADS_ATTR_INFO pAttrs = NULL; DWORD cAttrs = 0;
CWaitCursor Wait;
if (!ADsPropSetHwnd(m_hNotifyObj, m_hPage)) { m_pWritableAttrs = NULL; }
PTSTR ptzRDN; if (!UnicodeToTchar(m_pwszRDName, &ptzRDN)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); return S_OK; }
SetDlgItemText(m_hPage, IDC_CN, ptzRDN); delete ptzRDN;
//
// Get the icon from the DS and put it on the page.
//
ATTR_DATA ad = {0, 0};
hr = GeneralPageIcon(this, &GenIcon, NULL, 0, &ad, fInit);
CHECK_HRESULT_REPORT(hr, m_hPage, return S_OK);
m_pCIcon = (CDsIconCtrl *)ad.pVoid;
m_fTypeWritable = CheckIfWritable(g_wzGroupType); m_fDescrWritable = CheckIfWritable(m_rgpAttrMap[DESCR_IDX]->AttrInfo.pszAttrName); m_fSamNameWritable = CheckIfWritable(m_rgpAttrMap[SAMNAME_IDX]->AttrInfo.pszAttrName); m_fEmailWritable = CheckIfWritable(m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName); m_fCommentWritable = CheckIfWritable(m_rgpAttrMap[COMMENT_IDX]->AttrInfo.pszAttrName);
//
// Get description, SAM name, email address, and comment attributes.
//
SendDlgItemMessage(m_hPage, m_rgpAttrMap[DESCR_IDX]->nCtrlID, EM_LIMITTEXT, m_rgpAttrMap[DESCR_IDX]->nSizeLimit, 0); SendDlgItemMessage(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, EM_LIMITTEXT, m_rgpAttrMap[SAMNAME_IDX]->nSizeLimit, 0); SendDlgItemMessage(m_hPage, m_rgpAttrMap[EMAIL_IDX]->nCtrlID, EM_LIMITTEXT, m_rgpAttrMap[EMAIL_IDX]->nSizeLimit, 0); SendDlgItemMessage(m_hPage, m_rgpAttrMap[COMMENT_IDX]->nCtrlID, EM_LIMITTEXT, m_rgpAttrMap[COMMENT_IDX]->nSizeLimit, 0);
PWSTR rgpwzAttrNames[] = {m_rgpAttrMap[DESCR_IDX]->AttrInfo.pszAttrName, m_rgpAttrMap[SAMNAME_IDX]->AttrInfo.pszAttrName, m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName, m_rgpAttrMap[COMMENT_IDX]->AttrInfo.pszAttrName, g_wzGroupType};
hr = m_pDsObj->GetObjectAttributes(rgpwzAttrNames, 5, &pAttrs, &cAttrs);
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, m_hPage)) { return S_OK; }
for (DWORD i = 0; i < cAttrs; i++) { dspAssert(pAttrs); dspAssert(pAttrs[i].pADsValues); PTSTR ptz;
if (_wcsicmp(pAttrs[i].pszAttrName, m_rgpAttrMap[DESCR_IDX]->AttrInfo.pszAttrName) == 0) { // description.
//
if (!UnicodeToTchar(pAttrs[i].pADsValues->CaseIgnoreString, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); FreeADsMem(pAttrs); return S_OK; }
SetDlgItemText(m_hPage, m_rgpAttrMap[DESCR_IDX]->nCtrlID, ptz);
delete ptz; } if (_wcsicmp(pAttrs[i].pszAttrName, m_rgpAttrMap[SAMNAME_IDX]->AttrInfo.pszAttrName) == 0) { // SAM name.
//
if (!UnicodeToTchar(pAttrs[i].pADsValues->CaseIgnoreString, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); FreeADsMem(pAttrs); return S_OK; }
SetDlgItemText(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, ptz);
delete ptz; } if (_wcsicmp(pAttrs[i].pszAttrName, m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName) == 0) { // email address.
//
if (!UnicodeToTchar(pAttrs[i].pADsValues->CaseIgnoreString, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); FreeADsMem(pAttrs); return S_OK; }
SetDlgItemText(m_hPage, m_rgpAttrMap[EMAIL_IDX]->nCtrlID, ptz);
delete ptz; } if (_wcsicmp(pAttrs[i].pszAttrName, m_rgpAttrMap[COMMENT_IDX]->AttrInfo.pszAttrName) == 0) { // comment.
//
if (!UnicodeToTchar(pAttrs[i].pADsValues->CaseIgnoreString, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); FreeADsMem(pAttrs); return S_OK; }
SetDlgItemText(m_hPage, m_rgpAttrMap[COMMENT_IDX]->nCtrlID, ptz);
delete ptz; } if (_wcsicmp(pAttrs[i].pszAttrName, g_wzGroupType) == 0) { // group type.
//
m_dwType = pAttrs[i].pADsValues->Integer; } }
if (pAttrs) { FreeADsMem(pAttrs); }
//
// Get the domain type and set the buttons accordingly.
//
GetDomainMode(this, &m_fMixed);
BOOL Sec = m_dwType & GROUP_TYPE_SECURITY_ENABLED; CheckDlgButton(m_hPage, (Sec) ? IDC_RADIO_SEC_ENABLED : IDC_RADIO_SEC_DISABLED, BST_CHECKED); if (m_fMixed) { EnableWindow(GetDlgItem(m_hPage, (Sec) ? IDC_RADIO_SEC_DISABLED : IDC_RADIO_SEC_ENABLED), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_UNIVERSAL), FALSE); } UINT id; if (m_dwType & GROUP_TYPE_ACCOUNT_GROUP) { id = IDC_RADIO_ACCOUNT; EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_RESOURCE), FALSE); } else if (m_dwType & GROUP_TYPE_RESOURCE_GROUP) { id = IDC_RADIO_RESOURCE; EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_ACCOUNT), FALSE); if (m_dwType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { TCHAR szLabel[100]; if (!LoadStringReport(IDS_BUILTIN_GROUP, szLabel, 100, m_hPage)) { hr = E_OUTOFMEMORY; return S_OK; } SetWindowText(GetDlgItem(m_hPage, IDC_RADIO_RESOURCE), szLabel); } } else if (m_dwType & GROUP_TYPE_UNIVERSAL_GROUP) { id = IDC_RADIO_UNIVERSAL; EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_ACCOUNT), m_fMixed ? FALSE : TRUE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_RESOURCE), m_fMixed ? FALSE : TRUE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_UNIVERSAL), TRUE); } else { //
// Probably a default but we should never get here anyway
//
id = IDC_RADIO_ACCOUNT; #if DBG == 1
dspAssert(FALSE && "Unknown group type!"); #endif
}
CheckDlgButton(m_hPage, id, BST_CHECKED);
bool fIsSpecialAccount = false;
IsSpecialAccount (fIsSpecialAccount);
if (!m_fTypeWritable || (m_dwType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) || fIsSpecialAccount) { EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_ACCOUNT), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_RESOURCE), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_UNIVERSAL), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_SEC_ENABLED), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_RADIO_SEC_DISABLED), FALSE); } if (!m_fDescrWritable) { SendDlgItemMessage(m_hPage, m_rgpAttrMap[DESCR_IDX]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0); } if (!m_fSamNameWritable) { SendDlgItemMessage(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0); } if (!m_fEmailWritable) { SendDlgItemMessage(m_hPage, m_rgpAttrMap[EMAIL_IDX]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0); } if (!m_fCommentWritable) { SendDlgItemMessage(m_hPage, m_rgpAttrMap[COMMENT_IDX]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0); }
return S_OK; }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::IsSpecialAccount
//
// Synopsis: Returns true if group RID indicates a special account
//
//-----------------------------------------------------------------------------
HRESULT CDsGroupGenObjPage::IsSpecialAccount(bool& fIsSpecialAccount) { //
// Get the group SID. This is a required attribute so bail if not found.
//
PWSTR rgpwzAttrNames[] = {g_wzObjectSID}; PADS_ATTR_INFO pAttrs = NULL; DWORD cAttrs = 0;
CWaitCursor Wait;
HRESULT hr = m_pDsObj->GetObjectAttributes(rgpwzAttrNames, 1, &pAttrs, &cAttrs);
if (!CHECK_ADS_HR(&hr, m_hPage)) { return hr; }
dspAssert(cAttrs); if (cAttrs != 1) { return E_FAIL; } dspAssert(pAttrs);
PUCHAR saCount = GetSidSubAuthorityCount(pAttrs->pADsValues->OctetString.lpValue); DWORD dwGroupRID = *GetSidSubAuthority(pAttrs->pADsValues->OctetString.lpValue, (ULONG)*saCount - 1); dspDebugOut((DEB_ITRACE, "Group RID = %d\n", dwGroupRID));
// This is the highest special account RID or alias in ntseapi.h
if ( dwGroupRID <= DOMAIN_ALIAS_RID_RAS_SERVERS ) fIsSpecialAccount = true;
FreeADsMem(pAttrs);
return hr; }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnApply
//
// Synopsis: Handles the Apply notification.
//
//-----------------------------------------------------------------------------
LRESULT CDsGroupGenObjPage::OnApply(void) { TRACE(CDsGroupGenObjPage,OnApply); HRESULT hr = S_OK; ADSVALUE ADsValueType = {ADSTYPE_INTEGER, 0}; ADS_ATTR_INFO AttrInfoDesc = m_rgpAttrMap[DESCR_IDX]->AttrInfo; ADS_ATTR_INFO AttrInfoSAMn = m_rgpAttrMap[SAMNAME_IDX]->AttrInfo; ADS_ATTR_INFO AttrInfoMail = m_rgpAttrMap[EMAIL_IDX]->AttrInfo; ADS_ATTR_INFO AttrInfoComm = m_rgpAttrMap[COMMENT_IDX]->AttrInfo; ADS_ATTR_INFO AttrInfoType = {g_wzGroupType, ADS_ATTR_UPDATE, ADSTYPE_INTEGER, &ADsValueType, 1};
ADS_ATTR_INFO rgAttrs[5]; DWORD cAttrs = 0;
ADSVALUE ADsValueDesc = {m_rgpAttrMap[DESCR_IDX]->AttrInfo.dwADsType, NULL}; ADSVALUE ADsValueSAMname = {m_rgpAttrMap[SAMNAME_IDX]->AttrInfo.dwADsType, NULL}; ADSVALUE ADsValueComm = {m_rgpAttrMap[COMMENT_IDX]->AttrInfo.dwADsType, NULL}; ADSVALUE ADsValueMail = {m_rgpAttrMap[EMAIL_IDX]->AttrInfo.dwADsType, NULL};
//
// Description.
//
AttrInfoDesc.pADsValues = &ADsValueDesc; AttrInfoDesc.dwNumValues = 1; LPTSTR ptsz;
if (m_fDescrDirty) { dspAssert(m_fDescrWritable);
ptsz = new TCHAR[m_rgpAttrMap[DESCR_IDX]->nSizeLimit + 1]; CHECK_NULL(ptsz, return -1);
if (GetDlgItemText(m_hPage, m_rgpAttrMap[DESCR_IDX]->nCtrlID, ptsz, m_rgpAttrMap[DESCR_IDX]->nSizeLimit + 1) == 0) { // An empty control means remove the attribute value from the
// object.
//
AttrInfoDesc.dwNumValues = 0; AttrInfoDesc.pADsValues = NULL; AttrInfoDesc.dwControlCode = ADS_ATTR_CLEAR; } else { if (!TcharToUnicode(ptsz, &ADsValueDesc.CaseIgnoreString)) { delete[] ptsz; return -1; } } delete[] ptsz; rgAttrs[cAttrs++] = AttrInfoDesc; }
//
// SAM name.
//
AttrInfoSAMn.pADsValues = &ADsValueSAMname; AttrInfoSAMn.dwNumValues = 1;
if (m_fSamNameDirty) { dspAssert(m_fSamNameWritable);
ptsz = new TCHAR[m_rgpAttrMap[SAMNAME_IDX]->nSizeLimit + 1]; if (ptsz == NULL) { DO_DEL(ADsValueDesc.CaseExactString) return -1; }
if (GetDlgItemText(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, ptsz, m_rgpAttrMap[SAMNAME_IDX]->nSizeLimit + 1) == 0) { ErrMsg (IDS_ERR_DNLEVELNAME_MISSING, m_hPage); delete[] ptsz; hr = E_FAIL; goto Cleanup; } else { CStr csSAMName = ptsz;
//
// Now check for illegal characters
//
bool bSAMNameChanged = false; int iFind = csSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS); if (iFind != -1 && !csSAMName.IsEmpty()) { PVOID apv[1] = {(LPWSTR)(LPCWSTR)csSAMName}; if (IDYES == SuperMsgBox(m_hPage, IDS_GROUP_SAMNAME_ILLEGAL, 0, MB_YESNO | MB_ICONWARNING, S_OK, apv, 1, FALSE, __FILE__, __LINE__)) { while (iFind != -1) { csSAMName.SetAt(iFind, L'_'); iFind = csSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS); bSAMNameChanged = true; } } else { //
// Set the focus to the edit box and select the text
//
SetFocus(GetDlgItem(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID)); SendDlgItemMessage(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, EM_SETSEL, 0, -1);
delete[] ptsz; hr = E_FAIL; goto Cleanup; } }
if (bSAMNameChanged) { //
// Write the change back to the control
//
SetDlgItemText(m_hPage, m_rgpAttrMap[SAMNAME_IDX]->nCtrlID, const_cast<PWSTR>((LPCWSTR)csSAMName)); }
if (!AllocWStr((PWSTR)(PCWSTR)csSAMName, &ADsValueSAMname.CaseIgnoreString)) { delete[] ptsz; DO_DEL(ADsValueDesc.CaseExactString) return -1; }
} delete[] ptsz; rgAttrs[cAttrs++] = AttrInfoSAMn; }
//
// Email Address.
//
AttrInfoMail.pADsValues = &ADsValueMail; AttrInfoMail.dwNumValues = 1;
if (m_fEmailWritable) { if (!m_fEmailDirty) { SendMessage(GetParent(GetHWnd()), PSM_QUERYSIBLINGS, (WPARAM)m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName, (LPARAM)GetHWnd()); }
// SendMessage is syncronous. If the sibling page has an updated email
// attribute value, it will get written to this page's edit control
// and the dirty state member will be set. So, check it now rather than
// use a 'else' clause after the above 'if' clause.
//
if (m_fEmailDirty) { ptsz = new TCHAR[m_rgpAttrMap[EMAIL_IDX]->nSizeLimit + 1]; if (ptsz == NULL) { DO_DEL(ADsValueDesc.CaseExactString) DO_DEL(ADsValueSAMname.CaseIgnoreString); return -1; }
if (GetDlgItemText(m_hPage, m_rgpAttrMap[EMAIL_IDX]->nCtrlID, ptsz, m_rgpAttrMap[EMAIL_IDX]->nSizeLimit + 1) == 0) { AttrInfoMail.dwNumValues = 0; AttrInfoMail.pADsValues = NULL; AttrInfoMail.dwControlCode = ADS_ATTR_CLEAR; } else { if (!TcharToUnicode(ptsz, &ADsValueMail.CaseIgnoreString)) { delete[] ptsz; hr = E_OUTOFMEMORY; goto Cleanup; } if (!FValidSMTPAddress(ADsValueMail.CaseIgnoreString)) { ErrMsg(IDS_INVALID_MAIL_ADDR, GetHWnd()); delete [] ptsz; hr = E_FAIL; goto Cleanup; } } delete[] ptsz; rgAttrs[cAttrs++] = AttrInfoMail; } }
//
// Comment.
//
AttrInfoComm.pADsValues = &ADsValueComm; AttrInfoComm.dwNumValues = 1;
if (m_fCommentDirty) { dspAssert(m_fCommentWritable);
ptsz = new TCHAR[m_rgpAttrMap[COMMENT_IDX]->nSizeLimit + 1]; if (ptsz == NULL) { DO_DEL(ADsValueDesc.CaseExactString) DO_DEL(ADsValueSAMname.CaseIgnoreString); DO_DEL(ADsValueMail.CaseExactString) return -1; }
if (GetDlgItemText(m_hPage, m_rgpAttrMap[COMMENT_IDX]->nCtrlID, ptsz, m_rgpAttrMap[COMMENT_IDX]->nSizeLimit + 1) == 0) { AttrInfoComm.dwNumValues = 0; AttrInfoComm.pADsValues = NULL; AttrInfoComm.dwControlCode = ADS_ATTR_CLEAR; } else { if (!TcharToUnicode(ptsz, &ADsValueComm.CaseIgnoreString)) { delete[] ptsz; DO_DEL(ADsValueDesc.CaseExactString) DO_DEL(ADsValueSAMname.CaseIgnoreString); DO_DEL(ADsValueMail.CaseExactString) return -1; } } delete[] ptsz; rgAttrs[cAttrs++] = AttrInfoComm; }
//
// set the group type flags
//
if (m_fTypeDirty) { dspAssert(m_fTypeWritable);
BOOL Account = (IsDlgButtonChecked (m_hPage,IDC_RADIO_ACCOUNT) == BST_CHECKED); BOOL Resource = (IsDlgButtonChecked (m_hPage,IDC_RADIO_RESOURCE) == BST_CHECKED); BOOL Security = (IsDlgButtonChecked (m_hPage, IDC_RADIO_SEC_ENABLED) == BST_CHECKED); if (Security) { ADsValueType.Integer = GROUP_TYPE_SECURITY_ENABLED; } else { if (m_dwType & GROUP_TYPE_SECURITY_ENABLED) { TCHAR szTitle[80], szMessage[512]; if (!LoadStringReport(IDS_MSG_TITLE, szTitle, 80, m_hPage)) { hr = E_OUTOFMEMORY; goto Cleanup; } if (!LoadStringReport(IDS_MSG_DISABLING_SECURITY, szMessage, 512, m_hPage)) { hr = E_OUTOFMEMORY; goto Cleanup; } LONG iRet = MessageBox(m_hPage, szMessage, szTitle, MB_YESNO | MB_ICONWARNING); if (iRet == IDNO) { //
// The user declined, so go back to prop sheet.
//
hr = S_FALSE; goto Cleanup; } } ADsValueType.Integer = 0; }
if (Resource) { ADsValueType.Integer |= GROUP_TYPE_RESOURCE_GROUP; } else { if (Account) { ADsValueType.Integer |= GROUP_TYPE_ACCOUNT_GROUP; } else { ADsValueType.Integer |= GROUP_TYPE_UNIVERSAL_GROUP; } } rgAttrs[cAttrs++] = AttrInfoType; }
//
// Write the description, and group type.
//
DWORD cModified;
hr = m_pDsObj->SetObjectAttributes(rgAttrs, cAttrs, &cModified);
if (!CHECK_ADS_HR(&hr, m_hPage)) { goto Cleanup; }
m_fTypeDirty = m_fDescrDirty = m_fSamNameDirty = m_fEmailDirty = m_fCommentDirty = FALSE;
Cleanup: DO_DEL(ADsValueDesc.CaseExactString) DO_DEL(ADsValueSAMname.CaseIgnoreString); DO_DEL(ADsValueMail.CaseExactString) DO_DEL(ADsValueComm.CaseExactString) if (hr == S_FALSE) return PSNRET_INVALID_NOCHANGEPAGE; else return (SUCCEEDED(hr)) ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnCommand
//
// Synopsis: Handle control notifications.
//
//-----------------------------------------------------------------------------
LRESULT CDsGroupGenObjPage::OnCommand(int id, HWND hwndCtl, UINT codeNotify) { if (m_fInInit) { return 0; } switch (codeNotify) { case BN_CLICKED: if ((id == IDC_RADIO_UNIVERSAL) || (id == IDC_RADIO_RESOURCE) || (id == IDC_RADIO_ACCOUNT)) { int iCheck1, iCheck2; switch (id) { case IDC_RADIO_UNIVERSAL: iCheck1 = IDC_RADIO_RESOURCE; iCheck2 = IDC_RADIO_ACCOUNT; break; case IDC_RADIO_RESOURCE: iCheck1 = IDC_RADIO_UNIVERSAL; iCheck2 = IDC_RADIO_ACCOUNT; break; case IDC_RADIO_ACCOUNT: iCheck1 = IDC_RADIO_UNIVERSAL; iCheck2 = IDC_RADIO_RESOURCE; break; default: dspAssert(FALSE); iCheck1 = IDC_RADIO_RESOURCE; iCheck2 = IDC_RADIO_ACCOUNT; break; } CheckDlgButton(m_hPage, iCheck1, BST_UNCHECKED); CheckDlgButton(m_hPage, iCheck2, BST_UNCHECKED); m_fTypeDirty = TRUE; SetDirty(); } if ((id == IDC_RADIO_SEC_ENABLED) || (id == IDC_RADIO_SEC_DISABLED)) { CheckDlgButton(m_hPage, (id == IDC_RADIO_SEC_ENABLED) ? IDC_RADIO_SEC_DISABLED : IDC_RADIO_SEC_ENABLED, BST_UNCHECKED); m_fTypeDirty = TRUE; SetDirty(); } break;
case EN_CHANGE: switch (id) { case IDC_EMAIL_EDIT: m_fEmailDirty = TRUE; break;
case IDC_DESCRIPTION_EDIT: m_fDescrDirty = TRUE; break;
case IDC_SAM_NAME_EDIT: m_fSamNameDirty = TRUE; break;
case IDC_EDIT_COMMENT: m_fCommentDirty = TRUE; break; } break; } return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify); }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnNotify
//
// Synopsis: Handles list notification messages
//
//-----------------------------------------------------------------------------
LRESULT CDsGroupGenObjPage::OnNotify(WPARAM wParam, LPARAM lParam) { if (m_fInInit) { return 0; } if (((LPNMHDR)lParam)->code == PSN_SETACTIVE) { dspDebugOut((DEB_ITRACE, "(HWND: %08x) got PSN_SETACTIVE, sending PSM_QUERYSIBLINGS.\n", GetHWnd())); SendMessage(GetParent(GetHWnd()), PSM_QUERYSIBLINGS, (WPARAM)m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName, (LPARAM)GetHWnd()); }
return CDsPropPageBase::OnNotify(wParam, lParam); }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnQuerySiblings
//
// Synopsis: Inter-page communications for shared attributes.
//
// lParam == the HWND of the sending window.
// wParam == the name of the attribute whose status is sought.
//
//-----------------------------------------------------------------------------
void CDsGroupGenObjPage::OnQuerySiblings(WPARAM wParam, LPARAM lParam) { PWSTR pwz = NULL; int cch;
#if DBG == 1
char szBuf[100]; strcpy(szBuf, "(HWND: %08x) got PSM_QUERYSIBLINGS for '%ws'"); #endif
if ((HWND)lParam != GetHWnd()) { if (m_fEmailDirty && wParam && _wcsicmp((PWSTR)wParam, m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName) == 0) { #if DBG == 1
strcat(szBuf, " sending DSPROP_ATTRCHANGED_MSG"); #endif
ADS_ATTR_INFO Attr; ADSVALUE ADsValue;
cch = (int)SendDlgItemMessage(GetHWnd(), m_rgpAttrMap[EMAIL_IDX]->nCtrlID, WM_GETTEXTLENGTH, 0, 0); pwz = new WCHAR[++cch]; CHECK_NULL_REPORT(pwz, GetHWnd(), return);
Attr.dwNumValues = 1; Attr.pszAttrName = m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName; Attr.pADsValues = &ADsValue; Attr.pADsValues->dwType = m_rgpAttrMap[EMAIL_IDX]->AttrInfo.dwADsType; Attr.pADsValues->CaseIgnoreString = pwz;
GetDlgItemText(GetHWnd(), m_rgpAttrMap[EMAIL_IDX]->nCtrlID, Attr.pADsValues->CaseIgnoreString, cch);
SendMessage((HWND)lParam, g_uChangeMsg, (WPARAM)&Attr, 0);
delete pwz; } } #if DBG == 1
else { strcat(szBuf, " (it was sent by this page!)"); } strcat(szBuf, "\n"); dspDebugOut((DEB_ITRACE, szBuf, GetHWnd(), wParam)); #endif
}
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnAttrChanged
//
// Synopsis: Inter-page communications for shared attributes.
//
// wParam == the PADS_ATTR_INFO struct for the changed attribute.
//
//-----------------------------------------------------------------------------
void CDsGroupGenObjPage::OnAttrChanged(WPARAM wParam) { PADS_ATTR_INFO pAttrInfo = (PADS_ATTR_INFO)wParam;
dspAssert(pAttrInfo && pAttrInfo->pszAttrName && pAttrInfo->pADsValues && pAttrInfo->pADsValues->CaseIgnoreString); dspDebugOut((DEB_ITRACE, "(HWND: %08x) got DSPROP_ATTRCHANGED_MSG for '%ws'.\n", GetHWnd(), pAttrInfo->pszAttrName)); if (_wcsicmp(pAttrInfo->pszAttrName, m_rgpAttrMap[EMAIL_IDX]->AttrInfo.pszAttrName) == 0) { SetDlgItemText(GetHWnd(), m_rgpAttrMap[EMAIL_IDX]->nCtrlID, pAttrInfo->pADsValues->CaseIgnoreString); } }
//+----------------------------------------------------------------------------
//
// Method: CDsGroupGenObjPage::OnDestroy
//
// Synopsis: Exit cleanup
//
//-----------------------------------------------------------------------------
LRESULT CDsGroupGenObjPage::OnDestroy(void) { ATTR_DATA ad = {0, (LPARAM)m_pCIcon};
GeneralPageIcon(this, &GenIcon, NULL, 0, &ad, fOnDestroy);
CDsPropPageBase::OnDestroy(); // If an application processes this message, it should return zero.
return 0; }
#endif // DSADMIN
//+----------------------------------------------------------------------------
//
// Member: CDsGrpMembersPage::CDsGrpMembersPage
//
//-----------------------------------------------------------------------------
CDsGrpMembersPage::CDsGrpMembersPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, HWND hNotifyObj, DWORD dwFlags) : m_pList(NULL), m_fMixed(TRUE), m_dwType(0), m_fMemberWritable(FALSE), m_dwGroupRID(0), m_fShowIcons(FALSE), m_pszSecurityGroupExtraClasses(NULL), m_dwSecurityGroupExtraClassesCount(0), m_pszNonSecurityGroupExtraClasses(NULL), m_dwNonSecurityGroupExtraClassesCount(0), m_hwndObjPicker(NULL), m_pInitInfo(NULL), CDsPropPageBase(pDsPage, pDataObj, hNotifyObj, dwFlags) { TRACE(CDsGrpMembersPage,CDsGrpMembersPage); #ifdef _DEBUG
strcpy(szClass, "CDsGrpMembersPage"); #endif
}
//+----------------------------------------------------------------------------
//
// Member: CDsGrpMembersPage::~CDsGrpMembersPage
//
//-----------------------------------------------------------------------------
CDsGrpMembersPage::~CDsGrpMembersPage() { TRACE(CDsGrpMembersPage,~CDsGrpMembersPage); DO_DEL(m_pList);
if (m_pszSecurityGroupExtraClasses != NULL) { for (DWORD idx = 0; idx < m_dwSecurityGroupExtraClassesCount; idx++) { if (m_pszSecurityGroupExtraClasses[idx] != NULL) { delete[] m_pszSecurityGroupExtraClasses[idx]; m_pszSecurityGroupExtraClasses[idx] = NULL; } } delete[] m_pszSecurityGroupExtraClasses; } if (m_pszNonSecurityGroupExtraClasses != NULL) { for (DWORD idx = 0; idx < m_dwNonSecurityGroupExtraClassesCount; idx++) { if (m_pszNonSecurityGroupExtraClasses[idx] != NULL) { delete[] m_pszNonSecurityGroupExtraClasses[idx]; m_pszNonSecurityGroupExtraClasses[idx] = NULL; } } delete[] m_pszNonSecurityGroupExtraClasses; } }
//+----------------------------------------------------------------------------
//
// Member: CDsGrpMembersPage::IUnknown::QueryInterface
//
// Synopsis: Returns requested interface pointer
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDsGrpMembersPage::QueryInterface(REFIID riid, void ** ppvObject) { TRACE2(CDsGrpMembersPage,QueryInterface); if (IID_ICustomizeDsBrowser == riid) { *ppvObject = (ICustomizeDsBrowser*)this; } else { return CDsPropPageBase::QueryInterface(riid, ppvObject); } AddRef(); return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: CDsGrpMembersPage::IUnknown::AddRef
//
// Synopsis: increments reference count
//
// Returns: the reference count
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDsGrpMembersPage::AddRef(void) { dspDebugOut((DEB_USER2, "CDsGrpMembersPage::AddRef refcount going in %d\n", m_uRefs)); return CDsPropPageBase::AddRef(); }
//+----------------------------------------------------------------------------
//
// Member: CDsGrpMembersPage::IUnknown::Release
//
// Synopsis: Decrements the object's reference count and frees it when
// no longer referenced.
//
// Returns: zero if the reference count is zero or non-zero otherwise
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CDsGrpMembersPage::Release(void) { dspDebugOut((DEB_USER2, "CDsGrpMembersPage::Release ref count going in %d\n", m_uRefs)); return CDsPropPageBase::Release(); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::Initialize
//
// Synopsis: Initializes the ICustomizeDsBrowser interface
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::Initialize(HWND hwnd, PCDSOP_INIT_INFO pInitInfo, IBindHelper *pBindHelper) { HRESULT hr = S_OK;
dspAssert(IsWindow(hwnd)); dspAssert(pBindHelper);
m_hwndObjPicker = hwnd; m_pInitInfo = pInitInfo; m_pBinder = pBindHelper;
return hr; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::BuildQueryString
//
// Synopsis: Used to build the query string from the securityGroupExtraClasses
// and nonSecurityGroupExtraClasses in the DisplaySpecifiers
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::BuildQueryString(PWSTR* ppszFilterString) { CStrW szFilterString = L"(|";
BOOL bSecurityGroup = (m_dwType & GROUP_TYPE_SECURITY_ENABLED) ? TRUE : FALSE; if (bSecurityGroup) { if (m_dwSecurityGroupExtraClassesCount == 0) { return S_FALSE; }
for (DWORD idx = 0; idx < m_dwSecurityGroupExtraClassesCount; idx++) { if (m_pszSecurityGroupExtraClasses[idx] != NULL) { szFilterString += L"(objectClass="; szFilterString += m_pszSecurityGroupExtraClasses[idx]; szFilterString += L")"; } } } else { if (m_dwNonSecurityGroupExtraClassesCount == 0) { return S_FALSE; }
for (DWORD idx = 0; idx < m_dwNonSecurityGroupExtraClassesCount; idx++) { if (m_pszNonSecurityGroupExtraClasses[idx] != NULL) { szFilterString += L"(objectClass="; szFilterString += m_pszNonSecurityGroupExtraClasses[idx]; szFilterString += L")"; } } }
szFilterString += L")";
*ppszFilterString = new WCHAR[szFilterString.GetLength() + 1]; CHECK_NULL_REPORT(*ppszFilterString, GetHWnd(), return E_OUTOFMEMORY);
wcscpy(*ppszFilterString, szFilterString); return S_OK; }
//+----------------------------------------------------------------------------
//
// Method: CDsSelectionListWrapper::CreateSelectionList
//
// Synopsis: Used to convert a CDsSelectionListWrapper to a PDS_SELECTION_LIST
//
//-----------------------------------------------------------------------------
PDS_SELECTION_LIST CDsSelectionListWrapper::CreateSelectionList(CDsSelectionListWrapper* pHead) { if (pHead == NULL) { return NULL; }
PDS_SELECTION_LIST pSelectionList = NULL;
UINT nCount = CDsSelectionListWrapper::GetCount(pHead); if (nCount > 0) { pSelectionList = (PDS_SELECTION_LIST)malloc(sizeof(DS_SELECTION_LIST) + (sizeof(DS_SELECTION) * (nCount - 1))); if (pSelectionList != NULL) { memset(pSelectionList, 0, sizeof(DS_SELECTION_LIST) + (sizeof(DS_SELECTION) * (nCount - 1)));
pSelectionList->cItems = nCount; pSelectionList->cFetchedAttributes = 0;
//
// Now fill in the selection list by walking the wrapper list
//
UINT idx = 0; CDsSelectionListWrapper* pCurrentItem = pHead; while (pCurrentItem != NULL) { memcpy(&(pSelectionList->aDsSelection[idx]), pCurrentItem->m_pSelection, sizeof(DS_SELECTION)); pCurrentItem = pCurrentItem->m_pNext; idx++; } } } return pSelectionList; }
//+----------------------------------------------------------------------------
//
// Method: CDsSelectionListWrapper::CreateSelectionList
//
// Synopsis: Counts the number of items in the CDsSelectionListWrapper
//
//-----------------------------------------------------------------------------
UINT CDsSelectionListWrapper::GetCount(CDsSelectionListWrapper* pHead) { CDsSelectionListWrapper* pCurrentItem = pHead; UINT nCount = 0; while (pCurrentItem != NULL) { nCount++; pCurrentItem = pCurrentItem->m_pNext; } return nCount; }
//+----------------------------------------------------------------------------
//
// Method: CDsSelectionListWrapper::DetachItemsAndDeleteList
//
// Synopsis: Counts the number of items in the CDsSelectionListWrapper
//
//-----------------------------------------------------------------------------
void CDsSelectionListWrapper::DetachItemsAndDeleteList(CDsSelectionListWrapper* pHead) { CDsSelectionListWrapper* pNextItem = pHead; CDsSelectionListWrapper* pDeleteItem = NULL;
while (pNextItem != NULL) { pDeleteItem = pNextItem; pNextItem = pNextItem->m_pNext; delete pDeleteItem->m_pSelection; delete pDeleteItem; } }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::CollectDsObjects
//
// Synopsis: Used by AddObjects and PrefixSearch to retrieve the dataobject
// of the additional objects
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::CollectDsObjects(PWSTR pszFilter, IDsObjectPickerScope *pDsScope, CDsPropDataObj *pdo) { HRESULT hr = S_OK;
dspAssert(pdo != NULL); if (pdo == NULL) { return E_POINTER; }
//
// Prepare the search object
//
PWSTR pszScopePath = NULL; hr = pDsScope->GetADsPath(&pszScopePath); CHECK_HRESULT(hr, return hr;);
CDSSearch searchObj; hr = searchObj.Init(pszScopePath); CHECK_HRESULT(hr, return hr;);
PWSTR pszAttributes[] = { g_wzADsPath }; hr = searchObj.SetAttributeList(pszAttributes, 1); CHECK_HRESULT(hr, return hr);
dspAssert(pszFilter != NULL); if (pszFilter == NULL) { return E_INVALIDARG; }
hr = searchObj.SetFilterString(pszFilter); CHECK_HRESULT(hr, return hr);
hr = searchObj.SetSearchScope(ADS_SCOPE_SUBTREE); CHECK_HRESULT(hr, return hr);
//
// Prepare the linked list for temporary storage of DS_SELECTION items
//
CDsSelectionListWrapper* pListHead = NULL; CDsSelectionListWrapper* pCurrentListItem = NULL;
//
// Get the path cracker
//
CComPtr<IADsPathname> spPathCracker; hr = GetADsPathname(spPathCracker); CHECK_HRESULT(hr, return hr);
//
// Execute the query
//
hr = searchObj.DoQuery(); while (SUCCEEDED(hr)) { hr = searchObj.GetNextRow(); if (S_ADS_NOMORE_ROWS == hr) { hr = S_OK; break; }
if (SUCCEEDED(hr)) { ADS_SEARCH_COLUMN PathColumn, ClassColumn; ::ZeroMemory( &PathColumn, sizeof(PathColumn) ); ::ZeroMemory(&ClassColumn, sizeof(ClassColumn));
//
// Get the ADsPath
//
hr = searchObj.GetColumn(pszAttributes[0], &PathColumn); CHECK_HRESULT(hr, continue); dspAssert(PathColumn.pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING);
//
// Get the objectClass
//
CComPtr<IDirectoryObject> spDirObject; hr = ADsOpenObject(PathColumn.pADsValues->CaseIgnoreString, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (PVOID*)&spDirObject); CHECK_HRESULT(hr, continue); //
// Get the object info
//
ADS_OBJECT_INFO* pADsObjectInfo = NULL; hr = spDirObject->GetObjectInformation(&pADsObjectInfo); CHECK_HRESULT(hr, continue); dspAssert(pADsObjectInfo != NULL);
PDS_SELECTION pSelection = new DS_SELECTION; CHECK_NULL(pSelection, return E_OUTOFMEMORY);
::ZeroMemory(pSelection, sizeof(DS_SELECTION));
if (!AllocWStr(PathColumn.pADsValues->CaseIgnoreString, &(pSelection->pwzADsPath))) { CHECK_HRESULT(E_OUTOFMEMORY, return E_OUTOFMEMORY); }
//
// Assume that the class we are interested in is the first in the multivalued attribute
//
if (!AllocWStr(pADsObjectInfo->pszClassName, &(pSelection->pwzClass))) { CHECK_HRESULT(E_OUTOFMEMORY, return E_OUTOFMEMORY); }
hr = spPathCracker->Set(PathColumn.pADsValues->CaseIgnoreString, ADS_SETTYPE_FULL); CHECK_HRESULT(hr, continue);
hr = spPathCracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY); CHECK_HRESULT(hr, continue);
// CODEWORK 122531 Should we be turning off escaped mode here?
CComBSTR bstrName; hr = spPathCracker->Retrieve(ADS_FORMAT_LEAF, &bstrName); CHECK_HRESULT(hr, continue);
//
// Return the display to full
//
hr = spPathCracker->SetDisplayType(ADS_DISPLAY_FULL); dspAssert(SUCCEEDED(hr));
if (!AllocWStr(bstrName, &(pSelection->pwzName))) { CHECK_HRESULT(E_OUTOFMEMORY, return E_OUTOFMEMORY); }
CDsSelectionListWrapper* pNewItem = new CDsSelectionListWrapper; CHECK_NULL(pNewItem, return E_OUTOFMEMORY);
pNewItem->m_pSelection = pSelection;
//
// Add selection item to list
//
if (pListHead == NULL) { pListHead = pNewItem; pCurrentListItem = pNewItem; } else { pCurrentListItem->m_pNext = pNewItem; pCurrentListItem = pNewItem; }
searchObj.FreeColumn(&PathColumn); searchObj.FreeColumn(&ClassColumn); } }
if (pListHead != NULL) { PDS_SELECTION_LIST pSelectionList = CDsSelectionListWrapper::CreateSelectionList(pListHead); if (pSelectionList != NULL) { hr = pdo->Init(pSelectionList); CHECK_HRESULT(hr, return hr); } CDsSelectionListWrapper::DetachItemsAndDeleteList(pListHead); } else { hr = S_FALSE; } return hr; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::AddObjects
//
// Synopsis: Called by the Object Picker UI to add additional objects to the UI
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::AddObjects(IDsObjectPickerScope *pDsScope, IDataObject **ppdo) { HRESULT hr = S_OK;
//
// Prepare the data object
//
CDsPropDataObj* pDataObj = new CDsPropDataObj(GetHWnd(), m_fReadOnly); CHECK_NULL(pDataObj, return E_OUTOFMEMORY);
*ppdo = pDataObj;
PWSTR pszFilter = NULL; hr = BuildQueryString(&pszFilter); if (FAILED(hr) || !pszFilter || hr == S_FALSE) { delete pDataObj; pDataObj = NULL; *ppdo = NULL; hr = S_FALSE; } else { hr = CollectDsObjects(pszFilter, pDsScope, pDataObj); }
if (pszFilter != NULL) { delete[] pszFilter; pszFilter = NULL; }
return hr; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::GetQueryInfoByScope
//
// Synopsis: Called by the Object Picker UI
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::GetQueryInfoByScope(IDsObjectPickerScope*, PDSQUERYINFO *ppdsqi) { return E_NOTIMPL; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::PrefixSearch
//
// Synopsis: Called by the Object Picker UI to get additional objects starting
// with a specific string
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::PrefixSearch(IDsObjectPickerScope *pDsScope, PCWSTR pwzSearchFor, IDataObject **ppdo) { HRESULT hr = S_OK;
//
// Prepare the data object
//
CDsPropDataObj* pDataObj = new CDsPropDataObj(GetHWnd(), m_fReadOnly); CHECK_NULL(pDataObj, return E_OUTOFMEMORY);
*ppdo = pDataObj;
CStrW szFilter; PWSTR pszFilter = NULL; hr = BuildQueryString(&pszFilter); if (FAILED(hr) || hr == S_FALSE || pszFilter == NULL) { delete pDataObj; pDataObj = NULL; *ppdo = NULL;
if (pszFilter) { delete[] pszFilter; pszFilter = NULL; }
hr = S_FALSE; } else { szFilter = pszFilter; CStrW szPrefix; szPrefix = L"(&(name="; szPrefix += pwzSearchFor; szPrefix += L"*)";
szFilter = szPrefix + szFilter + L")"; hr = CollectDsObjects(szFilter.GetBuffer(szFilter.GetLength() + 1), pDsScope, pDataObj); }
return hr; }
//+----------------------------------------------------------------------------
//
// Function: CreateGroupMembersPage
//
// Synopsis: Creates an instance of the group membership page window.
//
//-----------------------------------------------------------------------------
HRESULT CreateGroupMembersPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, PWSTR pwzADsPath, PWSTR pwzClass, HWND hNotifyObj, DWORD dwFlags, CDSBasePathsInfo* pBasePathsInfo, HPROPSHEETPAGE * phPage) { TRACE_FUNCTION(CreateGroupMembersPage);
CDsGrpMembersPage * pPageObj = new CDsGrpMembersPage(pDsPage, pDataObj, hNotifyObj, dwFlags); CHECK_NULL(pPageObj, return E_OUTOFMEMORY);
pPageObj->Init(pwzADsPath, pwzClass, pBasePathsInfo);
return pPageObj->CreatePage(phPage); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::DlgProc
//
// Synopsis: per-instance dialog proc
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpMembersPage::DlgProc(HWND, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: return InitDlg(lParam);
case WM_NOTIFY: return OnNotify(wParam, lParam);
case WM_SHOWWINDOW: return OnShowWindow();
case WM_SETFOCUS: return OnSetFocus((HWND)wParam);
case WM_HELP: return OnHelp((LPHELPINFO)lParam);
case WM_COMMAND: if (m_fInInit) { return TRUE; } return(OnCommand(GET_WM_COMMAND_ID(wParam, lParam), GET_WM_COMMAND_HWND(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam))); case WM_DESTROY: return OnDestroy();
default: return(FALSE); }
return(TRUE); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::OnInitDialog
//
// Synopsis: Set the initial control values from the corresponding DS
// attributes.
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::OnInitDialog(LPARAM lParam) { return OnInitDialog(lParam, TRUE); }
HRESULT CDsGrpMembersPage::OnInitDialog(LPARAM, BOOL fShowIcons) { TRACE(CDsGrpMembersPage,OnInitDialog); HRESULT hr; PADS_ATTR_INFO pAttrs = NULL; DWORD cAttrs = 0;
m_fShowIcons = (0 != g_ulMemberFilterCount) ? fShowIcons : FALSE;
CWaitCursor Wait;
if (!ADsPropSetHwnd(m_hNotifyObj, m_hPage)) { m_pWritableAttrs = NULL; }
PTSTR ptzRDN; if (!UnicodeToTchar(m_pwszRDName, &ptzRDN)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); return S_OK; }
SetDlgItemText(m_hPage, IDC_CN, ptzRDN); delete ptzRDN;
GetDomainMode(this, &m_fMixed);
//
// Get the group RID.
//
PWSTR rgpwzAttrNames[] = {L"primaryGroupToken"};
hr = m_pDsObj->GetObjectAttributes(rgpwzAttrNames, 1, &pAttrs, &cAttrs);
if (!CHECK_ADS_HR(&hr, m_hPage)) { return S_OK; }
dspAssert(cAttrs);
if (cAttrs == 1) { dspAssert(pAttrs);
m_dwGroupRID = pAttrs->pADsValues->Integer;
FreeADsMem(pAttrs); }
GetGroupType(this, &m_dwType); dspDebugOut((DEB_ITRACE, "Group Type = 0x%x\n", m_dwType));
//
// Get the membership list and fill the listview control.
//
m_pList = new CDsMembershipList(m_hPage, IDC_MEMBER_LIST);
CHECK_NULL_REPORT(m_pList, m_hPage, return S_OK);
hr = m_pList->Init(m_fShowIcons);
CHECK_HRESULT(hr, return S_OK);
hr = FillGroupList();
CHECK_HRESULT(hr, return S_OK);
m_fMemberWritable = CheckIfWritable(g_wzMemberAttr);
if (!m_fMemberWritable) { EnableWindow(GetDlgItem(m_hPage, IDC_ADD_BTN), FALSE); EnableWindow(GetDlgItem(m_hPage, IDC_REMOVE_BTN), FALSE); }
//Set the focus on first item in the list
ListView_SetItemState(GetDlgItem(m_hPage, IDC_MEMBER_LIST), 0, LVIS_SELECTED, LVIS_SELECTED);
BOOL bSecurityGroup = (m_dwType & GROUP_TYPE_SECURITY_ENABLED) ? TRUE : FALSE; hr = LoadGroupExtraClasses(bSecurityGroup);
return S_OK; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::OnApply
//
// Synopsis: Handles the Apply notification.
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpMembersPage::OnApply(void) { TRACE(CDsGrpMembersPage,OnApply); HRESULT hr = S_OK; ADS_ATTR_INFO AttrInfo; PADS_ATTR_INFO pAttrs = &AttrInfo;
AttrInfo.pszAttrName = g_wzMemberAttr; AttrInfo.dwADsType = ADSTYPE_DN_STRING;
//
// Read the list of members and do additions.
//
DWORD cModified; int i, cMembers = m_pList->GetCount();
if (cMembers > 0) { AttrInfo.dwControlCode = ADS_ATTR_APPEND; PADSVALUE rgADsValues;
rgADsValues = new ADSVALUE[cMembers];
CHECK_NULL(rgADsValues, return PSNRET_INVALID_NOCHANGEPAGE);
memset(rgADsValues, 0, cMembers * sizeof(ADSVALUE));
pAttrs->pADsValues = rgADsValues; pAttrs->dwNumValues = 0;
CMemberListItem * pItem;
for (i = 0; i < cMembers; i++) { if (FAILED(m_pList->GetItem(i, &pItem))) { dspAssert(FALSE && "List Error"); return PSNRET_INVALID_NOCHANGEPAGE; } if (!pItem) { dspAssert(pItem); return PSNRET_INVALID_NOCHANGEPAGE; }
if (pItem->m_fIsAlreadyMember) { continue; }
dspAssert(pItem->m_pwzDN);
rgADsValues[pAttrs->dwNumValues].DNString = pItem->m_pwzDN; rgADsValues[pAttrs->dwNumValues].dwType = ADSTYPE_DN_STRING;
pItem->m_fIsAlreadyMember = TRUE; pAttrs->dwNumValues++; }
if (pAttrs->dwNumValues) { hr = m_pDsObj->SetObjectAttributes(pAttrs, 1, &cModified);
if (!CheckGroupUpdate(hr, m_hPage)) { delete rgADsValues; return PSNRET_INVALID_NOCHANGEPAGE; } } delete rgADsValues; }
//
// Do removals.
//
DWORD cDelItems = m_DelList.GetItemCount();
if (cDelItems) { AttrInfo.dwControlCode = ADS_ATTR_DELETE; PADSVALUE rgADsValues;
rgADsValues = new ADSVALUE[cDelItems];
CHECK_NULL(rgADsValues, return PSNRET_INVALID_NOCHANGEPAGE);
memset(rgADsValues, 0, cDelItems * sizeof(ADSVALUE));
pAttrs->pADsValues = rgADsValues; pAttrs->dwNumValues = 0;
CMemberListItem * pDelItem = m_DelList.RemoveFirstItem();
while (pDelItem) { if (pDelItem->m_fIsExternal) { hr = GetRealDN(pDelItem);
CHECK_HRESULT_REPORT(hr, m_hPage, continue); }
dspAssert(pDelItem->m_pwzDN);
rgADsValues[pAttrs->dwNumValues].DNString = pDelItem->m_pwzDN; rgADsValues[pAttrs->dwNumValues].dwType = ADSTYPE_DN_STRING;
pAttrs->dwNumValues++;
pDelItem = m_DelList.RemoveFirstItem(); }
if (pAttrs->dwNumValues) { hr = m_pDsObj->SetObjectAttributes(pAttrs, 1, &cModified);
if (!CheckGroupUpdate(hr, m_hPage, FALSE)) { delete rgADsValues; return PSNRET_INVALID_NOCHANGEPAGE; } } delete rgADsValues; }
return (SUCCEEDED(hr)) ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::OnCommand
//
// Synopsis: Handle control notifications.
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpMembersPage::OnCommand(int id, HWND hwndCtl, UINT codeNotify) { if (m_fInInit) { return 0; } switch (codeNotify) { case BN_CLICKED: TRACE(CDsGrpMembersPage,OnCommand); if (id == IDC_ADD_BTN) { InvokeUserQuery(); } if (id == IDC_REMOVE_BTN) { RemoveMember(); } break; } return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::OnNotify
//
// Synopsis: Handles list notification messages
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpMembersPage::OnNotify(WPARAM wParam, LPARAM lParam) { if (m_fInInit) { return 0; } switch (((LPNMHDR)lParam)->code) { case LVN_ITEMCHANGED: if (m_fMemberWritable) { EnableWindow(GetDlgItem(m_hPage, IDC_REMOVE_BTN), TRUE); } break;
case NM_DBLCLK: //
// Display properties for the selected item. First, find out
// which item is selected.
//
CMemberListItem * pItem;
if (!m_pList->GetCurListItem(NULL, NULL, &pItem)) { break; }
dspAssert(pItem);
if (pItem->m_fIsExternal) { HRESULT hr = GetRealDN(pItem);
if (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND)) { MsgBox(IDS_CANT_VIEW_EXTERNAL, m_hPage); break; } CHECK_HRESULT_REPORT(hr, m_hPage, break); }
if (pItem->m_ulScopeType & DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN) { //
// We cannot show the properties for downlevel users
//
// Put a useful message up
PTSTR ptzTitle, ptzMsg; if (!LoadStringToTchar(IDS_MSG_NO_DOWNLEVEL_PROPERTIES, &ptzMsg)) { break; } if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle)) { break; } MessageBox(m_hPage, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION); delete[] ptzTitle; delete[] ptzMsg;
break; } PostPropSheet(pItem->m_pwzDN, this); break; }
return CDsPropPageBase::OnNotify(wParam, lParam); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::InvokeUserQuery
//
// Synopsis: Bring up the query dialog to search for users and groups.
//
//-----------------------------------------------------------------------------
void CDsGrpMembersPage::InvokeUserQuery(void) { TRACE(CDsGrpMembersPage,InvokeUserQuery); HRESULT hr; UINT i; CWaitCursor WaitCursor; CSmartWStr cstrCleanDN; IDsObjectPicker * pObjSel; BOOL fIsObjSelInited, fNativeModeUSG = FALSE; CStr strExternMemberList;
hr = GetObjSel(&pObjSel, &fIsObjSelInited);
CHECK_HRESULT(hr, return);
if (!fIsObjSelInited) { CStrW cstrDC; hr = GetLdapServerName(m_pDsObj, cstrDC);
CHECK_HRESULT_REPORT(hr, m_hPage, return); dspDebugOut((DEB_ITRACE, "ObjSel targetted to %ws\n", (LPCWSTR)cstrDC));
DSOP_SCOPE_INIT_INFO rgScopes[5]; DSOP_INIT_INFO InitInfo;
ZeroMemory(rgScopes, sizeof(rgScopes)); ZeroMemory(&InitInfo, sizeof(InitInfo));
// The first scope is the local domain. All group types can contain
// users, computers, and contacts from the local domain.
//
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 | DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS; rgScopes[0].pwzDcName = cstrDC; rgScopes[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS | DSOP_FILTER_CONTACTS | DSOP_FILTER_COMPUTERS;
// The second scope is the local forest.
//
rgScopes[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); rgScopes[1].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN; rgScopes[1].flScope = DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
// The third scope is the GC.
//
rgScopes[2].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); rgScopes[2].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG; rgScopes[2].flScope = DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
// The fourth scope is uplevel external trusted domains.
//
rgScopes[3].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); rgScopes[3].flType = DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN; rgScopes[3].flScope = DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
// The fifth scope is downlevel external trusted domains.
//
rgScopes[4].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); rgScopes[4].flType = DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN; rgScopes[4].flScope = DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
if (m_dwType & GROUP_TYPE_ACCOUNT_GROUP) // Global group
{ if (!(m_fMixed && (m_dwType & GROUP_TYPE_SECURITY_ENABLED))) { // if it is not mixed-mode, security-enabled, add global.
//
rgScopes[0].FilterFlags.Uplevel.flBothModes |= DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE; } rgScopes[1].FilterFlags.Uplevel.flBothModes = rgScopes[2].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_CONTACTS;
InitInfo.cDsScopeInfos = 3; // Enterprise scope.
} else if (m_dwType & GROUP_TYPE_RESOURCE_GROUP) // Local group.
{ rgScopes[0].FilterFlags.Uplevel.flBothModes |= DSOP_FILTER_UNIVERSAL_GROUPS_DL | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE; if (!(m_fMixed && (m_dwType & GROUP_TYPE_SECURITY_ENABLED)) && !(m_dwType & GROUP_TYPE_BUILTIN_LOCAL_GROUP)) { // If this is not a mixed-mode security-enabled local group
// or a builtin group, then add local groups.
//
rgScopes[0].FilterFlags.Uplevel.flBothModes |= DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE; } //bug 37724
if( m_dwType & GROUP_TYPE_BUILTIN_LOCAL_GROUP ) rgScopes[0].FilterFlags.Uplevel.flBothModes |= DSOP_FILTER_WELL_KNOWN_PRINCIPALS;
rgScopes[1].FilterFlags.Uplevel.flBothModes = rgScopes[2].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS | DSOP_FILTER_CONTACTS | DSOP_FILTER_COMPUTERS | DSOP_FILTER_UNIVERSAL_GROUPS_DL | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE; //
// Uplevel external domains:
//
rgScopes[3].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS | DSOP_FILTER_COMPUTERS | DSOP_FILTER_UNIVERSAL_GROUPS_DL | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE; //
// Downlevel external domains:
//
rgScopes[4].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS | DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS;
InitInfo.cDsScopeInfos = 5; // Any trusted domain.
} else if (m_dwType & GROUP_TYPE_UNIVERSAL_GROUP) { rgScopes[0].FilterFlags.Uplevel.flBothModes = rgScopes[1].FilterFlags.Uplevel.flBothModes = rgScopes[2].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS | DSOP_FILTER_CONTACTS | DSOP_FILTER_COMPUTERS | DSOP_FILTER_UNIVERSAL_GROUPS_DL | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE;
InitInfo.cDsScopeInfos = 3; // Enterprise scope.
}
InitInfo.cbSize = sizeof(DSOP_INIT_INFO); InitInfo.aDsScopeInfos = rgScopes; InitInfo.pwzTargetComputer = cstrDC; InitInfo.flOptions = DSOP_FLAG_MULTISELECT; InitInfo.cAttributesToFetch = 2; LPCWSTR rgAttrNames[] = {g_wzObjectSID, g_wzUserAccountControl}; InitInfo.apwzAttributeNames = rgAttrNames;
hr = pObjSel->Initialize(&InitInfo);
CHECK_HRESULT_REPORT(hr, m_hPage, return);
ObjSelInited(); }
IDataObject * pdoSelections = NULL;
CComPtr<IDsObjectPickerEx> spObjPickerEx; hr = pObjSel->QueryInterface(IID_IDsObjectPickerEx, (void**)&spObjPickerEx); CHECK_HRESULT_REPORT(hr, m_hPage, return);
hr = spObjPickerEx->InvokeDialogEx(m_hPage, this, &pdoSelections);
// hr = pObjSel->InvokeDialog(m_hPage, &pdoSelections);
CHECK_HRESULT_REPORT(hr, m_hPage, return);
if (hr == S_FALSE || !pdoSelections) { return; }
// Security enabled universal groups shouldn't contain members
// from mixed-mode domains BUT, we have to allow it for Exchange's
// non-standard public folder security model.
//
if (!m_fMixed && (m_dwType & GROUP_TYPE_UNIVERSAL_GROUP) && (m_dwType & GROUP_TYPE_SECURITY_ENABLED)) { fNativeModeUSG = TRUE; }
m_MixedModeMembers.Init(this);
CSmartWStr cstrCleanGroup; 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, m_hPage, return);
PDS_SELECTION_LIST pSelList = (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);
if (!pSelList) { goto ExitCleanup; }
WaitCursor.SetWait();
// Clean the group name so it can be compared with those returned by the
// user's selection.
//
hr = SkipPrefix(m_pwszObjPathName, &cstrCleanGroup);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
//
// Insert the returned items into the group.
//
for (i = 0; i < pSelList->cItems; i++) { CMemberListItem * pItemInDelList = NULL; PSID pSid = NULL;
if (!pSelList->aDsSelection[i].pwzADsPath) continue;
// Check for an object from an external trusted domain. These objects
// have a path of the form "LDAP://<SID=01050xxxx>". SAM will create
// an FSPO for this member and will then store that DN rather than the
// above path. We won't know this DN until after the member is added,
// so use its object-SID to identify it.
//
if ((pSelList->aDsSelection[i].flScopeType == DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN) || (pSelList->aDsSelection[i].flScopeType == DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN)) { dspAssert(pSelList->aDsSelection[i].pvarFetchedAttributes); if (pSelList->aDsSelection[i].pvarFetchedAttributes[0].vt != (VT_ARRAY | VT_UI1)) { REPORT_ERROR(ERROR_DATATYPE_MISMATCH, m_hPage); continue; } pSid = pSelList->aDsSelection[i].pvarFetchedAttributes[0].parray->pvData; dspAssert(IsValidSid(pSid)); //
// Check if the item is in the delete list, if so remove it.
//
pItemInDelList = m_DelList.FindItemRemove(pSid); } else { hr = SkipPrefix(pSelList->aDsSelection[i].pwzADsPath, &cstrCleanDN);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
// See if the user is trying to add the group to itself.
//
if (_wcsicmp(cstrCleanDN, cstrCleanGroup) == 0) { if (pSelList->cItems == 1) { ErrMsg(IDS_ERROR_GRP_SELF, m_hPage); goto ExitCleanup; } continue; }
// Check if the item is in the delete list, if so remove it.
//
pItemInDelList = m_DelList.FindItemRemove(cstrCleanDN); }
if (pItemInDelList) { hr = m_pList->InsertIntoList(pItemInDelList); } else { if (pSid) { CComPtr<IADsPathname> spPathCracker;
hr = GetADsPathname(spPathCracker);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
hr = spPathCracker->Set(pSelList->aDsSelection[i].pwzADsPath, ADS_SETTYPE_FULL);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup); PWSTR pwzName; BSTR bstr;
hr = spPathCracker->Retrieve(ADS_FORMAT_PROVIDER, &bstr);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
if (_wcsicmp(bstr, L"LDAP") == 0) { SysFreeString(bstr);
hr = SkipPrefix(pSelList->aDsSelection[i].pwzADsPath, &cstrCleanDN);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
hr = CrackName(cstrCleanDN, &pwzName, GET_OBJ_CAN_NAME_EX, m_hPage);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
hr = m_pList->InsertIntoList(pSid, pwzName);
LocalFreeStringW(&pwzName); } else { SysFreeString(bstr);
hr = spPathCracker->Retrieve(ADS_FORMAT_WINDOWS_DN, &bstr);
CHECK_HRESULT_REPORT(hr, m_hPage, goto ExitCleanup);
hr = m_pList->InsertIntoList(pSid, bstr);
SysFreeString(bstr); } } else { int iIcon = -1; if (m_fShowIcons) { BOOL fDisabled = FALSE; if (pSelList->aDsSelection[i].pvarFetchedAttributes[1].vt == VT_I4) { fDisabled = pSelList->aDsSelection[i].pvarFetchedAttributes[1].lVal & UF_ACCOUNTDISABLE; } iIcon = g_ClassIconCache.GetClassIconIndex(pSelList->aDsSelection[i].pwzClass, fDisabled); if (iIcon == -1) { iIcon = g_ClassIconCache.AddClassIcon(pSelList->aDsSelection[i].pwzClass, fDisabled); } }
if (fNativeModeUSG && ((DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN == pSelList->aDsSelection[i].flScopeType) || (DSOP_SCOPE_TYPE_GLOBAL_CATALOG == pSelList->aDsSelection[i].flScopeType))) { // member from domain in forest is DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
// member from the same domain is DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
//
m_MixedModeMembers.CheckMember(cstrCleanDN); }
dspDebugOut((DEB_ITRACE, "New member scope is 0x%x\n", pSelList->aDsSelection[i].flScopeType));
hr = m_pList->InsertIntoList(cstrCleanDN, iIcon); } }
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)) { continue; } CHECK_HRESULT(hr, goto ExitCleanup); }
m_MixedModeMembers.ListExternalMembers(strExternMemberList);
if (!strExternMemberList.IsEmpty()) { CStr strMessage, strFormat;
strFormat.LoadString(g_hInstance, IDS_USG_MIXED_WARNING);
strMessage.Format(strFormat, strExternMemberList);
ReportErrorWorker(m_hPage, (LPTSTR)(LPCTSTR)strMessage); }
SetDirty(); ExitCleanup: GlobalUnlock(medium.hGlobal); ReleaseStgMedium(&medium); pdoSelections->Release(); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::FillGroupList
//
// Synopsis: Fill the list box with the names of the group members.
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::FillGroupList(void) { TRACE(CDsGrpMembersPage,FillGroupList); return ::FillGroupList(this, m_pList, m_dwGroupRID); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::RemoveMember
//
// Synopsis: Removes the selected users.
//
//-----------------------------------------------------------------------------
void CDsGrpMembersPage::RemoveMember(void) { TRACE(CDsGrpMembersPage,RemoveMember); if (!m_pList) { return; } int* pIndex = NULL; CMemberListItem ** ppItem; int nNumSelected = 0;
//
// Compose the confirmation message and post it.
//
TCHAR szMsg[160]; if (!LoadStringReport(IDS_RM_MBR_MSG, szMsg, 160, m_hPage)) { return; }
TCHAR szTitle[80]; if (!LoadStringReport(IDS_MSG_TITLE, szTitle, 80, m_hPage)) { return; }
LONG iRet = MessageBox(m_hPage, szMsg, szTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2);
if (iRet == IDNO) { // The user declined, so go home.
//
return; }
CWaitCursor cWait;
if (!m_pList->GetCurListItems(&pIndex, NULL, &ppItem, &nNumSelected)) { return; }
for (int idx = 0; idx < nNumSelected; idx++) { if (!ppItem[idx]) { if (pIndex != NULL) { delete[] pIndex; pIndex = 0; } delete[] ppItem; return; }
if (ppItem[idx]->m_fIsPrimary) { ErrMsg(IDS_RM_USR_PRI_GRP, m_hPage); continue; }
//
// Put the item into the delete list and remove it from the list box.
//
if (!m_DelList.AddItem(ppItem[idx])) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
if (pIndex != NULL) { delete[] pIndex; pIndex = 0; } delete[] ppItem; return; }
m_pList->RemoveListItem(pIndex[idx]);
for (int idx2 = idx; idx2 < nNumSelected; idx2++) { if (pIndex[idx2] > pIndex[idx]) { pIndex[idx2]--; } }
SetDirty(); } //
// Disable the Remove button, since nothing in the list box should have
// the selection at this point.
//
//Since Remove Button has focus now, set focus to add button
//before disabling
SetFocus(GetDlgItem(m_hPage,IDC_ADD_BTN)); EnableWindow(GetDlgItem(m_hPage, IDC_REMOVE_BTN), FALSE);
if (pIndex != NULL) { delete[] pIndex; pIndex = 0; } delete[] ppItem;
return; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::GetRealDN
//
// Synopsis: If a member from an external domain that was added to the
// group during this instance of the page, we won't yet have the
// path to the FPO as the DN. So, search for the FPO using the
// object-SID.
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::GetRealDN(CMemberListItem * pItem) { return ::GetRealDN(this, pItem); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::OnDestroy
//
// Synopsis: Exit cleanup
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpMembersPage::OnDestroy(void) { if (m_pList) { m_pList->ClearList(); }
CDsPropPageBase::OnDestroy(); // If an application processes this message, it should return zero.
return 0; }
HRESULT HrVariantToStringArray(const CComVariant& refvar, PWSTR** pppszStringArray, DWORD* pdwCount) { HRESULT hr = S_OK; long start, end, current; *pdwCount = 0; *pppszStringArray = NULL;
if (V_VT(&refvar) == VT_BSTR) { CComBSTR bstrVal = V_BSTR(&refvar); *pppszStringArray = new PWSTR[1]; if (*pppszStringArray != NULL) { size_t length = wcslen(bstrVal); PWSTR pszVal = new WCHAR[length + 1]; if (pszVal != NULL) { wcscpy(pszVal, bstrVal); (*pppszStringArray)[0] = pszVal; } else { delete[] *pppszStringArray; *pppszStringArray = NULL; *pdwCount = 0; return E_OUTOFMEMORY; } } *pdwCount = 1; return S_OK; }
//
// Check the VARIANT to make sure we have
// an array of variants.
//
if ( V_VT(&refvar) != ( VT_ARRAY | VT_VARIANT ) ) { dspAssert(FALSE); return E_UNEXPECTED; } SAFEARRAY *saAttributes = V_ARRAY( &refvar );
//
// Figure out the dimensions of the array.
//
hr = SafeArrayGetLBound( saAttributes, 1, &start ); if( FAILED(hr) ) return hr;
hr = SafeArrayGetUBound( saAttributes, 1, &end ); if( FAILED(hr) ) return hr;
CComVariant SingleResult;
//
// Process the array elements.
//
*pppszStringArray = new PWSTR[(end - start) + 1]; if (*pppszStringArray != NULL) { for ( current = start; current <= end; current++) { hr = SafeArrayGetElement( saAttributes, ¤t, &SingleResult ); if( FAILED(hr) ) return hr; if ( V_VT(&SingleResult) != VT_BSTR ) return E_UNEXPECTED;
CComBSTR bstrVal = V_BSTR(&SingleResult); size_t length = wcslen(bstrVal); PWSTR pszVal = new WCHAR[length + 1]; if (pszVal != NULL) { wcscpy(pszVal, bstrVal);
long lCount = static_cast<long>(*pdwCount); if (lCount < (end - start) + 1) { (*pppszStringArray)[(*pdwCount)++] = pszVal; } } else { return E_OUTOFMEMORY; } } } else { hr = E_OUTOFMEMORY; *pdwCount = 0; }
return hr; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpMembersPage::LoadGroupExtraClasses
//
// Synopsis: Read the extra classes that need to be displayed from the
// DisplaySpecifiers
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpMembersPage::LoadGroupExtraClasses(BOOL bSecurity) { HRESULT hr = S_OK; dspAssert(m_pDsObj != NULL); if (m_pDsObj == NULL) { return E_INVALIDARG; }
static LPCWSTR lpszSettingsObjectClass = L"dsUISettings"; static LPCWSTR lpszSettingsObject = L"cn=DS-UI-Default-Settings"; static LPCWSTR lpszSecurityGroupProperty = L"msDS-Security-Group-Extra-Classes"; static LPCWSTR lpszNonSecurityGroupProperty = L"msDS-Non-Security-Group-Extra-Classes";
//
// Not AddRef'd so don't use a smart pointer
//
IDsDisplaySpecifier* pDispSpec; hr = GetIDispSpec(&pDispSpec); CHECK_HRESULT_REPORT(hr, GetHWnd(), return hr);
//
// get the display specifiers locale container (e.g. 409)
//
CComPtr<IADsContainer> spLocaleContainer; hr = pDispSpec->GetDisplaySpecifier(NULL, IID_IADsContainer, (void**)&spLocaleContainer); if (FAILED(hr)) { return hr; }
//
// bind to the settings object
//
CComPtr<IDispatch> spIDispatchObject; hr = spLocaleContainer->GetObject((LPWSTR)lpszSettingsObjectClass, (LPWSTR)lpszSettingsObject, &spIDispatchObject); if (FAILED(hr)) { return hr; }
CComPtr<IADs> spSettingsObject; hr = spIDispatchObject->QueryInterface(IID_IADs, (void**)&spSettingsObject); if (FAILED(hr)) { return hr; }
if (bSecurity) { //
// get the security group extra classes as a CStringList
//
CComVariant var; hr = spSettingsObject->Get((LPWSTR)lpszSecurityGroupProperty, &var); if (SUCCEEDED(hr)) { hr = HrVariantToStringArray(var, &m_pszSecurityGroupExtraClasses, &m_dwSecurityGroupExtraClassesCount); } } else { //
// get the non-security group extra classes as a CStringList
//
CComVariant var; hr = spSettingsObject->Get((LPWSTR)lpszNonSecurityGroupProperty, &var); if (SUCCEEDED(hr)) { hr = HrVariantToStringArray(var, &m_pszNonSecurityGroupExtraClasses, &m_dwNonSecurityGroupExtraClassesCount); } } return hr; } //+----------------------------------------------------------------------------
//
// Function: GetDomainMode
//
// Synopsis: Is the domain to which the indicated object belongs in mixed
// or native mode?
//
//-----------------------------------------------------------------------------
HRESULT GetDomainMode(CDsPropPageBase * pObj, PBOOL pfMixed) { HRESULT hr; CComBSTR cbstrDomain;
hr = GetDomainScope(pObj, &cbstrDomain);
CHECK_HRESULT_REPORT(hr, pObj->GetHWnd(), return hr);
return GetDomainMode(cbstrDomain, pObj->GetHWnd(), pfMixed); }
HRESULT GetDomainMode(PWSTR pwzDomain, HWND hWnd, PBOOL pfMixed) { HRESULT hr; WCHAR wzMixedAttr[] = L"nTMixedDomain"; PWSTR rgpwzAttrNames[] = {wzMixedAttr}; CComPtr <IDirectoryObject> pDomObj; PADS_ATTR_INFO pAttrs = NULL; DWORD cAttrs = 0;
dspDebugOut((DEB_ITRACE, "GetDomainMode targetted to %ws\n", pwzDomain));
hr = ADsOpenObject(pwzDomain, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (void **)&pDomObj);
CHECK_HRESULT_REPORT(hr, hWnd, return hr);
hr = pDomObj->GetObjectAttributes(rgpwzAttrNames, 1, &pAttrs, &cAttrs);
CHECK_HRESULT_REPORT(hr, hWnd, return hr);
if (cAttrs && pAttrs && (_wcsicmp(pAttrs->pszAttrName, wzMixedAttr) == 0)) { *pfMixed = (BOOL)pAttrs->pADsValues->Integer;
FreeADsMem(pAttrs); } else { *pfMixed = 0; }
return hr; }
//+----------------------------------------------------------------------------
//
// Function: GetGroupType
//
//-----------------------------------------------------------------------------
HRESULT GetGroupType(CDsPropPageBase * pObj, DWORD * pdwType) { HRESULT hr; PWSTR rgpwzAttrNames[] = {g_wzGroupType}; PADS_ATTR_INFO pAttrs = NULL; DWORD cAttrs = 0;
hr = pObj->m_pDsObj->GetObjectAttributes(rgpwzAttrNames, 1, &pAttrs, &cAttrs);
CHECK_HRESULT_REPORT(hr, pObj->GetHWnd(), return hr);
if (cAttrs && pAttrs && (_wcsicmp(pAttrs->pszAttrName, g_wzGroupType) == 0)) { *pdwType = pAttrs->pADsValues->Integer;
FreeADsMem(pAttrs); } else { *pdwType = 0; }
return hr; }
//+----------------------------------------------------------------------------
//
// Function: FillGroupList
//
// Synopsis: Fill the list box with the names of the group members.
//
//-----------------------------------------------------------------------------
HRESULT FillGroupList(CDsPropPageBase * pPage, CDsMembershipList * pList, DWORD dwGroupRID) { TRACE_FUNCTION(FillGroupList); HRESULT hr = S_OK; Smart_PADS_ATTR_INFO spAttrs; DWORD i, cAttrs = 0; WCHAR wzMemberAttr[MAX_PATH] = L"member;range=0-*"; const WCHAR wcSep = L'-'; const WCHAR wcEnd = L'*'; const WCHAR wzFormat[] = L"member;range=%ld-*"; PWSTR pwzAttrName[] = {wzMemberAttr}, pwzPath; BOOL fMoreRemain = FALSE, fNameNotMapped = FALSE; CComPtr <IDirectorySearch> spDsSearch;
//
// Read the membership list from the object using range (incremental)
// retrieval.
//
do { hr = pPage->m_pDsObj->GetObjectAttributes(pwzAttrName, 1, &spAttrs, &cAttrs);
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, pPage->GetHWnd())) { return hr; }
if (cAttrs > 0 && spAttrs != NULL) { for (i = 0; i < spAttrs->dwNumValues; i++) { hr = pList->InsertIntoNewList(spAttrs->pADsValues[i].CaseIgnoreString);
if (DS_NAME_ERROR_NO_MAPPING == HRESULT_CODE(hr)) { fNameNotMapped = TRUE; hr = S_OK; } else { CHECK_HRESULT(hr, return hr); } } //
// Check to see if there is more data. If the last char of the
// attribute name string is an asterisk, then we have everything.
//
size_t cchEnd = wcslen(spAttrs->pszAttrName);
fMoreRemain = spAttrs->pszAttrName[cchEnd - 1] != wcEnd;
if (fMoreRemain) { PWSTR pwz = wcsrchr(spAttrs->pszAttrName, wcSep); if (!pwz) { dspAssert(FALSE && spAttrs->pszAttrName); fMoreRemain = FALSE; } else { pwz++; // move past the hyphen to the range end value.
dspAssert(*pwz); long lEnd = _wtol(pwz); lEnd++; // start with the next value.
wsprintfW(wzMemberAttr, wzFormat, lEnd); dspDebugOut((DEB_ITRACE, "Range returned is %ws, now asking for %ws\n", spAttrs->pszAttrName, wzMemberAttr)); } } } } while (fMoreRemain);
//
// Query for all users/computers who have this as their primary group.
//
// Filter out interdomain-trust accounts (0x30000002).
// This value is defined in ds\src\dsamain\include\mappings.h
//
WCHAR wzSearchFormat[] = L"(&(primaryGroupID=%u)(sAMAccountType<=805306369))";
CStrW strSearchFilter; strSearchFilter.Format(wzSearchFormat, dwGroupRID);
BSTR bstrDomain;
hr = GetDomainScope(pPage, &bstrDomain);
CHECK_HRESULT(hr, return hr);
pwzAttrName[0] = g_wzADsPath;
CDSSearch Search; hr = Search.Init((LPCWSTR)bstrDomain);
SysFreeString(bstrDomain); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
Search.SetFilterString(const_cast<LPWSTR>((LPCWSTR)strSearchFilter));
Search.SetAttributeList(pwzAttrName, 1); Search.SetSearchScope(ADS_SCOPE_SUBTREE);
hr = Search.DoQuery();
while (SUCCEEDED(hr)) { hr = Search.GetNextRow();
if (hr == S_ADS_NOMORE_ROWS) { hr = S_OK; break; }
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
ADS_SEARCH_COLUMN Column = {0};
hr = Search.GetColumn(g_wzADsPath, &Column);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
hr = pPage->SkipPrefix(Column.pADsValues->CaseIgnoreString, &pwzPath);
Search.FreeColumn(&Column); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
hr = pList->InsertIntoNewList(pwzPath, TRUE);
delete pwzPath; CHECK_HRESULT(hr, return hr); }
if (pList->GetCount() < 1) { EnableWindow(GetDlgItem(pPage->GetHWnd(), IDC_REMOVE_BTN), FALSE); } else if (((CDsGrpMembersPage *)pPage)->m_fShowIcons) { // Get class and userAccountControl for the group members and use
// those values to select icons.
//
pList->SetMemberIcons(pPage); }
if (fNameNotMapped) { MsgBox(IDS_GRP_NO_NAME_MAPPING, pPage->GetHWnd()); }
return hr; }
//+----------------------------------------------------------------------------
//
// Function: GetRealDN
//
// Synopsis: If a member from an external domain that was added to the
// group during this instance of the page, we won't yet have the
// path to the FPO as the DN. So, search for the FPO using the
// object-SID.
//
//-----------------------------------------------------------------------------
HRESULT GetRealDN(CDsPropPageBase * pPage, CMemberListItem * pItem) { HRESULT hr = S_OK;
if (!pItem->GetSid()) { return E_FAIL; }
CComBSTR cbstrDomain;
hr = GetDomainScope(pPage, &cbstrDomain);
CHECK_HRESULT(hr, return hr);
CStrW strDN;
hr = FindFPO(pItem->GetSid(), cbstrDomain, strDN); //Don't show this eror here
if(FAILED(hr)) return hr;
PWSTR pwzOldDN = pItem->m_pwzDN;
if (!AllocWStr(const_cast<PWSTR>((LPCWSTR)strDN), &pItem->m_pwzDN)) { REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd()); return E_OUTOFMEMORY; }
DO_DEL(pwzOldDN);
pItem->m_fIsExternal = FALSE;
return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: CDsGrpShlGenPage::CDsGrpShlGenPage
//
//-----------------------------------------------------------------------------
CDsGrpShlGenPage::CDsGrpShlGenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, HWND hNotifyObj, DWORD dwFlags) : m_pCIcon(NULL), m_fDescrWritable(FALSE), m_fDescrDirty(FALSE), CDsGrpMembersPage(pDsPage, pDataObj, hNotifyObj, dwFlags) { TRACE(CDsGrpShlGenPage,CDsGrpShlGenPage); #ifdef _DEBUG
strcpy(szClass, "CDsGrpShlGenPage"); #endif
}
//+----------------------------------------------------------------------------
//
// Member: CDsGrpShlGenPage::~CDsGrpShlGenPage
//
//-----------------------------------------------------------------------------
CDsGrpShlGenPage::~CDsGrpShlGenPage() { TRACE(CDsGrpShlGenPage,~CDsGrpShlGenPage); }
//+----------------------------------------------------------------------------
//
// Function: CreateGrpShlGenPage
//
// Synopsis: Creates an instance of the group shell general page window.
//
//-----------------------------------------------------------------------------
HRESULT CreateGrpShlGenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, PWSTR pwzADsPath, PWSTR pwzClass, HWND hNotifyObj, DWORD dwFlags, CDSBasePathsInfo* pBasePathsInfo, HPROPSHEETPAGE * phPage) { TRACE_FUNCTION(CreateGroupMembersPage);
CDsGrpShlGenPage * pPageObj = new CDsGrpShlGenPage(pDsPage, pDataObj, hNotifyObj, dwFlags); CHECK_NULL(pPageObj, return E_OUTOFMEMORY);
pPageObj->Init(pwzADsPath, pwzClass, pBasePathsInfo);
return pPageObj->CreatePage(phPage); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpShlGenPage::OnInitDialog
//
// Synopsis: Set the initial control values from the corresponding DS
// attributes.
//
//-----------------------------------------------------------------------------
HRESULT CDsGrpShlGenPage::OnInitDialog(LPARAM lParam) { TRACE(CDsGrpShlGenPage,OnInitDialog); HRESULT hr; Smart_PADS_ATTR_INFO spAttrs; DWORD cAttrs = 0;
CWaitCursor Wait;
//
// Get the icon from the DS and put it on the page.
//
ATTR_DATA ad = {0, 0};
hr = GeneralPageIcon(this, &GenIcon, NULL, 0, &ad, fInit);
CHECK_HRESULT_REPORT(hr, m_hPage, return S_OK);
m_pCIcon = (CDsIconCtrl *)ad.pVoid;
//
// Get the name.
//
LPTSTR ptz; if (!UnicodeToTchar(m_pwszRDName, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); return S_OK; }
SetDlgItemText(m_hPage, IDC_CN, ptz); delete [] ptz;
m_fDescrWritable = CheckIfWritable(g_wzDescription);
//
// Get the description
//
PWSTR rgpwzAttrNames[] = {g_wzDescription};
hr = m_pDsObj->GetObjectAttributes(rgpwzAttrNames, 1, &spAttrs, &cAttrs);
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, m_hPage)) { return S_OK; }
if (1 == cAttrs) { dspAssert(spAttrs); if (!UnicodeToTchar(spAttrs->pADsValues->CaseIgnoreString, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); return S_OK; } SetDlgItemText(m_hPage, IDC_DESCRIPTION_EDIT, ptz); delete [] ptz; }
if (m_fDescrWritable) { SendDlgItemMessage(m_hPage, IDC_DESCRIPTION_EDIT, EM_LIMITTEXT, DSPROP_DESCRIPTION_RANGE_UPPER, 0); } else { SendDlgItemMessage(m_hPage, IDC_DESCRIPTION_EDIT, EM_SETREADONLY, (WPARAM)TRUE, 0); }
HRESULT hRes = CDsGrpMembersPage::OnInitDialog(lParam, FALSE);
#if !defined(DSADMIN)
// in the Win95 shell, we do not want to have the buttons
// because we do not have object picker
MakeNotWritable(); EnableWindow(GetDlgItem(m_hPage, IDC_ADD_BTN), FALSE); #endif
EnableWindow(GetDlgItem(m_hPage, IDC_REMOVE_BTN), FALSE);
return hRes; }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpShlGenPage::OnCommand
//
// Synopsis: Handle control notifications.
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpShlGenPage::OnCommand(int id, HWND hwndCtl, UINT codeNotify) { if (m_fInInit) { return 0; } if (EN_CHANGE == codeNotify && IDC_DESCRIPTION_EDIT == id) { m_fDescrDirty = TRUE; } TRACE(CDsGrpShlGenPage,OnCommand); return CDsGrpMembersPage::OnCommand(id, hwndCtl, codeNotify); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpShlGenPage::OnApply
//
// Synopsis: Write changes
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpShlGenPage::OnApply(void) { TRACE(CDsGrpShlGenPage,OnApply);
ADS_ATTR_INFO AttrInfoDesc = {g_wzDescription, ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, NULL, 0}; ADSVALUE ADsValueDesc = {ADSTYPE_CASE_IGNORE_STRING, NULL};
AttrInfoDesc.pADsValues = &ADsValueDesc; AttrInfoDesc.dwNumValues = 1; LPTSTR ptsz;
if (m_fDescrDirty) { dspAssert(m_fDescrWritable);
ptsz = new TCHAR[DSPROP_DESCRIPTION_RANGE_UPPER + 1]; CHECK_NULL_REPORT(ptsz, m_hPage, return -1);
if (GetDlgItemText(m_hPage, IDC_DESCRIPTION_EDIT, ptsz, DSPROP_DESCRIPTION_RANGE_UPPER + 1) == 0) { // An empty control means remove the attribute value from the
// object.
//
AttrInfoDesc.dwNumValues = 0; AttrInfoDesc.pADsValues = NULL; AttrInfoDesc.dwControlCode = ADS_ATTR_CLEAR; } else { if (!TcharToUnicode(ptsz, &ADsValueDesc.CaseIgnoreString)) { REPORT_ERROR(E_OUTOFMEMORY, m_hPage); delete ptsz; return -1; } } delete ptsz; DWORD cModified;
HRESULT hr = m_pDsObj->SetObjectAttributes(&AttrInfoDesc, 1, &cModified);
if (!CHECK_ADS_HR(&hr, m_hPage)) { goto Cleanup; }
m_fDescrDirty = FALSE; }
Cleanup: DO_DEL(ADsValueDesc.CaseExactString);
return CDsGrpMembersPage::OnApply(); }
//+----------------------------------------------------------------------------
//
// Method: CDsGrpShlGenPage::OnDestroy
//
// Synopsis: Exit cleanup
//
//-----------------------------------------------------------------------------
LRESULT CDsGrpShlGenPage::OnDestroy(void) { ATTR_DATA ad = {0, (LPARAM)m_pCIcon};
GeneralPageIcon(this, &GenIcon, NULL, 0, &ad, fOnDestroy);
CDsGrpMembersPage::OnDestroy(); // If an application processes this message, it should return zero.
return 0; }
//+----------------------------------------------------------------------------
//
// Function: CheckGroupUpdate
//
// Synopsis: Checks the result code to see if a group-specific error has
// occured.
//
//-----------------------------------------------------------------------------
BOOL CheckGroupUpdate(HRESULT hr, HWND hPage, BOOL fAdd, PWSTR pwzDN) { if (SUCCEEDED(hr)) { return TRUE; } if (hPage == NULL) { hPage = GetDesktopWindow(); } DWORD dwErr = 0; WCHAR wszErrBuf[MAX_PATH+1]; WCHAR wszNameBuf[MAX_PATH+1]; ADsGetLastError(&dwErr, wszErrBuf, MAX_PATH, wszNameBuf, MAX_PATH); //
// ERROR_DS_CONSTRAINT_VIOLATION is the error returned for
// duplicate name.
//
if ((LDAP_RETCODE)dwErr == LDAP_CONSTRAINT_VIOLATION || hr == HRESULT_FROM_WIN32(ERROR_DS_CONSTRAINT_VIOLATION)) { PTSTR ptzTitle, ptzMsg;
if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle)) { goto FatalError; } if (!LoadStringToTchar((fAdd) ? IDS_ERRMSG_GROUP_CONSTRAINT : IDS_ERRMSG_GROUP_DELETE, &ptzMsg)) { delete ptzTitle; goto FatalError; } MessageBox(hPage, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION); delete [] ptzTitle; delete [] ptzMsg; } else if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT && fAdd) { // Put a useful message up
PTSTR ptzTitle = 0, ptzMsg = 0; if (!LoadStringToTchar(IDS_MSG_USER_NOT_PRESENT, &ptzMsg)) { goto FatalError; } if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle)) { goto FatalError; } MessageBox(hPage, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION); delete[] ptzTitle; delete[] ptzMsg; } else if (HRESULT_CODE(dwErr) == ERROR_DS_NO_ATTRIBUTE_OR_VALUE && !fAdd) { // No message needed
return FALSE; } else if (HRESULT_CODE(dwErr) == ERROR_MEMBER_NOT_IN_ALIAS && !fAdd) { // Put a useful message up
bool bShowGenericMessage = true; if (pwzDN) { //
// Crack the DN into the name
//
CComPtr<IADsPathname> spPathcracker; hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathcracker); if (SUCCEEDED(hr)) { hr = spPathcracker->Set(pwzDN, ADS_SETTYPE_DN); if (SUCCEEDED(hr)) { hr = spPathcracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY); if (SUCCEEDED(hr)) { CComBSTR sbstrName; hr = spPathcracker->Retrieve(ADS_FORMAT_LEAF, &sbstrName); if (SUCCEEDED(hr)) { ErrMsgParam(IDS_MSG_MEMBER_ALREADY_GONE, (LPARAM)(PWSTR)sbstrName, hPage); bShowGenericMessage = false; } } } } }
if (bShowGenericMessage) { PTSTR ptzTitle = 0, ptzMsg = 0; if (!LoadStringToTchar(IDS_MSG_MEMBER_ALREADY_GONE2, &ptzMsg)) { goto FatalError; } if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle)) { goto FatalError; } MessageBox(hPage, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION); delete[] ptzTitle; delete[] ptzMsg; } } else { if (dwErr) { dspDebugOut((DEB_ERROR, "Extended Error 0x%x: %ws %ws.\n", dwErr, wszErrBuf, wszNameBuf)); ReportError(dwErr, IDS_ADS_ERROR_FORMAT, hPage); } else { dspDebugOut((DEB_ERROR, "Error %08lx\n", hr)); ReportError(hr, IDS_ADS_ERROR_FORMAT, hPage); } } return FALSE;
FatalError: MessageBoxA(hPage, "A Fatal Error has occured!", "Active Directory Service", MB_OK | MB_ICONEXCLAMATION);
return FALSE; }
//+----------------------------------------------------------------------------
//
// Function: FindFPO
//
// Synopsis: Given a SID, look for a corresponding FPO.
//
//-----------------------------------------------------------------------------
HRESULT FindFPO(PSID pSid, PWSTR pwzDomain, CStrW & strFPODN) { HRESULT hr; CDSSearch Srch;
hr = Srch.Init(pwzDomain);
CHECK_HRESULT(hr, return hr);
PWSTR rgpwzAttrNames[] = {g_wzDN};
hr = Srch.SetAttributeList(rgpwzAttrNames, 1);
CHECK_HRESULT(hr, return hr);
Srch.SetSearchScope(ADS_SCOPE_SUBTREE);
WCHAR wzSearchFormat[] = L"(&(objectCategory=foreignSecurityPrincipal)(objectSid=%s))"; PWSTR pwzSID; CStrW strSearchFilter;
hr = ADsEncodeBinaryData((PBYTE)pSid, GetLengthSid(pSid), &pwzSID);
CHECK_HRESULT(hr, return hr);
strSearchFilter.Format(wzSearchFormat, pwzSID);
FreeADsMem(pwzSID);
Srch.SetFilterString(const_cast<LPWSTR>((LPCWSTR)strSearchFilter));
hr = Srch.DoQuery();
CHECK_HRESULT(hr, return hr);
hr = Srch.GetNextRow();
if (hr == S_ADS_NOMORE_ROWS) { // No object has a matching SID, the FPO must have been deleted.
//
return HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND); } CHECK_HRESULT(hr, return hr); ADS_SEARCH_COLUMN Column;
hr = Srch.GetColumn(g_wzDN, &Column);
CHECK_HRESULT(hr, return hr);
strFPODN = Column.pADsValues->CaseIgnoreString;
if (strFPODN.IsEmpty()) { Srch.FreeColumn(&Column); return E_OUTOFMEMORY; }
Srch.FreeColumn(&Column);
return S_OK; }
//+----------------------------------------------------------------------------
//
// Class: CMemberDomainMode
//
// Purpose: Maintains a list of all domains in the enterprise from which
// members have been added along with those domains' mode. Keeps
// a second list of members who have been added from mixed-mode
// domains.
//
//-----------------------------------------------------------------------------
void CMemberDomainMode::Init(CDsPropPageBase * pPage) { m_pPage = pPage;
m_MemberList.Clear(); }
HRESULT CMemberDomainMode::CheckMember(PWSTR pwzMemberDN) { HRESULT hr; CComBSTR cbstrDomain; BOOL fMixed = FALSE;
hr = GetObjectsDomain(m_pPage, pwzMemberDN, &cbstrDomain);
if (SUCCEEDED(hr) && cbstrDomain) { if (!m_DomainList.Find(cbstrDomain, &fMixed)) { // The member's domain is not already in the list. Read the domain
// mode and then add it.
//
hr = GetDomainMode(cbstrDomain, m_pPage->GetHWnd(), &fMixed);
CHECK_HRESULT(hr, return hr);
hr = m_DomainList.Insert(cbstrDomain, fMixed);
CHECK_HRESULT_REPORT(hr, m_pPage->GetHWnd(), return hr); } }
if (fMixed) { PWSTR pwzCanEx; PTSTR ptzCanEx; CStr strName;
hr = CrackName(pwzMemberDN, &pwzCanEx, GET_OBJ_CAN_NAME_EX, m_pPage->GetHWnd());
CHECK_HRESULT(hr, return hr);
if (!UnicodeToTchar(pwzCanEx, &ptzCanEx)) { LocalFreeStringW(&pwzCanEx); REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd()); return E_OUTOFMEMORY; } LocalFreeStringW(&pwzCanEx);
CStr cstrFolder;
GetNameParts(ptzCanEx, cstrFolder, strName);
DO_DEL(ptzCanEx);
hr = m_MemberList.Insert(strName);
CHECK_HRESULT_REPORT(hr, m_pPage->GetHWnd(), return hr); }
return S_OK; }
HRESULT CMemberDomainMode::ListExternalMembers(CStr & strList) { m_MemberList.GetList(strList);
return S_OK; }
//+----------------------------------------------------------------------------
//
// CMemberDomainMode helper classes
//
//-----------------------------------------------------------------------------
HRESULT CMMMemberList::Insert(LPCTSTR ptzName) { CMMMemberListItem * pItem = new CMMMemberListItem;
if (!pItem) { return E_OUTOFMEMORY; }
pItem->m_strName = ptzName;
if (m_pListHead == NULL) { m_pListHead = pItem; } else { pItem->LinkAfter(m_pListHead); } return S_OK; }
#define MAX_MMMLISTING 25
void CMMMemberList::GetList(CStr & strList) { int nCount = 0;
strList.Empty();
CMMMemberListItem * pItem = m_pListHead;
while (pItem) { strList += pItem->m_strName;
nCount++;
pItem = pItem->Next(); if (pItem) { if (nCount > MAX_MMMLISTING) { strList += TEXT("..."); return; } else { strList += TEXT(", "); } } } }
void CMMMemberList::Clear(void) { CMMMemberListItem * pItem = m_pListHead, * pNext;
while (pItem) { pNext = pItem->Next(); delete pItem; pItem = pNext; }
m_pListHead = NULL; }
CDomainModeList::~CDomainModeList(void) { CDomainModeListItem * pItem = m_pListHead, * pNext;
while (pItem) { pNext = pItem->Next(); delete pItem; pItem = pNext; } }
HRESULT CDomainModeList::Insert(PWSTR pwzDomain, BOOL fMixed) { CDomainModeListItem * pItem = new CDomainModeListItem;
if (!pItem) { return E_OUTOFMEMORY; }
pItem->m_strName = pwzDomain; pItem->m_fMixed = fMixed;
if (m_pListHead == NULL) { m_pListHead = pItem; } else { pItem->LinkAfter(m_pListHead); } return S_OK; }
BOOL CDomainModeList::Find(LPCWSTR pwzDomain, PBOOL pfMixed) { CDomainModeListItem * pItem = m_pListHead;
while (pItem) { if (_wcsicmp(pwzDomain, pItem->m_strName) == 0) { *pfMixed = pItem->m_fMixed; return TRUE; } pItem = pItem->Next(); }
return FALSE; }
|