Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1060 lines
35 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: CInteractiveLogon.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // File that implements encapsulation of interactive logon information.
  7. //
  8. // History: 2000-12-07 vtan created
  9. // --------------------------------------------------------------------------
  10. #include "priv.h"
  11. #include "CInteractiveLogon.h"
  12. #include <winsta.h>
  13. #include "GinaIPC.h"
  14. #include "TokenInformation.h"
  15. #include "UIHostIPC.h"
  16. const TCHAR CInteractiveLogon::s_szEventReplyName[] = TEXT("shgina: InteractiveLogonRequestReply");
  17. const TCHAR CInteractiveLogon::s_szEventSignalName[] = TEXT("shgina: InteractiveLogonRequestSignal");
  18. const TCHAR CInteractiveLogon::s_szSectionName[] = TEXT("shgina: InteractiveLogonRequestSection");
  19. // --------------------------------------------------------------------------
  20. // CInteractiveLogon::CRequestData::CRequestData
  21. //
  22. // Arguments: <none>
  23. //
  24. // Returns: <none>
  25. //
  26. // Purpose: Constructor for CRequestData.
  27. //
  28. // History: 2000-12-08 vtan created
  29. // --------------------------------------------------------------------------
  30. CInteractiveLogon::CRequestData::CRequestData (void)
  31. {
  32. }
  33. // --------------------------------------------------------------------------
  34. // CInteractiveLogon::CRequestData::~CRequestData
  35. //
  36. // Arguments: <none>
  37. //
  38. // Returns: <none>
  39. //
  40. // Purpose: Destructor for CRequestData.
  41. //
  42. // History: 2000-12-08 vtan created
  43. // --------------------------------------------------------------------------
  44. CInteractiveLogon::CRequestData::~CRequestData (void)
  45. {
  46. }
  47. // --------------------------------------------------------------------------
  48. // CInteractiveLogon::CRequestData::Set
  49. //
  50. // Arguments: pszUsername = Username.
  51. // pszDomain = Domain.
  52. // pszPassword = Password.
  53. //
  54. // Returns: <none>
  55. //
  56. // Purpose: Sets the information into the section object. Makes the data
  57. // valid by signing it with a 4-byte signature.
  58. //
  59. // History: 2000-12-07 vtan created
  60. // --------------------------------------------------------------------------
  61. void CInteractiveLogon::CRequestData::Set (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword)
  62. {
  63. UNICODE_STRING passwordString;
  64. _ulMagicNumber = MAGIC_NUMBER;
  65. _dwErrorCode = ERROR_ACCESS_DENIED;
  66. lstrcpyn(_szEventReplyName, s_szEventReplyName, ARRAYSIZE(s_szEventReplyName));
  67. lstrcpyn(_szUsername, pszUsername, ARRAYSIZE(_szUsername));
  68. lstrcpyn(_szDomain, pszDomain, ARRAYSIZE(_szDomain));
  69. lstrcpyn(_szPassword, pszPassword, ARRAYSIZE(_szPassword));
  70. ZeroMemory(pszPassword, (lstrlen(pszPassword) + sizeof('\0')) * sizeof(WCHAR));
  71. _iPasswordLength = lstrlen(_szPassword);
  72. if (_iPasswordLength > 127)
  73. {
  74. _iPasswordLength = 127;
  75. }
  76. _szPassword[_iPasswordLength] = L'\0';
  77. RtlInitUnicodeString(&passwordString, _szPassword);
  78. _ucSeed = 0;
  79. RtlRunEncodeUnicodeString(&_ucSeed, &passwordString);
  80. }
  81. // --------------------------------------------------------------------------
  82. // CInteractiveLogon::CRequestData::Get
  83. //
  84. // Arguments: pszUsername = Username (returned).
  85. // pszDomain = Domain (returned).
  86. // pszPassword = Password (clear-text) returned.
  87. //
  88. // Returns: DWORD
  89. //
  90. // Purpose: Extracts the information transmitted in the section across
  91. // sessions in the receiving process' context. Checks the
  92. // signature written by Set.
  93. //
  94. // History: 2000-12-07 vtan created
  95. // --------------------------------------------------------------------------
  96. DWORD CInteractiveLogon::CRequestData::Get (WCHAR *pszUsername, WCHAR *pszDomain, WCHAR *pszPassword) const
  97. {
  98. DWORD dwErrorCode;
  99. if (_ulMagicNumber == MAGIC_NUMBER)
  100. {
  101. UNICODE_STRING passwordString;
  102. lstrcpy(pszUsername, _szUsername);
  103. lstrcpy(pszDomain, _szDomain);
  104. CopyMemory(pszPassword, _szPassword, (PWLEN + sizeof('\0')) * sizeof(WCHAR));
  105. passwordString.Length = (PWLEN * sizeof(WCHAR));
  106. passwordString.MaximumLength = (PWLEN + sizeof('\0')) * sizeof(WCHAR);
  107. passwordString.Buffer = pszPassword;
  108. RtlRunDecodeUnicodeString(_ucSeed, &passwordString);
  109. pszPassword[_iPasswordLength] = L'\0';
  110. dwErrorCode = ERROR_SUCCESS;
  111. }
  112. else
  113. {
  114. dwErrorCode = ERROR_INVALID_PARAMETER;
  115. }
  116. return(dwErrorCode);
  117. }
  118. // --------------------------------------------------------------------------
  119. // CInteractiveLogon::CRequestData::SetErrorCode
  120. //
  121. // Arguments: dwErrorCode = Error code to set.
  122. //
  123. // Returns: DWORD
  124. //
  125. // Purpose: Sets the error code into the section.
  126. //
  127. // History: 2000-12-08 vtan created
  128. // --------------------------------------------------------------------------
  129. void CInteractiveLogon::CRequestData::SetErrorCode (DWORD dwErrorCode)
  130. {
  131. _dwErrorCode = dwErrorCode;
  132. }
  133. // --------------------------------------------------------------------------
  134. // CInteractiveLogon::CRequestData::GetErrorCode
  135. //
  136. // Arguments: <none>
  137. //
  138. // Returns: DWORD
  139. //
  140. // Purpose: Returns the error code from the section.
  141. //
  142. // History: 2000-12-08 vtan created
  143. // --------------------------------------------------------------------------
  144. DWORD CInteractiveLogon::CRequestData::GetErrorCode (void) const
  145. {
  146. return(_dwErrorCode);
  147. }
  148. // --------------------------------------------------------------------------
  149. // CInteractiveLogon::CRequestData::OpenEventReply
  150. //
  151. // Arguments: <none>
  152. //
  153. // Returns: HANDLE
  154. //
  155. // Purpose: Opens a handle to the reply event. The reply event is named
  156. // in the section object.
  157. //
  158. // History: 2000-12-08 vtan created
  159. // --------------------------------------------------------------------------
  160. HANDLE CInteractiveLogon::CRequestData::OpenEventReply (void) const
  161. {
  162. return(OpenEvent(EVENT_MODIFY_STATE, FALSE, _szEventReplyName));
  163. }
  164. // --------------------------------------------------------------------------
  165. // CInteractiveLogon::CInteractiveLogon
  166. //
  167. // Arguments: <none>
  168. //
  169. // Returns: <none>
  170. //
  171. // Purpose: Constructor for CInteractiveLogon. Create a thread to wait
  172. // on the auto-reset event signaled on an external request. This
  173. // thread is cleaned up on object destruction and also on
  174. // process termination.
  175. //
  176. // History: 2000-12-08 vtan created
  177. // --------------------------------------------------------------------------
  178. CInteractiveLogon::CInteractiveLogon (void) :
  179. _hThread(NULL),
  180. _fContinue(true),
  181. _hwndHost(NULL)
  182. {
  183. Start();
  184. }
  185. // --------------------------------------------------------------------------
  186. // CInteractiveLogon::~CInteractiveLogon
  187. //
  188. // Arguments: <none>
  189. //
  190. // Returns: <none>
  191. //
  192. // Purpose: Terminate the wait thread. Queue an APC to set the member
  193. // variable to end the termination. The wait is satisfied and
  194. // returns (WAIT_IO_COMPLETION). The loop is exited and the
  195. // thread is exited.
  196. //
  197. // History: 2000-12-08 vtan created
  198. // --------------------------------------------------------------------------
  199. CInteractiveLogon::~CInteractiveLogon (void)
  200. {
  201. Stop();
  202. }
  203. // --------------------------------------------------------------------------
  204. // CInteractiveLogon::Start
  205. //
  206. // Arguments: <none>
  207. //
  208. // Returns: <none>
  209. //
  210. // Purpose: Create the thread that listens on interactive logon requests.
  211. //
  212. // History: 2001-04-06 vtan created
  213. // --------------------------------------------------------------------------
  214. void CInteractiveLogon::Start (void)
  215. {
  216. if (_hThread == NULL)
  217. {
  218. DWORD dwThreadID;
  219. _hThread = CreateThread(NULL,
  220. 0,
  221. CB_ThreadProc,
  222. this,
  223. 0,
  224. &dwThreadID);
  225. }
  226. }
  227. // --------------------------------------------------------------------------
  228. // CInteractiveLogon::Stop
  229. //
  230. // Arguments: <none>
  231. //
  232. // Returns: <none>
  233. //
  234. // Purpose: Stop the thread that listens on interactive logon requests.
  235. //
  236. // History: 2001-04-06 vtan created
  237. // --------------------------------------------------------------------------
  238. void CInteractiveLogon::Stop (void)
  239. {
  240. HANDLE hThread;
  241. hThread = InterlockedExchangePointer(&_hThread, NULL);
  242. if (hThread != NULL)
  243. {
  244. if (QueueUserAPC(CB_APCProc, hThread, reinterpret_cast<ULONG_PTR>(this)) != FALSE)
  245. {
  246. (DWORD)WaitForSingleObject(hThread, INFINITE);
  247. }
  248. TBOOL(CloseHandle(hThread));
  249. }
  250. }
  251. // --------------------------------------------------------------------------
  252. // CInteractiveLogon::SetHostWindow
  253. //
  254. // Arguments: hwndHost = HWND of the actual UI host.
  255. //
  256. // Returns: <none>
  257. //
  258. // Purpose: Sets the HWND into the member variable so that the message
  259. // can be sent directly to the UI host rather than the status
  260. // host which is a go-between.
  261. //
  262. // History: 2000-12-08 vtan created
  263. // --------------------------------------------------------------------------
  264. void CInteractiveLogon::SetHostWindow (HWND hwndHost)
  265. {
  266. _hwndHost = hwndHost;
  267. }
  268. // --------------------------------------------------------------------------
  269. // CInteractiveLogon::Initiate
  270. //
  271. // Arguments: pszUsername = User name.
  272. // pszDomain = Domain.
  273. // pszPassword = Password.
  274. // dwTimeout = Timeout value.
  275. //
  276. // Returns: DWORD
  277. //
  278. // Purpose: External entry point implementing interactive logon requests.
  279. // This function checks for privileges and mutexes and events
  280. // and does the right thing.
  281. //
  282. // History: 2001-04-06 vtan created
  283. // --------------------------------------------------------------------------
  284. DWORD CInteractiveLogon::Initiate (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword, DWORD dwTimeout)
  285. {
  286. DWORD dwErrorCode;
  287. dwErrorCode = CheckInteractiveLogonAllowed(dwTimeout);
  288. if (ERROR_SUCCESS == dwErrorCode)
  289. {
  290. HANDLE hToken;
  291. // First authenticate the user with the given credentials for an
  292. // interactive logon. Go no further unless that's valid.
  293. dwErrorCode = CTokenInformation::LogonUser(pszUsername,
  294. pszDomain,
  295. pszPassword,
  296. &hToken);
  297. if (ERROR_SUCCESS == dwErrorCode)
  298. {
  299. HANDLE hMutex;
  300. hMutex = OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, SZ_INTERACTIVE_LOGON_REQUEST_MUTEX_NAME);
  301. if (hMutex != NULL)
  302. {
  303. dwErrorCode = WaitForSingleObject(hMutex, dwTimeout);
  304. if (WAIT_OBJECT_0 == dwErrorCode)
  305. {
  306. DWORD dwSessionID, dwUserSessionID;
  307. HANDLE hEvent;
  308. // User is authenticated correctly. There are several cases
  309. // that need to be handled.
  310. dwSessionID = USER_SHARED_DATA->ActiveConsoleId;
  311. // Determine if the session has the welcome screen displayed
  312. // by opening the named signal event for the session.
  313. hEvent = OpenSessionNamedSignalEvent(dwSessionID);
  314. if (hEvent != NULL)
  315. {
  316. TBOOL(CloseHandle(hEvent));
  317. dwErrorCode = SendRequest(pszUsername, pszDomain, pszPassword);
  318. }
  319. else
  320. {
  321. // Do whatever needs to be done to log the user on.
  322. if (FoundUserSessionID(hToken, &dwUserSessionID))
  323. {
  324. if (dwUserSessionID == dwSessionID)
  325. {
  326. // User is the active console session. No further work needs
  327. // to be done. Return success.
  328. dwErrorCode = ERROR_SUCCESS;
  329. }
  330. else
  331. {
  332. // User is disconnected. Reconnect back to the user session.
  333. // If that fails then return the error code back.
  334. if (WinStationConnect(SERVERNAME_CURRENT,
  335. dwUserSessionID,
  336. USER_SHARED_DATA->ActiveConsoleId,
  337. L"",
  338. TRUE) != FALSE)
  339. {
  340. dwErrorCode = ERROR_SUCCESS;
  341. }
  342. else
  343. {
  344. dwErrorCode = GetLastError();
  345. }
  346. }
  347. }
  348. else
  349. {
  350. HANDLE hEvent;
  351. hEvent = CreateEvent(NULL, TRUE, FALSE, SZ_INTERACTIVE_LOGON_REPLY_EVENT_NAME);
  352. if (hEvent != NULL)
  353. {
  354. // User has no session. If at the welcome screen then send the
  355. // request to the welcome screen. Otherwise disconnect the
  356. // current session and use a new session to log the user on.
  357. dwErrorCode = ShellStartCredentialServer(pszUsername, pszDomain, pszPassword, dwTimeout);
  358. if (ERROR_SUCCESS == dwErrorCode)
  359. {
  360. dwErrorCode = WaitForSingleObject(hEvent, dwTimeout);
  361. }
  362. TBOOL(CloseHandle(hEvent));
  363. }
  364. else
  365. {
  366. dwErrorCode = GetLastError();
  367. }
  368. }
  369. }
  370. TBOOL(ReleaseMutex(hMutex));
  371. }
  372. TBOOL(CloseHandle(hMutex));
  373. }
  374. TBOOL(CloseHandle(hToken));
  375. }
  376. }
  377. return(dwErrorCode);
  378. }
  379. // --------------------------------------------------------------------------
  380. // CInteractiveLogon::CheckInteractiveLogonAllowed
  381. //
  382. // Arguments: dwTimeout = Timeout value.
  383. //
  384. // Returns: DWORD
  385. //
  386. // Purpose: Check whether the interactive logon request is allowed. To
  387. // make this call:
  388. //
  389. // 1. You must have SE_TCB_PRIVILEGE.
  390. // 2. There must be an active console session ID that's valid.
  391. // 3. The machine must not be shutting down.
  392. // 4. The logon mutex must be available.
  393. //
  394. // History: 2001-04-06 vtan created
  395. // --------------------------------------------------------------------------
  396. DWORD CInteractiveLogon::CheckInteractiveLogonAllowed (DWORD dwTimeout)
  397. {
  398. DWORD dwErrorCode;
  399. // 1. Check for trusted call (SE_TCB_PRIVILEGE).
  400. if (SHTestTokenPrivilege(NULL, SE_TCB_NAME) != FALSE)
  401. {
  402. // 2. Check for active console session.
  403. if (USER_SHARED_DATA->ActiveConsoleId != static_cast<DWORD>(-1))
  404. {
  405. // 3. Check for machine shutdown.
  406. dwErrorCode = CheckShutdown();
  407. if (ERROR_SUCCESS == dwErrorCode)
  408. {
  409. // 4. Check for mutex availability.
  410. dwErrorCode = CheckMutex(dwTimeout);
  411. }
  412. }
  413. else
  414. {
  415. dwErrorCode = ERROR_NOT_READY;
  416. }
  417. }
  418. else
  419. {
  420. dwErrorCode = ERROR_PRIVILEGE_NOT_HELD;
  421. }
  422. return(dwErrorCode);
  423. }
  424. // --------------------------------------------------------------------------
  425. // CInteractiveLogon::CheckShutdown
  426. //
  427. // Arguments: <none>
  428. //
  429. // Returns: DWORD
  430. //
  431. // Purpose: Returns an error code indicating if the machine is shutting
  432. // down or not. If the event cannot be opened then the request
  433. // is rejected.
  434. //
  435. // History: 2001-04-06 vtan created
  436. // --------------------------------------------------------------------------
  437. DWORD CInteractiveLogon::CheckShutdown (void)
  438. {
  439. DWORD dwErrorCode;
  440. HANDLE hEvent;
  441. hEvent = OpenEvent(SYNCHRONIZE, FALSE, SZ_SHUT_DOWN_EVENT_NAME);
  442. if (hEvent != NULL)
  443. {
  444. if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0))
  445. {
  446. dwErrorCode = ERROR_SHUTDOWN_IN_PROGRESS;
  447. }
  448. else
  449. {
  450. dwErrorCode = ERROR_SUCCESS;
  451. }
  452. TBOOL(CloseHandle(hEvent));
  453. }
  454. else
  455. {
  456. dwErrorCode = GetLastError();
  457. }
  458. return(dwErrorCode);
  459. }
  460. // --------------------------------------------------------------------------
  461. // CInteractiveLogon::CheckMutex
  462. //
  463. // Arguments: dwTimeout = Timeout value.
  464. //
  465. // Returns: DWORD
  466. //
  467. // Purpose: Attempts to grab the logon mutex. This ensures that the state
  468. // of winlogon is known and it's not busy processing a request.
  469. //
  470. // History: 2001-04-06 vtan created
  471. // --------------------------------------------------------------------------
  472. DWORD CInteractiveLogon::CheckMutex (DWORD dwTimeout)
  473. {
  474. DWORD dwErrorCode;
  475. HANDLE hMutex;
  476. hMutex = OpenMutex(SYNCHRONIZE, FALSE, SZ_INTERACTIVE_LOGON_MUTEX_NAME);
  477. if (hMutex != NULL)
  478. {
  479. dwErrorCode = WaitForSingleObject(hMutex, dwTimeout);
  480. if ((WAIT_OBJECT_0 == dwErrorCode) || (WAIT_ABANDONED == dwErrorCode))
  481. {
  482. TBOOL(ReleaseMutex(hMutex));
  483. dwErrorCode = ERROR_SUCCESS;
  484. }
  485. }
  486. else
  487. {
  488. dwErrorCode = GetLastError();
  489. }
  490. return(dwErrorCode);
  491. }
  492. // --------------------------------------------------------------------------
  493. // CInteractiveLogon::FoundUserSessionID
  494. //
  495. // Arguments: hToken = Token of user session to find.
  496. // pdwSessionID = Returned session ID.
  497. //
  498. // Returns: bool
  499. //
  500. // Purpose: Looks for a user session based on a given token. The match
  501. // is made by user SID.
  502. //
  503. // History: 2001-04-06 vtan created
  504. // --------------------------------------------------------------------------
  505. bool CInteractiveLogon::FoundUserSessionID (HANDLE hToken, DWORD *pdwSessionID)
  506. {
  507. bool fResult;
  508. PLOGONID pLogonIDs;
  509. ULONG ulEntries;
  510. fResult = false;
  511. if (WinStationEnumerate(SERVERNAME_CURRENT, &pLogonIDs, &ulEntries) != FALSE)
  512. {
  513. ULONG ulIndex;
  514. PLOGONID pLogonID;
  515. for (ulIndex = 0, pLogonID = pLogonIDs; !fResult && (ulIndex < ulEntries); ++ulIndex, ++pLogonID)
  516. {
  517. if ((pLogonID->State == State_Active) || (pLogonID->State == State_Disconnected))
  518. {
  519. ULONG ulReturnLength;
  520. WINSTATIONUSERTOKEN winStationUserToken;
  521. winStationUserToken.ProcessId = ULongToHandle(GetCurrentProcessId());
  522. winStationUserToken.ThreadId = ULongToHandle(GetCurrentThreadId());
  523. winStationUserToken.UserToken = NULL;
  524. if (WinStationQueryInformation(SERVERNAME_CURRENT,
  525. pLogonID->SessionId,
  526. WinStationUserToken,
  527. &winStationUserToken,
  528. sizeof(winStationUserToken),
  529. &ulReturnLength) != FALSE)
  530. {
  531. fResult = CTokenInformation::IsSameUser(hToken, winStationUserToken.UserToken);
  532. if (fResult)
  533. {
  534. *pdwSessionID = pLogonID->SessionId;
  535. }
  536. TBOOL(CloseHandle(winStationUserToken.UserToken));
  537. }
  538. }
  539. }
  540. // Free any resources used.
  541. (BOOLEAN)WinStationFreeMemory(pLogonIDs);
  542. }
  543. return(fResult);
  544. }
  545. // --------------------------------------------------------------------------
  546. // CInteractiveLogon::SendRequest
  547. //
  548. // Arguments: pszUsername = Username.
  549. // pszDomain = Domain.
  550. // pszPassword = Password. This string must be writable.
  551. //
  552. // Returns: DWORD
  553. //
  554. // Purpose: This function knows how to transmit the interactive logon
  555. // request from (presumably) session 0 to whatever session is
  556. // the active console session ID.
  557. //
  558. // pszUsername must be UNLEN + sizeof('\0') characters.
  559. // pszDomain must be DNLEN + sizeof('\0') characters.
  560. // pszPassword must be PWLEN + sizeof('\0') characters.
  561. //
  562. // pszPassword must be writable. The password is copied and
  563. // encoded and erased from the source buffer.
  564. //
  565. // History: 2000-12-07 vtan created
  566. // --------------------------------------------------------------------------
  567. DWORD CInteractiveLogon::SendRequest (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword)
  568. {
  569. DWORD dwErrorCode, dwActiveConsoleID;
  570. HANDLE hEventReply;
  571. dwErrorCode = ERROR_ACCESS_DENIED;
  572. // First get the active console session ID.
  573. dwActiveConsoleID = USER_SHARED_DATA->ActiveConsoleId;
  574. // Create a named event in that session named object space.
  575. hEventReply = CreateSessionNamedReplyEvent(dwActiveConsoleID);
  576. if (hEventReply != NULL)
  577. {
  578. HANDLE hEventSignal;
  579. hEventSignal = OpenSessionNamedSignalEvent(dwActiveConsoleID);
  580. if (hEventSignal != NULL)
  581. {
  582. HANDLE hSection;
  583. // Create a named section that the UI host will open. This code
  584. // is executed in the service context so it's always on session 0.
  585. hSection = CreateSessionNamedSection(dwActiveConsoleID);
  586. if (hSection != NULL)
  587. {
  588. void *pV;
  589. // Map the section into this process address space so we can put
  590. // stuff it in.
  591. pV = MapViewOfFile(hSection,
  592. FILE_MAP_WRITE,
  593. 0,
  594. 0,
  595. 0);
  596. if (pV != NULL)
  597. {
  598. __try
  599. {
  600. DWORD dwWaitResult;
  601. CRequestData *pRequestData;
  602. // Fill the section data with the information given.
  603. pRequestData = static_cast<CRequestData*>(pV);
  604. pRequestData->Set(pszUsername, pszDomain, pszPassword);
  605. // Wake up the waiting thread in the UI host.
  606. TBOOL(SetEvent(hEventSignal));
  607. // Wait 15 seconds for a reply the UI host.
  608. dwWaitResult = WaitForSingleObject(hEventReply, 15000);
  609. // Return an error code accordingly.
  610. if (WAIT_OBJECT_0 == dwWaitResult)
  611. {
  612. dwErrorCode = pRequestData->GetErrorCode();
  613. }
  614. else
  615. {
  616. dwErrorCode = dwWaitResult;
  617. }
  618. }
  619. __except (EXCEPTION_EXECUTE_HANDLER)
  620. {
  621. dwErrorCode = ERROR_OUTOFMEMORY;
  622. }
  623. TBOOL(UnmapViewOfFile(pV));
  624. }
  625. TBOOL(CloseHandle(hSection));
  626. }
  627. TBOOL(CloseHandle(hEventSignal));
  628. }
  629. TBOOL(CloseHandle(hEventReply));
  630. }
  631. return(dwErrorCode);
  632. }
  633. // --------------------------------------------------------------------------
  634. // CInteractiveLogon::FormulateObjectBasePath
  635. //
  636. // Arguments: dwSessionID = Session ID of the named object space.
  637. // pszObjectPath = Buffer to receive path.
  638. //
  639. // Returns: <none>
  640. //
  641. // Purpose: Creates the correct path to the named object space for the
  642. // given session ID.
  643. //
  644. // History: 2000-12-08 vtan created
  645. // --------------------------------------------------------------------------
  646. void CInteractiveLogon::FormulateObjectBasePath (DWORD dwSessionID, WCHAR *pszObjectPath)
  647. {
  648. if (dwSessionID == 0)
  649. {
  650. (WCHAR*)lstrcpyW(pszObjectPath, L"\\BaseNamedObjects\\");
  651. }
  652. else
  653. {
  654. wsprintfW(pszObjectPath, L"\\Sessions\\%d\\BaseNamedObjects\\", dwSessionID);
  655. }
  656. }
  657. // --------------------------------------------------------------------------
  658. // CInteractiveLogon::CreateSessionNamedReplyEvent
  659. //
  660. // Arguments: dwSessionID = Session ID.
  661. //
  662. // Returns: HANDLE
  663. //
  664. // Purpose: Creates the named reply event in the target session ID.
  665. //
  666. // History: 2000-12-08 vtan created
  667. // --------------------------------------------------------------------------
  668. HANDLE CInteractiveLogon::CreateSessionNamedReplyEvent (DWORD dwSessionID)
  669. {
  670. NTSTATUS status;
  671. HANDLE hEvent;
  672. OBJECT_ATTRIBUTES objectAttributes;
  673. UNICODE_STRING eventName;
  674. WCHAR szEventName[128];
  675. FormulateObjectBasePath(dwSessionID, szEventName);
  676. (WCHAR*)lstrcatW(szEventName, s_szEventReplyName);
  677. RtlInitUnicodeString(&eventName, szEventName);
  678. InitializeObjectAttributes(&objectAttributes,
  679. &eventName,
  680. 0,
  681. NULL,
  682. NULL);
  683. status = NtCreateEvent(&hEvent,
  684. EVENT_ALL_ACCESS,
  685. &objectAttributes,
  686. SynchronizationEvent,
  687. FALSE);
  688. if (!NT_SUCCESS(status))
  689. {
  690. hEvent = NULL;
  691. }
  692. return(hEvent);
  693. }
  694. // --------------------------------------------------------------------------
  695. // CInteractiveLogon::OpenSessionNamedSignalEvent
  696. //
  697. // Arguments: dwSessionID = Session ID.
  698. //
  699. // Returns: HANDLE
  700. //
  701. // Purpose: Opens the named signal event in the target session ID.
  702. //
  703. // History: 2000-12-08 vtan created
  704. // --------------------------------------------------------------------------
  705. HANDLE CInteractiveLogon::OpenSessionNamedSignalEvent (DWORD dwSessionID)
  706. {
  707. NTSTATUS status;
  708. HANDLE hEvent;
  709. OBJECT_ATTRIBUTES objectAttributes;
  710. UNICODE_STRING eventName;
  711. WCHAR szEventName[128];
  712. FormulateObjectBasePath(dwSessionID, szEventName);
  713. (WCHAR*)lstrcatW(szEventName, s_szEventSignalName);
  714. RtlInitUnicodeString(&eventName, szEventName);
  715. InitializeObjectAttributes(&objectAttributes,
  716. &eventName,
  717. 0,
  718. NULL,
  719. NULL);
  720. status = NtOpenEvent(&hEvent,
  721. EVENT_MODIFY_STATE,
  722. &objectAttributes);
  723. if (!NT_SUCCESS(status))
  724. {
  725. hEvent = NULL;
  726. }
  727. return(hEvent);
  728. }
  729. // --------------------------------------------------------------------------
  730. // CInteractiveLogon::CreateSessionNamedSection
  731. //
  732. // Arguments: dwSessionID = Session ID.
  733. //
  734. // Returns: HANDLE
  735. //
  736. // Purpose: Creates a named section object in the target session ID.
  737. //
  738. // History: 2000-12-08 vtan created
  739. // --------------------------------------------------------------------------
  740. HANDLE CInteractiveLogon::CreateSessionNamedSection (DWORD dwSessionID)
  741. {
  742. NTSTATUS status;
  743. HANDLE hSection;
  744. OBJECT_ATTRIBUTES objectAttributes;
  745. UNICODE_STRING sectionName;
  746. LARGE_INTEGER sectionSize;
  747. WCHAR szSectionName[128];
  748. FormulateObjectBasePath(dwSessionID, szSectionName);
  749. (WCHAR*)lstrcatW(szSectionName, s_szSectionName);
  750. RtlInitUnicodeString(&sectionName, szSectionName);
  751. InitializeObjectAttributes(&objectAttributes,
  752. &sectionName,
  753. 0,
  754. NULL,
  755. NULL);
  756. sectionSize.LowPart = sizeof(CRequestData);
  757. sectionSize.HighPart = 0;
  758. status = NtCreateSection(&hSection,
  759. STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ,
  760. &objectAttributes,
  761. &sectionSize,
  762. PAGE_READWRITE,
  763. SEC_COMMIT,
  764. NULL);
  765. if (!NT_SUCCESS(status))
  766. {
  767. hSection = NULL;
  768. }
  769. return(hSection);
  770. }
  771. // --------------------------------------------------------------------------
  772. // CInteractiveLogon::WaitForInteractiveLogonRequest
  773. //
  774. // Arguments: <none>
  775. //
  776. // Returns: <none>
  777. //
  778. // Purpose: Thread that executes in the UI host context of the receiving
  779. // session. This thread waits in an alertable state for the
  780. // signal event. If the event is signaled it does work to log the
  781. // specified user on.
  782. //
  783. // History: 2000-12-08 vtan created
  784. // --------------------------------------------------------------------------
  785. void CInteractiveLogon::WaitForInteractiveLogonRequest (void)
  786. {
  787. HANDLE hEvent;
  788. hEvent = CreateEvent(NULL,
  789. FALSE,
  790. FALSE,
  791. s_szEventSignalName);
  792. if (hEvent != NULL)
  793. {
  794. DWORD dwWaitResult;
  795. while (_fContinue)
  796. {
  797. dwWaitResult = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
  798. if (WAIT_OBJECT_0 == dwWaitResult)
  799. {
  800. HANDLE hSection;
  801. hSection = OpenFileMapping(FILE_MAP_WRITE,
  802. FALSE,
  803. s_szSectionName);
  804. if (hSection != NULL)
  805. {
  806. void *pV;
  807. pV = MapViewOfFile(hSection,
  808. FILE_MAP_WRITE,
  809. 0,
  810. 0,
  811. 0);
  812. if (pV != NULL)
  813. {
  814. __try
  815. {
  816. DWORD dwErrorCode;
  817. HANDLE hEventReply;
  818. CRequestData *pRequestData;
  819. INTERACTIVE_LOGON_REQUEST interactiveLogonRequest;
  820. pRequestData = static_cast<CRequestData*>(pV);
  821. hEventReply = pRequestData->OpenEventReply();
  822. if (hEventReply != NULL)
  823. {
  824. dwErrorCode = pRequestData->Get(interactiveLogonRequest.szUsername,
  825. interactiveLogonRequest.szDomain,
  826. interactiveLogonRequest.szPassword);
  827. if (ERROR_SUCCESS == dwErrorCode)
  828. {
  829. dwErrorCode = static_cast<DWORD>(SendMessage(_hwndHost, WM_UIHOSTMESSAGE, HM_INTERACTIVE_LOGON_REQUEST, reinterpret_cast<LPARAM>(&interactiveLogonRequest)));
  830. }
  831. pRequestData->SetErrorCode(dwErrorCode);
  832. TBOOL(SetEvent(hEventReply));
  833. TBOOL(CloseHandle(hEventReply));
  834. }
  835. else
  836. {
  837. dwErrorCode = GetLastError();
  838. pRequestData->SetErrorCode(dwErrorCode);
  839. }
  840. }
  841. __except (EXCEPTION_EXECUTE_HANDLER)
  842. {
  843. }
  844. TBOOL(UnmapViewOfFile(pV));
  845. }
  846. TBOOL(CloseHandle(hSection));
  847. }
  848. }
  849. else
  850. {
  851. ASSERTMSG((WAIT_FAILED == dwWaitResult) || (WAIT_IO_COMPLETION == dwWaitResult), "Unexpected result from kernel32!WaitForSingleObjectEx in CInteractiveLogon::WaitForInteractiveLogonRequest");
  852. _fContinue = false;
  853. }
  854. }
  855. TBOOL(CloseHandle(hEvent));
  856. }
  857. }
  858. // --------------------------------------------------------------------------
  859. // CInteractiveLogon::CB_ThreadProc
  860. //
  861. // Arguments: pParameter = this object.
  862. //
  863. // Returns: DWORD
  864. //
  865. // Purpose: Callback function stub to member function.
  866. //
  867. // History: 2000-12-08 vtan created
  868. // --------------------------------------------------------------------------
  869. DWORD WINAPI CInteractiveLogon::CB_ThreadProc (void *pParameter)
  870. {
  871. static_cast<CInteractiveLogon*>(pParameter)->WaitForInteractiveLogonRequest();
  872. return(0);
  873. }
  874. // --------------------------------------------------------------------------
  875. // CInteractiveLogon::CB_APCProc
  876. //
  877. // Arguments: dwParam = this object.
  878. //
  879. // Returns: <none>
  880. //
  881. // Purpose: Set object member variable to exit thread loop.
  882. //
  883. // History: 2000-12-08 vtan created
  884. // --------------------------------------------------------------------------
  885. void CALLBACK CInteractiveLogon::CB_APCProc (ULONG_PTR dwParam)
  886. {
  887. reinterpret_cast<CInteractiveLogon*>(dwParam)->_fContinue = false;
  888. }
  889. // --------------------------------------------------------------------------
  890. // ::InitiateInteractiveLogon
  891. //
  892. // Arguments: pszUsername = User name.
  893. // pszPassword = Password.
  894. // dwTimeout = Time out in milliseconds.
  895. //
  896. // Returns: BOOL
  897. //
  898. // Purpose: External entry point function exported by name to initiate
  899. // an interactive logon with specified timeout.
  900. //
  901. // History: 2001-04-10 vtan created
  902. // 2001-06-04 vtan added timeout
  903. // --------------------------------------------------------------------------
  904. EXTERN_C BOOL WINAPI InitiateInteractiveLogon (const WCHAR *pszUsername, WCHAR *pszPassword, DWORD dwTimeout)
  905. {
  906. DWORD dwErrorCode;
  907. dwErrorCode = CInteractiveLogon::Initiate(pszUsername, L"", pszPassword, dwTimeout);
  908. if (ERROR_SUCCESS != dwErrorCode)
  909. {
  910. SetLastError(dwErrorCode);
  911. }
  912. return(ERROR_SUCCESS == dwErrorCode);
  913. }