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.

1251 lines
29 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. senslogn.cxx
  5. Abstract:
  6. This file contains the implementation of a Stub DLL to notify SENS of
  7. events generated by Winlogon.
  8. Author:
  9. Gopal Parupudi <GopalP>
  10. Notes:
  11. a. This DLL notifies the following components:
  12. o EventSystem (contact DMcCrady)
  13. o IR service (contact JRoberts)
  14. o SENS service (contact GopalP)
  15. b. This DLL also maintains tokens of the currently logged on user. This
  16. is used by COM for activation.
  17. Revision History:
  18. GopalP 12/7/1997 Start.
  19. --*/
  20. #include <common.hxx>
  21. #include <stdio.h>
  22. #include <windows.h>
  23. #include <malloc.h>
  24. #include <winwlx.h>
  25. #include <sensapip.h>
  26. #include <rpc.h>
  27. #include "mutex.hxx"
  28. #include "usertok.h"
  29. #include "senslogn.hxx"
  30. #include "onestop.cxx"
  31. //
  32. // Constants
  33. //
  34. #define NOTIFY_LCE_STARTSHELL 0x00000003
  35. #define NOTIFY_LCE_LOGOFF 0x00000004
  36. #define SENS_START_WAIT_TIMEOUT 180*1000 // 3 minutes
  37. #define NOTIFY_LCE_LOGONUSER "NotifyLogonUser"
  38. #define NOTIFY_LCE_LOGOFFUSER "NotifyLogoffUser"
  39. #define SENS_SERVICE SENS_STRING("SENS")
  40. #define EVENTSYSTEM_DLL SENS_STRING("ES.DLL")
  41. //
  42. // Globals
  43. //
  44. HANDLE ghSensStartedEvent;
  45. BOOL gbIsTokenCodeInitialized;
  46. // For GetCurrentUserToken
  47. USER_LOGON_TABLE * ActiveUserList;
  48. //
  49. // Some useful Macros
  50. //
  51. #ifdef DETAIL_DEBUG
  52. #define DUMP_INFO(_EventType_) \
  53. \
  54. PWLX_NOTIFICATION_INFO pInfo = (PWLX_NOTIFICATION_INFO) lpvParam; \
  55. \
  56. LogMessage(("------------------------------------------------------\n")); \
  57. LogMessage((SENSLOGN " Received a %s Event.\n", _EventType_)); \
  58. LogMessage((" Size - %d\n", pInfo->Size)); \
  59. LogMessage((" Flags - 0x%x\n", pInfo->Flags)); \
  60. LogMessage((" UserName - %ws\n", pInfo->UserName)); \
  61. LogMessage((" Domain - %ws\n", pInfo->Domain)); \
  62. LogMessage((" WinStation - %ws\n", pInfo->WindowStation)); \
  63. LogMessage((" hToken - 0x%x\n", pInfo->hToken)); \
  64. LogMessage((" hDesktop - 0x%x\n", pInfo->hDesktop)); \
  65. LogMessage((" pCallback - 0x%x\n", pInfo->pStatusCallback)); \
  66. LogMessage((" dwSessionId - 0x%x\n", NtCurrentPeb()->SessionId)); \
  67. LogMessage(("------------------------------------------------------\n"));
  68. #else // ! DETAIL_DEBUG
  69. #define DUMP_INFO(_EventType_)
  70. #endif // DETAIL_DEBUG
  71. #define FIRE_EVENT(_EventType_) \
  72. { \
  73. \
  74. SENS_NOTIFY_WINLOGON Data; \
  75. \
  76. Data.eType = _EventType_; \
  77. Data.Info.Size = sizeof(SENS_NOTIFY_WINLOGON); \
  78. Data.Info.Flags = ((PWLX_NOTIFICATION_INFO)lpvParam)->Flags; \
  79. Data.Info.UserName = ((PWLX_NOTIFICATION_INFO)lpvParam)->UserName; \
  80. Data.Info.Domain = ((PWLX_NOTIFICATION_INFO)lpvParam)->Domain; \
  81. Data.Info.WindowStation = ((PWLX_NOTIFICATION_INFO)lpvParam)->WindowStation; \
  82. Data.Info.hToken = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hToken); \
  83. Data.Info.hDesktop = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hDesktop); \
  84. Data.Info.dwSessionId = NtCurrentPeb()->SessionId; \
  85. \
  86. status = SensNotifyWinlogonEvent(&Data); \
  87. \
  88. if (status) {SensPrintToDebugger(SENS_DBG, (SENSLOGN "SensNotifyWinlogonEvent(0x%x) returned %d\n", _EventType_, status));} \
  89. }
  90. /*****************************************************************************
  91. *
  92. * IsRemoteSession
  93. *
  94. * On a Terminal Server: returns TRUE if current Session is the not the physical
  95. * console , FALSE if it is the console session (SessionId == 0)
  96. *
  97. * ENTRY:
  98. * nothing
  99. *
  100. * EXIT:
  101. * nothing
  102. *
  103. ****************************************************************************/
  104. BOOL
  105. IsRemoteSession(VOID)
  106. {
  107. DWORD dwSessionId;
  108. if (ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId))
  109. {
  110. return (dwSessionId != 0);
  111. }
  112. return FALSE;
  113. }
  114. DWORD WINAPI
  115. SensLogonEvent(
  116. LPVOID lpvParam
  117. )
  118. /*++
  119. Routine Description:
  120. Hook to trap the Logon Event. In addition, we do the following:
  121. a. Populate our token table with the current token.
  122. b. Initialize The token RPC interface, if necessary.
  123. Arguments:
  124. lpvParam - Winlogon notification info.
  125. Return Value:
  126. RPC status from SensNotifyWinlogonEvent()
  127. --*/
  128. {
  129. DWORD status;
  130. PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  131. DUMP_INFO("Logon");
  132. ActiveUserList->Add( pTempInfo );
  133. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGON);
  134. return status;
  135. }
  136. DWORD WINAPI
  137. SensLogoffEvent(
  138. LPVOID lpvParam
  139. )
  140. /*++
  141. Routine Description:
  142. Hook to trap the Logoff Event. We notify various components
  143. (like OneStop, EventSystem, SENS) of the Logoff event.
  144. Arguments:
  145. lpvParam - Winlogon notification info.
  146. Notes:
  147. a. The system logoff will block till this call returns. Be very
  148. careful in adding code here.
  149. Return Value:
  150. RPC status from SensNotifyWinlogonEvent()
  151. --*/
  152. {
  153. DWORD status;
  154. DWORD dwError;
  155. HRESULT hr;
  156. PWLX_NOTIFICATION_INFO pTempInfo;
  157. hr = S_OK;
  158. dwError = 0x0;
  159. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  160. LogMessage((SENSLOGN "[%d] Entered Logoff.\n", GetTickCount()));
  161. DUMP_INFO("Logoff");
  162. // Try to fire SENS Event
  163. LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
  164. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGOFF);
  165. LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(LOGOFF) succeeded.\n", GetTickCount()));
  166. // Start OneStop if necessary, except on Restart.
  167. if ( ((pTempInfo->Flags & EWX_REBOOT) == 0)
  168. && (IsAutoSyncEnabled(pTempInfo->hToken, AUTOSYNC_ON_LOGOFF)))
  169. {
  170. //
  171. // NOTE: If SENS ever becomes demandstarted on NT5, there are a couple
  172. // of things that can be done:
  173. // o Call StartSensIfNecessary() here. (OR)
  174. // o Make Sens APIs call StartSensIfNecessary().
  175. //
  176. LogMessage((SENSLOGN "[%d] Notifying OneStop...\n", GetTickCount()));
  177. hr = SensNotifyOneStop(pTempInfo->hToken, SYNC_MANAGER_LOGOFF, TRUE);
  178. LogMessage((SENSLOGN "[%d] SensNotifyOneStop() returned 0x%x\n", GetTickCount(), hr));
  179. }
  180. // Notify EventSystem
  181. LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
  182. hr = SensNotifyEventSystem(NOTIFY_LCE_LOGOFF, lpvParam);
  183. LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
  184. //
  185. // Remove token handle from the list at the end so that COM activation
  186. // works till SENS gets done with event firings.
  187. //
  188. ActiveUserList->Remove( pTempInfo );
  189. LogMessage((SENSLOGN "Removed current user's token!\n"));
  190. return status;
  191. }
  192. DWORD WINAPI
  193. SensStartupEvent(
  194. LPVOID lpvParam
  195. )
  196. /*++
  197. Routine Description:
  198. Hook to trap the Startup Event. Do some token management related
  199. initialization.
  200. Arguments:
  201. lpvParam - Winlogon notification info.
  202. Notes:
  203. a. This occurs very early in the bootup sequence. At this time,
  204. SENS service hasn't yet started up.
  205. Return Value:
  206. RPC status from SensNotifyWinlogonEvent()
  207. --*/
  208. {
  209. DWORD status;
  210. DWORD dwLastError;
  211. status = 0x0;
  212. gbIsTokenCodeInitialized = FALSE;
  213. //
  214. // Create the table of logged-in users.
  215. //
  216. ActiveUserList = new USER_LOGON_TABLE( &status );
  217. if (!ActiveUserList || status)
  218. {
  219. delete ActiveUserList;
  220. return ERROR_NOT_ENOUGH_MEMORY;
  221. }
  222. InitializeNotifyInterface();
  223. //
  224. // We are ready to use Token Code.
  225. //
  226. gbIsTokenCodeInitialized = TRUE;
  227. LogMessage((SENSLOGN "**** Token code initialized successfully ****\n"));
  228. //
  229. // Create an Event to indicate the starting of SENS.
  230. //
  231. ghSensStartedEvent = CreateEvent(
  232. NULL, // Specific Security Attributes
  233. TRUE, // Event is ManualReset
  234. FALSE, // Initial state is not Signalled
  235. SENS_STARTED_EVENT
  236. );
  237. if (ghSensStartedEvent == NULL)
  238. {
  239. dwLastError = GetLastError();
  240. LogMessage((SENSLOGN "SensStartupEvent() - CreateEvent() failed - %x.\n",
  241. dwLastError));
  242. }
  243. else
  244. {
  245. LogMessage((SENSLOGN "SensStartedEvent created successfully\n"));
  246. }
  247. DUMP_INFO("Startup");
  248. return status;
  249. }
  250. BOOLEAN
  251. InitializeNotifyInterface(
  252. void
  253. )
  254. /*++
  255. Routine Description:
  256. Initialize RPC interface for accepting calls to GetCurrentUserToken() API.
  257. Arguments:
  258. None.
  259. Return Value:
  260. TRUE, if successful
  261. FALSE, otherwise.
  262. --*/
  263. {
  264. RPC_STATUS status;
  265. if (!IsRemoteSession())
  266. {
  267. status = RpcServerRegisterIfEx(
  268. _GetUserToken_ServerIfHandle,
  269. NULL,
  270. NULL,
  271. 0,
  272. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  273. AllowLocalSystem
  274. );
  275. if (RPC_S_OK != status)
  276. {
  277. return FALSE;
  278. }
  279. }
  280. return TRUE;
  281. }
  282. DWORD WINAPI
  283. SensStartShellEvent(
  284. LPVOID lpvParam
  285. )
  286. /*++
  287. Routine Description:
  288. Hook to trap the StartShell Event. We treat this as Logon and notify
  289. various components (OneStop, SENS, EventSystem) of Logon.
  290. Arguments:
  291. lpvParam - Winlogon notification info.
  292. Notes:
  293. a. When this function is called by Winlogon, the shell has begun starting.
  294. There is no guarantee that shell has started completely and is up and
  295. running.
  296. b. We create a thread to do bulk of the work and allow the function
  297. to return.
  298. Return Value:
  299. RPC status from SensNotifyWinlogonEvent()
  300. --*/
  301. {
  302. BOOL bRetVal;
  303. DWORD status;
  304. DWORD dwLastError;
  305. PWLX_NOTIFICATION_INFO pTempInfo;
  306. PWLX_NOTIFICATION_INFO pDuplicateInfo;
  307. dwLastError = 0;
  308. bRetVal = TRUE;
  309. DUMP_INFO("StartShell");
  310. // Duplicate the parts of the notification info so we can process this
  311. // event on another thread.
  312. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  313. SIZE_T sizeUserName = wcslen(pTempInfo->UserName) + 1;
  314. SIZE_T sizeDomain = wcslen(pTempInfo->Domain) + 1;
  315. SIZE_T sizeWinsta = wcslen(pTempInfo->WindowStation) + 1;
  316. //
  317. // Allocate space for the notification block
  318. //
  319. pDuplicateInfo = new WLX_NOTIFICATION_INFO;
  320. if (pDuplicateInfo == NULL)
  321. {
  322. dwLastError = GetLastError();
  323. LogMessage((SENSLOGN "SensStartShellEvent(): new() failed - %x.\n", dwLastError));
  324. return dwLastError;
  325. }
  326. //
  327. // Copy simple types, safely initialize everything in case of failure.
  328. //
  329. pDuplicateInfo->Size = sizeof(WLX_NOTIFICATION_INFO);
  330. pDuplicateInfo->Flags = pTempInfo->Flags;
  331. pDuplicateInfo->hToken = NULL; // duplicated below, closed on error
  332. pDuplicateInfo->hDesktop = NULL; // not duplicated, unused
  333. pDuplicateInfo->pStatusCallback = NULL;
  334. // Allocate space for the string parameters.
  335. pDuplicateInfo->UserName = (PWSTR) new WCHAR[sizeUserName];
  336. pDuplicateInfo->Domain = (PWSTR) new WCHAR[sizeDomain];
  337. pDuplicateInfo->WindowStation = (PWSTR) new WCHAR[sizeWinsta];
  338. if ( (pDuplicateInfo->UserName == NULL)
  339. || (pDuplicateInfo->Domain == NULL)
  340. || (pDuplicateInfo->WindowStation == NULL))
  341. {
  342. dwLastError = GetLastError();
  343. LogMessage((SENSLOGN "SensStartShellEvent(): new() of strings failed - %x.\n", dwLastError));
  344. goto Cleanup;
  345. }
  346. //
  347. // Deep copy the parameters
  348. //
  349. StringCchCopy(pDuplicateInfo->UserName, sizeUserName, pTempInfo->UserName);
  350. StringCchCopy(pDuplicateInfo->Domain, sizeDomain, pTempInfo->Domain);
  351. StringCchCopy(pDuplicateInfo->WindowStation, sizeWinsta, pTempInfo->WindowStation);
  352. if ( !DuplicateHandle(GetCurrentProcess(),
  353. pTempInfo->hToken,
  354. GetCurrentProcess(),
  355. &pDuplicateInfo->hToken,
  356. 0, // ignored, same access flag set
  357. FALSE,
  358. DUPLICATE_SAME_ACCESS))
  359. {
  360. dwLastError = GetLastError();
  361. LogMessage((SENSLOGN "SensStartShellEvent(): failed to duplicate users token - %x\n", dwLastError));
  362. goto Cleanup;
  363. }
  364. //
  365. // Create a thread to wait on the StartShell event
  366. //
  367. bRetVal = SensQueueUserWorkItem(
  368. (LPTHREAD_START_ROUTINE) SensWaitToStartRoutine,
  369. pDuplicateInfo, // Winlogon event info
  370. SENS_LONG_ITEM // Flags
  371. );
  372. if (FALSE == bRetVal)
  373. {
  374. dwLastError = GetLastError();
  375. LogMessage((SENSLOGN "SensStartShellEvent(): SensQueueUserWorkItem() failed with %x.\n",
  376. dwLastError));
  377. }
  378. // Success - SensWaitToStartRoutine now owns pDuplicateInfo
  379. return 0;
  380. Cleanup:
  381. // All branches here occur after the parameter block is copied and initalized
  382. ASSERT(pDuplicateInfo);
  383. if (pDuplicateInfo->hToken)
  384. {
  385. CloseHandle(pDuplicateInfo->hToken);
  386. }
  387. delete pDuplicateInfo->UserName;
  388. delete pDuplicateInfo->Domain;
  389. delete pDuplicateInfo->WindowStation;
  390. delete pDuplicateInfo;
  391. return dwLastError;
  392. }
  393. DWORD WINAPI
  394. SensPostShellEvent(
  395. LPVOID lpvParam
  396. )
  397. /*++
  398. Routine Description:
  399. Hook to trap the Post Shell Event.
  400. Arguments:
  401. lpvParam - Winlogon notification info.
  402. Return Value:
  403. RPC status from SensNotifyWinlogonEvent()
  404. --*/
  405. {
  406. DWORD status;
  407. DUMP_INFO("Post Shell");
  408. FIRE_EVENT(SENS_NOTIFY_WINLOGON_POSTSHELL);
  409. return status;
  410. }
  411. DWORD WINAPI
  412. SensDisconnectEvent(
  413. LPVOID lpvParam
  414. )
  415. /*++
  416. Routine Description:
  417. Hook to trap the Session Disconnect Event.
  418. Arguments:
  419. lpvParam - Winlogon notification info.
  420. Return Value:
  421. RPC status from SensNotifyWinlogonEvent()
  422. --*/
  423. {
  424. DWORD status;
  425. DUMP_INFO("Session Disconnect");
  426. FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_DISCONNECT);
  427. return status;
  428. }
  429. DWORD WINAPI
  430. SensReconnectEvent(
  431. LPVOID lpvParam
  432. )
  433. /*++
  434. Routine Description:
  435. Hook to trap the Session Reconnect Event.
  436. Arguments:
  437. lpvParam - Winlogon notification info.
  438. Return Value:
  439. RPC status from SensNotifyWinlogonEvent()
  440. --*/
  441. {
  442. DWORD status;
  443. DUMP_INFO("Session Reconnect");
  444. FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_RECONNECT);
  445. return status;
  446. }
  447. DWORD WINAPI
  448. SensShutdownEvent(
  449. LPVOID lpvParam
  450. )
  451. /*++
  452. Routine Description:
  453. Hook to trap the Shutdown Event. Do some cleanup.
  454. Arguments:
  455. lpvParam - Winlogon notification info.
  456. Notes:
  457. a. It is guaranteed that COM activation will not work when this event
  458. is received.
  459. Return Value:
  460. RPC status from SensNotifyWinlogonEvent()
  461. --*/
  462. {
  463. DWORD status;
  464. status = ERROR_SUCCESS;
  465. DUMP_INFO("Shutdown");
  466. return status;
  467. }
  468. DWORD WINAPI
  469. SensLockEvent(
  470. LPVOID lpvParam
  471. )
  472. /*++
  473. Routine Description:
  474. Hook to trap the Display Lock Event.
  475. Arguments:
  476. lpvParam - Winlogon notification info.
  477. Return Value:
  478. RPC status from SensNotifyWinlogonEvent()
  479. --*/
  480. {
  481. DWORD status;
  482. DUMP_INFO("Display Lock");
  483. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOCK);
  484. return status;
  485. }
  486. DWORD WINAPI
  487. SensUnlockEvent(
  488. LPVOID lpvParam
  489. )
  490. /*++
  491. Routine Description:
  492. Hook to trap the Display unlock Event.
  493. Arguments:
  494. lpvParam - Winlogon notification info.
  495. Return Value:
  496. RPC status from SensNotifyWinlogonEvent()
  497. --*/
  498. {
  499. DWORD status;
  500. DUMP_INFO("Display Unlock");
  501. FIRE_EVENT(SENS_NOTIFY_WINLOGON_UNLOCK);
  502. return status;
  503. }
  504. DWORD WINAPI
  505. SensStartScreenSaverEvent(
  506. LPVOID lpvParam
  507. )
  508. /*++
  509. Routine Description:
  510. Hook to trap the ScreenSaver Start Event.
  511. Arguments:
  512. lpvParam - Winlogon notification info.
  513. Return Value:
  514. RPC status from SensNotifyWinlogonEvent()
  515. --*/
  516. {
  517. DWORD status;
  518. DUMP_INFO("StartScreenSaver");
  519. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSCREENSAVER);
  520. return status;
  521. }
  522. DWORD WINAPI
  523. SensStopScreenSaverEvent(
  524. LPVOID lpvParam
  525. )
  526. /*++
  527. Routine Description:
  528. Hook to trap the Screen Saver Stop Event.
  529. Arguments:
  530. lpvParam - Winlogon notification info.
  531. Return Value:
  532. RPC status from SensNotifyWinlogonEvent()
  533. --*/
  534. {
  535. DWORD status;
  536. DUMP_INFO("StopScreenSaver");
  537. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STOPSCREENSAVER);
  538. return status;
  539. }
  540. DWORD WINAPI
  541. SensWaitToStartRoutine(
  542. LPVOID lpvParam
  543. )
  544. /*++
  545. Routine Description:
  546. This routine implements the work item that is queued when the StartShell
  547. event is received.
  548. Arguments:
  549. lpvParam - Winlogon notification info.
  550. Return Value:
  551. ERROR_SUCCESS, always
  552. --*/
  553. {
  554. DWORD dwError;
  555. DWORD dwWaitStatus;
  556. DWORD status;
  557. HRESULT hr;
  558. PWLX_NOTIFICATION_INFO pTempInfo;
  559. dwError = ERROR_SUCCESS;
  560. dwWaitStatus = 0x0;
  561. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  562. // Give SENS a chance to start if it has not already stated.
  563. // Give up after a short time in case sens is has been set to manual start
  564. // We could check the service configuration but the thread as already been
  565. // created so we save won't very much.
  566. ASSERT(ghSensStartedEvent);
  567. dwError = WaitForSingleObject(ghSensStartedEvent, 20*1000);
  568. if (dwError != STATUS_WAIT_0)
  569. {
  570. LogMessage((SENSLOGN "[%d] Wait for sens start event timed out...\n", GetTickCount()));
  571. }
  572. // Notify EventSystem
  573. LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
  574. hr = SensNotifyEventSystem(NOTIFY_LCE_STARTSHELL, lpvParam);
  575. LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
  576. // Try to fire SENS Event
  577. LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
  578. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSHELL);
  579. LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(STARTSHELL) succeeded.\n", GetTickCount()));
  580. // Cleanup
  581. CloseHandle(pTempInfo->hToken);
  582. delete pTempInfo->UserName;
  583. delete pTempInfo->Domain;
  584. delete pTempInfo->WindowStation;
  585. delete pTempInfo;
  586. return ERROR_SUCCESS;
  587. }
  588. HRESULT
  589. SensNotifyEventSystem(
  590. DWORD dwEvent,
  591. LPVOID lpvParam
  592. )
  593. /*++
  594. Routine Description:
  595. This routine notifies EventSystem of the Logon/Logoff events.
  596. Arguments:
  597. dwEvent - Tells if the event is Logon or Logoff.
  598. lpvParam - Winlogon notification info.
  599. Notes:
  600. a. EventSystem's notify routine has been observed sometimes to take
  601. a long time causing Logoff to take longer time to complete.
  602. Return Value:
  603. HRESULT from EventSystem's Notify routine.
  604. --*/
  605. {
  606. HRESULT hr;
  607. hr = S_OK;
  608. PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO)lpvParam;
  609. //
  610. // Notify the COM+ Event System that a user has just logged on.
  611. // Per-user subscriptions will be activated.
  612. //
  613. typedef HRESULT (__stdcall *LPFN_NOTIFICATION)(HANDLE);
  614. HMODULE hDLL;
  615. LPFN_NOTIFICATION lpfnNotify = NULL;
  616. hDLL = (HMODULE) LoadLibrary(EVENTSYSTEM_DLL);
  617. if (hDLL == NULL)
  618. {
  619. hr = HRESULT_FROM_WIN32(GetLastError());
  620. }
  621. else
  622. {
  623. if (dwEvent == NOTIFY_LCE_STARTSHELL)
  624. {
  625. lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGONUSER);
  626. }
  627. else
  628. if (dwEvent == NOTIFY_LCE_LOGOFF)
  629. {
  630. lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGOFFUSER);
  631. }
  632. hr = (lpfnNotify == NULL) ? HRESULT_FROM_WIN32(GetLastError()) : (*lpfnNotify)(pTempInfo->hToken);
  633. FreeLibrary(hDLL);
  634. }
  635. return hr;
  636. }
  637. #define MAX_WINDOWSTATION_NAME_LENGTH 1000
  638. DWORD
  639. _SecpGetCurrentUserToken(
  640. handle_t Binding,
  641. wchar_t WindowStation[],
  642. unsigned long * pToken,
  643. unsigned long DesiredAccess
  644. )
  645. /*++
  646. Routine Description:
  647. RPC server manager routine. This is the only method in the GetUserToken
  648. interface.
  649. The interface registered a callback function to verify that the caller is
  650. both non-remote and is local system.
  651. Arguments:
  652. Binding - RPC server binding
  653. WindowStation - window station retrive the token from
  654. pToken - Upon return this is the handle ID of the duplicated token in the
  655. callers process
  656. DesiredAccess - Access mask passed directly to the DuplicateHandle() call.
  657. Return Value:
  658. WIN32 ERROR value or 0
  659. --*/
  660. {
  661. HANDLE LocalToken;
  662. HANDLE RemoteToken;
  663. HANDLE RemoteProcess;
  664. unsigned long ProcessId;
  665. if (FALSE == gbIsTokenCodeInitialized)
  666. {
  667. return ERROR_OUTOFMEMORY;
  668. }
  669. //
  670. // Validate arguments. The only one that can cause us harm is the window station.
  671. //
  672. if (IsBadStringPtr( WindowStation, MAX_WINDOWSTATION_NAME_LENGTH))
  673. {
  674. return ERROR_ACCESS_DENIED;
  675. }
  676. if (I_RpcBindingInqLocalClientPID(0, &ProcessId))
  677. {
  678. return ERROR_ACCESS_DENIED;
  679. }
  680. //
  681. // Clone the token into the requested process.
  682. //
  683. LocalToken = ActiveUserList->CurrentUserTokenFromWindowStation( WindowStation );
  684. if (!LocalToken)
  685. {
  686. LogMessage((SENSLOGN "GetCurrentUserToken(): User not logged on!\n"));
  687. return ERROR_NOT_LOGGED_ON;
  688. }
  689. RemoteProcess = OpenProcess(
  690. PROCESS_DUP_HANDLE,
  691. FALSE, // not inheritable
  692. ProcessId
  693. );
  694. if (!RemoteProcess)
  695. {
  696. LogMessage((SENSLOGN "GetCurrentUserToken(): OpenProcess() failed!\n"));
  697. return GetLastError();
  698. }
  699. // Only way to verify that the client process has not exited while waiting for
  700. // the response. (this is to avoid duplicating the handle into another process).
  701. //
  702. // This is done after the OpenProcess() call to keep the PID from being reused before
  703. // we could open the process.
  704. if (RPC_S_OK != RpcImpersonateClient(0))
  705. {
  706. CloseHandle(RemoteProcess);
  707. return ERROR_ACCESS_DENIED;
  708. }
  709. // We have already validated that the caller is local system in the interface callback.
  710. RpcRevertToSelf();
  711. if (!DuplicateHandle(
  712. GetCurrentProcess(),
  713. LocalToken,
  714. RemoteProcess,
  715. &RemoteToken,
  716. DesiredAccess,
  717. FALSE, // not inheritable
  718. 0 // no funny options
  719. ))
  720. {
  721. LogMessage((SENSLOGN "GetCurrentUserToken(): DuplicateHandle() failed!\n"));
  722. CloseHandle( RemoteProcess );
  723. return GetLastError();
  724. }
  725. CloseHandle( RemoteProcess );
  726. *pToken = HandleToUlong(RemoteToken);
  727. LogMessage((SENSLOGN "GetCurrentUserToken(): Succeeded. Returning 0x%x.\n", *pToken));
  728. return ERROR_SUCCESS;
  729. }
  730. BOOL
  731. USER_LOGON_TABLE::Add(
  732. WLX_NOTIFICATION_INFO * User
  733. )
  734. {
  735. USER_INFO_NODE * Entry;
  736. if (FALSE == gbIsTokenCodeInitialized)
  737. {
  738. return FALSE;
  739. }
  740. CLAIM_MUTEX Lock( Mutex );
  741. Entry = FindInactiveEntry();
  742. if (!Entry)
  743. {
  744. Entry = new USER_INFO_NODE;
  745. if (!Entry)
  746. {
  747. return FALSE;
  748. }
  749. Entry->fActive = FALSE;
  750. InsertTailList( &List, &Entry->Links );
  751. }
  752. Entry->Info.Size = sizeof(WLX_NOTIFICATION_INFO);
  753. Entry->Info.Flags = User->Flags;
  754. Entry->Info.hToken = User->hToken;
  755. SIZE_T sizeUserName = wcslen(User->UserName) + 1;
  756. SIZE_T sizeDomain = wcslen(User->Domain) + 1;
  757. SIZE_T sizeWinsta = wcslen(User->WindowStation) + 1;
  758. WCHAR * Buffer = new WCHAR[sizeUserName + sizeDomain + sizeWinsta];
  759. if (!Buffer)
  760. {
  761. Entry->Info.UserName = 0;
  762. Entry->Info.Domain = 0;
  763. Entry->Info.WindowStation = 0;
  764. return FALSE;
  765. }
  766. //
  767. // This must match the code in Remove().
  768. //
  769. Entry->Info.UserName = Buffer;
  770. Entry->Info.Domain = Entry->Info.UserName+1+wcslen(User->UserName);
  771. Entry->Info.WindowStation = Entry->Info.Domain +1+wcslen(User->Domain);
  772. StringCchCopy(Entry->Info.UserName, sizeUserName, User->UserName);
  773. StringCchCopy(Entry->Info.Domain, sizeDomain, User->Domain);
  774. StringCchCopy(Entry->Info.WindowStation, sizeWinsta, User->WindowStation);
  775. Entry->fActive = TRUE;
  776. return TRUE;
  777. }
  778. BOOL
  779. USER_LOGON_TABLE::Remove(
  780. WLX_NOTIFICATION_INFO * User
  781. )
  782. {
  783. if (FALSE == gbIsTokenCodeInitialized)
  784. {
  785. return FALSE;
  786. }
  787. USER_INFO_NODE * Entry = FromWindowStation( User->WindowStation );
  788. if (Entry)
  789. {
  790. //
  791. // This must match the code in Add().
  792. //
  793. delete Entry->Info.UserName;
  794. Entry->fActive = FALSE;
  795. Mutex.Leave();
  796. return TRUE;
  797. }
  798. Mutex.Leave();
  799. return FALSE;
  800. }
  801. HANDLE
  802. USER_LOGON_TABLE::CurrentUserTokenFromWindowStation(
  803. wchar_t WindowStation[]
  804. )
  805. {
  806. HANDLE Token = NULL;
  807. USER_INFO_NODE * Node = FromWindowStation(WindowStation);
  808. if (Node)
  809. {
  810. Token = Node->Info.hToken;
  811. }
  812. Mutex.Leave();
  813. return Token;
  814. }
  815. USER_INFO_NODE *
  816. USER_LOGON_TABLE::FromWindowStation(
  817. wchar_t WindowStation[]
  818. )
  819. /*++
  820. Note that the mutex is held on exit, to avoid race conditions.
  821. --*/
  822. {
  823. USER_INFO_NODE * Node;
  824. LIST_ENTRY * Link;
  825. Mutex.Enter();
  826. for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
  827. Link != &List;
  828. Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
  829. {
  830. if (Node->fActive && 0 == wcscmp(Node->Info.WindowStation, WindowStation))
  831. {
  832. return Node;
  833. }
  834. }
  835. return 0;
  836. }
  837. USER_INFO_NODE *
  838. USER_LOGON_TABLE::FindInactiveEntry(
  839. void
  840. )
  841. {
  842. USER_INFO_NODE * Node;
  843. LIST_ENTRY * Link;
  844. for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
  845. Link != &List;
  846. Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
  847. {
  848. if (!Node->fActive)
  849. {
  850. return Node;
  851. }
  852. }
  853. return 0;
  854. }
  855. RPC_STATUS RPC_ENTRY
  856. AllowLocalSystem (
  857. IN RPC_IF_HANDLE InterfaceUuid,
  858. IN void *Context
  859. )
  860. {
  861. unsigned fLocal = FALSE;
  862. if (RPC_S_OK != I_RpcBindingIsClientLocal(NULL, &fLocal))
  863. {
  864. return ERROR_ACCESS_DENIED;
  865. }
  866. if (!fLocal)
  867. {
  868. return ERROR_ACCESS_DENIED;
  869. }
  870. if (!IsRpcCallerLocalSystem())
  871. {
  872. return ERROR_ACCESS_DENIED;
  873. }
  874. return RPC_S_OK;
  875. }