You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1374 lines
41 KiB
1374 lines
41 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 "globals.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();
|
|
|
|
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
|
|
//
|
|
int 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(CComBSTR(gsz_samAccountName), m_strSAMName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
strUPN.TrimRight();
|
|
strUPN.TrimLeft();
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstr(CComBSTR(L"userPrincipalName"), strUPN);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
m_strFullName.TrimLeft();
|
|
m_strFullName.TrimRight();
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstr(CComBSTR(L"displayName"), m_strFullName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(L"givenName"), m_strFirstName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(L"initials"), m_strInitials);
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(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, 6);
|
|
Edit_LimitText (GetDlgItem(IDC_NT4_USER_EDIT)->m_hWnd, MAX_NT4_LOGON_LENGTH);
|
|
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 ( CComBSTR(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 ( CComBSTR(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 = 0;
|
|
UINT iRoot = 0;
|
|
|
|
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 (pRoot >= pwzDomain &&
|
|
!_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);
|
|
}
|
|
|
|
UpdateComboBoxDropWidth(pCC);
|
|
|
|
m_nameFormatter.Initialize(pNewADsObjectCreateInfo->GetBasePathsInfo(),
|
|
pNewADsObjectCreateInfo->m_pszObjectClass);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
CCreateNewUserPage1::UpdateComboBoxDropWidth(CComboBox* comboBox)
|
|
{
|
|
if (!comboBox)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int nHorzExtent = 0;
|
|
CClientDC dc(comboBox);
|
|
int nItems = comboBox->GetCount();
|
|
for (int i=0; i < nItems; i++)
|
|
{
|
|
CString szBuffer;
|
|
comboBox->GetLBText(i, szBuffer);
|
|
CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
|
|
nHorzExtent = max(ext.cx ,nHorzExtent);
|
|
}
|
|
comboBox->SetDroppedWidth(nHorzExtent);
|
|
}
|
|
|
|
BOOL CCreateNewUserPage1::OnSetActive()
|
|
{
|
|
BOOL ret = CCreateNewObjectDataPage::OnSetActive();
|
|
|
|
// Set the focus to the first field after the horizontal bar
|
|
// To do this, first set the focus to the container name edit
|
|
// box and then set the focus to the next control that has
|
|
// a tabstop.
|
|
// It has to be done this way instead of setting the focus
|
|
// directly to the first name field because in Far East languages
|
|
// they switch the last name and first name fields.
|
|
|
|
GetParent()->PostMessage(
|
|
WM_NEXTDLGCTL,
|
|
(WPARAM)GetDlgItem(IDC_EDIT_CONTAINER)->GetSafeHwnd(),
|
|
(LPARAM)TRUE);
|
|
|
|
// By specifying zero for both LPARAM and WPARAM, the next
|
|
// control with WS_TABSTOP should get the focus.
|
|
|
|
GetParent()->PostMessage(
|
|
WM_NEXTDLGCTL,
|
|
0,
|
|
0);
|
|
|
|
GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
|
|
!m_strFullName.IsEmpty() &&
|
|
!m_strSAMName.IsEmpty()));
|
|
return ret;
|
|
}
|
|
|
|
BOOL CCreateNewUserPage1::GetData(IADs* pIADsCopyFrom)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (pIADsCopyFrom != NULL)
|
|
{
|
|
// copy operation
|
|
|
|
|
|
// we copy the UPN suffix
|
|
CComVariant varData;
|
|
hr = pIADsCopyFrom->Get(CComBSTR(L"userPrincipalName"), &varData);
|
|
if (SUCCEEDED(hr) && varData.bstrVal != NULL)
|
|
{
|
|
// got something like "[email protected]."
|
|
TRACE(L"source userPrincipalName: %s\n", varData.bstrVal);
|
|
|
|
// need to get the suffix "@acme.com."
|
|
PWSTR lpszUPNSuffix = wcschr(varData.bstrVal, L'@');
|
|
if (lpszUPNSuffix)
|
|
{
|
|
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)MAX_PASSWORD_LENGTH, 0);
|
|
SendDlgItemMessage(IDC_EDIT_PASSWORD_CONFIRM, EM_LIMITTEXT, (WPARAM)MAX_PASSWORD_LENGTH, 0);
|
|
|
|
CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, TRUE);
|
|
|
|
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)
|
|
{
|
|
// NTRAID#NTBUG9-684597-2002/08/09-artm
|
|
// Use EncryptedStrings to hold passwords, guarantee scribbling out memory.
|
|
EncryptedString password, confirmation;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD, password);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD_CONFIRM, confirmation);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (!bSilent)
|
|
{
|
|
ReportErrorEx(
|
|
::GetParent(m_hWnd),
|
|
IDS_ERR_FATAL,
|
|
hr,
|
|
MB_OK | MB_ICONERROR,
|
|
NULL,
|
|
0);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
if (password != confirmation)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
// 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;
|
|
|
|
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;
|
|
|
|
// NTRAID#NTBUG9-684597-2002/08/09-artm
|
|
// Store copy of password in encrypted string.
|
|
EncryptedString password;
|
|
hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD, password);
|
|
if (FAILED(hr))
|
|
{
|
|
if (!bSilent)
|
|
{
|
|
ReportErrorEx(
|
|
::GetParent(m_hWnd),
|
|
IDS_ERR_FATAL,
|
|
hr,
|
|
MB_OK | MB_ICONERROR,
|
|
NULL,
|
|
0);
|
|
}
|
|
goto ExitCleanup;
|
|
}
|
|
|
|
// 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
|
|
|
|
// NTRAID#NTBUG9-684597-2002/08/09-artm
|
|
// Ensure that clear text copy scribbled out as soon as possible.
|
|
ASSERT(pIADsUser != NULL);
|
|
WCHAR* cleartext = password.GetClearTextCopy();
|
|
if (cleartext != NULL)
|
|
{
|
|
hr = pIADsUser->SetPassword(CComBSTR(cleartext));
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
password.DestroyClearTextCopy(cleartext);
|
|
|
|
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_ICONERROR, 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(CComBSTR(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(CComBSTR(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(CComBSTR(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) &&
|
|
password.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(CComBSTR(gsz_userAccountControl), OUT &varAccountFlags);
|
|
varAccountFlags.lVal &= ~UF_ACCOUNTDISABLE;
|
|
hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(CComBSTR(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) &&
|
|
password.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(CComBSTR(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);
|
|
}
|
|
else
|
|
{
|
|
// NTRAID#NTBUG9-651998-2002/07/02-artm
|
|
// If pwd cannot change, then it is stupid to have "must change"
|
|
// marked by default.
|
|
CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, FALSE);
|
|
}
|
|
}
|
|
|
|
} // 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(CComBSTR(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);
|
|
}
|
|
}
|