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.

1167 lines
29 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. migpwd.c
  5. Abstract:
  6. Implements a simple password application that sets a default password
  7. for each local account created. This application is placed in the
  8. RunOnce registry key when the Administrator account is set to auto-logon,
  9. and at least one other local account was created.
  10. The list of migrated local accounts is kept in
  11. HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\Win9xUpg\Users
  12. This app prompts the user for a password, explaining what exactly is going
  13. on, and then deletes the RunOnce and Users value on exit.
  14. Author:
  15. Jim Schmidt (jimschm) 18-Mar-1998
  16. Revision History:
  17. jimschm 06-Jul-1998 Added private stress option
  18. --*/
  19. #include "pch.h"
  20. #include "resource.h"
  21. #include "msg.h"
  22. #include <lm.h>
  23. //
  24. // Constants
  25. //
  26. #define MAX_PASSWORD 64
  27. //
  28. // Globals
  29. //
  30. HINSTANCE g_hInst;
  31. HANDLE g_hHeap;
  32. UINT g_TotalUsers;
  33. BOOL g_AutoPassword = FALSE;
  34. TCHAR g_AutoLogonUser[256];
  35. TCHAR g_AutoLogonPassword[MAX_PASSWORD + 1];
  36. //
  37. // !!! This is for internal use only !!! It is used for auto stress.
  38. //
  39. #ifdef PRERELEASE
  40. BOOL g_AutoStress = FALSE;
  41. TCHAR g_AutoStressUser[MAX_USER_NAME];
  42. TCHAR g_AutoStressPwd[MAX_PASSWORD];
  43. TCHAR g_AutoStressOffice[32];
  44. TCHAR g_AutoStressDbg[MAX_COMPUTER_NAME];
  45. DWORD g_AutoStressFlags;
  46. #endif
  47. //
  48. // Library prototypes
  49. //
  50. BOOL
  51. WINAPI
  52. MigUtil_Entry (
  53. HINSTANCE hInstance,
  54. DWORD dwReason,
  55. PVOID lpReserved
  56. );
  57. //
  58. // Local prototypes
  59. //
  60. VOID
  61. pCleanup (
  62. VOID
  63. );
  64. BOOL
  65. pIsAdministratorOnly (
  66. VOID
  67. );
  68. BOOL
  69. CALLBACK
  70. PasswordProc (
  71. HWND hdlg,
  72. UINT uMsg,
  73. WPARAM wParam,
  74. LPARAM lParam
  75. );
  76. BOOL
  77. pIsBlankPasswordAllowed (
  78. VOID
  79. );
  80. BOOL
  81. pIsPersonal (
  82. VOID
  83. )
  84. {
  85. static BOOL g_Determined = FALSE;
  86. static BOOL g_Personal = FALSE;
  87. OSVERSIONINFOEX osviex;
  88. //
  89. // Determine if Personal SKU
  90. //
  91. if (!g_Determined) {
  92. g_Determined = TRUE;
  93. osviex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
  94. if (GetVersionEx ((LPOSVERSIONINFO)&osviex)) {
  95. if (osviex.wProductType == VER_NT_WORKSTATION &&
  96. (osviex.wSuiteMask & VER_SUITE_PERSONAL)
  97. ) {
  98. g_Personal = TRUE;
  99. }
  100. }
  101. }
  102. return g_Personal;
  103. }
  104. //
  105. // Implementation
  106. //
  107. INT
  108. WINAPI
  109. WinMain (
  110. HINSTANCE hInstance,
  111. HINSTANCE hPrevInstance,
  112. PSTR AnsiCmdLine,
  113. INT CmdShow
  114. )
  115. /*++
  116. Routine Description:
  117. The entry point to migpwd.exe. All the work is done in a dialog box,
  118. so no message loop is necessary.
  119. Arguments:
  120. hInstance - The instance handle of this EXE
  121. hPrevInstance - The previous instance handle of this EXE if it is
  122. running, or NULL if no other instances exist.
  123. AnsiCmdLine - The command line (ANSI version)
  124. CmdShow - The ShowWindow command passed by the shell
  125. Return Value:
  126. Returns -1 if an error occurred, or 0 if the exe completed. The exe
  127. will automatically terminate with 0 if the migration DLL throws an
  128. exception.
  129. --*/
  130. {
  131. UINT Result;
  132. PCTSTR ArgArray[1];
  133. TCHAR UserName[MAX_USER_NAME];
  134. DWORD Size;
  135. HCURSOR OldCursor;
  136. INITCOMMONCONTROLSEX init = {sizeof (INITCOMMONCONTROLSEX), 0};
  137. STARTUPINFO si;
  138. PROCESS_INFORMATION pi;
  139. TCHAR winDir[MAX_PATH];
  140. PTSTR oobeBalnPath;
  141. PTSTR cmdLine;
  142. BOOL ProcessResult;
  143. #ifdef PRERELEASE
  144. HKEY Key;
  145. PCTSTR Data;
  146. #endif
  147. InitCommonControlsEx (&init);
  148. g_hInst = hInstance;
  149. g_hHeap = GetProcessHeap();
  150. OldCursor = SetCursor (LoadCursor (NULL, IDC_ARROW));
  151. MigUtil_Entry (hInstance, DLL_PROCESS_ATTACH, NULL);
  152. #ifdef PRERELEASE
  153. Key = OpenRegKeyStr (S_AUTOSTRESS_KEY);
  154. if (Key) {
  155. g_AutoStress = TRUE;
  156. Data = GetRegValueString (Key, S_AUTOSTRESS_USER);
  157. if (Data) {
  158. StringCopy (g_AutoStressUser, Data);
  159. MemFree (g_hHeap, 0, Data);
  160. } else {
  161. g_AutoStress = FALSE;
  162. }
  163. Data = GetRegValueString (Key, S_AUTOSTRESS_PASSWORD);
  164. if (Data) {
  165. StringCopy (g_AutoStressPwd, Data);
  166. MemFree (g_hHeap, 0, Data);
  167. } else {
  168. g_AutoStress = FALSE;
  169. }
  170. Data = GetRegValueString (Key, S_AUTOSTRESS_OFFICE);
  171. if (Data) {
  172. StringCopy (g_AutoStressOffice, Data);
  173. MemFree (g_hHeap, 0, Data);
  174. } else {
  175. g_AutoStress = FALSE;
  176. }
  177. Data = GetRegValueString (Key, S_AUTOSTRESS_DBG);
  178. if (Data) {
  179. StringCopy (g_AutoStressDbg, Data);
  180. MemFree (g_hHeap, 0, Data);
  181. } else {
  182. g_AutoStress = FALSE;
  183. }
  184. Data = GetRegValueString (Key, S_AUTOSTRESS_FLAGS);
  185. if (Data) {
  186. g_AutoStressFlags = _tcstoul (Data, NULL, 10);
  187. MemFree (g_hHeap, 0, Data);
  188. } else {
  189. g_AutoStress = FALSE;
  190. }
  191. CloseRegKey (Key);
  192. }
  193. #endif
  194. //
  195. // Launch oobebaln.exe /init
  196. //
  197. ZeroMemory (&si, sizeof (si));
  198. si.cb = sizeof (si);
  199. si.dwFlags = STARTF_FORCEOFFFEEDBACK;
  200. if (!GetWindowsDirectory (winDir, ARRAYSIZE(winDir))) {
  201. StringCopy (winDir, TEXT("c:\\windows"));
  202. }
  203. oobeBalnPath = JoinPaths (winDir, TEXT("system32\\oobe\\oobebaln.exe"));
  204. cmdLine = JoinText (oobeBalnPath, TEXT(" /init"));
  205. ProcessResult = CreateProcess (
  206. oobeBalnPath,
  207. cmdLine,
  208. NULL,
  209. NULL,
  210. FALSE,
  211. CREATE_DEFAULT_ERROR_MODE,
  212. NULL,
  213. NULL,
  214. &si,
  215. &pi
  216. );
  217. if (ProcessResult) {
  218. CloseHandle (pi.hThread);
  219. CloseHandle (pi.hProcess);
  220. } else {
  221. LOG ((LOG_ERROR, "Cannot start %s", cmdLine));
  222. }
  223. FreePathString (oobeBalnPath);
  224. FreeText (cmdLine);
  225. //
  226. // Set passwords
  227. //
  228. if (pIsAdministratorOnly()) {
  229. DEBUGMSG ((DBG_VERBOSE, "Calling Adminitrator password dialog"));
  230. Result = DialogBox (
  231. hInstance,
  232. MAKEINTRESOURCE(IDD_ADMIN_PASSWORD_DLG),
  233. NULL,
  234. PasswordProc
  235. );
  236. } else {
  237. DEBUGMSG ((DBG_VERBOSE, "Calling multi user password dialog"));
  238. Result = DialogBox (
  239. hInstance,
  240. MAKEINTRESOURCE(IDD_PASSWORD_DLG),
  241. NULL,
  242. PasswordProc
  243. );
  244. }
  245. if (Result == IDOK) {
  246. Size = MAX_USER_NAME;
  247. GetUserName (UserName, &Size);
  248. ArgArray[0] = UserName;
  249. pCleanup();
  250. #ifdef PRERELEASE
  251. if (!g_AutoStress) {
  252. #endif
  253. //if (g_TotalUsers) {
  254. // ResourceMessageBox (NULL, MSG_YOU_ARE_ADMIN, MB_ICONINFORMATION|MB_OK, ArgArray);
  255. //}
  256. #ifdef PRERELEASE
  257. } else {
  258. NETRESOURCE nr;
  259. LONG rc;
  260. TCHAR CmdLine[MAX_TCHAR_PATH];
  261. STARTUPINFO si;
  262. PROCESS_INFORMATION pi;
  263. PTSTR UserName;
  264. TCHAR StressCmdLine[MAX_TCHAR_PATH];
  265. TCHAR NtDevDomain[MAX_COMPUTER_NAME];
  266. TCHAR Msg[1024];
  267. //
  268. // Autostress: Create connection to \\ntstress or \\ntstress2
  269. // Turn on autologon
  270. // Create Run key for stress
  271. // Run munge /p
  272. //
  273. nr.dwType = RESOURCETYPE_ANY;
  274. nr.lpLocalName = TEXT("s:");
  275. nr.lpRemoteName = TEXT("\\\\ntstress\\stress");
  276. nr.lpProvider = NULL;
  277. rc = WNetAddConnection2 (&nr, g_AutoStressPwd, g_AutoStressUser, 0);
  278. if (rc != ERROR_SUCCESS) {
  279. nr.lpRemoteName = TEXT("\\\\ntstress2\\stress");
  280. rc = WNetAddConnection2 (&nr, g_AutoStressPwd, g_AutoStressUser, 0);
  281. }
  282. if (rc == ERROR_SUCCESS) {
  283. // Prepare command line
  284. StringCopy (NtDevDomain, g_AutoStressUser);
  285. UserName = _tcschr (NtDevDomain, TEXT('\\'));
  286. if (UserName) {
  287. *UserName = 0;
  288. UserName++;
  289. } else {
  290. UserName = g_AutoStressUser;
  291. StringCopy (NtDevDomain, TEXT("ntdev"));
  292. }
  293. wsprintf (
  294. StressCmdLine,
  295. TEXT("%s\\stress.cmd /o %s /n %s /d c:\\stress /k %s /g"),
  296. nr.lpRemoteName,
  297. g_AutoStressOffice,
  298. UserName,
  299. g_AutoStressDbg
  300. );
  301. if (g_AutoStressFlags & AUTOSTRESS_PRIVATE) {
  302. StringCat (StressCmdLine, TEXT(" /P"));
  303. }
  304. if (g_AutoStressFlags & AUTOSTRESS_MANUAL_TESTS) {
  305. StringCat (StressCmdLine, TEXT(" /M"));
  306. }
  307. // Turn on autologon
  308. Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
  309. MYASSERT (Key);
  310. RegSetValueEx (
  311. Key,
  312. S_AUTOADMIN_LOGON_VALUE,
  313. 0,
  314. REG_SZ,
  315. (PBYTE) TEXT("1"),
  316. sizeof (TCHAR) * 2
  317. );
  318. RegSetValueEx (
  319. Key,
  320. S_DEFAULT_USER_NAME_VALUE,
  321. 0,
  322. REG_SZ,
  323. (PBYTE) UserName,
  324. SizeOfString (UserName)
  325. );
  326. RegSetValueEx (
  327. Key,
  328. S_DEFAULT_PASSWORD_VALUE,
  329. 0,
  330. REG_SZ,
  331. (PBYTE) g_AutoStressPwd,
  332. SizeOfString (g_AutoStressPwd)
  333. );
  334. RegSetValueEx (
  335. Key,
  336. S_DEFAULT_DOMAIN_NAME_VALUE,
  337. 0,
  338. REG_SZ,
  339. (PBYTE) NtDevDomain,
  340. SizeOfString (NtDevDomain)
  341. );
  342. CloseRegKey (Key);
  343. // Prepare the launch of stress
  344. Key = OpenRegKeyStr (S_RUN_KEY);
  345. MYASSERT (Key);
  346. RegSetValueEx (
  347. Key,
  348. TEXT("Stress"),
  349. 0,
  350. REG_SZ,
  351. (PBYTE) StressCmdLine,
  352. SizeOfString (StressCmdLine)
  353. );
  354. CloseRegKey (Key);
  355. // Run munge /p /q /y (to set preferred stress settings and reboot)
  356. wsprintf (CmdLine, TEXT("%s\\munge.bat /p /q /y"), nr.lpRemoteName);
  357. ZeroMemory (&si, sizeof (si));
  358. si.cb = sizeof (si);
  359. if (!CreateProcess (
  360. NULL,
  361. CmdLine,
  362. NULL,
  363. NULL,
  364. FALSE,
  365. 0,
  366. NULL,
  367. NULL,
  368. &si,
  369. &pi
  370. )) {
  371. wsprintf (Msg, TEXT("Can't start %s. rc=%u"), CmdLine, GetLastError());
  372. MessageBox (NULL, Msg, NULL, MB_OK);
  373. }
  374. } else {
  375. wsprintf (Msg, TEXT("Can't connect to ntstress or ntstress2. rc=%u"), GetLastError());
  376. MessageBox (NULL, Msg, NULL, MB_OK);
  377. }
  378. }
  379. #endif
  380. }
  381. MigUtil_Entry (hInstance, DLL_PROCESS_DETACH, NULL);
  382. SetCursor (OldCursor);
  383. return 0;
  384. }
  385. VOID
  386. pCopyRegString (
  387. IN HKEY DestKey,
  388. IN HKEY SrcKey,
  389. IN PCTSTR SrcValue
  390. )
  391. /*++
  392. Routine Description:
  393. pCopyRegString copies a REG_SZ value from one key to another. If the value
  394. does not exist or is not a REG_SZ, nothing is copied.
  395. Arguments:
  396. DestKey - Specifies the destination key handle
  397. SrcKey - Specifies the source key handle
  398. SrcValue - Specifies the value in SrcKey to copy
  399. Return Value:
  400. None.
  401. --*/
  402. {
  403. PCTSTR Data;
  404. Data = GetRegValueString (SrcKey, SrcValue);
  405. if (Data) {
  406. RegSetValueEx (
  407. DestKey,
  408. SrcValue,
  409. 0,
  410. REG_SZ,
  411. (PBYTE) Data,
  412. SizeOfString (Data)
  413. );
  414. MemFree (g_hHeap, 0, Data);
  415. }
  416. }
  417. VOID
  418. pCleanup (
  419. VOID
  420. )
  421. /*++
  422. Routine Description:
  423. pCleanup performs all cleanup necessary to remove auto-logon and migpwd.exe.
  424. Arguments:
  425. None.
  426. Return Value:
  427. None.
  428. --*/
  429. {
  430. HKEY Key;
  431. HKEY DestKey;
  432. TCHAR ExeName[MAX_PATH];
  433. //
  434. // This is the place where we will delete the Run or RunOnce entry,
  435. // remove the Setup\Win9xUpg\Users key, remove the auto logon,
  436. // and delete this EXE.
  437. //
  438. Key = OpenRegKeyStr (S_RUNONCE_KEY);
  439. if (Key) {
  440. RegDeleteValue (Key, S_MIGPWD);
  441. CloseRegKey (Key);
  442. }
  443. Key = OpenRegKeyStr (S_RUN_KEY);
  444. if (Key) {
  445. RegDeleteValue (Key, S_MIGPWD);
  446. CloseRegKey (Key);
  447. }
  448. Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
  449. if (Key) {
  450. RegDeleteValue (Key, S_AUTOADMIN_LOGON_VALUE);
  451. RegDeleteValue (Key, S_DEFAULT_PASSWORD_VALUE);
  452. CloseRegKey (Key);
  453. }
  454. Key = OpenRegKeyStr (S_WIN9XUPG_KEY);
  455. if (Key) {
  456. RegDeleteKey (Key, S_USERS_SUBKEY);
  457. CloseRegKey (Key);
  458. }
  459. GetModuleFileName (NULL, ExeName, MAX_PATH);
  460. MoveFileEx (ExeName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  461. //
  462. // Transfer auto logon from Win9xUpg
  463. //
  464. Key = OpenRegKeyStr (S_WIN9XUPG_KEY);
  465. if (Key) {
  466. DestKey = OpenRegKeyStr (S_WINLOGON_REGKEY);
  467. if (DestKey) {
  468. pCopyRegString (DestKey, Key, S_AUTOADMIN_LOGON_VALUE);
  469. if (g_AutoLogonUser[0]) {
  470. //
  471. // We changed the password for this user
  472. //
  473. RegSetValueEx (
  474. DestKey,
  475. S_DEFAULT_PASSWORD_VALUE,
  476. 0,
  477. REG_SZ,
  478. (PBYTE) g_AutoLogonPassword,
  479. SizeOfString (g_AutoLogonPassword)
  480. );
  481. } else {
  482. pCopyRegString (DestKey, Key, S_DEFAULT_PASSWORD_VALUE);
  483. }
  484. pCopyRegString (DestKey, Key, S_DEFAULT_USER_NAME_VALUE);
  485. pCopyRegString (DestKey, Key, S_DEFAULT_DOMAIN_NAME_VALUE);
  486. CloseRegKey (DestKey);
  487. }
  488. CloseRegKey (Key);
  489. }
  490. }
  491. BOOL
  492. pSetUserPassword (
  493. IN PCTSTR User,
  494. IN PCTSTR Password
  495. )
  496. /*++
  497. Routine Description:
  498. pSetUserPassword changes the password on the specified user account.
  499. Arguments:
  500. User - Specifies the user name to change
  501. Password - Specifies the new password
  502. Return Value:
  503. TRUE if the password was changed, or FALSE if an error occurred.
  504. --*/
  505. {
  506. LONG rc;
  507. PCWSTR UnicodeUser;
  508. PCWSTR UnicodePassword;
  509. PUSER_INFO_1 ui1;
  510. UnicodeUser = CreateUnicode (User);
  511. UnicodePassword = CreateUnicode (Password);
  512. rc = NetUserGetInfo (NULL, (PWSTR) UnicodeUser, 1, (PBYTE *) (&ui1));
  513. if (rc != NO_ERROR) {
  514. SetLastError (rc);
  515. DEBUGMSG ((DBG_ERROR, "User %s does not exist", User));
  516. rc = NO_ERROR;
  517. } else {
  518. ui1->usri1_password = (PWSTR) UnicodePassword;
  519. rc = NetUserSetInfo (NULL, (PWSTR) UnicodeUser, 1, (PBYTE) ui1, NULL);
  520. NetApiBufferFree ((PVOID) ui1);
  521. }
  522. DestroyUnicode (UnicodeUser);
  523. DestroyUnicode (UnicodePassword);
  524. DEBUGMSG_IF ((rc != NO_ERROR, DBG_ERROR, "Password could not be set, rc=%u", rc));
  525. SetLastError (rc);
  526. return rc == NO_ERROR;
  527. }
  528. BOOL
  529. CALLBACK
  530. PasswordProc (
  531. HWND hdlg,
  532. UINT uMsg,
  533. WPARAM wParam,
  534. LPARAM lParam
  535. )
  536. /*++
  537. Routine Description:
  538. PasswordProc is the dialog procedure for the password dialog. It
  539. initializes the list box with the names of all new accounts. When the user
  540. choses Change, the password is tested and changed if possible. A popup is
  541. presented if the user tries to enter a blank password.
  542. Arguments:
  543. hdlg - Dialog window handle
  544. uMsg - Message to process
  545. wParam - Message-specific
  546. lParam - Message-specific
  547. Return Value:
  548. TRUE if the message was processed, or FALSE if the message should be
  549. processed by the OS.
  550. --*/
  551. {
  552. HKEY Key;
  553. HKEY win9xUpgKey;
  554. static HWND List;
  555. REGVALUE_ENUM e;
  556. PCTSTR Data;
  557. //LONG Index;
  558. //LONG Count;
  559. TCHAR Pwd[MAX_PASSWORD + 1];
  560. TCHAR ConfirmPwd[MAX_PASSWORD + 1];
  561. static HWND Edit1, Edit2;
  562. GROWBUFFER Line = GROWBUF_INIT;
  563. BOOL b;
  564. SIZE Size;
  565. INT MaxWidth;
  566. INT IntegralWidth;
  567. TEXTMETRIC tm;
  568. HDC dc;
  569. RECT rect;
  570. DWORD bufSize;
  571. TCHAR computerName[MAX_PATH];
  572. PCTSTR domainName;
  573. BOOL changingAutoLogonPwd;
  574. *Pwd = 0;
  575. *ConfirmPwd = 0;
  576. switch (uMsg) {
  577. case WM_INITDIALOG:
  578. //
  579. // Enable a timer so the dialog never goes to sleep
  580. // and we ensure it's always the foreground window
  581. //
  582. SetTimer (hdlg, 1, 30000, NULL);
  583. SetTimer (hdlg, 2, 1000, NULL);
  584. //
  585. // Fill list box with user names from registry
  586. //
  587. List = GetDlgItem (hdlg, IDC_USER_LIST);
  588. Edit1 = GetDlgItem (hdlg, IDC_PASSWORD);
  589. Edit2 = GetDlgItem (hdlg, IDC_CONFIRM);
  590. SendMessage (Edit1, EM_LIMITTEXT, MAX_PASSWORD, 0);
  591. SendMessage (Edit2, EM_LIMITTEXT, MAX_PASSWORD, 0);
  592. g_TotalUsers = 0;
  593. if (List) {
  594. //
  595. // Compute text metrics for list
  596. //
  597. dc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
  598. SelectObject (dc, (HFONT) SendMessage (List, WM_GETFONT, 0, 0));
  599. GetTextMetrics (dc, &tm);
  600. Key = OpenRegKeyStr (S_USER_LIST_KEY);
  601. if (Key) {
  602. //
  603. // Enumerate the users in this key. Data is saved with
  604. // each list entry, though it is not currently used.
  605. //
  606. MaxWidth = 0;
  607. if (EnumFirstRegValue (&e, Key)) {
  608. do {
  609. Data = GetRegValueString (e.KeyHandle, e.ValueName);
  610. if (Data) {
  611. GetTextExtentPoint (
  612. dc,
  613. e.ValueName,
  614. TcharCount (e.ValueName),
  615. &Size
  616. );
  617. MaxWidth = max (MaxWidth, Size.cx);
  618. if (g_TotalUsers) {
  619. GrowBufAppendString (&Line, TEXT("\t"));
  620. }
  621. GrowBufAppendString (&Line, e.ValueName);
  622. g_TotalUsers++;
  623. MemFree (g_hHeap, 0, Data); // edit ctrl version
  624. //
  625. // List box code:
  626. //
  627. //
  628. //Index = SendMessage (
  629. // List,
  630. // LB_ADDSTRING,
  631. // 0,
  632. // (LPARAM) e.ValueName
  633. // );
  634. //
  635. //MYASSERT (Index != LB_ERR);
  636. //SendMessage (
  637. // List,
  638. // LB_SETITEMDATA,
  639. // Index,
  640. // (LPARAM) Data
  641. // );
  642. //
  643. // free Data later
  644. }
  645. } while (EnumNextRegValue (&e));
  646. }
  647. GrowBufAppendString (&Line, TEXT("\r\n"));
  648. SetWindowText (List, (PCTSTR) Line.Buf);
  649. MaxWidth += tm.tmAveCharWidth * 2;
  650. GetWindowRect (List, &rect);
  651. IntegralWidth = (rect.right - rect.left) / MaxWidth;
  652. IntegralWidth = max (IntegralWidth, 1);
  653. MaxWidth = IntegralWidth * (rect.right - rect.left);
  654. rect.left = 0;
  655. rect.right = 100;
  656. rect.top = 0;
  657. rect.bottom = 100;
  658. MapDialogRect (hdlg, &rect);
  659. MaxWidth = (MaxWidth * 100) / (rect.right - rect.left);
  660. SendMessage (List, EM_SETTABSTOPS, 1, (LPARAM) (&MaxWidth));
  661. CloseRegKey (Key);
  662. DeleteDC (dc);
  663. }
  664. ELSE_DEBUGMSG ((DBG_WARNING, "%s not found", S_USER_LIST_KEY));
  665. FreeGrowBuffer (&Line);
  666. if (!g_TotalUsers) {
  667. EndDialog (hdlg, IDOK);
  668. } else {
  669. SetForegroundWindow (hdlg);
  670. }
  671. }
  672. if (pIsPersonal ()) {
  673. g_AutoPassword = TRUE;
  674. PostMessage (hdlg, WM_COMMAND, IDOK, 0);
  675. }
  676. #ifdef PRERELEASE
  677. //
  678. // !!! This is for internal use only !!! It is used for auto stress.
  679. //
  680. else if (g_AutoStress) {
  681. PostMessage (hdlg, WM_COMMAND, IDOK, 0);
  682. }
  683. #endif
  684. return FALSE;
  685. case WM_COMMAND:
  686. switch (LOWORD(wParam)) {
  687. case IDOK:
  688. if (pIsPersonal () && g_AutoPassword) {
  689. StringCopy (Pwd, TEXT(""));
  690. StringCopy (ConfirmPwd, Pwd);
  691. } else {
  692. GetWindowText (Edit1, Pwd, MAX_PASSWORD + 1);
  693. GetWindowText (Edit2, ConfirmPwd, MAX_PASSWORD + 1);
  694. if (lstrcmp (Pwd, ConfirmPwd)) {
  695. OkBox (hdlg, MSG_PASSWORDS_DO_NOT_MATCH);
  696. SetWindowText (Edit1, S_EMPTY);
  697. SetWindowText (Edit2, S_EMPTY);
  698. SetFocus (Edit1);
  699. break;
  700. }
  701. #ifdef PRERELEASE
  702. //
  703. // !!! This is for internal use only !!! It is used for auto stress.
  704. //
  705. if (g_AutoStress) {
  706. StringCopy (Pwd, TEXT("Password1"));
  707. StringCopy (ConfirmPwd, Pwd);
  708. }
  709. #endif
  710. if (*Pwd == 0) {
  711. if (pIsBlankPasswordAllowed()) {
  712. //
  713. // Don't warn about blank passwords, since on Whistler they
  714. // are safe.
  715. //
  716. //if (IDYES != YesNoBox (hdlg, MSG_EMPTY_PASSWORD_WARNING)) {
  717. // break;
  718. //}
  719. } else {
  720. OkBox (hdlg, MSG_MUST_SPECIFY_PASSWORD);
  721. break;
  722. }
  723. }
  724. }
  725. //
  726. // Enumerate all the users and set the password on each
  727. //
  728. b = TRUE;
  729. Key = OpenRegKeyStr (S_USER_LIST_KEY);
  730. if (Key) {
  731. //
  732. // Get the user name & pwd of the autologon (if any)
  733. //
  734. g_AutoLogonUser[0] = 0;
  735. g_AutoLogonPassword[0] = 0;
  736. bufSize = ARRAYSIZE (computerName);
  737. if (GetComputerName (computerName, &bufSize)) {
  738. win9xUpgKey = OpenRegKeyStr (S_WIN9XUPG_KEY);
  739. if (win9xUpgKey) {
  740. domainName = GetRegValueString (win9xUpgKey, S_DEFAULT_DOMAIN_NAME_VALUE);
  741. if (domainName) {
  742. if (StringIMatch (computerName, domainName)) {
  743. //
  744. // Process local accounts only
  745. //
  746. Data = GetRegValueString (win9xUpgKey, S_DEFAULT_USER_NAME_VALUE);
  747. if (Data) {
  748. StringCopyByteCount (g_AutoLogonUser, Data, sizeof(g_AutoLogonUser));
  749. MemFree (g_hHeap, 0, Data);
  750. }
  751. }
  752. ELSE_DEBUGMSG ((DBG_VERBOSE, "Autologon set for non-local user (domain is %s)", domainName));
  753. MemFree (g_hHeap, 0, domainName);
  754. }
  755. CloseRegKey (win9xUpgKey);
  756. }
  757. }
  758. //
  759. // Enumerate the users in this key
  760. //
  761. changingAutoLogonPwd = FALSE;
  762. if (EnumFirstRegValue (&e, Key)) {
  763. do {
  764. if (g_AutoLogonUser[0]) {
  765. if (!changingAutoLogonPwd && StringIMatch (e.ValueName, g_AutoLogonUser)) {
  766. changingAutoLogonPwd = TRUE;
  767. StringCopy (g_AutoLogonPassword, Pwd);
  768. }
  769. }
  770. if (!pSetUserPassword (e.ValueName, Pwd)) {
  771. if (!g_AutoPassword) {
  772. if (GetLastError() == NERR_PasswordTooShort) {
  773. OkBox (hdlg, MSG_PASSWORD_TOO_SHORT);
  774. } else {
  775. OkBox (hdlg, MSG_PASSWORD_INVALID);
  776. }
  777. }
  778. b = FALSE;
  779. g_AutoPassword = FALSE;
  780. break;
  781. }
  782. } while (EnumNextRegValue (&e));
  783. }
  784. //
  785. // NOTE: b might be FALSE; changingAutoLogonPwd only matters
  786. // when b is TRUE, because we just stay in the dialog until
  787. // then.
  788. //
  789. if (b && !changingAutoLogonPwd) {
  790. g_AutoLogonUser[0] = 0;
  791. }
  792. CloseRegKey (Key);
  793. }
  794. if (b) {
  795. EndDialog (hdlg, LOWORD (wParam));
  796. }
  797. break;
  798. }
  799. break;
  800. case WM_TIMER:
  801. if (wParam == 2) {
  802. //
  803. // This timer ensures we have the keyboard focus
  804. // even if another process tries to take it while
  805. // the dialog is being shown.
  806. //
  807. if (GetForegroundWindow () != hdlg) {
  808. SetForegroundWindow (hdlg);
  809. }
  810. } else {
  811. //
  812. // Make this thread a no-sleep thread
  813. //
  814. SetThreadExecutionState (ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS);
  815. }
  816. break;
  817. case WM_DESTROY:
  818. KillTimer (hdlg, 1);
  819. KillTimer (hdlg, 2);
  820. //List = GetDlgItem (hdlg, IDC_LIST);
  821. //if (List) {
  822. //
  823. // Count = SendMessage (List, LB_GETCOUNT, 0, 0);
  824. // for (Index = 0 ; Index < Count ; Index++) {
  825. // Data = (PCTSTR) SendMessage (List, LB_GETITEMDATA, Index, 0);
  826. // if (Data) {
  827. // MemFree (g_hHeap, 0, Data);
  828. // }
  829. // }
  830. //}
  831. break;
  832. }
  833. return FALSE;
  834. }
  835. BOOL
  836. pIsAdministratorOnly (
  837. VOID
  838. )
  839. {
  840. BOOL NonAdminExists = FALSE;
  841. PCTSTR AdministratorName;
  842. HKEY Key;
  843. REGVALUE_ENUM e;
  844. PCTSTR Data;
  845. BOOL AdministratorExists = FALSE;
  846. AdministratorName = GetStringResource (MSG_ADMINISTRATOR);
  847. MYASSERT (AdministratorName);
  848. Key = OpenRegKeyStr (S_USER_LIST_KEY);
  849. if (Key) {
  850. //
  851. // Enumerate the users in this key. Data is saved with
  852. // each list entry, though it is not currently used.
  853. //
  854. if (EnumFirstRegValue (&e, Key)) {
  855. do {
  856. Data = GetRegValueString (e.KeyHandle, e.ValueName);
  857. if (Data) {
  858. if (!StringIMatch (e.ValueName, AdministratorName)) {
  859. NonAdminExists = TRUE;
  860. } else {
  861. AdministratorExists = TRUE;
  862. }
  863. MemFree (g_hHeap, 0, Data);
  864. }
  865. } while (EnumNextRegValue (&e));
  866. }
  867. CloseRegKey (Key);
  868. }
  869. ELSE_DEBUGMSG ((DBG_WARNING, "%s not found", S_USER_LIST_KEY));
  870. FreeStringResource (AdministratorName);
  871. return !NonAdminExists && AdministratorExists;
  872. }
  873. BOOL
  874. pIsBlankPasswordAllowed (
  875. VOID
  876. )
  877. {
  878. PUSER_MODALS_INFO_0 umi;
  879. NET_API_STATUS rc;
  880. BOOL b;
  881. rc = NetUserModalsGet (
  882. NULL,
  883. 0,
  884. (PBYTE *) &umi
  885. );
  886. if (rc != ERROR_SUCCESS) {
  887. SetLastError(rc);
  888. DEBUGMSG ((DBG_ERROR, "Can't get password policy info"));
  889. return TRUE;
  890. }
  891. b = (umi->usrmod0_min_passwd_len == 0);
  892. NetApiBufferFree ((PVOID) umi);
  893. return b;
  894. }