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.

1186 lines
37 KiB

  1. //*************************************************************
  2. //
  3. // File name: TSrvVC.c
  4. //
  5. // Description: Contains routines to support Virtual Channel
  6. // addins
  7. //
  8. // Microsoft Confidential
  9. // Copyright (c) Microsoft Corporation 1998
  10. // All rights reserved
  11. //
  12. //*************************************************************
  13. #include <tchar.h>
  14. #include <TSrv.h>
  15. #include <TSrvInfo.h>
  16. #include <TSrvVC.h>
  17. #include <TSrvExp.h>
  18. #include <tschannl.h>
  19. //
  20. // Global data
  21. //
  22. CRITICAL_SECTION g_TSrvVCCritSect = {0};
  23. UINT g_AddinCount = 0;
  24. PTSRV_VC_ADDIN g_pAddin = NULL;
  25. HANDLE g_hVCAddinChangeEvent = NULL;
  26. HKEY g_hAddinRegKey = NULL; // handle to Addins reg subkey
  27. BOOL g_bNeedToSetRegNotify = TRUE;
  28. LONG g_WsxInitialized = FALSE;
  29. BOOL g_DoubleInitialized = FALSE;
  30. //*************************************************************
  31. //
  32. // TSrvInitVC()
  33. //
  34. // Purpose: Initializes the Virtual Channel support
  35. //
  36. // Parameters: None.
  37. //
  38. // Return: TRUE - success
  39. // FALSE - failure
  40. //
  41. // Notes: Function is called by the main processing thread
  42. // during initialization. We store the list of
  43. // addins from the registry.
  44. //
  45. //*************************************************************
  46. BOOL
  47. TSrvInitVC(VOID)
  48. {
  49. BOOL rc = FALSE;
  50. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvInitVC\n"));
  51. if (InterlockedExchange(&g_WsxInitialized, TRUE) == TRUE) {
  52. g_DoubleInitialized = TRUE;
  53. }
  54. //
  55. // Set up the critical section structure for access to the VC globals
  56. //
  57. if (RtlInitializeCriticalSection(&g_TSrvVCCritSect) == STATUS_SUCCESS)
  58. {
  59. //
  60. // Read the Addins registry key for the first time and store the data
  61. // for WinStations to copy when they initialize.
  62. //
  63. EnterCriticalSection(&g_TSrvVCCritSect);
  64. TSrvReadVCAddins();
  65. LeaveCriticalSection(&g_TSrvVCCritSect);
  66. rc = TRUE;
  67. }
  68. else
  69. {
  70. TRACE((DEBUG_TSHRSRV_ERROR,
  71. "TShrSRV VC: cannot initialize g_TSrvVCCritSect\n"));
  72. }
  73. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvInitVC - %d\n", rc));
  74. return(rc);
  75. }
  76. //*************************************************************
  77. //
  78. // TSrvTermVC()
  79. //
  80. // Purpose: Terminates the Virtual Channel support
  81. //
  82. // Parameters: None.
  83. //
  84. // Return: None.
  85. //
  86. // Notes: Frees data used by VC support.
  87. //
  88. //*************************************************************
  89. VOID
  90. TSrvTermVC(VOID)
  91. {
  92. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvTermVC\n"));
  93. EnterCriticalSection(&g_TSrvVCCritSect);
  94. if (g_pAddin != NULL)
  95. {
  96. TSHeapFree(g_pAddin);
  97. g_pAddin = NULL;
  98. }
  99. g_AddinCount = 0;
  100. LeaveCriticalSection(&g_TSrvVCCritSect);
  101. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvTermVC\n"));
  102. }
  103. //*************************************************************
  104. //
  105. // TSrvReleaseVCAddins()
  106. //
  107. // Purpose: Releases session-specific addin resources
  108. //
  109. // Parameters: None.
  110. //
  111. // Return: None.
  112. //
  113. //*************************************************************
  114. VOID
  115. TSrvReleaseVCAddins(PWSX_CONTEXT pWsxContext)
  116. {
  117. PTSRV_VC_ADDIN pVCAddin;
  118. UINT i;
  119. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvReleaseVCAddins\n"));
  120. //
  121. // We must go through all the addin entries and release each one's
  122. // device handle (if it has one).
  123. //
  124. pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext + 1);
  125. for (i = 0; i < pWsxContext->cVCAddins; i++)
  126. {
  127. if (pVCAddin[i].hDevice != INVALID_HANDLE_VALUE)
  128. {
  129. NtClose(pVCAddin[i].hDevice);
  130. pVCAddin[i].hDevice = INVALID_HANDLE_VALUE;
  131. }
  132. }
  133. TRACE((DEBUG_TSHRSRV_NORMAL,
  134. "TShrSRV VC: All handles released for %u addin(s)\n",
  135. pWsxContext->cVCAddins));
  136. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvReleaseVCAddins\n"));
  137. }
  138. //*************************************************************
  139. //
  140. // TSrvNotifyVC()
  141. //
  142. // Purpose: Notify Addins of VC events
  143. //
  144. // Parameters: IN pWsxContext
  145. // IN Event - event that has occured (one of the
  146. // TSRV_VC_ constants)
  147. //
  148. // Return: none
  149. //
  150. // Notes: Function is called to notify Virtual Channel addins
  151. // of interesting events
  152. //
  153. //*************************************************************
  154. VOID
  155. TSrvNotifyVC(PWSX_CONTEXT pWsxContext, ULONG Event)
  156. {
  157. TRACE((DEBUG_TSHRSRV_NORMAL,
  158. "TShrSRV VC: Informing %u addin(s) of event %lu\n",
  159. pWsxContext->cVCAddins,
  160. Event));
  161. //
  162. // Call worker functions to handle different Addin types
  163. //
  164. TSrvNotifyVC_0(pWsxContext, Event);
  165. TSrvNotifyVC_3(pWsxContext, Event);
  166. }
  167. //*************************************************************
  168. //
  169. // TSrvNotifyVC_0()
  170. //
  171. // Purpose: Notify K-mode system-wide addins of VC events
  172. //
  173. // Parameters: IN pWsxContext
  174. // IN Event - event that has occured (one of the
  175. // TSRV_VC_ constants)
  176. //
  177. // Return: none
  178. //
  179. // Notes: Function is called to notify Virtual Channel addins
  180. // of interesting events
  181. //
  182. //*************************************************************
  183. VOID
  184. TSrvNotifyVC_0(PWSX_CONTEXT pWsxContext, ULONG Event)
  185. {
  186. PCHANNEL_IOCTL_IN pInHdr;
  187. PCHANNEL_IOCTL_OUT pOutHdr;
  188. char InBuf[sizeof(CHANNEL_CONNECT_IN) + (CHANNEL_MAX_COUNT * sizeof(CHANNEL_DEF))];
  189. char OutBuf[sizeof(CHANNEL_CONNECT_OUT)];
  190. DWORD InBufSize;
  191. DWORD OutBufSize;
  192. PVOID pOutBuf;
  193. UINT Code;
  194. UINT BytesReturned;
  195. UINT i;
  196. BOOL bRc;
  197. NTSTATUS ntStatus;
  198. UNICODE_STRING FileName;
  199. PTSRV_VC_ADDIN pVCAddin;
  200. OBJECT_ATTRIBUTES FileAttributes;
  201. IO_STATUS_BLOCK IoStatusBlock;
  202. TRACE((DEBUG_TSHRSRV_FLOW,
  203. "TShrSRV VC: Enter TSrvNotifyVC_0: event %d, session %d\n", Event, pWsxContext->LogonId));
  204. //
  205. // Build the InBuf based on the event
  206. //
  207. switch (Event)
  208. {
  209. case TSRV_VC_SESSION_CONNECT:
  210. case TSRV_VC_SESSION_SHADOW_END:
  211. {
  212. TRACE((DEBUG_TSHRSRV_NORMAL,
  213. "TShrSRV VC: Connect session %d\n",
  214. pWsxContext->LogonId));
  215. //
  216. // Ask WD for the list of channels
  217. //
  218. ntStatus = IcaStackIoControl(pWsxContext->hStack,
  219. IOCTL_TSHARE_QUERY_CHANNELS,
  220. NULL,
  221. 0,
  222. InBuf,
  223. sizeof(InBuf),
  224. &InBufSize);
  225. if (!NT_SUCCESS(ntStatus))
  226. {
  227. TRACE((DEBUG_TSHRSRV_ERROR,
  228. "TShrSRV VC: Failed to get channels for session %d, status %#x\n",
  229. pWsxContext->LogonId, ntStatus));
  230. //
  231. // WD didn't answer, so return 0 channels
  232. //
  233. InBufSize = sizeof(CHANNEL_CONNECT_IN);
  234. ((PCHANNEL_CONNECT_IN)InBuf)->channelCount = 0;
  235. }
  236. ((PCHANNEL_CONNECT_IN)InBuf)->fAutoClientDrives =
  237. pWsxContext->fAutoClientDrives;
  238. ((PCHANNEL_CONNECT_IN)InBuf)->fAutoClientLpts =
  239. pWsxContext->fAutoClientLpts;
  240. ((PCHANNEL_CONNECT_IN)InBuf)->fForceClientLptDef =
  241. pWsxContext->fForceClientLptDef;
  242. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCpm =
  243. pWsxContext->fDisableCpm;
  244. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCdm =
  245. pWsxContext->fDisableCdm;
  246. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCcm =
  247. pWsxContext->fDisableCcm;
  248. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableLPT =
  249. pWsxContext->fDisableLPT;
  250. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableClip =
  251. pWsxContext->fDisableClip;
  252. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableExe =
  253. pWsxContext->fDisableExe;
  254. ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCam =
  255. pWsxContext->fDisableCam;
  256. TRACE((DEBUG_TSHRSRV_NORMAL,
  257. "TShrSRV VC: %d channels returned by WD\n",
  258. ((PCHANNEL_CONNECT_IN)InBuf)->channelCount));
  259. //
  260. // Complete the Ioctl
  261. //
  262. Code = IOCTL_CHANNEL_CONNECT;
  263. }
  264. break;
  265. case TSRV_VC_SESSION_DISCONNECT:
  266. case TSRV_VC_SESSION_SHADOW_START:
  267. {
  268. TRACE((DEBUG_TSHRSRV_NORMAL,
  269. "TShrSRV VC: Disconnect session %d\n",
  270. pWsxContext->LogonId));
  271. InBufSize = sizeof(CHANNEL_DISCONNECT_IN);
  272. Code = IOCTL_CHANNEL_DISCONNECT;
  273. }
  274. break;
  275. default:
  276. {
  277. TRACE((DEBUG_TSHRSRV_ERROR,
  278. "TShrSRV VC: Unknown event %d\n", Event));
  279. goto EXIT_POINT;
  280. }
  281. break;
  282. }
  283. //
  284. // Complete the common parts of the IoCtl
  285. //
  286. pInHdr = (PCHANNEL_IOCTL_IN)InBuf;
  287. pInHdr->sessionID = pWsxContext->LogonId;
  288. pInHdr->IcaHandle = pWsxContext->hIca;
  289. pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext + 1);
  290. //
  291. // Send the IoCtl to all addin devices
  292. //
  293. for (i = 0; i < pWsxContext->cVCAddins; i++)
  294. {
  295. //
  296. // Check it's a K-mode system-wide Addin
  297. //
  298. if (pVCAddin[i].Type != TSRV_VC_TYPE_KERNEL_SYSTEM)
  299. {
  300. TRACE((DEBUG_TSHRSRV_NORMAL,
  301. "TShrSRV VC: Skipping addin %d type %d\n", i, pVCAddin[i].Type));
  302. continue;
  303. }
  304. //
  305. // Open the device if it hasn't already been opened
  306. //
  307. if (pVCAddin[i].hDevice == INVALID_HANDLE_VALUE)
  308. {
  309. RtlInitUnicodeString(&FileName, pVCAddin[i].Name);
  310. InitializeObjectAttributes(&FileAttributes, &FileName, 0,
  311. NULL, NULL);
  312. ntStatus = NtCreateFile(&(pVCAddin[i].hDevice),
  313. GENERIC_READ | GENERIC_WRITE, &FileAttributes, &IoStatusBlock,
  314. 0, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF,
  315. FILE_SEQUENTIAL_ONLY, NULL, 0);
  316. TRACE((DEBUG_TSHRSRV_NORMAL,
  317. "TShrSRV VC: Open addin %d: %S, status = %#x, handle %p\n",
  318. i, pVCAddin[i].Name, ntStatus, pVCAddin[i].hDevice));
  319. if (!NT_SUCCESS(ntStatus))
  320. {
  321. TRACE((DEBUG_TSHRSRV_ERROR,
  322. "TShrSRV VC: Failed to open addin %d: %S, status = %#x\n",
  323. i, pVCAddin[i].Name, ntStatus));
  324. pVCAddin[i].hDevice = INVALID_HANDLE_VALUE;
  325. }
  326. }
  327. //
  328. // Send the IOCtl if it's a valid device
  329. //
  330. if (pVCAddin[i].hDevice != INVALID_HANDLE_VALUE)
  331. {
  332. memset(OutBuf, 0, sizeof(OutBuf));
  333. pInHdr->contextData = pVCAddin[i].AddinContext;
  334. bRc = DeviceIoControl(pVCAddin[i].hDevice, Code, InBuf, InBufSize,
  335. OutBuf, sizeof(OutBuf), &BytesReturned, NULL);
  336. TRACE((DEBUG_TSHRSRV_NORMAL,
  337. "TShrSRV VC: IOCtl %x to addin %d (device %x), rc %d\n",
  338. Code, i, pVCAddin[i].hDevice, bRc));
  339. if (bRc)
  340. {
  341. pVCAddin[i].AddinContext =
  342. ((PCHANNEL_IOCTL_OUT)OutBuf)->contextData;
  343. TRACE((DEBUG_TSHRSRV_NORMAL,
  344. "TShrSRV VC: Saved return context data %p\n",
  345. pVCAddin[i].AddinContext));
  346. }
  347. }
  348. else
  349. {
  350. TRACE((DEBUG_TSHRSRV_WARN,
  351. "TShrSRV VC: Skip IOCtl %#x to invalid addin %d\n",
  352. Code, i));
  353. }
  354. }
  355. EXIT_POINT:
  356. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvNotifyVC_0\n"));
  357. }
  358. //*************************************************************
  359. //
  360. // TSrvNotifyVC_3()
  361. //
  362. // Purpose: Notify U-mode session addins of VC events
  363. //
  364. // Parameters: IN pWsxContext
  365. // IN Event - event that has occured (one of the
  366. // TSRV_VC_ constants)
  367. //
  368. // Return: none
  369. //
  370. // Notes: Function is called to notify Virtual Channel addins
  371. // of interesting events
  372. //
  373. //*************************************************************
  374. #define VCEVT_TYPE_DISCONNECT _T("Disconnect")
  375. #define VCEVT_TYPE_RECONNECT _T("Reconnect")
  376. VOID
  377. TSrvNotifyVC_3(PWSX_CONTEXT pWsxContext, ULONG Event)
  378. {
  379. UINT i;
  380. TCHAR EventName[MAX_PATH];
  381. PTSRV_VC_ADDIN pVCAddin;
  382. HANDLE hEvent;
  383. BOOL fSignalEvent;
  384. BOOL fOpenInSessionSpace;
  385. LPTSTR szEvtType;
  386. TRACE((DEBUG_TSHRSRV_FLOW,
  387. "TShrSRV VC: Enter TSrvNotifyVC_3: event %d, session %d\n", Event, pWsxContext->LogonId));
  388. pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext+1);
  389. for (i = 0; i < pWsxContext->cVCAddins; i++)
  390. {
  391. //
  392. // Check it's a U-mode session Addin
  393. //
  394. if (pVCAddin[i].Type != TSRV_VC_TYPE_USER_SESSION)
  395. {
  396. TRACE((DEBUG_TSHRSRV_NORMAL,
  397. "TShrSrv VC: Skipping addin %d type %d\n", i, pVCAddin[i].Type));
  398. continue;
  399. }
  400. fSignalEvent = FALSE;
  401. if ((Event == TSRV_VC_SESSION_DISCONNECT) ||
  402. ((Event == TSRV_VC_SESSION_SHADOW_START) && !pVCAddin[i].bShadowPersistent))
  403. {
  404. fSignalEvent = TRUE;
  405. szEvtType = VCEVT_TYPE_DISCONNECT;
  406. }
  407. else if ((Event == TSRV_VC_SESSION_CONNECT) ||
  408. ((Event == TSRV_VC_SESSION_SHADOW_END) && !pVCAddin[i].bShadowPersistent))
  409. {
  410. fSignalEvent = TRUE;
  411. szEvtType = VCEVT_TYPE_RECONNECT;
  412. }
  413. //Gilles added the commented out code below....
  414. /*
  415. else if ((Event == TSRV_VC_SESSION_SHADOW_START) && pVCAddin[i].bShadowPersistent)
  416. {
  417. // Open the event
  418. _stprintf(EventName,
  419. _T("Global\\%s-%d-RemoteControlStart"),
  420. pVCAddin[i].Name, pWsxContext->LogonId);
  421. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, EventName);
  422. if (hEvent != NULL)
  423. {
  424. TRACE((DEBUG_TSHRSRV_NORMAL,
  425. "TShrSrv VC: Opened event %S, handle %p\n",
  426. EventName, hEvent));
  427. // Post the event
  428. if (!SetEvent(hEvent))
  429. {
  430. TRACE((DEBUG_TSHRSRV_ERROR,
  431. "TShrSrv VC: Failed to post shadow start event %d\n", GetLastError()));
  432. }
  433. CloseHandle(hEvent);
  434. }
  435. else
  436. {
  437. TRACE((DEBUG_TSHRSRV_ERROR,
  438. "TShrSrv VC: Failed to open shadow start event %S, %d\n",
  439. EventName, GetLastError()));
  440. }
  441. }
  442. else if ((Event == TSRV_VC_SESSION_SHADOW_END) && pVCAddin[i].bShadowPersistent)
  443. {
  444. // Open the event
  445. _stprintf(EventName,
  446. _T("Global\\%s-%d-RemoteControlStop"),
  447. pVCAddin[i].Name, pWsxContext->LogonId);
  448. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, EventName);
  449. if (hEvent != NULL)
  450. {
  451. TRACE((DEBUG_TSHRSRV_NORMAL,
  452. "TShrSrv VC: Opened event %S, handle %p\n",
  453. EventName, hEvent));
  454. // Post the event
  455. if (!SetEvent(hEvent))
  456. {
  457. TRACE((DEBUG_TSHRSRV_ERROR,
  458. "TShrSrv VC: Failed to post shadow stop event %d\n", GetLastError()));
  459. }
  460. CloseHandle(hEvent);
  461. }
  462. else
  463. {
  464. TRACE((DEBUG_TSHRSRV_ERROR,
  465. "TShrSrv VC: Failed to open shadow stop event %S, %d\n",
  466. EventName, GetLastError()));
  467. }
  468. }
  469. */
  470. else
  471. {
  472. TRACE((DEBUG_TSHRSRV_ERROR,
  473. "TShrSRV VC: Unexpected event %d\n", Event));
  474. }
  475. if(fSignalEvent)
  476. {
  477. // First try the new style per session event, if that fails
  478. // revert to the old style global event
  479. //
  480. // New style event name format is:
  481. // (in appropriate session namespace) AddinName-Event
  482. // Old style is:
  483. // (always in global namespace) AddinName-SessionId-Event
  484. //
  485. if(pWsxContext->LogonId)
  486. {
  487. _stprintf(EventName,
  488. _T("\\Sessions\\%d\\BaseNamedObjects\\%s-%s"),
  489. pWsxContext->LogonId,
  490. pVCAddin[i].Name,
  491. szEvtType);
  492. fOpenInSessionSpace = TRUE;
  493. }
  494. else
  495. {
  496. //in SessionID 0 events are in the global namespace
  497. //we still need to open the new style event in global space
  498. _stprintf(EventName,
  499. _T("Global\\%s-%s"),
  500. pVCAddin[i].Name,
  501. szEvtType);
  502. //Need to start at the global namespace
  503. fOpenInSessionSpace = FALSE;
  504. }
  505. if(!TSrvOpenAndSetEvent(EventName, fOpenInSessionSpace))
  506. {
  507. TRACE((DEBUG_TSHRSRV_NORMAL,
  508. "TShrSrv VC: Failed to OpenAndSet new style event %S, %#x\n",
  509. EventName, GetLastError()));
  510. //Try the legacy style global event
  511. _stprintf(EventName,
  512. _T("Global\\%s-%d-%s"),
  513. pVCAddin[i].Name,
  514. pWsxContext->LogonId,
  515. szEvtType);
  516. if(!TSrvOpenAndSetEvent(EventName, FALSE))
  517. {
  518. TRACE((DEBUG_TSHRSRV_ERROR,
  519. "TShrSrv VC: Failed OpenAndSet legacy style evt %S, %#x\n",
  520. EventName, GetLastError()));
  521. }
  522. }
  523. }
  524. }
  525. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvNotifyVC_3\n"));
  526. }
  527. //*************************************************************
  528. //
  529. // TSrvOpenAndSetEvent()
  530. //
  531. // Purpose: Opens and sets an event
  532. // This function is used instead of OpenEvent()
  533. // because it can access events in session space
  534. // OpenEvent is hardcoded to be rooted at the
  535. // global namespace's BaseNamedObjects directory
  536. //
  537. // Parameters:
  538. // szEventName - full path to event
  539. // bPerSessionEvent - TRUE if event is in per-session directory
  540. //
  541. // Return: Success status, sets error state with SetLastError
  542. //
  543. //*************************************************************
  544. BOOL
  545. TSrvOpenAndSetEvent(LPCTSTR szEventName, BOOL bPerSessionEvent)
  546. {
  547. HANDLE hEvent;
  548. BOOL bSuccess = FALSE;
  549. if(szEventName)
  550. {
  551. if(bPerSessionEvent)
  552. {
  553. hEvent = OpenPerSessionEvent(EVENT_MODIFY_STATE, FALSE, szEventName);
  554. }
  555. else
  556. {
  557. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, szEventName);
  558. }
  559. if (hEvent != NULL)
  560. {
  561. TRACE((DEBUG_TSHRSRV_NORMAL,
  562. "TShrSrv VC: Opened event %S, handle %p\n",
  563. szEventName, hEvent));
  564. // Post the event
  565. if (SetEvent(hEvent))
  566. {
  567. bSuccess = TRUE;
  568. }
  569. else
  570. {
  571. TRACE((DEBUG_TSHRSRV_ERROR,
  572. "TShrSrv VC: Failed to post event %s - error %d\n",
  573. szEventName, GetLastError()));
  574. }
  575. CloseHandle(hEvent);
  576. }
  577. else
  578. {
  579. TRACE((DEBUG_TSHRSRV_ERROR,
  580. "TShrSrv VC: Failed to open event %S, %d\n",
  581. szEventName, GetLastError()));
  582. }
  583. }
  584. return bSuccess;
  585. }
  586. //*************************************************************
  587. //
  588. // OpenPerSessionEvent()
  589. //
  590. // Purpose: Opens an event in session space
  591. // this has to override nt's OpenEvent in order
  592. // to access events in the sessions directory
  593. //
  594. // Yes, we really need to do this ugliness to access
  595. // per session events because OpenEvent opens
  596. // named events from a basedirectory it chooses.
  597. //
  598. // Parameters: (see OpenEvent api)
  599. // dwDesiredAccess - access level
  600. // bInheritHandle
  601. // szEventName - name of the event
  602. //
  603. // Return: Handle to the event
  604. //
  605. //*************************************************************
  606. HANDLE
  607. OpenPerSessionEvent(DWORD dwDesiredAccess, BOOL bInheritHandle,
  608. LPCTSTR szEventName)
  609. {
  610. OBJECT_ATTRIBUTES Obja;
  611. UNICODE_STRING ObjectName;
  612. NTSTATUS Status;
  613. HANDLE Object = NULL;
  614. PWCHAR pstrNewObjName = NULL;
  615. if(szEventName)
  616. {
  617. RtlInitUnicodeString(&ObjectName,szEventName);
  618. InitializeObjectAttributes(
  619. &Obja,
  620. &ObjectName,
  621. (bInheritHandle ? OBJ_INHERIT : 0),
  622. NULL, //root directory
  623. NULL);
  624. Status = NtOpenEvent(
  625. &Object,
  626. dwDesiredAccess,
  627. &Obja
  628. );
  629. if ( !NT_SUCCESS(Status) ) {
  630. TRACE((DEBUG_TSHRSRV_ERROR,
  631. "TShrSRV VC: NtOpenEvent failed, status %#x\n",
  632. Status));
  633. SetLastError(Status);
  634. }
  635. return Object;
  636. }
  637. else
  638. {
  639. return NULL;
  640. }
  641. }
  642. //*************************************************************
  643. //
  644. // TSrvAllocVCContext()
  645. //
  646. // Purpose: Allocates the necessary amount of storage for the
  647. // Addin list, plus the amount specified by extraBytes.
  648. // The Addin list is copied in at an offset of extraBytes
  649. // from the start of the buffer.
  650. //
  651. // Parameters: extraBytes - extra space to alloc
  652. // OUT numAddins - number of TSRV_VC_ADDIN structures allocated
  653. //
  654. // Return: the result of the allocation call
  655. //
  656. //*************************************************************
  657. LPVOID
  658. TSrvAllocVCContext(UINT extraBytes, OUT UINT * pNumAddins)
  659. {
  660. UINT addinsSize;
  661. LPVOID pMem;
  662. TRACE((DEBUG_TSHRSRV_FLOW,
  663. "TShrSRV VC: Enter TSrvAllocVCContext\n"));
  664. EnterCriticalSection(&g_TSrvVCCritSect);
  665. //
  666. // If we still need to set up the registry change notification, then
  667. // we may have missed a change in the addins config. This call will also
  668. // try again to set up the change notification.
  669. //
  670. if (g_bNeedToSetRegNotify)
  671. {
  672. TRACE((DEBUG_TSHRSRV_WARN,
  673. "TShrSRV VC: TSrvAllocVCContext: Need to read addins and "
  674. "set up registry change notification\n"));
  675. TSrvReadVCAddins();
  676. }
  677. addinsSize = g_AddinCount * sizeof(TSRV_VC_ADDIN);
  678. TRACE((DEBUG_TSHRSRV_NORMAL,
  679. "TShrSRV VC: Allocating context for %u addins @ %d each + %u extra\n",
  680. g_AddinCount, sizeof(TSRV_VC_ADDIN), extraBytes));
  681. pMem = TSHeapAlloc(HEAP_ZERO_MEMORY,
  682. addinsSize + extraBytes,
  683. TS_HTAG_TSS_WSXCONTEXT);
  684. if (pMem)
  685. {
  686. //
  687. // Great, the alloc succeeded. Now copy over the addins info.
  688. //
  689. TRACE((DEBUG_TSHRSRV_NORMAL,
  690. "TShrSRV VC: Context allocated at 0x%x for %u bytes\n",
  691. pMem, addinsSize + extraBytes));
  692. // g_pAddin will be null if there were no addins in the registry
  693. if (g_pAddin)
  694. {
  695. memcpy(((LPBYTE)pMem) + extraBytes, g_pAddin, addinsSize);
  696. }
  697. *pNumAddins = g_AddinCount;
  698. }
  699. else
  700. {
  701. //
  702. // The alloc failed, so indicate that zero structures were copied
  703. //
  704. TRACE((DEBUG_TSHRSRV_ERROR,
  705. "TShrSRV VC: Context allocation FAILED for %d bytes\n",
  706. addinsSize + extraBytes));
  707. *pNumAddins = 0;
  708. }
  709. LeaveCriticalSection(&g_TSrvVCCritSect);
  710. TRACE((DEBUG_TSHRSRV_FLOW,
  711. "TShrSRV VC: Leave TSrvAllocVCContext - %p\n", pMem));
  712. return(pMem);
  713. }
  714. //*************************************************************
  715. //
  716. // TSrvReadVCAddins()
  717. //
  718. // Purpose: Reads the Addins subkey from the registry into memory.
  719. // New WinStations grab a copy of this data when they start up.
  720. // We expect to be called once at start of day, then again
  721. // each time a change is detected in the Addins subkey.
  722. //
  723. // NB - Caller must hold the g_TSrvVCCritSect
  724. //
  725. // Parameters: none
  726. //
  727. // Return: ERROR_SUCCESS if successful;
  728. // an error code from winerror.h if not.
  729. //
  730. //*************************************************************
  731. LONG
  732. TSrvReadVCAddins(VOID)
  733. {
  734. ULONG rc;
  735. PTSRV_VC_ADDIN pNewAddins = NULL;
  736. DWORD newAddinCount = 0;
  737. HKEY hKeySub = NULL;
  738. DWORD Index;
  739. UINT SavedCount = 0;
  740. WCHAR SubKeyName[TSRV_VC_ADDIN_SUBKEY_LEN];
  741. TCHAR AddinName[TSRV_VC_ADDIN_NAMELEN];
  742. FILETIME FileTime;
  743. DWORD Type;
  744. DWORD AddinType, dwRCPersistent;
  745. BOOL bRCPersistent = FALSE; // false by default - optional value
  746. DWORD cb;
  747. UINT i;
  748. BOOL dupFound;
  749. TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvReadVCAddins\n"));
  750. if (!g_hAddinRegKey)
  751. {
  752. TRACE((DEBUG_TSHRSRV_WARN,
  753. "TShrSRV VC: Tried to read VC addins with g_hAddinRegKey = NULL\n"));
  754. rc = ERROR_FILE_NOT_FOUND;
  755. goto EXIT_POINT;
  756. }
  757. //
  758. // Query the number of subkeys
  759. //
  760. rc = RegQueryInfoKey(g_hAddinRegKey, NULL, NULL, NULL, &newAddinCount,
  761. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  762. if (rc != ERROR_SUCCESS)
  763. {
  764. TRACE((DEBUG_TSHRSRV_WARN,
  765. "TShrSRV VC: Failed to query key info, rc %d, count %d\n",
  766. rc, newAddinCount));
  767. goto EXIT_POINT;
  768. }
  769. if (newAddinCount != 0)
  770. {
  771. //
  772. // Allocate memory to hold information from all subkeys
  773. //
  774. TRACE((DEBUG_TSHRSRV_NORMAL,
  775. "TShrSRV VC: %d addin(s), %d bytes\n",
  776. newAddinCount, newAddinCount * sizeof(*pNewAddins)));
  777. pNewAddins = TSHeapAlloc(HEAP_ZERO_MEMORY,
  778. newAddinCount * sizeof(*pNewAddins),
  779. TS_HTAG_VC_ADDINS);
  780. if (pNewAddins == NULL)
  781. {
  782. TRACE((DEBUG_TSHRSRV_ERROR,
  783. "TShrSRV VC: Failed to alloc %d bytes for Addins\n",
  784. newAddinCount * sizeof(*pNewAddins)));
  785. goto EXIT_POINT;
  786. }
  787. //
  788. // Enumerate the sub-keys
  789. //
  790. for (Index = 0, SavedCount = 0; Index < newAddinCount; Index++)
  791. {
  792. //
  793. // If there is a sub key open, it's left over from a previous loop
  794. // iteration, so close it now
  795. //
  796. if (hKeySub)
  797. {
  798. TRACE((DEBUG_TSHRSRV_NORMAL,
  799. "TShrSRV VC: Close sub key %p\n", hKeySub));
  800. RegCloseKey(hKeySub);
  801. hKeySub = NULL;
  802. }
  803. //
  804. // Enumerate the next key
  805. //
  806. TRACE((DEBUG_TSHRSRV_DEBUG,
  807. "TShrSRV VC: Enumerate key %d\n", Index));
  808. cb = TSRV_VC_ADDIN_SUBKEY_LEN;
  809. rc = RegEnumKeyEx(g_hAddinRegKey, Index, SubKeyName, &cb,
  810. NULL, NULL, NULL, &FileTime);
  811. if (rc != ERROR_SUCCESS)
  812. {
  813. if (rc == ERROR_MORE_DATA)
  814. {
  815. TRACE((DEBUG_TSHRSRV_ERROR,
  816. "TShrSRV VC: Subkey name too long, skipping\n"));
  817. continue;
  818. }
  819. else if (rc == ERROR_NO_MORE_ITEMS)
  820. {
  821. TRACE((DEBUG_TSHRSRV_NORMAL,
  822. "TShrSRV VC: End of enumeration\n"));
  823. }
  824. else
  825. {
  826. TRACE((DEBUG_TSHRSRV_ERROR,
  827. "TShrSRV VC: Failed to enumerate key %d, rc %d\n",
  828. Index, rc));
  829. }
  830. break;
  831. }
  832. //
  833. // Open the subkey
  834. //
  835. rc = RegOpenKeyEx(g_hAddinRegKey, SubKeyName, 0, KEY_READ, &hKeySub);
  836. if (rc != ERROR_SUCCESS)
  837. {
  838. TRACE((DEBUG_TSHRSRV_WARN,
  839. "TShrSRV VC: Failed to open key %s, rc %d\n",
  840. SubKeyName, rc));
  841. continue;
  842. }
  843. //
  844. // Read the Addin name
  845. //
  846. cb = TSRV_VC_ADDIN_NAMELEN * sizeof(TCHAR);
  847. rc = RegQueryValueEx(hKeySub, TSRV_VC_NAME, NULL, &Type,
  848. (LPBYTE)AddinName, &cb);
  849. if ((rc != ERROR_SUCCESS) || (Type != REG_SZ) || (cb == 0))
  850. {
  851. TRACE((DEBUG_TSHRSRV_WARN,
  852. "TShrSRV VC: Failed to read addin name rc %d, type %d, cb %d\n",
  853. rc, Type, cb));
  854. continue;
  855. }
  856. //
  857. // Read the Addin type
  858. //
  859. cb = sizeof(AddinType);
  860. rc = RegQueryValueEx(hKeySub, TSRV_VC_TYPE, NULL, &Type,
  861. (LPBYTE)(&AddinType), &cb);
  862. if ((rc != ERROR_SUCCESS) || (Type != REG_DWORD))
  863. {
  864. TRACE((DEBUG_TSHRSRV_WARN,
  865. "TShrSRV VC: Failed to read addin type rc %d, type %d, cb %d\n",
  866. rc, Type, cb));
  867. continue;
  868. }
  869. //
  870. // Read the Shadow Persistent value
  871. //
  872. cb = sizeof(dwRCPersistent);
  873. rc = RegQueryValueEx(hKeySub, TSRV_VC_SHADOW, NULL, &Type,
  874. (LPBYTE)(&dwRCPersistent), &cb);
  875. if ((rc == ERROR_SUCCESS) &&
  876. (Type == REG_DWORD) &&
  877. (dwRCPersistent != 0))
  878. {
  879. bRCPersistent = TRUE;
  880. }
  881. //
  882. // Check for duplicates
  883. //
  884. TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV VC: Check for dups of %S\n", AddinName));
  885. dupFound = FALSE;
  886. for (i = 0; i < SavedCount; i++) {
  887. TRACE((DEBUG_TSHRSRV_DEBUG,
  888. "TShrSRV VC: Test Addin %d (%S)\n",
  889. i, pNewAddins[i].Name));
  890. if (0 == _tcscmp(pNewAddins[i].Name, AddinName)) {
  891. TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Duplicate addin name %S (%d)\n",
  892. AddinName, i));
  893. //
  894. // We can't directly do a continue here, because we're in
  895. // an inner loop. So set a flag and do it outside.
  896. //
  897. dupFound = TRUE;
  898. break;
  899. }
  900. }
  901. if (dupFound) {
  902. // Now we can do the continue.
  903. continue;
  904. }
  905. //
  906. // Check for supported addin types
  907. //
  908. if ((AddinType == TSRV_VC_TYPE_KERNEL_SYSTEM) ||
  909. (AddinType == TSRV_VC_TYPE_USER_SESSION))
  910. {
  911. TRACE((DEBUG_TSHRSRV_DEBUG,
  912. "TShrSRV VC: Supported addin type %d\n", AddinType));
  913. }
  914. else if ((AddinType == TSRV_VC_TYPE_KERNEL_SESSION) ||
  915. (AddinType == TSRV_VC_TYPE_USER_SESSION))
  916. {
  917. TRACE((DEBUG_TSHRSRV_ERROR,
  918. "TShrSRV VC: Unsupported addin type %d\n", AddinType));
  919. continue;
  920. }
  921. else
  922. {
  923. TRACE((DEBUG_TSHRSRV_ERROR,
  924. "TShrSRV VC: Unknown addin type %d\n", AddinType));
  925. continue;
  926. }
  927. //
  928. // Save all pertinent information.
  929. //
  930. _tcscpy(pNewAddins[SavedCount].Name, AddinName);
  931. pNewAddins[SavedCount].Type = AddinType;
  932. pNewAddins[SavedCount].hDevice = INVALID_HANDLE_VALUE;
  933. pNewAddins[SavedCount].bShadowPersistent = bRCPersistent;
  934. TRACE((DEBUG_TSHRSRV_NORMAL,
  935. "TShrSRV VC: Addin %d, %S, type %d\n",
  936. SavedCount, AddinName, AddinType));
  937. SavedCount++;
  938. } // for
  939. }
  940. else
  941. {
  942. // We have no addins in the registry. SavedCount and pNewAddins are
  943. // already initialized for this case.
  944. TRACE((DEBUG_TSHRSRV_WARN,
  945. "TShrSRV VC: No addins found in registry\n"));
  946. SavedCount = 0;
  947. pNewAddins = NULL;
  948. }
  949. //
  950. // It's now safe to free the old Addins information and update the globals.
  951. //
  952. if (g_pAddin != NULL)
  953. {
  954. TSHeapFree(g_pAddin);
  955. }
  956. g_pAddin = pNewAddins;
  957. g_AddinCount = SavedCount;
  958. //
  959. // Now set up the registry change notification so that we are notified
  960. // next time the registered addins change.
  961. //
  962. TSrvSetAddinChangeNotification();
  963. TRACE((DEBUG_TSHRSRV_NORMAL,
  964. "TShrSRV VC: Saved %d addin(s)\n", SavedCount));
  965. EXIT_POINT:
  966. //
  967. // Close the sub key, if there is still one open
  968. //
  969. if (hKeySub)
  970. {
  971. TRACE((DEBUG_TSHRSRV_NORMAL,
  972. "TShrSRV VC: Close sub key %p\n", hKeySub));
  973. RegCloseKey(hKeySub);
  974. }
  975. TRACE((DEBUG_TSHRSRV_FLOW,
  976. "TShrSRV VC: Leave TSrvReadVCAddins - %lu\n", rc));
  977. return(rc);
  978. }
  979. //*************************************************************
  980. //
  981. // TSrvGotAddinChangedEvent()
  982. //
  983. // Purpose: Does the necessary actions when TSrvMainThread gets
  984. // a notification that the Addins registry key has changed.
  985. // Called on the TSrvMainThread thread.
  986. //
  987. // Parameters: None.
  988. //
  989. // Return: None.
  990. //
  991. // History: 05-03-99 a-oking Created
  992. //
  993. //*************************************************************
  994. VOID
  995. TSrvGotAddinChangedEvent(void)
  996. {
  997. TRACE((DEBUG_TSHRSRV_FLOW,
  998. "TShrSRV VC: TSrvGotAddinChangedEvent entry\n"));
  999. EnterCriticalSection(&g_TSrvVCCritSect);
  1000. //
  1001. // We're here because the notify event just popped, so
  1002. // we set this flag to get it set up again.
  1003. //
  1004. g_bNeedToSetRegNotify = TRUE;
  1005. TSrvReadVCAddins();
  1006. LeaveCriticalSection(&g_TSrvVCCritSect);
  1007. TRACE((DEBUG_TSHRSRV_FLOW,
  1008. "TShrSRV VC: TSrvGotAddinChangedEvent exit\n"));
  1009. }
  1010. //*************************************************************
  1011. //
  1012. // TSrvSetAddinChangeNotification()
  1013. //
  1014. // Purpose: Sets up a notification event that will pop if
  1015. // anything in the Addins registry key changes.
  1016. //
  1017. // NB - Caller must hold the g_TSrvVCCritSect
  1018. //
  1019. // Parameters: None.
  1020. //
  1021. // Return: TRUE if successful
  1022. // FALSE if not
  1023. //
  1024. // History: 05-03-99 a-oking Created
  1025. //
  1026. //*************************************************************
  1027. BOOL
  1028. TSrvSetAddinChangeNotification(void)
  1029. {
  1030. LONG rc;
  1031. BOOL fSuccess;
  1032. static ULONG count = 0;
  1033. TRACE((DEBUG_TSHRSRV_FLOW,
  1034. "TShrSRV VC: TSrvSetAddinChangeNotification entry\n"));
  1035. if (g_hAddinRegKey && g_hVCAddinChangeEvent && g_bNeedToSetRegNotify)
  1036. {
  1037. rc = RegNotifyChangeKeyValue(g_hAddinRegKey,
  1038. TRUE,
  1039. REG_NOTIFY_CHANGE_NAME
  1040. | REG_NOTIFY_CHANGE_LAST_SET,
  1041. g_hVCAddinChangeEvent,
  1042. TRUE);
  1043. if (ERROR_SUCCESS == rc)
  1044. {
  1045. TRACE((DEBUG_TSHRSRV_NORMAL,
  1046. "TShrSRV VC: Set up VC Addin change notification OK\n"));
  1047. g_bNeedToSetRegNotify = FALSE;
  1048. }
  1049. else
  1050. {
  1051. TRACE((DEBUG_TSHRSRV_ERROR,
  1052. "TShrSRV VC: Failed to set up VC Addin change "
  1053. "notification - 0x%x\n", rc));
  1054. }
  1055. }
  1056. else
  1057. {
  1058. TRACE((DEBUG_TSHRSRV_ERROR,
  1059. "TShrSRV VC: Couldn't set up VC Addin change notification - "
  1060. "g_hAddinRegKey %p, g_hVCAddinChangeEvent %p\n",
  1061. g_hAddinRegKey, g_hVCAddinChangeEvent));
  1062. }
  1063. fSuccess = !g_bNeedToSetRegNotify;
  1064. TRACE((DEBUG_TSHRSRV_FLOW,
  1065. "TShrSRV VC: TSrvSetAddinChangeNotification exit - 0x%x\n", fSuccess));
  1066. return(fSuccess);
  1067. }