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.

5407 lines
168 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: mslogon.c
  7. //
  8. // Contents: Microsoft Logon GUI DLL
  9. //
  10. // History: 7-14-94 RichardW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "msgina.h"
  14. #include "shtdnp.h"
  15. #include "authmon.h"
  16. #include <stdio.h>
  17. #include <wchar.h>
  18. #include <wincrypt.h>
  19. #include <sclogon.h>
  20. #include "shlwapi.h"
  21. #include "shlwapip.h"
  22. #include "winsta.h"
  23. #include "wtsapi32.h"
  24. #include <keymgr.h>
  25. #include <passrec.h>
  26. typedef void (WINAPI *RUNDLLPROC)(HWND hWndStub,HINSTANCE hInstance,LPWSTR szCommandLine,int nShow);
  27. typedef struct _MSGINA_LOGON_PARAMETERS {
  28. PGLOBALS pGlobals;
  29. DWORD SasType;
  30. } MSGINA_LOGON_PARAMETERS, * PMSGINA_LOGON_PARAMETERS ;
  31. #define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
  32. //
  33. // Number of seconds we will display the legal notices
  34. // before timing out.
  35. //
  36. #define LEGAL_NOTICE_TIMEOUT 120
  37. #define LOGON_SLEEP_PERIOD 750
  38. #define WM_LOGONPROMPT WM_USER + 257
  39. #define WM_LOGONCOMPLETE WM_USER + 258
  40. #define WM_HANDLEFAILEDLOGON WM_USER + 259
  41. #define WM_DCACHE_COMPLETE WM_USER + 260
  42. #define MAX_CAPTION_LENGTH 256
  43. // Maximum size of a UPN name we allow at present
  44. #define MAX_UPN_NAME_SIZE 520
  45. typedef struct FAILEDLOGONINFO_t
  46. {
  47. PGLOBALS pGlobals;
  48. NTSTATUS Status;
  49. NTSTATUS SubStatus;
  50. TCHAR UserName[UNLEN + DNLEN + 2];
  51. TCHAR Domain[DNLEN + 1];
  52. } FAILEDLOGONINFO, *PFAILEDLOGONINFO;
  53. typedef struct _LEGALINFO
  54. {
  55. LPTSTR NoticeText;
  56. LPTSTR CaptionText;
  57. } LEGALINFO, *PLEGALINFO;
  58. // Also defined in wstrpc.c
  59. #define INET_CONNECTOR_EVENT_NAME L"Global\\TermSrvInetConnectorEvent"
  60. #define TERMSERV_EVENTSOURCE L"TermService"
  61. // Also defined in icaevent.mc
  62. #define EVENT_BAD_TSINTERNET_USER 1007
  63. //
  64. // Globals:
  65. //
  66. static WNDPROC OldCBWndProc;
  67. HICON hSteadyFlag;
  68. HICON hWavingFlag;
  69. HICON hAuditFull;
  70. extern HICON hLockedIcon;
  71. BOOL IsPswBackupAvailable;
  72. BOOL s_fAttemptedAutoLogon;
  73. BOOL g_fHelpAssistantLogon = FALSE;
  74. BOOL g_FirstTime = TRUE;
  75. //
  76. // Prototypes:
  77. //
  78. INT_PTR
  79. DisplayLegalNotices(
  80. PGLOBALS pGlobals
  81. );
  82. BOOL
  83. GetLegalNotices(
  84. LPTSTR lpSubKey,
  85. LPTSTR *NoticeText,
  86. LPTSTR *CaptionText
  87. );
  88. INT_PTR WINAPI
  89. LogonDlgCBProc(
  90. HWND hDlg,
  91. UINT message,
  92. WPARAM wParam,
  93. LPARAM lParam
  94. );
  95. INT_PTR WINAPI
  96. LogonDlgUsernameProc(
  97. HWND hDlg,
  98. UINT message,
  99. WPARAM wParam,
  100. LPARAM lParam
  101. );
  102. INT_PTR WINAPI
  103. LogonDlgProc(
  104. HWND hDlg,
  105. UINT message,
  106. WPARAM wParam,
  107. LPARAM lParam
  108. );
  109. BOOL
  110. LogonDlgInit(
  111. HWND hDlg,
  112. BOOL bAutoLogon,
  113. DWORD SasType
  114. );
  115. NTSTATUS
  116. UpnFromCert(
  117. IN PCCERT_CONTEXT pCert,
  118. IN OUT DWORD *pcUpn,
  119. IN OUT LPWSTR pUPN
  120. );
  121. BOOL
  122. WINAPI
  123. QuerySwitchConsoleCredentials(
  124. PGLOBALS pGlobals,
  125. HANDLE * phUserToken,
  126. PLUID pLogonId);
  127. // Global structure for a failed logon filled in by the worker thread to be consumed
  128. // by the ui thread.
  129. FAILEDLOGONINFO g_failinfo;
  130. void PostFailedLogonMessage(HWND hDlg,
  131. PGLOBALS pGlobals,
  132. NTSTATUS Status,
  133. NTSTATUS SubStatus,
  134. PWCHAR UserName,
  135. PWCHAR Domain
  136. );
  137. INT_PTR
  138. HandleFailedLogon(
  139. HWND hDlg
  140. );
  141. VOID
  142. ReportBootGood(
  143. PGLOBALS pGlobals
  144. );
  145. VOID LogonShowOptions(
  146. PGLOBALS pGlobals,
  147. HWND hDlg,
  148. BOOL fShow,
  149. BOOL fSticky);
  150. VOID AttemptLogonSetControls(
  151. PGLOBALS pGlobals,
  152. HWND hDlg
  153. );
  154. INT_PTR
  155. AttemptLogon(
  156. HWND hDlg
  157. );
  158. DWORD
  159. AttemptLogonThread(
  160. PGLOBALS pGlobals
  161. );
  162. BOOL
  163. GetAndAllocateLogonSid(
  164. HANDLE hToken,
  165. PSID *pLogonSid
  166. );
  167. BOOL GetSessionZeroUser(LPTSTR szUser, int nUserMax);
  168. BOOL FastUserSwitchingEnabled();
  169. //
  170. // control tables for showing/hiding options
  171. //
  172. static UINT ctrlNoShutdown[] =
  173. {
  174. IDOK,
  175. IDCANCEL,
  176. };
  177. static UINT ctrlNoCancel[] =
  178. {
  179. IDOK,
  180. };
  181. static UINT ctrlNoDomain[] =
  182. {
  183. IDOK,
  184. IDCANCEL,
  185. IDD_LOGON_SHUTDOWN,
  186. IDD_LOGON_OPTIONS,
  187. IDD_LOGON_RASBOX,
  188. IDD_KBLAYOUT_ICON,
  189. };
  190. static UINT ctrlNoRAS[] =
  191. {
  192. IDOK,
  193. IDCANCEL,
  194. IDD_LOGON_SHUTDOWN,
  195. IDD_LOGON_OPTIONS,
  196. IDD_KBLAYOUT_ICON,
  197. };
  198. static UINT ctrlNoOptions[] =
  199. {
  200. IDOK,
  201. IDCANCEL,
  202. IDD_LOGON_SHUTDOWN,
  203. IDD_KBLAYOUT_ICON,
  204. };
  205. static UINT ctrlNoLegalBanner[] =
  206. {
  207. IDD_LOGON_NAME_LABEL,
  208. IDD_LOGON_NAME,
  209. IDD_LOGON_PASSWORD_LABEL,
  210. IDD_LOGON_PASSWORD,
  211. IDD_LOGON_DOMAIN_LABEL,
  212. IDD_LOGON_DOMAIN,
  213. IDD_LOGON_RASBOX,
  214. IDD_KBLAYOUT_ICON,
  215. IDOK,
  216. IDCANCEL,
  217. IDD_LOGON_SHUTDOWN,
  218. IDD_LOGON_OPTIONS,
  219. };
  220. static UINT ctrlNoUserName[] =
  221. {
  222. IDD_LOGON_PASSWORD_LABEL,
  223. IDD_LOGON_PASSWORD,
  224. IDD_LOGON_DOMAIN_LABEL,
  225. IDD_LOGON_DOMAIN,
  226. IDD_LOGON_RASBOX,
  227. IDD_KBLAYOUT_ICON,
  228. IDOK,
  229. IDCANCEL,
  230. IDD_LOGON_SHUTDOWN,
  231. IDD_LOGON_OPTIONS,
  232. };
  233. // --------------------------------------------------------------------------
  234. // ::DisableEditSubClassProc
  235. //
  236. // Arguments: hwnd = See the platform SDK under WindowProc.
  237. // uMsg = See the platform SDK under WindowProc.
  238. // wParam = See the platform SDK under WindowProc.
  239. // lParam = See the platform SDK under WindowProc.
  240. // uiID = ID assigned at subclass time.
  241. // dwRefData = reference data assigned at subclass time.
  242. //
  243. // Returns: LRESULT
  244. //
  245. // Purpose: comctl32 subclass callback function. This allows us to not
  246. // process WM_CUT/WM_COPY/WM_PASTE/WM_CLEAR/WM_UNDO and any
  247. // other messages to be discarded.
  248. //
  249. // History: 2001-02-18 vtan created
  250. // --------------------------------------------------------------------------
  251. LRESULT CALLBACK DisableEditSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
  252. {
  253. LRESULT lResult;
  254. switch (uMsg)
  255. {
  256. case WM_CUT:
  257. case WM_COPY:
  258. case WM_PASTE:
  259. case WM_CLEAR:
  260. case WM_UNDO:
  261. case WM_CONTEXTMENU:
  262. lResult = FALSE;
  263. break;
  264. default:
  265. lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
  266. break;
  267. }
  268. return(lResult);
  269. }
  270. INT_PTR WINAPI
  271. LegalDlgProc(
  272. HWND hDlg,
  273. UINT message,
  274. WPARAM wParam,
  275. LPARAM lParam
  276. )
  277. {
  278. switch (message)
  279. {
  280. case WM_INITDIALOG:
  281. {
  282. PLEGALINFO pLegalInfo;
  283. pLegalInfo = (PLEGALINFO) lParam;
  284. SetWindowText (hDlg, pLegalInfo->CaptionText);
  285. SetWindowText (GetDlgItem(hDlg, IDD_LEGALTEXT), pLegalInfo->NoticeText);
  286. CentreWindow(hDlg);
  287. // Ensure the window is topmost so it's not obscured by the welcome screen.
  288. SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  289. return( TRUE );
  290. }
  291. case WM_COMMAND:
  292. {
  293. if (LOWORD(wParam) == IDOK)
  294. {
  295. EndDialog(hDlg, IDOK);
  296. }
  297. }
  298. break;
  299. }
  300. return FALSE;
  301. }
  302. /***************************************************************************\
  303. * FUNCTION: DisplayLegalNotices
  304. *
  305. * PURPOSE: Puts up a dialog box containing legal notices, if any.
  306. *
  307. * RETURNS: MSGINA_DLG_SUCCESS - the dialog was shown and dismissed successfully.
  308. * MSGINA_DLG_FAILURE - the dialog could not be shown
  309. * DLG_INTERRUPTED() - a set defined in winlogon.h
  310. *
  311. * HISTORY:
  312. *
  313. * Robertre 6-30-93 Created
  314. *
  315. \***************************************************************************/
  316. INT_PTR
  317. DisplayLegalNotices(
  318. PGLOBALS pGlobals
  319. )
  320. {
  321. INT_PTR Result = MSGINA_DLG_SUCCESS;
  322. LPTSTR NoticeText;
  323. LPTSTR CaptionText;
  324. LEGALINFO LegalInfo;
  325. if (GetLegalNotices( WINLOGON_POLICY_KEY, &NoticeText, &CaptionText ))
  326. {
  327. LegalInfo.NoticeText = NoticeText;
  328. LegalInfo.CaptionText = CaptionText;
  329. _Shell_LogonStatus_Hide();
  330. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
  331. Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
  332. hDllInstance,
  333. (LPTSTR) IDD_LEGALMSG,
  334. NULL,
  335. LegalDlgProc,
  336. (LPARAM) &LegalInfo );
  337. _Shell_LogonStatus_Show();
  338. Free( NoticeText );
  339. Free( CaptionText );
  340. }
  341. else if (GetLegalNotices( WINLOGON_KEY, &NoticeText, &CaptionText ))
  342. {
  343. LegalInfo.NoticeText = NoticeText;
  344. LegalInfo.CaptionText = CaptionText;
  345. _Shell_LogonStatus_Hide();
  346. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
  347. Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
  348. hDllInstance,
  349. (LPTSTR) IDD_LEGALMSG,
  350. NULL,
  351. LegalDlgProc,
  352. (LPARAM) &LegalInfo );
  353. _Shell_LogonStatus_Show();
  354. Free( NoticeText );
  355. Free( CaptionText );
  356. }
  357. return( Result );
  358. }
  359. /***************************************************************************\
  360. * FUNCTION: GetLegalNotices
  361. *
  362. * PURPOSE: Get legal notice information out of the registry.
  363. *
  364. * RETURNS: TRUE - Output parameters contain valid data
  365. * FALSE - No data returned.
  366. *
  367. * HISTORY:
  368. *
  369. * Robertre 6-30-93 Created
  370. *
  371. \***************************************************************************/
  372. BOOL
  373. GetLegalNotices(
  374. LPTSTR lpSubKey,
  375. LPTSTR *NoticeText,
  376. LPTSTR *CaptionText
  377. )
  378. {
  379. LPTSTR lpCaption, lpText;
  380. HKEY hKey;
  381. DWORD dwSize, dwType, dwMaxSize = 0;
  382. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey,
  383. 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  384. {
  385. RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL,
  386. NULL, NULL, NULL, NULL, &dwMaxSize,
  387. NULL, NULL);
  388. lpCaption = Alloc (dwMaxSize);
  389. if (!lpCaption) {
  390. RegCloseKey(hKey);
  391. return FALSE;
  392. }
  393. lpText = Alloc (dwMaxSize);
  394. if (!lpText) {
  395. Free(lpCaption);
  396. RegCloseKey(hKey);
  397. return FALSE;
  398. }
  399. dwSize = dwMaxSize;
  400. if ((ERROR_SUCCESS != RegQueryValueEx(hKey, LEGAL_NOTICE_CAPTION_KEY,
  401. 0, &dwType, (LPBYTE)lpCaption, &dwSize)) ||
  402. (dwType != REG_SZ))
  403. {
  404. lpCaption[0] = 0;
  405. }
  406. dwSize = dwMaxSize;
  407. if ((ERROR_SUCCESS != RegQueryValueEx(hKey, LEGAL_NOTICE_TEXT_KEY,
  408. 0, &dwType, (LPBYTE)lpText, &dwSize)) ||
  409. (dwType != REG_SZ))
  410. {
  411. lpText[0] = 0;
  412. }
  413. RegCloseKey(hKey);
  414. if (*lpCaption && *lpText) {
  415. *CaptionText = lpCaption;
  416. *NoticeText = lpText;
  417. return TRUE;
  418. }
  419. Free(lpCaption);
  420. Free(lpText);
  421. }
  422. return FALSE;
  423. }
  424. /***************************************************************************\
  425. * FUNCTION: Logon
  426. *
  427. * PURPOSE: Display the logon UI depending on the SAS type.
  428. *
  429. * RETURNS: -
  430. *
  431. * NOTES: If the logon is successful, the global structure is filled in
  432. * with the logon information.
  433. *
  434. * HISTORY:
  435. * 12-09-91 daviddv Comments.
  436. *
  437. \***************************************************************************/
  438. INT_PTR
  439. Logon(
  440. PGLOBALS pGlobals,
  441. DWORD SasType
  442. )
  443. {
  444. INT_PTR Result;
  445. MSGINA_LOGON_PARAMETERS Parm ;
  446. if ( SasType == WLX_SAS_TYPE_SC_REMOVE )
  447. {
  448. return WLX_SAS_ACTION_NONE ;
  449. }
  450. if( !g_Console )
  451. {
  452. //
  453. // Check if current session is HelpAssistant Session, HelpAssisant
  454. // session can not be console session.
  455. //
  456. g_fHelpAssistantLogon = WinStationIsHelpAssistantSession(
  457. SERVERNAME_CURRENT,
  458. LOGONID_CURRENT
  459. );
  460. }
  461. if ( SasType == WLX_SAS_TYPE_SC_INSERT )
  462. {
  463. PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
  464. pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
  465. WLX_OPTION_SMART_CARD_INFO,
  466. (ULONG_PTR *) &ScInfo );
  467. //
  468. // Validate the SC info against some common user
  469. // errors before the PIN dialog appears
  470. //
  471. if ( ScInfo )
  472. {
  473. if ( ( ScInfo->pszReader ) &&
  474. ( ScInfo->pszCard == NULL ) )
  475. {
  476. //
  477. // The card could not be read. Might not be
  478. // inserted correctly.
  479. //
  480. LocalFree(ScInfo);
  481. TimeoutMessageBox( NULL, pGlobals, IDS_CARD_NOT_RECOGNIZED,
  482. IDS_LOGON_MESSAGE,
  483. MB_OK | MB_ICONEXCLAMATION,
  484. LOGON_TIMEOUT );
  485. return WLX_SAS_ACTION_NONE;
  486. }
  487. if ( ( ScInfo->pszReader ) &&
  488. ( ScInfo->pszCryptoProvider == NULL ) )
  489. {
  490. //
  491. // Got a card, but the CSP for it could not be
  492. // found.
  493. //
  494. LocalFree(ScInfo);
  495. TimeoutMessageBox( NULL, pGlobals, IDS_CARD_CSP_NOT_RECOGNIZED,
  496. IDS_LOGON_MESSAGE,
  497. MB_OK | MB_ICONEXCLAMATION,
  498. LOGON_TIMEOUT );
  499. return WLX_SAS_ACTION_NONE;
  500. }
  501. LocalFree(ScInfo);
  502. }
  503. }
  504. //
  505. // Asynchronously update domain cache if necessary.
  506. // We won't ask to wait so this routine will do no UI.
  507. // i.e. we can ignore the result.
  508. //
  509. // Result = UpdateDomainCache(pGlobals, NULL, FALSE);
  510. // ASSERT(!DLG_INTERRUPTED(Result));
  511. if( !g_fHelpAssistantLogon ) {
  512. //
  513. // See if there are legal notices in the registry.
  514. // If so, put them up in a message box
  515. //
  516. Result = DisplayLegalNotices( pGlobals );
  517. if ( Result != MSGINA_DLG_SUCCESS ) {
  518. return(WLX_SAS_ACTION_NONE);
  519. }
  520. //
  521. // Get the latest audit log status and store in our globals
  522. // If the audit log is full we show a different logon dialog.
  523. //
  524. GetAuditLogStatus(pGlobals);
  525. } else {
  526. //
  527. // fake it so audit log is not full, setting is from GetAuditLogStatus()
  528. //
  529. pGlobals->AuditLogFull = FALSE;
  530. pGlobals->AuditLogNearFull = FALSE;
  531. }
  532. Parm.pGlobals = pGlobals ;
  533. Parm.SasType = SasType ;
  534. //
  535. // Take their username and password and try to log them on
  536. //
  537. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx,
  538. ( (GetDisableCad(pGlobals) && IsActiveConsoleSession()) ? TIMEOUT_NONE : LOGON_TIMEOUT));
  539. Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx,
  540. hDllInstance,
  541. MAKEINTRESOURCE(IDD_LOGON_DIALOG),
  542. NULL,
  543. LogonDlgProc,
  544. (LPARAM) &Parm );
  545. return(Result);
  546. }
  547. /***************************************************************************\
  548. * FUNCTION: LogonDlgCBProc
  549. *
  550. * PURPOSE: Processes messages for Logon dialog combo box
  551. *
  552. * RETURNS: Return value depends on message being sent.
  553. *
  554. * HISTORY:
  555. *
  556. * 05-21-93 RobertRe Created.
  557. *
  558. \***************************************************************************/
  559. INT_PTR WINAPI
  560. LogonDlgCBProc(
  561. HWND hwnd,
  562. UINT message,
  563. WPARAM wParam,
  564. LPARAM lParam
  565. )
  566. {
  567. TCHAR KeyPressed;
  568. // DbgPrint("message = %X\n",message);
  569. switch (message) {
  570. case WM_CHAR:
  571. {
  572. KeyPressed = (TCHAR) wParam;
  573. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)KeyPressed);
  574. //
  575. // This fake CBN_SELCHANGE message will cause the
  576. // "Please wait..." dialog box to appear even if
  577. // the character pressed doesn't exist in the combobox yet.
  578. //
  579. PostMessage (GetParent(hwnd), WM_COMMAND,
  580. MAKELONG(0, CBN_SELCHANGE), 0);
  581. break;
  582. }
  583. }
  584. return CallWindowProc(OldCBWndProc,hwnd,message,wParam,lParam);
  585. }
  586. INT_PTR
  587. CALLBACK
  588. DomainCacheDlgProc(
  589. HWND hDlg,
  590. UINT Message,
  591. WPARAM wParam,
  592. LPARAM lParam
  593. )
  594. {
  595. PGLOBALS pGlobals ;
  596. DebugLog(( DEB_TRACE_DOMAIN, "DomainCacheDlgProc( %p, %x, %p, %p )\n",
  597. hDlg, Message, wParam, lParam ));
  598. switch ( Message )
  599. {
  600. case WM_INITDIALOG:
  601. pGlobals = (PGLOBALS) lParam ;
  602. if ( DCacheSetNotifyWindowIfNotReady(
  603. pGlobals->Cache,
  604. hDlg,
  605. WM_DCACHE_COMPLETE ) )
  606. {
  607. EndDialog( hDlg, TRUE );
  608. }
  609. return TRUE ;
  610. case WM_DCACHE_COMPLETE:
  611. EndDialog( hDlg, TRUE );
  612. return TRUE ;
  613. default:
  614. return FALSE ;
  615. }
  616. }
  617. #ifdef ANNOY_AUTOLOGON_REGISTRY
  618. #define TIMER_COUNTDOWN 0
  619. INT_PTR
  620. CALLBACK
  621. AnnoyAutologonDlgProc(
  622. HWND hDlg,
  623. UINT Message,
  624. WPARAM wParam,
  625. LPARAM lParam
  626. )
  627. {
  628. PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  629. LARGE_INTEGER Now;
  630. WCHAR szBuild[10]; // Build number or countdown
  631. switch ( Message )
  632. {
  633. case WM_INITDIALOG:
  634. pGlobals = (PGLOBALS) lParam ;
  635. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pGlobals);
  636. SetTimer(hDlg, TIMER_COUNTDOWN, 1000, NULL); // 1 sec
  637. {
  638. DWORD cbBuild;
  639. HKEY hKey;
  640. DWORD dwStatus = RegOpenKeyEx(
  641. HKEY_LOCAL_MACHINE,
  642. L"Software\\Microsoft\\Windows NT\\CurrentVersion",
  643. 0,
  644. KEY_READ,
  645. &hKey
  646. );
  647. cbBuild = sizeof(szBuild);
  648. wcscpy(szBuild, L""); // OK
  649. if (dwStatus == ERROR_SUCCESS)
  650. {
  651. DWORD dwType = REG_SZ;
  652. dwStatus = RegQueryValueEx(
  653. hKey,
  654. L"CurrentBuildNumber",
  655. 0,
  656. &dwType,
  657. (LPBYTE) szBuild,
  658. &cbBuild
  659. );
  660. if ((dwStatus != ERROR_SUCCESS) || (dwType != REG_SZ))
  661. {
  662. szBuild[0] = 0;
  663. }
  664. RegCloseKey(hKey);
  665. }
  666. // 10 sec per build penalty, up to 15 minutes
  667. cbBuild = _wtol(szBuild);
  668. if ((0 == cbBuild) || (cbBuild <= 3590))
  669. {
  670. cbBuild = 3591;
  671. }
  672. if (cbBuild - 3590 > 15 * 6)
  673. {
  674. cbBuild = 3590 + 15 * 6;
  675. }
  676. GetSystemTimeAsFileTime((FILETIME*) &Now);
  677. Now.QuadPart += (cbBuild - 3590) * 10 * 10000000I64;
  678. pGlobals->LastNotification.dwHighDateTime = Now.HighPart;
  679. pGlobals->LastNotification.dwLowDateTime = Now.LowPart;
  680. cbBuild = (cbBuild - 3590) * 10;
  681. // SAFE: "00:XX:YY" is 8+1 characters (fits in 10)
  682. swprintf(szBuild, L"00:%02d:%02d", (cbBuild/60)%100, cbBuild%60);
  683. SetDlgItemText(hDlg, IDC_COUNTDOWN_STATIC, szBuild);
  684. }
  685. return TRUE ;
  686. case WM_TIMER:
  687. if (wParam == TIMER_COUNTDOWN)
  688. {
  689. LARGE_INTEGER End;
  690. End.HighPart = pGlobals->LastNotification.dwHighDateTime;
  691. End.LowPart = pGlobals->LastNotification.dwLowDateTime;
  692. GetSystemTimeAsFileTime((FILETIME*) &Now);
  693. if (Now.QuadPart >= End.QuadPart)
  694. {
  695. EndDialog(hDlg, MSGINA_DLG_SUCCESS);
  696. }
  697. else
  698. {
  699. DWORD dwMins, dwSecs;
  700. End.QuadPart -= Now.QuadPart;
  701. End.QuadPart = End.QuadPart / 10000000I64; // secs
  702. dwMins = ((DWORD)End.QuadPart) / 60 % 100;
  703. dwSecs = ((DWORD)End.QuadPart) % 60;
  704. // SAFE: "00:XX:YY" is 8+1 characters (fits in 10)
  705. swprintf(szBuild, L"00:%02d:%02d", dwMins, dwSecs);
  706. SetDlgItemText(hDlg, IDC_COUNTDOWN_STATIC, szBuild);
  707. }
  708. return TRUE;
  709. }
  710. break;
  711. case WM_DESTROY:
  712. KillTimer(hDlg, TIMER_COUNTDOWN);
  713. pGlobals->LastNotification.dwHighDateTime = 0;
  714. pGlobals->LastNotification.dwLowDateTime = 0;
  715. break;
  716. case WM_COMMAND:
  717. switch (LOWORD(wParam))
  718. {
  719. case IDCANCEL:
  720. // EndDialog(hDlg, MSGINA_DLG_FAILURE);
  721. return(TRUE);
  722. }
  723. break;
  724. case WLX_WM_SAS:
  725. // Swallow SAS
  726. return(TRUE);
  727. }
  728. return FALSE ;
  729. }
  730. #endif
  731. BOOL IsAutoLogonUserInteractiveLogonRestricted (HWND hDlg)
  732. {
  733. WCHAR szUsername[UNLEN + 1]; // sizeof('\0')
  734. return((GetDlgItemText(hDlg, IDD_LOGON_NAME, szUsername, ARRAYSIZE(szUsername)) != 0) &&
  735. !ShellIsUserInteractiveLogonAllowed(szUsername));
  736. }
  737. BOOL HasDefaultPassword (TCHAR *pszPassword, int cchPassword)
  738. {
  739. DWORD dwType, dwPasswordSize;
  740. dwType = REG_NONE;
  741. dwPasswordSize = cchPassword * sizeof(TCHAR);
  742. return(ERROR_SUCCESS == RegQueryValueEx(WinlogonKey,
  743. DEFAULT_PASSWORD_KEY,
  744. NULL,
  745. &dwType,
  746. (LPBYTE)pszPassword,
  747. &dwPasswordSize) &&
  748. (REG_SZ == dwType));
  749. }
  750. NTSTATUS RetrieveStoredSecret(LPCWSTR pswSecretName, WCHAR *PasswordBuffer, int nBufferSize)
  751. {
  752. NTSTATUS Status = STATUS_SUCCESS;
  753. OBJECT_ATTRIBUTES ObjectAttributes;
  754. LSA_HANDLE LsaHandle = NULL;
  755. UNICODE_STRING SecretName;
  756. PUNICODE_STRING SecretValue = NULL;
  757. //
  758. // Set up the object attributes to open the Lsa policy object
  759. //
  760. InitializeObjectAttributes(&ObjectAttributes,
  761. NULL,
  762. 0L,
  763. (HANDLE)NULL,
  764. NULL);
  765. //
  766. // Open the local LSA policy object
  767. //
  768. Status = LsaOpenPolicy( NULL,
  769. &ObjectAttributes,
  770. POLICY_VIEW_LOCAL_INFORMATION,
  771. &LsaHandle
  772. );
  773. if (NT_SUCCESS(Status)) {
  774. RtlInitUnicodeString(
  775. &SecretName,
  776. pswSecretName
  777. );
  778. Status = LsaRetrievePrivateData(
  779. LsaHandle,
  780. &SecretName,
  781. &SecretValue
  782. );
  783. if (NT_SUCCESS(Status)) {
  784. if ( SecretValue->Length > 0 ) {
  785. //
  786. // If the password fits in the buffer, copy it there
  787. // and null terminate
  788. //
  789. if (SecretValue->Length < (nBufferSize - 1) * sizeof(WCHAR)) {
  790. RtlCopyMemory(
  791. PasswordBuffer,
  792. SecretValue->Buffer,
  793. SecretValue->Length
  794. );
  795. PasswordBuffer[SecretValue->Length/sizeof(WCHAR)] = L'\0';
  796. } else {
  797. Status = STATUS_INVALID_PARAMETER;
  798. }
  799. ZeroMemory(SecretValue->Buffer, SecretValue->Length);
  800. }
  801. else
  802. {
  803. PasswordBuffer[0] = L'\0';
  804. }
  805. LsaFreeMemory(SecretValue);
  806. }
  807. LsaClose(LsaHandle);
  808. }
  809. return Status;
  810. }
  811. // ==========================================================================================
  812. // Logon dialog has 2 formats, one that looks like logon dialog box, another that looks like
  813. // unlock desktop dialogbox. When user connects to session 0 from remote (tsclient) the
  814. // dialog that appears at console // need to change to unlock computer. so if session 0 is in
  815. // use, and if this session is created at active console. we change logon dialog to look like
  816. // "unlock computer" dialog.
  817. // This function SwitchLogonLocked does most of the stuff related to switching these
  818. // dialog controls.
  819. // Parameters:
  820. // HWND hDlg - dialog window handle,
  821. // BOOL bShowLocked - if true show locked dialog, if false show normal logon dialog.
  822. // BOOL bInit - TRUE when this function is called for the first time.
  823. // ==========================================================================================
  824. static bLocked = TRUE;
  825. BOOL IsthisUnlockWindowsDialog ()
  826. {
  827. return bLocked;
  828. }
  829. BOOL SwitchLogonLocked(HWND hDlg, BOOL bShowLocked, BOOL bInit)
  830. {
  831. UINT rgidLockControls[] = {IDC_GROUP_UNLOCK, IDD_UNLOCK_ICON, IDD_UNLOCK_MESSAGE, IDD_UNLOCK_NAME_INFO};
  832. static LockedControlHeight = 0;
  833. BOOL bShutdownWithoutLogon;
  834. int i;
  835. if (bShowLocked == bLocked && !bInit)
  836. {
  837. // nothing to do.
  838. return TRUE;
  839. }
  840. if (bInit)
  841. {
  842. {
  843. //
  844. // remember the reference rectangle height (groupbox) for control movements.
  845. //
  846. RECT rectLockedControls;
  847. HWND hWnd = GetDlgItem(hDlg, rgidLockControls[0]);
  848. GetWindowRect(hWnd, &rectLockedControls);
  849. LockedControlHeight = rectLockedControls.bottom - rectLockedControls.top;
  850. //
  851. // this group box was only for reference, now hide it forever.
  852. //
  853. ShowWindow(hWnd, SW_HIDE);
  854. }
  855. bLocked = TRUE;
  856. if ( !hLockedIcon )
  857. {
  858. hLockedIcon = LoadImage( hDllInstance,
  859. MAKEINTRESOURCE( IDI_LOCKED),
  860. IMAGE_ICON,
  861. 0, 0,
  862. LR_DEFAULTCOLOR );
  863. }
  864. SendMessage( GetDlgItem( hDlg, IDD_UNLOCK_ICON),
  865. STM_SETICON,
  866. (WPARAM)hLockedIcon,
  867. 0 );
  868. }
  869. // lets move controls arround, depending upon if lock controls are to be shown or not.
  870. if (bLocked != bShowLocked)
  871. {
  872. if (bShowLocked)
  873. {
  874. MoveChildren(hDlg, 0, LockedControlHeight);
  875. for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++)
  876. {
  877. HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]);
  878. ASSERT(hWnd);
  879. EnableWindow(hWnd, TRUE);
  880. ShowWindow(hWnd, SW_SHOW);
  881. }
  882. }
  883. else
  884. {
  885. for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++)
  886. {
  887. HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]);
  888. ASSERT(hWnd);
  889. ShowWindow(hWnd, SW_HIDE);
  890. EnableWindow(hWnd, FALSE);
  891. }
  892. MoveChildren(hDlg, 0, -LockedControlHeight);
  893. }
  894. }
  895. // some more processing
  896. {
  897. if (bShowLocked)
  898. {
  899. TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2];
  900. TCHAR szMessage[MAX_STRING_BYTES] = TEXT("");
  901. TCHAR szFinalMessage[MAX_STRING_BYTES] = TEXT("");
  902. if (GetSessionZeroUser(szUser, USERNAME_LENGTH + DOMAIN_LENGTH + 2))
  903. {
  904. LoadString(hDllInstance, IDS_LOCKED_EMAIL_NFN_MESSAGE, szMessage, MAX_STRING_BYTES);
  905. _snwprintf(szFinalMessage, sizeof(szFinalMessage)/sizeof(TCHAR), szMessage, szUser );
  906. szFinalMessage[sizeof(szFinalMessage)/sizeof(TCHAR) - 1] = 0; // NULL terminate
  907. }
  908. else
  909. {
  910. //
  911. // for some reason we could not get the current session zero user.
  912. //
  913. LoadString(hDllInstance, IDS_LOCKED_NO_USER_MESSAGE, szFinalMessage, MAX_STRING_BYTES);
  914. }
  915. SetDlgItemText(hDlg, IDD_UNLOCK_NAME_INFO, szFinalMessage);
  916. }
  917. //
  918. // update the dialog box caption, accordingly
  919. //
  920. {
  921. TCHAR szCaption[MAX_CAPTION_LENGTH] = TEXT("");
  922. LoadString(hDllInstance, bShowLocked ? IDS_CAPTION_UNLOCK_DIALOG : IDS_CAPTION_LOGON_DIALOG, szCaption, ARRAYSIZE(szCaption));
  923. if ( szCaption[0] != TEXT('\0') )
  924. SetWindowText( hDlg, szCaption );
  925. }
  926. }
  927. bLocked = bShowLocked;
  928. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  929. {
  930. bShutdownWithoutLogon = TRUE ;
  931. }
  932. else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession())
  933. {
  934. bShutdownWithoutLogon = FALSE ;
  935. }
  936. else
  937. {
  938. bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE);
  939. }
  940. EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, bShutdownWithoutLogon);
  941. InvalidateRect(hDlg, NULL, TRUE);
  942. return TRUE;
  943. }
  944. /***************************************************************************\
  945. * FUNCTION: LogonDlgProc
  946. *
  947. * PURPOSE: Processes messages for Logon dialog
  948. *
  949. * RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
  950. * MSGINA_DLG_FAILURE - the logon failed,
  951. * DLG_INTERRUPTED() - a set defined in winlogon.h
  952. *
  953. * HISTORY:
  954. *
  955. * 12-09-91 Davidc Created.
  956. *
  957. \***************************************************************************/
  958. void MyZeroMemory(PVOID lpv, SIZE_T size);
  959. #define WM_HIDEOURSELVES (WM_USER + 1000)
  960. INT_PTR WINAPI
  961. LogonDlgProc(
  962. HWND hDlg,
  963. UINT message,
  964. WPARAM wParam,
  965. LPARAM lParam
  966. )
  967. {
  968. PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  969. INT_PTR Result;
  970. HWND CBHandle;
  971. BOOL fDisconnectOnTsAutoLogonFailure = FALSE;
  972. static BOOL bSessionZeroInUse = FALSE;
  973. static int iSessionRegistrationCount = 0;
  974. static BOOL bSmartCardInserted = FALSE;
  975. switch (message)
  976. {
  977. case WM_INITDIALOG:
  978. {
  979. TCHAR PasswordBuffer[127];
  980. BOOL bAutoLogon;
  981. PMSGINA_LOGON_PARAMETERS pParam ;
  982. pParam = (PMSGINA_LOGON_PARAMETERS) lParam ;
  983. pGlobals = pParam->pGlobals ;
  984. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pGlobals);
  985. // Hide the keyboard accelerator keys to start
  986. SendMessage(hDlg, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
  987. // Limit the maximum password length to 127
  988. SendDlgItemMessage(hDlg, IDD_LOGON_PASSWORD, EM_SETLIMITTEXT, (WPARAM) 127, 0);
  989. s_fAttemptedAutoLogon = FALSE;
  990. //
  991. // Check if auto logon is enabled.
  992. //
  993. pGlobals->AutoAdminLogon = GetProfileInt( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, 0 ) != 0;
  994. bAutoLogon = !pGlobals->IgnoreAutoAdminLogon;
  995. if ( !pGlobals->AutoAdminLogon || (!g_Console) ||
  996. ((GetAsyncKeyState(VK_SHIFT) < 0) && (GetProfileInt( APPLICATION_NAME, IGNORE_SHIFT_OVERRIDE_KEY, 0 ) == 0)) )
  997. {
  998. bAutoLogon = FALSE;
  999. }
  1000. KdPrint(("AutoAdminLogon = %d, IgnoreAutoAdminLogon = %d, bAutoLogon = %d\n",
  1001. pGlobals->AutoAdminLogon,
  1002. pGlobals->IgnoreAutoAdminLogon,
  1003. bAutoLogon ));
  1004. //
  1005. // Subclass the domain list control so we can filter messages
  1006. //
  1007. CBHandle = GetDlgItem(hDlg,IDD_LOGON_DOMAIN);
  1008. SetWindowLongPtr(CBHandle, GWLP_USERDATA, 0);
  1009. OldCBWndProc = (WNDPROC) SetWindowLongPtr(CBHandle, GWLP_WNDPROC, (LONG_PTR)LogonDlgCBProc);
  1010. //
  1011. // Subclass the user name and password edit also so we can disable edits
  1012. //
  1013. SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME) , DisableEditSubClassProc, IDD_LOGON_NAME , 0);
  1014. SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD, 0);
  1015. ShellReleaseLogonMutex(FALSE);
  1016. if (!LogonDlgInit(hDlg, bAutoLogon, pParam->SasType ))
  1017. {
  1018. bSmartCardInserted = FALSE;
  1019. EndDialog(hDlg, MSGINA_DLG_FAILURE);
  1020. return(TRUE);
  1021. }
  1022. //
  1023. // If the default user for auto logon is present and the user is
  1024. // restricted (interactive logon denied) then disable auto logon.
  1025. //
  1026. if (bAutoLogon && IsAutoLogonUserInteractiveLogonRestricted(hDlg))
  1027. {
  1028. bAutoLogon = FALSE;
  1029. }
  1030. //
  1031. // If CAD is disabled, then gray out the Cancel button
  1032. // if we are going to the PIN dialog we will need a cancel button
  1033. //
  1034. if (GetDisableCad(pGlobals) &&
  1035. IsActiveConsoleSession() &&
  1036. (pParam->SasType != WLX_SAS_TYPE_SC_INSERT))
  1037. {
  1038. EnableDlgItem(hDlg, IDCANCEL, FALSE);
  1039. }
  1040. //
  1041. // this dialog has 2 formats, one that looks like logon dialog box,
  1042. // another that looks like unlock desktop dialogbox.
  1043. // we choose locked one, if session 0 is in use, and if this session is created at
  1044. // active console.
  1045. //
  1046. if (g_IsTerminalServer &&
  1047. IsActiveConsoleSession() &&
  1048. NtCurrentPeb()->SessionId != 0 &&
  1049. !FastUserSwitchingEnabled() &&
  1050. !_ShellIsFriendlyUIActive())
  1051. {
  1052. TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2];
  1053. //
  1054. // we are at temporary session created at console...
  1055. //
  1056. // check if a user is logged on at console session
  1057. bSessionZeroInUse = GetSessionZeroUser(szUser, USERNAME_LENGTH + DOMAIN_LENGTH + 2);
  1058. if (WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, hDlg, NOTIFY_FOR_ALL_SESSIONS))
  1059. {
  1060. iSessionRegistrationCount++;
  1061. }
  1062. }
  1063. else
  1064. {
  1065. //
  1066. // this is not active console nonzero session.
  1067. //
  1068. bSessionZeroInUse = FALSE;
  1069. }
  1070. //
  1071. //
  1072. // now switch the control, accordigly to show logon or unlock dialog
  1073. //
  1074. SwitchLogonLocked(hDlg, bSessionZeroInUse, TRUE);
  1075. if (g_IsTerminalServer) {
  1076. BOOL fForceUPN;
  1077. BOOL fPopulateFields = TRUE;
  1078. BOOL fResult = FALSE;
  1079. BOOL fNoAutologon = FALSE;
  1080. PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pAutoLogon;
  1081. //
  1082. // Query network WinStation client credentials for
  1083. // auto logon
  1084. //
  1085. pGlobals->MuGlobals.pAutoLogon =
  1086. LocalAlloc( LPTR, sizeof(WLX_CLIENT_CREDENTIALS_INFO_V2_0) );
  1087. if (pGlobals->MuGlobals.pAutoLogon) {
  1088. pGlobals->MuGlobals.pAutoLogon->dwType = WLX_CREDENTIAL_TYPE_V2_0;
  1089. if (NtCurrentPeb()->SessionId != 0) {
  1090. fResult = pWlxFuncs->WlxQueryTsLogonCredentials(
  1091. pGlobals->MuGlobals.pAutoLogon
  1092. );
  1093. }
  1094. // Query TermSrv if this was a Session directory redirected SmartCard autoLogon
  1095. if (fResult && !pGlobals->MuGlobals.pAutoLogon->fPromptForPassword && g_FirstTime) {
  1096. BOOL fSessionDirectoryRedirectedAutoLogon = FALSE;
  1097. DWORD Length;
  1098. if (WinStationQueryInformation(
  1099. SERVERNAME_CURRENT,
  1100. LOGONID_CURRENT,
  1101. WinStationSDRedirectedSmartCardLogon,
  1102. &fSessionDirectoryRedirectedAutoLogon,
  1103. sizeof(BOOL),
  1104. &Length)) {
  1105. if ( fSessionDirectoryRedirectedAutoLogon ) {
  1106. //
  1107. // This is a TS Session directory redirected Smartcard autologon
  1108. // We should not proceed with normal Autologon for this special case
  1109. // This is so that Winlogon detects the SmartCard and takes the SmartCard route
  1110. //
  1111. fNoAutologon = TRUE;
  1112. }
  1113. }
  1114. }
  1115. if (FALSE == g_FirstTime)
  1116. {
  1117. // We have tried this password once, no need to retry forever...
  1118. pGlobals->MuGlobals.pAutoLogon->fPromptForPassword = TRUE;
  1119. }
  1120. g_FirstTime = FALSE ;
  1121. if ( fResult && !fNoAutologon &&
  1122. (pGlobals->MuGlobals.pAutoLogon->pszUserName[0] || pGlobals->MuGlobals.pAutoLogon->pszDomain[0] )) {
  1123. pAutoLogon = pGlobals->MuGlobals.pAutoLogon;
  1124. fDisconnectOnTsAutoLogonFailure = pAutoLogon->fDisconnectOnLogonFailure;
  1125. SetupCursor(TRUE); // hourglass cursor
  1126. fForceUPN = GetProfileInt( APPLICATION_NAME, TEXT("TSForceUPN"), FALSE );
  1127. if (fForceUPN)
  1128. {
  1129. fPopulateFields = FALSE; // never show old SAM style is UPN is forced
  1130. }
  1131. if (pAutoLogon->pszDomain[0] == TEXT('\0') && fForceUPN)
  1132. {
  1133. fForceUPN = FALSE; // domain name not provided, can't apply policy
  1134. }
  1135. if (fForceUPN && pGlobals->MuGlobals.pAutoLogon->pszUserName[0] )
  1136. {
  1137. LRESULT iDomain;
  1138. HWND hwndDomain;
  1139. PDOMAIN_CACHE_ENTRY Entry ;
  1140. ULONG nSize;
  1141. // Performance issue. We don't want to perform a UPN conversion
  1142. // for local machine accounts (or unknown domains). When this
  1143. // happens, the lookup will take a LONG time.
  1144. hwndDomain = GetDlgItem( hDlg, IDD_LOGON_DOMAIN );
  1145. iDomain = SendMessage( hwndDomain,
  1146. CB_FINDSTRING,
  1147. (WPARAM) -1,
  1148. (LPARAM) pAutoLogon->pszDomain );
  1149. fForceUPN = FALSE; // don't do the conversion
  1150. if (iDomain != CB_ERR)
  1151. {
  1152. Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomain, 0);
  1153. if ( Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR && Entry != NULL)
  1154. {
  1155. switch (Entry->Type)
  1156. {
  1157. case DomainNt5:
  1158. fForceUPN = TRUE; // Attempt the conversion
  1159. break;
  1160. }
  1161. }
  1162. }
  1163. // Convert the domain\username into UPN format.
  1164. // and make sure the dialog is in UPN form.
  1165. // 2000/10/09 vtan: this function used to have two stack variables
  1166. // szOldStyle and szUPNName that were TCHARs of MAX_UPN_NAME_SIZE size. The
  1167. // fix for this makes these dynamically allocated to save stack space
  1168. {
  1169. TCHAR *pszOldStyle;
  1170. TCHAR *pszUPNName;
  1171. pszOldStyle = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR));
  1172. pszUPNName = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR));
  1173. if ((pszOldStyle != NULL) && (pszUPNName != NULL))
  1174. {
  1175. _snwprintf(pszOldStyle, MAX_UPN_NAME_SIZE, TEXT("%s\\%s"), pAutoLogon->pszDomain, pAutoLogon->pszUserName);
  1176. pszOldStyle[MAX_UPN_NAME_SIZE - 1] = 0;
  1177. nSize = MAX_UPN_NAME_SIZE;
  1178. fResult = TranslateName(
  1179. pszOldStyle,
  1180. NameSamCompatible,
  1181. NameUserPrincipal,
  1182. pszUPNName,
  1183. &nSize
  1184. );
  1185. if (fResult)
  1186. {
  1187. // We now have the UPN form of the user account.
  1188. SetDlgItemText( hDlg, IDD_LOGON_NAME, pszUPNName);
  1189. }
  1190. }
  1191. if (pszOldStyle != NULL)
  1192. {
  1193. LocalFree(pszOldStyle);
  1194. }
  1195. if (pszUPNName != NULL)
  1196. {
  1197. LocalFree(pszUPNName);
  1198. }
  1199. }
  1200. }
  1201. if (fPopulateFields)
  1202. {
  1203. // display the old SAM style
  1204. SetDlgItemText( hDlg, IDD_LOGON_NAME, pAutoLogon->pszUserName );
  1205. SendMessage( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
  1206. CB_SELECTSTRING,
  1207. (WPARAM) -1,
  1208. (LPARAM) pAutoLogon->pszDomain );
  1209. }
  1210. else
  1211. {
  1212. // Enable or disable the domain box depending on whether a UPN name has been typed
  1213. EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
  1214. // Since we're forcing UPN, hide the options dialog, but don't make it sticky
  1215. LogonShowOptions(pGlobals, hDlg, FALSE, FALSE);
  1216. }
  1217. // See if the administrator always wants password prompting
  1218. if ( TRUE == g_fHelpAssistantLogon || !pAutoLogon->fPromptForPassword ) {
  1219. SetDlgItemText( hDlg, IDD_LOGON_PASSWORD, pAutoLogon->pszPassword );
  1220. }
  1221. DCacheSetDefaultEntry(
  1222. pGlobals->Cache,
  1223. pAutoLogon->pszDomain,
  1224. NULL );
  1225. if( TRUE == g_fHelpAssistantLogon || !pGlobals->MuGlobals.pAutoLogon->fPromptForPassword )
  1226. {
  1227. FreeAutoLogonInfo( pGlobals );
  1228. // Drop through as if Enter had been pressed...
  1229. wParam = IDOK;
  1230. goto go_logon;
  1231. }
  1232. else
  1233. {
  1234. FreeAutoLogonInfo( pGlobals );
  1235. }
  1236. }
  1237. else
  1238. {
  1239. FreeAutoLogonInfo( pGlobals );
  1240. }
  1241. }
  1242. }
  1243. if (pGlobals->SmartCardLogon) {
  1244. bAutoLogon = FALSE;
  1245. pGlobals->AutoAdminLogon = FALSE;
  1246. if ( RetrieveStoredSecret( TEXT("DefaultPIN"), PasswordBuffer, ARRAYSIZE(PasswordBuffer)) == STATUS_SUCCESS )
  1247. {
  1248. // Ensure we never write more than 127 chars into the password box
  1249. PasswordBuffer[126] = 0;
  1250. SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
  1251. goto go_logon;
  1252. }
  1253. }
  1254. // save off the auto logon attempt.
  1255. s_fAttemptedAutoLogon = (bAutoLogon != FALSE);
  1256. if (bAutoLogon)
  1257. {
  1258. if (_Shell_LogonDialog_UIHostActive())
  1259. {
  1260. GetWindowRect(hDlg, &pGlobals->rcDialog);
  1261. SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  1262. PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
  1263. }
  1264. }
  1265. else
  1266. {
  1267. switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF))
  1268. {
  1269. case SHELL_LOGONDIALOG_NONE:
  1270. default:
  1271. {
  1272. //
  1273. // If auto logon isn't enabled, set the focus to the
  1274. // password edit control and leave.
  1275. //
  1276. return(SetPasswordFocus(hDlg));
  1277. }
  1278. case SHELL_LOGONDIALOG_LOGON:
  1279. {
  1280. GetWindowRect(hDlg, &pGlobals->rcDialog);
  1281. SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  1282. PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
  1283. goto go_logon;
  1284. }
  1285. case SHELL_LOGONDIALOG_EXTERNALHOST:
  1286. {
  1287. return(TRUE);
  1288. }
  1289. }
  1290. }
  1291. //
  1292. // Attempt to auto logon. If no default password
  1293. // specified, then this is a one shot attempt, which handles
  1294. // the case when auto logging on as Administrator.
  1295. //
  1296. if (HasDefaultPassword(PasswordBuffer, ARRAYSIZE(PasswordBuffer)) != FALSE)
  1297. {
  1298. // Ensure we never write more than 127 chars into the password box
  1299. PasswordBuffer[126] = 0;
  1300. SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
  1301. #ifdef ANNOY_AUTOLOGON_REGISTRY
  1302. pWlxFuncs->WlxDialogBoxParam(
  1303. pGlobals->hGlobalWlx,
  1304. hDllInstance,
  1305. (LPTSTR) IDD_ANNOYAUTOLOGON_DIALOG,
  1306. hDlg,
  1307. AnnoyAutologonDlgProc,
  1308. (LPARAM) pGlobals );
  1309. #endif
  1310. }
  1311. else
  1312. {
  1313. NTSTATUS Status;
  1314. Status = RetrieveStoredSecret( DEFAULT_PASSWORD_KEY, PasswordBuffer, ARRAYSIZE(PasswordBuffer) );
  1315. if (NT_SUCCESS(Status)) {
  1316. SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
  1317. }
  1318. else
  1319. {
  1320. WriteProfileString( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, TEXT("0") );
  1321. }
  1322. }
  1323. go_logon:
  1324. // Zeroize this buffer for obvious security reasons
  1325. // Need to call this stub, otherwise the compiler optimizes this out!
  1326. MyZeroMemory(PasswordBuffer, sizeof(PasswordBuffer));
  1327. // Drop through as if Enter had been pressed...
  1328. wParam = IDOK;
  1329. }
  1330. // nb: deliberate drop through from above
  1331. case WM_COMMAND:
  1332. switch (HIWORD(wParam))
  1333. {
  1334. case CBN_DROPDOWN:
  1335. case CBN_SELCHANGE:
  1336. DebugLog((DEB_TRACE, "Got CBN_DROPDOWN\n"));
  1337. if ( !pGlobals->ListPopulated )
  1338. {
  1339. WCHAR Buffer[ 2 ];
  1340. if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache )
  1341. {
  1342. pWlxFuncs->WlxDialogBoxParam(
  1343. pGlobals->hGlobalWlx,
  1344. hDllInstance,
  1345. (LPTSTR) IDD_WAITDOMAINCACHEVALID_DIALOG,
  1346. hDlg,
  1347. DomainCacheDlgProc,
  1348. (LPARAM) pGlobals );
  1349. }
  1350. if ( DCacheGetCacheState( pGlobals->Cache ) == DomainCacheReady )
  1351. {
  1352. PDOMAIN_CACHE_ARRAY ActiveArrayBackup ;
  1353. ActiveArrayBackup = pGlobals->ActiveArray;
  1354. pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
  1355. if ( pGlobals->ActiveArray )
  1356. {
  1357. DCacheFreeArray( ActiveArrayBackup ); // Not needed anymore
  1358. Buffer[ 0 ] = (WCHAR) GetWindowLongPtr( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
  1359. GWLP_USERDATA );
  1360. Buffer[ 1 ] = L'\0';
  1361. DCachePopulateListBoxFromArray(
  1362. pGlobals->ActiveArray,
  1363. GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
  1364. Buffer );
  1365. pGlobals->ListPopulated = TRUE ;
  1366. }
  1367. else
  1368. {
  1369. //
  1370. // Restore the old array, otherwise the pointers in the
  1371. // combo items will point to freed memory
  1372. //
  1373. pGlobals->ActiveArray = ActiveArrayBackup ;
  1374. }
  1375. }
  1376. }
  1377. break;
  1378. default:
  1379. switch (LOWORD(wParam))
  1380. {
  1381. case IDD_LOGON_NAME:
  1382. {
  1383. switch(HIWORD(wParam))
  1384. {
  1385. case EN_CHANGE:
  1386. {
  1387. EnableDomainForUPN((HWND) lParam, GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
  1388. return TRUE;
  1389. }
  1390. }
  1391. }
  1392. break;
  1393. case IDOK:
  1394. //
  1395. // Deal with combo-box UI requirements
  1396. //
  1397. if (HandleComboBoxOK(hDlg, IDD_LOGON_DOMAIN))
  1398. {
  1399. return(TRUE);
  1400. }
  1401. Result = AttemptLogon( hDlg );
  1402. if (Result == MSGINA_DLG_FAILURE)
  1403. {
  1404. if (!fDisconnectOnTsAutoLogonFailure &&
  1405. !g_fHelpAssistantLogon ) {
  1406. // Let the user try again
  1407. // Clear the password field and set focus to it
  1408. SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL);
  1409. SetPasswordFocus(hDlg);
  1410. } else {
  1411. bSmartCardInserted = FALSE;
  1412. EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF);
  1413. }
  1414. return(TRUE);
  1415. }
  1416. return(TRUE);
  1417. case IDCANCEL:
  1418. {
  1419. if (!_Shell_LogonDialog_Cancel())
  1420. {
  1421. // If this is TS and the user hit ESC at the smart card pin prompt
  1422. // we want to switch to the password dialog
  1423. if (/*!g_Console && !IsActiveConsoleSession() && */pGlobals->SmartCardLogon) {
  1424. EndDialog(hDlg, bSmartCardInserted ? MSGINA_DLG_SMARTCARD_REMOVED : MSGINA_DLG_FAILURE);
  1425. bSmartCardInserted = FALSE;
  1426. return TRUE;
  1427. }
  1428. //
  1429. // Allow logon screen to go away if not at console
  1430. //
  1431. bSmartCardInserted = FALSE;
  1432. EndDialog(hDlg, !g_Console ? MSGINA_DLG_USER_LOGOFF
  1433. : MSGINA_DLG_FAILURE);
  1434. if (g_Console && !IsActiveConsoleSession()) {
  1435. pWlxFuncs->WlxDisconnect();
  1436. }
  1437. }
  1438. return(TRUE);
  1439. }
  1440. case IDD_LOGON_SHUTDOWN:
  1441. //
  1442. // This is a normal shutdown request
  1443. //
  1444. // Check they know what they're doing and find
  1445. // out if they want to reboot too.
  1446. //
  1447. // Note that we definitely don't want disconnect or logofff
  1448. // here since no one is logged on
  1449. Result = WinlogonShutdownDialog(hDlg, pGlobals, (SHTDN_DISCONNECT | SHTDN_LOGOFF));
  1450. if (DLG_SHUTDOWN(Result))
  1451. {
  1452. _Shell_LogonDialog_ShuttingDown();
  1453. bSmartCardInserted = FALSE;
  1454. EndDialog(hDlg, Result);
  1455. }
  1456. return(TRUE);
  1457. case IDD_LOGON_OPTIONS:
  1458. LogonShowOptions(pGlobals, hDlg, !pGlobals->LogonOptionsShown, TRUE);
  1459. return(TRUE);
  1460. }
  1461. break;
  1462. }
  1463. break;
  1464. case WM_TIMER:
  1465. {
  1466. switch (wParam)
  1467. {
  1468. case 0:
  1469. {
  1470. HDC hDC;
  1471. RtlEnterCriticalSection(&pGlobals->csGlobals);
  1472. if ( pGlobals->LogonInProgress )
  1473. {
  1474. if (pGlobals->cxBand != 0)
  1475. {
  1476. pGlobals->xBandOffset = (pGlobals->xBandOffset+5) % pGlobals->cxBand;
  1477. }
  1478. }
  1479. else
  1480. {
  1481. pGlobals->xBandOffset = 0;
  1482. KillTimer(hDlg, 0);
  1483. }
  1484. RtlLeaveCriticalSection(&pGlobals->csGlobals);
  1485. hDC = GetDC(hDlg);
  1486. if ( hDC )
  1487. {
  1488. PaintBranding(hDlg, hDC, pGlobals->xBandOffset, TRUE, TRUE, COLOR_BTNFACE);
  1489. ReleaseDC(hDlg, hDC);
  1490. }
  1491. return FALSE;
  1492. }
  1493. case TIMER_MYLANGUAGECHECK:
  1494. {
  1495. LayoutCheckHandler(hDlg, LAYOUT_DEF_USER);
  1496. break;
  1497. }
  1498. }
  1499. break;
  1500. }
  1501. case WM_ERASEBKGND:
  1502. return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, TRUE, COLOR_BTNFACE);
  1503. case WM_QUERYNEWPALETTE:
  1504. return BrandingQueryNewPalete(hDlg);
  1505. case WM_PALETTECHANGED:
  1506. return BrandingPaletteChanged(hDlg, (HWND)wParam);
  1507. case WM_LOGONCOMPLETE:
  1508. {
  1509. _Shell_LogonDialog_LogonCompleted(lParam, pGlobals->UserName, pGlobals->Domain);
  1510. Result = lParam;
  1511. //
  1512. // Discard the logon in progress dialog if one is displayed
  1513. //
  1514. RtlEnterCriticalSection(&pGlobals->csGlobals);
  1515. pGlobals->LogonInProgress = FALSE;
  1516. RtlLeaveCriticalSection(&pGlobals->csGlobals);
  1517. AttemptLogonSetControls(pGlobals, hDlg);
  1518. if (Result == MSGINA_DLG_FAILURE)
  1519. {
  1520. //
  1521. // reset autoadmin logon flag (Bug 532161)
  1522. //
  1523. pGlobals->AutoAdminLogon = FALSE;
  1524. //
  1525. // erase the stored password, that otherwise (on success)
  1526. // would get erased after the dialog finishes with
  1527. // MSGINA_DLG_SUCCESS in WlxLoggedOutSAS after Logon
  1528. //
  1529. if (!pGlobals->TransderedCredentials)
  1530. {
  1531. ErasePassword( &pGlobals->PasswordString );
  1532. }
  1533. if (fDisconnectOnTsAutoLogonFailure || g_fHelpAssistantLogon)
  1534. {
  1535. //
  1536. // If TermSrv Internet Connector is on
  1537. // don't allow a second chance at the logon dialog
  1538. //
  1539. bSmartCardInserted = FALSE;
  1540. EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF);
  1541. break;
  1542. }
  1543. if (s_fAttemptedAutoLogon != FALSE)
  1544. {
  1545. s_fAttemptedAutoLogon = FALSE;
  1546. switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF))
  1547. {
  1548. case SHELL_LOGONDIALOG_LOGON:
  1549. goto go_logon;
  1550. break;
  1551. case SHELL_LOGONDIALOG_EXTERNALHOST:
  1552. break;
  1553. case SHELL_LOGONDIALOG_NONE:
  1554. default:
  1555. if (!IsWindowVisible(hDlg))
  1556. {
  1557. //
  1558. // The dialog was hidden for automatic logon. An error occurred.
  1559. // Show the dialog so the error can be seen and the problem corrected.
  1560. //
  1561. SetWindowPos(hDlg, NULL, 0, 0, pGlobals->rcDialog.right - pGlobals->rcDialog.left, pGlobals->rcDialog.bottom - pGlobals->rcDialog.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  1562. ShowWindow(hDlg, SW_SHOW);
  1563. }
  1564. break;
  1565. }
  1566. }
  1567. if (!_Shell_LogonDialog_UIHostActive())
  1568. {
  1569. // Let the user try again - clear the password
  1570. SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL);
  1571. SetPasswordFocus(hDlg);
  1572. // the logon failed, so lets ensure we show the options pane so they can update
  1573. // their domain selection if needed.
  1574. if ( !pGlobals->LogonOptionsShown )
  1575. LogonShowOptions(pGlobals, hDlg, TRUE, FALSE);
  1576. }
  1577. return(TRUE);
  1578. }
  1579. bSmartCardInserted = FALSE;
  1580. EndDialog( hDlg, Result );
  1581. break;
  1582. }
  1583. case WM_HANDLEFAILEDLOGON:
  1584. {
  1585. if (_Shell_LogonDialog_LogonDisplayError(g_failinfo.Status, g_failinfo.SubStatus))
  1586. {
  1587. if (!IsWindowVisible(hDlg))
  1588. {
  1589. //
  1590. // The dialog was hidden for automatic logon. An error occurred.
  1591. // Show the dialog so the error can be seen and the problem corrected.
  1592. //
  1593. SetWindowPos(hDlg, NULL, 0, 0, pGlobals->rcDialog.right - pGlobals->rcDialog.left, pGlobals->rcDialog.bottom - pGlobals->rcDialog.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  1594. ShowWindow(hDlg, SW_SHOW);
  1595. }
  1596. Result = HandleFailedLogon(hDlg);
  1597. }
  1598. else
  1599. {
  1600. Result = MSGINA_DLG_FAILURE;
  1601. }
  1602. SendMessage(hDlg, WM_LOGONCOMPLETE, 0, (LPARAM) Result);
  1603. return TRUE;
  1604. }
  1605. case WLX_WM_SAS:
  1606. // Give the consumer logon part a chance to handle the SAS
  1607. // or to key off the fact that a SAS has occurred.
  1608. (BOOL)_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam);
  1609. if ((wParam == WLX_SAS_TYPE_TIMEOUT) ||
  1610. (wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) )
  1611. {
  1612. //
  1613. // If this was a timeout, return false, and let winlogon
  1614. // kill us later
  1615. //
  1616. bSmartCardInserted = FALSE;
  1617. return(FALSE);
  1618. }
  1619. if ( wParam == WLX_SAS_TYPE_SC_INSERT ) {
  1620. //
  1621. // If a password logon is already taking place then ignore this sas
  1622. //
  1623. if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon)
  1624. {
  1625. return(TRUE);
  1626. }
  1627. bSmartCardInserted = TRUE;
  1628. EndDialog( hDlg, MSGINA_DLG_SMARTCARD_INSERTED );
  1629. } else if ( wParam == WLX_SAS_TYPE_SC_REMOVE ) {
  1630. //
  1631. // If a password logon is already taking place then ignore this sas
  1632. //
  1633. if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon)
  1634. {
  1635. return(TRUE);
  1636. }
  1637. if ( bSmartCardInserted ) {
  1638. bSmartCardInserted = FALSE;
  1639. EndDialog( hDlg, MSGINA_DLG_SMARTCARD_REMOVED );
  1640. } else if ( pGlobals->SmartCardLogon ) {
  1641. // If this was a s/c initiated logon, then cancel
  1642. // the dialog. Otherwise, ignore it.
  1643. bSmartCardInserted = FALSE;
  1644. EndDialog( hDlg, MSGINA_DLG_FAILURE );
  1645. }
  1646. } else if ( wParam == WLX_SAS_TYPE_AUTHENTICATED )
  1647. {
  1648. bSmartCardInserted = FALSE;
  1649. _Shell_LogonDialog_LogonCompleted(MSGINA_DLG_SWITCH_CONSOLE, pGlobals->UserName, pGlobals->Domain);
  1650. EndDialog( hDlg, MSGINA_DLG_SWITCH_CONSOLE );
  1651. }
  1652. return(TRUE);
  1653. case WM_WTSSESSION_CHANGE:
  1654. ASSERT(iSessionRegistrationCount < 2);
  1655. //
  1656. // its possible, that we unregister for notification in wm_destroy and still receive this notification,
  1657. // as the notification may already have been sent.
  1658. //
  1659. if (iSessionRegistrationCount == 1)
  1660. {
  1661. if (lParam == 0)
  1662. {
  1663. //
  1664. // we are interested only in logon/logoff messages from session 0.
  1665. //
  1666. if (wParam == WTS_SESSION_LOGON || wParam == WTS_SESSION_LOGOFF)
  1667. {
  1668. bSessionZeroInUse = (wParam == WTS_SESSION_LOGON);
  1669. SwitchLogonLocked(hDlg, bSessionZeroInUse, FALSE);
  1670. }
  1671. }
  1672. }
  1673. break;
  1674. case WM_DESTROY:
  1675. // if registered for notification unregister now.
  1676. if (iSessionRegistrationCount)
  1677. {
  1678. WinStationUnRegisterConsoleNotification (SERVERNAME_CURRENT, hDlg);
  1679. iSessionRegistrationCount--;
  1680. ASSERT(iSessionRegistrationCount == 0);
  1681. }
  1682. _Shell_LogonDialog_Destroy();
  1683. FreeLayoutInfo(LAYOUT_DEF_USER);
  1684. if ( pGlobals->ActiveArray )
  1685. {
  1686. DCacheFreeArray( pGlobals->ActiveArray );
  1687. pGlobals->ActiveArray = NULL ;
  1688. }
  1689. RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME), DisableEditSubClassProc, IDD_LOGON_NAME);
  1690. RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD);
  1691. break;
  1692. case WM_HIDEOURSELVES:
  1693. ShowWindow(hDlg, SW_HIDE);
  1694. break;
  1695. default:
  1696. if (_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam) != FALSE)
  1697. {
  1698. return(TRUE);
  1699. }
  1700. }
  1701. return(FALSE);
  1702. }
  1703. SECURITY_STATUS PopulateSecPackageList(
  1704. PGLOBALS pGlobals
  1705. )
  1706. {
  1707. static UCHAR s_bDoneThat = 0;
  1708. STRING Narrow;
  1709. SECURITY_STATUS Status;
  1710. //
  1711. // Populate Security Package List:
  1712. //
  1713. if ( ( s_bDoneThat & 1) == 0)
  1714. {
  1715. RtlInitString( &Narrow, MICROSOFT_KERBEROS_NAME_A );
  1716. Status = LsaLookupAuthenticationPackage(
  1717. pGlobals->LsaHandle,
  1718. &Narrow,
  1719. &pGlobals->SmartCardLogonPackage );
  1720. if ( NT_SUCCESS( Status ) )
  1721. {
  1722. s_bDoneThat |= 1;
  1723. }
  1724. //
  1725. // this (potential) failure is not critical. If it fails, then s/c logons later
  1726. // will fail.
  1727. //
  1728. }
  1729. Status = 0;
  1730. if ( ( s_bDoneThat & 2) == 0)
  1731. {
  1732. RtlInitString( &Narrow, NEGOSSP_NAME_A );
  1733. Status = LsaLookupAuthenticationPackage(
  1734. pGlobals->LsaHandle,
  1735. &Narrow,
  1736. &pGlobals->PasswordLogonPackage );
  1737. if ( NT_SUCCESS( Status ) )
  1738. {
  1739. s_bDoneThat |= 2;
  1740. }
  1741. }
  1742. return Status;
  1743. }
  1744. /***************************************************************************\
  1745. * FUNCTION: LogonDlgInit
  1746. *
  1747. * PURPOSE: Handles initialization of logon dialog
  1748. *
  1749. * RETURNS: TRUE on success, FALSE on failure
  1750. *
  1751. * HISTORY:
  1752. *
  1753. * 12-09-91 Davidc Created.
  1754. *
  1755. \***************************************************************************/
  1756. BOOL
  1757. LogonDlgInit(
  1758. HWND hDlg,
  1759. BOOL bAutoLogon,
  1760. DWORD SasType
  1761. )
  1762. {
  1763. PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  1764. LPTSTR String = NULL;
  1765. TCHAR LogonMsg[MAX_PATH];
  1766. BOOL RemoveLegalBanner;
  1767. BOOL ShowOptions = FALSE;
  1768. HKEY hKey;
  1769. int err;
  1770. DWORD RasDisable;
  1771. DWORD RasForce;
  1772. SECURITY_STATUS Status;
  1773. RECT rc, rc2;
  1774. BOOL bHasLangIcon = FALSE;
  1775. ULONG CacheFlags ;
  1776. //
  1777. // Populate Security Package List:
  1778. //
  1779. Status = PopulateSecPackageList(
  1780. pGlobals );
  1781. if ( !NT_SUCCESS( Status ) )
  1782. {
  1783. return FALSE ;
  1784. }
  1785. //
  1786. // Update the caption for certain banks
  1787. //
  1788. SetWelcomeCaption(hDlg);
  1789. //
  1790. // Get username and domain last used to login
  1791. //
  1792. //
  1793. // Ignore the default user name unless on the active console
  1794. //
  1795. if (IsActiveConsoleSession())
  1796. {
  1797. String = NULL;
  1798. if ( pGlobals->AutoAdminLogon && pGlobals->IgnoreAutoAdminLogon)
  1799. {
  1800. String = AllocAndGetProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, TEXT(""));
  1801. }
  1802. if ( (!String) || (!String[0]) )
  1803. {
  1804. if ( String )
  1805. {
  1806. Free(String);
  1807. }
  1808. String = AllocAndGetProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, TEXT(""));
  1809. }
  1810. if ( String )
  1811. {
  1812. if (!bAutoLogon && (ReadWinlogonBoolValue(DONT_DISPLAY_LAST_USER_KEY, FALSE) == TRUE))
  1813. {
  1814. String[0] = 0;
  1815. }
  1816. SetDlgItemText(hDlg, IDD_LOGON_NAME, String);
  1817. Free(String);
  1818. }
  1819. }
  1820. GetProfileString( APPLICATION_NAME,
  1821. DEFAULT_DOMAIN_NAME_KEY,
  1822. TEXT(""),
  1823. pGlobals->Domain,
  1824. MAX_STRING_BYTES );
  1825. if ( !DCacheValidateCache( pGlobals->Cache ) )
  1826. {
  1827. ASSERT( pGlobals->ActiveArray == NULL );
  1828. DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, FALSE );
  1829. }
  1830. else
  1831. {
  1832. //
  1833. // Set the current default:
  1834. //
  1835. DCacheSetDefaultEntry( pGlobals->Cache,
  1836. pGlobals->Domain,
  1837. NULL );
  1838. }
  1839. CacheFlags = DCacheGetFlags( pGlobals->Cache );
  1840. if ( ( CacheFlags & DCACHE_NO_CACHE ) &&
  1841. ( SafeBootMode != SAFEBOOT_MINIMAL ) &&
  1842. ( ( pGlobals->AutoAdminLogon ) ||
  1843. ( CacheFlags & DCACHE_DEF_UNKNOWN ) ) )
  1844. {
  1845. //
  1846. // Must wait for the cache to be populated
  1847. //
  1848. DCacheUpdateFull( pGlobals->Cache,
  1849. pGlobals->Domain );
  1850. CacheFlags = DCacheGetFlags( pGlobals->Cache );
  1851. }
  1852. else
  1853. {
  1854. if ( DCacheGetCacheState( pGlobals->Cache ) != DomainCacheReady )
  1855. {
  1856. DCacheUpdateFullAsync( pGlobals->Cache );
  1857. }
  1858. }
  1859. pGlobals->ListPopulated = FALSE ;
  1860. pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
  1861. if ( pGlobals->ActiveArray )
  1862. {
  1863. DCachePopulateListBoxFromArray( pGlobals->ActiveArray,
  1864. GetDlgItem( hDlg, IDD_LOGON_DOMAIN ),
  1865. NULL );
  1866. }
  1867. else
  1868. {
  1869. return ( FALSE );
  1870. }
  1871. pGlobals->ShowRasBox = FALSE;
  1872. if (g_Console) {
  1873. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1874. TEXT("Software\\Microsoft\\RAS"),
  1875. 0,
  1876. KEY_READ,
  1877. & hKey );
  1878. if ( err == 0 )
  1879. {
  1880. RegCloseKey( hKey );
  1881. if ( GetRasDialOutProtocols() )
  1882. {
  1883. if ( ( CacheFlags & DCACHE_MEMBER ) != 0 )
  1884. {
  1885. pGlobals->ShowRasBox = TRUE;
  1886. }
  1887. else
  1888. {
  1889. UNICODE_STRING DnsDomain = { 0 } ;
  1890. if ( GetPrimaryDomainEx( NULL, &DnsDomain, NULL, NULL ) &&
  1891. ( DnsDomain.Buffer != NULL) )
  1892. { // We are "joined" to a MIT realm
  1893. pGlobals->ShowRasBox = TRUE;
  1894. LocalFree( DnsDomain.Buffer );
  1895. }
  1896. }
  1897. }
  1898. }
  1899. }
  1900. //
  1901. // If the audit log is full then display the banner, otherwise
  1902. // load the text from the resource if that gives us a string
  1903. // then set the control.
  1904. //
  1905. // Should neither of these apply then remove the control.
  1906. // The log full info is only displayed at the console so we
  1907. // don't disclose too much info in TS sessions.
  1908. //
  1909. RemoveLegalBanner = FALSE;
  1910. if ( pGlobals->AuditLogFull && !GetSystemMetrics(SM_REMOTESESSION))
  1911. {
  1912. if ( LoadString( hDllInstance, IDS_LOGON_LOG_FULL, LogonMsg, MAX_PATH ) )
  1913. {
  1914. SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, LogonMsg );
  1915. }
  1916. else
  1917. {
  1918. RemoveLegalBanner = TRUE;
  1919. }
  1920. }
  1921. else
  1922. {
  1923. String = AllocAndGetProfileString( APPLICATION_NAME,
  1924. LOGON_MSG_KEY, TEXT("") );
  1925. if ( String )
  1926. {
  1927. if ( *String )
  1928. {
  1929. SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, String );
  1930. }
  1931. else
  1932. {
  1933. RemoveLegalBanner = TRUE;
  1934. }
  1935. Free( String );
  1936. }
  1937. else
  1938. {
  1939. RemoveLegalBanner = TRUE;
  1940. }
  1941. }
  1942. if ( RemoveLegalBanner )
  1943. {
  1944. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_ANNOUNCE), &rc);
  1945. MoveControls(hDlg, ctrlNoLegalBanner,
  1946. sizeof(ctrlNoLegalBanner)/sizeof(ctrlNoLegalBanner[0]),
  1947. 0, rc.top-rc.bottom,
  1948. TRUE);
  1949. ShowDlgItem(hDlg, IDD_LOGON_ANNOUNCE, FALSE);
  1950. }
  1951. //
  1952. // Smart Card Specific Stuff:
  1953. //
  1954. if ( SasType == WLX_SAS_TYPE_SC_INSERT )
  1955. {
  1956. //
  1957. // remove the user name fields
  1958. //
  1959. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_NAME), &rc);
  1960. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc2);
  1961. MoveControls(hDlg, ctrlNoUserName,
  1962. sizeof(ctrlNoUserName)/sizeof(ctrlNoUserName[0]),
  1963. 0, -(rc2.top-rc.top),
  1964. TRUE);
  1965. ShowDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE);
  1966. EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE);
  1967. ShowDlgItem(hDlg, IDD_LOGON_NAME, FALSE);
  1968. EnableDlgItem(hDlg, IDD_LOGON_NAME, FALSE);
  1969. SetDlgItemText( hDlg, IDD_LOGON_NAME, TEXT(""));
  1970. LogonMsg[0] = 0;
  1971. LoadString(hDllInstance, IDS_PIN, LogonMsg, MAX_PATH);
  1972. SetDlgItemText( hDlg, IDD_LOGON_PASSWORD_LABEL, LogonMsg );
  1973. pGlobals->SmartCardLogon = TRUE;
  1974. }
  1975. else
  1976. {
  1977. pGlobals->SmartCardLogon = FALSE;
  1978. }
  1979. //
  1980. // If this is safe boot and/or we are not part of a domain then lets
  1981. // remove the domain and nix out the RAS box.
  1982. //
  1983. if ((SafeBootMode == SAFEBOOT_MINIMAL)
  1984. || (!IsMachineDomainMember())
  1985. || (SasType == WLX_SAS_TYPE_SC_INSERT)
  1986. || (ForceNoDomainUI()))
  1987. {
  1988. ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE);
  1989. EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE);
  1990. ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE);
  1991. EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE);
  1992. pGlobals->ShowDomainBox = FALSE;
  1993. // Shorten the window since the domain box isn't used
  1994. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc);
  1995. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2);
  1996. MoveControls(hDlg, ctrlNoDomain,
  1997. ARRAYSIZE(ctrlNoDomain),
  1998. 0, -(rc2.bottom-rc.bottom),
  1999. TRUE);
  2000. }
  2001. else
  2002. {
  2003. pGlobals->ShowDomainBox = TRUE;
  2004. }
  2005. bHasLangIcon = DisplayLanguageIcon(hDlg, LAYOUT_DEF_USER, GetKeyboardLayout(0));
  2006. //
  2007. // Handle showing the RAS box if needed
  2008. //
  2009. if ( pGlobals->ShowRasBox )
  2010. {
  2011. RasDisable = GetProfileInt( APPLICATION_NAME, RAS_DISABLE, 0 );
  2012. RasForce = GetProfileInt( APPLICATION_NAME, RAS_FORCE, 0 );
  2013. if (RasForce)
  2014. {
  2015. CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 1 );
  2016. }
  2017. else
  2018. {
  2019. CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
  2020. }
  2021. // SM_CLEANBOOT tells us we are in safe mode. In this case, disable since tapisrv isn't started
  2022. if (RasDisable || RasForce || GetSystemMetrics(SM_CLEANBOOT))
  2023. {
  2024. EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
  2025. }
  2026. else
  2027. {
  2028. EnableDlgItem(hDlg, IDD_LOGON_RASBOX, TRUE);
  2029. }
  2030. }
  2031. else
  2032. {
  2033. // If the domain box is hidden, then we'll have to shorten the dialog by the distance
  2034. // between the RAS box and the password box instead of the distance between the
  2035. // RAS box and the domain box since the RAS and Domain boxes will be on top of each other
  2036. BOOL fUsePassword = !pGlobals->ShowDomainBox;
  2037. CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
  2038. EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
  2039. ShowDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
  2040. GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc);
  2041. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2);
  2042. if (!bHasLangIcon)
  2043. {
  2044. MoveControls(hDlg, ctrlNoRAS,
  2045. sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]),
  2046. 0, -(rc2.bottom-rc.bottom),
  2047. TRUE);
  2048. }
  2049. }
  2050. // Centre the window on the screen and bring it to the front
  2051. pGlobals->xBandOffset = 0; // band is not animated yet
  2052. SizeForBranding(hDlg, TRUE);
  2053. // Position the window at the same coords as the welcome window
  2054. if ((pGlobals->rcWelcome.right - pGlobals->rcWelcome.left) != 0)
  2055. {
  2056. SetWindowPos(hDlg, NULL, pGlobals->rcWelcome.left, pGlobals->rcWelcome.top,
  2057. 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  2058. }
  2059. else
  2060. {
  2061. CentreWindow(hDlg);
  2062. }
  2063. //
  2064. // Handle showing and hiding the logon bits
  2065. //
  2066. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ,
  2067. &hKey) == ERROR_SUCCESS)
  2068. {
  2069. DWORD dwType, dwSize = sizeof(ShowOptions);
  2070. if ((ERROR_SUCCESS != RegQueryValueEx (hKey, SHOW_LOGON_OPTIONS, NULL, &dwType,
  2071. (LPBYTE)&ShowOptions, &dwSize)) ||
  2072. (REG_DWORD != dwType))
  2073. {
  2074. ShowOptions = FALSE; // restore default
  2075. }
  2076. RegCloseKey (hKey);
  2077. }
  2078. pGlobals->LogonOptionsShown = TRUE;
  2079. LogonShowOptions(pGlobals, hDlg, ShowOptions, TRUE);
  2080. // Success
  2081. return TRUE;
  2082. }
  2083. /****************************************************************************\
  2084. *
  2085. * FUNCTION: LogonShowOptions
  2086. *
  2087. * PURPOSE: Hide the options part of the logon dialog
  2088. *
  2089. * RETURNS: Nothing
  2090. *
  2091. * HISTORY:
  2092. *
  2093. * 15-dec-97 daviddv - Created
  2094. *
  2095. \****************************************************************************/
  2096. VOID LogonShowOptions(PGLOBALS pGlobals, HWND hDlg, BOOL fShow, BOOL fSticky)
  2097. {
  2098. HKEY hKey;
  2099. RECT rc, rc2;
  2100. INT dy = 0;
  2101. INT dx = 0;
  2102. TCHAR szBuffer[32] = TEXT("");
  2103. BOOL bHasLangIcon = TRUE;
  2104. DWORD RasDisable;
  2105. DWORD RasForce;
  2106. if ( pGlobals->LogonOptionsShown != fShow )
  2107. {
  2108. BOOL bShutdownWithoutLogon;
  2109. //
  2110. // Show/hide domain if it is present in the dialog
  2111. //
  2112. if (pGlobals->ShowDomainBox)
  2113. {
  2114. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc);
  2115. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2);
  2116. dy += rc2.bottom-rc.bottom;
  2117. }
  2118. //
  2119. // If RAS is present then lets ensure that we remove that.
  2120. //
  2121. if (GetKeyboardLayoutList(0,NULL) < 2)
  2122. {
  2123. bHasLangIcon = FALSE;
  2124. }
  2125. if ( pGlobals->ShowRasBox || bHasLangIcon)
  2126. {
  2127. // Since the domain box may be hidden with the RAS box directly over
  2128. // top of it, we may need to use the space between the RAS box and the password
  2129. // box
  2130. BOOL fUsePassword = !pGlobals->ShowDomainBox;
  2131. GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc);
  2132. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2);
  2133. dy += rc2.bottom-rc.bottom;
  2134. }
  2135. MoveControls(hDlg, ctrlNoRAS,
  2136. sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]),
  2137. 0, fShow ? dy:-dy,
  2138. TRUE);
  2139. // Handle showing or hiding the shutdown button
  2140. // and moving other controls.
  2141. ShowDlgItem(hDlg, IDD_KBLAYOUT_ICON, fShow);
  2142. EnableWindow(GetDlgItem(hDlg, IDD_KBLAYOUT_ICON), fShow);
  2143. ShowDlgItem(hDlg, IDD_LOGON_SHUTDOWN, fShow);
  2144. // Move the OK and Cancel buttons over if we are hiding shutdown
  2145. // ..Calculate one "button space". Assumes shutdown will always be on the left of options
  2146. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN), &rc);
  2147. GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_OPTIONS), &rc2);
  2148. dx = rc2.left - rc.left;
  2149. // Move OK and Cancel left or right 1 button space
  2150. MoveControls(hDlg, ctrlNoShutdown,
  2151. sizeof(ctrlNoShutdown)/sizeof(ctrlNoShutdown[0]),
  2152. fShow ? -dx:dx, 0,
  2153. FALSE);
  2154. //
  2155. // if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
  2156. // instead of the 2 buttons OK and Cancel
  2157. //
  2158. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  2159. {
  2160. bShutdownWithoutLogon = TRUE ;
  2161. }
  2162. else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession())
  2163. {
  2164. bShutdownWithoutLogon = FALSE ;
  2165. }
  2166. else
  2167. {
  2168. bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE);
  2169. }
  2170. EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, (fShow) &&
  2171. (bShutdownWithoutLogon));
  2172. if ( pGlobals->ShowRasBox )
  2173. {
  2174. ShowDlgItem(hDlg, IDD_LOGON_RASBOX, fShow);
  2175. RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE,0);
  2176. RasForce = GetProfileInt(APPLICATION_NAME, RAS_FORCE, 0);
  2177. // Never enable RAS for cleanboot
  2178. if (!GetSystemMetrics(SM_CLEANBOOT) && !RasForce && !RasDisable)
  2179. {
  2180. EnableWindow(GetDlgItem(hDlg, IDD_LOGON_RASBOX), fShow);
  2181. }
  2182. }
  2183. if ( pGlobals->ShowDomainBox )
  2184. {
  2185. ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, fShow);
  2186. EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL), fShow);
  2187. ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, fShow);
  2188. EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), fShow);
  2189. }
  2190. if ( fSticky )
  2191. {
  2192. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
  2193. {
  2194. RegSetValueEx(hKey, SHOW_LOGON_OPTIONS, 0, REG_DWORD,
  2195. (LPBYTE)&fShow, sizeof(fShow));
  2196. RegCloseKey (hKey);
  2197. }
  2198. }
  2199. }
  2200. //
  2201. // Change the options button to reflect the open/close state
  2202. //
  2203. LoadString(hDllInstance, fShow ? IDS_LESSOPTIONS:IDS_MOREOPTIONS,
  2204. szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]));
  2205. SetDlgItemText(hDlg, IDD_LOGON_OPTIONS, szBuffer);
  2206. pGlobals->LogonOptionsShown = fShow;
  2207. // Enable or disable the domain box depending on whether a UPN name has been typed
  2208. EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
  2209. }
  2210. /***************************************************************************\
  2211. * FUNCTION: AttemptLogonSetControls
  2212. *
  2213. * PURPOSE: Sets up the logon UI to animating and controls to the
  2214. * correct state.
  2215. *
  2216. * HISTORY:
  2217. *
  2218. * 02-05-98 diz Created
  2219. *
  2220. \***************************************************************************/
  2221. VOID AttemptLogonSetControls(
  2222. PGLOBALS pGlobals,
  2223. HWND hDlg
  2224. )
  2225. {
  2226. DWORD RasDisable;
  2227. static BOOL sbRasBoxOriginalyEnabled;
  2228. static BOOL sbShutDownOriginallyEnabled;
  2229. RtlEnterCriticalSection( &pGlobals->csGlobals );
  2230. EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, !pGlobals->LogonInProgress);
  2231. EnableDlgItem(hDlg, IDD_LOGON_NAME, !pGlobals->LogonInProgress);
  2232. EnableDlgItem(hDlg, IDD_LOGON_PASSWORD_LABEL, !pGlobals->LogonInProgress);
  2233. EnableDlgItem(hDlg, IDD_LOGON_PASSWORD, !pGlobals->LogonInProgress);
  2234. EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, !pGlobals->LogonInProgress);
  2235. EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, !pGlobals->LogonInProgress);
  2236. // If no logon is in progress, we want to enable domain box based on whether
  2237. // a UPN has been typed
  2238. if (!pGlobals->LogonInProgress)
  2239. {
  2240. EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
  2241. }
  2242. //
  2243. // MakarP: we should not enable all these control when !pGlobals->LogonInProgress, they should really be reverted back to their original state.
  2244. // but for now I am just looking after IDD_LOGON_RASBOX in remote connection cases to fix bug #267270
  2245. //
  2246. if (pGlobals->LogonInProgress)
  2247. {
  2248. sbRasBoxOriginalyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_RASBOX));
  2249. RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE, 0);
  2250. EnableDlgItem(hDlg, IDD_LOGON_RASBOX, !RasDisable && !pGlobals->LogonInProgress);
  2251. sbShutDownOriginallyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN));
  2252. EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, !pGlobals->LogonInProgress);
  2253. }
  2254. else
  2255. {
  2256. EnableDlgItem(hDlg, IDD_LOGON_RASBOX, sbRasBoxOriginalyEnabled);
  2257. EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, sbShutDownOriginallyEnabled);
  2258. }
  2259. EnableDlgItem(hDlg, IDD_KBLAYOUT_ICON, !pGlobals->LogonInProgress);
  2260. EnableDlgItem(hDlg, IDD_LOGON_OPTIONS, !pGlobals->LogonInProgress);
  2261. //
  2262. // if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
  2263. // instead of the 2 buttons OK and Cancel
  2264. //
  2265. EnableDlgItem(hDlg, IDOK, !pGlobals->LogonInProgress);
  2266. //
  2267. // the logic of enabling the CANCEL button is as follows
  2268. // - if a logon is in progress always disable it (not allowed to cancel)
  2269. // - else if a SC logon always enable it (always allow to get to CAD)
  2270. // - else gray it only when DisableCAD and is set and we're in
  2271. // the active session (i.e. TS always allows Cancel)
  2272. //
  2273. if( pGlobals->LogonInProgress )
  2274. {
  2275. EnableDlgItem(hDlg, IDCANCEL, FALSE);
  2276. }
  2277. else
  2278. {
  2279. if( pGlobals->SmartCardLogon )
  2280. {
  2281. EnableDlgItem(hDlg, IDCANCEL, TRUE);
  2282. }
  2283. else
  2284. {
  2285. EnableDlgItem(hDlg, IDCANCEL,
  2286. !(GetDisableCad(pGlobals) &&
  2287. IsActiveConsoleSession()) );
  2288. }
  2289. }
  2290. RtlLeaveCriticalSection( &pGlobals->csGlobals );
  2291. }
  2292. /***************************************************************************\
  2293. * FUNCTION: AttemptLogon
  2294. *
  2295. * PURPOSE: Tries to the log the user on using the current values in the
  2296. * logon dialog controls
  2297. *
  2298. * RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
  2299. * MSGINA_DLG_FAILURE - the logon failed,
  2300. * DLG_INTERRUPTED() - a set defined in winlogon.h
  2301. *
  2302. * NOTES: If the logon is successful, the global structure is filled in
  2303. * with the logon information.
  2304. *
  2305. * HISTORY:
  2306. *
  2307. * 12-09-91 Davidc Created.
  2308. *
  2309. \***************************************************************************/
  2310. INT_PTR
  2311. AttemptLogon(
  2312. HWND hDlg
  2313. )
  2314. {
  2315. PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  2316. PWCHAR UserName = pGlobals->UserName;
  2317. PWCHAR Domain = pGlobals->Domain;
  2318. PWCHAR Password = pGlobals->Password;
  2319. PDOMAIN_CACHE_ENTRY Entry ;
  2320. RECT rc;
  2321. HANDLE hThread;
  2322. DWORD tid;
  2323. BOOL timeout;
  2324. PUCHAR Dummy;
  2325. BOOL RasBox;
  2326. DWORD dwAnimationTimeSlice;
  2327. UserName[0] = TEXT('\0');
  2328. Domain[0] = TEXT('\0');
  2329. Password[0] = TEXT('\0');
  2330. //
  2331. // Hide the password so it doesn't make it to the pagefile in
  2332. // cleartext. Do this before getting the username and password
  2333. // so that it can't easily be identified (by association with
  2334. // the username and password) if we should crash or be rebooted
  2335. // before getting a chance to encode it.
  2336. //
  2337. GetDlgItemText(hDlg, IDD_LOGON_PASSWORD, Password, MAX_STRING_BYTES);
  2338. RtlInitUnicodeString(&pGlobals->PasswordString, Password);
  2339. pGlobals->Seed = 0; // Causes the encode routine to assign a seed
  2340. HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
  2341. //
  2342. // Now get the username and domain
  2343. //
  2344. if ( pGlobals->SmartCardLogon == FALSE )
  2345. {
  2346. HWND hwndDomain = GetDlgItem(hDlg, IDD_LOGON_DOMAIN);
  2347. if (hwndDomain != NULL)
  2348. {
  2349. INT iDomainSel = (INT)SendMessage(hwndDomain, CB_GETCURSEL, 0, 0);
  2350. GetDlgItemText(hDlg, IDD_LOGON_NAME, UserName, MAX_STRING_BYTES);
  2351. //
  2352. // is this the magical "this computer" entry???
  2353. // If so, set local domain flag used by password UI to show/notshow password restore
  2354. //
  2355. pGlobals->fLocalDomain = FALSE;
  2356. Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomainSel, 0);
  2357. if (CB_ERR != (ULONG_PTR) Entry)
  2358. {
  2359. if (NULL != Entry)
  2360. {
  2361. if (Entry->Type == DomainMachine)
  2362. {
  2363. pGlobals->fLocalDomain = TRUE;
  2364. }
  2365. }
  2366. }
  2367. }
  2368. else
  2369. {
  2370. Entry = (PDOMAIN_CACHE_ENTRY) CB_ERR;
  2371. }
  2372. if ( (Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR) && (NULL != Entry))
  2373. {
  2374. // MAX_STRING_BYTES is the size of pGlobals->Domain (WlxInitialize)
  2375. // Truncation should never occur
  2376. lstrcpyn( Domain, Entry->FlatName.Buffer, MAX_STRING_BYTES );
  2377. }
  2378. else
  2379. {
  2380. Domain[0] = L'\0';
  2381. }
  2382. }
  2383. else
  2384. {
  2385. UserName[0] = TEXT('\0');
  2386. Domain[0] = TEXT('\0') ;
  2387. }
  2388. // If we are forcing a NoDomainUI, populate the domain with the local machine name now
  2389. if (ForceNoDomainUI())
  2390. {
  2391. DWORD chSize = MAX_STRING_BYTES;
  2392. pGlobals->fLocalDomain = TRUE;
  2393. if (GetComputerName(Domain, &chSize))
  2394. {
  2395. NOTHING;
  2396. }
  2397. else
  2398. {
  2399. *Domain = 0;
  2400. }
  2401. }
  2402. //
  2403. // If there is a at-sign in the name, assume that means that a UPN logon
  2404. // attempt is being made. Set the domain to NULL.
  2405. //
  2406. if ( wcspbrk( UserName, L"@\\" ) )
  2407. {
  2408. Domain[0] = TEXT('\0');
  2409. }
  2410. RtlInitUnicodeString(&pGlobals->UserNameString, UserName);
  2411. RtlInitUnicodeString(&pGlobals->DomainString, Domain);
  2412. //
  2413. // Ok, is the RASbox checked?
  2414. //
  2415. RasBox = IsDlgButtonChecked( hDlg, IDD_LOGON_RASBOX );
  2416. pGlobals->RasUsed = FALSE;
  2417. if ( RasBox == BST_CHECKED )
  2418. {
  2419. //
  2420. // Reset the current timeout so that they neatly clean up before
  2421. // winlogon up and blows them away.
  2422. //
  2423. pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, 5 * 60 );
  2424. if ( !PopupRasPhonebookDlg( hDlg, pGlobals, &timeout) )
  2425. {
  2426. return( MSGINA_DLG_FAILURE );
  2427. }
  2428. pGlobals->RasUsed = TRUE;
  2429. //
  2430. // Reinitialize strings in case they've changed
  2431. //
  2432. RtlInitUnicodeString( &pGlobals->UserNameString, UserName );
  2433. //
  2434. // Ping Netlogon to allow us to go out on the net again...
  2435. //
  2436. I_NetLogonControl2(NULL,
  2437. NETLOGON_CONTROL_TRANSPORT_NOTIFY,
  2438. 1, (LPBYTE) &Dummy, &Dummy );
  2439. Sleep ((DWORD) ReadWinlogonBoolValue(TEXT("RASSleepTime"), 3000));
  2440. RefreshPolicy(TRUE);
  2441. }
  2442. //
  2443. // Process arguments before kicking off the thread
  2444. //
  2445. pGlobals->hwndLogon = hDlg;
  2446. RtlEnterCriticalSection( &pGlobals->csGlobals );
  2447. pGlobals->LogonInProgress = TRUE ;
  2448. RtlLeaveCriticalSection( &pGlobals->csGlobals );
  2449. GetClientRect(hDlg, &rc);
  2450. pGlobals->cxBand = rc.right-rc.left;
  2451. dwAnimationTimeSlice = GetAnimationTimeInterval(pGlobals);
  2452. // setup the progress timer
  2453. SetTimer(hDlg, 0, dwAnimationTimeSlice, NULL);
  2454. //
  2455. // Kick off real logon thread
  2456. //
  2457. // Set timeout to infinite while attempting to logon
  2458. pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, TIMEOUT_NONE );
  2459. hThread = CreateThread( NULL, 0,
  2460. AttemptLogonThread,
  2461. pGlobals,
  2462. 0, &tid );
  2463. if (hThread)
  2464. {
  2465. CloseHandle( hThread );
  2466. }
  2467. else
  2468. {
  2469. //
  2470. // CreateThread failed, likely because of low memory.
  2471. // Inform the user.
  2472. //
  2473. PostFailedLogonMessage(pGlobals->hwndLogon,
  2474. pGlobals,
  2475. GetLastError(),
  2476. 0,
  2477. NULL,
  2478. NULL);
  2479. RtlEnterCriticalSection( &pGlobals->csGlobals );
  2480. pGlobals->LogonInProgress = FALSE ;
  2481. RtlLeaveCriticalSection( &pGlobals->csGlobals );
  2482. return MSGINA_DLG_FAILURE ;
  2483. }
  2484. AttemptLogonSetControls(pGlobals, hDlg);
  2485. return MSGINA_DLG_SUCCESS;
  2486. }
  2487. BOOL ReplacedPossibleDisplayName (WCHAR *pszUsername, int nUserMax)
  2488. {
  2489. BOOL fReplaced;
  2490. DWORD dwIndex, dwReturnedEntryCount;
  2491. NET_API_STATUS nasCode;
  2492. NET_DISPLAY_USER *pNDU;
  2493. fReplaced = FALSE;
  2494. if (*pszUsername) // Name is not empty (Admin has empty full name by default...)
  2495. {
  2496. dwIndex = 0;
  2497. nasCode = NetQueryDisplayInformation(NULL,
  2498. 1,
  2499. dwIndex,
  2500. 1,
  2501. sizeof(NET_DISPLAY_USER),
  2502. &dwReturnedEntryCount,
  2503. (void**)&pNDU);
  2504. while (!fReplaced &&
  2505. (dwReturnedEntryCount > 0) &&
  2506. (NERR_Success == nasCode) || (ERROR_MORE_DATA == nasCode))
  2507. {
  2508. fReplaced = (lstrcmpiW(pNDU->usri1_full_name, pszUsername) == 0);
  2509. if (fReplaced)
  2510. {
  2511. lstrcpyn(pszUsername, pNDU->usri1_name, nUserMax); // Zero terminated
  2512. }
  2513. nasCode = NetApiBufferFree(pNDU);
  2514. if (!fReplaced)
  2515. {
  2516. nasCode = NetQueryDisplayInformation(NULL,
  2517. 1,
  2518. ++dwIndex,
  2519. 1,
  2520. sizeof(NET_DISPLAY_USER),
  2521. &dwReturnedEntryCount,
  2522. (void**)&pNDU);
  2523. }
  2524. }
  2525. }
  2526. return(fReplaced);
  2527. }
  2528. BOOL ReplacedLogonName (PGLOBALS pGlobals)
  2529. {
  2530. BOOL fReplaced;
  2531. // MAX_STRING_BYTES is the size of pGlobals->UserName (WlxInitialize)
  2532. fReplaced = ReplacedPossibleDisplayName(pGlobals->UserName, MAX_STRING_BYTES);
  2533. if (fReplaced)
  2534. {
  2535. RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName);
  2536. }
  2537. return(fReplaced);
  2538. }
  2539. DWORD
  2540. AttemptLogonThread(
  2541. PGLOBALS pGlobals
  2542. )
  2543. {
  2544. STRING PackageName;
  2545. PSID LogonSid;
  2546. PSID DuplicatedLogonSID;
  2547. LUID LogonId = { 0, 0 };
  2548. HANDLE UserToken = NULL;
  2549. HANDLE RestrictedToken;
  2550. BOOL PasswordExpired, ChangedLogonName;
  2551. NTSTATUS FinalStatus;
  2552. NTSTATUS Status = STATUS_SUCCESS;
  2553. NTSTATUS SubStatus = STATUS_SUCCESS;
  2554. INT_PTR Result = MSGINA_DLG_FAILURE;
  2555. ULONG LogonPackage;
  2556. BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)];
  2557. PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer;
  2558. PVOID AuthInfo ;
  2559. ULONG AuthInfoSize ;
  2560. UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ];
  2561. PTOKEN_USER pTokenUser ;
  2562. ULONG TokenInfoSize ;
  2563. PUCHAR SmartCardInfo ;
  2564. SECURITY_LOGON_TYPE logonType;
  2565. PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
  2566. #ifdef SMARTCARD_DOGFOOD
  2567. DWORD StartTime = 0, EndTime = 0;
  2568. #endif
  2569. //
  2570. // Store the logon time
  2571. // Do this before calling Lsa so we know if logon is successful that
  2572. // the password-must-change time will be greater than this time.
  2573. // If we grabbed this time after calling the lsa, this might not be true.
  2574. //
  2575. if ( IsActiveConsoleSession() )
  2576. {
  2577. // this is the console logon;
  2578. logonType = Interactive;
  2579. }
  2580. else
  2581. {
  2582. // remote sessions user must have the SeRemoteInteractiveLogonRight right which
  2583. // is granted to a user due to their membership in the new Remote-Desktop Users group.
  2584. logonType = RemoteInteractive;
  2585. }
  2586. GetSystemTimeAsFileTime( (LPFILETIME) &pGlobals->LogonTime );
  2587. DebugLog((DEB_TRACE, "In Attempt Logon!\n"));
  2588. if ( pGlobals->RasUsed )
  2589. {
  2590. if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache )
  2591. {
  2592. //
  2593. // We are using really stale data. Poke the cache to get it to use the
  2594. // now made RAS connection
  2595. //
  2596. DCacheUpdateMinimal( pGlobals->Cache, NULL, TRUE );
  2597. }
  2598. }
  2599. SetupCursor( TRUE );
  2600. FinalStatus = STATUS_SUCCESS;
  2601. //
  2602. // Generate a unique sid for this logon.
  2603. // Duplicate the SID. It is possible that the function that called
  2604. // the thread (and created the SID originally) may return causing
  2605. // the SID to be freed while this thread is still running.
  2606. // (see bug# 478186).
  2607. // the solution was to duplicate the SID here and free it at the end
  2608. // This still leaves a "small" window between starting the thread
  2609. // and duplicating the token where freeing may potentially cause the
  2610. // same problem (if the pGlobal->LogonSID is freed but not NULL'ed in
  2611. // which case duplication will fail)
  2612. // Notes:
  2613. // - if the duplication fails abort this
  2614. // - there is no need to actually verify the SID on free time
  2615. // at this point.
  2616. //
  2617. LogonSid = DuplicatedLogonSID = DuplicateSID(pGlobals->LogonSid);
  2618. if( NULL == LogonSid )
  2619. {
  2620. FinalStatus = STATUS_NO_MEMORY ;
  2621. Status = FinalStatus ;
  2622. }
  2623. else
  2624. {
  2625. if ( !wcspbrk( pGlobals->UserName, L"@\\" ) &&
  2626. wcschr( pGlobals->UserName, L'/' ))
  2627. {
  2628. FinalStatus = STATUS_LOGON_FAILURE ;
  2629. Status = FinalStatus ;
  2630. }
  2631. }
  2632. // clear card and reader name
  2633. pGlobals->Smartcard[0] = TEXT('\0');
  2634. pGlobals->SmartcardReader[0] = TEXT('\0');
  2635. if ( NT_SUCCESS( FinalStatus ) )
  2636. {
  2637. if ( pGlobals->SmartCardLogon )
  2638. {
  2639. pGlobals->AuthenticationPackage = pGlobals->SmartCardLogonPackage ;
  2640. }
  2641. else
  2642. {
  2643. pGlobals->AuthenticationPackage = pGlobals->PasswordLogonPackage ;
  2644. }
  2645. if ( pGlobals->SmartCardLogon )
  2646. {
  2647. pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
  2648. WLX_OPTION_SMART_CARD_INFO,
  2649. (ULONG_PTR *) &ScInfo );
  2650. if ( !ScInfo )
  2651. {
  2652. goto exit;
  2653. }
  2654. SmartCardInfo = ScBuildLogonInfo(
  2655. ScInfo->pszCard,
  2656. ScInfo->pszReader,
  2657. ScInfo->pszContainer,
  2658. ScInfo->pszCryptoProvider );
  2659. if(ScInfo->pszCard && ScInfo->pszReader) {
  2660. lstrcpyn(
  2661. pGlobals->Smartcard,
  2662. ScInfo->pszCard,
  2663. sizeof(pGlobals->Smartcard) / sizeof(TCHAR)
  2664. );
  2665. lstrcpyn(
  2666. pGlobals->SmartcardReader,
  2667. ScInfo->pszReader,
  2668. sizeof(pGlobals->SmartcardReader) / sizeof(TCHAR)
  2669. );
  2670. }
  2671. #ifndef SMARTCARD_DOGFOOD
  2672. LocalFree( ScInfo );
  2673. #endif
  2674. AuthInfo = FormatSmartCardCredentials(
  2675. &pGlobals->PasswordString,
  2676. SmartCardInfo,
  2677. FALSE,
  2678. NULL,
  2679. &AuthInfoSize );
  2680. LocalFree( SmartCardInfo );
  2681. }
  2682. else
  2683. {
  2684. AuthInfo = FormatPasswordCredentials(
  2685. &pGlobals->UserNameString,
  2686. &pGlobals->DomainString,
  2687. &pGlobals->PasswordString,
  2688. FALSE,
  2689. NULL,
  2690. &AuthInfoSize );
  2691. }
  2692. //
  2693. // Actually try to logon the user
  2694. //
  2695. #ifdef SMARTCARD_DOGFOOD
  2696. StartTime = GetTickCount();
  2697. #endif
  2698. FinalStatus = WinLogonUser(
  2699. pGlobals->LsaHandle,
  2700. pGlobals->AuthenticationPackage,
  2701. logonType,
  2702. AuthInfo,
  2703. AuthInfoSize,
  2704. LogonSid,
  2705. &LogonId,
  2706. &UserToken,
  2707. &pGlobals->UserProcessData.Quotas,
  2708. (PVOID *)&pGlobals->Profile,
  2709. &pGlobals->ProfileLength,
  2710. &SubStatus,
  2711. &pGlobals->OptimizedLogonStatus);
  2712. #ifdef SMARTCARD_DOGFOOD
  2713. EndTime = GetTickCount();
  2714. #endif
  2715. Status = FinalStatus;
  2716. }
  2717. SetupCursor( FALSE );
  2718. RtlEnterCriticalSection( &pGlobals->csGlobals );
  2719. pGlobals->LogonInProgress = FALSE;
  2720. RtlLeaveCriticalSection( &pGlobals->csGlobals );
  2721. DebugLog((DEB_TRACE, "WinLogonUser returned %#x\n", Status));
  2722. PasswordExpired = (((Status == STATUS_ACCOUNT_RESTRICTION) && (SubStatus == STATUS_PASSWORD_EXPIRED)) ||
  2723. (Status == STATUS_PASSWORD_MUST_CHANGE));
  2724. //
  2725. // If the account has expired we let them change their password and
  2726. // automatically retry the logon with the new password.
  2727. //
  2728. if (PasswordExpired)
  2729. {
  2730. _Shell_LogonDialog_HideUIHost();
  2731. if( pGlobals->SmartCardLogon )
  2732. {
  2733. //
  2734. // this was a SC logon that failed because the account had
  2735. // a password that expired. Put an error message and exit
  2736. //
  2737. TimeoutMessageBox(pGlobals->hwndLogon, pGlobals,
  2738. IDS_LOGON_SMARTCARD_PWD_CHANGE,
  2739. IDS_LOGON_MESSAGE,
  2740. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
  2741. LOGON_TIMEOUT);
  2742. Result = MSGINA_DLG_FAILURE;
  2743. goto exit;
  2744. }
  2745. if (Status == STATUS_PASSWORD_MUST_CHANGE)
  2746. {
  2747. Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_MUST_CHANGE,
  2748. IDS_LOGON_MESSAGE,
  2749. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
  2750. LOGON_TIMEOUT);
  2751. }
  2752. else
  2753. {
  2754. Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_EXPIRED,
  2755. IDS_LOGON_MESSAGE,
  2756. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
  2757. LOGON_TIMEOUT);
  2758. }
  2759. if (DLG_INTERRUPTED(Result) || (WLX_DLG_INPUT_TIMEOUT == Result))
  2760. goto exit;
  2761. //
  2762. // Copy the old password for mpr notification later
  2763. //
  2764. RevealPassword( &pGlobals->PasswordString );
  2765. // pGlobals->Password has the same size as pGlobals->OldPassword (WlxInitialize)
  2766. // so no need to zero terminate
  2767. wcsncpy(pGlobals->OldPassword, pGlobals->Password, MAX_STRING_BYTES);
  2768. pGlobals->OldSeed = 0;
  2769. RtlInitUnicodeString(&pGlobals->OldPasswordString, pGlobals->OldPassword);
  2770. HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
  2771. pGlobals->OldPasswordPresent = 1;
  2772. //
  2773. // Let the user change their password
  2774. //
  2775. LogonPackage = pGlobals->AuthenticationPackage ;
  2776. RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME );
  2777. Status = LsaLookupAuthenticationPackage (
  2778. pGlobals->LsaHandle,
  2779. &PackageName,
  2780. &pGlobals->AuthenticationPackage
  2781. );
  2782. if (!NT_SUCCESS(Status)) {
  2783. DebugLog((DEB_ERROR, "Failed to find %s authentication package, status = 0x%lx",
  2784. MSV1_0_PACKAGE_NAME, Status));
  2785. Result = MSGINA_DLG_FAILURE;
  2786. goto exit;
  2787. }
  2788. Result = ChangePasswordLogon(pGlobals->hwndLogon, pGlobals,
  2789. pGlobals->UserName,
  2790. pGlobals->Domain,
  2791. pGlobals->Password);
  2792. pGlobals->AuthenticationPackage = LogonPackage ;
  2793. if (DLG_INTERRUPTED(Result))
  2794. goto exit;
  2795. if (Result == MSGINA_DLG_FAILURE)
  2796. {
  2797. // The user doesn't want to, or failed to change their password.
  2798. goto exit;
  2799. }
  2800. }
  2801. // Special handling for failed logon on personal or professional
  2802. // machines that are NOT joined to a domain. In this case it's
  2803. // probably a user who disabled friendly UI and only knows of
  2804. // their "display name" not their real "logon name". This
  2805. // transparently maps one to the other to allow logons using
  2806. // the "display name".
  2807. ChangedLogonName = ((FinalStatus == STATUS_LOGON_FAILURE) &&
  2808. (IsOS(OS_PERSONAL) || IsOS(OS_PROFESSIONAL)) &&
  2809. !IsMachineDomainMember() &&
  2810. ReplacedLogonName(pGlobals));
  2811. if (PasswordExpired || ChangedLogonName)
  2812. {
  2813. //
  2814. // Retry the logon with the changed password
  2815. //
  2816. //
  2817. // Generate a unique sid for this logon
  2818. //
  2819. LogonSid = DuplicatedLogonSID;
  2820. AuthInfo = FormatPasswordCredentials(
  2821. &pGlobals->UserNameString,
  2822. &pGlobals->DomainString,
  2823. &pGlobals->PasswordString,
  2824. FALSE,
  2825. NULL,
  2826. &AuthInfoSize );
  2827. Status = WinLogonUser(
  2828. pGlobals->LsaHandle,
  2829. pGlobals->AuthenticationPackage,
  2830. logonType,
  2831. AuthInfo,
  2832. AuthInfoSize,
  2833. LogonSid,
  2834. &LogonId,
  2835. &UserToken,
  2836. &pGlobals->UserProcessData.Quotas,
  2837. (PVOID *)&pGlobals->Profile,
  2838. &pGlobals->ProfileLength,
  2839. &SubStatus,
  2840. &pGlobals->OptimizedLogonStatus);
  2841. }
  2842. //
  2843. // Deal with a terminally failed logon attempt
  2844. //
  2845. if (!NT_SUCCESS(Status))
  2846. {
  2847. //
  2848. // Do lockout processing
  2849. //
  2850. LockoutHandleFailedLogon(pGlobals);
  2851. Result = MSGINA_DLG_FAILEDMSGSENT;
  2852. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, SubStatus, pGlobals->UserName, pGlobals->Domain);
  2853. goto exit;
  2854. }
  2855. //
  2856. // The user logged on successfully
  2857. //
  2858. //
  2859. // Do lockout processing
  2860. //
  2861. LockoutHandleSuccessfulLogon(pGlobals);
  2862. //
  2863. // If the audit log is full, check they're an admin
  2864. //
  2865. if (pGlobals->AuditLogFull)
  2866. {
  2867. //
  2868. // The audit log is full, so only administrators are allowed to logon.
  2869. //
  2870. if (!UserToken || !TestTokenForAdmin(UserToken))
  2871. {
  2872. //
  2873. // The user is not an administrator, boot 'em.
  2874. //
  2875. LsaFreeReturnBuffer(pGlobals->Profile);
  2876. pGlobals->Profile = NULL;
  2877. NtClose(UserToken);
  2878. Result = MSGINA_DLG_FAILEDMSGSENT;
  2879. // Post a specific substatus so we can display a meaningful error message
  2880. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, STATUS_LOGON_FAILURE, IDS_LOGON_LOG_FULL, pGlobals->UserName, pGlobals->Domain);
  2881. goto exit;
  2882. }
  2883. else
  2884. {
  2885. //
  2886. // If we are in a session, we didn't display the log full onfo on the welcome
  2887. // screen, so tell the admin
  2888. //
  2889. if (GetSystemMetrics(SM_REMOTESESSION))
  2890. {
  2891. TimeoutMessageBox(
  2892. pGlobals->hwndLogon,
  2893. pGlobals,
  2894. IDS_LOGON_LOG_FULL_ADMIN,
  2895. IDS_LOGON_MESSAGE,
  2896. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND,
  2897. TIMEOUT_CURRENT);
  2898. }
  2899. }
  2900. }
  2901. //
  2902. // Force smart card logon for normal boot
  2903. //
  2904. if(!pGlobals->SmartCardLogon &&
  2905. (SafeBootMode != SAFEBOOT_MINIMAL) && (SafeBootMode != SAFEBOOT_DSREPAIR) &&
  2906. GetSCForceOption() )
  2907. {
  2908. //
  2909. // not a safe boot - boot 'em.
  2910. //
  2911. LsaFreeReturnBuffer(pGlobals->Profile);
  2912. pGlobals->Profile = NULL;
  2913. NtClose(UserToken);
  2914. Result = MSGINA_DLG_FAILEDMSGSENT;
  2915. // Post a specific substatus so we can display a meaningful error message
  2916. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals,
  2917. STATUS_LOGON_FAILURE, IDS_LOGON_SC_REQUIRED,
  2918. pGlobals->UserName, pGlobals->Domain);
  2919. goto exit;
  2920. }
  2921. //
  2922. // Hide ourselves before letting other credential managers put
  2923. // up dialogs
  2924. //
  2925. #if 0
  2926. ShowWindow(hDlg, SW_HIDE);
  2927. #endif
  2928. //
  2929. // Create a filtered version of the token for running normal applications
  2930. // if so indicated by a registry setting
  2931. //
  2932. if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) {
  2933. TokenGroups->Groups[0].Attributes = 0;
  2934. TokenGroups->Groups[0].Sid = gAdminSid;
  2935. TokenGroups->GroupCount = 1;
  2936. Status = NtFilterToken(
  2937. UserToken,
  2938. DISABLE_MAX_PRIVILEGE,
  2939. TokenGroups, // disable the administrators sid
  2940. NULL, // no privileges
  2941. NULL,
  2942. &RestrictedToken
  2943. );
  2944. if (!NT_SUCCESS(Status))
  2945. {
  2946. DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status));
  2947. RestrictedToken = NULL;
  2948. }
  2949. //
  2950. // Now set the default dacl for the token
  2951. //
  2952. {
  2953. PACL Dacl = NULL;
  2954. ULONG DaclLength = 0;
  2955. TOKEN_DEFAULT_DACL DefaultDacl;
  2956. DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid);
  2957. Dacl = Alloc(DaclLength);
  2958. Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION);
  2959. ASSERT(NT_SUCCESS(Status));
  2960. Status = RtlAddAccessAllowedAce(
  2961. Dacl,
  2962. ACL_REVISION,
  2963. GENERIC_ALL,
  2964. LogonSid
  2965. );
  2966. ASSERT(NT_SUCCESS(Status));
  2967. DefaultDacl.DefaultDacl = Dacl;
  2968. Status = NtSetInformationToken(
  2969. RestrictedToken,
  2970. TokenDefaultDacl,
  2971. &DefaultDacl,
  2972. sizeof(TOKEN_DEFAULT_DACL)
  2973. );
  2974. ASSERT(NT_SUCCESS(Status));
  2975. Free(Dacl);
  2976. }
  2977. } else {
  2978. RestrictedToken = NULL;
  2979. }
  2980. //
  2981. // Notify credential managers of the successful logon
  2982. //
  2983. pTokenUser = (PTOKEN_USER) UserBuffer ;
  2984. Status = NtQueryInformationToken( UserToken,
  2985. TokenUser,
  2986. pTokenUser,
  2987. sizeof( UserBuffer ),
  2988. &TokenInfoSize );
  2989. if ( NT_SUCCESS( Status ) )
  2990. {
  2991. pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED,
  2992. RtlLengthSid( pTokenUser->User.Sid ) );
  2993. if ( pGlobals->UserProcessData.UserSid )
  2994. {
  2995. RtlCopyMemory( pGlobals->UserProcessData.UserSid,
  2996. pTokenUser->User.Sid,
  2997. RtlLengthSid( pTokenUser->User.Sid ) );
  2998. }
  2999. else
  3000. {
  3001. Status = STATUS_NO_MEMORY ;
  3002. }
  3003. }
  3004. if ( !NT_SUCCESS( Status ) )
  3005. {
  3006. if (pGlobals->Profile)
  3007. {
  3008. LsaFreeReturnBuffer(pGlobals->Profile);
  3009. pGlobals->Profile = NULL;
  3010. }
  3011. NtClose(UserToken);
  3012. Result = MSGINA_DLG_FAILEDMSGSENT;
  3013. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, 0, pGlobals->UserName, pGlobals->Domain);
  3014. goto exit;
  3015. }
  3016. pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
  3017. if ( NULL == pGlobals->UserProcessData.NewThreadTokenSD )
  3018. {
  3019. if (pGlobals->Profile)
  3020. {
  3021. LsaFreeReturnBuffer(pGlobals->Profile);
  3022. pGlobals->Profile = NULL;
  3023. }
  3024. NtClose(UserToken);
  3025. Result = MSGINA_DLG_FAILEDMSGSENT;
  3026. Status = STATUS_NO_MEMORY;
  3027. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, 0, pGlobals->UserName, pGlobals->Domain);
  3028. goto exit;
  3029. }
  3030. pGlobals->UserProcessData.RestrictedToken = RestrictedToken;
  3031. pGlobals->UserProcessData.UserToken = UserToken;
  3032. pGlobals->MprLogonScripts = NULL;
  3033. // Run the dirty dialog box.
  3034. if ( WinlogonDirtyDialog( NULL, pGlobals ) == WLX_SAS_ACTION_LOGOFF )
  3035. {
  3036. //
  3037. // If this returns logoff, it means that the dialog timed out and
  3038. // we need to force the user back off. Not the best user experience,
  3039. // but that's what the PMs want.
  3040. //
  3041. FreeSecurityDescriptor( pGlobals->UserProcessData.NewThreadTokenSD );
  3042. LsaFreeReturnBuffer(pGlobals->Profile);
  3043. pGlobals->Profile = NULL;
  3044. NtClose(UserToken);
  3045. Result = MSGINA_DLG_FAILEDMSGSENT;
  3046. // Post a specific substatus so we can display a meaningful error message
  3047. PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, STATUS_LOGON_FAILURE, IDS_SET_DIRTY_UI_TIMEOUT, pGlobals->UserName, pGlobals->Domain);
  3048. goto exit;
  3049. }
  3050. //
  3051. // If we get here, the system works well enough for the user to have
  3052. // actually logged on. Profile failures aren't fixable by last known
  3053. // good anyway. Therefore, declare the boot good.
  3054. //
  3055. ReportBootGood(pGlobals);
  3056. //
  3057. // Set up the system for the new user
  3058. //
  3059. pGlobals->LogonId = LogonId;
  3060. if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) {
  3061. DWORD cb = pGlobals->Profile->FullName.Length;
  3062. if (cb + sizeof(WCHAR) > MAX_STRING_LENGTH * sizeof(WCHAR))
  3063. cb = MAX_STRING_LENGTH * sizeof(WCHAR) - sizeof(WCHAR);
  3064. memcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, cb);
  3065. pGlobals->UserFullName[cb / sizeof(WCHAR)] = UNICODE_NULL;
  3066. } else {
  3067. //
  3068. // No profile - set full name = NULL
  3069. pGlobals->UserFullName[0] = 0;
  3070. ASSERT( lstrlen(pGlobals->UserFullName) == 0);
  3071. }
  3072. if ( pGlobals->SmartCardLogon )
  3073. {
  3074. PCCERT_CONTEXT Cert ;
  3075. PKERB_SMART_CARD_PROFILE ScProfile ;
  3076. //
  3077. // Need to fix up the user name with the name (UPN) from the
  3078. // certificate, so that unlock, etc. work correctly.
  3079. //
  3080. ScProfile = (PKERB_SMART_CARD_PROFILE) pGlobals->Profile ;
  3081. pGlobals->UserName[0] = 0 ;
  3082. try
  3083. {
  3084. Cert = CertCreateCertificateContext( X509_ASN_ENCODING,
  3085. ScProfile->CertificateData,
  3086. ScProfile->CertificateSize );
  3087. if ( Cert )
  3088. {
  3089. // Even though the name is MAX_STRING_BYTES, the way it is used
  3090. // throughout the code, it is used as a character counter
  3091. // (Grrr, crappy gina code)
  3092. //
  3093. DWORD dwLen = MAX_STRING_BYTES;
  3094. if(STATUS_SUCCESS == UpnFromCert(Cert, &dwLen, pGlobals->UserName))
  3095. {
  3096. RtlInitUnicodeString( &pGlobals->UserNameString,
  3097. pGlobals->UserName );
  3098. }
  3099. CertFreeCertificateContext( Cert );
  3100. }
  3101. }
  3102. except( EXCEPTION_EXECUTE_HANDLER )
  3103. {
  3104. pGlobals->UserName[0] = L'\0';
  3105. }
  3106. //
  3107. // If this is still 0 on exit, the code that sets up the flat name
  3108. // will copy the flat name into UserName, so the failure case is
  3109. // easy.
  3110. //
  3111. }
  3112. pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 );
  3113. //
  3114. // WE SHOULD NOT WRITE INTO THE REGISTRY.
  3115. // CLupu
  3116. //
  3117. //
  3118. // Update our default username and domain ready for the next logon
  3119. //
  3120. //
  3121. // Update the default username & domain only if on the console. Otherwise
  3122. // we'll break AutoAdminLogon by changing the user name.
  3123. //
  3124. if ( g_Console )
  3125. {
  3126. if ( (!pGlobals->AutoAdminLogon) &&
  3127. (SafeBootMode != SAFEBOOT_MINIMAL ) )
  3128. {
  3129. WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName);
  3130. WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
  3131. }
  3132. WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName);
  3133. WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
  3134. }
  3135. if ( pGlobals->Domain[0] )
  3136. {
  3137. DCacheSetDefaultEntry( pGlobals->Cache,
  3138. pGlobals->Domain,
  3139. NULL );
  3140. }
  3141. Result = MSGINA_DLG_SUCCESS;
  3142. exit:
  3143. #ifdef SMARTCARD_DOGFOOD
  3144. if (pGlobals->SmartCardLogon) {
  3145. switch (SubStatus)
  3146. {
  3147. case STATUS_SMARTCARD_WRONG_PIN:
  3148. case STATUS_SMARTCARD_CARD_BLOCKED:
  3149. case STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED:
  3150. case STATUS_SMARTCARD_NO_CARD:
  3151. case STATUS_SMARTCARD_NO_KEY_CONTAINER:
  3152. case STATUS_SMARTCARD_NO_CERTIFICATE:
  3153. case STATUS_SMARTCARD_NO_KEYSET:
  3154. case STATUS_SMARTCARD_IO_ERROR:
  3155. case STATUS_SMARTCARD_SUBSYSTEM_FAILURE:
  3156. case STATUS_SMARTCARD_CERT_EXPIRED:
  3157. case STATUS_SMARTCARD_CERT_REVOKED:
  3158. case STATUS_ISSUING_CA_UNTRUSTED:
  3159. case STATUS_REVOCATION_OFFLINE_C:
  3160. case STATUS_PKINIT_CLIENT_FAILURE:
  3161. FinalStatus = SubStatus;
  3162. break;
  3163. default:
  3164. break; // do NOTHING
  3165. }
  3166. // write logon data to database
  3167. AuthMonitor(
  3168. AuthOperLogon,
  3169. g_Console,
  3170. &pGlobals->UserNameString,
  3171. &pGlobals->DomainString,
  3172. (ScInfo ? ScInfo->pszCard : NULL),
  3173. (ScInfo ? ScInfo->pszReader : NULL),
  3174. (PKERB_SMART_CARD_PROFILE) pGlobals->Profile,
  3175. EndTime - StartTime,
  3176. FinalStatus
  3177. );
  3178. }
  3179. if (ScInfo)
  3180. {
  3181. LocalFree( ScInfo );
  3182. }
  3183. #endif
  3184. // Only send a logon complete message if we haven't sent a failed
  3185. // message. The failed message will send a logon complete message
  3186. // when its done.
  3187. if (Result != MSGINA_DLG_FAILEDMSGSENT)
  3188. {
  3189. if (WLX_DLG_INPUT_TIMEOUT == Result)
  3190. {
  3191. //
  3192. // this came from a timeout when:
  3193. // - we want to go back to CAD screen w/out an extra error dialog
  3194. // - we want this to look like a logon failure code
  3195. // the solution is to send WM_LOGONCOMPLETE / MSGINA_DLG_FAILURE
  3196. //
  3197. //
  3198. Result = MSGINA_DLG_FAILURE;
  3199. }
  3200. PostMessage(pGlobals->hwndLogon, WM_LOGONCOMPLETE, 0, Result);
  3201. }
  3202. //
  3203. // free the duplicated SID
  3204. //
  3205. if( DuplicatedLogonSID && RtlValidSid(DuplicatedLogonSID) )
  3206. {
  3207. Free(DuplicatedLogonSID);
  3208. }
  3209. return 0L;
  3210. }
  3211. /****************************************************************************\
  3212. *
  3213. * FUNCTION: PostFailedLogonMessage
  3214. *
  3215. * PURPOSE: Posts a message to the UI thread telling it to display a dialog that
  3216. * tells the user why their logon attempt failed.
  3217. *
  3218. * The window on the UI thread must correctly handle WM_HANDLEFAILEDLOGON
  3219. * by calling HandleFailedLogon and the Free'ing the structure
  3220. *
  3221. * RETURNS: void
  3222. *
  3223. * HISTORY:
  3224. *
  3225. * 12-09-91 Davidc Created.
  3226. *
  3227. \****************************************************************************/
  3228. void PostFailedLogonMessage(HWND hDlg,
  3229. PGLOBALS pGlobals,
  3230. NTSTATUS Status,
  3231. NTSTATUS SubStatus,
  3232. PWCHAR UserName,
  3233. PWCHAR Domain
  3234. )
  3235. {
  3236. g_failinfo.pGlobals = pGlobals;
  3237. g_failinfo.Status = Status;
  3238. g_failinfo.SubStatus = SubStatus;
  3239. if ( UserName )
  3240. {
  3241. lstrcpyn(g_failinfo.UserName, UserName, ARRAYSIZE(g_failinfo.UserName));
  3242. }
  3243. else
  3244. {
  3245. g_failinfo.UserName[0] = L'\0';
  3246. }
  3247. if ( Domain )
  3248. {
  3249. lstrcpyn(g_failinfo.Domain, Domain, ARRAYSIZE(g_failinfo.Domain));
  3250. }
  3251. else
  3252. {
  3253. g_failinfo.Domain[0] = L'\0' ;
  3254. }
  3255. PostMessage(hDlg, WM_HANDLEFAILEDLOGON, 0 , 0);
  3256. }
  3257. INT_PTR
  3258. CALLBACK
  3259. FailDlgProc(
  3260. HWND hDlg,
  3261. UINT message,
  3262. WPARAM wParam,
  3263. LPARAM lParam
  3264. )
  3265. {
  3266. RUNDLLPROC fptr;
  3267. HMODULE hDll;
  3268. switch (message)
  3269. {
  3270. case WM_INITDIALOG:
  3271. {
  3272. CentreWindow(hDlg);
  3273. return( TRUE );
  3274. }
  3275. case WM_COMMAND:
  3276. {
  3277. if (LOWORD(wParam) == IDOK)
  3278. {
  3279. EndDialog(hDlg, IDOK);
  3280. }
  3281. if (LOWORD(wParam) == IDC_RECOVER)
  3282. {
  3283. // Will eventually supply username to the recover wizard
  3284. // We use a single export from KEYMGR.DLL for this operation. When this operation completes,
  3285. // we don't use the DLL again without unlikely user intervention. We could DELAYLOAD keymgr.dll,
  3286. // but explicitly loading and unloading this DLL permits us to minimize the memory footprint of msgina.
  3287. hDll = LoadLibraryW(L"keymgr.dll");
  3288. if (hDll)
  3289. {
  3290. fptr = (RUNDLLPROC) GetProcAddress(hDll,(LPCSTR)"PRShowRestoreFromMsginaW");
  3291. // next stmt will be removed eventually when we pass the username
  3292. if (fptr)
  3293. {
  3294. fptr(hDlg,NULL,g_failinfo.UserName,0);
  3295. }
  3296. FreeLibrary(hDll);
  3297. EndDialog(hDlg,IDOK);
  3298. }
  3299. }
  3300. }
  3301. break;
  3302. }
  3303. return FALSE;
  3304. }
  3305. /****************************************************************************\
  3306. *
  3307. * FUNCTION: HandleFailedLogon
  3308. *
  3309. * PURPOSE: Tells the user why their logon attempt failed.
  3310. *
  3311. * RETURNS: MSGINA_DLG_FAILURE - we told them what the problem was successfully.
  3312. * DLG_INTERRUPTED() - a set of return values - see winlogon.h
  3313. *
  3314. * HISTORY:
  3315. *
  3316. * 12-09-91 Davidc Created.
  3317. *
  3318. \****************************************************************************/
  3319. INT_PTR
  3320. HandleFailedLogon(
  3321. HWND hDlg
  3322. )
  3323. {
  3324. INT_PTR Result = 0xffffffff;
  3325. DWORD Win32Error ;
  3326. TCHAR *Buffer1 = NULL;
  3327. TCHAR *Buffer2 = NULL;
  3328. TCHAR *Buffer3 = NULL;
  3329. PGLOBALS pGlobals = g_failinfo.pGlobals;
  3330. NTSTATUS Status = g_failinfo.Status;
  3331. NTSTATUS SubStatus = g_failinfo.SubStatus;
  3332. PWCHAR Domain = g_failinfo.Domain;
  3333. DWORD BUStatus = 0xffffffff;
  3334. UINT uiMsgId = 0xabab; // abab is out of range value for default handler at the bottom of this
  3335. // routine. 0 indicates that the user has a psw reset disk
  3336. // -1 means that Buffer1 & 2 contain the message
  3337. // otherwise there is a corresponding resource message
  3338. //
  3339. // for remote sessions, we must set finite timeout value for messagebox.
  3340. // so that the session does not remain there forever
  3341. //
  3342. DWORD TimeOut = IsActiveConsoleSession() ? TIMEOUT_CURRENT : 20;
  3343. switch (Status)
  3344. {
  3345. case STATUS_LOGON_FAILURE:
  3346. case STATUS_NAME_TOO_LONG: // Returned if username is too long
  3347. if (SubStatus == IDS_LOGON_LOG_FULL)
  3348. {
  3349. uiMsgId = IDS_LOGON_LOG_FULL;
  3350. }
  3351. else if( SubStatus == IDS_LOGON_SC_REQUIRED )
  3352. {
  3353. uiMsgId = IDS_LOGON_SC_REQUIRED;
  3354. }
  3355. else if ( SubStatus == IDS_SET_DIRTY_UI_TIMEOUT )
  3356. {
  3357. uiMsgId = IDS_SET_DIRTY_UI_TIMEOUT;
  3358. }
  3359. else if (pGlobals->SmartCardLogon)
  3360. {
  3361. switch(SubStatus)
  3362. {
  3363. case STATUS_SMARTCARD_WRONG_PIN:
  3364. uiMsgId = IDS_STATUS_SMARTCARD_WRONG_PIN;
  3365. break;
  3366. case STATUS_SMARTCARD_CARD_BLOCKED:
  3367. uiMsgId = IDS_STATUS_SMARTCARD_CARD_BLOCKED;
  3368. break;
  3369. case STATUS_SMARTCARD_NO_CARD:
  3370. uiMsgId = IDS_STATUS_SMARTCARD_NO_CARD;
  3371. break;
  3372. case STATUS_SMARTCARD_NO_KEY_CONTAINER:
  3373. uiMsgId = IDS_STATUS_SMARTCARD_NO_KEY_CONTAINER;
  3374. break;
  3375. case STATUS_SMARTCARD_NO_CERTIFICATE:
  3376. uiMsgId = IDS_STATUS_SMARTCARD_NO_CERTIFICATE;
  3377. break;
  3378. case STATUS_SMARTCARD_NO_KEYSET:
  3379. uiMsgId = IDS_STATUS_SMARTCARD_NO_KEYSET;
  3380. break;
  3381. case STATUS_SMARTCARD_IO_ERROR:
  3382. uiMsgId = IDS_STATUS_SMARTCARD_IO_ERROR;
  3383. break;
  3384. case STATUS_SMARTCARD_SUBSYSTEM_FAILURE:
  3385. uiMsgId = IDS_STATUS_SMARTCARD_SUBSYSTEM_FAILURE;
  3386. break;
  3387. case STATUS_SMARTCARD_CERT_REVOKED:
  3388. uiMsgId = IDS_STATUS_SMARTCARD_CERT_REVOKED;
  3389. break;
  3390. case STATUS_ISSUING_CA_UNTRUSTED:
  3391. uiMsgId = IDS_STATUS_ISSUING_CA_UNTRUSTED;
  3392. break;
  3393. case STATUS_REVOCATION_OFFLINE_C:
  3394. uiMsgId = IDS_STATUS_REVOCATION_OFFLINE_C;
  3395. break;
  3396. case STATUS_PKINIT_CLIENT_FAILURE:
  3397. uiMsgId = IDS_STATUS_PKINIT_CLIENT_FAILURE;
  3398. break;
  3399. case STATUS_SMARTCARD_CERT_EXPIRED:
  3400. uiMsgId = IDS_STATUS_SMARTCARD_CERT_EXPIRED;
  3401. break;
  3402. default:
  3403. uiMsgId = IDS_INCORRECT_NAME_OR_PWD_SC;
  3404. }
  3405. }
  3406. else
  3407. {
  3408. // Non-smartcard logon case:
  3409. // Find out if the user who attempted logon has a password backup disk
  3410. // that could be used to reset the password. If so, present a dialog that
  3411. // offers that possibility. Else simple message box. (see passrec.h)
  3412. if (pGlobals->fLocalDomain)
  3413. {
  3414. if ((0 == PRQueryStatus(NULL,g_failinfo.UserName,&BUStatus)) && (0 == GetSystemMetrics(SM_REMOTESESSION)))
  3415. {
  3416. if (BUStatus == 0)
  3417. {
  3418. uiMsgId = 0;
  3419. break;
  3420. }
  3421. }
  3422. }
  3423. // Else UI message is generic one
  3424. uiMsgId = IDS_INCORRECT_NAME_OR_PWD;
  3425. }
  3426. break;
  3427. case STATUS_NOT_SUPPORTED:
  3428. case STATUS_PKINIT_NAME_MISMATCH:
  3429. case STATUS_PKINIT_FAILURE:
  3430. Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3431. Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3432. if ((Buffer1 == NULL) || (Buffer2 == NULL))
  3433. {
  3434. uiMsgId = IDS_STATUS_SERVER_SIDE_ERROR_NOINSERT;
  3435. }
  3436. else
  3437. {
  3438. // Buffer1[0] = 0; unnecessary since LPTR was used
  3439. LoadString(hDllInstance,
  3440. IDS_STATUS_SERVER_SIDE_ERROR,
  3441. Buffer1,
  3442. MAX_STRING_BYTES);
  3443. _snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Status );
  3444. Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
  3445. Buffer1[0] = 0;
  3446. LoadString(hDllInstance,
  3447. IDS_LOGON_MESSAGE,
  3448. Buffer1,
  3449. MAX_STRING_BYTES);
  3450. uiMsgId = (DWORD)-1;
  3451. }
  3452. break;
  3453. case STATUS_ACCOUNT_RESTRICTION:
  3454. switch (SubStatus)
  3455. {
  3456. case STATUS_INVALID_LOGON_HOURS:
  3457. uiMsgId = IDS_INVALID_LOGON_HOURS;
  3458. break;
  3459. case STATUS_INVALID_WORKSTATION:
  3460. uiMsgId = IDS_INVALID_WORKSTATION;
  3461. break;
  3462. case STATUS_ACCOUNT_DISABLED:
  3463. uiMsgId = IDS_ACCOUNT_DISABLED;
  3464. break;
  3465. case STATUS_ACCOUNT_EXPIRED:
  3466. uiMsgId = IDS_ACCOUNT_EXPIRED2;
  3467. break;
  3468. case STATUS_SMARTCARD_LOGON_REQUIRED:
  3469. uiMsgId = IDS_SMARTCARD_REQUIRED;
  3470. break;
  3471. default:
  3472. uiMsgId = IDS_ACCOUNT_RESTRICTION;
  3473. break;
  3474. }
  3475. break;
  3476. case STATUS_NO_LOGON_SERVERS:
  3477. Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3478. Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3479. if ((Buffer1 == NULL) || (Buffer2 == NULL))
  3480. {
  3481. uiMsgId = IDS_LOGON_NO_DOMAIN_NOINSERT;
  3482. }
  3483. else
  3484. {
  3485. // Buffer1[0] = 0; unnecessary since LPTR was used
  3486. LoadString(hDllInstance, IDS_LOGON_NO_DOMAIN, Buffer1, MAX_STRING_BYTES);
  3487. _snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Domain);
  3488. Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
  3489. Buffer1[0] = 0;
  3490. LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, MAX_STRING_BYTES);
  3491. uiMsgId = (DWORD)-1;
  3492. }
  3493. break;
  3494. case STATUS_LOGON_TYPE_NOT_GRANTED:
  3495. uiMsgId = IDS_LOGON_TYPE_NOT_GRANTED;
  3496. break;
  3497. case STATUS_NO_TRUST_LSA_SECRET:
  3498. uiMsgId = IDS_NO_TRUST_LSA_SECRET;
  3499. break;
  3500. case STATUS_TRUSTED_DOMAIN_FAILURE:
  3501. uiMsgId = IDS_TRUSTED_DOMAIN_FAILURE;
  3502. break;
  3503. case STATUS_TRUSTED_RELATIONSHIP_FAILURE:
  3504. uiMsgId = IDS_TRUSTED_RELATIONSHIP_FAILURE;
  3505. break;
  3506. case STATUS_ACCOUNT_EXPIRED:
  3507. uiMsgId = IDS_ACCOUNT_EXPIRED;
  3508. break;
  3509. case STATUS_NETLOGON_NOT_STARTED:
  3510. uiMsgId = IDS_NETLOGON_NOT_STARTED;
  3511. break;
  3512. case STATUS_ACCOUNT_LOCKED_OUT:
  3513. uiMsgId = IDS_ACCOUNT_LOCKED;
  3514. break;
  3515. case ERROR_CTX_LOGON_DISABLED:
  3516. uiMsgId = IDS_MULTIUSER_LOGON_DISABLED;
  3517. break;
  3518. case ERROR_CTX_WINSTATION_ACCESS_DENIED:
  3519. uiMsgId = IDS_MULTIUSER_WINSTATION_ACCESS_DENIED;
  3520. break;
  3521. case SCARD_E_NO_SMARTCARD:
  3522. case SCARD_E_UNKNOWN_CARD:
  3523. //
  3524. // Card not recognized (although we should never get this far)
  3525. //
  3526. uiMsgId = IDS_CARD_NOT_RECOGNIZED;
  3527. break;
  3528. case NTE_PROV_DLL_NOT_FOUND:
  3529. //
  3530. // Card's CSP not found (although we should never get this far)
  3531. //
  3532. uiMsgId = IDS_CARD_CSP_NOT_RECOGNIZED;
  3533. break;
  3534. case STATUS_TIME_DIFFERENCE_AT_DC:
  3535. uiMsgId = IDS_TIME_DIFFERENCE_AT_DC;
  3536. break;
  3537. default:
  3538. WLPrint(("Logon failure status = 0x%lx, sub-status = 0x%lx", Status, SubStatus));
  3539. Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3540. Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3541. Buffer3 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
  3542. if ((Buffer1 == NULL) || (Buffer2 == NULL) || (Buffer3 == NULL))
  3543. {
  3544. uiMsgId = IDS_UNKNOWN_LOGON_FAILURE_NOINSERT;
  3545. }
  3546. else
  3547. {
  3548. // Buffer1[0] = 0; unnecessary since LPTR was used
  3549. LoadString(hDllInstance,
  3550. IDS_UNKNOWN_LOGON_FAILURE,
  3551. Buffer1,
  3552. MAX_STRING_BYTES);
  3553. if ( NT_ERROR( Status ) )
  3554. {
  3555. Win32Error = RtlNtStatusToDosError( Status );
  3556. }
  3557. else
  3558. {
  3559. //
  3560. // Probably an HRESULT:
  3561. //
  3562. Win32Error = Status ;
  3563. }
  3564. // Buffer3[0] = 0; unnecessary since LPTR was used
  3565. GetErrorDescription( Win32Error, Buffer3, MAX_STRING_BYTES);
  3566. _snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Buffer3 );
  3567. Buffer2[MAX_STRING_BYTES - 1] = 0; // zero terminate
  3568. Buffer1[0] = 0;
  3569. LoadString(hDllInstance,
  3570. IDS_LOGON_MESSAGE,
  3571. Buffer1,
  3572. MAX_STRING_BYTES);
  3573. uiMsgId = (DWORD)-1;
  3574. }
  3575. break;
  3576. }
  3577. _Shell_LogonDialog_HideUIHost();
  3578. switch (uiMsgId)
  3579. {
  3580. case 0:
  3581. // User has a password reset disk - present the option to use it along with the usual
  3582. // help message
  3583. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx,LOGON_TIMEOUT);
  3584. Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx,
  3585. hDllInstance,
  3586. (LPTSTR) IDD_FAILLOGONHELP_DIALOG,
  3587. hDlg,
  3588. FailDlgProc,
  3589. 0);
  3590. break;
  3591. case (DWORD)-1:
  3592. Result = TimeoutMessageBoxlpstr(hDlg, pGlobals,
  3593. Buffer2,
  3594. Buffer1,
  3595. MB_OK | MB_ICONEXCLAMATION,
  3596. TimeOut);
  3597. break;
  3598. default:
  3599. Result = TimeoutMessageBox(hDlg, pGlobals,
  3600. uiMsgId,
  3601. IDS_LOGON_MESSAGE,
  3602. MB_OK | MB_ICONEXCLAMATION,
  3603. TimeOut);
  3604. }
  3605. if (Buffer1 != NULL)
  3606. LocalFree(Buffer1);
  3607. if (Buffer2 != NULL)
  3608. LocalFree(Buffer2);
  3609. if (Buffer3 != NULL)
  3610. LocalFree(Buffer3);
  3611. if (!DLG_INTERRUPTED(Result))
  3612. {
  3613. Result = MSGINA_DLG_FAILURE;
  3614. }
  3615. return(Result);
  3616. }
  3617. VOID
  3618. ReportBootGoodThread (LPVOID lpDummy)
  3619. {
  3620. HANDLE hInstDll;
  3621. // PGLOBALS pGlobals = (PGLOBALS)lpDummy;
  3622. // SetThreadDesktop(pGlobals->hdeskParent);
  3623. hInstDll = LoadLibrary (TEXT("msgina.dll"));
  3624. NotifyBootConfigStatus(TRUE);
  3625. if (hInstDll) {
  3626. FreeLibraryAndExitThread(hInstDll, TRUE);
  3627. } else {
  3628. ExitThread (TRUE);
  3629. }
  3630. }
  3631. /****************************************************************************\
  3632. *
  3633. * FUNCTION: ReportBootGood
  3634. *
  3635. * PURPOSE: Discover if reporting boot success is responsibility of
  3636. * winlogon or not.
  3637. * If it is, report boot success.
  3638. * Otherwise, do nothing.
  3639. *
  3640. * RETURNS: Nothing
  3641. *
  3642. * HISTORY:
  3643. *
  3644. * 02-Feb-1993 bryanwi - created
  3645. *
  3646. \****************************************************************************/
  3647. VOID
  3648. ReportBootGood(PGLOBALS pGlobals)
  3649. {
  3650. static DWORD fDoIt = (DWORD) -1; // -1 == uninited
  3651. // 0 == don't do it, or done
  3652. // 1 == do it
  3653. PWCH pchData;
  3654. DWORD cb, cbCopied;
  3655. HANDLE hThread;
  3656. DWORD dwThreadID;
  3657. if (fDoIt == -1) {
  3658. if ((pchData = Alloc(cb = sizeof(TCHAR)*128)) == NULL) {
  3659. return;
  3660. }
  3661. pchData[0] = TEXT('0');
  3662. cbCopied = GetProfileString(APPLICATION_NAME, REPORT_BOOT_OK_KEY, TEXT("0"),
  3663. (LPTSTR)pchData, 128);
  3664. fDoIt = 0;
  3665. if (pchData[0] != TEXT('0')) {
  3666. //
  3667. // "ReportBootGood" is present, and has some value other than
  3668. // '0', so report success.
  3669. //
  3670. fDoIt = 1;
  3671. }
  3672. Free((TCHAR *)pchData);
  3673. }
  3674. if (fDoIt == 1) {
  3675. hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)ReportBootGoodThread,
  3676. pGlobals, CREATE_SUSPENDED, &dwThreadID);
  3677. if (hThread) {
  3678. SetThreadPriority (hThread, THREAD_PRIORITY_LOWEST);
  3679. ResumeThread (hThread);
  3680. CloseHandle (hThread);
  3681. } else {
  3682. NotifyBootConfigStatus(TRUE);
  3683. }
  3684. fDoIt = 0;
  3685. }
  3686. return;
  3687. }
  3688. //+---------------------------------------------------------------------------
  3689. //
  3690. // Function: UpnFromCert
  3691. //
  3692. // Notes:
  3693. //
  3694. //----------------------------------------------------------------------------
  3695. NTSTATUS
  3696. UpnFromCert(
  3697. IN PCCERT_CONTEXT pCert,
  3698. IN OUT DWORD *pcUpn,
  3699. IN OUT LPWSTR pUPN
  3700. )
  3701. {
  3702. NTSTATUS Status = STATUS_SUCCESS;
  3703. ULONG ExtensionIndex = 0;
  3704. PCERT_ALT_NAME_INFO AltName=NULL;
  3705. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  3706. //
  3707. // Get the client name from the cert
  3708. //
  3709. // See if cert has UPN in AltSubjectName->otherName
  3710. for(ExtensionIndex = 0;
  3711. ExtensionIndex < pCert->pCertInfo->cExtension;
  3712. ExtensionIndex++)
  3713. {
  3714. if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  3715. szOID_SUBJECT_ALT_NAME2) == 0)
  3716. {
  3717. DWORD AltNameStructSize = 0;
  3718. ULONG CertAltNameIndex = 0;
  3719. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  3720. X509_ALTERNATE_NAME,
  3721. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  3722. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  3723. CRYPT_DECODE_ALLOC_FLAG,
  3724. NULL,
  3725. (PVOID)&AltName,
  3726. &AltNameStructSize))
  3727. {
  3728. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  3729. {
  3730. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  3731. if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) &&
  3732. (NULL != AltNameEntry->pOtherName) &&
  3733. (0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId)))
  3734. {
  3735. DWORD PrincipalNameBlobSize = 0;
  3736. // We found a UPN!
  3737. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  3738. X509_UNICODE_ANY_STRING,
  3739. AltNameEntry->pOtherName->Value.pbData,
  3740. AltNameEntry->pOtherName->Value.cbData,
  3741. CRYPT_DECODE_ALLOC_FLAG,
  3742. NULL,
  3743. (PVOID)&PrincipalNameBlob,
  3744. &PrincipalNameBlobSize))
  3745. {
  3746. if(PrincipalNameBlob->Value.cbData + sizeof(WCHAR) > *pcUpn)
  3747. {
  3748. Status = STATUS_BUFFER_OVERFLOW;
  3749. }
  3750. else
  3751. {
  3752. *pcUpn = PrincipalNameBlob->Value.cbData + sizeof(WCHAR);
  3753. CopyMemory(pUPN, PrincipalNameBlob->Value.pbData, PrincipalNameBlob->Value.cbData);
  3754. *(WCHAR *)((PBYTE)pUPN+PrincipalNameBlob->Value.cbData) = 0;
  3755. }
  3756. LocalFree(PrincipalNameBlob);
  3757. PrincipalNameBlob = NULL;
  3758. LocalFree(AltName);
  3759. AltName = NULL;
  3760. goto Finished;
  3761. }
  3762. }
  3763. }
  3764. LocalFree(AltName);
  3765. AltName = NULL;
  3766. }
  3767. }
  3768. }
  3769. //
  3770. // If the name was not found in the UPN, then
  3771. // we grab it the old way.
  3772. if ( !CertGetNameString( pCert,
  3773. CERT_NAME_ATTR_TYPE,
  3774. 0,
  3775. szOID_COMMON_NAME,
  3776. pUPN,
  3777. *pcUpn ) )
  3778. {
  3779. Status = GetLastError();
  3780. }
  3781. Finished:
  3782. return Status ;
  3783. }
  3784. //+---------------------------------------------------------------------------
  3785. //
  3786. // Function:TSAuthenticatedLogon
  3787. //
  3788. // Notes: This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
  3789. // in the context of the console session (sessionid 0) winlogon.
  3790. // This type of logon is for Single Session Terminal Server. When a user
  3791. // logs on from a remote TS session, we pass the credentials from the remote session
  3792. // to the console session and do an auto-logon. This routine queries the credentials
  3793. // logs on the user on the console sesion
  3794. //
  3795. //
  3796. //----------------------------------------------------------------------------
  3797. INT_PTR TSAuthenticatedLogon(PGLOBALS pGlobals)
  3798. {
  3799. PSID LogonSid;
  3800. LUID LogonId;
  3801. HANDLE UserToken;
  3802. HANDLE RestrictedToken;
  3803. INT_PTR Result = MSGINA_DLG_SUCCESS;
  3804. UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ];
  3805. PTOKEN_USER pTokenUser ;
  3806. ULONG TokenInfoSize ;
  3807. NTSTATUS Status;
  3808. BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)];
  3809. PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer;
  3810. PACL Dacl = NULL;
  3811. if (!QuerySwitchConsoleCredentials(pGlobals,&UserToken,&LogonId)) {
  3812. Result = MSGINA_DLG_FAILEDMSGSENT;
  3813. goto exit;
  3814. }
  3815. if (pGlobals->SmartCardLogon) {
  3816. wcscpy(pGlobals->Password,L"");
  3817. wcscpy(pGlobals->OldPassword,L"");
  3818. {
  3819. KERB_REFRESH_SCCRED_REQUEST PurgeRequest = {0};
  3820. PVOID Response = NULL;
  3821. ULONG ResponseSize;
  3822. NTSTATUS SubStatus;
  3823. PopulateSecPackageList(
  3824. pGlobals );
  3825. PurgeRequest.LogonId = LogonId;
  3826. PurgeRequest.MessageType = KerbRefreshSmartcardCredentialsMessage;
  3827. PurgeRequest.Flags = KERB_REFRESH_SCCRED_RELEASE;
  3828. Status = LsaCallAuthenticationPackage(
  3829. pGlobals->LsaHandle,
  3830. pGlobals->SmartCardLogonPackage,
  3831. &PurgeRequest,
  3832. sizeof(KERB_REFRESH_SCCRED_REQUEST),
  3833. &Response,
  3834. &ResponseSize,
  3835. &SubStatus
  3836. );
  3837. if (NT_SUCCESS(Status) && NT_SUCCESS(SubStatus))
  3838. {
  3839. if (Response)
  3840. {
  3841. LsaFreeReturnBuffer(Response);
  3842. }
  3843. }
  3844. else
  3845. {
  3846. DebugLog((DEB_ERROR, "KerbRefreshSmartcardCredentials failed: (0x%x - 0x%x)\n", Status, SubStatus));
  3847. }
  3848. }
  3849. }
  3850. else
  3851. {
  3852. wcscpy(pGlobals->Password,L"");
  3853. RtlInitUnicodeString(&pGlobals->PasswordString,pGlobals->Password);
  3854. wcscpy(pGlobals->OldPassword,L"");
  3855. RtlInitUnicodeString(&pGlobals->OldPasswordString,pGlobals->OldPassword);
  3856. }
  3857. RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName);
  3858. RtlInitUnicodeString(&pGlobals->DomainString, pGlobals->Domain);
  3859. pGlobals->RasUsed = FALSE;
  3860. pGlobals->hwndLogon = NULL;
  3861. //
  3862. // Generate a unique sid for this logon
  3863. //
  3864. if (!GetAndAllocateLogonSid(UserToken,&(pGlobals->LogonSid))) {
  3865. goto error_exit;
  3866. }
  3867. LogonSid = pGlobals->LogonSid;
  3868. //
  3869. // The user logged on successfully
  3870. //
  3871. //
  3872. // Create a filtered version of the token for running normal applications
  3873. // if so indicated by a registry setting
  3874. //
  3875. if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) {
  3876. TokenGroups->Groups[0].Attributes = 0;
  3877. TokenGroups->Groups[0].Sid = gAdminSid;
  3878. TokenGroups->GroupCount = 1;
  3879. Status = NtFilterToken(
  3880. UserToken,
  3881. DISABLE_MAX_PRIVILEGE,
  3882. TokenGroups, // disable the administrators sid
  3883. NULL, // no privileges
  3884. NULL,
  3885. &RestrictedToken
  3886. );
  3887. if (!NT_SUCCESS(Status))
  3888. {
  3889. DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status));
  3890. RestrictedToken = NULL;
  3891. }
  3892. //
  3893. // Now set the default dacl for the token
  3894. //
  3895. {
  3896. ULONG DaclLength = 0;
  3897. TOKEN_DEFAULT_DACL DefaultDacl;
  3898. DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid);
  3899. Dacl = Alloc(DaclLength);
  3900. // Check for memory allocation failure
  3901. if (Dacl == NULL) {
  3902. goto error_exit ;
  3903. }
  3904. Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION);
  3905. ASSERT(NT_SUCCESS(Status));
  3906. if (Status != STATUS_SUCCESS) {
  3907. goto error_exit;
  3908. }
  3909. Status = RtlAddAccessAllowedAce(
  3910. Dacl,
  3911. ACL_REVISION,
  3912. GENERIC_ALL,
  3913. LogonSid
  3914. );
  3915. ASSERT(NT_SUCCESS(Status));
  3916. if (Status != STATUS_SUCCESS) {
  3917. goto error_exit;
  3918. }
  3919. DefaultDacl.DefaultDacl = Dacl;
  3920. Status = NtSetInformationToken(
  3921. RestrictedToken,
  3922. TokenDefaultDacl,
  3923. &DefaultDacl,
  3924. sizeof(TOKEN_DEFAULT_DACL)
  3925. );
  3926. ASSERT(NT_SUCCESS(Status));
  3927. if (Status != STATUS_SUCCESS) {
  3928. goto error_exit;
  3929. }
  3930. Free(Dacl);
  3931. Dacl = NULL;
  3932. }
  3933. } else {
  3934. RestrictedToken = NULL;
  3935. }
  3936. //
  3937. // Notify credential managers of the successful logon
  3938. //
  3939. pTokenUser = (PTOKEN_USER) UserBuffer ;
  3940. Status = NtQueryInformationToken( UserToken,
  3941. TokenUser,
  3942. pTokenUser,
  3943. sizeof( UserBuffer ),
  3944. &TokenInfoSize );
  3945. if ( NT_SUCCESS( Status ) )
  3946. {
  3947. pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED,
  3948. RtlLengthSid( pTokenUser->User.Sid ) );
  3949. if ( pGlobals->UserProcessData.UserSid )
  3950. {
  3951. RtlCopyMemory( pGlobals->UserProcessData.UserSid,
  3952. pTokenUser->User.Sid,
  3953. RtlLengthSid( pTokenUser->User.Sid ) );
  3954. }
  3955. else
  3956. {
  3957. Status = STATUS_NO_MEMORY ;
  3958. }
  3959. }
  3960. if ( !NT_SUCCESS( Status ) )
  3961. {
  3962. NtClose(UserToken);
  3963. goto error_exit;
  3964. }
  3965. pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
  3966. if ( NULL == pGlobals->UserProcessData.NewThreadTokenSD )
  3967. {
  3968. if (pGlobals->Profile)
  3969. {
  3970. VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
  3971. pGlobals->Profile = NULL;
  3972. pGlobals->ProfileLength = 0;
  3973. }
  3974. NtClose(UserToken);
  3975. Result = MSGINA_DLG_FAILEDMSGSENT;
  3976. Status = STATUS_NO_MEMORY;
  3977. goto exit;
  3978. }
  3979. pGlobals->UserProcessData.RestrictedToken = RestrictedToken;
  3980. pGlobals->UserProcessData.UserToken = UserToken;
  3981. pGlobals->MprLogonScripts = NULL;
  3982. //
  3983. // If we get here, the system works well enough for the user to have
  3984. // actually logged on. Profile failures aren't fixable by last known
  3985. // good anyway. Therefore, declare the boot good.
  3986. //
  3987. ReportBootGood(pGlobals);
  3988. //
  3989. // Set up the system for the new user
  3990. //
  3991. pGlobals->LogonId = LogonId;
  3992. if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) {
  3993. DWORD cb = pGlobals->Profile->FullName.Length;
  3994. if (cb + sizeof(WCHAR) > MAX_STRING_LENGTH * sizeof(WCHAR))
  3995. cb = MAX_STRING_LENGTH * sizeof(WCHAR) - sizeof(WCHAR);
  3996. memcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, cb);
  3997. pGlobals->UserFullName[cb / sizeof(WCHAR)] = UNICODE_NULL;
  3998. } else {
  3999. //
  4000. // No profile - set full name = NULL
  4001. pGlobals->UserFullName[0] = 0;
  4002. ASSERT( lstrlen(pGlobals->UserFullName) == 0);
  4003. }
  4004. //
  4005. // Update our default username and domain ready for the next logon
  4006. //
  4007. //
  4008. // Update the default username & domain only if on the console. Otherwise
  4009. // we'll break AutoAdminLogon by changing the user name.
  4010. //
  4011. if ( g_Console )
  4012. {
  4013. if ( (!pGlobals->AutoAdminLogon) &&
  4014. (SafeBootMode != SAFEBOOT_MINIMAL ) )
  4015. {
  4016. WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName);
  4017. WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
  4018. }
  4019. WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName);
  4020. WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
  4021. }
  4022. if ( pGlobals->Domain[0] == '\0' )
  4023. {
  4024. GetProfileString( APPLICATION_NAME,
  4025. DEFAULT_DOMAIN_NAME_KEY,
  4026. TEXT(""),
  4027. pGlobals->Domain,
  4028. MAX_STRING_BYTES );
  4029. }
  4030. if ( !DCacheValidateCache( pGlobals->Cache ) )
  4031. {
  4032. ASSERT( pGlobals->ActiveArray == NULL );
  4033. DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, TRUE );
  4034. }
  4035. else
  4036. {
  4037. //
  4038. // Set the current default:
  4039. //
  4040. DCacheSetDefaultEntry( pGlobals->Cache,
  4041. pGlobals->Domain,
  4042. NULL );
  4043. }
  4044. Result = MSGINA_DLG_SUCCESS;
  4045. exit:
  4046. return Result;
  4047. error_exit:
  4048. Result = MSGINA_DLG_FAILEDMSGSENT;
  4049. if (pGlobals->Profile) {
  4050. VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
  4051. pGlobals->Profile = NULL;
  4052. pGlobals->ProfileLength = 0;
  4053. }
  4054. if (Dacl != NULL) {
  4055. Free(Dacl);
  4056. Dacl = NULL;
  4057. }
  4058. return Result;
  4059. }
  4060. PWSTR
  4061. AllocAndDuplicateString(
  4062. PWSTR pszString,
  4063. int len)
  4064. {
  4065. PWSTR pszNewString;
  4066. if (!pszString || !len)
  4067. {
  4068. return(NULL);
  4069. }
  4070. pszNewString = LocalAlloc(LMEM_FIXED, (len + 2)*sizeof(WCHAR));
  4071. if (pszNewString)
  4072. {
  4073. wcsncpy(pszNewString, pszString, len);
  4074. pszNewString[len] = UNICODE_NULL;
  4075. }
  4076. return(pszNewString);
  4077. }
  4078. BOOL
  4079. WINAPI
  4080. WlxGetConsoleSwitchCredentials (
  4081. PVOID pWlxContext,
  4082. PVOID pInfo
  4083. )
  4084. {
  4085. PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
  4086. PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 pReq = (PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0)pInfo;
  4087. BOOL bReturn = FALSE;
  4088. if (pReq->dwType != WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0) {
  4089. return FALSE;
  4090. }
  4091. //
  4092. // Initialize allocated pointers.
  4093. //
  4094. pReq->UserName = NULL;
  4095. pReq->Domain = NULL;
  4096. pReq->LogonScript = NULL;
  4097. pReq->HomeDirectory = NULL;
  4098. pReq->FullName = NULL;
  4099. pReq->ProfilePath = NULL;
  4100. pReq->HomeDirectoryDrive = NULL;
  4101. pReq->LogonServer = NULL;
  4102. pReq->PrivateData = NULL;
  4103. pReq->LogonId = pGlobals->LogonId;
  4104. pReq->UserToken = pGlobals->UserProcessData.UserToken;
  4105. pReq->LogonTime = pGlobals->LogonTime;
  4106. pReq->SmartCardLogon = pGlobals->SmartCardLogon;
  4107. pReq->UserName = AllocAndDuplicateString(pGlobals->UserName,
  4108. (DWORD) wcslen(pGlobals->UserName));
  4109. pReq->Domain = AllocAndDuplicateString(pGlobals->Domain,
  4110. (DWORD) wcslen(pGlobals->Domain));
  4111. //
  4112. // Quota Information
  4113. //
  4114. pReq->Quotas.PagedPoolLimit = pGlobals->UserProcessData.Quotas.PagedPoolLimit;
  4115. pReq->Quotas.NonPagedPoolLimit = pGlobals->UserProcessData.Quotas.NonPagedPoolLimit;
  4116. pReq->Quotas.MinimumWorkingSetSize = pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize;
  4117. pReq->Quotas.MaximumWorkingSetSize = pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize;
  4118. pReq->Quotas.PagefileLimit = pGlobals->UserProcessData.Quotas.PagefileLimit;
  4119. pReq->Quotas.TimeLimit = pGlobals->UserProcessData.Quotas.TimeLimit;
  4120. //
  4121. // Profile Information
  4122. //
  4123. pReq->ProfileLength = pGlobals->ProfileLength;
  4124. pReq->UserFlags = pGlobals->Profile->UserFlags;
  4125. pReq->MessageType = pGlobals->Profile->MessageType;
  4126. pReq->LogonCount = pGlobals->Profile->LogonCount;
  4127. pReq->BadPasswordCount = pGlobals->Profile->BadPasswordCount;
  4128. pReq->ProfileLogonTime = pGlobals->Profile->LogonTime;
  4129. pReq->LogoffTime = pGlobals->Profile->LogoffTime;
  4130. pReq->KickOffTime = pGlobals->Profile->KickOffTime;
  4131. pReq->PasswordLastSet = pGlobals->Profile->PasswordLastSet;
  4132. pReq->PasswordCanChange = pGlobals->Profile->PasswordCanChange;
  4133. pReq->PasswordMustChange = pGlobals->Profile->PasswordMustChange;
  4134. pReq->LogonScript = AllocAndDuplicateString(pGlobals->Profile->LogonScript.Buffer, pGlobals->Profile->LogonScript.Length/sizeof(WCHAR));
  4135. pReq->HomeDirectory = AllocAndDuplicateString(pGlobals->Profile->HomeDirectory.Buffer, pGlobals->Profile->HomeDirectory.Length/sizeof(WCHAR));
  4136. pReq->FullName = AllocAndDuplicateString(pGlobals->Profile->FullName.Buffer, pGlobals->Profile->FullName.Length/sizeof(WCHAR));
  4137. pReq->ProfilePath = AllocAndDuplicateString(pGlobals->Profile->ProfilePath.Buffer, pGlobals->Profile->ProfilePath.Length/sizeof(WCHAR));
  4138. pReq->HomeDirectoryDrive = AllocAndDuplicateString(pGlobals->Profile->HomeDirectoryDrive.Buffer, pGlobals->Profile->HomeDirectoryDrive.Length/sizeof(WCHAR));
  4139. pReq->LogonServer = AllocAndDuplicateString(pGlobals->Profile->LogonServer.Buffer, pGlobals->Profile->LogonServer.Length/sizeof(WCHAR));
  4140. pReq->PrivateDataLen = PASSWORD_HASH_SIZE;
  4141. pReq->PrivateData = LocalAlloc(LMEM_FIXED, PASSWORD_HASH_SIZE );
  4142. if (pReq->PrivateData == NULL) {
  4143. goto done;
  4144. }
  4145. memcpy(pReq->PrivateData, pGlobals->PasswordHash, PASSWORD_HASH_SIZE );
  4146. bReturn = TRUE;
  4147. done:
  4148. if (!bReturn) {
  4149. if (pReq->UserName != NULL) {
  4150. LocalFree(pReq->UserName);
  4151. }
  4152. if (pReq->Domain != NULL) {
  4153. LocalFree(pReq->Domain);
  4154. }
  4155. if (pReq->LogonScript != NULL) {
  4156. LocalFree(pReq->LogonScript);
  4157. }
  4158. if (pReq->HomeDirectory != NULL) {
  4159. LocalFree(pReq->HomeDirectory);
  4160. }
  4161. if (pReq->FullName != NULL) {
  4162. LocalFree(pReq->FullName);
  4163. }
  4164. if (pReq->ProfilePath != NULL) {
  4165. LocalFree(pReq->ProfilePath);
  4166. }
  4167. if (pReq->HomeDirectoryDrive != NULL) {
  4168. LocalFree(pReq->HomeDirectoryDrive);
  4169. }
  4170. if (pReq->LogonServer != NULL) {
  4171. LocalFree(pReq->LogonServer);
  4172. }
  4173. if (pReq->PrivateData != NULL) {
  4174. LocalFree(pReq->PrivateData);
  4175. }
  4176. }
  4177. return bReturn;
  4178. }
  4179. //+---------------------------------------------------------------------------
  4180. //
  4181. // Function: QuerySwitchConsoleCredentials
  4182. //
  4183. // Notes:
  4184. //
  4185. // Query credentials from session connecting to console to do switch console
  4186. // This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
  4187. // in the context of the console session (sessionid 0) winlogon.
  4188. // This type of logon is for Single Session Terminal Server. When a user
  4189. // logs on from a remote TS session, we pass the credentials from the remote session
  4190. // to the console session and do an auto-logon. This routine queries the credentials,
  4191. // logs on the user on the console sesion
  4192. //
  4193. //
  4194. //----------------------------------------------------------------------------
  4195. BOOL
  4196. WINAPI
  4197. QuerySwitchConsoleCredentials(PGLOBALS pGlobals, HANDLE * phUserToken, PLUID pLogonId)
  4198. {
  4199. WLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 CredInfo;
  4200. RtlZeroMemory(&CredInfo,sizeof(CredInfo));
  4201. CredInfo.dwType = WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0;
  4202. if (!pWlxFuncs->WlxQueryConsoleSwitchCredentials(&CredInfo)){
  4203. return FALSE;
  4204. }
  4205. if (!CredInfo.UserToken || !CredInfo.UserName) {
  4206. //return false if any of the critical information is missing
  4207. return FALSE;
  4208. }
  4209. pGlobals->Profile = (PMSV1_0_INTERACTIVE_PROFILE) VirtualAlloc(NULL,
  4210. sizeof(MSV1_0_INTERACTIVE_PROFILE),
  4211. MEM_COMMIT,
  4212. PAGE_READWRITE);
  4213. if (pGlobals->Profile == NULL) {
  4214. goto returnerror;
  4215. }
  4216. //
  4217. // Token, LUID
  4218. //
  4219. *pLogonId = CredInfo.LogonId;
  4220. *phUserToken = CredInfo.UserToken;
  4221. pGlobals->LogonTime = CredInfo.LogonTime;
  4222. pGlobals->SmartCardLogon = CredInfo.SmartCardLogon;
  4223. pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 );
  4224. //
  4225. // Quota Information
  4226. //
  4227. pGlobals->UserProcessData.Quotas.PagedPoolLimit = CredInfo.Quotas.PagedPoolLimit ;
  4228. pGlobals->UserProcessData.Quotas.NonPagedPoolLimit = CredInfo.Quotas.NonPagedPoolLimit;
  4229. pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize = CredInfo.Quotas.MinimumWorkingSetSize;
  4230. pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize = CredInfo.Quotas.MaximumWorkingSetSize;
  4231. pGlobals->UserProcessData.Quotas.PagefileLimit = CredInfo.Quotas.PagefileLimit;
  4232. pGlobals->UserProcessData.Quotas.TimeLimit = CredInfo.Quotas.TimeLimit;
  4233. //
  4234. // Profile Information
  4235. //
  4236. pGlobals->ProfileLength = CredInfo.ProfileLength;
  4237. pGlobals->Profile->UserFlags = CredInfo.UserFlags;
  4238. pGlobals->Profile->MessageType = CredInfo.MessageType;
  4239. pGlobals->Profile->LogonCount = CredInfo.LogonCount;
  4240. pGlobals->Profile->BadPasswordCount = CredInfo.BadPasswordCount;
  4241. pGlobals->Profile->LogonTime = CredInfo.ProfileLogonTime;
  4242. pGlobals->Profile->LogoffTime = CredInfo.LogoffTime;
  4243. pGlobals->Profile->KickOffTime = CredInfo.KickOffTime;
  4244. pGlobals->Profile->PasswordLastSet = CredInfo.PasswordLastSet;
  4245. pGlobals->Profile->PasswordCanChange = CredInfo.PasswordCanChange;
  4246. pGlobals->Profile->PasswordMustChange = CredInfo.PasswordMustChange;
  4247. RtlInitUnicodeString(&pGlobals->Profile->LogonScript, CredInfo.LogonScript);
  4248. RtlInitUnicodeString(&pGlobals->Profile->HomeDirectory, CredInfo.HomeDirectory);
  4249. RtlInitUnicodeString(&pGlobals->Profile->FullName, CredInfo.FullName);
  4250. RtlInitUnicodeString(&pGlobals->Profile->ProfilePath, CredInfo.ProfilePath);
  4251. RtlInitUnicodeString(&pGlobals->Profile->HomeDirectoryDrive, CredInfo.HomeDirectoryDrive);
  4252. RtlInitUnicodeString(&pGlobals->Profile->LogonServer, CredInfo.LogonServer);
  4253. if (CredInfo.UserName) {
  4254. // CredInfo.UserName is a copy of pGlobals->UserName in another session (OK)
  4255. wcscpy(pGlobals->UserName,CredInfo.UserName);
  4256. LocalFree(CredInfo.UserName);
  4257. } else {
  4258. wcscpy(pGlobals->UserName,L"");
  4259. }
  4260. if (CredInfo.Domain) {
  4261. // CredInfo.Domain is a copy of pGlobals->Domain in another session (OK)
  4262. wcscpy(pGlobals->Domain,CredInfo.Domain);
  4263. LocalFree(CredInfo.Domain);
  4264. } else {
  4265. wcscpy(pGlobals->Domain,L"");
  4266. }
  4267. if (CredInfo.PrivateDataLen) {
  4268. RtlCopyMemory(pGlobals->PasswordHash,CredInfo.PrivateData, CredInfo.PrivateDataLen );
  4269. LocalFree(CredInfo.PrivateData);
  4270. } else {
  4271. RtlZeroMemory(pGlobals->PasswordHash,PASSWORD_HASH_SIZE);
  4272. }
  4273. pGlobals->TransderedCredentials = TRUE;
  4274. return TRUE;
  4275. returnerror:
  4276. if (CredInfo.UserName) {
  4277. LocalFree(CredInfo.UserName);
  4278. }
  4279. if (CredInfo.Domain) {
  4280. LocalFree(CredInfo.Domain);
  4281. }
  4282. if (CredInfo.LogonScript) {
  4283. LocalFree(CredInfo.LogonScript);
  4284. }
  4285. if (CredInfo.HomeDirectory) {
  4286. LocalFree(CredInfo.HomeDirectory);
  4287. }
  4288. if (CredInfo.FullName) {
  4289. LocalFree(CredInfo.FullName);
  4290. }
  4291. if (CredInfo.ProfilePath) {
  4292. LocalFree(CredInfo.ProfilePath);
  4293. }
  4294. if (CredInfo.HomeDirectoryDrive) {
  4295. LocalFree(CredInfo.HomeDirectoryDrive);
  4296. }
  4297. if (CredInfo.LogonServer) {
  4298. LocalFree(CredInfo.LogonServer);
  4299. }
  4300. if (CredInfo.UserToken) {
  4301. CloseHandle(CredInfo.UserToken);
  4302. }
  4303. if (pGlobals->Profile) {
  4304. VirtualFree(pGlobals->Profile, 0, MEM_RELEASE);
  4305. pGlobals->Profile = NULL;
  4306. pGlobals->ProfileLength = 0;
  4307. }
  4308. return FALSE;
  4309. }
  4310. BOOL
  4311. GetAndAllocateLogonSid(
  4312. HANDLE hToken,
  4313. PSID *pLogonSid
  4314. )
  4315. {
  4316. PTOKEN_GROUPS ptgGroups = NULL;
  4317. PTOKEN_GROUPS ptgOldGroups = NULL;
  4318. DWORD cbBuffer = 512; // allocation size
  4319. DWORD dwSidLength; // required size to hold Sid
  4320. UINT i; // Sid index counter
  4321. BOOL bSuccess = FALSE; // assume this function will fail
  4322. *pLogonSid = NULL; // invalidate pointer
  4323. //
  4324. // initial allocation attempts
  4325. //
  4326. ptgGroups=(PTOKEN_GROUPS)Alloc(cbBuffer);
  4327. if(ptgGroups == NULL) return FALSE;
  4328. __try {
  4329. //
  4330. // obtain token information. reallocate memory if necessary
  4331. //
  4332. while(!GetTokenInformation(
  4333. hToken, TokenGroups, ptgGroups, cbBuffer, &cbBuffer)) {
  4334. //
  4335. // if appropriate, reallocate memory, otherwise bail
  4336. //
  4337. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  4338. //
  4339. // attempt to reallocate buffer
  4340. //
  4341. ptgOldGroups = ptgGroups;
  4342. #pragma prefast(suppress: 308, "PREfast noise: LocalRealloc use is valid since old pointer was saved")
  4343. if((ptgGroups=(PTOKEN_GROUPS)ReAlloc(
  4344. ptgGroups, cbBuffer)) == NULL)
  4345. {
  4346. Free(ptgOldGroups);
  4347. __leave;
  4348. }
  4349. }
  4350. else __leave;
  4351. }
  4352. //
  4353. // Get the logon Sid by looping through the Sids in the token
  4354. //
  4355. for(i = 0 ; i < ptgGroups->GroupCount ; i++) {
  4356. if(ptgGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID) {
  4357. //
  4358. // insure we are dealing with a valid Sid
  4359. //
  4360. if(!IsValidSid(ptgGroups->Groups[i].Sid)) __leave;
  4361. //
  4362. // get required allocation size to copy the Sid
  4363. //
  4364. dwSidLength=GetLengthSid(ptgGroups->Groups[i].Sid);
  4365. //
  4366. // allocate storage for the Logon Sid
  4367. //
  4368. if((*pLogonSid=(PSID *)Alloc(
  4369. dwSidLength)) == NULL) __leave;
  4370. //
  4371. // copy the Logon Sid to the storage we just allocated
  4372. //
  4373. if(!CopySid(dwSidLength, *pLogonSid, ptgGroups->Groups[i].Sid)) __leave;
  4374. bSuccess=TRUE; // indicate success...
  4375. break; // ...and get out
  4376. }
  4377. }
  4378. } // try
  4379. __finally {
  4380. //
  4381. // free allocated resources
  4382. //
  4383. if(ptgGroups != NULL) Free(ptgGroups);
  4384. if(!bSuccess) {
  4385. if(*pLogonSid != NULL) {
  4386. Free(*pLogonSid);
  4387. *pLogonSid = NULL;
  4388. }
  4389. }
  4390. } // finally
  4391. return bSuccess;
  4392. }