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.

1409 lines
42 KiB

  1. #include "setupp.h"
  2. #pragma hdrstop
  3. //
  4. // List of characters that are not legal in netnames.
  5. //
  6. PCWSTR IllegalNetNameChars = L"\"/\\[]:|<>+=;,?*";
  7. //
  8. // Computer name.
  9. //
  10. WCHAR ComputerName[DNS_MAX_LABEL_LENGTH+1];
  11. WCHAR Win32ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  12. BOOL IsNameTruncated;
  13. BOOL IsNameNonRfc;
  14. //
  15. // Copy disincentive name/organization strings.
  16. //
  17. WCHAR NameOrgName[MAX_NAMEORG_NAME+1];
  18. WCHAR NameOrgOrg[MAX_NAMEORG_ORG+1];
  19. #ifdef DOLOCALUSER
  20. //
  21. // User name and password
  22. //
  23. WCHAR UserName[MAX_USERNAME+1];
  24. WCHAR UserPassword[MAX_PASSWORD+1];
  25. BOOL CreateUserAccount = FALSE;
  26. #endif // def DOLOCALUSER
  27. //
  28. // Administrator password.
  29. //
  30. WCHAR CurrentAdminPassword[MAX_PASSWORD+1];
  31. WCHAR AdminPassword[MAX_PASSWORD+1];
  32. BOOL EncryptedAdminPasswordSet = FALSE;
  33. BOOL DontChangeAdminPassword = FALSE;
  34. // --------------------------------------------------------------------------
  35. // ::DisableEditSubClassProc
  36. //
  37. // Arguments: hwnd = See the platform SDK under WindowProc.
  38. // uMsg = See the platform SDK under WindowProc.
  39. // wParam = See the platform SDK under WindowProc.
  40. // lParam = See the platform SDK under WindowProc.
  41. // uiID = ID assigned at subclass time.
  42. // dwRefData = reference data assigned at subclass time.
  43. //
  44. // Returns: LRESULT
  45. //
  46. // Purpose: comctl32 subclass callback function. This allows us to not
  47. // process WM_CUT/WM_COPY/WM_PASTE/WM_CLEAR/WM_UNDO and any
  48. // other messages to be discarded.
  49. //
  50. // History: 2001-02-18 vtan created
  51. // --------------------------------------------------------------------------
  52. LRESULT CALLBACK DisableEditSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
  53. {
  54. LRESULT lResult;
  55. switch (uMsg)
  56. {
  57. case WM_CUT:
  58. case WM_COPY:
  59. case WM_PASTE:
  60. case WM_CLEAR:
  61. case WM_UNDO:
  62. case WM_CONTEXTMENU:
  63. lResult = FALSE;
  64. break;
  65. default:
  66. lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
  67. break;
  68. }
  69. return(lResult);
  70. }
  71. INT_PTR NoPasswordDlgProc(
  72. IN HWND hdlg,
  73. IN UINT msg,
  74. IN WPARAM wParam,
  75. IN LPARAM lParam
  76. )
  77. {
  78. HICON hicon = NULL;
  79. switch(msg) {
  80. case WM_INITDIALOG:
  81. // if we have the BB window, do the positioning on that. MainWindowHandle point to that window
  82. if (GetBBhwnd())
  83. CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE);
  84. else
  85. pSetupCenterWindowRelativeToParent(hdlg);
  86. if (hicon = LoadIcon(NULL, IDI_WARNING))
  87. {
  88. SendDlgItemMessage(hdlg, IDC_WARNING, STM_SETICON, (WPARAM)hicon, 0L);
  89. DestroyIcon(hicon);
  90. }
  91. // Make the No button the default button
  92. SetFocus(GetDlgItem(hdlg,IDCANCEL));
  93. return(FALSE);
  94. case WM_COMMAND:
  95. EndDialog (hdlg, wParam);
  96. break;
  97. default:
  98. return(FALSE);
  99. }
  100. return(TRUE);
  101. }
  102. INT_PTR WeakPasswordDlgProc(
  103. IN HWND hdlg,
  104. IN UINT msg,
  105. IN WPARAM wParam,
  106. IN LPARAM lParam
  107. )
  108. {
  109. HICON hicon = NULL;
  110. switch(msg) {
  111. case WM_INITDIALOG:
  112. {
  113. WCHAR szString[MAX_BUF];
  114. LPWSTR szAdminName = (LPWSTR)lParam;
  115. // if we have the BB window, do the positioning on that. MainWindowHandle point to that window
  116. if (GetBBhwnd())
  117. {
  118. CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE);
  119. }
  120. else
  121. {
  122. pSetupCenterWindowRelativeToParent(hdlg);
  123. }
  124. if (LoadString(MyModuleHandle,
  125. IDS_WEAKPASSWORD_MSG1,
  126. szString,
  127. MAX_BUF) != 0)
  128. {
  129. PWSTR szLine;
  130. szLine = RetrieveAndFormatMessage( szString, 0, szAdminName );
  131. if (szLine)
  132. {
  133. SetWindowText(GetDlgItem(hdlg, IDC_WEAK_MSG1),szLine);
  134. MyFree( szLine );
  135. }
  136. }
  137. if (hicon = LoadIcon(NULL, IDI_WARNING))
  138. {
  139. SendDlgItemMessage(hdlg, IDC_WARNING, STM_SETICON, (WPARAM)hicon, 0L);
  140. DestroyIcon(hicon);
  141. }
  142. // Make the No button the default button
  143. SetFocus(GetDlgItem(hdlg,IDCANCEL));
  144. }
  145. return(FALSE);
  146. case WM_COMMAND:
  147. EndDialog(hdlg, wParam);
  148. break;
  149. default:
  150. return(FALSE);
  151. }
  152. return(TRUE);
  153. }
  154. BOOL IsComplexPassword(LPWSTR szPassword)
  155. {
  156. BOOL bComplex = FALSE; // assume the password in not complex enough
  157. DWORD cchPassword;
  158. PWORD CharType;
  159. DWORD i;
  160. DWORD dwNum = 0;
  161. DWORD dwUpper = 0;
  162. DWORD dwLower = 0;
  163. DWORD dwSpecial = 0;
  164. //
  165. // check if the password is complex enough for our liking by
  166. // checking that at least two of the four character types are
  167. // present.
  168. //
  169. cchPassword = lstrlen(szPassword);
  170. CharType = LocalAlloc(LPTR, cchPassword * sizeof(WORD) );
  171. if (CharType == NULL)
  172. {
  173. return FALSE;
  174. }
  175. if (GetStringTypeW(
  176. CT_CTYPE1,
  177. szPassword,
  178. cchPassword,
  179. CharType
  180. ))
  181. {
  182. for (i = 0 ; i < cchPassword ; i++)
  183. {
  184. //
  185. // keep track of what type of characters we have encountered
  186. //
  187. if (CharType[i] & C1_DIGIT)
  188. {
  189. dwNum = 1;
  190. continue;
  191. }
  192. if (CharType[i] & C1_UPPER)
  193. {
  194. dwUpper = 1;
  195. continue;
  196. }
  197. if (CharType[i] & C1_LOWER)
  198. {
  199. dwLower = 1;
  200. continue;
  201. }
  202. if (!(CharType[i] & (C1_ALPHA | C1_DIGIT) ))
  203. {
  204. dwSpecial = 1;
  205. continue;
  206. }
  207. } // for
  208. //
  209. // Indicate whether we encountered enough password complexity
  210. //
  211. if ( (dwNum + dwUpper + dwLower + dwSpecial) > 2 )
  212. {
  213. bComplex = TRUE;
  214. }
  215. } // if
  216. LocalFree(CharType);
  217. return bComplex;
  218. }
  219. BOOL IsStrongPasswordEx(LPWSTR szPassword, LPWSTR szAdminAccountName)
  220. {
  221. BOOL bStrong = FALSE; // assume the password in not strong
  222. if ((lstrlen(szPassword) >= 6) &&
  223. (StrStrI(szPassword,L"Admin") == NULL) &&
  224. (StrStrI(szPassword,szAdminAccountName) == NULL))
  225. {
  226. bStrong = IsComplexPassword(szPassword);
  227. }
  228. return bStrong;
  229. }
  230. VOID
  231. GenerateName(
  232. OUT PWSTR GeneratedString,
  233. IN DWORD DesiredStrLen
  234. )
  235. {
  236. static DWORD Seed = 98725757;
  237. static PCWSTR UsableChars = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  238. //
  239. // How many characters will come from the org/name string.
  240. //
  241. DWORD BaseLength = 8;
  242. DWORD i,j;
  243. DWORD UsableCount;
  244. if( DesiredStrLen < BaseLength ) {
  245. BaseLength = DesiredStrLen - 1;
  246. }
  247. if( NameOrgOrg[0] ) {
  248. wcscpy( GeneratedString, NameOrgOrg );
  249. } else if( NameOrgName[0] ) {
  250. wcscpy( GeneratedString, NameOrgName );
  251. } else {
  252. wcscpy( GeneratedString, TEXT("X") );
  253. for( i = 1; i < BaseLength; i++ ) {
  254. wcscat( GeneratedString, TEXT("X") );
  255. }
  256. }
  257. //
  258. // Get him upper-case for our filter...
  259. //
  260. CharUpper(GeneratedString);
  261. //
  262. // Now we want to put a '-' at the end
  263. // of our GeneratedString. We'd like it to
  264. // be placed in the BASE_LENGTH character, but
  265. // the string may be shorter than that, or may
  266. // even have a ' ' in it. Figure out where to
  267. // put the '-' now.
  268. //
  269. for( i = 0; i <= BaseLength; i++ ) {
  270. //
  271. // Check for a short string.
  272. //
  273. if( (GeneratedString[i] == 0 ) ||
  274. (GeneratedString[i] == L' ') ||
  275. (!wcschr(UsableChars, GeneratedString[i])) ||
  276. (i == BaseLength )
  277. ) {
  278. GeneratedString[i] = L'-';
  279. GeneratedString[i+1] = 0;
  280. break;
  281. }
  282. }
  283. //
  284. // Special case the scenario where we had no usable
  285. // characters.
  286. //
  287. if( GeneratedString[0] == L'-' ) {
  288. GeneratedString[0] = 0;
  289. }
  290. UsableCount = lstrlen(UsableChars);
  291. Seed ^= GetCurrentTime();
  292. srand( Seed );
  293. j = lstrlen( GeneratedString );
  294. for( i = j; i < DesiredStrLen; i++ ) {
  295. GeneratedString[i] = UsableChars[rand() % UsableCount];
  296. }
  297. GeneratedString[i] = 0;
  298. //
  299. // In the normal case, the edit control in the wizard page
  300. // has the ES_UPPER bit set. In the normal unattend case
  301. // there is code in unattend.txt that uppercases the name.
  302. // But if we get to generating the name then then the text
  303. // in unattend.txt was * and we thus never had any text in
  304. // the edit control or unattend.txt to be uppercased.
  305. //
  306. CharUpper(GeneratedString);
  307. }
  308. BOOL
  309. ContainsDot(
  310. IN PCWSTR NameToCheck
  311. )
  312. /*++
  313. Routine Description:
  314. Determine whether a given name contains a '.'
  315. Arguments:
  316. NameToCheck - supplies name to be checked.
  317. Return Value:
  318. TRUE if the name contains a '.'; FALSE if not.
  319. --*/
  320. {
  321. UINT Length,u;
  322. if (!NameToCheck)
  323. return FALSE;
  324. Length = lstrlen(NameToCheck);
  325. for (u = 0; u < Length; u++) {
  326. if (NameToCheck[u] == L'.')
  327. return TRUE;
  328. }
  329. return FALSE;
  330. }
  331. BOOL
  332. IsNetNameValid(
  333. IN PCWSTR NameToCheck,
  334. IN BOOL AlphaNumericOnly
  335. )
  336. /*++
  337. Routine Description:
  338. Determine whether a given name is valid as a netname, such as
  339. a computer name.
  340. Arguments:
  341. NameToCheck - supplies name to be checked.
  342. Return Value:
  343. TRUE if the name is valid; FALSE if not.
  344. --*/
  345. {
  346. UINT Length,u;
  347. Length = lstrlen(NameToCheck);
  348. //
  349. // Want at least one character.
  350. //
  351. if(!Length) {
  352. return(FALSE);
  353. }
  354. //
  355. // Leading/trailing spaces are invalid.
  356. //
  357. if((NameToCheck[0] == L' ') || (NameToCheck[Length-1] == L' ')) {
  358. return(FALSE);
  359. }
  360. //
  361. // Control chars are invalid, as are characters in the illegal chars list.
  362. //
  363. for(u=0; u<Length; u++) {
  364. if (AlphaNumericOnly) {
  365. if (NameToCheck[u] == L'-' || NameToCheck[u] == L'_') {
  366. continue;
  367. }
  368. if (!iswalnum(NameToCheck[u])) {
  369. return(FALSE);
  370. }
  371. } else {
  372. if((NameToCheck[u] < L' ') || wcschr(IllegalNetNameChars,NameToCheck[u])) {
  373. return(FALSE);
  374. }
  375. }
  376. }
  377. //
  378. // We got here, name is ok.
  379. //
  380. return(TRUE);
  381. }
  382. BOOL SetIMEOpenStatus(
  383. IN HWND hDlg,
  384. IN BOOL bSetActive)
  385. {
  386. typedef HIMC (WINAPI* PFN_IMMGETCONTEXT)(HWND);
  387. typedef BOOL (WINAPI* PFN_IMMSETOPENSTATUS)(HIMC,BOOL);
  388. typedef BOOL (WINAPI* PFN_IMMGETOPENSTATUS)(HIMC);
  389. typedef BOOL (WINAPI* PFN_IMMRELEASECONTEXT)(HWND,HIMC);
  390. PFN_IMMGETCONTEXT PFN_ImmGetContext;
  391. PFN_IMMSETOPENSTATUS PFN_ImmSetOpenStatus;
  392. PFN_IMMGETOPENSTATUS PFN_ImmGetOpenStatus;
  393. PFN_IMMRELEASECONTEXT PFN_ImmReleaseContext;
  394. HIMC hIMC;
  395. HKL hKL;
  396. HMODULE hImmDll;
  397. static BOOL bImeEnable=TRUE;
  398. hKL = GetKeyboardLayout(0);
  399. if ((HIWORD(HandleToUlong(hKL)) & 0xF000) != 0xE000) {
  400. //
  401. // not an IME, do nothing !
  402. //
  403. return TRUE;
  404. }
  405. hImmDll = GetModuleHandle(TEXT("IMM32.DLL"));
  406. if (hImmDll == NULL) {
  407. //
  408. // weird case, if the kbd layout is an IME, then
  409. // Imm32.dll should have already been loaded into process.
  410. //
  411. return FALSE;
  412. }
  413. PFN_ImmGetContext = (PFN_IMMGETCONTEXT) GetProcAddress(hImmDll,"ImmGetContext");
  414. if (PFN_ImmGetContext == NULL) {
  415. return FALSE;
  416. }
  417. PFN_ImmReleaseContext = (PFN_IMMRELEASECONTEXT) GetProcAddress(hImmDll,"ImmReleaseContext");
  418. if (PFN_ImmReleaseContext == NULL) {
  419. return FALSE;
  420. }
  421. PFN_ImmSetOpenStatus = (PFN_IMMSETOPENSTATUS) GetProcAddress(hImmDll,"ImmSetOpenStatus");
  422. if (PFN_ImmSetOpenStatus == NULL) {
  423. return FALSE;
  424. }
  425. PFN_ImmGetOpenStatus = (PFN_IMMGETOPENSTATUS) GetProcAddress(hImmDll,"ImmGetOpenStatus");
  426. if (PFN_ImmGetOpenStatus == NULL) {
  427. return FALSE;
  428. }
  429. //
  430. // Get Current Input Context.
  431. //
  432. hIMC = PFN_ImmGetContext(hDlg);
  433. if (hIMC == NULL) {
  434. return FALSE;
  435. }
  436. if (bSetActive) {
  437. PFN_ImmSetOpenStatus(hIMC,bImeEnable);
  438. }
  439. else {
  440. //
  441. // Save Current Status.
  442. //
  443. bImeEnable = PFN_ImmGetOpenStatus(hIMC);
  444. //
  445. // Close IME.
  446. //
  447. PFN_ImmSetOpenStatus(hIMC,FALSE);
  448. }
  449. PFN_ImmReleaseContext(hDlg,hIMC);
  450. return TRUE;
  451. }
  452. // returns TRUE if the name is valid, FALSE if it is not
  453. BOOL ValidateNameOrgName (
  454. WCHAR* pszName
  455. )
  456. {
  457. WCHAR adminName[MAX_USERNAME+1];
  458. WCHAR guestName[MAX_USERNAME+1];
  459. LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
  460. LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
  461. if ( pszName == NULL )
  462. return FALSE;
  463. if(pszName[0] == 0)
  464. return FALSE;
  465. if(lstrcmpi(pszName,adminName) == 0 )
  466. return FALSE;
  467. if ( lstrcmpi(pszName,guestName) == 0 )
  468. return FALSE;
  469. return TRUE;
  470. }
  471. INT_PTR
  472. CALLBACK
  473. NameOrgDlgProc(
  474. IN HWND hdlg,
  475. IN UINT msg,
  476. IN WPARAM wParam,
  477. IN LPARAM lParam
  478. )
  479. {
  480. NMHDR *NotifyParams;
  481. switch(msg) {
  482. case WM_INITDIALOG: {
  483. //
  484. // Limit text fields to maximum lengths
  485. //
  486. SendDlgItemMessage(hdlg,IDT_NAME,EM_LIMITTEXT,MAX_NAMEORG_NAME,0);
  487. SendDlgItemMessage(hdlg,IDT_ORGANIZATION,EM_LIMITTEXT,MAX_NAMEORG_ORG,0);
  488. //
  489. // Set Initial Values
  490. //
  491. SetDlgItemText(hdlg,IDT_NAME,NameOrgName);
  492. SetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg);
  493. break;
  494. }
  495. case WM_IAMVISIBLE:
  496. //
  497. // If an error occured during out INIT phase, show the box to the
  498. // user so that they know there is a problem
  499. //
  500. MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,
  501. MB_OK | MB_ICONSTOP);
  502. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  503. break;
  504. case WM_SIMULATENEXT:
  505. // Simulate the next button somehow
  506. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  507. break;
  508. case WM_COMMAND:
  509. if (HIWORD(wParam) == EN_CHANGE) {
  510. if(LOWORD(wParam) == IDT_ORGANIZATION) {
  511. GetDlgItemText( hdlg, IDT_ORGANIZATION, NameOrgOrg, MAX_NAMEORG_ORG+1);
  512. #ifdef DOLOCALUSER
  513. } else if(LOWORD(wParam) == IDT_NAME) {
  514. GetDlgItemText( hdlg, IDT_NAME, NameOrgName, MAX_NAMEORG_NAME+1);
  515. #endif
  516. }
  517. }
  518. break;
  519. case WMX_VALIDATE:
  520. //
  521. // lParam == 0 for no UI, or 1 for UI
  522. // Return 1 for success, -1 for error.
  523. //
  524. GetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg,MAX_NAMEORG_ORG+1);
  525. GetDlgItemText(hdlg,IDT_NAME,NameOrgName,MAX_NAMEORG_NAME+1);
  526. // JMH - NameOrgName cannot be "Administrator", "Guest" or "" (blank).
  527. if(ValidateNameOrgName(NameOrgName) == FALSE) {
  528. //
  529. // Skip UI?
  530. //
  531. if (!lParam) {
  532. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  533. }
  534. //
  535. // Tell user he must at least enter a name, and
  536. // don't allow next page to be activated.
  537. //
  538. if (Unattended) {
  539. UnattendErrorDlg(hdlg,IDD_NAMEORG);
  540. } // if
  541. MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  542. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  543. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  544. }
  545. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  546. case WM_NOTIFY:
  547. NotifyParams = (NMHDR *)lParam;
  548. switch(NotifyParams->code) {
  549. case PSN_SETACTIVE:
  550. TESTHOOK(503);
  551. BEGIN_SECTION(L"Personalize Your Software Page");
  552. SetWizardButtons(hdlg,WizPageNameOrg);
  553. if (Unattended) {
  554. if (!UnattendSetActiveDlg(hdlg,IDD_NAMEORG)) {
  555. break;
  556. }
  557. }
  558. // Page becomes active, make page visible.
  559. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  560. //
  561. // Set focus on the name edit control.
  562. //
  563. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  564. //
  565. // Open/Close IME.
  566. //
  567. SetIMEOpenStatus(hdlg,TRUE);
  568. break;
  569. case PSN_WIZNEXT:
  570. case PSN_WIZFINISH:
  571. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  572. break;
  573. case PSN_KILLACTIVE:
  574. WizardKillHelp(hdlg);
  575. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
  576. //
  577. // Close IME.
  578. //
  579. SetIMEOpenStatus(hdlg,FALSE);
  580. END_SECTION(L"Personalize Your Software Page");
  581. break;
  582. case PSN_HELP:
  583. WizardBringUpHelp(hdlg,WizPageNameOrg);
  584. break;
  585. default:
  586. break;
  587. }
  588. break;
  589. default:
  590. return(FALSE);
  591. }
  592. return(TRUE);
  593. }
  594. INT_PTR
  595. CALLBACK
  596. ComputerNameDlgProc(
  597. IN HWND hdlg,
  598. IN UINT msg,
  599. IN WPARAM wParam,
  600. IN LPARAM lParam
  601. )
  602. {
  603. NMHDR *NotifyParams;
  604. DWORD err, Win32NameSize = MAX_COMPUTERNAME_LENGTH + 1;
  605. static BOOL EncryptedAdminPasswordBad = FALSE;
  606. static BOOL bPersonal = FALSE;
  607. switch(msg) {
  608. case WM_INITDIALOG: {
  609. bPersonal = ( GetProductFlavor() == 4);
  610. //
  611. // Limit text to maximum length
  612. //
  613. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,DNS_MAX_LABEL_LENGTH,0);
  614. if (!bPersonal)
  615. {
  616. SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
  617. SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
  618. }
  619. SetWindowSubclass(GetDlgItem(hdlg, IDT_EDIT2), DisableEditSubClassProc, IDT_EDIT2, 0);
  620. SetWindowSubclass(GetDlgItem(hdlg, IDT_EDIT3), DisableEditSubClassProc, IDT_EDIT3, 0);
  621. //
  622. // Set the Edit boxes to the initial text
  623. //
  624. //
  625. // Generate a computer name if we're unattended and
  626. // the user has requested a random name, or if we're
  627. // attended.
  628. //
  629. GenerateName( ComputerName, 15 );
  630. if( (Unattended) &&
  631. (UnattendAnswerTable[UAE_COMPNAME].Answer.String) &&
  632. (UnattendAnswerTable[UAE_COMPNAME].Answer.String[0] == L'*') ) {
  633. //
  634. // The unattend engine has asked us to generate a Computer
  635. // name. Let's write the data back into the unattend
  636. // database.
  637. //
  638. MyFree( UnattendAnswerTable[UAE_COMPNAME].Answer.String );
  639. UnattendAnswerTable[UAE_COMPNAME].Answer.String = ComputerName;
  640. }
  641. if (!bPersonal)
  642. {
  643. if(DontChangeAdminPassword) {
  644. EnableWindow(GetDlgItem(hdlg,IDT_EDIT2),FALSE);
  645. EnableWindow(GetDlgItem(hdlg,IDT_EDIT3),FALSE);
  646. } else {
  647. SetDlgItemText(hdlg,IDT_EDIT2,AdminPassword);
  648. SetDlgItemText(hdlg,IDT_EDIT3,AdminPassword);
  649. }
  650. }
  651. break;
  652. }
  653. case WM_IAMVISIBLE:
  654. MessageBoxFromMessage(
  655. hdlg,
  656. ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
  657. NULL,
  658. IDS_ERROR,MB_OK|MB_ICONSTOP);
  659. break;
  660. case WM_SIMULATENEXT:
  661. // Simulate the next button somehow
  662. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  663. break;
  664. case WMX_VALIDATE:
  665. //
  666. // lParam == 0 for no UI, or 1 for UI
  667. // Return 1 for success, -1 for error.
  668. //
  669. IsNameNonRfc = FALSE;
  670. IsNameTruncated = FALSE;
  671. GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
  672. // StrTrim removes both leading and trailing spaces
  673. StrTrim(ComputerName, TEXT(" "));
  674. if (ContainsDot(ComputerName)) {
  675. err = ERROR_INVALID_NAME;
  676. } else {
  677. err = DnsValidateDnsName_W(ComputerName);
  678. if (err == DNS_ERROR_NON_RFC_NAME) {
  679. IsNameNonRfc = TRUE;
  680. err = ERROR_SUCCESS;
  681. }
  682. if(err == ERROR_SUCCESS) {
  683. //The name is a valid DNS name. Now verify that it is
  684. //also a valid WIN32 computer name.
  685. if (!DnsHostnameToComputerNameW(ComputerName,
  686. Win32ComputerName,
  687. &Win32NameSize) ||
  688. !IsNetNameValid(Win32ComputerName, FALSE)) {
  689. err = ERROR_INVALID_NAME;
  690. }
  691. else {
  692. if (Win32NameSize < (UINT)lstrlen(ComputerName) ) {
  693. //The DNSName was truncated to get a Win32 ComputerName.
  694. IsNameTruncated = TRUE;
  695. }
  696. }
  697. }
  698. }
  699. //
  700. // If the name has non-RFC characters or if it was truncated, warn
  701. // user if it is not an unattended install and we have GUI.
  702. //
  703. if (err == ERROR_SUCCESS && !Unattended && lParam) {
  704. if (IsNameNonRfc) {
  705. //ComputerName has non-standard characters.
  706. if (MessageBoxFromMessage(
  707. hdlg,
  708. MSG_DNS_NON_RFC_NAME,
  709. NULL,
  710. IDS_SETUP,MB_YESNO|MB_ICONWARNING,
  711. ComputerName) == IDNO) {
  712. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  713. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  714. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  715. }
  716. }
  717. if (IsNameTruncated) {
  718. //The computer name was truncated.
  719. if (MessageBoxFromMessage(
  720. hdlg,
  721. MSG_DNS_NAME_TRUNCATED,
  722. NULL,
  723. IDS_SETUP,MB_YESNO|MB_ICONWARNING,
  724. ComputerName, Win32ComputerName) == IDNO) {
  725. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  726. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  727. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  728. }
  729. }
  730. }
  731. if(err == ERROR_SUCCESS) {
  732. WCHAR pw1[MAX_PASSWORD+1],pw2[MAX_PASSWORD+1];
  733. if (bPersonal)
  734. {
  735. // if we are in personal we are done.
  736. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  737. }
  738. //
  739. // Good computer name. Now make sure passwords match.
  740. //
  741. GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
  742. GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
  743. if(lstrcmp(pw1,pw2)) {
  744. //
  745. // Skip UI?
  746. //
  747. if (!lParam) {
  748. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  749. }
  750. //
  751. //
  752. // Inform user of password mismatch, and don't allow next page
  753. // to be activated.
  754. //
  755. if (Unattended) {
  756. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  757. }
  758. MessageBoxFromMessage(hdlg,MSG_PW_MISMATCH,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  759. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  760. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  761. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  762. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  763. } else {
  764. WCHAR adminName[MAX_USERNAME+1];
  765. BOOL bContinue = TRUE;
  766. GetAdminAccountName( adminName );
  767. // We do the password check only on Server SKUs and if
  768. // We are in GUI Attended or ProvideDefault mode
  769. if ( (UnattendMode == UAM_GUIATTENDED)
  770. && (ProductType != PRODUCT_WORKSTATION))
  771. {
  772. if (*pw1 == L'\0')
  773. {
  774. // Warning about empty password
  775. bContinue = (DialogBox(MyModuleHandle,
  776. MAKEINTRESOURCE(IDD_NOPASSWORD),
  777. hdlg,
  778. NoPasswordDlgProc) == IDOK);
  779. }
  780. else if (!IsStrongPasswordEx(pw1, adminName))
  781. {
  782. // warning about weak password
  783. bContinue = (DialogBoxParam(MyModuleHandle,
  784. MAKEINTRESOURCE(IDD_WEAKPASSWORD),
  785. hdlg,
  786. WeakPasswordDlgProc, (LPARAM)&adminName) == IDOK);
  787. }
  788. }
  789. if (bContinue)
  790. {
  791. //
  792. // Process the encrypted password if
  793. // 1) We are unattended and
  794. // 2) The EncryptedAdminPassword key is "Yes" in the unatttend file and
  795. // 3) We are not back here after setting it - i.e. via the back button etc.
  796. // 4) We are not back here after failing to set it once.
  797. if( Unattended && IsEncryptedAdminPasswordPresent() &&
  798. !DontChangeAdminPassword && !EncryptedAdminPasswordBad){
  799. // Logging is done inside the call to ProcessEncryptedAdminPassword
  800. if(!(ProcessEncryptedAdminPassword(adminName))){
  801. EncryptedAdminPasswordBad = TRUE;
  802. // Page becomes active, make page visible.
  803. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  804. // Inform the user and enable the password fields
  805. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  806. MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
  807. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  808. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  809. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  810. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  811. }else{
  812. EncryptedAdminPasswordSet = TRUE;
  813. //
  814. // Set DontChangeAdminPassword to avoid the user from ever trying to
  815. // reset the password using the dialog. This is needed in the case where the
  816. // unattend fails, say, in the next page and the user gets here using the back button.
  817. //
  818. DontChangeAdminPassword = TRUE;
  819. }
  820. }else{
  821. //
  822. // They match; allow next page to be activated.
  823. //
  824. if (Unattended && pw1[0] == L'*') {
  825. pw1[0] = L'\0';
  826. }
  827. // Set administrator password. We need to do some checking here though.
  828. // There are 3 scenarios that can occur in mini-setup:
  829. // 1. The OEM doesn't want to have the admin password changed.
  830. // In this case, he's set OEMAdminPassword = "NoChange". If that's
  831. // what we find, we don't assign the password. Remember that this
  832. // system has already been installed, so there's already an admin
  833. // password.
  834. // 2. The OEM wants to set the admin password to a specific string.
  835. // In this case, he's set OEMAdminPassword = <some quoted word>.
  836. // If this is the case, we've already caught this string in the
  837. // wizard page.
  838. // 3. The OEM wants to let the user set the admin password. In this
  839. // case, there's no OEMAdminpassword in the answer file. If this
  840. // is the case, we've already caught this and gotten a password
  841. // from the user in the wizard page.
  842. //
  843. // The good news is that the unattend engine has already looked
  844. // for a password in the unattend file called "NoChange" and has
  845. // set a global called "DontChangeAdminPassword" to indicate.
  846. if(!DontChangeAdminPassword) {
  847. lstrcpy(AdminPassword,pw1);
  848. //
  849. // The user may have changed the name of the Administrator
  850. // account. We'll call some special code to retrieve the
  851. // name on the account. This is really only needed in the
  852. // case of a sysprep run, but it can't hurt to do it always.
  853. //
  854. // In the Win9x case their code in winnt32 generates a random
  855. // password and passes it to us through the unattend file and
  856. // so we set it here and do the right thing.
  857. // For Minisetup the behavior for now is to silently fail setting
  858. // the admin password if there was an existing Password on the system.
  859. // WE only allow setting the admin password from NULL i.e. one time change.
  860. // In any other case we log the error and move on.
  861. //
  862. if(!SetLocalUserPassword(adminName,CurrentAdminPassword,AdminPassword) && !MiniSetup) {
  863. SetupDebugPrint( L"SETUP: SetLocalUserPassword failed" );
  864. // Page becomes active, make page visible.
  865. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  866. MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
  867. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  868. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  869. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  870. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  871. }
  872. //
  873. // Now store this so that we work fine when the user comes to this page by hitting "Back".
  874. //
  875. lstrcpy( CurrentAdminPassword, AdminPassword );
  876. }
  877. }
  878. }
  879. else
  880. {
  881. // Either empty or weak password and user wants to change it.
  882. // Stay on the page
  883. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  884. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  885. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  886. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  887. }
  888. }
  889. } else {
  890. //
  891. // Skip UI?
  892. //
  893. if (!lParam) {
  894. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  895. }
  896. //
  897. // Inform user of bogus computer name, and don't allow next page
  898. // to be activated.
  899. //
  900. if (Unattended) {
  901. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  902. }
  903. MessageBoxFromMessage(
  904. hdlg,
  905. ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
  906. NULL,
  907. IDS_ERROR,MB_OK|MB_ICONSTOP
  908. );
  909. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  910. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  911. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  912. }
  913. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  914. case WM_NOTIFY:
  915. NotifyParams = (NMHDR *)lParam;
  916. switch(NotifyParams->code) {
  917. case PSN_SETACTIVE:
  918. TESTHOOK(504);
  919. BEGIN_SECTION(L"Computer Name Page");
  920. SetWizardButtons(hdlg,WizPageComputerName);
  921. //
  922. // Load ComputerName because it may have been set when the user
  923. // entered the organization name.
  924. //
  925. SetDlgItemText(hdlg,IDT_EDIT1,ComputerName);
  926. if(Unattended && !UnattendSetActiveDlg(hdlg,IDD_COMPUTERNAME)) {
  927. break;
  928. }
  929. //
  930. // Post ourselves a message we'll get once displayed.
  931. //
  932. PostMessage(hdlg,WM_USER,0,0);
  933. break;
  934. case PSN_WIZBACK:
  935. //
  936. // Save ComputerName because we're going to load it into the dialog
  937. // again when we come back.
  938. //
  939. GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
  940. break;
  941. case PSN_WIZNEXT:
  942. case PSN_WIZFINISH:
  943. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  944. break;
  945. case PSN_KILLACTIVE:
  946. WizardKillHelp(hdlg);
  947. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
  948. END_SECTION(L"Computer Name Page");
  949. break;
  950. case PSN_HELP:
  951. WizardBringUpHelp(hdlg,WizPageComputerName);
  952. break;
  953. default:
  954. break;
  955. }
  956. break;
  957. case WM_USER:
  958. // Page becomes active, make page visible.
  959. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  960. //
  961. // Select the computer name string and set focus to it.
  962. //
  963. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  964. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  965. break;
  966. default:
  967. return(FALSE);
  968. }
  969. return(TRUE);
  970. }
  971. #ifdef DOLOCALUSER
  972. BOOL
  973. CheckUserAccountData(
  974. IN HWND hdlg,
  975. OUT BOOL ValidateOnly
  976. )
  977. {
  978. WCHAR userName[MAX_USERNAME+1];
  979. WCHAR pw1[MAX_PASSWORD+1];
  980. WCHAR pw2[MAX_PASSWORD+1];
  981. WCHAR adminName[MAX_USERNAME+1];
  982. WCHAR guestName[MAX_USERNAME+1];
  983. UINT MessageId;
  984. FocusId = 0;
  985. //
  986. // Load names of built-in accounts.
  987. //
  988. LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
  989. LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
  990. //
  991. // Fetch data user typed in for username and password.
  992. //
  993. GetDlgItemText(hdlg,IDT_EDIT1,userName,MAX_USERNAME+1);
  994. GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
  995. GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
  996. if(lstrcmpi(userName,adminName) && lstrcmpi(userName,guestName)) {
  997. if(userName[0]) {
  998. if(IsNetNameValid(userName,FALSE)) {
  999. if(lstrcmp(pw1,pw2)) {
  1000. //
  1001. // Passwords don't match.
  1002. //
  1003. MessageId = MSG_PW_MISMATCH;
  1004. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  1005. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  1006. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  1007. } else {
  1008. //
  1009. // Name is non-empty, is not a built-in, is valid,
  1010. // and the passwords match.
  1011. //
  1012. MessageId = 0;
  1013. }
  1014. } else {
  1015. //
  1016. // Name is not valid.
  1017. //
  1018. MessageId = MSG_BAD_USER_NAME1;
  1019. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  1020. }
  1021. } else {
  1022. //
  1023. // Don't allow empty name.
  1024. //
  1025. MessageId = MSG_BAD_USER_NAME2;
  1026. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  1027. }
  1028. } else {
  1029. //
  1030. // User entered name of a built-in account.
  1031. //
  1032. MessageId = MSG_BAD_USER_NAME3;
  1033. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  1034. }
  1035. if(MessageId && !ValidateOnly) {
  1036. MessageBoxFromMessage(hdlg,MessageId,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  1037. }
  1038. return(MessageId == 0);
  1039. }
  1040. BOOL
  1041. CALLBACK
  1042. UserAccountDlgProc(
  1043. IN HWND hdlg,
  1044. IN UINT msg,
  1045. IN WPARAM wParam,
  1046. IN LPARAM lParam
  1047. )
  1048. {
  1049. NMHDR *NotifyParams;
  1050. switch(msg) {
  1051. case WM_INITDIALOG:
  1052. //
  1053. // Limit text to maximum length of a user account name,
  1054. // and limit password text to max langth of a password.
  1055. // Also set initial text.
  1056. //
  1057. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,MAX_USERNAME,0);
  1058. SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
  1059. SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
  1060. SetDlgItemText(hdlg,IDT_EDIT1,UserName);
  1061. SetDlgItemText(hdlg,IDT_EDIT2,UserPassword);
  1062. SetDlgItemText(hdlg,IDT_EDIT3,UserPassword);
  1063. break;
  1064. case WM_SIMULATENEXT:
  1065. // Simulate the next button somehow
  1066. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  1067. break;
  1068. case WMX_VALIDATE:
  1069. //
  1070. // lParam == 0 for no UI, or 1 for UI
  1071. // Return 1 for success, -1 for error.
  1072. //
  1073. //
  1074. // Check name.
  1075. //
  1076. if(CheckUserAccountData(hdlg, lParam == 0)) {
  1077. //
  1078. // Data is valid. Move on to next page.
  1079. //
  1080. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  1081. GetDlgItemText(hdlg,IDT_EDIT2,UserPassword,MAX_PASSWORD+1);
  1082. CreateUserAccount = TRUE;
  1083. } else if (Unattended) {
  1084. //
  1085. // Data is invalid but we're unattended, so just don't create
  1086. // the account.
  1087. //
  1088. CreateUserAccount = FALSE;
  1089. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  1090. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  1091. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  1092. UserPassword[0] = 0;
  1093. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  1094. }
  1095. //
  1096. // Don't allow next page to be activated.
  1097. //
  1098. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  1099. case WM_NOTIFY:
  1100. NotifyParams = (NMHDR *)lParam;
  1101. switch(NotifyParams->code) {
  1102. case PSN_SETACTIVE:
  1103. TESTHOOK(505);
  1104. BEGIN_SECTION(L"User Name and Password Page");
  1105. SetWizardButtons(hdlg,WizPageUserAccount);
  1106. //
  1107. // Load ComputerName because it may have been set when the user
  1108. // entered the user name.
  1109. //
  1110. SetDlgItemText(hdlg,IDT_EDIT1,UserName);
  1111. //
  1112. // Always activate in ui test mode
  1113. //
  1114. if(!UiTest) {
  1115. //
  1116. // Don't activate if this is a dc server or Win9x upgrade.
  1117. //
  1118. if(ISDC(ProductType) || Win95Upgrade) {
  1119. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  1120. break;
  1121. }
  1122. }
  1123. if (Unattended) {
  1124. if (!UnattendSetActiveDlg(hdlg,IDD_USERACCOUNT)) {
  1125. break;
  1126. }
  1127. }
  1128. // Page becomes active, make page visible.
  1129. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  1130. break;
  1131. case PSN_WIZBACK:
  1132. //
  1133. // Save UserName because we're going to load it into the dialog
  1134. // again when we come back.
  1135. //
  1136. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  1137. break;
  1138. case PSN_WIZNEXT:
  1139. case PSN_WIZFINISH:
  1140. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  1141. break;
  1142. case PSN_KILLACTIVE:
  1143. WizardKillHelp(hdlg);
  1144. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, FALSE );
  1145. END_SECTION(L"User Name and Password Page");
  1146. break;
  1147. case PSN_HELP:
  1148. WizardBringUpHelp(hdlg,WizPageUserAccount);
  1149. break;
  1150. default:
  1151. break;
  1152. }
  1153. break;
  1154. default:
  1155. return(FALSE);
  1156. }
  1157. return(TRUE);
  1158. }
  1159. #endif //def DOLOCALUSER