Source code of Windows XP (NT5)
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.

1157 lines
32 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. VOID
  35. GenerateName(
  36. OUT PWSTR GeneratedString,
  37. IN DWORD DesiredStrLen
  38. )
  39. {
  40. static DWORD Seed = 98725757;
  41. static PCWSTR UsableChars = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  42. //
  43. // How many characters will come from the org/name string.
  44. //
  45. DWORD BaseLength = 8;
  46. DWORD i,j;
  47. DWORD UsableCount;
  48. if( DesiredStrLen < BaseLength ) {
  49. BaseLength = DesiredStrLen - 1;
  50. }
  51. if( NameOrgOrg[0] ) {
  52. wcscpy( GeneratedString, NameOrgOrg );
  53. } else if( NameOrgName[0] ) {
  54. wcscpy( GeneratedString, NameOrgName );
  55. } else {
  56. wcscpy( GeneratedString, TEXT("X") );
  57. for( i = 1; i < BaseLength; i++ ) {
  58. wcscat( GeneratedString, TEXT("X") );
  59. }
  60. }
  61. //
  62. // Get him upper-case for our filter...
  63. //
  64. CharUpper(GeneratedString);
  65. //
  66. // Now we want to put a '-' at the end
  67. // of our GeneratedString. We'd like it to
  68. // be placed in the BASE_LENGTH character, but
  69. // the string may be shorter than that, or may
  70. // even have a ' ' in it. Figure out where to
  71. // put the '-' now.
  72. //
  73. for( i = 0; i <= BaseLength; i++ ) {
  74. //
  75. // Check for a short string.
  76. //
  77. if( (GeneratedString[i] == 0 ) ||
  78. (GeneratedString[i] == L' ') ||
  79. (!wcschr(UsableChars, GeneratedString[i])) ||
  80. (i == BaseLength )
  81. ) {
  82. GeneratedString[i] = L'-';
  83. GeneratedString[i+1] = 0;
  84. break;
  85. }
  86. }
  87. //
  88. // Special case the scenario where we had no usable
  89. // characters.
  90. //
  91. if( GeneratedString[0] == L'-' ) {
  92. GeneratedString[0] = 0;
  93. }
  94. UsableCount = lstrlen(UsableChars);
  95. Seed ^= GetCurrentTime();
  96. srand( Seed );
  97. j = lstrlen( GeneratedString );
  98. for( i = j; i < DesiredStrLen; i++ ) {
  99. GeneratedString[i] = UsableChars[rand() % UsableCount];
  100. }
  101. GeneratedString[i] = 0;
  102. //
  103. // In the normal case, the edit control in the wizard page
  104. // has the ES_UPPER bit set. In the normal unattend case
  105. // there is code in unattend.txt that uppercases the name.
  106. // But if we get to generating the name then then the text
  107. // in unattend.txt was * and we thus never had any text in
  108. // the edit control or unattend.txt to be uppercased.
  109. //
  110. CharUpper(GeneratedString);
  111. }
  112. BOOL
  113. ContainsDot(
  114. IN PCWSTR NameToCheck
  115. )
  116. /*++
  117. Routine Description:
  118. Determine whether a given name contains a '.'
  119. Arguments:
  120. NameToCheck - supplies name to be checked.
  121. Return Value:
  122. TRUE if the name contains a '.'; FALSE if not.
  123. --*/
  124. {
  125. UINT Length,u;
  126. if (!NameToCheck)
  127. return FALSE;
  128. Length = lstrlen(NameToCheck);
  129. for (u = 0; u < Length; u++) {
  130. if (NameToCheck[u] == L'.')
  131. return TRUE;
  132. }
  133. return FALSE;
  134. }
  135. BOOL
  136. IsNetNameValid(
  137. IN PCWSTR NameToCheck,
  138. IN BOOL AlphaNumericOnly
  139. )
  140. /*++
  141. Routine Description:
  142. Determine whether a given name is valid as a netname, such as
  143. a computer name.
  144. Arguments:
  145. NameToCheck - supplies name to be checked.
  146. Return Value:
  147. TRUE if the name is valid; FALSE if not.
  148. --*/
  149. {
  150. UINT Length,u;
  151. Length = lstrlen(NameToCheck);
  152. //
  153. // Want at least one character.
  154. //
  155. if(!Length) {
  156. return(FALSE);
  157. }
  158. //
  159. // Leading/trailing spaces are invalid.
  160. //
  161. if((NameToCheck[0] == L' ') || (NameToCheck[Length-1] == L' ')) {
  162. return(FALSE);
  163. }
  164. //
  165. // Control chars are invalid, as are characters in the illegal chars list.
  166. //
  167. for(u=0; u<Length; u++) {
  168. if (AlphaNumericOnly) {
  169. if (NameToCheck[u] == L'-' || NameToCheck[u] == L'_') {
  170. continue;
  171. }
  172. if (!iswalnum(NameToCheck[u])) {
  173. return(FALSE);
  174. }
  175. } else {
  176. if((NameToCheck[u] < L' ') || wcschr(IllegalNetNameChars,NameToCheck[u])) {
  177. return(FALSE);
  178. }
  179. }
  180. }
  181. //
  182. // We got here, name is ok.
  183. //
  184. return(TRUE);
  185. }
  186. BOOL SetIMEOpenStatus(
  187. IN HWND hDlg,
  188. IN BOOL bSetActive)
  189. {
  190. typedef HIMC (WINAPI* PFN_IMMGETCONTEXT)(HWND);
  191. typedef BOOL (WINAPI* PFN_IMMSETOPENSTATUS)(HIMC,BOOL);
  192. typedef BOOL (WINAPI* PFN_IMMGETOPENSTATUS)(HIMC);
  193. typedef BOOL (WINAPI* PFN_IMMRELEASECONTEXT)(HWND,HIMC);
  194. PFN_IMMGETCONTEXT PFN_ImmGetContext;
  195. PFN_IMMSETOPENSTATUS PFN_ImmSetOpenStatus;
  196. PFN_IMMGETOPENSTATUS PFN_ImmGetOpenStatus;
  197. PFN_IMMRELEASECONTEXT PFN_ImmReleaseContext;
  198. HIMC hIMC;
  199. HKL hKL;
  200. HMODULE hImmDll;
  201. static BOOL bImeEnable=TRUE;
  202. hKL = GetKeyboardLayout(0);
  203. if ((HIWORD(HandleToUlong(hKL)) & 0xF000) != 0xE000) {
  204. //
  205. // not an IME, do nothing !
  206. //
  207. return TRUE;
  208. }
  209. hImmDll = GetModuleHandle(TEXT("IMM32.DLL"));
  210. if (hImmDll == NULL) {
  211. //
  212. // weird case, if the kbd layout is an IME, then
  213. // Imm32.dll should have already been loaded into process.
  214. //
  215. return FALSE;
  216. }
  217. PFN_ImmGetContext = (PFN_IMMGETCONTEXT) GetProcAddress(hImmDll,"ImmGetContext");
  218. if (PFN_ImmGetContext == NULL) {
  219. return FALSE;
  220. }
  221. PFN_ImmReleaseContext = (PFN_IMMRELEASECONTEXT) GetProcAddress(hImmDll,"ImmReleaseContext");
  222. if (PFN_ImmReleaseContext == NULL) {
  223. return FALSE;
  224. }
  225. PFN_ImmSetOpenStatus = (PFN_IMMSETOPENSTATUS) GetProcAddress(hImmDll,"ImmSetOpenStatus");
  226. if (PFN_ImmSetOpenStatus == NULL) {
  227. return FALSE;
  228. }
  229. PFN_ImmGetOpenStatus = (PFN_IMMGETOPENSTATUS) GetProcAddress(hImmDll,"ImmGetOpenStatus");
  230. if (PFN_ImmGetOpenStatus == NULL) {
  231. return FALSE;
  232. }
  233. //
  234. // Get Current Input Context.
  235. //
  236. hIMC = PFN_ImmGetContext(hDlg);
  237. if (hIMC == NULL) {
  238. return FALSE;
  239. }
  240. if (bSetActive) {
  241. PFN_ImmSetOpenStatus(hIMC,bImeEnable);
  242. }
  243. else {
  244. //
  245. // Save Current Status.
  246. //
  247. bImeEnable = PFN_ImmGetOpenStatus(hIMC);
  248. //
  249. // Close IME.
  250. //
  251. PFN_ImmSetOpenStatus(hIMC,FALSE);
  252. }
  253. PFN_ImmReleaseContext(hDlg,hIMC);
  254. return TRUE;
  255. }
  256. // returns TRUE if the name is valid, FALSE if it is not
  257. BOOL ValidateNameOrgName (
  258. WCHAR* pszName
  259. )
  260. {
  261. WCHAR adminName[MAX_USERNAME+1];
  262. WCHAR guestName[MAX_USERNAME+1];
  263. LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
  264. LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
  265. if ( pszName == NULL )
  266. return FALSE;
  267. if(pszName[0] == 0)
  268. return FALSE;
  269. if(lstrcmpi(pszName,adminName) == 0 )
  270. return FALSE;
  271. if ( lstrcmpi(pszName,guestName) == 0 )
  272. return FALSE;
  273. return TRUE;
  274. }
  275. INT_PTR
  276. CALLBACK
  277. NameOrgDlgProc(
  278. IN HWND hdlg,
  279. IN UINT msg,
  280. IN WPARAM wParam,
  281. IN LPARAM lParam
  282. )
  283. {
  284. NMHDR *NotifyParams;
  285. switch(msg) {
  286. case WM_INITDIALOG: {
  287. //
  288. // Limit text fields to maximum lengths
  289. //
  290. SendDlgItemMessage(hdlg,IDT_NAME,EM_LIMITTEXT,MAX_NAMEORG_NAME,0);
  291. SendDlgItemMessage(hdlg,IDT_ORGANIZATION,EM_LIMITTEXT,MAX_NAMEORG_ORG,0);
  292. //
  293. // Set Initial Values
  294. //
  295. SetDlgItemText(hdlg,IDT_NAME,NameOrgName);
  296. SetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg);
  297. break;
  298. }
  299. case WM_IAMVISIBLE:
  300. //
  301. // If an error occured during out INIT phase, show the box to the
  302. // user so that they know there is a problem
  303. //
  304. MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,
  305. MB_OK | MB_ICONSTOP);
  306. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  307. break;
  308. case WM_SIMULATENEXT:
  309. // Simulate the next button somehow
  310. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  311. break;
  312. case WM_COMMAND:
  313. if (HIWORD(wParam) == EN_CHANGE) {
  314. if(LOWORD(wParam) == IDT_ORGANIZATION) {
  315. GetDlgItemText( hdlg, IDT_ORGANIZATION, NameOrgOrg, MAX_NAMEORG_ORG+1);
  316. #ifdef DOLOCALUSER
  317. } else if(LOWORD(wParam) == IDT_NAME) {
  318. GetDlgItemText( hdlg, IDT_NAME, NameOrgName, MAX_NAMEORG_NAME+1);
  319. #endif
  320. }
  321. }
  322. break;
  323. case WMX_VALIDATE:
  324. //
  325. // lParam == 0 for no UI, or 1 for UI
  326. // Return 1 for success, -1 for error.
  327. //
  328. GetDlgItemText(hdlg,IDT_ORGANIZATION,NameOrgOrg,MAX_NAMEORG_ORG+1);
  329. GetDlgItemText(hdlg,IDT_NAME,NameOrgName,MAX_NAMEORG_NAME+1);
  330. // JMH - NameOrgName cannot be "Administrator", "Guest" or "" (blank).
  331. if(ValidateNameOrgName(NameOrgName) == FALSE) {
  332. //
  333. // Skip UI?
  334. //
  335. if (!lParam) {
  336. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  337. }
  338. //
  339. // Tell user he must at least enter a name, and
  340. // don't allow next page to be activated.
  341. //
  342. if (Unattended) {
  343. UnattendErrorDlg(hdlg,IDD_NAMEORG);
  344. } // if
  345. MessageBoxFromMessage(hdlg,MSG_NO_NAMEORG_NAME,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  346. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  347. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  348. }
  349. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  350. case WM_NOTIFY:
  351. NotifyParams = (NMHDR *)lParam;
  352. switch(NotifyParams->code) {
  353. case PSN_SETACTIVE:
  354. TESTHOOK(503);
  355. BEGIN_SECTION(L"Personalize Your Software Page");
  356. SetWizardButtons(hdlg,WizPageNameOrg);
  357. if (Unattended) {
  358. if (!UnattendSetActiveDlg(hdlg,IDD_NAMEORG)) {
  359. break;
  360. }
  361. }
  362. // Page becomes active, make page visible.
  363. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  364. //
  365. // Set focus on the name edit control.
  366. //
  367. SetFocus(GetDlgItem(hdlg,IDT_NAME));
  368. //
  369. // Open/Close IME.
  370. //
  371. SetIMEOpenStatus(hdlg,TRUE);
  372. break;
  373. case PSN_WIZNEXT:
  374. case PSN_WIZFINISH:
  375. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  376. break;
  377. case PSN_KILLACTIVE:
  378. WizardKillHelp(hdlg);
  379. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
  380. //
  381. // Close IME.
  382. //
  383. SetIMEOpenStatus(hdlg,FALSE);
  384. END_SECTION(L"Personalize Your Software Page");
  385. break;
  386. case PSN_HELP:
  387. WizardBringUpHelp(hdlg,WizPageNameOrg);
  388. break;
  389. default:
  390. break;
  391. }
  392. break;
  393. default:
  394. return(FALSE);
  395. }
  396. return(TRUE);
  397. }
  398. INT_PTR
  399. CALLBACK
  400. ComputerNameDlgProc(
  401. IN HWND hdlg,
  402. IN UINT msg,
  403. IN WPARAM wParam,
  404. IN LPARAM lParam
  405. )
  406. {
  407. NMHDR *NotifyParams;
  408. DWORD err, Win32NameSize = MAX_COMPUTERNAME_LENGTH + 1;
  409. static BOOL EncryptedAdminPasswordBad = FALSE;
  410. static BOOL bPersonal = FALSE;
  411. switch(msg) {
  412. case WM_INITDIALOG: {
  413. bPersonal = ( GetProductFlavor() == 4);
  414. //
  415. // Limit text to maximum length
  416. //
  417. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,DNS_MAX_LABEL_LENGTH,0);
  418. if (!bPersonal)
  419. {
  420. SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
  421. SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
  422. }
  423. //
  424. // Set the Edit boxes to the initial text
  425. //
  426. //
  427. // Generate a computer name if we're unattended and
  428. // the user has requested a random name, or if we're
  429. // attended.
  430. //
  431. GenerateName( ComputerName, 15 );
  432. if( (Unattended) &&
  433. (UnattendAnswerTable[UAE_COMPNAME].Answer.String) &&
  434. (UnattendAnswerTable[UAE_COMPNAME].Answer.String[0] == L'*') ) {
  435. //
  436. // The unattend engine has asked us to generate a Computer
  437. // name. Let's write the data back into the unattend
  438. // database.
  439. //
  440. MyFree( UnattendAnswerTable[UAE_COMPNAME].Answer.String );
  441. UnattendAnswerTable[UAE_COMPNAME].Answer.String = ComputerName;
  442. }
  443. if (!bPersonal)
  444. {
  445. if(DontChangeAdminPassword) {
  446. EnableWindow(GetDlgItem(hdlg,IDT_EDIT2),FALSE);
  447. EnableWindow(GetDlgItem(hdlg,IDT_EDIT3),FALSE);
  448. } else {
  449. SetDlgItemText(hdlg,IDT_EDIT2,AdminPassword);
  450. SetDlgItemText(hdlg,IDT_EDIT3,AdminPassword);
  451. }
  452. }
  453. break;
  454. }
  455. case WM_IAMVISIBLE:
  456. MessageBoxFromMessage(
  457. hdlg,
  458. ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
  459. NULL,
  460. IDS_ERROR,MB_OK|MB_ICONSTOP);
  461. break;
  462. case WM_SIMULATENEXT:
  463. // Simulate the next button somehow
  464. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  465. break;
  466. case WMX_VALIDATE:
  467. //
  468. // lParam == 0 for no UI, or 1 for UI
  469. // Return 1 for success, -1 for error.
  470. //
  471. IsNameNonRfc = FALSE;
  472. IsNameTruncated = FALSE;
  473. GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
  474. // StrTrim removes both leading and trailing spaces
  475. StrTrim(ComputerName, TEXT(" "));
  476. if (ContainsDot(ComputerName)) {
  477. err = ERROR_INVALID_NAME;
  478. } else {
  479. err = DnsValidateDnsName_W(ComputerName);
  480. if (err == DNS_ERROR_NON_RFC_NAME) {
  481. IsNameNonRfc = TRUE;
  482. err = ERROR_SUCCESS;
  483. }
  484. if(err == ERROR_SUCCESS) {
  485. //The name is a valid DNS name. Now verify that it is
  486. //also a valid WIN32 computer name.
  487. if (!DnsHostnameToComputerNameW(ComputerName,
  488. Win32ComputerName,
  489. &Win32NameSize) ||
  490. !IsNetNameValid(Win32ComputerName, FALSE)) {
  491. err = ERROR_INVALID_NAME;
  492. }
  493. else {
  494. if (Win32NameSize < (UINT)lstrlen(ComputerName) ) {
  495. //The DNSName was truncated to get a Win32 ComputerName.
  496. IsNameTruncated = TRUE;
  497. }
  498. }
  499. }
  500. }
  501. //
  502. // If the name has non-RFC characters or if it was truncated, warn
  503. // user if it is not an unattended install and we have GUI.
  504. //
  505. if (err == ERROR_SUCCESS && !Unattended && lParam) {
  506. if (IsNameNonRfc) {
  507. //ComputerName has non-standard characters.
  508. if (MessageBoxFromMessage(
  509. hdlg,
  510. MSG_DNS_NON_RFC_NAME,
  511. NULL,
  512. IDS_SETUP,MB_YESNO|MB_ICONWARNING,
  513. ComputerName) == IDNO) {
  514. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  515. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  516. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  517. }
  518. }
  519. if (IsNameTruncated) {
  520. //The computer name was truncated.
  521. if (MessageBoxFromMessage(
  522. hdlg,
  523. MSG_DNS_NAME_TRUNCATED,
  524. NULL,
  525. IDS_SETUP,MB_YESNO|MB_ICONWARNING,
  526. ComputerName, Win32ComputerName) == IDNO) {
  527. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  528. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  529. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  530. }
  531. }
  532. }
  533. if(err == ERROR_SUCCESS) {
  534. WCHAR pw1[MAX_PASSWORD+1],pw2[MAX_PASSWORD+1];
  535. if (bPersonal)
  536. {
  537. // if we are in personal we are done.
  538. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  539. }
  540. //
  541. // Good computer name. Now make sure passwords match.
  542. //
  543. GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
  544. GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
  545. if(lstrcmp(pw1,pw2)) {
  546. //
  547. // Skip UI?
  548. //
  549. if (!lParam) {
  550. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  551. }
  552. //
  553. //
  554. // Inform user of password mismatch, and don't allow next page
  555. // to be activated.
  556. //
  557. if (Unattended) {
  558. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  559. }
  560. MessageBoxFromMessage(hdlg,MSG_PW_MISMATCH,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  561. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  562. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  563. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  564. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  565. } else {
  566. WCHAR adminName[MAX_USERNAME+1];
  567. GetAdminAccountName( adminName );
  568. //
  569. // Process the encrypted password if
  570. // 1) We are unattended and
  571. // 2) The EncryptedAdminPassword key is "Yes" in the unatttend file and
  572. // 3) We are not back here after setting it - i.e. via the back button etc.
  573. // 4) We are not back here after failing to set it once.
  574. if( Unattended && IsEncryptedAdminPasswordPresent() &&
  575. !DontChangeAdminPassword && !EncryptedAdminPasswordBad){
  576. // Logging is done inside the call to ProcessEncryptedAdminPassword
  577. if(!(ProcessEncryptedAdminPassword(adminName))){
  578. EncryptedAdminPasswordBad = TRUE;
  579. // Page becomes active, make page visible.
  580. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  581. // Inform the user and enable the password fields
  582. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  583. MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
  584. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  585. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  586. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  587. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  588. }else{
  589. EncryptedAdminPasswordSet = TRUE;
  590. //
  591. // Set DontChangeAdminPassword to avoid the user from ever trying to
  592. // reset the password using the dialog. This is needed in the case where the
  593. // unattend fails, say, in the next page and the user gets here using the back button.
  594. //
  595. DontChangeAdminPassword = TRUE;
  596. }
  597. }else{
  598. //
  599. // They match; allow next page to be activated.
  600. //
  601. if (Unattended && pw1[0] == L'*') {
  602. pw1[0] = L'\0';
  603. }
  604. // Set administrator password. We need to do some checking here though.
  605. // There are 3 scenarios that can occur in mini-setup:
  606. // 1. The OEM doesn't want to have the admin password changed.
  607. // In this case, he's set OEMAdminPassword = "NoChange". If that's
  608. // what we find, we don't assign the password. Remember that this
  609. // system has already been installed, so there's already an admin
  610. // password.
  611. // 2. The OEM wants to set the admin password to a specific string.
  612. // In this case, he's set OEMAdminPassword = <some quoted word>.
  613. // If this is the case, we've already caught this string in the
  614. // wizard page.
  615. // 3. The OEM wants to let the user set the admin password. In this
  616. // case, there's no OEMAdminpassword in the answer file. If this
  617. // is the case, we've already caught this and gotten a password
  618. // from the user in the wizard page.
  619. //
  620. // The good news is that the unattend engine has already looked
  621. // for a password in the unattend file called "NoChange" and has
  622. // set a global called "DontChangeAdminPassword" to indicate.
  623. if(!DontChangeAdminPassword) {
  624. lstrcpy(AdminPassword,pw1);
  625. //
  626. // The user may have changed the name of the Administrator
  627. // account. We'll call some special code to retrieve the
  628. // name on the account. This is really only needed in the
  629. // case of a sysprep run, but it can't hurt to do it always.
  630. //
  631. // In the Win9x case their code in winnt32 generates a random
  632. // password and passes it to us through the unattend file and
  633. // so we set it here and do the right thing.
  634. // For Minisetup the behavior for now is to silently fail setting
  635. // the admin password if there was an existing Password on the system.
  636. // WE only allow setting the admin password from NULL i.e. one time change.
  637. // In any other case we log the error and move on.
  638. //
  639. if(!SetLocalUserPassword(adminName,CurrentAdminPassword,AdminPassword) && !MiniSetup) {
  640. SetupDebugPrint( L"SETUP: SetLocalUserPassword failed" );
  641. // Page becomes active, make page visible.
  642. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  643. MessageBoxFromMessage(hdlg,MSG_CHANGING_PW_FAIL,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP, adminName );
  644. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  645. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  646. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  647. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  648. }
  649. //
  650. // Now store this so that we work fine when the user comes to this page by hitting "Back".
  651. //
  652. lstrcpy( CurrentAdminPassword, AdminPassword );
  653. }
  654. }
  655. }
  656. } else {
  657. //
  658. // Skip UI?
  659. //
  660. if (!lParam) {
  661. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  662. }
  663. //
  664. // Inform user of bogus computer name, and don't allow next page
  665. // to be activated.
  666. //
  667. if (Unattended) {
  668. UnattendErrorDlg(hdlg, IDD_COMPUTERNAME);
  669. }
  670. MessageBoxFromMessage(
  671. hdlg,
  672. ComputerName[0] ? MSG_BAD_COMPUTER_NAME1 : MSG_BAD_COMPUTER_NAME2,
  673. NULL,
  674. IDS_ERROR,MB_OK|MB_ICONSTOP
  675. );
  676. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  677. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  678. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  679. }
  680. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  681. case WM_NOTIFY:
  682. NotifyParams = (NMHDR *)lParam;
  683. switch(NotifyParams->code) {
  684. case PSN_SETACTIVE:
  685. TESTHOOK(504);
  686. BEGIN_SECTION(L"Computer Name Page");
  687. SetWizardButtons(hdlg,WizPageComputerName);
  688. //
  689. // Load ComputerName because it may have been set when the user
  690. // entered the organization name.
  691. //
  692. SetDlgItemText(hdlg,IDT_EDIT1,ComputerName);
  693. if(Unattended && !UnattendSetActiveDlg(hdlg,IDD_COMPUTERNAME)) {
  694. break;
  695. }
  696. //
  697. // Post ourselves a message we'll get once displayed.
  698. //
  699. PostMessage(hdlg,WM_USER,0,0);
  700. break;
  701. case PSN_WIZBACK:
  702. //
  703. // Save ComputerName because we're going to load it into the dialog
  704. // again when we come back.
  705. //
  706. GetDlgItemText(hdlg,IDT_EDIT1,ComputerName,DNS_MAX_LABEL_LENGTH+1);
  707. break;
  708. case PSN_WIZNEXT:
  709. case PSN_WIZFINISH:
  710. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  711. break;
  712. case PSN_KILLACTIVE:
  713. WizardKillHelp(hdlg);
  714. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FALSE);
  715. END_SECTION(L"Computer Name Page");
  716. break;
  717. case PSN_HELP:
  718. WizardBringUpHelp(hdlg,WizPageComputerName);
  719. break;
  720. default:
  721. break;
  722. }
  723. break;
  724. case WM_USER:
  725. // Page becomes active, make page visible.
  726. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  727. //
  728. // Select the computer name string and set focus to it.
  729. //
  730. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_SETSEL,0,-1);
  731. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  732. break;
  733. default:
  734. return(FALSE);
  735. }
  736. return(TRUE);
  737. }
  738. #ifdef DOLOCALUSER
  739. BOOL
  740. CheckUserAccountData(
  741. IN HWND hdlg,
  742. OUT BOOL ValidateOnly
  743. )
  744. {
  745. WCHAR userName[MAX_USERNAME+1];
  746. WCHAR pw1[MAX_PASSWORD+1];
  747. WCHAR pw2[MAX_PASSWORD+1];
  748. WCHAR adminName[MAX_USERNAME+1];
  749. WCHAR guestName[MAX_USERNAME+1];
  750. UINT MessageId;
  751. FocusId = 0;
  752. //
  753. // Load names of built-in accounts.
  754. //
  755. LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminName,MAX_USERNAME+1);
  756. LoadString(MyModuleHandle,IDS_GUEST,guestName,MAX_USERNAME+1);
  757. //
  758. // Fetch data user typed in for username and password.
  759. //
  760. GetDlgItemText(hdlg,IDT_EDIT1,userName,MAX_USERNAME+1);
  761. GetDlgItemText(hdlg,IDT_EDIT2,pw1,MAX_PASSWORD+1);
  762. GetDlgItemText(hdlg,IDT_EDIT3,pw2,MAX_PASSWORD+1);
  763. if(lstrcmpi(userName,adminName) && lstrcmpi(userName,guestName)) {
  764. if(userName[0]) {
  765. if(IsNetNameValid(userName,FALSE)) {
  766. if(lstrcmp(pw1,pw2)) {
  767. //
  768. // Passwords don't match.
  769. //
  770. MessageId = MSG_PW_MISMATCH;
  771. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  772. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  773. SetFocus(GetDlgItem(hdlg,IDT_EDIT2));
  774. } else {
  775. //
  776. // Name is non-empty, is not a built-in, is valid,
  777. // and the passwords match.
  778. //
  779. MessageId = 0;
  780. }
  781. } else {
  782. //
  783. // Name is not valid.
  784. //
  785. MessageId = MSG_BAD_USER_NAME1;
  786. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  787. }
  788. } else {
  789. //
  790. // Don't allow empty name.
  791. //
  792. MessageId = MSG_BAD_USER_NAME2;
  793. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  794. }
  795. } else {
  796. //
  797. // User entered name of a built-in account.
  798. //
  799. MessageId = MSG_BAD_USER_NAME3;
  800. SetFocus(GetDlgItem(hdlg,IDT_EDIT1));
  801. }
  802. if(MessageId && !ValidateOnly) {
  803. MessageBoxFromMessage(hdlg,MessageId,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  804. }
  805. return(MessageId == 0);
  806. }
  807. BOOL
  808. CALLBACK
  809. UserAccountDlgProc(
  810. IN HWND hdlg,
  811. IN UINT msg,
  812. IN WPARAM wParam,
  813. IN LPARAM lParam
  814. )
  815. {
  816. NMHDR *NotifyParams;
  817. switch(msg) {
  818. case WM_INITDIALOG:
  819. //
  820. // Limit text to maximum length of a user account name,
  821. // and limit password text to max langth of a password.
  822. // Also set initial text.
  823. //
  824. SendDlgItemMessage(hdlg,IDT_EDIT1,EM_LIMITTEXT,MAX_USERNAME,0);
  825. SendDlgItemMessage(hdlg,IDT_EDIT2,EM_LIMITTEXT,MAX_PASSWORD,0);
  826. SendDlgItemMessage(hdlg,IDT_EDIT3,EM_LIMITTEXT,MAX_PASSWORD,0);
  827. SetDlgItemText(hdlg,IDT_EDIT1,UserName);
  828. SetDlgItemText(hdlg,IDT_EDIT2,UserPassword);
  829. SetDlgItemText(hdlg,IDT_EDIT3,UserPassword);
  830. break;
  831. case WM_SIMULATENEXT:
  832. // Simulate the next button somehow
  833. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  834. break;
  835. case WMX_VALIDATE:
  836. //
  837. // lParam == 0 for no UI, or 1 for UI
  838. // Return 1 for success, -1 for error.
  839. //
  840. //
  841. // Check name.
  842. //
  843. if(CheckUserAccountData(hdlg, lParam == 0)) {
  844. //
  845. // Data is valid. Move on to next page.
  846. //
  847. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  848. GetDlgItemText(hdlg,IDT_EDIT2,UserPassword,MAX_PASSWORD+1);
  849. CreateUserAccount = TRUE;
  850. } else if (Unattended) {
  851. //
  852. // Data is invalid but we're unattended, so just don't create
  853. // the account.
  854. //
  855. CreateUserAccount = FALSE;
  856. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  857. SetDlgItemText(hdlg,IDT_EDIT2,L"");
  858. SetDlgItemText(hdlg,IDT_EDIT3,L"");
  859. UserPassword[0] = 0;
  860. return ReturnDlgResult (hdlg, VALIDATE_DATA_OK);
  861. }
  862. //
  863. // Don't allow next page to be activated.
  864. //
  865. return ReturnDlgResult (hdlg, VALIDATE_DATA_INVALID);
  866. case WM_NOTIFY:
  867. NotifyParams = (NMHDR *)lParam;
  868. switch(NotifyParams->code) {
  869. case PSN_SETACTIVE:
  870. TESTHOOK(505);
  871. BEGIN_SECTION(L"User Name and Password Page");
  872. SetWizardButtons(hdlg,WizPageUserAccount);
  873. //
  874. // Load ComputerName because it may have been set when the user
  875. // entered the user name.
  876. //
  877. SetDlgItemText(hdlg,IDT_EDIT1,UserName);
  878. //
  879. // Always activate in ui test mode
  880. //
  881. if(!UiTest) {
  882. //
  883. // Don't activate if this is a dc server or Win9x upgrade.
  884. //
  885. if(ISDC(ProductType) || Win95Upgrade) {
  886. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  887. break;
  888. }
  889. }
  890. if (Unattended) {
  891. if (!UnattendSetActiveDlg(hdlg,IDD_USERACCOUNT)) {
  892. break;
  893. }
  894. }
  895. // Page becomes active, make page visible.
  896. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  897. break;
  898. case PSN_WIZBACK:
  899. //
  900. // Save UserName because we're going to load it into the dialog
  901. // again when we come back.
  902. //
  903. GetDlgItemText(hdlg,IDT_EDIT1,UserName,MAX_USERNAME+1);
  904. break;
  905. case PSN_WIZNEXT:
  906. case PSN_WIZFINISH:
  907. UnattendAdvanceIfValid (hdlg); // see WMX_VALIDATE
  908. break;
  909. case PSN_KILLACTIVE:
  910. WizardKillHelp(hdlg);
  911. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, FALSE );
  912. END_SECTION(L"User Name and Password Page");
  913. break;
  914. case PSN_HELP:
  915. WizardBringUpHelp(hdlg,WizPageUserAccount);
  916. break;
  917. default:
  918. break;
  919. }
  920. break;
  921. default:
  922. return(FALSE);
  923. }
  924. return(TRUE);
  925. }
  926. #endif //def DOLOCALUSER