1267 lines
37 KiB
C++
1267 lines
37 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
||
|
//
|
||
|
// File: newuser.cpp
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// newuser.cpp
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "dsutil.h"
|
||
|
|
||
|
#include "newobj.h" // CNewADsObjectCreateInfo
|
||
|
|
||
|
#include "dlgcreat.h"
|
||
|
#include "querysup.h"
|
||
|
|
||
|
#include <windowsx.h>
|
||
|
#include <lmaccess.h>
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// NEW USER WIZARD
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// CCreateNewUserPage1
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CCreateNewUserPage1, CCreateNewObjectDataPage)
|
||
|
ON_EN_CHANGE(IDC_EDIT_FIRST_NAME, OnNameChange)
|
||
|
ON_EN_CHANGE(IDC_EDIT_INITIALS, OnNameChange)
|
||
|
ON_EN_CHANGE(IDC_EDIT_LAST_NAME, OnNameChange)
|
||
|
ON_EN_CHANGE(IDC_NT5_USER_EDIT, OnLoginNameChange)
|
||
|
ON_EN_CHANGE(IDC_NT4_USER_EDIT, OnSAMNameChange)
|
||
|
ON_EN_CHANGE(IDC_EDIT_FULL_NAME, OnFullNameChange)
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
CCreateNewUserPage1::CCreateNewUserPage1() :
|
||
|
CCreateNewObjectDataPage(CCreateNewUserPage1::IDD)
|
||
|
{
|
||
|
m_bForcingNameChange = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CCreateNewUserPage1::OnInitDialog()
|
||
|
{
|
||
|
CCreateNewObjectDataPage::OnInitDialog();
|
||
|
VERIFY(_InitUI());
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CCreateNewUserPage1::GetSummaryInfo(CString& s)
|
||
|
{
|
||
|
// get the UPN name
|
||
|
CString strDomain;
|
||
|
GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
|
||
|
CString strUPN = m_strLoginName + strDomain;
|
||
|
|
||
|
// format the line
|
||
|
CString szFmt;
|
||
|
szFmt.LoadString(IDS_s_CREATE_NEW_SUMMARY_USER_UPN);
|
||
|
CString szBuffer;
|
||
|
szBuffer.Format((LPCWSTR)szFmt, (LPCWSTR)strUPN);
|
||
|
s += szBuffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CCreateNewUserPage1::SetData(BOOL bSilent)
|
||
|
{
|
||
|
//
|
||
|
// start with a new temporary object
|
||
|
//
|
||
|
HRESULT hr;
|
||
|
CString strDomain;
|
||
|
|
||
|
GetDlgItemText (IDC_EDIT_FULL_NAME, OUT m_strFullName);
|
||
|
GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
|
||
|
|
||
|
m_strLoginName.TrimRight();
|
||
|
m_strLoginName.TrimLeft();
|
||
|
|
||
|
//
|
||
|
// First check for illegal characters
|
||
|
//
|
||
|
int iFind = m_strLoginName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS);
|
||
|
if (iFind != -1 && !m_strLoginName.IsEmpty())
|
||
|
{
|
||
|
PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strLoginName};
|
||
|
if (!bSilent && IDYES == ReportErrorEx (::GetParent(m_hWnd),IDS_LOGINNAME_ILLEGAL,S_OK,
|
||
|
MB_YESNO | MB_ICONWARNING, apv, 1))
|
||
|
{
|
||
|
while (iFind != -1)
|
||
|
{
|
||
|
m_strLoginName.SetAt(iFind, L'_');
|
||
|
iFind = m_strLoginName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS);
|
||
|
}
|
||
|
m_bForcingNameChange = TRUE;
|
||
|
SetDlgItemText(IDC_NT5_USER_EDIT, m_strLoginName);
|
||
|
m_bForcingNameChange = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Set the focus to the edit box and select the text
|
||
|
//
|
||
|
GetDlgItem(IDC_NT5_USER_EDIT)->SetFocus();
|
||
|
SendDlgItemMessage(IDC_NT5_USER_EDIT, EM_SETSEL, 0 , -1);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CString strUPN = m_strLoginName + strDomain;
|
||
|
CString strDomainDNS = strDomain;
|
||
|
CString strFilter;
|
||
|
|
||
|
//
|
||
|
// Store the object name in the temporary storage
|
||
|
//
|
||
|
CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
|
||
|
|
||
|
//
|
||
|
// create a new temporary ADs object
|
||
|
//
|
||
|
hr = pNewADsObjectCreateInfo->HrCreateNew(m_strFullName);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
BOOL fDomainSearchFailed = FALSE;
|
||
|
BOOL fGCSearchFailed = FALSE;
|
||
|
|
||
|
//
|
||
|
// now validate UPN with current domain before doing the put.
|
||
|
//
|
||
|
CDSSearch DSS;
|
||
|
IDirectorySearch *pGCObj = NULL;
|
||
|
|
||
|
//
|
||
|
// validate UPN with GC before doing the put.
|
||
|
//
|
||
|
CString strDomainName = m_LocalDomain.Right (m_LocalDomain.GetLength() - 1);
|
||
|
hr = DSPROP_GetGCSearchOnDomain((LPWSTR)(LPCWSTR)strDomainName,
|
||
|
IID_IDirectorySearch, (void **)&pGCObj);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = DSS.Init (pGCObj);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
//
|
||
|
// NTRAID#NTBUG9-257580-2000/12/14-jeffjon,
|
||
|
// We must get an escaped filter because the UPN may contain "special" characters
|
||
|
//
|
||
|
CString szEscapedUPN;
|
||
|
EscapeFilterElement(strUPN, szEscapedUPN);
|
||
|
|
||
|
LPWSTR pAttributes[1] = {L"cn"};
|
||
|
strFilter = L"(userPrincipalName=";
|
||
|
strFilter += szEscapedUPN;
|
||
|
strFilter += L")";
|
||
|
TRACE(_T("searching global catalog for %s...\n"), strUPN);
|
||
|
|
||
|
|
||
|
DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
|
||
|
DSS.SetAttributeList (pAttributes, 1);
|
||
|
DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
|
||
|
DSS.DoQuery();
|
||
|
hr = DSS.GetNextRow();
|
||
|
TRACE(_T("done searching global catalog for %s...\n"), strUPN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hr == S_OK) // this means a row was returned, so we're dup
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strLoginName};
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_DUP,hr,
|
||
|
MB_OK | MB_ICONWARNING, apv, 1);
|
||
|
}
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
if (hr != S_ADS_NOMORE_ROWS) // oops, had another problem
|
||
|
{
|
||
|
fGCSearchFailed = TRUE;
|
||
|
}
|
||
|
|
||
|
CString strInitPath = L"LDAP://";
|
||
|
strInitPath += m_LocalDomain.Right (m_LocalDomain.GetLength() - 1);
|
||
|
TRACE(_T("Initialize Domain search object with: %s...\n"), strInitPath);
|
||
|
HRESULT hr2 = DSS.Init (strInitPath);
|
||
|
if (SUCCEEDED(hr2))
|
||
|
{
|
||
|
CString szEscapedUPN;
|
||
|
EscapeFilterElement(strUPN, szEscapedUPN);
|
||
|
|
||
|
LPWSTR pAttributes2[1] = {L"cn"};
|
||
|
strFilter = L"(userPrincipalName=";
|
||
|
strFilter += szEscapedUPN;
|
||
|
strFilter += L")";
|
||
|
TRACE(_T("searching current domain for %s...\n"), strUPN);
|
||
|
DSS.SetAttributeList (pAttributes2, 1);
|
||
|
DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
|
||
|
DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
|
||
|
DSS.DoQuery();
|
||
|
hr2 = DSS.GetNextRow();
|
||
|
TRACE(_T("done searching current domain for %s...\n"), strUPN);
|
||
|
}
|
||
|
|
||
|
if (hr2 == S_OK) // this means a row was returned, so we're dup
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_DUP,hr2,
|
||
|
MB_OK | MB_ICONWARNING, NULL, 0);
|
||
|
}
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (hr2 != S_ADS_NOMORE_ROWS) // oops, had another problem
|
||
|
{
|
||
|
fDomainSearchFailed = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fDomainSearchFailed || fGCSearchFailed)
|
||
|
{
|
||
|
HRESULT hrSearch = S_OK;
|
||
|
if (fDomainSearchFailed)
|
||
|
{
|
||
|
hrSearch = hr2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hrSearch = hr;
|
||
|
}
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_SEARCH_FAILED,hrSearch,
|
||
|
MB_OK | MB_ICONWARNING, NULL, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pGCObj)
|
||
|
{
|
||
|
pGCObj->Release();
|
||
|
pGCObj = NULL;
|
||
|
}
|
||
|
|
||
|
GetDlgItemText (IDC_NT4_USER_EDIT, OUT m_strSAMName);
|
||
|
m_strSAMName.TrimLeft();
|
||
|
m_strSAMName.TrimRight();
|
||
|
|
||
|
//
|
||
|
// First check for illegal characters
|
||
|
//
|
||
|
iFind = m_strSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS_WITH_AT);
|
||
|
if (iFind != -1 && !m_strSAMName.IsEmpty())
|
||
|
{
|
||
|
PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strSAMName};
|
||
|
if (!bSilent && IDYES == ReportErrorEx (::GetParent(m_hWnd),IDS_SAMNAME_ILLEGAL,S_OK,
|
||
|
MB_YESNO | MB_ICONWARNING, apv, 1))
|
||
|
{
|
||
|
while (iFind != -1)
|
||
|
{
|
||
|
m_strSAMName.SetAt(iFind, L'_');
|
||
|
iFind = m_strSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS_WITH_AT);
|
||
|
}
|
||
|
m_bForcingNameChange = TRUE;
|
||
|
SetDlgItemText(IDC_NT4_USER_EDIT, m_strSAMName);
|
||
|
m_bForcingNameChange = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Set the focus to the edit box and select the text
|
||
|
//
|
||
|
GetDlgItem(IDC_NT4_USER_EDIT)->SetFocus();
|
||
|
SendDlgItemMessage(IDC_NT4_USER_EDIT, EM_SETSEL, 0 , -1);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// validate samAccountName with domain before doing the put.
|
||
|
// There is no reason to verify the uniqueness against the GC
|
||
|
// since sAMAccountName only has to be unique within the domain
|
||
|
//
|
||
|
CDSSearch DSSSAM;
|
||
|
|
||
|
if (!fDomainSearchFailed && !fGCSearchFailed)
|
||
|
{
|
||
|
fDomainSearchFailed = FALSE;
|
||
|
fGCSearchFailed = FALSE;
|
||
|
|
||
|
hr2 = DSSSAM.Init (strInitPath);
|
||
|
if (SUCCEEDED(hr2))
|
||
|
{
|
||
|
CString szEscapedSAMName;
|
||
|
EscapeFilterElement(m_strSAMName, szEscapedSAMName);
|
||
|
|
||
|
LPWSTR pAttributes2[1] = {L"cn"};
|
||
|
strFilter = L"(samAccountName=";
|
||
|
strFilter += szEscapedSAMName;
|
||
|
strFilter += L")";
|
||
|
TRACE(_T("searching current domain for %s...\n"), strUPN);
|
||
|
DSSSAM.SetAttributeList (pAttributes2, 1);
|
||
|
DSSSAM.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
|
||
|
DSSSAM.SetSearchScope (ADS_SCOPE_SUBTREE);
|
||
|
DSSSAM.DoQuery();
|
||
|
hr2 = DSSSAM.GetNextRow();
|
||
|
TRACE(_T("done searching current domain for %s...\n"), strUPN);
|
||
|
}
|
||
|
|
||
|
if (hr2 == S_OK) // this means a row was returned, so we're dup
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_SAMNAME_DUP,hr2,
|
||
|
MB_OK | MB_ICONWARNING, NULL, 0);
|
||
|
}
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (hr2 != S_ADS_NOMORE_ROWS) // oops, had another problem
|
||
|
{
|
||
|
fDomainSearchFailed = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fDomainSearchFailed)
|
||
|
{
|
||
|
HRESULT hrSearch = S_OK;
|
||
|
if (fDomainSearchFailed)
|
||
|
{
|
||
|
hrSearch = hr2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hrSearch = hr;
|
||
|
}
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_SEARCH_FAILED,hrSearch,
|
||
|
MB_OK | MB_ICONWARNING, NULL, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pGCObj)
|
||
|
{
|
||
|
pGCObj->Release();
|
||
|
}
|
||
|
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstr(const_cast<PWSTR>(gsz_samAccountName), m_strSAMName);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
|
||
|
strUPN.TrimRight();
|
||
|
strUPN.TrimLeft();
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstr(L"userPrincipalName", strUPN);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
|
||
|
m_strFullName.TrimLeft();
|
||
|
m_strFullName.TrimRight();
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstr(L"displayName", m_strFullName);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(L"givenName", m_strFirstName);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(L"initials", m_strInitials);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(L"sn", m_strLastName);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CCreateNewUserPage1::_InitUI()
|
||
|
{
|
||
|
CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
|
||
|
IADs * pObj = NULL;
|
||
|
CComBSTR bsPath;
|
||
|
CComBSTR bsDN;
|
||
|
LPWSTR pwzDomain = NULL;
|
||
|
|
||
|
Edit_LimitText (GetDlgItem(IDC_EDIT_FULL_NAME)->m_hWnd, 64);
|
||
|
Edit_LimitText (GetDlgItem(IDC_EDIT_LAST_NAME)->m_hWnd, 29);
|
||
|
Edit_LimitText (GetDlgItem(IDC_EDIT_FIRST_NAME)->m_hWnd, 28);
|
||
|
Edit_LimitText (GetDlgItem(IDC_EDIT_INITIALS)->m_hWnd, 4);
|
||
|
Edit_LimitText (GetDlgItem(IDC_NT4_USER_EDIT)->m_hWnd, 20);
|
||
|
Edit_LimitText (GetDlgItem(IDC_NT5_USER_EDIT)->m_hWnd, 256);
|
||
|
|
||
|
HRESULT hr = pNewADsObjectCreateInfo->m_pIADsContainer->QueryInterface(
|
||
|
IID_IADs, (void **)&pObj);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// get the DN of the container from its LDAP path
|
||
|
pObj->get_ADsPath (&bsPath);
|
||
|
|
||
|
{ // scope for smart pointer
|
||
|
CPathCracker pathCracker;
|
||
|
|
||
|
pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
|
||
|
pathCracker.Set(bsPath, ADS_SETTYPE_FULL);
|
||
|
pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsDN);
|
||
|
}
|
||
|
|
||
|
// get the NT 5 (dns) domain name
|
||
|
TRACE(L"CrackName(%s, &pwzDomain, GET_DNS_DOMAIN_NAME, NULL);\n", bsDN);
|
||
|
hr = CrackName(bsDN, &pwzDomain, GET_DNS_DOMAIN_NAME, NULL);
|
||
|
TRACE(L"CrackName returned hr = 0x%x, pwzDomain = <%s>\n", hr, pwzDomain);
|
||
|
|
||
|
// get the NT 4 domain name from the DN
|
||
|
LPWSTR pwzNT4Domain = NULL;
|
||
|
TRACE(L"CrackName (%s, &pwzNT4Domain, GET_NT4_DOMAIN_NAME, NULL);\n", bsDN);
|
||
|
hr = CrackName(bsDN, &pwzNT4Domain, GET_NT4_DOMAIN_NAME, NULL);
|
||
|
TRACE(L"CrackName returned hr = 0x%x, pwzNT4Domain = <%s>\n", hr, pwzNT4Domain);
|
||
|
|
||
|
// set the NT 4 domain name read only edit box
|
||
|
if (pwzNT4Domain != NULL)
|
||
|
{
|
||
|
CString szBuffer;
|
||
|
szBuffer.Format(L"%s\\", pwzNT4Domain);
|
||
|
SetDlgItemText(IDC_NT4_DOMAIN_EDIT, szBuffer);
|
||
|
LocalFreeStringW(&pwzNT4Domain);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TRACE(L"After CrackName() calls, pwzDomain = <%s>\n", pwzDomain);
|
||
|
|
||
|
// if we do not have a domain name, we cannot proceed further,
|
||
|
// this is a catastrophic failure
|
||
|
if (pwzDomain == NULL)
|
||
|
{
|
||
|
// should never get here in normal operations
|
||
|
HWND hWndWiz = ::GetParent(m_hWnd);
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
|
||
|
MB_OK | MB_ICONERROR, NULL, 0);
|
||
|
|
||
|
// bail out of the wizard
|
||
|
VERIFY(::PostMessage(hWndWiz, WM_COMMAND, IDCANCEL, 0));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
m_LocalDomain = L"@";
|
||
|
m_LocalDomain += pwzDomain;
|
||
|
|
||
|
CComboBox * pCC = (CComboBox *)GetDlgItem (IDC_NT5_DOMAIN_COMBO);
|
||
|
|
||
|
// get the current domain (only present if we're going around a second time
|
||
|
// due an error.) need this to prevent dups when on second trip.
|
||
|
|
||
|
CString strDomain;
|
||
|
GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
|
||
|
|
||
|
CStringList UPNs;
|
||
|
|
||
|
// get UPN suffixes from this OU, if present
|
||
|
CComVariant Var;
|
||
|
hr = pObj->Get ( L"uPNSuffixes", &Var);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
hr = HrVariantToStringList (IN Var, UPNs);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
POSITION pos = UPNs.GetHeadPosition();
|
||
|
CString csSuffix;
|
||
|
while (pos != NULL) {
|
||
|
csSuffix = L"@";
|
||
|
csSuffix += UPNs.GetNext(INOUT pos);
|
||
|
TRACE(_T("UPN suffix: %s\n"), csSuffix);
|
||
|
pCC->AddString (csSuffix);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
CString csPartitions;
|
||
|
IADs * pPartitions = NULL;
|
||
|
|
||
|
// get config path from main object
|
||
|
csPartitions.Format(L"%sCN=Partitions,%s",
|
||
|
pNewADsObjectCreateInfo->GetBasePathsInfo()->GetProviderAndServerName(),
|
||
|
pNewADsObjectCreateInfo->GetBasePathsInfo()->GetConfigNamingContext());
|
||
|
|
||
|
hr = DSAdminOpenObject(csPartitions,
|
||
|
IID_IADs,
|
||
|
(void **)&pPartitions,
|
||
|
TRUE /*bServer*/);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
CComVariant sVar;
|
||
|
hr = pPartitions->Get ( L"uPNSuffixes", &sVar);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
hr = HrVariantToStringList (IN sVar, UPNs);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
POSITION pos = UPNs.GetHeadPosition();
|
||
|
CString csSuffix;
|
||
|
while (pos != NULL) {
|
||
|
csSuffix = L"@";
|
||
|
csSuffix += UPNs.GetNext(INOUT pos);
|
||
|
TRACE(_T("UPN suffix: %s\n"), csSuffix);
|
||
|
if (wcscmp (strDomain, csSuffix)) {
|
||
|
pCC->AddString (csSuffix);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pPartitions->Release();
|
||
|
}
|
||
|
|
||
|
// get rest of domains in this tree
|
||
|
CComPtr <IDsBrowseDomainTree> spDsDomains;
|
||
|
hr = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IDsBrowseDomainTree,
|
||
|
(LPVOID*)&spDsDomains);
|
||
|
if (FAILED(hr)) {
|
||
|
LocalFreeStringW(&pwzDomain);
|
||
|
return FALSE;
|
||
|
}
|
||
|
LPCWSTR lpszServerName = GetWiz()->GetInfo()->GetBasePathsInfo()->GetServerName();
|
||
|
hr = spDsDomains->SetComputer(lpszServerName, NULL, NULL);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
TRACE(L"returned from SetComputer(%s). hr is %lx\n", lpszServerName, hr);
|
||
|
PDOMAIN_TREE pNewDomains = NULL;
|
||
|
hr = spDsDomains->GetDomains(&pNewDomains, 0);
|
||
|
TRACE(L"returned from GetDomains(), hr is %lx\n", hr);
|
||
|
CString csRootDomain = L"@";
|
||
|
INT pos;
|
||
|
UINT iRoot;
|
||
|
|
||
|
if (SUCCEEDED(hr) && pNewDomains) {
|
||
|
TRACE(L"pNewDomains->dwCount = %d\n", pNewDomains->dwCount);
|
||
|
for (UINT index = 0; index < pNewDomains->dwCount; index++) {
|
||
|
TRACE(L"pNewDomains->aDomains[%d].pszName = <%s>\n", index, pNewDomains->aDomains[index].pszName);
|
||
|
if (pNewDomains->aDomains[index].pszTrustParent == NULL) {
|
||
|
//
|
||
|
// Add the root domain only if it is a substring of the current
|
||
|
// domain.
|
||
|
//
|
||
|
size_t cchRoot = wcslen(pNewDomains->aDomains[index].pszName);
|
||
|
PWSTR pRoot = pwzDomain + wcslen(pwzDomain) - cchRoot;
|
||
|
|
||
|
if (!_wcsicmp(pRoot, pNewDomains->aDomains[index].pszName))
|
||
|
{
|
||
|
csRootDomain += pNewDomains->aDomains[index].pszName;
|
||
|
if (_wcsicmp (strDomain, csRootDomain)) {
|
||
|
pos = pCC->AddString (csRootDomain);
|
||
|
}
|
||
|
iRoot = index;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If the local domain is not the root, add it as well.
|
||
|
//
|
||
|
CString csOtherDomain = L"@";
|
||
|
|
||
|
if (_wcsicmp(csRootDomain, m_LocalDomain))
|
||
|
{
|
||
|
if (_wcsicmp (strDomain, m_LocalDomain)) {
|
||
|
pos = pCC->AddString(m_LocalDomain);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pNewDomains) {
|
||
|
spDsDomains->FreeDomains(&pNewDomains);
|
||
|
}
|
||
|
LocalFreeStringW(&pwzDomain);
|
||
|
}
|
||
|
|
||
|
if (pObj) {
|
||
|
pObj->Release();
|
||
|
pObj = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the local domain is not already in the list then add it
|
||
|
//
|
||
|
int iFind = pCC->FindStringExact(-1, m_LocalDomain);
|
||
|
if (iFind == CB_ERR)
|
||
|
{
|
||
|
pCC->InsertString(0, m_LocalDomain);
|
||
|
pCC->SetCurSel(0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pCC->SetCurSel(iFind);
|
||
|
}
|
||
|
|
||
|
m_nameFormatter.Initialize(pNewADsObjectCreateInfo->GetBasePathsInfo(),
|
||
|
pNewADsObjectCreateInfo->m_pszObjectClass);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL CCreateNewUserPage1::GetData(IADs* pIADsCopyFrom)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
if (pIADsCopyFrom != NULL)
|
||
|
{
|
||
|
// copy operation
|
||
|
|
||
|
|
||
|
// we copy the UPN suffix
|
||
|
CComVariant varData;
|
||
|
hr = pIADsCopyFrom->Get(L"userPrincipalName", &varData);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// got something like "JoeB@acme.com."
|
||
|
TRACE(L"source userPrincipalName: %s\n", varData.bstrVal);
|
||
|
|
||
|
// need to get the suffix "@acme.com."
|
||
|
for (LPWSTR lpszUPNSuffix = varData.bstrVal; lpszUPNSuffix != NULL; lpszUPNSuffix++)
|
||
|
{
|
||
|
if ((*lpszUPNSuffix) == L'@')
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (lpszUPNSuffix != NULL)
|
||
|
{
|
||
|
TRACE(L"source UPN suffix: %s\n", lpszUPNSuffix);
|
||
|
|
||
|
// need to find out of the suffix is already there
|
||
|
CComboBox * pDomainCombo = (CComboBox *)GetDlgItem(IDC_NT5_DOMAIN_COMBO);
|
||
|
int iIndex = pDomainCombo->FindString(-1, lpszUPNSuffix);
|
||
|
if (iIndex == CB_ERR)
|
||
|
{
|
||
|
// not found, just add at the top
|
||
|
pDomainCombo->InsertString(0, lpszUPNSuffix);
|
||
|
iIndex = 0;
|
||
|
}
|
||
|
|
||
|
ASSERT( (iIndex >= 0) && (iIndex < pDomainCombo->GetCount()));
|
||
|
// set the selection to the source UPN suffix
|
||
|
pDomainCombo->SetCurSel(iIndex);
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
return (!m_strLoginName.IsEmpty() &&!m_strFullName.IsEmpty());
|
||
|
}
|
||
|
|
||
|
|
||
|
void CCreateNewUserPage1::OnNameChange()
|
||
|
{
|
||
|
GetDlgItemText(IDC_EDIT_FIRST_NAME, OUT m_strFirstName);
|
||
|
GetDlgItemText(IDC_EDIT_INITIALS, OUT m_strInitials);
|
||
|
GetDlgItemText(IDC_EDIT_LAST_NAME, OUT m_strLastName);
|
||
|
|
||
|
m_strFirstName.TrimLeft();
|
||
|
m_strFirstName.TrimRight();
|
||
|
|
||
|
m_strInitials.TrimLeft();
|
||
|
m_strInitials.TrimRight();
|
||
|
|
||
|
m_strLastName.TrimLeft();
|
||
|
m_strLastName.TrimRight();
|
||
|
|
||
|
m_nameFormatter.FormatName(m_strFullName,
|
||
|
m_strFirstName.IsEmpty() ? NULL : (LPCWSTR)m_strFirstName,
|
||
|
m_strInitials.IsEmpty() ? NULL : (LPCWSTR)m_strInitials,
|
||
|
m_strLastName.IsEmpty() ? NULL : (LPCWSTR)m_strLastName);
|
||
|
|
||
|
|
||
|
SetDlgItemText (IDC_EDIT_FULL_NAME,
|
||
|
IN m_strFullName);
|
||
|
|
||
|
GetDlgItemText(IDC_NT5_USER_EDIT, OUT m_strLoginName);
|
||
|
GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
|
||
|
!m_strFullName.IsEmpty() &&
|
||
|
!m_strSAMName.IsEmpty()));
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserPage1::OnLoginNameChange()
|
||
|
{
|
||
|
if (!m_bForcingNameChange)
|
||
|
{
|
||
|
CString csSamName;
|
||
|
GetDlgItemText(IDC_NT5_USER_EDIT, OUT m_strLoginName);
|
||
|
csSamName = m_strLoginName.Left(20);
|
||
|
SetDlgItemText (IDC_NT4_USER_EDIT, OUT csSamName);
|
||
|
}
|
||
|
GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
|
||
|
!m_strFullName.IsEmpty() &&
|
||
|
!m_strSAMName.IsEmpty()));
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserPage1::OnSAMNameChange()
|
||
|
{
|
||
|
GetDlgItemText (IDC_NT4_USER_EDIT, OUT m_strSAMName);
|
||
|
GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
|
||
|
!m_strFullName.IsEmpty() &&
|
||
|
!m_strSAMName.IsEmpty()));
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserPage1::OnFullNameChange()
|
||
|
{
|
||
|
GetDlgItemText (IDC_EDIT_FULL_NAME, OUT m_strFullName);
|
||
|
GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
|
||
|
!m_strFullName.IsEmpty() &&
|
||
|
!m_strSAMName.IsEmpty()));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
BOOL CCreateNewUserPage1::OnError( HRESULT hr )
|
||
|
{
|
||
|
BOOL bRetVal = FALSE;
|
||
|
|
||
|
if( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS )
|
||
|
{
|
||
|
|
||
|
HRESULT Localhr;
|
||
|
DWORD LastError;
|
||
|
WCHAR Buf1[256], Buf2[256];
|
||
|
Localhr = ADsGetLastError (&LastError,
|
||
|
Buf1, 256, Buf2, 256);
|
||
|
switch( LastError )
|
||
|
{
|
||
|
case ERROR_USER_EXISTS:
|
||
|
{
|
||
|
PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strSAMName};
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_ERROR_USER_EXISTS,hr,
|
||
|
MB_OK|MB_ICONWARNING , apv, 1);
|
||
|
bRetVal = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ERROR_DS_OBJ_STRING_NAME_EXISTS:
|
||
|
{
|
||
|
PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strFullName};
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_ERROR_USER_DS_OBJ_STRING_NAME_EXISTS,hr,
|
||
|
MB_OK|MB_ICONWARNING , apv, 1);
|
||
|
bRetVal = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return bRetVal;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// CCreateNewUserPage2
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CCreateNewUserPage2, CCreateNewObjectDataPage)
|
||
|
ON_BN_CLICKED (IDC_CHECK_PASSWORD_MUST_CHANGE, OnPasswordPropsClick)
|
||
|
ON_BN_CLICKED (IDC_CHECK_PASSWORD_NEVER_EXPIRES, OnPasswordPropsClick)
|
||
|
ON_BN_CLICKED (IDC_CHECK_PASSWORD_CANNOT_CHANGE, OnPasswordPropsClick)
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
CCreateNewUserPage2::CCreateNewUserPage2() :
|
||
|
CCreateNewObjectDataPage(CCreateNewUserPage2::IDD)
|
||
|
{
|
||
|
m_pPage1 = NULL;
|
||
|
}
|
||
|
|
||
|
BOOL CCreateNewUserPage2::OnInitDialog()
|
||
|
{
|
||
|
CCreateNewObjectDataPage::OnInitDialog();
|
||
|
|
||
|
SendDlgItemMessage(IDC_EDIT_PASSWORD, EM_LIMITTEXT, (WPARAM)127, 0);
|
||
|
SendDlgItemMessage(IDC_EDIT_PASSWORD_CONFIRM, EM_LIMITTEXT, (WPARAM)127, 0);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserPage2::_GetCheckBoxSummaryInfo(UINT nCtrlID, UINT nStringID, CString& s)
|
||
|
{
|
||
|
if (IsDlgButtonChecked(nCtrlID))
|
||
|
{
|
||
|
CString sz;
|
||
|
sz.LoadString(nStringID);
|
||
|
s += sz;
|
||
|
s += L"\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserPage2::GetSummaryInfo(CString& s)
|
||
|
{
|
||
|
_GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_MUST_CHANGE, IDS_USER_CREATE_DLG_PASSWORD_MUST_CHANGE, s);
|
||
|
_GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_CANNOT_CHANGE, IDS_USER_CREATE_DLG_PASSWORD_CANNOT_CHANGE, s);
|
||
|
_GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_NEVER_EXPIRES, IDS_USER_CREATE_DLG_PASSWORD_NEVER_EXPIRES, s);
|
||
|
_GetCheckBoxSummaryInfo(IDC_CHECK_ACCOUNT_DISABLED, IDS_USER_CREATE_DLG_ACCOUNT_DISABLED, s);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCreateNewUserPage2::OnPasswordPropsClick()
|
||
|
{
|
||
|
BOOL fPasswordMustChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_MUST_CHANGE);
|
||
|
BOOL fPasswordCannotChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_CANNOT_CHANGE);
|
||
|
BOOL fPasswordNeverExpires = IsDlgButtonChecked(IDC_CHECK_PASSWORD_NEVER_EXPIRES);
|
||
|
|
||
|
if (fPasswordMustChange && fPasswordNeverExpires)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_PASSWORD_MUTEX,S_OK,
|
||
|
MB_OK, NULL, 0);
|
||
|
CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, FALSE);
|
||
|
fPasswordMustChange = FALSE;
|
||
|
}
|
||
|
|
||
|
if (fPasswordMustChange && fPasswordCannotChange)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_ERR_BOTH_PW_BTNS,S_OK,
|
||
|
MB_OK, NULL, 0);
|
||
|
CheckDlgButton(IDC_CHECK_PASSWORD_CANNOT_CHANGE, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CCreateNewUserPage2::SetData(BOOL bSilent)
|
||
|
{
|
||
|
CString strPassword;
|
||
|
CString strPasswordConfirm;
|
||
|
|
||
|
GetDlgItemText(IDC_EDIT_PASSWORD, OUT strPassword);
|
||
|
GetDlgItemText(IDC_EDIT_PASSWORD_CONFIRM, OUT strPasswordConfirm);
|
||
|
if (strPassword != strPasswordConfirm)
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx (::GetParent(m_hWnd),IDS_PASSWORDS_DONT_MATCH,S_OK,
|
||
|
MB_OK, NULL, 0);
|
||
|
}
|
||
|
SetDlgItemText(IDC_EDIT_PASSWORD, L"");
|
||
|
SetDlgItemText(IDC_EDIT_PASSWORD_CONFIRM, L"");
|
||
|
SetDlgItemFocus(IDC_EDIT_PASSWORD);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
// intelligent copy of path info, it if is a copy operation
|
||
|
{
|
||
|
CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
|
||
|
CCopyObjectHandlerBase* pCopyHandler = pNewADsObjectCreateInfo->GetCopyHandler();
|
||
|
if (pCopyHandler != NULL)
|
||
|
{
|
||
|
IADs * pIADs = pNewADsObjectCreateInfo->PGetIADsPtr();
|
||
|
ASSERT(pIADs != NULL);
|
||
|
hr = pCopyHandler->Copy(pIADs, FALSE /*bPostCommit*/, ::GetParent(m_hWnd),
|
||
|
m_pPage1->GetFullName());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: _RevokeChangePasswordPrivilege
|
||
|
//
|
||
|
// Purpose: Revoke the user's change password privilege.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT RevokeChangePasswordPrivilege(IADs * pIADs)
|
||
|
{
|
||
|
CChangePasswordPrivilegeAction ChangePasswordPrivilegeAction;
|
||
|
|
||
|
HRESULT hr = ChangePasswordPrivilegeAction.Load(pIADs);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
TRACE(L"ChangePasswordPrivilegeAction.Load() failed with hr = 0x%x\n", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = ChangePasswordPrivilegeAction.Revoke();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
TRACE(L"ChangePasswordPrivilegeAction.Revoke() failed with hr = 0x%x\n", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT CCreateNewUserPage2::OnPostCommit(BOOL bSilent)
|
||
|
{
|
||
|
// local variables
|
||
|
HRESULT hr = E_FAIL;
|
||
|
PVOID apv[1] = {(LPWSTR)(m_pPage1->GetFullName())};
|
||
|
CWaitCursor Wait;
|
||
|
|
||
|
CComPtr <IDirectoryObject> pIDSObject; // smart pointer, no need to release
|
||
|
CComPtr <IADsUser> pIADsUser; // smart pointer, no need to release
|
||
|
|
||
|
BOOL bCanEnable = TRUE;
|
||
|
|
||
|
CString strPassword;
|
||
|
GetDlgItemText(IDC_EDIT_PASSWORD, OUT strPassword);
|
||
|
|
||
|
BOOL fPasswordMustChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_MUST_CHANGE);
|
||
|
BOOL fPasswordCannotChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_CANNOT_CHANGE);
|
||
|
BOOL fPasswordNeverExpires = IsDlgButtonChecked(IDC_CHECK_PASSWORD_NEVER_EXPIRES);
|
||
|
BOOL fAccountEnabled = !IsDlgButtonChecked(IDC_CHECK_ACCOUNT_DISABLED);
|
||
|
|
||
|
CComVariant varAccountFlags;
|
||
|
|
||
|
// get object info and useful interfaces
|
||
|
CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
|
||
|
ASSERT(pNewADsObjectCreateInfo != NULL);
|
||
|
|
||
|
IADs * pIADs = pNewADsObjectCreateInfo->PGetIADsPtr();
|
||
|
ASSERT(pIADs != NULL);
|
||
|
|
||
|
// get the IDirectoryObject interface
|
||
|
hr = pIADs->QueryInterface(IID_IDirectoryObject, OUT (void **)&pIDSObject);
|
||
|
ASSERT(pIDSObject != NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ASSERT(FALSE); // should never get here in normal operations
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
|
||
|
MB_OK | MB_ICONERROR, NULL, 0);
|
||
|
}
|
||
|
goto ExitCleanup;
|
||
|
}
|
||
|
|
||
|
// get the IADsUser interface
|
||
|
hr = pIADs->QueryInterface(IID_IADsUser, OUT (void **)&pIADsUser);
|
||
|
ASSERT(pIDSObject != NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ASSERT(FALSE); // should never get here in normal operations
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
|
||
|
MB_OK | MB_ICONERROR, NULL, 0);
|
||
|
}
|
||
|
goto ExitCleanup;
|
||
|
}
|
||
|
|
||
|
// try to set password
|
||
|
|
||
|
ASSERT(pIADsUser != NULL);
|
||
|
hr = pIADsUser->SetPassword(const_cast<LPTSTR>((LPCTSTR)strPassword));
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (hr != E_ACCESSDENIED)
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
// fatal error, put up error message
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PASSWORD,hr,
|
||
|
MB_OK | MB_ICONWARNING, apv, 1);
|
||
|
}
|
||
|
bCanEnable = FALSE;
|
||
|
goto ExitCleanup;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_ACCESS_DENIED_SET_PASSWORD,hr,
|
||
|
MB_OK | MB_ICONWARNING, apv, 1);
|
||
|
}
|
||
|
bCanEnable = FALSE;
|
||
|
}
|
||
|
}
|
||
|
if (fPasswordMustChange)
|
||
|
{
|
||
|
LPWSTR szPwdLastSet = L"pwdLastSet";
|
||
|
ADSVALUE ADsValuePwdLastSet = {ADSTYPE_LARGE_INTEGER, NULL};
|
||
|
ADS_ATTR_INFO AttrInfoPwdLastSet = {szPwdLastSet, ADS_ATTR_UPDATE,
|
||
|
ADSTYPE_LARGE_INTEGER,
|
||
|
&ADsValuePwdLastSet, 1};
|
||
|
ADsValuePwdLastSet.LargeInteger.QuadPart = 0;
|
||
|
ASSERT(pIDSObject != NULL);
|
||
|
DWORD cAttrModified = 0;
|
||
|
hr = pIDSObject->SetObjectAttributes(&AttrInfoPwdLastSet, 1, &cAttrModified);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ASSERT(cAttrModified == 0);
|
||
|
// fatal error, put up error message and bail out
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PWD_MUST_CHANGE,hr,
|
||
|
MB_OK | MB_ICONERROR, apv, 1);
|
||
|
}
|
||
|
bCanEnable = FALSE;
|
||
|
}
|
||
|
ASSERT(cAttrModified == 1);
|
||
|
} // if (fPasswordMustChange)
|
||
|
|
||
|
if (fPasswordCannotChange)
|
||
|
{
|
||
|
hr = RevokeChangePasswordPrivilege(pIADs);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
// warning ad go on
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PWD_CANNOT_CHANGE,hr,
|
||
|
MB_OK | MB_ICONWARNING, apv, 1);
|
||
|
}
|
||
|
bCanEnable = FALSE;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set userAccountControl
|
||
|
hr = pNewADsObjectCreateInfo->HrGetAttributeVariant(const_cast<PWSTR>(gsz_userAccountControl), OUT &varAccountFlags);
|
||
|
|
||
|
{ // scope for local variables
|
||
|
// if copy operation, makes sure we get the right set of bits copied over
|
||
|
CCopyUserHandler* pCopyUserHandler =
|
||
|
dynamic_cast<CCopyUserHandler*>(GetWiz()->GetInfo()->GetCopyHandler());
|
||
|
if (pCopyUserHandler != NULL)
|
||
|
{
|
||
|
CComVariant varAccountControlSource;
|
||
|
hr = pCopyUserHandler->GetCopyFrom()->Get((LPWSTR)gsz_userAccountControl, &varAccountControlSource);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
ASSERT(varAccountControlSource.vt == VT_I4);
|
||
|
// some bits are already set in the UI and the user can change them,
|
||
|
// we will get them later on
|
||
|
varAccountControlSource.vt &= ~UF_DONT_EXPIRE_PASSWD;
|
||
|
varAccountControlSource.vt &= ~UF_ACCOUNTDISABLE;
|
||
|
|
||
|
// add the remaining bits to the default ones after creation
|
||
|
varAccountFlags.vt |= varAccountControlSource.vt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
ASSERT(varAccountFlags.vt == VT_I4);
|
||
|
if (fPasswordNeverExpires)
|
||
|
varAccountFlags.lVal |= UF_DONT_EXPIRE_PASSWD;
|
||
|
varAccountFlags.lVal &= ~UF_PASSWD_NOTREQD;
|
||
|
|
||
|
// Update the userAccountControl attribute
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(const_cast<PWSTR>(gsz_userAccountControl), varAccountFlags);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent /* fSilentError */ );
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (HRESULT_CODE(hr) == ERROR_DS_UNWILLING_TO_PERFORM)
|
||
|
{
|
||
|
DWORD status;
|
||
|
WCHAR Buf1[256], Buf2[256];
|
||
|
ADsGetLastError (&status, Buf1, 256, Buf2, 256);
|
||
|
TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
|
||
|
status, Buf1, Buf2);
|
||
|
|
||
|
if ((status == ERROR_PASSWORD_RESTRICTION) &&
|
||
|
strPassword.IsEmpty())
|
||
|
{
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_NULL_PASSWORD,hr,
|
||
|
MB_OK | MB_ICONERROR, NULL, 0);
|
||
|
}
|
||
|
goto ExitCleanup;
|
||
|
}
|
||
|
}
|
||
|
// we failed, so we put up a warning and leave the object intact
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
|
||
|
MB_OK | MB_ICONERROR, apv, 1);
|
||
|
}
|
||
|
// reset error code, just a warning
|
||
|
bCanEnable = FALSE;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE1("INFO: Unable to get userAccountControl for user %s.\n",
|
||
|
m_pPage1->GetFullName());
|
||
|
// put up message box, but continue
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
|
||
|
MB_OK | MB_ICONERROR, apv, 1);
|
||
|
}
|
||
|
// reset error code, just a warning
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
// finally, if all went well, we can enable the user account
|
||
|
hr = S_OK;
|
||
|
if (bCanEnable & fAccountEnabled)
|
||
|
{
|
||
|
hr = pNewADsObjectCreateInfo->HrGetAttributeVariant(const_cast<PWSTR>(gsz_userAccountControl), OUT &varAccountFlags);
|
||
|
varAccountFlags.lVal &= ~UF_ACCOUNTDISABLE;
|
||
|
hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(const_cast<PWSTR>(gsz_userAccountControl), varAccountFlags);
|
||
|
hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent /* fSilentError */ );
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (HRESULT_CODE(hr) == ERROR_DS_UNWILLING_TO_PERFORM)
|
||
|
{
|
||
|
DWORD status;
|
||
|
WCHAR Buf1[256], Buf2[256];
|
||
|
ADsGetLastError (&status, Buf1, 256, Buf2, 256);
|
||
|
TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
|
||
|
status, Buf1, Buf2);
|
||
|
|
||
|
if ((status == ERROR_PASSWORD_RESTRICTION) &&
|
||
|
strPassword.IsEmpty())
|
||
|
{
|
||
|
//
|
||
|
// NTRAID#Windows Bugs-367611-2001/04/14-jeffjon
|
||
|
// DsAdmin: When password policy set, create usr with blank psswrd
|
||
|
// and 2 error msgs appear. One msg is enough
|
||
|
//
|
||
|
// This message is being handled from within the HrSetInfo above
|
||
|
// and is actually more descriptive. Probably a change to winerror.mc
|
||
|
//
|
||
|
/*
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_NULL_PASSWORD,hr,
|
||
|
MB_OK | MB_ICONERROR, NULL, 0);
|
||
|
}
|
||
|
*/
|
||
|
goto ExitCleanup;
|
||
|
}
|
||
|
}
|
||
|
// we failed, so we put up a warning and leave the object intact
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
|
||
|
MB_OK | MB_ICONERROR, apv, 1);
|
||
|
}
|
||
|
// reset error code, just a warning
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// try to set group membership, it if is a copy operation
|
||
|
{
|
||
|
CCopyObjectHandlerBase* pCopyHandler = GetWiz()->GetInfo()->GetCopyHandler();
|
||
|
|
||
|
if (pCopyHandler != NULL)
|
||
|
{
|
||
|
hr = pCopyHandler->Copy(pIADs, TRUE /*bPostCommit*/,::GetParent(m_hWnd),
|
||
|
m_pPage1->GetFullName());
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent/* fSilentError */ );
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// we failed, so we put up a warning and leave the object intact
|
||
|
if (!bSilent)
|
||
|
{
|
||
|
ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_GROUP_MEMBERSHIP,hr,
|
||
|
MB_OK | MB_ICONERROR, apv, 1);
|
||
|
}
|
||
|
// reset error code, just a warning
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitCleanup:
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
BOOL CCreateNewUserPage2::GetData(IADs* pIADsCopyFrom)
|
||
|
{
|
||
|
if (pIADsCopyFrom != NULL)
|
||
|
{
|
||
|
CString szFmt;
|
||
|
szFmt.LoadString(IDS_s_COPY_SUMMARY_NAME);
|
||
|
|
||
|
// we just get the CN of the object
|
||
|
CComVariant varAccountControl;
|
||
|
HRESULT hr = pIADsCopyFrom->Get((LPWSTR)gsz_userAccountControl, &varAccountControl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BOOL bPasswordNeverExpires = (varAccountControl.lVal & UF_DONT_EXPIRE_PASSWD) != 0;
|
||
|
BOOL bDisabled = (varAccountControl.lVal & UF_ACCOUNTDISABLE) != 0;
|
||
|
|
||
|
CheckDlgButton(IDC_CHECK_PASSWORD_NEVER_EXPIRES, bPasswordNeverExpires);
|
||
|
CheckDlgButton(IDC_CHECK_ACCOUNT_DISABLED, bDisabled);
|
||
|
} // if
|
||
|
|
||
|
|
||
|
CCopyUserHandler* pCopyUserHandler =
|
||
|
dynamic_cast<CCopyUserHandler*>(GetWiz()->GetInfo()->GetCopyHandler());
|
||
|
ASSERT(pCopyUserHandler != NULL);
|
||
|
|
||
|
if (pCopyUserHandler != NULL)
|
||
|
{
|
||
|
// set the cannot change password checkbox
|
||
|
BOOL bPasswordCannotChange = pCopyUserHandler->PasswordCannotChange();
|
||
|
CheckDlgButton(IDC_CHECK_PASSWORD_CANNOT_CHANGE, bPasswordCannotChange);
|
||
|
|
||
|
if (!bPasswordCannotChange)
|
||
|
{
|
||
|
// set the must change password checkbox
|
||
|
BOOL bPasswordMustChange = pCopyUserHandler->PasswordMustChange();
|
||
|
CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, bPasswordMustChange);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // if
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// CCreateNewUserWizard
|
||
|
|
||
|
CCreateNewUserWizard::CCreateNewUserWizard(CNewADsObjectCreateInfo* pNewADsObjectCreateInfo) :
|
||
|
CCreateNewObjectWizardBase(pNewADsObjectCreateInfo)
|
||
|
{
|
||
|
AddPage(&m_page1);
|
||
|
AddPage(&m_page2);
|
||
|
m_page2.SetPage1(&m_page1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CCreateNewUserWizard::GetSummaryInfoHeader(CString& s)
|
||
|
{
|
||
|
IADs* pIADsCopyFrom = GetInfo()->GetCopyFromObject();
|
||
|
if (pIADsCopyFrom != NULL)
|
||
|
{
|
||
|
CString szFmt;
|
||
|
szFmt.LoadString(IDS_s_COPY_SUMMARY_NAME);
|
||
|
|
||
|
// we just get the CN of the object
|
||
|
CComVariant varName;
|
||
|
HRESULT hr = pIADsCopyFrom->Get(L"cn", &varName);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CString szTmp;
|
||
|
szTmp.Format((LPCWSTR)szFmt, varName.bstrVal);
|
||
|
s += szTmp;
|
||
|
s += L"\n";
|
||
|
}
|
||
|
}
|
||
|
CCreateNewObjectWizardBase::GetSummaryInfoHeader(s);
|
||
|
}
|
||
|
|
||
|
void CCreateNewUserWizard::OnFinishSetInfoFailed(HRESULT hr)
|
||
|
{
|
||
|
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
|
||
|
if ( !( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS &&
|
||
|
m_page1.OnError( hr ) ) )
|
||
|
{
|
||
|
// everything else is handled by the base class
|
||
|
CCreateNewObjectWizardBase::OnFinishSetInfoFailed(hr);
|
||
|
}
|
||
|
}
|