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.

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