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.

1009 lines
34 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: ReturnToWelcome.cpp
  3. //
  4. // Copyright (c) 2001, Microsoft Corporation
  5. //
  6. // File to handle return to welcome.
  7. //
  8. // History: 2001-01-11 vtan created
  9. // --------------------------------------------------------------------------
  10. #include "StandardHeader.h"
  11. #include "ReturnToWelcome.h"
  12. #include <ginaipc.h>
  13. #include <ginarcid.h>
  14. #include <msginaexports.h>
  15. #include <winsta.h>
  16. #include <winwlx.h>
  17. #include "Access.h"
  18. #include "Compatibility.h"
  19. #include "CredentialTransfer.h"
  20. #include "StatusCode.h"
  21. #include "SystemSettings.h"
  22. #include "TokenInformation.h"
  23. // --------------------------------------------------------------------------
  24. // CReturnToWelcome::s_pWlxContext
  25. // CReturnToWelcome::s_hEventRequest
  26. // CReturnToWelcome::s_hEventShown
  27. // CReturnToWelcome::s_hWait
  28. // CReturnToWelcome::s_szEventName
  29. // CReturnToWelcome::s_dwSessionID
  30. //
  31. // Purpose: Static member variables.
  32. //
  33. // History: 2001-01-11 vtan created
  34. // --------------------------------------------------------------------------
  35. void* CReturnToWelcome::s_pWlxContext = NULL;
  36. HANDLE CReturnToWelcome::s_hEventRequest = NULL;
  37. HANDLE CReturnToWelcome::s_hEventShown = NULL;
  38. HANDLE CReturnToWelcome::s_hWait = NULL;
  39. const TCHAR CReturnToWelcome::s_szEventName[] = TEXT("msgina: ReturnToWelcome");
  40. DWORD CReturnToWelcome::s_dwSessionID = static_cast<DWORD>(-1);
  41. // --------------------------------------------------------------------------
  42. // CReturnToWelcome::CReturnToWelcome
  43. //
  44. // Arguments: <none>
  45. //
  46. // Returns: <none>
  47. //
  48. // Purpose: Constructor for CReturnToWelcome.
  49. //
  50. // History: 2001-01-11 vtan created
  51. // --------------------------------------------------------------------------
  52. CReturnToWelcome::CReturnToWelcome (void) :
  53. _hToken(NULL),
  54. _pLogonIPCCredentials(NULL),
  55. _fUnlock(false),
  56. _fDialogEnded(false)
  57. {
  58. }
  59. // --------------------------------------------------------------------------
  60. // CReturnToWelcome::~CReturnToWelcome
  61. //
  62. // Arguments: <none>
  63. //
  64. // Returns: <none>
  65. //
  66. // Purpose: Destructor for CReturnToWelcome.
  67. //
  68. // History: 2001-01-11 vtan created
  69. // --------------------------------------------------------------------------
  70. CReturnToWelcome::~CReturnToWelcome (void)
  71. {
  72. ReleaseMemory(_pLogonIPCCredentials);
  73. ReleaseHandle(_hToken);
  74. }
  75. // --------------------------------------------------------------------------
  76. // CReturnToWelcome::Show
  77. //
  78. // Arguments: fUnlock = Required to unlock logon mode or not?
  79. //
  80. // Returns: INT_PTR
  81. //
  82. // Purpose: Presents the welcome screen with a logged on user. This is a
  83. // special case to increase performance by not performing
  84. // needless console disconnects and reconnects.
  85. //
  86. // History: 2001-01-11 vtan created
  87. // --------------------------------------------------------------------------
  88. INT_PTR CReturnToWelcome::Show (bool fUnlock)
  89. {
  90. INT_PTR iResult;
  91. _fUnlock = fUnlock;
  92. // If there was a reconnect failure then show it before showing the UI host.
  93. if (s_dwSessionID != static_cast<DWORD>(-1))
  94. {
  95. ShowReconnectFailure(s_dwSessionID);
  96. s_dwSessionID = static_cast<DWORD>(-1);
  97. }
  98. // Start the status host.
  99. _Shell_LogonStatus_Init(HOST_START_NORMAL);
  100. // Disable input timeouts on this dialog.
  101. TBOOL(_Gina_SetTimeout(s_pWlxContext, 0));
  102. // Use the DS component of msgina to display the dialog. It's a stub
  103. // dialog that pretends to be WlxLoggedOutSAS but really isn't.
  104. iResult = _Gina_DialogBoxParam(s_pWlxContext,
  105. hDllInstance,
  106. MAKEINTRESOURCE(IDD_GINA_RETURNTOWELCOME),
  107. NULL,
  108. CB_DialogProc,
  109. reinterpret_cast<LPARAM>(this));
  110. // The dialog has been shown. Release the CB_Request thread to
  111. // re-register the wait on the switch user event.
  112. if (s_hEventShown != NULL)
  113. {
  114. TBOOL(SetEvent(s_hEventShown));
  115. }
  116. // Handle MSGINA_DLG_SWITCH_CONSOLE and map this to WLX_SAS_ACTION_LOGON.
  117. // This is an authenticated logon from a different session causing
  118. // this one to get disconnected.
  119. if (iResult == MSGINA_DLG_SWITCH_CONSOLE)
  120. {
  121. iResult = WLX_SAS_ACTION_LOGON;
  122. }
  123. // Look at the return code and respond accordingly. Map power button
  124. // actions to the appropriate WLX_SAS_ACTION_SHUTDOWN_xxx.
  125. else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_REBOOT_FLAG))
  126. {
  127. iResult = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
  128. }
  129. else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SHUTDOWN_FLAG))
  130. {
  131. iResult = WLX_SAS_ACTION_SHUTDOWN;
  132. }
  133. else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_POWEROFF_FLAG))
  134. {
  135. iResult = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
  136. }
  137. else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_HIBERNATE_FLAG))
  138. {
  139. iResult = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
  140. }
  141. else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SLEEP_FLAG))
  142. {
  143. iResult = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
  144. }
  145. else if (iResult == MSGINA_DLG_LOCK_WORKSTATION)
  146. {
  147. iResult = WLX_SAS_ACTION_LOCK_WKSTA;
  148. }
  149. else if (iResult == WLX_DLG_USER_LOGOFF)
  150. {
  151. iResult = WLX_SAS_ACTION_LOGOFF;
  152. }
  153. else if (iResult == MSGINA_DLG_SUCCESS)
  154. {
  155. PSID pSIDNew;
  156. pSIDNew = NULL;
  157. if (_hToken != NULL)
  158. {
  159. PSID pSID;
  160. CTokenInformation tokenInformationNew(_hToken);
  161. pSID = tokenInformationNew.GetUserSID();
  162. if (pSID != NULL)
  163. {
  164. DWORD dwSIDSize;
  165. dwSIDSize = GetLengthSid(pSID);
  166. pSIDNew = LocalAlloc(LMEM_FIXED, dwSIDSize);
  167. if (pSIDNew != NULL)
  168. {
  169. TBOOL(CopySid(dwSIDSize, pSIDNew, pSID));
  170. }
  171. }
  172. }
  173. if (pSIDNew == NULL)
  174. {
  175. DWORD dwSIDSize, dwDomainSize;
  176. SID_NAME_USE sidNameUse;
  177. WCHAR *pszDomain;
  178. dwSIDSize = dwDomainSize = 0;
  179. (BOOL)LookupAccountNameW(NULL,
  180. _pLogonIPCCredentials->userID.wszUsername,
  181. NULL,
  182. &dwSIDSize,
  183. NULL,
  184. &dwDomainSize,
  185. &sidNameUse);
  186. pszDomain = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, dwDomainSize * sizeof(WCHAR)));
  187. if (pszDomain != NULL)
  188. {
  189. pSIDNew = LocalAlloc(LMEM_FIXED, dwSIDSize);
  190. if (pSIDNew != NULL)
  191. {
  192. if (LookupAccountNameW(NULL,
  193. _pLogonIPCCredentials->userID.wszUsername,
  194. pSIDNew,
  195. &dwSIDSize,
  196. pszDomain,
  197. &dwDomainSize,
  198. &sidNameUse) == FALSE)
  199. {
  200. (HLOCAL)LocalFree(pSIDNew);
  201. pSIDNew = NULL;
  202. }
  203. }
  204. (HLOCAL)LocalFree(pszDomain);
  205. }
  206. }
  207. if (pSIDNew != NULL)
  208. {
  209. // If the dialog succeeded then a user was authenticated.
  210. if (IsSameUser(pSIDNew, _Gina_GetUserToken(s_pWlxContext)))
  211. {
  212. // If it's the same user then there's no disconnect or reconnect
  213. // required. We're done. Return back to the user's desktop.
  214. iResult = WLX_SAS_ACTION_LOGON;
  215. }
  216. else
  217. {
  218. DWORD dwSessionID;
  219. // Assume something will fail. The return code
  220. // MSGINA_DLG_SWITCH_FAILURE is a special message back to
  221. // winlogon!HandleSwitchUser to signal that a
  222. // reconnect/disconnect of some kind failed and that the
  223. // welcome screen needs to be re-displayed along with an
  224. // appropriate error message.
  225. iResult = MSGINA_DLG_SWITCH_FAILURE;
  226. if (UserIsDisconnected(pSIDNew, &dwSessionID))
  227. {
  228. // If the user is a disconnected user then reconnect back to
  229. // their session. If this succeeds then we're done.
  230. if (WinStationConnect(SERVERNAME_CURRENT,
  231. dwSessionID,
  232. NtCurrentPeb()->SessionId,
  233. L"",
  234. TRUE) != FALSE)
  235. {
  236. CCompatibility::MinimizeWindowsOnDisconnect();
  237. CCompatibility::DropSessionProcessesWorkingSets();
  238. iResult = WLX_SAS_ACTION_LOGON;
  239. }
  240. else
  241. {
  242. // If it fails then stash this information globally.
  243. // The return code MSGINA_DLG_SWITCH_FAILURE will cause
  244. // us to get called again and this will be checked, used
  245. // and reset.
  246. s_dwSessionID = dwSessionID;
  247. }
  248. }
  249. else
  250. {
  251. // Otherwise credentials need to be transferred across sessions to
  252. // a newly created session. Start the credential transfer server.
  253. if (NT_SUCCESS(CCredentialServer::Start(_pLogonIPCCredentials, 0)))
  254. {
  255. CCompatibility::MinimizeWindowsOnDisconnect();
  256. CCompatibility::DropSessionProcessesWorkingSets();
  257. iResult = WLX_SAS_ACTION_LOGON;
  258. }
  259. }
  260. }
  261. (HLOCAL)LocalFree(pSIDNew);
  262. }
  263. else
  264. {
  265. iResult = MSGINA_DLG_SWITCH_FAILURE;
  266. s_dwSessionID = NtCurrentPeb()->SessionId;
  267. }
  268. }
  269. else
  270. {
  271. // If the dialog failed then do nothing. This will force a loop back
  272. // to the present the welcome screen again until authentication.
  273. iResult = WLX_SAS_ACTION_NONE;
  274. }
  275. if ((iResult == WLX_SAS_ACTION_LOGON) || (iResult == WLX_SAS_ACTION_NONE) || (iResult == MSGINA_DLG_SWITCH_FAILURE))
  276. {
  277. _Shell_LogonStatus_Destroy(HOST_END_HIDE);
  278. }
  279. return(iResult);
  280. }
  281. // --------------------------------------------------------------------------
  282. // CReturnToWelcome::GetEventName
  283. //
  284. // Arguments: <none>
  285. //
  286. // Returns: const WCHAR*
  287. //
  288. // Purpose: Returns the name of the event to return to welcome. Signal
  289. // this event and you'll get a return to welcome.
  290. //
  291. // History: 2001-01-11 vtan created
  292. // --------------------------------------------------------------------------
  293. const WCHAR* CReturnToWelcome::GetEventName (void)
  294. {
  295. return(s_szEventName);
  296. }
  297. // --------------------------------------------------------------------------
  298. // CReturnToWelcome::StaticInitialize
  299. //
  300. // Arguments: pWlxContext = PGLOBALS struct for msgina.
  301. //
  302. // Returns: NTSTATUS
  303. //
  304. // Purpose: Creates a named event and ACL's it so that anybody can signal
  305. // it but only S-1-5-18 (NT AUTHORITY\SYSTEM) or S-1-5-32-544
  306. // (local administrators) can synchronize to it. Then register a
  307. // wait on this object.
  308. //
  309. // History: 2001-01-11 vtan created
  310. // --------------------------------------------------------------------------
  311. NTSTATUS CReturnToWelcome::StaticInitialize (void *pWlxContext)
  312. {
  313. NTSTATUS status;
  314. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  315. SECURITY_ATTRIBUTES securityAttributes;
  316. ASSERTMSG(s_pWlxContext == NULL, "Non NULL pWlxContext in CReturnToWelcome::StaticInitialize");
  317. ASSERTMSG(s_hEventRequest == NULL, "Non NULL request event in CReturnToWelcome::StaticInitialize");
  318. s_pWlxContext = pWlxContext;
  319. // Build a security descriptor for the event that allows:
  320. // S-1-5-18 NT AUTHORITY\SYSTEM EVENT_ALL_ACCESS
  321. // S-1-5-32-544 <local administrators> READ_CONTROL | SYNCHRONIZE | EVENT_MODIFY_STATE
  322. // S-1-1-0 <everybody> EVENT_MODIFY_STATE
  323. static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
  324. static SID_IDENTIFIER_AUTHORITY s_SecurityWorldSID = SECURITY_WORLD_SID_AUTHORITY;
  325. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  326. {
  327. {
  328. &s_SecurityNTAuthority,
  329. 1,
  330. SECURITY_LOCAL_SYSTEM_RID,
  331. 0, 0, 0, 0, 0, 0, 0,
  332. EVENT_ALL_ACCESS
  333. },
  334. {
  335. &s_SecurityNTAuthority,
  336. 2,
  337. SECURITY_BUILTIN_DOMAIN_RID,
  338. DOMAIN_ALIAS_RID_ADMINS,
  339. 0, 0, 0, 0, 0, 0,
  340. READ_CONTROL | SYNCHRONIZE | EVENT_MODIFY_STATE
  341. },
  342. {
  343. &s_SecurityWorldSID,
  344. 1,
  345. SECURITY_WORLD_RID,
  346. 0, 0, 0, 0, 0, 0, 0,
  347. EVENT_MODIFY_STATE
  348. }
  349. };
  350. // Build a security descriptor that allows the described access above.
  351. pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  352. if (pSecurityDescriptor != NULL)
  353. {
  354. securityAttributes.nLength = sizeof(securityAttributes);
  355. securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  356. securityAttributes.bInheritHandle = FALSE;
  357. s_hEventRequest = CreateEvent(&securityAttributes, TRUE, FALSE, GetEventName());
  358. if (s_hEventRequest != NULL)
  359. {
  360. s_hEventShown = CreateEvent(NULL, FALSE, FALSE, NULL);
  361. if (s_hEventShown != NULL)
  362. {
  363. status = RegisterWaitForRequest();
  364. }
  365. else
  366. {
  367. status = CStatusCode::StatusCodeOfLastError();
  368. }
  369. }
  370. else
  371. {
  372. status = CStatusCode::StatusCodeOfLastError();
  373. }
  374. ReleaseMemory(pSecurityDescriptor);
  375. }
  376. else
  377. {
  378. status = STATUS_NO_MEMORY;
  379. }
  380. // Initialize the last failed connect session ID.
  381. s_dwSessionID = static_cast<DWORD>(-1);
  382. return(status);
  383. }
  384. // --------------------------------------------------------------------------
  385. // CReturnToWelcome::StaticTerminate
  386. //
  387. // Arguments: <none>
  388. //
  389. // Returns: NTSTATUS
  390. //
  391. // Purpose: Unregisters the wait on the named event and releases
  392. // associated resources.
  393. //
  394. // History: 2001-01-11 vtan created
  395. // --------------------------------------------------------------------------
  396. NTSTATUS CReturnToWelcome::StaticTerminate (void)
  397. {
  398. HANDLE hWait;
  399. hWait = InterlockedExchangePointer(&s_hWait, NULL);
  400. if (hWait != NULL)
  401. {
  402. (BOOL)UnregisterWait(hWait);
  403. }
  404. ReleaseHandle(s_hEventShown);
  405. ReleaseHandle(s_hEventRequest);
  406. s_pWlxContext = NULL;
  407. return(STATUS_SUCCESS);
  408. }
  409. // --------------------------------------------------------------------------
  410. // CReturnToWelcome::IsSameUser
  411. //
  412. // Arguments: hToken = Token of the user for the current session.
  413. //
  414. // Returns: bool
  415. //
  416. // Purpose: Compares the token of the user for the current session with
  417. // the token of the user who just authenticated. If the user is
  418. // the same (compared by user SID not logon SID) then this is
  419. // effectively a re-authentication. This will switch back.
  420. //
  421. // History: 2001-01-11 vtan created
  422. // --------------------------------------------------------------------------
  423. bool CReturnToWelcome::IsSameUser (PSID pSIDUser, HANDLE hToken) const
  424. {
  425. bool fResult;
  426. if (hToken != NULL)
  427. {
  428. PSID pSIDCompare;
  429. CTokenInformation tokenInformationCompare(hToken);
  430. pSIDCompare = tokenInformationCompare.GetUserSID();
  431. fResult = ((pSIDUser != NULL) &&
  432. (pSIDCompare != NULL) &&
  433. (EqualSid(pSIDUser, pSIDCompare) != FALSE));
  434. }
  435. else
  436. {
  437. fResult = false;
  438. }
  439. return(fResult);
  440. }
  441. // --------------------------------------------------------------------------
  442. // CReturnToWelcome::UserIsDisconnected
  443. //
  444. // Arguments: pdwSessionID = Session ID returned of found user.
  445. //
  446. // Returns: bool
  447. //
  448. // Purpose: Searches the list of disconnected sessions for the given
  449. // matching user SID. Retrieve the user token for each
  450. // disconnected window station and when a match is found return
  451. // that session ID and a result back to the caller.
  452. //
  453. // History: 2001-01-12 vtan created
  454. // --------------------------------------------------------------------------
  455. bool CReturnToWelcome::UserIsDisconnected (PSID pSIDUser, DWORD *pdwSessionID) const
  456. {
  457. bool fResult;
  458. PLOGONID pLogonIDs;
  459. ULONG ulEntries;
  460. fResult = false;
  461. if (WinStationEnumerate(SERVERNAME_CURRENT, &pLogonIDs, &ulEntries) != FALSE)
  462. {
  463. ULONG ulIndex;
  464. PLOGONID pLogonID;
  465. for (ulIndex = 0, pLogonID = pLogonIDs; !fResult && (ulIndex < ulEntries); ++ulIndex, ++pLogonID)
  466. {
  467. if (pLogonID->State == State_Disconnected)
  468. {
  469. ULONG ulReturnLength;
  470. WINSTATIONUSERTOKEN winStationUserToken;
  471. winStationUserToken.ProcessId = ULongToHandle(GetCurrentProcessId());
  472. winStationUserToken.ThreadId = ULongToHandle(GetCurrentThreadId());
  473. winStationUserToken.UserToken = NULL;
  474. if (WinStationQueryInformation(SERVERNAME_CURRENT,
  475. pLogonID->SessionId,
  476. WinStationUserToken,
  477. &winStationUserToken,
  478. sizeof(winStationUserToken),
  479. &ulReturnLength) != FALSE)
  480. {
  481. fResult = IsSameUser(pSIDUser, winStationUserToken.UserToken);
  482. if (fResult)
  483. {
  484. *pdwSessionID = pLogonID->SessionId;
  485. }
  486. TBOOL(CloseHandle(winStationUserToken.UserToken));
  487. }
  488. }
  489. }
  490. // Free any resources used.
  491. (BOOLEAN)WinStationFreeMemory(pLogonIDs);
  492. }
  493. return(fResult);
  494. }
  495. // --------------------------------------------------------------------------
  496. // CReturnToWelcome::GetSessionUserName
  497. //
  498. // Arguments: dwSessionID = Session ID of user name to get.
  499. // pszBuffer = UNLEN character buffer to use.
  500. //
  501. // Returns: <none>
  502. //
  503. // Purpose: Retrieves the display name of the user for the given session.
  504. // The buffer must be at least UNLEN + sizeof('\0') characters.
  505. //
  506. // History: 2001-03-02 vtan created
  507. // --------------------------------------------------------------------------
  508. void CReturnToWelcome::GetSessionUserName (DWORD dwSessionID, WCHAR *pszBuffer)
  509. {
  510. ULONG ulReturnLength;
  511. WINSTATIONINFORMATIONW winStationInformation;
  512. // Ask terminal server for the user name of the session.
  513. if (WinStationQueryInformationW(SERVERNAME_CURRENT,
  514. dwSessionID,
  515. WinStationInformation,
  516. &winStationInformation,
  517. sizeof(winStationInformation),
  518. &ulReturnLength) != FALSE)
  519. {
  520. USER_INFO_2 *pUI2;
  521. // Convert the user name to a display name.
  522. if (NERR_Success == NetUserGetInfo(NULL,
  523. winStationInformation.UserName,
  524. 2,
  525. reinterpret_cast<LPBYTE*>(&pUI2)))
  526. {
  527. const WCHAR *pszName;
  528. // Use the display name if it exists and isn't empty.
  529. // Otherwise use the logon name.
  530. if ((pUI2->usri2_full_name != NULL) && (pUI2->usri2_full_name[0] != L'\0'))
  531. {
  532. pszName = pUI2->usri2_full_name;
  533. }
  534. else
  535. {
  536. pszName = winStationInformation.UserName;
  537. }
  538. (WCHAR*)lstrcpyW(pszBuffer, pszName);
  539. (NET_API_STATUS)NetApiBufferFree(pUI2);
  540. }
  541. }
  542. }
  543. // --------------------------------------------------------------------------
  544. // CReturnToWelcome::ShowReconnectFailure
  545. //
  546. // Arguments: dwSessionID = Session that failed reconnection.
  547. //
  548. // Returns: <none>
  549. //
  550. // Purpose: Shows a message box indicating that the reconnection failed.
  551. // The message box times out in 120 seconds.
  552. //
  553. // History: 2001-03-02 vtan created
  554. // --------------------------------------------------------------------------
  555. void CReturnToWelcome::ShowReconnectFailure (DWORD dwSessionID)
  556. {
  557. static const int BUFFER_SIZE = 256;
  558. WCHAR *pszText;
  559. pszText = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(WCHAR)));
  560. if (pszText != NULL)
  561. {
  562. WCHAR *pszCaption;
  563. pszCaption = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(WCHAR)));
  564. if (pszCaption != NULL)
  565. {
  566. WCHAR *pszUsername;
  567. pszUsername = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, (UNLEN + sizeof('\0')) * sizeof(WCHAR)));
  568. if (pszUsername != NULL)
  569. {
  570. GetSessionUserName(dwSessionID, pszUsername);
  571. if (LoadString(hDllInstance,
  572. IDS_RECONNECT_FAILURE,
  573. pszCaption,
  574. BUFFER_SIZE) != 0)
  575. {
  576. wsprintf(pszText, pszCaption, pszUsername);
  577. if (LoadString(hDllInstance,
  578. IDS_GENERIC_CAPTION,
  579. pszCaption,
  580. BUFFER_SIZE) != 0)
  581. {
  582. TBOOL(_Gina_SetTimeout(s_pWlxContext, LOGON_TIMEOUT));
  583. (int)_Gina_MessageBox(s_pWlxContext,
  584. NULL,
  585. pszText,
  586. pszCaption,
  587. MB_OK | MB_ICONHAND);
  588. }
  589. }
  590. (HLOCAL)LocalFree(pszUsername);
  591. }
  592. (HLOCAL)LocalFree(pszCaption);
  593. }
  594. (HLOCAL)LocalFree(pszText);
  595. }
  596. }
  597. // --------------------------------------------------------------------------
  598. // CReturnToWelcome::EndDialog
  599. //
  600. // Arguments: hwnd = HWND of dialog.
  601. // iResult = Result to end dialog with.
  602. //
  603. // Returns: <none>
  604. //
  605. // Purpose: Ends the dialog. Marks the member variable to prevent
  606. // re-entrancy.
  607. //
  608. // History: 2001-03-04 vtan created
  609. // --------------------------------------------------------------------------
  610. void CReturnToWelcome::EndDialog (HWND hwnd, INT_PTR iResult)
  611. {
  612. _fDialogEnded = true;
  613. TBOOL(::EndDialog(hwnd, iResult));
  614. }
  615. // --------------------------------------------------------------------------
  616. // CReturnToWelcome::Handle_WM_INITDIALOG
  617. //
  618. // Arguments: hwndDialog = HWND of the dialog.
  619. //
  620. // Returns: <none>
  621. //
  622. // Purpose: Handles WM_INITDIALOG. Brings up the friendly logon screen.
  623. //
  624. // History: 2001-01-11 vtan created
  625. // --------------------------------------------------------------------------
  626. void CReturnToWelcome::Handle_WM_INITDIALOG (HWND hwndDialog)
  627. {
  628. switch (_Shell_LogonDialog_Init(hwndDialog, _fUnlock ? SHELL_LOGONDIALOG_RETURNTOWELCOME_UNLOCK : SHELL_LOGONDIALOG_RETURNTOWELCOME))
  629. {
  630. case SHELL_LOGONDIALOG_LOGON:
  631. case SHELL_LOGONDIALOG_NONE:
  632. default:
  633. {
  634. // If it's anything but external host then something went wrong.
  635. // Return MSGINA_DLG_LOCK_WORKSTATION to use the old method.
  636. EndDialog(hwndDialog, MSGINA_DLG_LOCK_WORKSTATION);
  637. break;
  638. }
  639. case SHELL_LOGONDIALOG_EXTERNALHOST:
  640. {
  641. break;
  642. }
  643. }
  644. }
  645. // --------------------------------------------------------------------------
  646. // CReturnToWelcome::Handle_WM_DESTROY
  647. //
  648. // Arguments: <none>
  649. //
  650. // Returns: <none>
  651. //
  652. // Purpose: Handles WM_DESTROY. Destroys the welcome logon screen.
  653. //
  654. // History: 2001-01-11 vtan created
  655. // --------------------------------------------------------------------------
  656. void CReturnToWelcome::Handle_WM_DESTROY (void)
  657. {
  658. _ShellReleaseLogonMutex(FALSE);
  659. _Shell_LogonDialog_Destroy();
  660. }
  661. // --------------------------------------------------------------------------
  662. // CReturnToWelcome::Handle_WM_COMMAND
  663. //
  664. // Arguments: See the platform SDK under DialogProc.
  665. //
  666. // Returns: bool
  667. //
  668. // Purpose: Handles WM_COMMAND. Handles IDOK and IDCANCEL. IDOK means a
  669. // logon request is made. IDCANCEL is special cased to take the
  670. // LPARAM and use it as a LOGONIPC_CREDENTIALS for IDOK.
  671. //
  672. // History: 2001-01-11 vtan created
  673. // --------------------------------------------------------------------------
  674. bool CReturnToWelcome::Handle_WM_COMMAND (HWND hwndDialog, WPARAM wParam, LPARAM lParam)
  675. {
  676. bool fResult;
  677. switch (wParam)
  678. {
  679. case IDOK:
  680. {
  681. bool fSuccessfulLogon;
  682. const WCHAR *pszUsername, *pszDomain, *pszPassword;
  683. // If credentials were successfully allocated then
  684. // use them. Attempt to log the user on.
  685. if (_pLogonIPCCredentials != NULL)
  686. {
  687. pszUsername = _pLogonIPCCredentials->userID.wszUsername;
  688. pszDomain = _pLogonIPCCredentials->userID.wszDomain;
  689. pszPassword = _pLogonIPCCredentials->wszPassword;
  690. fSuccessfulLogon = (CTokenInformation::LogonUser(_pLogonIPCCredentials->userID.wszUsername,
  691. _pLogonIPCCredentials->userID.wszDomain,
  692. _pLogonIPCCredentials->wszPassword,
  693. &_hToken) == ERROR_SUCCESS);
  694. }
  695. else
  696. {
  697. // Otherwise - no credentials - no logon.
  698. pszUsername = pszDomain = pszPassword = NULL;
  699. fSuccessfulLogon = false;
  700. }
  701. // Tell the logon component the result.
  702. _Shell_LogonDialog_LogonCompleted(fSuccessfulLogon ? MSGINA_DLG_SUCCESS : MSGINA_DLG_FAILURE,
  703. pszUsername,
  704. pszDomain);
  705. // And if successful then end the dialog with success code.
  706. if (fSuccessfulLogon)
  707. {
  708. EndDialog(hwndDialog, MSGINA_DLG_SUCCESS);
  709. }
  710. fResult = true;
  711. break;
  712. }
  713. case IDCANCEL:
  714. // IDCANCEL: Take the LPARAM and treat it as a LOGONIPC_CREDENTIALS struct.
  715. // Allocate memory for this and copy the structure.
  716. _pLogonIPCCredentials = static_cast<LOGONIPC_CREDENTIALS*>(LocalAlloc(LMEM_FIXED, sizeof(LOGONIPC_CREDENTIALS)));
  717. if ((_pLogonIPCCredentials != NULL) && (lParam != NULL))
  718. {
  719. *_pLogonIPCCredentials = *reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam);
  720. }
  721. fResult = true;
  722. break;
  723. default:
  724. fResult = false;
  725. break;
  726. }
  727. return(fResult);
  728. }
  729. // --------------------------------------------------------------------------
  730. // CReturnToWelcome::CB_DialogProc
  731. //
  732. // Arguments: See the platform SDK under DialogProc.
  733. //
  734. // Returns: INT_PTR
  735. //
  736. // Purpose: DialogProc for the return to welcome stub dialog. This handles
  737. // WM_INITDIALOG, WM_DESTROY, WM_COMMAND and WLX_WM_SAS.
  738. // WM_COMMAND is a request from the logon host. WLX_WM_SAS is a
  739. // SAS from the logon process.
  740. //
  741. // History: 2001-01-11 vtan created
  742. // --------------------------------------------------------------------------
  743. INT_PTR CReturnToWelcome::CB_DialogProc (HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
  744. {
  745. INT_PTR iResult;
  746. CReturnToWelcome *pThis;
  747. pThis = reinterpret_cast<CReturnToWelcome*>(GetWindowLongPtr(hwndDialog, GWLP_USERDATA));
  748. switch (uMsg)
  749. {
  750. case WM_INITDIALOG:
  751. pThis = reinterpret_cast<CReturnToWelcome*>(lParam);
  752. (LONG_PTR)SetWindowLongPtr(hwndDialog, GWLP_USERDATA, lParam);
  753. pThis->Handle_WM_INITDIALOG(hwndDialog);
  754. iResult = FALSE;
  755. break;
  756. case WM_DESTROY:
  757. pThis->Handle_WM_DESTROY();
  758. (LONG_PTR)SetWindowLongPtr(hwndDialog, GWLP_USERDATA, 0);
  759. iResult = TRUE;
  760. break;
  761. case WM_COMMAND:
  762. iResult = pThis->Handle_WM_COMMAND(hwndDialog, wParam, lParam);
  763. break;
  764. case WLX_WM_SAS:
  765. (BOOL)_Shell_LogonDialog_DlgProc(hwndDialog, uMsg, wParam, lParam);
  766. // If the SAS type is authenticated then end the return to welcome
  767. // dialog and return to the caller MSGINA_DLG_SWITCH_CONSOLE.
  768. if (wParam == WLX_SAS_TYPE_AUTHENTICATED)
  769. {
  770. pThis->EndDialog(hwndDialog, MSGINA_DLG_SWITCH_CONSOLE);
  771. }
  772. iResult = ((wParam != WLX_SAS_TYPE_TIMEOUT) && (wParam != WLX_SAS_TYPE_SCRNSVR_TIMEOUT));
  773. break;
  774. default:
  775. if ((pThis != NULL) && !pThis->_fDialogEnded && !CSystemSettings::IsActiveConsoleSession())
  776. {
  777. pThis->EndDialog(hwndDialog, MSGINA_DLG_SWITCH_CONSOLE);
  778. iResult = TRUE;
  779. }
  780. else
  781. {
  782. iResult = _Shell_LogonDialog_DlgProc(hwndDialog, uMsg, wParam, lParam);
  783. }
  784. break;
  785. }
  786. return(iResult);
  787. }
  788. // --------------------------------------------------------------------------
  789. // CReturnToWelcome::RegisterWaitForRequest
  790. //
  791. // Arguments: <none>
  792. //
  793. // Returns: NTSTATUS
  794. //
  795. // Purpose: Register a wait for the named event being signaled.
  796. //
  797. // History: 2001-01-11 vtan created
  798. // --------------------------------------------------------------------------
  799. NTSTATUS CReturnToWelcome::RegisterWaitForRequest (void)
  800. {
  801. NTSTATUS status;
  802. if (s_hEventRequest != NULL)
  803. {
  804. ASSERTMSG(s_hWait == NULL, "Non NULL wait in CReturnToWelcome::RegisterWaitForRequest");
  805. if (RegisterWaitForSingleObject(&s_hWait,
  806. s_hEventRequest,
  807. CB_Request,
  808. NULL,
  809. INFINITE,
  810. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE) != FALSE)
  811. {
  812. status = STATUS_SUCCESS;
  813. }
  814. else
  815. {
  816. status = CStatusCode::StatusCodeOfLastError();
  817. }
  818. }
  819. else
  820. {
  821. status = STATUS_INVALID_PARAMETER;
  822. }
  823. return(status);
  824. }
  825. // --------------------------------------------------------------------------
  826. // CReturnToWelcome::CB_Request
  827. //
  828. // Arguments: pParameter = User parameter.
  829. // TimerOrWaitFired = Timer or wait fired.
  830. //
  831. // Returns: <none>
  832. //
  833. // Purpose: Callback invoked when ShellSwitchUser signals the named event.
  834. //
  835. // History: 2001-01-11 vtan created
  836. // --------------------------------------------------------------------------
  837. void CALLBACK CReturnToWelcome::CB_Request (void *pParameter, BOOLEAN TimerOrWaitFired)
  838. {
  839. UNREFERENCED_PARAMETER(pParameter);
  840. UNREFERENCED_PARAMETER(TimerOrWaitFired);
  841. HANDLE hWait;
  842. // Unregister the wait if we can grab the wait.
  843. hWait = InterlockedExchangePointer(&s_hWait, NULL);
  844. if (hWait != NULL)
  845. {
  846. (BOOL)UnregisterWait(hWait);
  847. }
  848. // Send the SAS type WLX_SAS_TYPE_SWITCHUSER only if the workstation
  849. // is the active console session. This API won't be called on PTS.
  850. if (CSystemSettings::IsActiveConsoleSession() && CSystemSettings::IsFriendlyUIActive())
  851. {
  852. // Reset the shown event. When CReturnToWelcome::Show has shown the
  853. // dialog it will set this event which will allow us to re-register
  854. // a wait on the switch user event. This prevents multiple SAS events
  855. // of type WLX_SAS_TYPE_SWITCHUSER being posted to the SAS window.
  856. TBOOL(ResetEvent(s_hEventShown));
  857. _Gina_SasNotify(s_pWlxContext, WLX_SAS_TYPE_SWITCHUSER);
  858. (DWORD)WaitForSingleObject(s_hEventShown, INFINITE);
  859. }
  860. // Reset the event.
  861. TBOOL(ResetEvent(s_hEventRequest));
  862. // Reregister the wait.
  863. TSTATUS(RegisterWaitForRequest());
  864. }