Leaked source code of windows server 2003
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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: newuser.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. ////////////////////////////////////////////////////////////////////////////////////
  11. // newuser.cpp
  12. #include "stdafx.h"
  13. #include "dsutil.h"
  14. #include "newobj.h" // CNewADsObjectCreateInfo
  15. #include "dlgcreat.h"
  16. #include "querysup.h"
  17. #include "globals.h"
  18. #include <windowsx.h>
  19. #include <lmaccess.h>
  20. ///////////////////////////////////////////////////////////////
  21. ///////////////////////////////////////////////////////////////
  22. // NEW USER WIZARD
  23. ///////////////////////////////////////////////////////////////
  24. // CCreateNewUserPage1
  25. BEGIN_MESSAGE_MAP(CCreateNewUserPage1, CCreateNewObjectDataPage)
  26. ON_EN_CHANGE(IDC_EDIT_FIRST_NAME, OnNameChange)
  27. ON_EN_CHANGE(IDC_EDIT_INITIALS, OnNameChange)
  28. ON_EN_CHANGE(IDC_EDIT_LAST_NAME, OnNameChange)
  29. ON_EN_CHANGE(IDC_NT5_USER_EDIT, OnLoginNameChange)
  30. ON_EN_CHANGE(IDC_NT4_USER_EDIT, OnSAMNameChange)
  31. ON_EN_CHANGE(IDC_EDIT_FULL_NAME, OnFullNameChange)
  32. END_MESSAGE_MAP()
  33. CCreateNewUserPage1::CCreateNewUserPage1() :
  34. CCreateNewObjectDataPage(CCreateNewUserPage1::IDD)
  35. {
  36. m_bForcingNameChange = FALSE;
  37. }
  38. BOOL CCreateNewUserPage1::OnInitDialog()
  39. {
  40. CCreateNewObjectDataPage::OnInitDialog();
  41. VERIFY(_InitUI());
  42. return TRUE;
  43. }
  44. void CCreateNewUserPage1::GetSummaryInfo(CString& s)
  45. {
  46. // get the UPN name
  47. CString strDomain;
  48. GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
  49. CString strUPN = m_strLoginName + strDomain;
  50. // format the line
  51. CString szFmt;
  52. szFmt.LoadString(IDS_s_CREATE_NEW_SUMMARY_USER_UPN);
  53. CString szBuffer;
  54. szBuffer.Format((LPCWSTR)szFmt, (LPCWSTR)strUPN);
  55. s += szBuffer;
  56. }
  57. HRESULT CCreateNewUserPage1::SetData(BOOL bSilent)
  58. {
  59. //
  60. // start with a new temporary object
  61. //
  62. HRESULT hr;
  63. CString strDomain;
  64. GetDlgItemText (IDC_EDIT_FULL_NAME, OUT m_strFullName);
  65. GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
  66. m_strLoginName.TrimRight();
  67. m_strLoginName.TrimLeft();
  68. CString strUPN = m_strLoginName + strDomain;
  69. CString strDomainDNS = strDomain;
  70. CString strFilter;
  71. //
  72. // Store the object name in the temporary storage
  73. //
  74. CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
  75. //
  76. // create a new temporary ADs object
  77. //
  78. hr = pNewADsObjectCreateInfo->HrCreateNew(m_strFullName);
  79. if (FAILED(hr))
  80. {
  81. return hr;
  82. }
  83. BOOL fDomainSearchFailed = FALSE;
  84. BOOL fGCSearchFailed = FALSE;
  85. //
  86. // now validate UPN with current domain before doing the put.
  87. //
  88. CDSSearch DSS;
  89. IDirectorySearch *pGCObj = NULL;
  90. //
  91. // validate UPN with GC before doing the put.
  92. //
  93. CString strDomainName = m_LocalDomain.Right (m_LocalDomain.GetLength() - 1);
  94. hr = DSPROP_GetGCSearchOnDomain((LPWSTR)(LPCWSTR)strDomainName,
  95. IID_IDirectorySearch, (void **)&pGCObj);
  96. if (SUCCEEDED(hr))
  97. {
  98. hr = DSS.Init (pGCObj);
  99. if (SUCCEEDED(hr))
  100. {
  101. //
  102. // NTRAID#NTBUG9-257580-2000/12/14-jeffjon,
  103. // We must get an escaped filter because the UPN may contain "special" characters
  104. //
  105. CString szEscapedUPN;
  106. EscapeFilterElement(strUPN, szEscapedUPN);
  107. LPWSTR pAttributes[1] = {L"cn"};
  108. strFilter = L"(userPrincipalName=";
  109. strFilter += szEscapedUPN;
  110. strFilter += L")";
  111. TRACE(_T("searching global catalog for %s...\n"), strUPN);
  112. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  113. DSS.SetAttributeList (pAttributes, 1);
  114. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  115. DSS.DoQuery();
  116. hr = DSS.GetNextRow();
  117. TRACE(_T("done searching global catalog for %s...\n"), strUPN);
  118. }
  119. }
  120. if (hr == S_OK) // this means a row was returned, so we're dup
  121. {
  122. if (!bSilent)
  123. {
  124. PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strLoginName};
  125. ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_DUP,hr,
  126. MB_OK | MB_ICONWARNING, apv, 1);
  127. }
  128. return E_INVALIDARG;
  129. }
  130. if (hr != S_ADS_NOMORE_ROWS) // oops, had another problem
  131. {
  132. fGCSearchFailed = TRUE;
  133. }
  134. CString strInitPath = L"LDAP://";
  135. strInitPath += m_LocalDomain.Right (m_LocalDomain.GetLength() - 1);
  136. TRACE(_T("Initialize Domain search object with: %s...\n"), strInitPath);
  137. HRESULT hr2 = DSS.Init (strInitPath);
  138. if (SUCCEEDED(hr2))
  139. {
  140. CString szEscapedUPN;
  141. EscapeFilterElement(strUPN, szEscapedUPN);
  142. LPWSTR pAttributes2[1] = {L"cn"};
  143. strFilter = L"(userPrincipalName=";
  144. strFilter += szEscapedUPN;
  145. strFilter += L")";
  146. TRACE(_T("searching current domain for %s...\n"), strUPN);
  147. DSS.SetAttributeList (pAttributes2, 1);
  148. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  149. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  150. DSS.DoQuery();
  151. hr2 = DSS.GetNextRow();
  152. TRACE(_T("done searching current domain for %s...\n"), strUPN);
  153. }
  154. if (hr2 == S_OK) // this means a row was returned, so we're dup
  155. {
  156. if (!bSilent)
  157. {
  158. ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_DUP,hr2,
  159. MB_OK | MB_ICONWARNING, NULL, 0);
  160. }
  161. return E_INVALIDARG;
  162. }
  163. if (hr2 != S_ADS_NOMORE_ROWS) // oops, had another problem
  164. {
  165. fDomainSearchFailed = TRUE;
  166. }
  167. if (fDomainSearchFailed || fGCSearchFailed)
  168. {
  169. HRESULT hrSearch = S_OK;
  170. if (fDomainSearchFailed)
  171. {
  172. hrSearch = hr2;
  173. }
  174. else
  175. {
  176. hrSearch = hr;
  177. }
  178. if (!bSilent)
  179. {
  180. ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_SEARCH_FAILED,hrSearch,
  181. MB_OK | MB_ICONWARNING, NULL, 0);
  182. }
  183. }
  184. if (pGCObj)
  185. {
  186. pGCObj->Release();
  187. pGCObj = NULL;
  188. }
  189. GetDlgItemText (IDC_NT4_USER_EDIT, OUT m_strSAMName);
  190. m_strSAMName.TrimLeft();
  191. m_strSAMName.TrimRight();
  192. //
  193. // First check for illegal characters
  194. //
  195. int iFind = m_strSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS_WITH_AT);
  196. if (iFind != -1 && !m_strSAMName.IsEmpty())
  197. {
  198. PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strSAMName};
  199. if (!bSilent && IDYES == ReportErrorEx (::GetParent(m_hWnd),IDS_SAMNAME_ILLEGAL,S_OK,
  200. MB_YESNO | MB_ICONWARNING, apv, 1))
  201. {
  202. while (iFind != -1)
  203. {
  204. m_strSAMName.SetAt(iFind, L'_');
  205. iFind = m_strSAMName.FindOneOf(INVALID_ACCOUNT_NAME_CHARS_WITH_AT);
  206. }
  207. m_bForcingNameChange = TRUE;
  208. SetDlgItemText(IDC_NT4_USER_EDIT, m_strSAMName);
  209. m_bForcingNameChange = FALSE;
  210. }
  211. else
  212. {
  213. //
  214. // Set the focus to the edit box and select the text
  215. //
  216. GetDlgItem(IDC_NT4_USER_EDIT)->SetFocus();
  217. SendDlgItemMessage(IDC_NT4_USER_EDIT, EM_SETSEL, 0 , -1);
  218. return E_INVALIDARG;
  219. }
  220. }
  221. //
  222. // validate samAccountName with domain before doing the put.
  223. // There is no reason to verify the uniqueness against the GC
  224. // since sAMAccountName only has to be unique within the domain
  225. //
  226. CDSSearch DSSSAM;
  227. if (!fDomainSearchFailed && !fGCSearchFailed)
  228. {
  229. fDomainSearchFailed = FALSE;
  230. fGCSearchFailed = FALSE;
  231. hr2 = DSSSAM.Init (strInitPath);
  232. if (SUCCEEDED(hr2))
  233. {
  234. CString szEscapedSAMName;
  235. EscapeFilterElement(m_strSAMName, szEscapedSAMName);
  236. LPWSTR pAttributes2[1] = {L"cn"};
  237. strFilter = L"(samAccountName=";
  238. strFilter += szEscapedSAMName;
  239. strFilter += L")";
  240. TRACE(_T("searching current domain for %s...\n"), strUPN);
  241. DSSSAM.SetAttributeList (pAttributes2, 1);
  242. DSSSAM.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  243. DSSSAM.SetSearchScope (ADS_SCOPE_SUBTREE);
  244. DSSSAM.DoQuery();
  245. hr2 = DSSSAM.GetNextRow();
  246. TRACE(_T("done searching current domain for %s...\n"), strUPN);
  247. }
  248. if (hr2 == S_OK) // this means a row was returned, so we're dup
  249. {
  250. if (!bSilent)
  251. {
  252. ReportErrorEx (::GetParent(m_hWnd),IDS_SAMNAME_DUP,hr2,
  253. MB_OK | MB_ICONWARNING, NULL, 0);
  254. }
  255. return E_INVALIDARG;
  256. }
  257. if (hr2 != S_ADS_NOMORE_ROWS) // oops, had another problem
  258. {
  259. fDomainSearchFailed = TRUE;
  260. }
  261. if (fDomainSearchFailed)
  262. {
  263. HRESULT hrSearch = S_OK;
  264. if (fDomainSearchFailed)
  265. {
  266. hrSearch = hr2;
  267. }
  268. else
  269. {
  270. hrSearch = hr;
  271. }
  272. if (!bSilent)
  273. {
  274. ReportErrorEx (::GetParent(m_hWnd),IDS_UPN_SEARCH_FAILED,hrSearch,
  275. MB_OK | MB_ICONWARNING, NULL, 0);
  276. }
  277. }
  278. }
  279. if (pGCObj)
  280. {
  281. pGCObj->Release();
  282. }
  283. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(CComBSTR(gsz_samAccountName), m_strSAMName);
  284. ASSERT(SUCCEEDED(hr));
  285. strUPN.TrimRight();
  286. strUPN.TrimLeft();
  287. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(CComBSTR(L"userPrincipalName"), strUPN);
  288. ASSERT(SUCCEEDED(hr));
  289. m_strFullName.TrimLeft();
  290. m_strFullName.TrimRight();
  291. hr = pNewADsObjectCreateInfo->HrAddVariantBstr(CComBSTR(L"displayName"), m_strFullName);
  292. ASSERT(SUCCEEDED(hr));
  293. hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(L"givenName"), m_strFirstName);
  294. ASSERT(SUCCEEDED(hr));
  295. hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(L"initials"), m_strInitials);
  296. ASSERT(SUCCEEDED(hr));
  297. hr = pNewADsObjectCreateInfo->HrAddVariantBstrIfNotEmpty(CComBSTR(L"sn"), m_strLastName);
  298. ASSERT(SUCCEEDED(hr));
  299. return hr;
  300. }
  301. BOOL CCreateNewUserPage1::_InitUI()
  302. {
  303. CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
  304. IADs * pObj = NULL;
  305. CComBSTR bsPath;
  306. CComBSTR bsDN;
  307. LPWSTR pwzDomain = NULL;
  308. Edit_LimitText (GetDlgItem(IDC_EDIT_FULL_NAME)->m_hWnd, 64);
  309. Edit_LimitText (GetDlgItem(IDC_EDIT_LAST_NAME)->m_hWnd, 29);
  310. Edit_LimitText (GetDlgItem(IDC_EDIT_FIRST_NAME)->m_hWnd, 28);
  311. Edit_LimitText (GetDlgItem(IDC_EDIT_INITIALS)->m_hWnd, 6);
  312. Edit_LimitText (GetDlgItem(IDC_NT4_USER_EDIT)->m_hWnd, MAX_NT4_LOGON_LENGTH);
  313. Edit_LimitText (GetDlgItem(IDC_NT5_USER_EDIT)->m_hWnd, 256);
  314. HRESULT hr = pNewADsObjectCreateInfo->m_pIADsContainer->QueryInterface(
  315. IID_IADs, (void **)&pObj);
  316. if (SUCCEEDED(hr))
  317. {
  318. // get the DN of the container from its LDAP path
  319. pObj->get_ADsPath (&bsPath);
  320. { // scope for smart pointer
  321. CPathCracker pathCracker;
  322. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  323. pathCracker.Set(bsPath, ADS_SETTYPE_FULL);
  324. pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsDN);
  325. }
  326. // get the NT 5 (dns) domain name
  327. TRACE(L"CrackName(%s, &pwzDomain, GET_DNS_DOMAIN_NAME, NULL);\n", bsDN);
  328. hr = CrackName(bsDN, &pwzDomain, GET_DNS_DOMAIN_NAME, NULL);
  329. TRACE(L"CrackName returned hr = 0x%x, pwzDomain = <%s>\n", hr, pwzDomain);
  330. // get the NT 4 domain name from the DN
  331. LPWSTR pwzNT4Domain = NULL;
  332. TRACE(L"CrackName (%s, &pwzNT4Domain, GET_NT4_DOMAIN_NAME, NULL);\n", bsDN);
  333. hr = CrackName(bsDN, &pwzNT4Domain, GET_NT4_DOMAIN_NAME, NULL);
  334. TRACE(L"CrackName returned hr = 0x%x, pwzNT4Domain = <%s>\n", hr, pwzNT4Domain);
  335. // set the NT 4 domain name read only edit box
  336. if (pwzNT4Domain != NULL)
  337. {
  338. CString szBuffer;
  339. szBuffer.Format(L"%s\\", pwzNT4Domain);
  340. SetDlgItemText(IDC_NT4_DOMAIN_EDIT, szBuffer);
  341. LocalFreeStringW(&pwzNT4Domain);
  342. }
  343. }
  344. TRACE(L"After CrackName() calls, pwzDomain = <%s>\n", pwzDomain);
  345. // if we do not have a domain name, we cannot proceed further,
  346. // this is a catastrophic failure
  347. if (pwzDomain == NULL)
  348. {
  349. // should never get here in normal operations
  350. HWND hWndWiz = ::GetParent(m_hWnd);
  351. ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
  352. MB_OK | MB_ICONERROR, NULL, 0);
  353. // bail out of the wizard
  354. VERIFY(::PostMessage(hWndWiz, WM_COMMAND, IDCANCEL, 0));
  355. return TRUE;
  356. }
  357. m_LocalDomain = L"@";
  358. m_LocalDomain += pwzDomain;
  359. CComboBox * pCC = (CComboBox *)GetDlgItem (IDC_NT5_DOMAIN_COMBO);
  360. // get the current domain (only present if we're going around a second time
  361. // due an error.) need this to prevent dups when on second trip.
  362. CString strDomain;
  363. GetDlgItemText (IDC_NT5_DOMAIN_COMBO, OUT strDomain);
  364. CStringList UPNs;
  365. // get UPN suffixes from this OU, if present
  366. CComVariant Var;
  367. hr = pObj->Get ( CComBSTR(L"uPNSuffixes"), &Var);
  368. if (SUCCEEDED(hr))
  369. {
  370. hr = HrVariantToStringList (IN Var, UPNs);
  371. if (SUCCEEDED(hr))
  372. {
  373. POSITION pos = UPNs.GetHeadPosition();
  374. CString csSuffix;
  375. while (pos != NULL)
  376. {
  377. csSuffix = L"@";
  378. csSuffix += UPNs.GetNext(INOUT pos);
  379. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  380. pCC->AddString (csSuffix);
  381. }
  382. }
  383. }
  384. else
  385. {
  386. CString csPartitions;
  387. IADs * pPartitions = NULL;
  388. // get config path from main object
  389. csPartitions.Format(L"%sCN=Partitions,%s",
  390. pNewADsObjectCreateInfo->GetBasePathsInfo()->GetProviderAndServerName(),
  391. pNewADsObjectCreateInfo->GetBasePathsInfo()->GetConfigNamingContext());
  392. hr = DSAdminOpenObject(csPartitions,
  393. IID_IADs,
  394. (void **)&pPartitions,
  395. TRUE /*bServer*/);
  396. if (SUCCEEDED(hr))
  397. {
  398. CComVariant sVar;
  399. hr = pPartitions->Get ( CComBSTR(L"uPNSuffixes"), &sVar);
  400. if (SUCCEEDED(hr))
  401. {
  402. hr = HrVariantToStringList (IN sVar, UPNs);
  403. if (SUCCEEDED(hr))
  404. {
  405. POSITION pos = UPNs.GetHeadPosition();
  406. CString csSuffix;
  407. while (pos != NULL)
  408. {
  409. csSuffix = L"@";
  410. csSuffix += UPNs.GetNext(INOUT pos);
  411. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  412. if (wcscmp (strDomain, csSuffix))
  413. {
  414. pCC->AddString (csSuffix);
  415. }
  416. }
  417. }
  418. }
  419. pPartitions->Release();
  420. }
  421. // get rest of domains in this tree
  422. CComPtr <IDsBrowseDomainTree> spDsDomains;
  423. hr = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
  424. NULL,
  425. CLSCTX_INPROC_SERVER,
  426. IID_IDsBrowseDomainTree,
  427. (LPVOID*)&spDsDomains);
  428. if (FAILED(hr))
  429. {
  430. LocalFreeStringW(&pwzDomain);
  431. return FALSE;
  432. }
  433. LPCWSTR lpszServerName = GetWiz()->GetInfo()->GetBasePathsInfo()->GetServerName();
  434. hr = spDsDomains->SetComputer(lpszServerName, NULL, NULL);
  435. ASSERT(SUCCEEDED(hr));
  436. TRACE(L"returned from SetComputer(%s). hr is %lx\n", lpszServerName, hr);
  437. PDOMAIN_TREE pNewDomains = NULL;
  438. hr = spDsDomains->GetDomains(&pNewDomains, 0);
  439. TRACE(L"returned from GetDomains(), hr is %lx\n", hr);
  440. CString csRootDomain = L"@";
  441. INT pos = 0;
  442. UINT iRoot = 0;
  443. if (SUCCEEDED(hr) && pNewDomains)
  444. {
  445. TRACE(L"pNewDomains->dwCount = %d\n", pNewDomains->dwCount);
  446. for (UINT index = 0; index < pNewDomains->dwCount; index++)
  447. {
  448. TRACE(L"pNewDomains->aDomains[%d].pszName = <%s>\n", index, pNewDomains->aDomains[index].pszName);
  449. if (pNewDomains->aDomains[index].pszTrustParent == NULL)
  450. {
  451. //
  452. // Add the root domain only if it is a substring of the current
  453. // domain.
  454. //
  455. size_t cchRoot = wcslen(pNewDomains->aDomains[index].pszName);
  456. PWSTR pRoot = pwzDomain + wcslen(pwzDomain) - cchRoot;
  457. if (pRoot >= pwzDomain &&
  458. !_wcsicmp(pRoot, pNewDomains->aDomains[index].pszName))
  459. {
  460. csRootDomain += pNewDomains->aDomains[index].pszName;
  461. if (_wcsicmp (strDomain, csRootDomain))
  462. {
  463. pos = pCC->AddString (csRootDomain);
  464. }
  465. iRoot = index;
  466. }
  467. }
  468. }
  469. }
  470. // If the local domain is not the root, add it as well.
  471. //
  472. CString csOtherDomain = L"@";
  473. if (_wcsicmp(csRootDomain, m_LocalDomain))
  474. {
  475. if (_wcsicmp (strDomain, m_LocalDomain))
  476. {
  477. pos = pCC->AddString(m_LocalDomain);
  478. }
  479. }
  480. if (pNewDomains)
  481. {
  482. spDsDomains->FreeDomains(&pNewDomains);
  483. }
  484. LocalFreeStringW(&pwzDomain);
  485. }
  486. if (pObj)
  487. {
  488. pObj->Release();
  489. pObj = NULL;
  490. }
  491. //
  492. // If the local domain is not already in the list then add it
  493. //
  494. int iFind = pCC->FindStringExact(-1, m_LocalDomain);
  495. if (iFind == CB_ERR)
  496. {
  497. pCC->InsertString(0, m_LocalDomain);
  498. pCC->SetCurSel(0);
  499. }
  500. else
  501. {
  502. pCC->SetCurSel(iFind);
  503. }
  504. UpdateComboBoxDropWidth(pCC);
  505. m_nameFormatter.Initialize(pNewADsObjectCreateInfo->GetBasePathsInfo(),
  506. pNewADsObjectCreateInfo->m_pszObjectClass);
  507. return TRUE;
  508. }
  509. void
  510. CCreateNewUserPage1::UpdateComboBoxDropWidth(CComboBox* comboBox)
  511. {
  512. if (!comboBox)
  513. {
  514. return;
  515. }
  516. int nHorzExtent = 0;
  517. CClientDC dc(comboBox);
  518. int nItems = comboBox->GetCount();
  519. for (int i=0; i < nItems; i++)
  520. {
  521. CString szBuffer;
  522. comboBox->GetLBText(i, szBuffer);
  523. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  524. nHorzExtent = max(ext.cx ,nHorzExtent);
  525. }
  526. comboBox->SetDroppedWidth(nHorzExtent);
  527. }
  528. BOOL CCreateNewUserPage1::OnSetActive()
  529. {
  530. BOOL ret = CCreateNewObjectDataPage::OnSetActive();
  531. // Set the focus to the first field after the horizontal bar
  532. // To do this, first set the focus to the container name edit
  533. // box and then set the focus to the next control that has
  534. // a tabstop.
  535. // It has to be done this way instead of setting the focus
  536. // directly to the first name field because in Far East languages
  537. // they switch the last name and first name fields.
  538. GetParent()->PostMessage(
  539. WM_NEXTDLGCTL,
  540. (WPARAM)GetDlgItem(IDC_EDIT_CONTAINER)->GetSafeHwnd(),
  541. (LPARAM)TRUE);
  542. // By specifying zero for both LPARAM and WPARAM, the next
  543. // control with WS_TABSTOP should get the focus.
  544. GetParent()->PostMessage(
  545. WM_NEXTDLGCTL,
  546. 0,
  547. 0);
  548. GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
  549. !m_strFullName.IsEmpty() &&
  550. !m_strSAMName.IsEmpty()));
  551. return ret;
  552. }
  553. BOOL CCreateNewUserPage1::GetData(IADs* pIADsCopyFrom)
  554. {
  555. HRESULT hr = S_OK;
  556. if (pIADsCopyFrom != NULL)
  557. {
  558. // copy operation
  559. // we copy the UPN suffix
  560. CComVariant varData;
  561. hr = pIADsCopyFrom->Get(CComBSTR(L"userPrincipalName"), &varData);
  562. if (SUCCEEDED(hr) && varData.bstrVal != NULL)
  563. {
  564. // got something like "[email protected]."
  565. TRACE(L"source userPrincipalName: %s\n", varData.bstrVal);
  566. // need to get the suffix "@acme.com."
  567. PWSTR lpszUPNSuffix = wcschr(varData.bstrVal, L'@');
  568. if (lpszUPNSuffix)
  569. {
  570. TRACE(L"source UPN suffix: %s\n", lpszUPNSuffix);
  571. // need to find out of the suffix is already there
  572. CComboBox * pDomainCombo = (CComboBox *)GetDlgItem(IDC_NT5_DOMAIN_COMBO);
  573. int iIndex = pDomainCombo->FindString(-1, lpszUPNSuffix);
  574. if (iIndex == CB_ERR)
  575. {
  576. // not found, just add at the top
  577. pDomainCombo->InsertString(0, lpszUPNSuffix);
  578. iIndex = 0;
  579. }
  580. ASSERT( (iIndex >= 0) && (iIndex < pDomainCombo->GetCount()));
  581. // set the selection to the source UPN suffix
  582. pDomainCombo->SetCurSel(iIndex);
  583. }
  584. }
  585. return FALSE;
  586. }
  587. return (!m_strLoginName.IsEmpty() &&!m_strFullName.IsEmpty());
  588. }
  589. void CCreateNewUserPage1::OnNameChange()
  590. {
  591. GetDlgItemText(IDC_EDIT_FIRST_NAME, OUT m_strFirstName);
  592. GetDlgItemText(IDC_EDIT_INITIALS, OUT m_strInitials);
  593. GetDlgItemText(IDC_EDIT_LAST_NAME, OUT m_strLastName);
  594. m_strFirstName.TrimLeft();
  595. m_strFirstName.TrimRight();
  596. m_strInitials.TrimLeft();
  597. m_strInitials.TrimRight();
  598. m_strLastName.TrimLeft();
  599. m_strLastName.TrimRight();
  600. m_nameFormatter.FormatName(m_strFullName,
  601. m_strFirstName.IsEmpty() ? NULL : (LPCWSTR)m_strFirstName,
  602. m_strInitials.IsEmpty() ? NULL : (LPCWSTR)m_strInitials,
  603. m_strLastName.IsEmpty() ? NULL : (LPCWSTR)m_strLastName);
  604. SetDlgItemText (IDC_EDIT_FULL_NAME,
  605. IN m_strFullName);
  606. GetDlgItemText(IDC_NT5_USER_EDIT, OUT m_strLoginName);
  607. GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
  608. !m_strFullName.IsEmpty() &&
  609. !m_strSAMName.IsEmpty()));
  610. }
  611. void CCreateNewUserPage1::OnLoginNameChange()
  612. {
  613. if (!m_bForcingNameChange)
  614. {
  615. CString csSamName;
  616. GetDlgItemText(IDC_NT5_USER_EDIT, OUT m_strLoginName);
  617. csSamName = m_strLoginName.Left(20);
  618. SetDlgItemText (IDC_NT4_USER_EDIT, OUT csSamName);
  619. }
  620. GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
  621. !m_strFullName.IsEmpty() &&
  622. !m_strSAMName.IsEmpty()));
  623. }
  624. void CCreateNewUserPage1::OnSAMNameChange()
  625. {
  626. GetDlgItemText (IDC_NT4_USER_EDIT, OUT m_strSAMName);
  627. GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
  628. !m_strFullName.IsEmpty() &&
  629. !m_strSAMName.IsEmpty()));
  630. }
  631. void CCreateNewUserPage1::OnFullNameChange()
  632. {
  633. GetDlgItemText (IDC_EDIT_FULL_NAME, OUT m_strFullName);
  634. GetWiz()->SetWizardButtons(this, (!m_strLoginName.IsEmpty() &&
  635. !m_strFullName.IsEmpty() &&
  636. !m_strSAMName.IsEmpty()));
  637. }
  638. //
  639. BOOL CCreateNewUserPage1::OnError( HRESULT hr )
  640. {
  641. BOOL bRetVal = FALSE;
  642. if( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS )
  643. {
  644. HRESULT Localhr;
  645. DWORD LastError;
  646. WCHAR Buf1[256], Buf2[256];
  647. Localhr = ADsGetLastError (&LastError,
  648. Buf1, 256, Buf2, 256);
  649. switch( LastError )
  650. {
  651. case ERROR_USER_EXISTS:
  652. {
  653. PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strSAMName};
  654. ReportErrorEx (::GetParent(m_hWnd),IDS_ERROR_USER_EXISTS,hr,
  655. MB_OK|MB_ICONWARNING , apv, 1);
  656. bRetVal = TRUE;
  657. }
  658. break;
  659. case ERROR_DS_OBJ_STRING_NAME_EXISTS:
  660. {
  661. PVOID apv[1] = {(LPWSTR)(LPCWSTR)m_strFullName};
  662. ReportErrorEx (::GetParent(m_hWnd),IDS_ERROR_USER_DS_OBJ_STRING_NAME_EXISTS,hr,
  663. MB_OK|MB_ICONWARNING , apv, 1);
  664. bRetVal = TRUE;
  665. }
  666. break;
  667. }
  668. }
  669. return bRetVal;
  670. }
  671. ///////////////////////////////////////////////////////////////
  672. // CCreateNewUserPage2
  673. BEGIN_MESSAGE_MAP(CCreateNewUserPage2, CCreateNewObjectDataPage)
  674. ON_BN_CLICKED (IDC_CHECK_PASSWORD_MUST_CHANGE, OnPasswordPropsClick)
  675. ON_BN_CLICKED (IDC_CHECK_PASSWORD_NEVER_EXPIRES, OnPasswordPropsClick)
  676. ON_BN_CLICKED (IDC_CHECK_PASSWORD_CANNOT_CHANGE, OnPasswordPropsClick)
  677. END_MESSAGE_MAP()
  678. CCreateNewUserPage2::CCreateNewUserPage2() :
  679. CCreateNewObjectDataPage(CCreateNewUserPage2::IDD)
  680. {
  681. m_pPage1 = NULL;
  682. }
  683. BOOL CCreateNewUserPage2::OnInitDialog()
  684. {
  685. CCreateNewObjectDataPage::OnInitDialog();
  686. SendDlgItemMessage(IDC_EDIT_PASSWORD, EM_LIMITTEXT, (WPARAM)MAX_PASSWORD_LENGTH, 0);
  687. SendDlgItemMessage(IDC_EDIT_PASSWORD_CONFIRM, EM_LIMITTEXT, (WPARAM)MAX_PASSWORD_LENGTH, 0);
  688. CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, TRUE);
  689. return TRUE;
  690. }
  691. void CCreateNewUserPage2::_GetCheckBoxSummaryInfo(UINT nCtrlID, UINT nStringID, CString& s)
  692. {
  693. if (IsDlgButtonChecked(nCtrlID))
  694. {
  695. CString sz;
  696. sz.LoadString(nStringID);
  697. s += sz;
  698. s += L"\n";
  699. }
  700. }
  701. void CCreateNewUserPage2::GetSummaryInfo(CString& s)
  702. {
  703. _GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_MUST_CHANGE, IDS_USER_CREATE_DLG_PASSWORD_MUST_CHANGE, s);
  704. _GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_CANNOT_CHANGE, IDS_USER_CREATE_DLG_PASSWORD_CANNOT_CHANGE, s);
  705. _GetCheckBoxSummaryInfo(IDC_CHECK_PASSWORD_NEVER_EXPIRES, IDS_USER_CREATE_DLG_PASSWORD_NEVER_EXPIRES, s);
  706. _GetCheckBoxSummaryInfo(IDC_CHECK_ACCOUNT_DISABLED, IDS_USER_CREATE_DLG_ACCOUNT_DISABLED, s);
  707. }
  708. void
  709. CCreateNewUserPage2::OnPasswordPropsClick()
  710. {
  711. BOOL fPasswordMustChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_MUST_CHANGE);
  712. BOOL fPasswordCannotChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_CANNOT_CHANGE);
  713. BOOL fPasswordNeverExpires = IsDlgButtonChecked(IDC_CHECK_PASSWORD_NEVER_EXPIRES);
  714. if (fPasswordMustChange && fPasswordNeverExpires)
  715. {
  716. ReportErrorEx (::GetParent(m_hWnd),IDS_PASSWORD_MUTEX,S_OK,
  717. MB_OK, NULL, 0);
  718. CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, FALSE);
  719. fPasswordMustChange = FALSE;
  720. }
  721. if (fPasswordMustChange && fPasswordCannotChange)
  722. {
  723. ReportErrorEx (::GetParent(m_hWnd),IDS_ERR_BOTH_PW_BTNS,S_OK,
  724. MB_OK, NULL, 0);
  725. CheckDlgButton(IDC_CHECK_PASSWORD_CANNOT_CHANGE, FALSE);
  726. }
  727. }
  728. HRESULT CCreateNewUserPage2::SetData(BOOL bSilent)
  729. {
  730. // NTRAID#NTBUG9-684597-2002/08/09-artm
  731. // Use EncryptedStrings to hold passwords, guarantee scribbling out memory.
  732. EncryptedString password, confirmation;
  733. HRESULT hr = S_OK;
  734. hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD, password);
  735. if (SUCCEEDED(hr))
  736. {
  737. hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD_CONFIRM, confirmation);
  738. }
  739. if (FAILED(hr))
  740. {
  741. if (!bSilent)
  742. {
  743. ReportErrorEx(
  744. ::GetParent(m_hWnd),
  745. IDS_ERR_FATAL,
  746. hr,
  747. MB_OK | MB_ICONERROR,
  748. NULL,
  749. 0);
  750. }
  751. return hr;
  752. }
  753. if (password != confirmation)
  754. {
  755. if (!bSilent)
  756. {
  757. ReportErrorEx (::GetParent(m_hWnd),IDS_PASSWORDS_DONT_MATCH,S_OK,
  758. MB_OK, NULL, 0);
  759. }
  760. SetDlgItemText(IDC_EDIT_PASSWORD, L"");
  761. SetDlgItemText(IDC_EDIT_PASSWORD_CONFIRM, L"");
  762. SetDlgItemFocus(IDC_EDIT_PASSWORD);
  763. return E_INVALIDARG;
  764. }
  765. // intelligent copy of path info, it if is a copy operation
  766. {
  767. CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
  768. CCopyObjectHandlerBase* pCopyHandler = pNewADsObjectCreateInfo->GetCopyHandler();
  769. if (pCopyHandler != NULL)
  770. {
  771. IADs * pIADs = pNewADsObjectCreateInfo->PGetIADsPtr();
  772. ASSERT(pIADs != NULL);
  773. hr = pCopyHandler->Copy(pIADs, FALSE /*bPostCommit*/, ::GetParent(m_hWnd),
  774. m_pPage1->GetFullName());
  775. }
  776. }
  777. return hr;
  778. }
  779. //+----------------------------------------------------------------------------
  780. //
  781. // Method: _RevokeChangePasswordPrivilege
  782. //
  783. // Purpose: Revoke the user's change password privilege.
  784. //
  785. //-----------------------------------------------------------------------------
  786. HRESULT RevokeChangePasswordPrivilege(IADs * pIADs)
  787. {
  788. CChangePasswordPrivilegeAction ChangePasswordPrivilegeAction;
  789. HRESULT hr = ChangePasswordPrivilegeAction.Load(pIADs);
  790. if (FAILED(hr))
  791. {
  792. TRACE(L"ChangePasswordPrivilegeAction.Load() failed with hr = 0x%x\n", hr);
  793. return hr;
  794. }
  795. hr = ChangePasswordPrivilegeAction.Revoke();
  796. if (FAILED(hr))
  797. {
  798. TRACE(L"ChangePasswordPrivilegeAction.Revoke() failed with hr = 0x%x\n", hr);
  799. return hr;
  800. }
  801. return S_OK;
  802. }
  803. HRESULT CCreateNewUserPage2::OnPostCommit(BOOL bSilent)
  804. {
  805. // local variables
  806. HRESULT hr = E_FAIL;
  807. PVOID apv[1] = {(LPWSTR)(m_pPage1->GetFullName())};
  808. CWaitCursor Wait;
  809. CComPtr <IDirectoryObject> pIDSObject; // smart pointer, no need to release
  810. CComPtr <IADsUser> pIADsUser; // smart pointer, no need to release
  811. BOOL bCanEnable = TRUE;
  812. BOOL fPasswordMustChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_MUST_CHANGE);
  813. BOOL fPasswordCannotChange = IsDlgButtonChecked(IDC_CHECK_PASSWORD_CANNOT_CHANGE);
  814. BOOL fPasswordNeverExpires = IsDlgButtonChecked(IDC_CHECK_PASSWORD_NEVER_EXPIRES);
  815. BOOL fAccountEnabled = !IsDlgButtonChecked(IDC_CHECK_ACCOUNT_DISABLED);
  816. CComVariant varAccountFlags;
  817. // NTRAID#NTBUG9-684597-2002/08/09-artm
  818. // Store copy of password in encrypted string.
  819. EncryptedString password;
  820. hr = ::GetEncryptedDlgItemText(m_hWnd, IDC_EDIT_PASSWORD, password);
  821. if (FAILED(hr))
  822. {
  823. if (!bSilent)
  824. {
  825. ReportErrorEx(
  826. ::GetParent(m_hWnd),
  827. IDS_ERR_FATAL,
  828. hr,
  829. MB_OK | MB_ICONERROR,
  830. NULL,
  831. 0);
  832. }
  833. goto ExitCleanup;
  834. }
  835. // get object info and useful interfaces
  836. CNewADsObjectCreateInfo* pNewADsObjectCreateInfo = GetWiz()->GetInfo();
  837. ASSERT(pNewADsObjectCreateInfo != NULL);
  838. IADs * pIADs = pNewADsObjectCreateInfo->PGetIADsPtr();
  839. ASSERT(pIADs != NULL);
  840. // get the IDirectoryObject interface
  841. hr = pIADs->QueryInterface(IID_IDirectoryObject, OUT (void **)&pIDSObject);
  842. ASSERT(pIDSObject != NULL);
  843. if (FAILED(hr))
  844. {
  845. ASSERT(FALSE); // should never get here in normal operations
  846. if (!bSilent)
  847. {
  848. ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
  849. MB_OK | MB_ICONERROR, NULL, 0);
  850. }
  851. goto ExitCleanup;
  852. }
  853. // get the IADsUser interface
  854. hr = pIADs->QueryInterface(IID_IADsUser, OUT (void **)&pIADsUser);
  855. ASSERT(pIDSObject != NULL);
  856. if (FAILED(hr))
  857. {
  858. ASSERT(FALSE); // should never get here in normal operations
  859. if (!bSilent)
  860. {
  861. ReportErrorEx(::GetParent(m_hWnd),IDS_ERR_FATAL,hr,
  862. MB_OK | MB_ICONERROR, NULL, 0);
  863. }
  864. goto ExitCleanup;
  865. }
  866. // try to set password
  867. // NTRAID#NTBUG9-684597-2002/08/09-artm
  868. // Ensure that clear text copy scribbled out as soon as possible.
  869. ASSERT(pIADsUser != NULL);
  870. WCHAR* cleartext = password.GetClearTextCopy();
  871. if (cleartext != NULL)
  872. {
  873. hr = pIADsUser->SetPassword(CComBSTR(cleartext));
  874. }
  875. else
  876. {
  877. hr = E_OUTOFMEMORY;
  878. }
  879. password.DestroyClearTextCopy(cleartext);
  880. if (FAILED(hr))
  881. {
  882. if (hr != E_ACCESSDENIED)
  883. {
  884. if (!bSilent)
  885. {
  886. // fatal error, put up error message
  887. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PASSWORD,hr,
  888. MB_OK | MB_ICONERROR, apv, 1);
  889. }
  890. bCanEnable = FALSE;
  891. goto ExitCleanup;
  892. }
  893. else
  894. {
  895. if (!bSilent)
  896. {
  897. ReportErrorEx(::GetParent(m_hWnd),IDS_12_ACCESS_DENIED_SET_PASSWORD,hr,
  898. MB_OK | MB_ICONWARNING, apv, 1);
  899. }
  900. bCanEnable = FALSE;
  901. }
  902. }
  903. if (fPasswordMustChange)
  904. {
  905. LPWSTR szPwdLastSet = L"pwdLastSet";
  906. ADSVALUE ADsValuePwdLastSet = {ADSTYPE_LARGE_INTEGER, NULL};
  907. ADS_ATTR_INFO AttrInfoPwdLastSet = {szPwdLastSet, ADS_ATTR_UPDATE,
  908. ADSTYPE_LARGE_INTEGER,
  909. &ADsValuePwdLastSet, 1};
  910. ADsValuePwdLastSet.LargeInteger.QuadPart = 0;
  911. ASSERT(pIDSObject != NULL);
  912. DWORD cAttrModified = 0;
  913. hr = pIDSObject->SetObjectAttributes(&AttrInfoPwdLastSet, 1, &cAttrModified);
  914. if (FAILED(hr))
  915. {
  916. ASSERT(cAttrModified == 0);
  917. // fatal error, put up error message and bail out
  918. if (!bSilent)
  919. {
  920. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PWD_MUST_CHANGE,hr,
  921. MB_OK | MB_ICONERROR, apv, 1);
  922. }
  923. bCanEnable = FALSE;
  924. }
  925. ASSERT(cAttrModified == 1);
  926. } // if (fPasswordMustChange)
  927. if (fPasswordCannotChange)
  928. {
  929. hr = RevokeChangePasswordPrivilege(pIADs);
  930. if (FAILED(hr))
  931. {
  932. if (!bSilent)
  933. {
  934. // warning ad go on
  935. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_PWD_CANNOT_CHANGE,hr,
  936. MB_OK | MB_ICONWARNING, apv, 1);
  937. }
  938. bCanEnable = FALSE;
  939. hr = S_OK;
  940. }
  941. }
  942. // Set userAccountControl
  943. hr = pNewADsObjectCreateInfo->HrGetAttributeVariant(CComBSTR(gsz_userAccountControl), OUT &varAccountFlags);
  944. { // scope for local variables
  945. // if copy operation, makes sure we get the right set of bits copied over
  946. CCopyUserHandler* pCopyUserHandler =
  947. dynamic_cast<CCopyUserHandler*>(GetWiz()->GetInfo()->GetCopyHandler());
  948. if (pCopyUserHandler != NULL)
  949. {
  950. CComVariant varAccountControlSource;
  951. hr = pCopyUserHandler->GetCopyFrom()->Get(CComBSTR(gsz_userAccountControl), &varAccountControlSource);
  952. if (SUCCEEDED(hr))
  953. {
  954. ASSERT(varAccountControlSource.vt == VT_I4);
  955. // some bits are already set in the UI and the user can change them,
  956. // we will get them later on
  957. varAccountControlSource.vt &= ~UF_DONT_EXPIRE_PASSWD;
  958. varAccountControlSource.vt &= ~UF_ACCOUNTDISABLE;
  959. // add the remaining bits to the default ones after creation
  960. varAccountFlags.vt |= varAccountControlSource.vt;
  961. }
  962. }
  963. }
  964. if (SUCCEEDED(hr))
  965. {
  966. ASSERT(varAccountFlags.vt == VT_I4);
  967. if (fPasswordNeverExpires)
  968. varAccountFlags.lVal |= UF_DONT_EXPIRE_PASSWD;
  969. varAccountFlags.lVal &= ~UF_PASSWD_NOTREQD;
  970. // Update the userAccountControl attribute
  971. hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(CComBSTR(gsz_userAccountControl), varAccountFlags);
  972. ASSERT(SUCCEEDED(hr));
  973. hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent /* fSilentError */ );
  974. if (FAILED(hr))
  975. {
  976. if (HRESULT_CODE(hr) == ERROR_DS_UNWILLING_TO_PERFORM)
  977. {
  978. DWORD status;
  979. WCHAR Buf1[256], Buf2[256];
  980. ADsGetLastError (&status, Buf1, 256, Buf2, 256);
  981. TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
  982. status, Buf1, Buf2);
  983. if ((status == ERROR_PASSWORD_RESTRICTION) &&
  984. password.IsEmpty())
  985. {
  986. if (!bSilent)
  987. {
  988. ReportErrorEx(::GetParent(m_hWnd),IDS_NULL_PASSWORD,hr,
  989. MB_OK | MB_ICONERROR, NULL, 0);
  990. }
  991. goto ExitCleanup;
  992. }
  993. }
  994. // we failed, so we put up a warning and leave the object intact
  995. if (!bSilent)
  996. {
  997. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
  998. MB_OK | MB_ICONERROR, apv, 1);
  999. }
  1000. // reset error code, just a warning
  1001. bCanEnable = FALSE;
  1002. hr = S_OK;
  1003. }
  1004. }
  1005. else
  1006. {
  1007. TRACE1("INFO: Unable to get userAccountControl for user %s.\n",
  1008. m_pPage1->GetFullName());
  1009. // put up message box, but continue
  1010. if (!bSilent)
  1011. {
  1012. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
  1013. MB_OK | MB_ICONERROR, apv, 1);
  1014. }
  1015. // reset error code, just a warning
  1016. hr = S_OK;
  1017. }
  1018. // finally, if all went well, we can enable the user account
  1019. hr = S_OK;
  1020. if (bCanEnable & fAccountEnabled)
  1021. {
  1022. hr = pNewADsObjectCreateInfo->HrGetAttributeVariant(CComBSTR(gsz_userAccountControl), OUT &varAccountFlags);
  1023. varAccountFlags.lVal &= ~UF_ACCOUNTDISABLE;
  1024. hr = pNewADsObjectCreateInfo->HrAddVariantCopyVar(CComBSTR(gsz_userAccountControl), varAccountFlags);
  1025. hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent /* fSilentError */ );
  1026. if (FAILED(hr))
  1027. {
  1028. if (HRESULT_CODE(hr) == ERROR_DS_UNWILLING_TO_PERFORM)
  1029. {
  1030. DWORD status;
  1031. WCHAR Buf1[256], Buf2[256];
  1032. ADsGetLastError (&status, Buf1, 256, Buf2, 256);
  1033. TRACE(_T("ADsGetLastError returned status of %lx, error: %s, name %s\n"),
  1034. status, Buf1, Buf2);
  1035. if ((status == ERROR_PASSWORD_RESTRICTION) &&
  1036. password.IsEmpty())
  1037. {
  1038. //
  1039. // NTRAID#Windows Bugs-367611-2001/04/14-jeffjon
  1040. // DsAdmin: When password policy set, create usr with blank psswrd
  1041. // and 2 error msgs appear. One msg is enough
  1042. //
  1043. // This message is being handled from within the HrSetInfo above
  1044. // and is actually more descriptive. Probably a change to winerror.mc
  1045. //
  1046. /*
  1047. if (!bSilent)
  1048. {
  1049. ReportErrorEx(::GetParent(m_hWnd),IDS_NULL_PASSWORD,hr,
  1050. MB_OK | MB_ICONERROR, NULL, 0);
  1051. }
  1052. */
  1053. goto ExitCleanup;
  1054. }
  1055. }
  1056. // we failed, so we put up a warning and leave the object intact
  1057. if (!bSilent)
  1058. {
  1059. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_GET_USERACCOUNTCONTROL,hr,
  1060. MB_OK | MB_ICONERROR, apv, 1);
  1061. }
  1062. // reset error code, just a warning
  1063. hr = S_OK;
  1064. }
  1065. }
  1066. // try to set group membership, it if is a copy operation
  1067. {
  1068. CCopyObjectHandlerBase* pCopyHandler = GetWiz()->GetInfo()->GetCopyHandler();
  1069. if (pCopyHandler != NULL)
  1070. {
  1071. hr = pCopyHandler->Copy(pIADs, TRUE /*bPostCommit*/,::GetParent(m_hWnd),
  1072. m_pPage1->GetFullName());
  1073. if (SUCCEEDED(hr))
  1074. {
  1075. hr = pNewADsObjectCreateInfo->HrSetInfo(bSilent/* fSilentError */ );
  1076. }
  1077. if (FAILED(hr))
  1078. {
  1079. // we failed, so we put up a warning and leave the object intact
  1080. if (!bSilent)
  1081. {
  1082. ReportErrorEx(::GetParent(m_hWnd),IDS_12_CANT_SET_GROUP_MEMBERSHIP,hr,
  1083. MB_OK | MB_ICONERROR, apv, 1);
  1084. }
  1085. // reset error code, just a warning
  1086. hr = S_OK;
  1087. }
  1088. }
  1089. }
  1090. ExitCleanup:
  1091. return hr;
  1092. }
  1093. BOOL CCreateNewUserPage2::GetData(IADs* pIADsCopyFrom)
  1094. {
  1095. if (pIADsCopyFrom != NULL)
  1096. {
  1097. CString szFmt;
  1098. szFmt.LoadString(IDS_s_COPY_SUMMARY_NAME);
  1099. // we just get the CN of the object
  1100. CComVariant varAccountControl;
  1101. HRESULT hr = pIADsCopyFrom->Get(CComBSTR(gsz_userAccountControl), &varAccountControl);
  1102. if (SUCCEEDED(hr))
  1103. {
  1104. BOOL bPasswordNeverExpires = (varAccountControl.lVal & UF_DONT_EXPIRE_PASSWD) != 0;
  1105. BOOL bDisabled = (varAccountControl.lVal & UF_ACCOUNTDISABLE) != 0;
  1106. CheckDlgButton(IDC_CHECK_PASSWORD_NEVER_EXPIRES, bPasswordNeverExpires);
  1107. CheckDlgButton(IDC_CHECK_ACCOUNT_DISABLED, bDisabled);
  1108. } // if
  1109. CCopyUserHandler* pCopyUserHandler =
  1110. dynamic_cast<CCopyUserHandler*>(GetWiz()->GetInfo()->GetCopyHandler());
  1111. ASSERT(pCopyUserHandler != NULL);
  1112. if (pCopyUserHandler != NULL)
  1113. {
  1114. // set the cannot change password checkbox
  1115. BOOL bPasswordCannotChange = pCopyUserHandler->PasswordCannotChange();
  1116. CheckDlgButton(IDC_CHECK_PASSWORD_CANNOT_CHANGE, bPasswordCannotChange);
  1117. if (!bPasswordCannotChange)
  1118. {
  1119. // set the must change password checkbox
  1120. BOOL bPasswordMustChange = pCopyUserHandler->PasswordMustChange();
  1121. CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, bPasswordMustChange);
  1122. }
  1123. else
  1124. {
  1125. // NTRAID#NTBUG9-651998-2002/07/02-artm
  1126. // If pwd cannot change, then it is stupid to have "must change"
  1127. // marked by default.
  1128. CheckDlgButton(IDC_CHECK_PASSWORD_MUST_CHANGE, FALSE);
  1129. }
  1130. }
  1131. } // if
  1132. return TRUE;
  1133. }
  1134. ///////////////////////////////////////////////////////////////
  1135. // CCreateNewUserWizard
  1136. CCreateNewUserWizard::CCreateNewUserWizard(CNewADsObjectCreateInfo* pNewADsObjectCreateInfo) :
  1137. CCreateNewObjectWizardBase(pNewADsObjectCreateInfo)
  1138. {
  1139. AddPage(&m_page1);
  1140. AddPage(&m_page2);
  1141. m_page2.SetPage1(&m_page1);
  1142. }
  1143. void CCreateNewUserWizard::GetSummaryInfoHeader(CString& s)
  1144. {
  1145. IADs* pIADsCopyFrom = GetInfo()->GetCopyFromObject();
  1146. if (pIADsCopyFrom != NULL)
  1147. {
  1148. CString szFmt;
  1149. szFmt.LoadString(IDS_s_COPY_SUMMARY_NAME);
  1150. // we just get the CN of the object
  1151. CComVariant varName;
  1152. HRESULT hr = pIADsCopyFrom->Get(CComBSTR(L"cn"), &varName);
  1153. if (SUCCEEDED(hr))
  1154. {
  1155. CString szTmp;
  1156. szTmp.Format((LPCWSTR)szFmt, varName.bstrVal);
  1157. s += szTmp;
  1158. s += L"\n";
  1159. }
  1160. }
  1161. CCreateNewObjectWizardBase::GetSummaryInfoHeader(s);
  1162. }
  1163. void CCreateNewUserWizard::OnFinishSetInfoFailed(HRESULT hr)
  1164. {
  1165. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1166. if ( !( HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS &&
  1167. m_page1.OnError( hr ) ) )
  1168. {
  1169. // everything else is handled by the base class
  1170. CCreateNewObjectWizardBase::OnFinishSetInfoFailed(hr);
  1171. }
  1172. }