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.

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