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.

1389 lines
58 KiB

  1. /****************************************************************************/
  2. // nwdwapi.c
  3. //
  4. // RDPWD general header
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #define pTRCWd pTSWd
  11. #define TRC_FILE "nwdwapi"
  12. #include <adcg.h>
  13. #include <nwdwapi.h>
  14. #include <nwdwioct.h>
  15. #include <nwdwint.h>
  16. #include <aschapi.h>
  17. #include <anmapi.h>
  18. #include <asmapi.h>
  19. #include <asmint.h>
  20. #include <mcsioctl.h>
  21. #include <tsrvexp.h>
  22. #include "domain.h"
  23. /****************************************************************************/
  24. /* Name: DriverEntry */
  25. /* */
  26. /* Purpose: Default driver entry point */
  27. /* */
  28. /* Returns: NTSTATUS value. */
  29. /* */
  30. /* Params: INOUT pContext - Pointer to the SD context structure */
  31. /* IN fLoad - TRUE: load driver */
  32. /* FALSE: unload driver */
  33. /****************************************************************************/
  34. #ifdef _HYDRA_
  35. const PWCHAR ModuleName = L"rdpwd";
  36. NTSTATUS ModuleEntry(PSDCONTEXT pContext, BOOLEAN fLoad)
  37. #else
  38. NTSTATUS DriverEntry(PSDCONTEXT pContext, BOOLEAN fLoad)
  39. #endif
  40. {
  41. NTSTATUS rc;
  42. if (fLoad)
  43. {
  44. rc = WDWLoad(pContext);
  45. }
  46. else
  47. {
  48. rc = WDWUnload(pContext);
  49. }
  50. return(rc);
  51. }
  52. /****************************************************************************/
  53. /* Name: WD_Open */
  54. /* */
  55. /* Purpose: Open and initialize winstation driver */
  56. /* */
  57. /* Returns: NTSTATUS value. */
  58. /* */
  59. /* Params: IN pTSWd - Points to wd data structure */
  60. /* INOUT pSdOpen - Points to the parameter structure SD_OPEN */
  61. /* */
  62. /* Operation: Sanity check the details of the Open packet. */
  63. /* Save the address of the protocol counters struct. */
  64. /* */
  65. /****************************************************************************/
  66. NTSTATUS WD_Open(PTSHARE_WD pTSWd, PSD_OPEN pSdOpen)
  67. {
  68. NTSTATUS rc = STATUS_SUCCESS;
  69. MCSError MCSErr;
  70. DC_BEGIN_FN("WD_Open");
  71. /************************************************************************/
  72. /* None of the info in the SD_OPEN is of great relevance to us, but we */
  73. /* do some sanity checks that we aren't being confused with an ICA WD. */
  74. /************************************************************************/
  75. TRC_ASSERT((pSdOpen->WdConfig.WdFlag & WDF_TSHARE),
  76. (TB,"Not a TShare WD, %x", pSdOpen->WdConfig.WdFlag));
  77. pTSWd->StackClass = pSdOpen->StackClass;
  78. TRC_ALT((TB,"Stack class (%ld)", pSdOpen->StackClass));
  79. pTSWd->pProtocolStatus = pSdOpen->pStatus;
  80. TRC_DBG((TB, "Protocol counters are at %p", pTSWd->pProtocolStatus));
  81. /************************************************************************/
  82. /* Save our name for later use */
  83. /************************************************************************/
  84. memcpy(pTSWd->DLLName, pSdOpen->WdConfig.WdDLL, sizeof(DLLNAME));
  85. TRC_NRM((TB, "Our name is >%S<", pTSWd->DLLName));
  86. /************************************************************************/
  87. /* Save off the connection name. This is the registry key to look */
  88. /* under for config settings. */
  89. /************************************************************************/
  90. memcpy(pTSWd->WinStationRegName,
  91. pSdOpen->WinStationRegName,
  92. sizeof(pTSWd->WinStationRegName));
  93. /************************************************************************/
  94. /* Save the scheduling timings. These get copied later into */
  95. /* schNormalPeriod and schTurboPeriod respectively. */
  96. /************************************************************************/
  97. pTSWd->outBufDelay = pSdOpen->PdConfig.Create.OutBufDelay;
  98. pTSWd->interactiveDelay = pSdOpen->PdConfig.Create.InteractiveDelay;
  99. /************************************************************************/
  100. /* Indicate that we do not want ICADD managing outbuf headers/trailers */
  101. /************************************************************************/
  102. pSdOpen->SdOutBufHeader = 0;
  103. pSdOpen->SdOutBufTrailer = 0;
  104. /************************************************************************/
  105. /* Initalize MCS */
  106. /************************************************************************/
  107. MCSErr = MCSInitialize(pTSWd->pContext, pSdOpen, &pTSWd->hDomainKernel,
  108. pTSWd->pSmInfo);
  109. if (MCSErr != MCS_NO_ERROR)
  110. {
  111. TRC_ERR((TB, "MCSInitialize returned %d", MCSErr));
  112. return STATUS_INSUFFICIENT_RESOURCES;
  113. }
  114. /************************************************************************/
  115. /* We have not yet initialized virtual channels */
  116. /************************************************************************/
  117. pTSWd->bVirtualChannelBound = FALSE;
  118. pTSWd->_pRecvDecomprContext2 = NULL;
  119. pTSWd->_pVcDecomprReassemblyBuf = NULL;
  120. #ifdef DC_DEBUG
  121. /************************************************************************/
  122. /* There's no trace config yet */
  123. /************************************************************************/
  124. pTSWd->trcShmNeedsUpdate = FALSE;
  125. // // TODO: Need to fix termsrv so that it enabled tracing on shadow &
  126. // // primary stacks. For now, set it to standard alert level tracing.
  127. // if ((pTSWd->StackClass == Stack_Primary) ||
  128. // (pTSWd->StackClass == Stack_Console))
  129. // {
  130. // SD_IOCTL SdIoctl;
  131. // ICA_TRACE traceSettings;
  132. //
  133. // traceSettings.fDebugger = TRUE;
  134. // traceSettings.fTimestamp = TRUE;
  135. // traceSettings.TraceClass = 0x10000008;
  136. // traceSettings.TraceEnable = 0x000000cc;
  137. // memset(traceSettings.TraceOption, 0, sizeof(traceSettings.TraceOption));
  138. //
  139. // SdIoctl.IoControlCode = IOCTL_ICA_SET_TRACE; // IN
  140. // SdIoctl.InputBuffer = &traceSettings; // IN OPTIONAL
  141. // SdIoctl.InputBufferLength = sizeof(traceSettings); // IN
  142. // SdIoctl.OutputBuffer = NULL; // OUT OPTIONAL
  143. // SdIoctl.OutputBufferLength = 0; // OUT
  144. // SdIoctl.BytesReturned = 0; // OUT
  145. //
  146. // TRC_UpdateConfig(pTSWd, &SdIoctl);
  147. // }
  148. #endif /* DC_DEBUG */
  149. /************************************************************************/
  150. /* Read registry settings.
  151. /************************************************************************/
  152. if (COM_OpenRegistry(pTSWd, L""))
  153. {
  154. /************************************************************************/
  155. /* Read the flow control sleep interval.
  156. /************************************************************************/
  157. COM_ReadProfInt32(pTSWd,
  158. WD_FLOWCONTROL_SLEEPINTERVAL,
  159. WD_FLOWCONTROL_SLEEPINTERVAL_DFLT,
  160. &(pTSWd->flowControlSleepInterval));
  161. TRC_NRM((TB, "Flow control sleep interval %ld",
  162. pTSWd->flowControlSleepInterval));
  163. #ifdef DC_DEBUG
  164. #ifndef NO_MEMORY_CHECK
  165. /************************************************************************/
  166. /* Decide whether to break on memory leaks
  167. /************************************************************************/
  168. COM_ReadProfInt32(pTSWd,
  169. WD_BREAK_ON_MEMORY_LEAK,
  170. WD_BREAK_ON_MEMORY_LEAK_DFLT,
  171. &(pTSWd->breakOnLeak));
  172. TRC_NRM((TB, "Break on memory leak ? %s",
  173. pTSWd->breakOnLeak ? "yes" : "no"));
  174. #endif
  175. #endif /* DC_DEBUG */
  176. }
  177. COM_CloseRegistry(pTSWd);
  178. // Establish full connectivity (sans encryption) for passthru stacks.
  179. // The encrypted context will come up later if supported by the requesting
  180. // server. Hang the output user data off of our context so it can be
  181. // retrieved later by rpdwsx.
  182. if (pTSWd->StackClass == Stack_Passthru) {
  183. PUSERDATAINFO pUserData;
  184. ULONG OutputLength;
  185. // Because WDW_OnSMConnecting doesn't check the length of the
  186. // ioctl output buffer and doesn't return any error status, we
  187. // have to allocate enough space at the first try.
  188. // Use 128 as it is the amount used in rdpwsx/TSrvInitWDConnectInfo.
  189. OutputLength = 128;
  190. pUserData = (PUSERDATAINFO) COM_Malloc(OutputLength /*MIN_USERDATAINFO_SIZE*/) ;
  191. if (pUserData != NULL) {
  192. SD_IOCTL SdIoctl;
  193. memset(&SdIoctl, 0, sizeof(SdIoctl));
  194. memset(pUserData, 0, OutputLength /*MIN_USERDATAINFO_SIZE*/);
  195. pUserData->cbSize = OutputLength /*MIN_USERDATAINFO_SIZE*/;
  196. SdIoctl.IoControlCode = IOCTL_TSHARE_SHADOW_CONNECT;
  197. SdIoctl.OutputBuffer = pUserData;
  198. SdIoctl.OutputBufferLength = OutputLength /*MIN_USERDATAINFO_SIZE*/;
  199. rc = WDWShadowConnect(pTSWd, &SdIoctl) ;
  200. TRC_ALT((TB, "Passthru stack connected: rc=%lx", rc));
  201. if (NT_SUCCESS(rc)) {
  202. pTSWd->pUserData = pUserData;
  203. }
  204. }
  205. else {
  206. TRC_ERR((TB, "Passthru stack unable to allocate output user data"));
  207. rc = STATUS_NO_MEMORY;
  208. }
  209. }
  210. DC_END_FN();
  211. return rc;
  212. } /* WD_Open */
  213. /****************************************************************************/
  214. /* Name: WD_Close */
  215. /* */
  216. /* Purpose: Close winstation driver */
  217. /* */
  218. /* Params: IN pTSWd - Points to wd data structure */
  219. /* INOUT pSdClose - Points to the parameter structure SD_CLOSE */
  220. /****************************************************************************/
  221. NTSTATUS WD_Close(PTSHARE_WD pTSWd, PSD_CLOSE pSdClose)
  222. {
  223. DC_BEGIN_FN("WD_Close");
  224. TRC_NRM((TB, "WD_Close on WD %p", pTSWd));
  225. // Make sure that Domain.StatusDead is consistent with TSWd.dead
  226. pTSWd->dead = TRUE;
  227. ((PDomain)(pTSWd->hDomainKernel))->StatusDead = TRUE;
  228. pSdClose->SdOutBufHeader = 0; // OUT: returned by sd
  229. pSdClose->SdOutBufTrailer = 0; // OUT: returned by sd
  230. // Clean up MCS.
  231. if (pTSWd->hDomainKernel != NULL)
  232. MCSCleanup(&pTSWd->hDomainKernel);
  233. // Opportunity to clean up if anything has been left lying around.
  234. if (pTSWd->dcShare != NULL) {
  235. if (pTSWd->shareClassInit) {
  236. // Terminate the Share Class.
  237. TRC_NRM((TB, "Terminate Share Class"));
  238. WDWTermShareClass(pTSWd);
  239. }
  240. // It's OK to free the Share object - this is allocated out of
  241. // system memory and is therefore accessible to WD_Close.
  242. TRC_NRM((TB, "Delete Share object"));
  243. WDWDeleteShareClass(pTSWd);
  244. }
  245. // Terminate SM.
  246. if (pTSWd->pSmInfo != NULL) {
  247. TRC_NRM((TB, "Terminate SM"));
  248. SM_Term(pTSWd->pSmInfo);
  249. }
  250. // Clean up protocol stats pointer. NOTE: It's a pointer to TermDD's
  251. // memory - we should not attempt to free it!
  252. pTSWd->pProtocolStatus = NULL;
  253. // Clean up the MPPC compression context and buffer, if allocated.
  254. // Note that both buffers are concatenated into one allocation
  255. // starting at pMPPCContext.
  256. if (pTSWd->pMPPCContext != NULL) {
  257. COM_Free(pTSWd->pMPPCContext);
  258. pTSWd->pMPPCContext = NULL;
  259. pTSWd->pCompressBuffer = NULL;
  260. }
  261. // Clean up the decompression context buffer if allocated
  262. if( pTSWd->_pRecvDecomprContext2) {
  263. COM_Free( pTSWd->_pRecvDecomprContext2);
  264. pTSWd->_pRecvDecomprContext2 = NULL;
  265. }
  266. // Clean up the decompression reassembly buffer if allocated
  267. if(pTSWd->_pVcDecomprReassemblyBuf) {
  268. COM_Free(pTSWd->_pVcDecomprReassemblyBuf);
  269. pTSWd->_pVcDecomprReassemblyBuf = NULL;
  270. }
  271. // Set compression state to default.
  272. pTSWd->bCompress = FALSE;
  273. // Clean up shadow buffers if allocated.
  274. if (pTSWd->pShadowInfo != NULL) {
  275. COM_Free(pTSWd->pShadowInfo);
  276. pTSWd->pShadowInfo = NULL;
  277. }
  278. if (pTSWd->pShadowCert != NULL) {
  279. TRC_NRM((TB, "Free pShadowCert"));
  280. COM_Free(pTSWd->pShadowCert);
  281. pTSWd->pShadowCert = NULL;
  282. }
  283. if (pTSWd->pShadowRandom != NULL) {
  284. TRC_NRM((TB, "Free pShadowRandom"));
  285. COM_Free(pTSWd->pShadowRandom);
  286. pTSWd->pShadowRandom = NULL;
  287. }
  288. if (pTSWd->pUserData != NULL) {
  289. TRC_NRM((TB, "Free pUserData"));
  290. COM_Free(pTSWd->pUserData);
  291. pTSWd->pUserData = NULL;
  292. }
  293. // Free any shadow hotkey processing structures. Note that we don't free
  294. // pWd->pKbdTbl because we didn't allocate it!
  295. if (pTSWd->pgafPhysKeyState != NULL) {
  296. COM_Free(pTSWd->pgafPhysKeyState);
  297. pTSWd->pgafPhysKeyState = NULL;
  298. }
  299. if (pTSWd->pKbdLayout != NULL) {
  300. COM_Free(pTSWd->pKbdLayout);
  301. pTSWd->pKbdLayout = NULL;
  302. }
  303. if (pTSWd->gpScancodeMap != NULL) {
  304. COM_Free(pTSWd->gpScancodeMap);
  305. pTSWd->gpScancodeMap = NULL;
  306. }
  307. // Free the InfoPkt.
  308. if (pTSWd->pInfoPkt != NULL) {
  309. COM_Free(pTSWd->pInfoPkt);
  310. pTSWd->pInfoPkt = NULL;
  311. }
  312. #ifdef DC_DEBUG
  313. #ifndef NO_MEMORY_CHECK
  314. // Check for un-freed memory.
  315. if (pTSWd->memoryHeader.pNext != NULL) {
  316. PMALLOC_HEADER pNext;
  317. TRC_ERR((TB, "Unfreed memory"));
  318. pNext = pTSWd->memoryHeader.pNext;
  319. while (pNext != NULL) {
  320. TRC_ERR((TB, "At %#p, len %d, caller %#p",
  321. pNext, pNext->length, pNext->pCaller));
  322. pNext = pNext->pNext;
  323. }
  324. if (pTSWd->breakOnLeak)
  325. DbgBreakPoint();
  326. }
  327. #endif /* NO_MEMORY_CHECK */
  328. #endif /* DC_DEBUG */
  329. DC_END_FN();
  330. return STATUS_SUCCESS;
  331. } /* WD_Close */
  332. /****************************************************************************/
  333. /* Name: WD_ChannelWrite */
  334. /* */
  335. /* Purpose: Handle channel writing (virtual channel) */
  336. /****************************************************************************/
  337. NTSTATUS WD_ChannelWrite(PTSHARE_WD pTSWd, PSD_CHANNELWRITE pSdChannelWrite)
  338. {
  339. NTSTATUS status = STATUS_SUCCESS;
  340. PVOID pBuffer;
  341. UINT16 MCSChannelID;
  342. BOOL bRc;
  343. CHANNEL_PDU_HEADER UNALIGNED *pHdr;
  344. PBYTE pSrc;
  345. unsigned dataLeft;
  346. unsigned thisLength;
  347. unsigned lengthToSend;
  348. UINT16 flags;
  349. PNM_CHANNEL_DATA pChannelData;
  350. UCHAR compressResult = 0;
  351. ULONG CompressedSize = 0;
  352. BOOL fCompressVC;
  353. DWORD ret;
  354. DC_BEGIN_FN("WD_ChannelWrite");
  355. /************************************************************************/
  356. /* Check parameters */
  357. /************************************************************************/
  358. TRC_ASSERT((pTSWd != NULL), (TB,"NULL pTSWd"));
  359. TRC_ASSERT((pSdChannelWrite != NULL), (TB,"NULL pTSdChannelWrite"));
  360. TRC_ASSERT((pSdChannelWrite->ChannelClass == Channel_Virtual),
  361. (TB,"non Virtual Channel, class=%lu", pSdChannelWrite->ChannelClass));
  362. TRC_DBG((TB,
  363. "Received channel write. class %lu, channel %lu, numbytes %lu",
  364. (ULONG)pSdChannelWrite->ChannelClass,
  365. (ULONG)pSdChannelWrite->VirtualClass,
  366. pSdChannelWrite->ByteCount));
  367. /************************************************************************/
  368. /* Don't do this if we're dead */
  369. /************************************************************************/
  370. if (pTSWd->dead)
  371. {
  372. TRC_ALT((TB, "Dead - don't do anything"));
  373. status = STATUS_UNSUCCESSFUL;
  374. DC_QUIT;
  375. }
  376. /************************************************************************/
  377. /* Convert virtual channel ID to MCS channel ID */
  378. /************************************************************************/
  379. MCSChannelID = NM_VirtualChannelToMCS(pTSWd->pNMInfo,
  380. pSdChannelWrite->VirtualClass,
  381. &pChannelData);
  382. if (MCSChannelID == (UINT16) -1)
  383. {
  384. TRC_ERR((TB, "Unsupported virtual channel %d",
  385. pSdChannelWrite->VirtualClass));
  386. status = STATUS_UNSUCCESSFUL;
  387. DC_QUIT;
  388. }
  389. TRC_NRM((TB, "Virtual channel %d = MCS Channel %hx",
  390. pSdChannelWrite->VirtualClass, MCSChannelID));
  391. //
  392. // Check if VC compression is enabled for this channel
  393. //
  394. fCompressVC = ((pChannelData->flags & CHANNEL_OPTION_COMPRESS_RDP) &&
  395. (pTSWd->bCompress) &&
  396. (pTSWd->shadowState == SHADOW_NONE) &&
  397. (pTSWd->bClientSupportsVCCompression));
  398. TRC_NRM((TB,"Virtual Channel %d will be compressed.",
  399. pSdChannelWrite->VirtualClass));
  400. /************************************************************************/
  401. /* Initialize loop variables */
  402. /************************************************************************/
  403. flags = CHANNEL_FLAG_FIRST;
  404. pSrc = pSdChannelWrite->pBuffer;
  405. dataLeft = pSdChannelWrite->ByteCount;
  406. /************************************************************************/
  407. /* Loop through the data */
  408. /************************************************************************/
  409. while (dataLeft > 0)
  410. {
  411. /********************************************************************/
  412. /* Decide how much to send in this chunk */
  413. /********************************************************************/
  414. if (dataLeft > CHANNEL_CHUNK_LENGTH)
  415. {
  416. thisLength = CHANNEL_CHUNK_LENGTH;
  417. }
  418. else
  419. {
  420. thisLength = dataLeft;
  421. flags |= CHANNEL_FLAG_LAST;
  422. }
  423. /********************************************************************/
  424. // If the buffer is not a low prio write, then block right behind the
  425. // rest of the pending buffer allocs until we get a free buffer.
  426. /********************************************************************/
  427. if (!(pSdChannelWrite->fFlags & SD_CHANNELWRITE_LOWPRIO)) {
  428. status = SM_AllocBuffer(pTSWd->pSmInfo,
  429. &pBuffer,
  430. thisLength + sizeof(CHANNEL_PDU_HEADER),
  431. TRUE,
  432. FALSE);
  433. }
  434. /********************************************************************/
  435. // Else if the buffer is a low prio write, then sleep and alloc until
  436. // we get a buffer without blocking. This allows default priority allocs
  437. // that block in SM_AllocBuffer to take precedence.
  438. /********************************************************************/
  439. else {
  440. status = SM_AllocBuffer(pTSWd->pSmInfo,
  441. &pBuffer,
  442. thisLength + sizeof(CHANNEL_PDU_HEADER),
  443. FALSE,
  444. FALSE);
  445. while (status == STATUS_IO_TIMEOUT) {
  446. TRC_NRM((TB, "SM_AllocBuffer would block"));
  447. // Bail out on any failure in this function to prevent an
  448. // infinite loop. STATUS_CTX_CLOSE_PENDING will be returned
  449. // if the connection is being shut down.
  450. ret = IcaFlowControlSleep(pTSWd->pContext,
  451. pTSWd->flowControlSleepInterval);
  452. if (ret == STATUS_SUCCESS) {
  453. status = SM_AllocBuffer(pTSWd->pSmInfo,
  454. &pBuffer,
  455. thisLength + sizeof(CHANNEL_PDU_HEADER),
  456. FALSE,
  457. FALSE);
  458. }
  459. else {
  460. TRC_ALT((TB, "IcaFlowControlSleep failed."));
  461. status = ret;
  462. DC_QUIT;
  463. }
  464. }
  465. }
  466. if (status != STATUS_SUCCESS)
  467. {
  468. TRC_ALT((TB, "Failed to get a %d-byte buffer", thisLength));
  469. // prevent regression, keep original code path
  470. status = STATUS_NO_MEMORY;
  471. DC_QUIT;
  472. }
  473. TRC_NRM((TB, "Buffer (%d bytes) allocated OK", thisLength));
  474. /************************************************************************/
  475. /* Fill in the buffer header */
  476. /************************************************************************/
  477. pHdr = (CHANNEL_PDU_HEADER UNALIGNED *)pBuffer;
  478. pHdr->length = pSdChannelWrite->ByteCount;
  479. pHdr->flags = flags;
  480. /************************************************************************/
  481. /* Copy the data */
  482. /* If compression is enabled, try to compress directly into the outbuf */
  483. /************************************************************************/
  484. CompressedSize=0;
  485. lengthToSend=0;
  486. __try {
  487. if((fCompressVC) &&
  488. (thisLength > WD_MIN_COMPRESS_INPUT_BUF) &&
  489. (thisLength < MAX_COMPRESS_INPUT_BUF))
  490. {
  491. compressResult = WDWCompressToOutbuf(pTSWd,(UCHAR*)pSrc,thisLength,
  492. (UCHAR*)(pHdr+1),&CompressedSize);
  493. if(0 != compressResult)
  494. {
  495. lengthToSend = CompressedSize;
  496. //Update the VC packet header flags with the compression info
  497. pHdr->flags |= ((compressResult & VC_FLAG_COMPRESS_MASK) <<
  498. VC_FLAG_COMPRESS_SHIFT);
  499. }
  500. else
  501. {
  502. TRC_ERR((TB, "SC_CompressToOutbuf failed"));
  503. SM_FreeBuffer(pTSWd->pSmInfo, pBuffer, FALSE);
  504. DC_QUIT;
  505. }
  506. }
  507. else
  508. {
  509. //copy directly
  510. memcpy(pHdr + 1, pSrc, thisLength);
  511. lengthToSend = thisLength;
  512. }
  513. } __except (EXCEPTION_EXECUTE_HANDLER) {
  514. status = GetExceptionCode();
  515. TRC_ERR((TB, "Exception (0x%08lx) copying evil user buffer", status));
  516. SM_FreeBuffer(pTSWd->pSmInfo, pBuffer, FALSE);
  517. DC_QUIT;
  518. }
  519. TRC_NRM((TB, "Copied user buffer"));
  520. /************************************************************************/
  521. /* Send it */
  522. /************************************************************************/
  523. bRc = SM_SendData(pTSWd->pSmInfo, pBuffer,
  524. lengthToSend + sizeof(CHANNEL_PDU_HEADER), TS_LOWPRIORITY,
  525. MCSChannelID, FALSE, RNS_SEC_ENCRYPT, FALSE);
  526. if (!bRc)
  527. {
  528. TRC_ERR((TB, "Failed to send data"));
  529. status = STATUS_UNSUCCESSFUL;
  530. DC_QUIT;
  531. }
  532. TRC_NRM((TB, "Sent a %d-byte chunk, flags %#x", lengthToSend, flags));
  533. /********************************************************************/
  534. /* Set up for next loop */
  535. /********************************************************************/
  536. pSrc += thisLength;
  537. dataLeft -= thisLength;
  538. flags = 0;
  539. }
  540. /************************************************************************/
  541. /* Well, it's gone somwehere. */
  542. /************************************************************************/
  543. TRC_NRM((TB, "Data sent OK"));
  544. DC_EXIT_POINT:
  545. DC_END_FN();
  546. return(status);
  547. } /* WD_ChannelWrite */
  548. /****************************************************************************/
  549. // WDW_OnSMConnecting
  550. //
  551. // Handles a 'connecting' state change callback from SM. This state occurs
  552. // when the network connection is up but security negotiation has not yet
  553. // begun. It is assumed that at this point GCCConferenceCreateResponse will
  554. // be issued. Here we use the user data received from the client to build
  555. // return GCC data in the TShareSRV IOCTL buffer.
  556. /****************************************************************************/
  557. void RDPCALL WDW_OnSMConnecting(
  558. PVOID hWD,
  559. PRNS_UD_SC_SEC pSecData,
  560. PRNS_UD_SC_NET pNetData)
  561. {
  562. PTSHARE_WD pTSWd = (PTSHARE_WD)hWD;
  563. PUSERDATAINFO pOutData;
  564. RNS_UD_SC_CORE coreData;
  565. BOOL error = FALSE;
  566. BYTE *pRgData;
  567. GCCOctetString UNALIGNED *pOctet;
  568. DC_BEGIN_FN("WDW_OnSMConnecting");
  569. // Save the broadcast channel ID for use in shadowing
  570. pTSWd->broadcastChannel = pNetData->MCSChannelID;
  571. /************************************************************************/
  572. /* Locate the output buffer. NB the size of this has already been */
  573. /* checked when we rx'd the IOCtl. */
  574. /************************************************************************/
  575. if (pTSWd->pSdIoctl == NULL)
  576. {
  577. TRC_ERR((TB, "No IOCtl to fill in"));
  578. error = TRUE;
  579. DC_QUIT;
  580. }
  581. // Build the return GCC data required for the IOCTL_TSHARE_CONF_CONNECT
  582. pOutData = pTSWd->pSdIoctl->OutputBuffer;
  583. TRC_DBG((TB, "pOutData at %p", pOutData));
  584. /************************************************************************/
  585. /* Build core user data */
  586. /************************************************************************/
  587. memset(&coreData, 0, sizeof(coreData));
  588. coreData.header.type = RNS_UD_SC_CORE_ID;
  589. coreData.header.length = sizeof(coreData);
  590. coreData.version = RNS_UD_VERSION;
  591. /************************************************************************/
  592. /* Build the user data header and key */
  593. /************************************************************************/
  594. /************************************************************************/
  595. /* Only one piece of user data to fill in, and the following code is */
  596. /* specific to that. */
  597. /************************************************************************/
  598. pOutData->ulUserDataMembers = 1;
  599. pOutData->hDomain = pTSWd->hDomain;
  600. pOutData->version = pTSWd->version;
  601. pOutData->rgUserData[0].key.key_type = GCC_H221_NONSTANDARD_KEY;
  602. /************************************************************************/
  603. /* Put the key octet immediately after the rgUserData. */
  604. /************************************************************************/
  605. pRgData = (BYTE *)(pOutData + 1);
  606. pOctet = &(pOutData->rgUserData[0].key.u.h221_non_standard_id);
  607. pOctet->octet_string = pRgData - (UINT_PTR)pOutData;
  608. pOctet->octet_string_length = sizeof(SERVER_H221_KEY) - 1;
  609. strncpy(pRgData,
  610. (const char*)SERVER_H221_KEY,
  611. sizeof(SERVER_H221_KEY) - 1);
  612. TRC_DBG((TB, "Key octet at %p (offs %p)",
  613. pRgData, pRgData - (UINT_PTR)pOutData));
  614. /************************************************************************/
  615. /* Put the data octet immediately after the key octet. */
  616. /************************************************************************/
  617. pRgData += sizeof(SERVER_H221_KEY) - 1;
  618. pOctet = (GCCOctetString UNALIGNED *)pRgData;
  619. TRC_DBG((TB, "Data octet pointer at %p (offs %p)",
  620. pRgData, pRgData - (UINT_PTR)pOutData));
  621. pOutData->rgUserData[0].octet_string =
  622. (GCCOctetString *)(pRgData - (UINT_PTR)pOutData);
  623. pOctet->octet_string_length = pSecData->header.length +
  624. coreData.header.length +
  625. pNetData->header.length;
  626. pRgData += sizeof(GCCOctetString);
  627. pOctet->octet_string = pRgData - (UINT_PTR)pOutData;
  628. /************************************************************************/
  629. /* Now add the data itself */
  630. /************************************************************************/
  631. TRC_DBG((TB, "Core data at %p (offs %p)",
  632. pRgData, pRgData - (UINT_PTR)pOutData));
  633. memcpy(pRgData, &coreData, coreData.header.length);
  634. pRgData += coreData.header.length;
  635. TRC_DBG((TB, "Net data at %p (offs %p)",
  636. pRgData, pRgData - (UINT_PTR)pOutData));
  637. memcpy(pRgData, pNetData, pNetData->header.length);
  638. pRgData += pNetData->header.length;
  639. /************************************************************************/
  640. /* the security data is moved to the end of user data, fix the client */
  641. /* code accordingly. */
  642. /************************************************************************/
  643. TRC_DBG((TB, "Sec data at %p (offs %p)",
  644. pRgData, pRgData - (UINT_PTR)pOutData));
  645. memcpy(pRgData, pSecData, pSecData->header.length);
  646. pRgData += pSecData->header.length;
  647. /************************************************************************/
  648. /* Finally, set up the number of valid bytes. */
  649. /************************************************************************/
  650. pOutData->cbSize = (ULONG)(UINT_PTR)(pRgData - (UINT_PTR)pOutData);
  651. pTSWd->pSdIoctl->BytesReturned = pOutData->cbSize;
  652. TRC_DBG((TB, "Build %d bytes of returned user data", pOutData->cbSize));
  653. TRC_DATA_NRM("Returned user data", pOutData, pOutData->cbSize);
  654. DC_EXIT_POINT:
  655. if (error)
  656. {
  657. TRC_ERR((TB, "Something went wrong - bring down the WinStation"));
  658. WDW_LogAndDisconnect(pTSWd, TRUE,
  659. Log_RDP_CreateUserDataFailed,
  660. NULL, 0);
  661. }
  662. DC_END_FN();
  663. } /* WDW_OnSMConnecting */
  664. /****************************************************************************/
  665. // WDW_OnSMConnected
  666. //
  667. // Receives connection-completed state change callback from SM.
  668. /****************************************************************************/
  669. void RDPCALL WDW_OnSMConnected(PVOID hWD, unsigned Result)
  670. {
  671. PTSHARE_WD pTSWd = (PTSHARE_WD)hWD;
  672. DC_BEGIN_FN("WDW_OnSMConnected");
  673. TRC_NRM((TB, "Got Connected Notification, rc %lu", Result));
  674. // Unblock the query IOCtl.
  675. pTSWd->connected = TRUE;
  676. KeSetEvent (pTSWd->pConnEvent, EVENT_INCREMENT, FALSE);
  677. // If we failed, get the whole thing winding down straight away.
  678. if (Result != NM_CB_CONN_ERR) {
  679. // If compression is enabled in the net flags, indicate we need to
  680. // do the compression, get the compression level, and allocate
  681. // the context buffers.
  682. if (pTSWd->pInfoPkt->flags & RNS_INFO_COMPRESSION) {
  683. unsigned MPPCCompressionLevel;
  684. pTSWd->pMPPCContext = COM_Malloc(sizeof(SendContext) +
  685. MAX_COMPRESSED_BUFFER);
  686. if (pTSWd->pMPPCContext != NULL) {
  687. pTSWd->pCompressBuffer = (BYTE *)pTSWd->pMPPCContext +
  688. sizeof(SendContext);
  689. // Negotiate down to our highest level of compression support
  690. // if we receive a larger number.
  691. MPPCCompressionLevel =
  692. (pTSWd->pInfoPkt->flags & RNS_INFO_COMPR_TYPE_MASK) >>
  693. RNS_INFO_COMPR_TYPE_SHIFT;
  694. if (MPPCCompressionLevel > PACKET_COMPR_TYPE_MAX)
  695. MPPCCompressionLevel = PACKET_COMPR_TYPE_MAX;
  696. initsendcontext(pTSWd->pMPPCContext, MPPCCompressionLevel);
  697. pTSWd->bCompress = TRUE;
  698. }
  699. else {
  700. TRC_ERR((TB,"Failed allocation of MPPC compression buffers"));
  701. }
  702. }
  703. }
  704. else {
  705. TRC_ERR((TB, "Connection error: winding down now"));
  706. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_ConnectFailed, NULL, 0);
  707. }
  708. if(pTSWd->bCompress)
  709. {
  710. //If we're compressing then allocate a decompression context
  711. //for virtual channels
  712. pTSWd->_pRecvDecomprContext2 = (RecvContext2_8K*)COM_Malloc(sizeof(RecvContext2_8K));
  713. if(pTSWd->_pRecvDecomprContext2)
  714. {
  715. pTSWd->_pRecvDecomprContext2->cbSize = sizeof(RecvContext2_8K);
  716. initrecvcontext(&pTSWd->_DecomprContext1,
  717. (RecvContext2_Generic*)pTSWd->_pRecvDecomprContext2,
  718. PACKET_COMPR_TYPE_8K);
  719. }
  720. }
  721. DC_END_FN();
  722. }
  723. /****************************************************************************/
  724. // WDW_OnSMDisconnected
  725. //
  726. // Handles disconnection state change callback from SM.
  727. /****************************************************************************/
  728. void WDW_OnSMDisconnected(PVOID hWD)
  729. {
  730. PTSHARE_WD pTSWd = (PTSHARE_WD)hWD;
  731. DC_BEGIN_FN("WDW_OnSMDisconnected");
  732. TRC_ALT((TB, "Got Disconnected notification"));
  733. // Unblock the query IOCtl.
  734. pTSWd->connected = FALSE;
  735. KeSetEvent(pTSWd->pConnEvent, EVENT_INCREMENT, FALSE);
  736. DC_END_FN();
  737. }
  738. /****************************************************************************/
  739. // WDW_OnClientDisconnected
  740. //
  741. // Direct-disconnect path called from MCS to set the create event so that
  742. // CSRSS threads waiting for DD completion of DrvConnect or DrvDisconnect
  743. // will be freed when the client goes down. This prevents a timing window for
  744. // a denial-of-service attack where the client connects then closes its socket
  745. // immediately, leaving the DD waiting and the rest of rdpwsx unable
  746. // to complete closing the TermDD handle, until the 60-second create event
  747. // wait completes.
  748. //
  749. // We cannot use WDW_OnSMDisconnected because its being called is dependent
  750. // on the NM and SM state machines and whether they believe the disconnect
  751. // should be called.
  752. /****************************************************************************/
  753. void RDPCALL WDW_OnClientDisconnected(void *pWD)
  754. {
  755. PTSHARE_WD pTSWd = (PTSHARE_WD)pWD;
  756. DC_BEGIN_FN("WDW_OnClientDisconnected");
  757. // Set the disconnect event to cause any waiting connect-time events
  758. // to get a STATUS_TIMEOUT.
  759. KeSetEvent(pTSWd->pClientDisconnectEvent, EVENT_INCREMENT, FALSE);
  760. DC_END_FN();
  761. }
  762. /****************************************************************************/
  763. // WDW_WaitForConnectionEvent
  764. //
  765. // Encapsulates a wait for a connection-time event (e.g. pTSWd->pCreateEvent
  766. // for waiting for the font PDU to release the DD to draw). Adds
  767. // functionality to also wait on a single "client disconnected" event,
  768. // which allows the client disconnection code a single point of signaling
  769. // to shut down the various waits.
  770. /****************************************************************************/
  771. NTSTATUS RDPCALL WDW_WaitForConnectionEvent(
  772. PTSHARE_WD pTSWd,
  773. PKEVENT pEvent,
  774. LONG Timeout)
  775. {
  776. NTSTATUS Status;
  777. PKEVENT Events[2];
  778. DC_BEGIN_FN("WDW_WaitForConnectionEvent");
  779. Events[0] = pEvent;
  780. Events[1] = pTSWd->pClientDisconnectEvent;
  781. Status = IcaWaitForMultipleObjects(pTSWd->pContext, 2, Events,
  782. WaitAny, Timeout);
  783. if (Status == 0) {
  784. // First object (real wait) hit. We just return the status value.
  785. TRC_DBG((TB,"Primary event hit"));
  786. }
  787. else if (Status == 1) {
  788. // Second object (clietn disconnect) hit. Translate to a TIMEOUT
  789. // for the caller, so they clean up properly.
  790. Status = STATUS_TIMEOUT;
  791. TRC_ALT((TB,"Client disconnect event hit"));
  792. }
  793. else {
  794. // Other return (e.g. timeout or close error). Just return it normally.
  795. TRC_DBG((TB,"Other status 0x%X", Status));
  796. }
  797. DC_END_FN();
  798. return Status;
  799. }
  800. /****************************************************************************/
  801. /* Name: WDW_OnDataReceived */
  802. /* */
  803. /* Purpose: Callback when virtual channel data received from Client */
  804. /* */
  805. /* Returns: none */
  806. /* */
  807. /* Params: pTSWd - ptr to WD */
  808. /* pData - ptr to data received */
  809. /* dataLength - length of data received */
  810. /* chnnelID - MCS channel on which data was received */
  811. /* */
  812. /* NOTE: Can be called when dead, in which case our only job should be to */
  813. /* decompress the data to make sure the context remains in sync */
  814. /****************************************************************************/
  815. void WDW_OnDataReceived(PTSHARE_WD pTSWd,
  816. PVOID pData,
  817. unsigned dataLength,
  818. UINT16 channelID)
  819. {
  820. VIRTUALCHANNELCLASS virtualClass;
  821. NTSTATUS status;
  822. PNM_CHANNEL_DATA pChannelData;
  823. CHANNEL_PDU_HEADER UNALIGNED *pHdr;
  824. ULONG thisLength;
  825. unsigned totalLength;
  826. PUCHAR pDataOut;
  827. UCHAR vcCompressFlags;
  828. UCHAR *pDecompOutBuf;
  829. int cbDecompLen;
  830. DC_BEGIN_FN("WDW_OnDataReceived");
  831. /************************************************************************/
  832. /* Translate MCS channel ID to virtual channel ID */
  833. /************************************************************************/
  834. virtualClass = NM_MCSChannelToVirtual(pTSWd->pNMInfo,
  835. channelID,
  836. &pChannelData);
  837. if ((-1 == virtualClass) || (NULL == pChannelData))
  838. {
  839. TRC_ERR((TB,"Invalid MCS Channel ID: %u", channelID));
  840. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_InvalidChannelID,
  841. (BYTE *)pData, dataLength);
  842. DC_QUIT;
  843. }
  844. TRC_ASSERT((virtualClass < 32),
  845. (TB, "Invalid virtual channel %d for MCS channel %hx",
  846. virtualClass, channelID));
  847. TRC_NRM((TB, "Data received on MCS channel %hx, virtual channel %d",
  848. channelID, virtualClass));
  849. TRC_DATA_NRM("Channel data received", pData, dataLength);
  850. if (dataLength >= sizeof(CHANNEL_PDU_HEADER)) {
  851. pHdr = (CHANNEL_PDU_HEADER UNALIGNED *)pData;
  852. totalLength = pHdr->length;
  853. }
  854. else {
  855. TRC_ERR((TB,"Channel data len %u not enough for channel header",
  856. dataLength));
  857. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_VChannelDataTooShort,
  858. (BYTE *)pData, dataLength);
  859. DC_QUIT;
  860. }
  861. //
  862. // Decompress the buffer
  863. //
  864. vcCompressFlags = (pHdr->flags >> VC_FLAG_COMPRESS_SHIFT) &
  865. VC_FLAG_COMPRESS_MASK;
  866. //
  867. // Server only supports 8K decompression context
  868. //
  869. if((pChannelData->flags & CHANNEL_OPTION_COMPRESS_RDP) &&
  870. (vcCompressFlags & PACKET_COMPRESSED))
  871. {
  872. if(!pTSWd->_pRecvDecomprContext2)
  873. {
  874. TRC_ERR((TB,"No decompression context!!!"));
  875. DC_QUIT;
  876. }
  877. if(PACKET_COMPR_TYPE_8K == (vcCompressFlags & PACKET_COMPR_TYPE_MASK))
  878. {
  879. //Decompress channel data
  880. if(vcCompressFlags & PACKET_FLUSHED)
  881. {
  882. initrecvcontext (&pTSWd->_DecomprContext1,
  883. (RecvContext2_Generic*)pTSWd->_pRecvDecomprContext2,
  884. PACKET_COMPR_TYPE_8K);
  885. }
  886. if (decompress((PUCHAR)(pHdr+1),
  887. dataLength - sizeof(CHANNEL_PDU_HEADER),
  888. (vcCompressFlags & PACKET_AT_FRONT),
  889. &pDecompOutBuf,
  890. &cbDecompLen,
  891. &pTSWd->_DecomprContext1,
  892. (RecvContext2_Generic*)pTSWd->_pRecvDecomprContext2,
  893. vcCompressFlags & PACKET_COMPR_TYPE_MASK))
  894. {
  895. //
  896. // Successful decompression
  897. // If we're in the dead state then bail out now as the context
  898. // has been updated
  899. //
  900. if (!pTSWd->dead && (pHdr->flags & CHANNEL_FLAG_SHOW_PROTOCOL))
  901. {
  902. TRC_DBG((TB, "Include VC protocol header (decompressed)"));
  903. //Here is where things get nasty, we need to prepend
  904. //the header to the decompression buffer which lives
  905. //within the decompression context buffer.
  906. //There is no (un-hackerific) way to do this without a
  907. //memcpy, so go ahead and copy using a cached reassembly
  908. //buffer.
  909. if(!pTSWd->_pVcDecomprReassemblyBuf)
  910. {
  911. pTSWd->_pVcDecomprReassemblyBuf=(PUCHAR)
  912. COM_Malloc(WD_VC_DECOMPR_REASSEMBLY_BUF);
  913. }
  914. //Data received cannot decompress to something bigger
  915. //than the chunk length.
  916. TRC_ASSERT((cbDecompLen + sizeof(CHANNEL_PDU_HEADER)) <
  917. WD_VC_DECOMPR_REASSEMBLY_BUF,
  918. (TB,"Reassembly buffer too small"));
  919. if(pTSWd->_pVcDecomprReassemblyBuf &&
  920. ((cbDecompLen + sizeof(CHANNEL_PDU_HEADER)) <
  921. WD_VC_DECOMPR_REASSEMBLY_BUF))
  922. {
  923. memcpy(pTSWd->_pVcDecomprReassemblyBuf, pHdr,
  924. sizeof(CHANNEL_PDU_HEADER));
  925. memcpy(pTSWd->_pVcDecomprReassemblyBuf +
  926. sizeof(CHANNEL_PDU_HEADER),
  927. pDecompOutBuf,
  928. cbDecompLen);
  929. //Hide the internal protocol from the user
  930. pDataOut = pTSWd->_pVcDecomprReassemblyBuf;
  931. thisLength = cbDecompLen + sizeof(CHANNEL_PDU_HEADER);
  932. //Hide the internal protocol fields from the user
  933. ((CHANNEL_PDU_HEADER UNALIGNED *)pDataOut)->flags &=
  934. ~VC_FLAG_PRIVATE_PROTOCOL_MASK;
  935. }
  936. else
  937. {
  938. //Either the allocation failed or the channel
  939. //decompressed to something bigger than a chunk
  940. TRC_ERR((TB,"Can't use reassembly buffer"));
  941. DC_QUIT;
  942. }
  943. }
  944. else if (pTSWd->dead)
  945. {
  946. TRC_NRM((TB,"Decompressed when dead, bailing out"));
  947. DC_QUIT;
  948. }
  949. else
  950. {
  951. TRC_DBG((TB, "Exclude VC protocol header (decompressed)"));
  952. pDataOut = (PUCHAR)pDecompOutBuf;
  953. thisLength = cbDecompLen;
  954. }
  955. }
  956. else {
  957. TRC_ABORT((TB, "Decompression FAILURE!!!"));
  958. WDW_LogAndDisconnect(pTSWd, TRUE,
  959. Log_RDP_VirtualChannelDecompressionErr,
  960. NULL, 0);
  961. DC_QUIT;
  962. }
  963. }
  964. else
  965. {
  966. //
  967. //This server only supports 8K VC compression from client
  968. //(Specified by capabilities) it should not have
  969. //been sent this invalid compression type
  970. TRC_ABORT((TB,"Received packet with invalid compression type %d",
  971. (vcCompressFlags & PACKET_COMPR_TYPE_MASK)));
  972. WDW_LogAndDisconnect(pTSWd, TRUE,
  973. Log_RDP_InvalidVCCompressionType,
  974. NULL, 0);
  975. DC_QUIT;
  976. }
  977. }
  978. else
  979. {
  980. //Channel data is not compressd
  981. if (pHdr->flags & CHANNEL_FLAG_SHOW_PROTOCOL)
  982. {
  983. TRC_DBG((TB, "Include VC protocol header"));
  984. pDataOut = (PUCHAR)pHdr;
  985. thisLength = dataLength;
  986. //Hide the internal protocol fields from the user
  987. ((CHANNEL_PDU_HEADER UNALIGNED *)pDataOut)->flags &=
  988. ~VC_FLAG_PRIVATE_PROTOCOL_MASK;
  989. }
  990. else
  991. {
  992. TRC_DBG((TB, "Exclude VC protocol header"));
  993. pDataOut = (PUCHAR)(pHdr + 1);
  994. thisLength = dataLength - sizeof(*pHdr);
  995. }
  996. }
  997. if (!pTSWd->dead)
  998. {
  999. TRC_NRM((TB,
  1000. "Input %d bytes (of %d) at %p (Hdr %p, flags %#x) on channel %d",
  1001. thisLength, totalLength, pDataOut, pHdr, pHdr->flags,
  1002. virtualClass));
  1003. status = IcaChannelInput(pTSWd->pContext,
  1004. Channel_Virtual,
  1005. virtualClass,
  1006. NULL,
  1007. pDataOut,
  1008. thisLength);
  1009. }
  1010. else
  1011. {
  1012. TRC_NRM((TB,"Skipping input (%d bytes) because dead",
  1013. thisLength));
  1014. }
  1015. DC_EXIT_POINT:
  1016. DC_END_FN();
  1017. } /* WDW_OnDataReceived */
  1018. /****************************************************************************/
  1019. /* Name: WDW_InvalidateRect */
  1020. /* */
  1021. /* Purpose: Tell ICADD to redraw a given rectangle. */
  1022. /* */
  1023. /* Returns: VOID. */
  1024. /* */
  1025. /* Params: IN pTSWd - ptr to WD */
  1026. /* IN personID - the originator of this PDU */
  1027. /* IN rect - the area to redraw */
  1028. /* */
  1029. /* Operation: Build command and pass it to ICADD. */
  1030. /****************************************************************************/
  1031. void WDW_InvalidateRect(
  1032. PTSHARE_WD pTSWd,
  1033. PTS_REFRESH_RECT_PDU pRRPDU,
  1034. unsigned DataLength)
  1035. {
  1036. ICA_CHANNEL_COMMAND Cmd;
  1037. NTSTATUS status;
  1038. unsigned i;
  1039. DC_BEGIN_FN("WDW_InvalidateRect");
  1040. // Make sure we have enough data before accessing.
  1041. if (DataLength >= (sizeof(TS_REFRESH_RECT_PDU) - sizeof(TS_RECTANGLE16))) {
  1042. TRC_NRM((TB, "Got request to refresh %hu area%s",
  1043. (UINT16)pRRPDU->numberOfAreas,
  1044. pRRPDU->numberOfAreas == 1 ? " " : "s"));
  1045. if ((unsigned)(TS_UNCOMP_LEN(pRRPDU) -
  1046. FIELDOFFSET(TS_REFRESH_RECT_PDU, areaToRefresh[0])) >=
  1047. (pRRPDU->numberOfAreas * sizeof(TS_RECTANGLE16)) &&
  1048. (unsigned)(DataLength -
  1049. FIELDOFFSET(TS_REFRESH_RECT_PDU, areaToRefresh[0])) >=
  1050. (pRRPDU->numberOfAreas * sizeof(TS_RECTANGLE16))) {
  1051. for (i = 0; i < pRRPDU->numberOfAreas; i++) {
  1052. // Rects arrive inclusive, convert to exclusive for the system.
  1053. Cmd.Header.Command = ICA_COMMAND_REDRAW_RECTANGLE;
  1054. Cmd.RedrawRectangle.Rect.Left = pRRPDU->areaToRefresh[i].left;
  1055. Cmd.RedrawRectangle.Rect.Top = pRRPDU->areaToRefresh[i].top;
  1056. Cmd.RedrawRectangle.Rect.Right = pRRPDU->areaToRefresh[i].
  1057. right + 1;
  1058. Cmd.RedrawRectangle.Rect.Bottom = pRRPDU->areaToRefresh[i].
  1059. bottom + 1;
  1060. /************************************************************/
  1061. // Pass the filled in structure to ICADD.
  1062. /************************************************************/
  1063. status = IcaChannelInput(pTSWd->pContext,
  1064. Channel_Command,
  1065. 0,
  1066. NULL,
  1067. (unsigned char *) &Cmd,
  1068. sizeof(ICA_CHANNEL_COMMAND));
  1069. TRC_DBG((TB,"Issued Refresh Rect for %u,%u,%u,%u (exclusive); "
  1070. "status %lu",
  1071. pRRPDU->areaToRefresh[i].left,
  1072. pRRPDU->areaToRefresh[i].top,
  1073. pRRPDU->areaToRefresh[i].right + 1,
  1074. pRRPDU->areaToRefresh[i].bottom + 1,
  1075. status));
  1076. }
  1077. }
  1078. else {
  1079. /****************************************************************/
  1080. // There can't be enough space in this PDU to store the number of
  1081. // rectangles that it apparently contains. Don't process it.
  1082. /****************************************************************/
  1083. TCHAR detailData[(sizeof(UINT16) * 4) + 2];
  1084. TRC_ERR((TB, "Invalid RefreshRectPDU: %hu rects; %hu bytes long",
  1085. (UINT16)pRRPDU->numberOfAreas,
  1086. pRRPDU->shareDataHeader.uncompressedLength));
  1087. /****************************************************************/
  1088. // Log an error and disconnect the Client
  1089. /****************************************************************/
  1090. swprintf(detailData, L"%hx %hx",
  1091. (UINT16)pRRPDU->numberOfAreas,
  1092. pRRPDU->shareDataHeader.uncompressedLength,
  1093. sizeof(detailData));
  1094. WDW_LogAndDisconnect(pTSWd, TRUE,
  1095. Log_RDP_InvalidRefreshRectPDU,
  1096. NULL, 0);
  1097. }
  1098. }
  1099. else {
  1100. TRC_ERR((TB,"Data len %u not enough for refresh rect PDU",
  1101. DataLength));
  1102. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_InvalidRefreshRectPDU,
  1103. (BYTE *)pRRPDU, DataLength);
  1104. }
  1105. DC_END_FN();
  1106. } /* WDW_InvalidateRect */
  1107. #ifdef DC_DEBUG
  1108. /****************************************************************************/
  1109. /* Name: WDW_Malloc */
  1110. /* */
  1111. /* Purpose: Allocate memory (checked builds only) */
  1112. /* */
  1113. /* Returns: ptr to memory allocated */
  1114. /* */
  1115. /* Params: pTSWd */
  1116. /* length - size of memory required */
  1117. /****************************************************************************/
  1118. PVOID RDPCALL WDW_Malloc(PTSHARE_WD pTSWd, ULONG length)
  1119. {
  1120. PVOID pMemory;
  1121. #ifndef NO_MEMORY_CHECK
  1122. /************************************************************************/
  1123. /* If we're checking memory, allow space for the header */
  1124. /************************************************************************/
  1125. length += sizeof(MALLOC_HEADER);
  1126. #endif
  1127. /************************************************************************/
  1128. /* Allocate the memory */
  1129. /************************************************************************/
  1130. pMemory = ExAllocatePoolWithTag(PagedPool, length, WD_ALLOC_TAG);
  1131. if (pMemory == NULL)
  1132. {
  1133. KdPrint(("WDTShare: COM_Malloc failed to alloc %u bytes\n", length));
  1134. DC_QUIT;
  1135. }
  1136. #ifndef NO_MEMORY_CHECK
  1137. /************************************************************************/
  1138. /* If we haven't been passed a TSWd, we can't save the memory details - */
  1139. /* clear the header. */
  1140. /************************************************************************/
  1141. if (pTSWd == NULL)
  1142. {
  1143. memset(pMemory, 0, sizeof(MALLOC_HEADER));
  1144. }
  1145. else
  1146. {
  1147. /********************************************************************/
  1148. /* we've been passed a TSWd - save memory details */
  1149. /********************************************************************/
  1150. PVOID pReturnAddress = NULL;
  1151. PMALLOC_HEADER pHeader;
  1152. #ifdef _X86_
  1153. /********************************************************************/
  1154. /* Find caller's address (X86 only) */
  1155. /********************************************************************/
  1156. _asm mov eax,[ebp+4]
  1157. _asm mov pReturnAddress,eax
  1158. #endif /* _X86_ */
  1159. /********************************************************************/
  1160. /* Save memory allocation details */
  1161. /********************************************************************/
  1162. pHeader = (PMALLOC_HEADER)pMemory;
  1163. pHeader->pCaller = pReturnAddress;
  1164. pHeader->length = length;
  1165. pHeader->pPrev = &(pTSWd->memoryHeader);
  1166. if (pTSWd->memoryHeader.pNext != NULL)
  1167. {
  1168. (pTSWd->memoryHeader.pNext)->pPrev = pHeader;
  1169. }
  1170. pHeader->pNext = pTSWd->memoryHeader.pNext;
  1171. pTSWd->memoryHeader.pNext = pHeader;
  1172. }
  1173. /************************************************************************/
  1174. /* Bump pointer past header */
  1175. /************************************************************************/
  1176. pMemory = (PVOID)((BYTE *)pMemory + sizeof(MALLOC_HEADER));
  1177. #endif /* NO_MEMORY_CHECK */
  1178. DC_EXIT_POINT:
  1179. return(pMemory);
  1180. }
  1181. /****************************************************************************/
  1182. /* Name: WDW_Free */
  1183. /* */
  1184. /* Purpose: Free memory (checked builds only) */
  1185. /* */
  1186. /* Params: pMemory - pointer to memory to free */
  1187. /****************************************************************************/
  1188. void RDPCALL WDW_Free(PVOID pMemory)
  1189. {
  1190. #ifndef NO_MEMORY_CHECK
  1191. /************************************************************************/
  1192. /* Remove this block from memory allocation chain */
  1193. /************************************************************************/
  1194. PMALLOC_HEADER pHeader;
  1195. pHeader = (PMALLOC_HEADER)pMemory - 1;
  1196. if (pHeader->pNext != NULL)
  1197. {
  1198. pHeader->pNext->pPrev = pHeader->pPrev;
  1199. }
  1200. if (pHeader->pPrev != NULL)
  1201. {
  1202. pHeader->pPrev->pNext = pHeader->pNext;
  1203. }
  1204. pMemory = (PVOID)pHeader;
  1205. #endif /* NO_MEMORY_CHECK */
  1206. /************************************************************************/
  1207. /* Free the memory */
  1208. /************************************************************************/
  1209. ExFreePool(pMemory);
  1210. }
  1211. #endif /* DC_DEBUG */