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.

1470 lines
32 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 "irnotify.h"
  29. #include "usertok.h"
  30. #include "senslogn.hxx"
  31. #include "onestop.cxx"
  32. //
  33. // Constants
  34. //
  35. #define NOTIFY_LCE_STARTSHELL 0x00000003
  36. #define NOTIFY_LCE_LOGOFF 0x00000004
  37. #define SENS_START_WAIT_TIMEOUT 180*1000 // 3 minutes
  38. #define NOTIFY_LCE_LOGONUSER "NotifyLogonUser"
  39. #define NOTIFY_LCE_LOGOFFUSER "NotifyLogoffUser"
  40. #define NOTIFY_IR_LOGONUSER "OnUserLogon"
  41. #define NOTIFY_IR_LOGOFFUSER "OnUserLogoff"
  42. #define NOTIFY_IR_INIT "InitializeDll"
  43. #define SENS_SERVICE SENS_STRING("SENS")
  44. #define EVENTSYSTEM_DLL SENS_STRING("ES.DLL")
  45. #define IR_DLL SENS_STRING("IRNOTIFY.DLL")
  46. #define SENS_STARTED_EVENT SENS_STRING("SENS Started Event")
  47. //
  48. // Globals
  49. //
  50. PWLX_NOTIFICATION_INFO gpStartShellInfo;
  51. HANDLE ghSensStartedEvent;
  52. MUTEX * SetupMutex;
  53. BOOL gbIsTokenCodeInitialized;
  54. // For GetCurrentUserToken
  55. PSID LocalSystemSid;
  56. USER_LOGON_TABLE * ActiveUserList;
  57. // For IR notification of logon/logoff
  58. RPC_BINDING_HANDLE g_hIrxfer;
  59. //
  60. // Some useful Macros
  61. //
  62. #ifdef DETAIL_DEBUG
  63. #define DUMP_INFO(_EventType_) \
  64. \
  65. char buf[512]; \
  66. PWLX_NOTIFICATION_INFO pInfo = (PWLX_NOTIFICATION_INFO) lpvParam; \
  67. \
  68. LogMessage(("------------------------------------------------------\n")); \
  69. LogMessage((SENSLOGN " Received a %s Event.\n", _EventType_)); \
  70. LogMessage((" Size - %d\n", pInfo->Size)); \
  71. LogMessage((" Flags - 0x%x\n", pInfo->Flags)); \
  72. LogMessage((" UserName - %s\n", UnicodeToAnsi(pInfo->UserName, buf))); \
  73. LogMessage((" Domain - %s\n", UnicodeToAnsi(pInfo->Domain, buf))); \
  74. LogMessage((" WinStation - %s\n", UnicodeToAnsi(pInfo->WindowStation, buf))); \
  75. LogMessage((" hToken - 0x%x\n", pInfo->hToken)); \
  76. LogMessage((" hDesktop - 0x%x\n", pInfo->hDesktop)); \
  77. LogMessage((" pCallback - 0x%x\n", pInfo->pStatusCallback)); \
  78. LogMessage((" dwSessionId - 0x%x\n", NtCurrentPeb()->SessionId)); \
  79. LogMessage(("------------------------------------------------------\n"));
  80. //
  81. // Functions
  82. //
  83. PCHAR
  84. UnicodeToAnsi(
  85. PWSTR in,
  86. PCHAR out
  87. )
  88. {
  89. PCHAR pSave = out;
  90. if (in == NULL)
  91. {
  92. return "<NULL>";
  93. }
  94. if (*in == (WCHAR)'\0')
  95. {
  96. return "<Null String>";
  97. }
  98. while( *out++ = (CHAR)*in++)
  99. ;
  100. return pSave;
  101. }
  102. #else // ! DETAIL_DEBUG
  103. #define DUMP_INFO(_EventType_)
  104. #endif // DETAIL_DEBUG
  105. #define FIRE_EVENT(_EventType_) \
  106. { \
  107. \
  108. SENS_NOTIFY_WINLOGON Data; \
  109. \
  110. Data.eType = _EventType_; \
  111. Data.Info.Size = sizeof(SENS_NOTIFY_WINLOGON); \
  112. Data.Info.Flags = ((PWLX_NOTIFICATION_INFO)lpvParam)->Flags; \
  113. Data.Info.UserName = ((PWLX_NOTIFICATION_INFO)lpvParam)->UserName; \
  114. Data.Info.Domain = ((PWLX_NOTIFICATION_INFO)lpvParam)->Domain; \
  115. Data.Info.WindowStation = ((PWLX_NOTIFICATION_INFO)lpvParam)->WindowStation; \
  116. Data.Info.hToken = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hToken); \
  117. Data.Info.hDesktop = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hDesktop); \
  118. Data.Info.dwSessionId = NtCurrentPeb()->SessionId; \
  119. \
  120. status = SensNotifyWinlogonEvent(&Data); \
  121. \
  122. if (status) {SensPrintToDebugger(SENS_DBG, (SENSLOGN "SensNotifyWinlogonEvent(0x%x) returned %d\n", _EventType_, status));} \
  123. }
  124. /*****************************************************************************
  125. *
  126. * IsRemoteSession
  127. *
  128. * On a Terminal Server: returns TRUE if current Session is the not the physical
  129. * console , FALSE if it is the console session (SessionId == 0)
  130. * On non-Hydra NT: always returns FALSE
  131. *
  132. * ENTRY:
  133. * nothing
  134. *
  135. * EXIT:
  136. * nothing
  137. *
  138. ****************************************************************************/
  139. typedef BOOL (__stdcall * PFNPROCESSIDTOSESSIONID)(DWORD, PDWORD);
  140. #define PFN_FIRSTTIME (PFNPROCESSIDTOSESSIONID(-1))
  141. BOOL
  142. IsRemoteSession(VOID)
  143. {
  144. static PFNPROCESSIDTOSESSIONID s_pfn = PFN_FIRSTTIME;
  145. static BOOL bCachedIsRemoteSession = FALSE;
  146. DWORD dwSessionId;
  147. if (PFN_FIRSTTIME == s_pfn)
  148. {
  149. HINSTANCE hinst = GetModuleHandle(L"KERNEL32.DLL");
  150. if (hinst)
  151. {
  152. s_pfn = (PFNPROCESSIDTOSESSIONID)GetProcAddress(hinst, "ProcessIdToSessionId");
  153. }
  154. else
  155. {
  156. s_pfn = NULL;
  157. }
  158. }
  159. if (s_pfn && s_pfn(GetCurrentProcessId(), &dwSessionId))
  160. {
  161. bCachedIsRemoteSession = (dwSessionId != 0);
  162. }
  163. // we set s_pfn = NULL to guarntee we only ever call ProcessIdToSessionId
  164. // once, and after that we just use the bCachedIsRemoteSession value
  165. s_pfn = NULL;
  166. return bCachedIsRemoteSession;
  167. }
  168. DWORD WINAPI
  169. SensLogonEvent(
  170. LPVOID lpvParam
  171. )
  172. /*++
  173. Routine Description:
  174. Hook to trap the Logon Event. In addition, we do the following:
  175. a. Populate our token table with the current token.
  176. b. Initialize The token RPC interface, if necessary.
  177. Arguments:
  178. lpvParam - Winlogon notification info.
  179. Return Value:
  180. RPC status from SensNotifyWinlogonEvent()
  181. --*/
  182. {
  183. DWORD status;
  184. PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  185. DUMP_INFO("Logon");
  186. ActiveUserList->Add( pTempInfo );
  187. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGON);
  188. return status;
  189. }
  190. DWORD WINAPI
  191. SensLogoffEvent(
  192. LPVOID lpvParam
  193. )
  194. /*++
  195. Routine Description:
  196. Hook to trap the Logoff Event. We notify various components
  197. (like IR, OneStop, EventSystem, SENS) of the Logoff event.
  198. Arguments:
  199. lpvParam - Winlogon notification info.
  200. Notes:
  201. a. The system logoff will block till this call returns. Be very
  202. careful in adding code here.
  203. Return Value:
  204. RPC status from SensNotifyWinlogonEvent()
  205. --*/
  206. {
  207. DWORD status;
  208. DWORD dwError;
  209. HRESULT hr;
  210. PWLX_NOTIFICATION_INFO pTempInfo;
  211. hr = S_OK;
  212. dwError = 0x0;
  213. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  214. LogMessage((SENSLOGN "[%d] Entered Logoff.\n", GetTickCount()));
  215. DUMP_INFO("Logoff");
  216. // Try to fire SENS Event
  217. LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
  218. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGOFF);
  219. LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(LOGOFF) succeeded.\n", GetTickCount()));
  220. // Notify IR
  221. LogMessage((SENSLOGN "[%d] Notifying IR...\n", GetTickCount()));
  222. OnUserLogoff( pTempInfo );
  223. LogMessage((SENSLOGN "[%d] OnUserLogoff() succeeded, notified IR.\n", GetTickCount()));
  224. // Start OneStop if necessary, except on Restart.
  225. if ( ((pTempInfo->Flags & EWX_REBOOT) == 0)
  226. && (IsAutoSyncEnabled(pTempInfo->hToken, AUTOSYNC_ON_LOGOFF)))
  227. {
  228. //
  229. // NOTE: If SENS ever becomes demandstarted on NT5, there are a couple
  230. // of things that can be done:
  231. // o Call StartSensIfNecessary() here. (OR)
  232. // o Make Sens APIs call StartSensIfNecessary().
  233. //
  234. LogMessage((SENSLOGN "[%d] Notifying OneStop...\n", GetTickCount()));
  235. hr = SensNotifyOneStop(pTempInfo->hToken, SYNC_MANAGER_LOGOFF, TRUE);
  236. LogMessage((SENSLOGN "[%d] SensNotifyOneStop() returned 0x%x\n", GetTickCount(), hr));
  237. }
  238. // Notify EventSystem
  239. LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
  240. hr = SensNotifyEventSystem(NOTIFY_LCE_LOGOFF, lpvParam);
  241. LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
  242. //
  243. // Remove token handle from the list at the end so that COM activation
  244. // works till SENS gets done with event firings.
  245. //
  246. ActiveUserList->Remove( pTempInfo );
  247. LogMessage((SENSLOGN "Removed current user's token!\n"));
  248. return status;
  249. }
  250. DWORD WINAPI
  251. SensStartupEvent(
  252. LPVOID lpvParam
  253. )
  254. /*++
  255. Routine Description:
  256. Hook to trap the Startup Event. Do some token management related
  257. initialization.
  258. Arguments:
  259. lpvParam - Winlogon notification info.
  260. Notes:
  261. a. This occurs very early in the bootup sequence. At this time,
  262. SENS service hasn't yet started up.
  263. Return Value:
  264. RPC status from SensNotifyWinlogonEvent()
  265. --*/
  266. {
  267. DWORD status;
  268. DWORD dwLastError;
  269. status = 0x0;
  270. gbIsTokenCodeInitialized = FALSE;
  271. //
  272. // Create a SID representing the Local System account.
  273. //
  274. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
  275. status = RtlAllocateAndInitializeSid(
  276. &Authority,
  277. 1,
  278. SECURITY_LOCAL_SYSTEM_RID,
  279. 0,
  280. 0,
  281. 0,
  282. 0,
  283. 0,
  284. 0,
  285. 0,
  286. &LocalSystemSid
  287. );
  288. if (!NT_SUCCESS(status))
  289. {
  290. return RtlNtStatusToDosError(status);
  291. }
  292. //
  293. // Create the table of logged-in users.
  294. //
  295. ActiveUserList = new USER_LOGON_TABLE( &status );
  296. if (!ActiveUserList || status)
  297. {
  298. delete ActiveUserList;
  299. return ERROR_NOT_ENOUGH_MEMORY;
  300. }
  301. SetupMutex = new MUTEX( &status );
  302. if (!SetupMutex || status)
  303. {
  304. delete SetupMutex;
  305. return ERROR_NOT_ENOUGH_MEMORY;
  306. }
  307. InitializeNotifyInterface();
  308. //
  309. // We are ready to use Token Code.
  310. //
  311. gbIsTokenCodeInitialized = TRUE;
  312. LogMessage((SENSLOGN "**** Token code initialized successfully ****\n"));
  313. //
  314. // Create an Event to indicate the starting of SENS.
  315. //
  316. ghSensStartedEvent = CreateEvent(
  317. NULL, // Specific Security Attributes
  318. TRUE, // Event is ManualReset
  319. FALSE, // Initial state is not Signalled
  320. SENS_STARTED_EVENT
  321. );
  322. if (ghSensStartedEvent == NULL)
  323. {
  324. dwLastError = GetLastError();
  325. LogMessage((SENSLOGN "SensStartupEvent() - CreateEvent() failed - %x.\n",
  326. dwLastError));
  327. }
  328. else
  329. {
  330. LogMessage((SENSLOGN "SensStartedEvent created successfully\n"));
  331. }
  332. DUMP_INFO("Startup");
  333. return status;
  334. }
  335. BOOLEAN
  336. InitializeNotifyInterface(
  337. void
  338. )
  339. /*++
  340. Routine Description:
  341. Initialize RPC interface for accepting calls to GetCurrentUserToken() API.
  342. Arguments:
  343. None.
  344. Return Value:
  345. TRUE, if successful
  346. FALSE, otherwise.
  347. --*/
  348. {
  349. unsigned i;
  350. DWORD status;
  351. SetupMutex->Enter();
  352. //
  353. // Register the interface for GetCurrentUserToken().
  354. //
  355. status = RpcServerRegisterAuthInfo(
  356. NULL,
  357. RPC_C_AUTHN_WINNT,
  358. NULL,
  359. NULL
  360. );
  361. if (status)
  362. {
  363. SetupMutex->Leave();
  364. return FALSE;
  365. }
  366. status = RpcServerUseAllProtseqsIf( RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  367. _GetUserToken_ServerIfHandle,
  368. NULL
  369. );
  370. if (status)
  371. {
  372. SetupMutex->Leave();
  373. return FALSE;
  374. }
  375. //
  376. // We expect another part of the process has already called RpcServerListen.
  377. //
  378. status = RpcServerRegisterIfEx(
  379. _GetUserToken_ServerIfHandle,
  380. NULL,
  381. NULL,
  382. 0,
  383. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  384. AllowLocalSystem
  385. );
  386. if (status)
  387. {
  388. SetupMutex->Leave();
  389. return FALSE;
  390. }
  391. if (!IsRemoteSession())
  392. {
  393. //
  394. // Make a handle to the Infrared Monitor app.
  395. //
  396. RPC_BINDING_HANDLE hServer;
  397. status = RpcBindingFromStringBinding(L"ncalrpc:[,security=impersonation dynamic false]", &hServer);
  398. if (status)
  399. {
  400. SetupMutex->Leave();
  401. return FALSE;
  402. }
  403. RPC_SECURITY_QOS RpcSecQos;
  404. RpcSecQos.Version= RPC_C_SECURITY_QOS_VERSION_1;
  405. RpcSecQos.ImpersonationType= RPC_C_IMP_LEVEL_IMPERSONATE;
  406. RpcSecQos.IdentityTracking= RPC_C_QOS_IDENTITY_DYNAMIC;
  407. RpcSecQos.Capabilities= RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  408. status= RpcBindingSetAuthInfoEx(hServer,
  409. L"NT Authority\\System",
  410. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  411. RPC_C_AUTHN_WINNT,
  412. NULL,
  413. RPC_C_AUTHZ_NONE,
  414. (RPC_SECURITY_QOS *)&RpcSecQos);
  415. if (RPC_S_OK != status)
  416. {
  417. RpcBindingFree(&hServer);
  418. SetupMutex->Leave();
  419. return FALSE;
  420. }
  421. g_hIrxfer = hServer;
  422. }
  423. SetupMutex->Leave();
  424. return TRUE;
  425. }
  426. DWORD WINAPI
  427. SensStartShellEvent(
  428. LPVOID lpvParam
  429. )
  430. /*++
  431. Routine Description:
  432. Hook to trap the StartShell Event. We treat this as Logon and notify
  433. various components (IR, OneStop, SENS, EventSystem) of Logon.
  434. Arguments:
  435. lpvParam - Winlogon notification info.
  436. Notes:
  437. a. When this function is called by Winlogon, the shell has begun starting.
  438. There is no guarantee that shell has started completely and is up and
  439. running.
  440. b. We create a thread to do bulk of the work and allow the function
  441. to return.
  442. Return Value:
  443. RPC status from SensNotifyWinlogonEvent()
  444. --*/
  445. {
  446. BOOL bRetVal;
  447. DWORD status;
  448. DWORD dwLastError;
  449. PWLX_NOTIFICATION_INFO pTempInfo;
  450. dwLastError = 0;
  451. bRetVal = TRUE;
  452. DUMP_INFO("StartShell");
  453. //
  454. // Allocate space for the parameters
  455. //
  456. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  457. gpStartShellInfo = (PWLX_NOTIFICATION_INFO) new char[(sizeof(WLX_NOTIFICATION_INFO))];
  458. if (gpStartShellInfo == NULL)
  459. {
  460. dwLastError = GetLastError();
  461. LogMessage((SENSLOGN "SensStartShellEvent(): new() failed - %x.\n", dwLastError));
  462. return dwLastError;
  463. }
  464. memcpy(gpStartShellInfo, pTempInfo, sizeof(WLX_NOTIFICATION_INFO));
  465. // String in WLX_NOTIFICATION_INFO are Unicode
  466. gpStartShellInfo->UserName = (PWSTR) new WCHAR[(wcslen(pTempInfo->UserName) + 1)];
  467. gpStartShellInfo->Domain = (PWSTR) new WCHAR[(wcslen(pTempInfo->Domain) + 1)];
  468. gpStartShellInfo->WindowStation = (PWSTR) new WCHAR[(wcslen(pTempInfo->WindowStation) + 1)];
  469. if ( (gpStartShellInfo->UserName == NULL)
  470. || (gpStartShellInfo->Domain == NULL)
  471. || (gpStartShellInfo->WindowStation == NULL))
  472. {
  473. dwLastError = GetLastError();
  474. LogMessage((SENSLOGN "SensStartShellEvent(): new() of strings failed - %x.\n", dwLastError));
  475. delete gpStartShellInfo->UserName;
  476. delete gpStartShellInfo->Domain;
  477. delete gpStartShellInfo->WindowStation;
  478. delete gpStartShellInfo;
  479. gpStartShellInfo = NULL;
  480. return dwLastError;
  481. }
  482. //
  483. // Copy the parameters
  484. //
  485. wcscpy(gpStartShellInfo->UserName, pTempInfo->UserName);
  486. wcscpy(gpStartShellInfo->Domain, pTempInfo->Domain);
  487. wcscpy(gpStartShellInfo->WindowStation, pTempInfo->WindowStation);
  488. //
  489. // Create a thread to wait on the StartShell event
  490. //
  491. bRetVal = SensQueueUserWorkItem(
  492. (LPTHREAD_START_ROUTINE) SensWaitToStartRoutine,
  493. gpStartShellInfo, // Winlogon event info
  494. SENS_LONG_ITEM // Flags
  495. );
  496. if (FALSE == bRetVal)
  497. {
  498. dwLastError = GetLastError();
  499. LogMessage((SENSLOGN "SensStartShellEvent(): SensQueueUserWorkItem() failed with %x.\n",
  500. dwLastError));
  501. // Cleanup
  502. delete gpStartShellInfo->UserName;
  503. delete gpStartShellInfo->Domain;
  504. delete gpStartShellInfo->WindowStation;
  505. delete gpStartShellInfo;
  506. gpStartShellInfo = NULL;
  507. }
  508. return dwLastError;
  509. }
  510. DWORD WINAPI
  511. SensPostShellEvent(
  512. LPVOID lpvParam
  513. )
  514. /*++
  515. Routine Description:
  516. Hook to trap the Post Shell Event.
  517. Arguments:
  518. lpvParam - Winlogon notification info.
  519. Return Value:
  520. RPC status from SensNotifyWinlogonEvent()
  521. --*/
  522. {
  523. DWORD status;
  524. DUMP_INFO("Post Shell");
  525. FIRE_EVENT(SENS_NOTIFY_WINLOGON_POSTSHELL);
  526. return status;
  527. }
  528. DWORD WINAPI
  529. SensDisconnectEvent(
  530. LPVOID lpvParam
  531. )
  532. /*++
  533. Routine Description:
  534. Hook to trap the Session Disconnect Event.
  535. Arguments:
  536. lpvParam - Winlogon notification info.
  537. Return Value:
  538. RPC status from SensNotifyWinlogonEvent()
  539. --*/
  540. {
  541. DWORD status;
  542. DUMP_INFO("Session Disconnect");
  543. FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_DISCONNECT);
  544. return status;
  545. }
  546. DWORD WINAPI
  547. SensReconnectEvent(
  548. LPVOID lpvParam
  549. )
  550. /*++
  551. Routine Description:
  552. Hook to trap the Session Reconnect Event.
  553. Arguments:
  554. lpvParam - Winlogon notification info.
  555. Return Value:
  556. RPC status from SensNotifyWinlogonEvent()
  557. --*/
  558. {
  559. DWORD status;
  560. DUMP_INFO("Session Reconnect");
  561. FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_RECONNECT);
  562. return status;
  563. }
  564. DWORD WINAPI
  565. SensShutdownEvent(
  566. LPVOID lpvParam
  567. )
  568. /*++
  569. Routine Description:
  570. Hook to trap the Shutdown Event. Do some cleanup.
  571. Arguments:
  572. lpvParam - Winlogon notification info.
  573. Notes:
  574. a. It is guaranteed that COM activation will not work when this event
  575. is received.
  576. Return Value:
  577. RPC status from SensNotifyWinlogonEvent()
  578. --*/
  579. {
  580. DWORD status;
  581. status = ERROR_SUCCESS;
  582. DUMP_INFO("Shutdown");
  583. return status;
  584. }
  585. DWORD WINAPI
  586. SensLockEvent(
  587. LPVOID lpvParam
  588. )
  589. /*++
  590. Routine Description:
  591. Hook to trap the Display Lock Event.
  592. Arguments:
  593. lpvParam - Winlogon notification info.
  594. Return Value:
  595. RPC status from SensNotifyWinlogonEvent()
  596. --*/
  597. {
  598. DWORD status;
  599. DUMP_INFO("Display Lock");
  600. FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOCK);
  601. return status;
  602. }
  603. DWORD WINAPI
  604. SensUnlockEvent(
  605. LPVOID lpvParam
  606. )
  607. /*++
  608. Routine Description:
  609. Hook to trap the Display unlock Event.
  610. Arguments:
  611. lpvParam - Winlogon notification info.
  612. Return Value:
  613. RPC status from SensNotifyWinlogonEvent()
  614. --*/
  615. {
  616. DWORD status;
  617. DUMP_INFO("Display Unlock");
  618. FIRE_EVENT(SENS_NOTIFY_WINLOGON_UNLOCK);
  619. return status;
  620. }
  621. DWORD WINAPI
  622. SensStartScreenSaverEvent(
  623. LPVOID lpvParam
  624. )
  625. /*++
  626. Routine Description:
  627. Hook to trap the ScreenSaver Start Event.
  628. Arguments:
  629. lpvParam - Winlogon notification info.
  630. Return Value:
  631. RPC status from SensNotifyWinlogonEvent()
  632. --*/
  633. {
  634. DWORD status;
  635. DUMP_INFO("StartScreenSaver");
  636. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSCREENSAVER);
  637. return status;
  638. }
  639. DWORD WINAPI
  640. SensStopScreenSaverEvent(
  641. LPVOID lpvParam
  642. )
  643. /*++
  644. Routine Description:
  645. Hook to trap the Screen Saver Stop Event.
  646. Arguments:
  647. lpvParam - Winlogon notification info.
  648. Return Value:
  649. RPC status from SensNotifyWinlogonEvent()
  650. --*/
  651. {
  652. DWORD status;
  653. DUMP_INFO("StopScreenSaver");
  654. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STOPSCREENSAVER);
  655. return status;
  656. }
  657. DWORD WINAPI
  658. SensWaitToStartRoutine(
  659. LPVOID lpvParam
  660. )
  661. /*++
  662. Routine Description:
  663. This routine implements the work item that is queued when the StartShell
  664. event is received.
  665. Arguments:
  666. lpvParam - Winlogon notification info.
  667. Return Value:
  668. ERROR_SUCCESS, always
  669. --*/
  670. {
  671. DWORD dwError;
  672. DWORD dwWaitStatus;
  673. DWORD status;
  674. HRESULT hr;
  675. PWLX_NOTIFICATION_INFO pTempInfo;
  676. dwError = ERROR_SUCCESS;
  677. dwWaitStatus = 0x0;
  678. pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
  679. // Give SENS a chance to start if it has not already stated.
  680. // Give up after a short time in case sens is has been set to manual start
  681. // We could check the service configuration but the thread as already been
  682. // created so we save won't very much.
  683. ASSERT(ghSensStartedEvent);
  684. dwError = WaitForSingleObject(ghSensStartedEvent, 20*1000);
  685. if (dwError != STATUS_WAIT_0)
  686. {
  687. LogMessage((SENSLOGN "[%d] Wait for sens start event timed out...\n", GetTickCount()));
  688. }
  689. // Notify EventSystem
  690. LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
  691. hr = SensNotifyEventSystem(NOTIFY_LCE_STARTSHELL, lpvParam);
  692. LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
  693. // Notify IR
  694. LogMessage((SENSLOGN "[%d] Notifying IR...\n", GetTickCount()));
  695. OnUserLogon( pTempInfo );
  696. LogMessage((SENSLOGN "[%d] OnUserLogon succeeded.\n", GetTickCount()));
  697. // Try to fire SENS Event
  698. LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
  699. FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSHELL);
  700. LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(STARTSHELL) succeeded.\n", GetTickCount()));
  701. // Cleanup
  702. delete pTempInfo->UserName;
  703. delete pTempInfo->Domain;
  704. delete pTempInfo->WindowStation;
  705. delete pTempInfo;
  706. gpStartShellInfo = NULL;
  707. return ERROR_SUCCESS;
  708. }
  709. HRESULT
  710. SensNotifyEventSystem(
  711. DWORD dwEvent,
  712. LPVOID lpvParam
  713. )
  714. /*++
  715. Routine Description:
  716. This routine notifies EventSystem of the Logon/Logoff events.
  717. Arguments:
  718. dwEvent - Tells if the event is Logon or Logoff.
  719. lpvParam - Winlogon notification info.
  720. Notes:
  721. a. EventSystem's notify routine has been observed sometimes to take
  722. a long time causing Logoff to take longer time to complete.
  723. Return Value:
  724. HRESULT from EventSystem's Notify routine.
  725. --*/
  726. {
  727. HRESULT hr;
  728. hr = S_OK;
  729. PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO)lpvParam;
  730. //
  731. // Notify the COM+ Event System that a user has just logged on.
  732. // Per-user subscriptions will be activated.
  733. //
  734. typedef HRESULT (__stdcall *LPFN_NOTIFICATION)(HANDLE);
  735. HMODULE hDLL;
  736. LPFN_NOTIFICATION lpfnNotify = NULL;
  737. hDLL = (HMODULE) LoadLibrary(EVENTSYSTEM_DLL);
  738. if (hDLL == NULL)
  739. {
  740. hr = HRESULT_FROM_WIN32(GetLastError());
  741. }
  742. else
  743. {
  744. if (dwEvent == NOTIFY_LCE_STARTSHELL)
  745. {
  746. lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGONUSER);
  747. }
  748. else
  749. if (dwEvent == NOTIFY_LCE_LOGOFF)
  750. {
  751. lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGOFFUSER);
  752. }
  753. hr = (lpfnNotify == NULL) ? HRESULT_FROM_WIN32(GetLastError()) : (*lpfnNotify)(pTempInfo->hToken);
  754. FreeLibrary(hDLL);
  755. }
  756. return hr;
  757. }
  758. void
  759. OnUserLogon(
  760. WLX_NOTIFICATION_INFO * User
  761. )
  762. {
  763. DWORD status = 0;
  764. if (FALSE == gbIsTokenCodeInitialized)
  765. {
  766. return;
  767. }
  768. if (IsRemoteSession())
  769. {
  770. return;
  771. }
  772. if (!ImpersonateLoggedOnUser( User->hToken ))
  773. {
  774. return;
  775. }
  776. UserLoggedOn( g_hIrxfer, &status );
  777. RevertToSelf();
  778. }
  779. void
  780. OnUserLogoff(
  781. WLX_NOTIFICATION_INFO * User
  782. )
  783. {
  784. DWORD status;
  785. if (FALSE == gbIsTokenCodeInitialized)
  786. {
  787. return;
  788. }
  789. if (IsRemoteSession())
  790. {
  791. return;
  792. }
  793. if (!ImpersonateLoggedOnUser( User->hToken ))
  794. {
  795. return;
  796. }
  797. UserLoggedOff( g_hIrxfer, &status );
  798. RevertToSelf();
  799. }
  800. #define MAX_WINDOWSTATION_NAME_LENGTH 1000
  801. DWORD
  802. _SecpGetCurrentUserToken(
  803. handle_t Binding,
  804. wchar_t WindowStation[],
  805. unsigned long ProcessId,
  806. unsigned long * pToken,
  807. unsigned long DesiredAccess
  808. )
  809. {
  810. HANDLE LocalToken;
  811. HANDLE RemoteToken;
  812. HANDLE RemoteProcess;
  813. if (FALSE == gbIsTokenCodeInitialized)
  814. {
  815. return ERROR_OUTOFMEMORY;
  816. }
  817. //
  818. // Validate arguments. The only one that can cause us harm is the window station.
  819. //
  820. if (IsBadStringPtr( WindowStation, MAX_WINDOWSTATION_NAME_LENGTH))
  821. {
  822. return ERROR_ACCESS_DENIED;
  823. }
  824. //
  825. // Clone the token into the requested process.
  826. //
  827. LocalToken = ActiveUserList->CurrentUserTokenFromWindowStation( WindowStation );
  828. if (!LocalToken)
  829. {
  830. LogMessage((SENSLOGN "GetCurrentUserToken(): User not logged on!\n"));
  831. return ERROR_NOT_LOGGED_ON;
  832. }
  833. RemoteProcess = OpenProcess(
  834. PROCESS_DUP_HANDLE,
  835. FALSE, // not inheritable
  836. ProcessId
  837. );
  838. if (!RemoteProcess)
  839. {
  840. LogMessage((SENSLOGN "GetCurrentUserToken(): OpenProcess() failed!\n"));
  841. return GetLastError();
  842. }
  843. if (!DuplicateHandle(
  844. GetCurrentProcess(),
  845. LocalToken,
  846. RemoteProcess,
  847. &RemoteToken,
  848. DesiredAccess,
  849. FALSE, // not inheritable
  850. 0 // no funny options
  851. ))
  852. {
  853. LogMessage((SENSLOGN "GetCurrentUserToken(): DuplicateHandle() failed!\n"));
  854. CloseHandle( RemoteProcess );
  855. return GetLastError();
  856. }
  857. CloseHandle( RemoteProcess );
  858. *pToken = HandleToUlong(RemoteToken);
  859. LogMessage((SENSLOGN "GetCurrentUserToken(): Succeeded. Returning 0x%x.\n", *pToken));
  860. return ERROR_SUCCESS;
  861. }
  862. BOOL
  863. USER_LOGON_TABLE::Add(
  864. WLX_NOTIFICATION_INFO * User
  865. )
  866. {
  867. USER_INFO_NODE * Entry;
  868. if (FALSE == gbIsTokenCodeInitialized)
  869. {
  870. return FALSE;
  871. }
  872. CLAIM_MUTEX Lock( Mutex );
  873. Entry = FindInactiveEntry();
  874. if (!Entry)
  875. {
  876. Entry = new USER_INFO_NODE;
  877. if (!Entry)
  878. {
  879. return FALSE;
  880. }
  881. Entry->fActive = FALSE;
  882. InsertTailList( &List, &Entry->Links );
  883. }
  884. Entry->Info.Size = sizeof(WLX_NOTIFICATION_INFO);
  885. Entry->Info.Flags = User->Flags;
  886. Entry->Info.hToken = User->hToken;
  887. WCHAR * Buffer = new WCHAR[ 1+wcslen(User->UserName) +
  888. 1+wcslen(User->Domain) +
  889. 1+wcslen(User->WindowStation) ];
  890. if (!Buffer)
  891. {
  892. Entry->Info.UserName = 0;
  893. Entry->Info.Domain = 0;
  894. Entry->Info.WindowStation = 0;
  895. return FALSE;
  896. }
  897. //
  898. // This must match the code in Remove().
  899. //
  900. Entry->Info.UserName = Buffer;
  901. Entry->Info.Domain = Entry->Info.UserName+1+wcslen(User->UserName);
  902. Entry->Info.WindowStation = Entry->Info.Domain +1+wcslen(User->Domain);
  903. wcscpy(Entry->Info.UserName, User->UserName);
  904. wcscpy(Entry->Info.Domain, User->Domain);
  905. wcscpy(Entry->Info.WindowStation, User->WindowStation);
  906. Entry->fActive = TRUE;
  907. return TRUE;
  908. }
  909. BOOL
  910. USER_LOGON_TABLE::Remove(
  911. WLX_NOTIFICATION_INFO * User
  912. )
  913. {
  914. if (FALSE == gbIsTokenCodeInitialized)
  915. {
  916. return FALSE;
  917. }
  918. USER_INFO_NODE * Entry = FromWindowStation( User->WindowStation );
  919. if (Entry)
  920. {
  921. //
  922. // This must match the code in Add().
  923. //
  924. delete Entry->Info.UserName;
  925. Entry->fActive = FALSE;
  926. Mutex.Leave();
  927. return TRUE;
  928. }
  929. Mutex.Leave();
  930. return FALSE;
  931. }
  932. HANDLE
  933. USER_LOGON_TABLE::CurrentUserTokenFromWindowStation(
  934. wchar_t WindowStation[]
  935. )
  936. {
  937. HANDLE Token = NULL;
  938. USER_INFO_NODE * Node = FromWindowStation(WindowStation);
  939. if (Node)
  940. {
  941. Token = Node->Info.hToken;
  942. }
  943. Mutex.Leave();
  944. return Token;
  945. }
  946. USER_INFO_NODE *
  947. USER_LOGON_TABLE::FromWindowStation(
  948. wchar_t WindowStation[]
  949. )
  950. /*++
  951. Note that the mutex is held on exit, to avoid race conditions.
  952. --*/
  953. {
  954. USER_INFO_NODE * Node;
  955. LIST_ENTRY * Link;
  956. Mutex.Enter();
  957. for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
  958. Link != &List;
  959. Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
  960. {
  961. if (Node->fActive && 0 == wcscmp(Node->Info.WindowStation, WindowStation))
  962. {
  963. return Node;
  964. }
  965. }
  966. return 0;
  967. }
  968. USER_INFO_NODE *
  969. USER_LOGON_TABLE::FindInactiveEntry(
  970. void
  971. )
  972. {
  973. USER_INFO_NODE * Node;
  974. LIST_ENTRY * Link;
  975. for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
  976. Link != &List;
  977. Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
  978. {
  979. if (!Node->fActive)
  980. {
  981. return Node;
  982. }
  983. }
  984. return 0;
  985. }
  986. RPC_STATUS RPC_ENTRY
  987. AllowLocalSystem (
  988. IN RPC_IF_HANDLE InterfaceUuid,
  989. IN void *Context
  990. )
  991. {
  992. if (RpcImpersonateClient(Context))
  993. {
  994. return ERROR_ACCESS_DENIED;
  995. }
  996. //
  997. // Clone the user's token so we can launch apps on the desktop.
  998. //
  999. HANDLE ImpersonationToken;
  1000. if (!OpenThreadToken(
  1001. GetCurrentThread(),
  1002. TOKEN_QUERY,
  1003. TRUE, // use process token for access check
  1004. &ImpersonationToken
  1005. ))
  1006. {
  1007. return GetLastError();
  1008. }
  1009. //
  1010. // Get the SID from the token.
  1011. //
  1012. DWORD SizeNeeded = 0;
  1013. TOKEN_USER * TokenData = NULL;
  1014. // Get the size first.
  1015. if (!GetTokenInformation(
  1016. ImpersonationToken,
  1017. TokenUser,
  1018. 0,
  1019. 0,
  1020. &SizeNeeded
  1021. ))
  1022. {
  1023. DWORD dwLastError = GetLastError();
  1024. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  1025. {
  1026. CloseHandle( ImpersonationToken );
  1027. return dwLastError;
  1028. }
  1029. }
  1030. __try
  1031. {
  1032. TokenData = (TOKEN_USER *) _alloca( SizeNeeded );
  1033. }
  1034. __except(EXCEPTION_EXECUTE_HANDLER)
  1035. {
  1036. // Nothing
  1037. }
  1038. if (!TokenData)
  1039. {
  1040. CloseHandle( ImpersonationToken );
  1041. return ERROR_NOT_ENOUGH_MEMORY;
  1042. }
  1043. if (!GetTokenInformation(
  1044. ImpersonationToken,
  1045. TokenUser,
  1046. TokenData,
  1047. SizeNeeded,
  1048. &SizeNeeded
  1049. ))
  1050. {
  1051. CloseHandle( ImpersonationToken );
  1052. return GetLastError();
  1053. }
  1054. CloseHandle(ImpersonationToken);
  1055. if (!RtlEqualSid(
  1056. TokenData->User.Sid,
  1057. LocalSystemSid
  1058. ))
  1059. {
  1060. return ERROR_ACCESS_DENIED;
  1061. }
  1062. return 0;
  1063. }