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.

1865 lines
80 KiB

  1. /****************************************************************************/
  2. // nwdwint.c
  3. //
  4. // RDP WD code.
  5. //
  6. // Copyright (C) 1996-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #define pTRCWd pTSWd
  11. #define TRC_FILE "nwdwint"
  12. #include <adcg.h>
  13. #include <randlib.h>
  14. #include <pchannel.h>
  15. #include <anmapi.h>
  16. #include <asmint.h>
  17. #include <nwdwapi.h>
  18. #include <nwdwioct.h>
  19. #include <nwdwint.h>
  20. #include <nwdwdata.c>
  21. #include <asmint.h>
  22. #include <anmint.h>
  23. #include <tsperf.h>
  24. //
  25. // RNG api doesn't refcount it's shutdown so do it for them
  26. //
  27. LONG g_RngUsers = 0;
  28. /****************************************************************************/
  29. /* Name: WDWLoad */
  30. /* */
  31. /* Purpose: Load WinStation driver */
  32. /* */
  33. /* Params: INOUT pContext - pointer to the SD context structure */
  34. /****************************************************************************/
  35. NTSTATUS WDWLoad(PSDCONTEXT pContext)
  36. {
  37. NTSTATUS Status;
  38. PTSHARE_WD pTSWd;
  39. unsigned smnmBytes;
  40. unsigned wdBytes;
  41. DC_BEGIN_FN("WDWLoad");
  42. /************************************************************************/
  43. /* WARNING: Don't trace in this function, it will cause ICADD to crash, */
  44. /* as the stack context hasn't been set up properly until we return */
  45. /* from this function. */
  46. /* Use KdPrint instead. */
  47. /************************************************************************/
  48. // Initialize Calldown and callup procedures.
  49. pContext->pProcedures = (PSDPROCEDURE)G_pWdProcedures;
  50. pContext->pCallup = (SDCALLUP *)G_pWdCallups;
  51. // Do a quick sanity check on the SHM size to alert of bad paging
  52. // characteristics.
  53. wdBytes = sizeof(SHM_SHARED_MEMORY);
  54. #ifdef DC_DEBUG
  55. wdBytes -= sizeof(TRC_SHARED_DATA);
  56. #endif
  57. if ((wdBytes % PAGE_SIZE) < (PAGE_SIZE / 8))
  58. KdPrintEx((DPFLTR_TERMSRV_ID,
  59. DPFLTR_INFO_LEVEL,
  60. "RDPWD: **** Note SHM_SHARED_MEMORY fre size is wasting "
  61. "at least 7/8 of a page - page size=%u, SHM=%u, wasting %u\n",
  62. PAGE_SIZE, wdBytes, PAGE_SIZE - (wdBytes % PAGE_SIZE)));
  63. // Allocate WD data structure - first find out how many bytes are
  64. // needed by the SM/NM code.
  65. smnmBytes = SM_GetDataSize();
  66. wdBytes = DC_ROUND_UP_4(sizeof(TSHARE_WD));
  67. KdPrintEx((DPFLTR_TERMSRV_ID,
  68. DPFLTR_INFO_LEVEL,
  69. "RDPWD: WDWLoad: Alloc TSWD=%d + NM/SM=%d (= %d) bytes for TSWd\n",
  70. wdBytes, smnmBytes, wdBytes + smnmBytes));
  71. if ((wdBytes + smnmBytes) >= PAGE_SIZE)
  72. KdPrintEx((DPFLTR_TERMSRV_ID,
  73. DPFLTR_INFO_LEVEL,
  74. "RDPWD: **** Note TSWd allocation is above page size %u, "
  75. "wasting %u\n", PAGE_SIZE,
  76. PAGE_SIZE - ((wdBytes + smnmBytes) % PAGE_SIZE)));
  77. #ifdef DC_DEBUG
  78. // Preinit pTSWd for debug COM_Malloc.
  79. pTSWd = NULL;
  80. #endif
  81. pTSWd = COM_Malloc(wdBytes + smnmBytes);
  82. if (pTSWd != NULL) {
  83. // Zero the allocated mem.
  84. memset(pTSWd, 0, wdBytes + smnmBytes);
  85. }
  86. else {
  87. KdPrintEx((DPFLTR_TERMSRV_ID,
  88. DPFLTR_ERROR_LEVEL,
  89. "RDPWD: WDWLoad: Failed alloc TSWD\n"));
  90. Status = STATUS_NO_MEMORY;
  91. DC_QUIT;
  92. }
  93. //
  94. // Init the performance flags to non-perf-aware client setting.
  95. // We need this to differentiate between
  96. // non-experience-aware clients and xp clients.
  97. // We cannot use protocol versions as they are
  98. // are not being setup properly now.
  99. //
  100. pTSWd->performanceFlags = TS_PERF_DEFAULT_NONPERFCLIENT_SETTING;
  101. // Set up pointers both ways between PSDCONTEXT and PTSHARE_WD.
  102. // Note that we still can't yet trace.
  103. pTSWd->pSmInfo = ((BYTE *)pTSWd) + wdBytes;
  104. pTSWd->pNMInfo = (BYTE *)pTSWd->pSmInfo + sizeof(SM_HANDLE_DATA);
  105. KdPrintEx((DPFLTR_TERMSRV_ID,
  106. DPFLTR_INFO_LEVEL,
  107. "RDPWD: pTSWd=%p, pSM=%p, pNM=%p, sizeof(TSWd)=%u, sizeof(SM)=%u\n",
  108. pTSWd, pTSWd->pSmInfo, pTSWd->pNMInfo, sizeof(TSHARE_WD),
  109. sizeof(SM_HANDLE_DATA), sizeof(NM_HANDLE_DATA)));
  110. pTSWd->pContext = pContext;
  111. pContext->pContext = pTSWd;
  112. // Now allocate the RNS_INFO_PACKET as a separate allocation. InfoPkt
  113. // is large (~3K) and if included in TSHARE_WD pushes the TSWd
  114. // allocation over the Intel 4K page size, causing most of a second
  115. // page to be wasted. Since we can't get rid of the data (it's
  116. // referenced at various points in the normal and shadow connection
  117. // sequences), we alloc it separately to let the system sub-page
  118. // allocator use memory more effectively.
  119. KdPrintEx((DPFLTR_TERMSRV_ID,
  120. DPFLTR_INFO_LEVEL,
  121. "RDPWD: WDWLoad: Alloc %u bytes for InfoPkt\n",
  122. sizeof(RNS_INFO_PACKET)));
  123. if ((sizeof(RNS_INFO_PACKET)) >= PAGE_SIZE)
  124. KdPrintEx((DPFLTR_TERMSRV_ID,
  125. DPFLTR_INFO_LEVEL,
  126. "RDPWD: **** Note INFO_PACKET allocation is above "
  127. "page size %u, wasting %u\n", PAGE_SIZE,
  128. PAGE_SIZE - (sizeof(RNS_INFO_PACKET) % PAGE_SIZE)));
  129. pTSWd->pInfoPkt = COM_Malloc(sizeof(RNS_INFO_PACKET));
  130. if (pTSWd->pInfoPkt != NULL) {
  131. memset(pTSWd->pInfoPkt, 0, sizeof(RNS_INFO_PACKET));
  132. }
  133. else {
  134. KdPrintEx((DPFLTR_TERMSRV_ID,
  135. DPFLTR_ERROR_LEVEL,
  136. "RDPWD: WDWLoad: Failed alloc InfoPkt\n"));
  137. COM_Free(pTSWd);
  138. Status = STATUS_NO_MEMORY;
  139. DC_QUIT;
  140. }
  141. // Allocate and initialize the connEvent, createEvent, secEvent,
  142. // SessKeyEvent, and ClientDisconnectEvent. Use ExAllocatePool directly,
  143. // as COM_Malloc allocates paged memory, and these events must be in
  144. // non-paged memory.
  145. pTSWd->pConnEvent = ExAllocatePoolWithTag(NonPagedPool,
  146. sizeof(KEVENT) * 5,
  147. WD_ALLOC_TAG);
  148. if (pTSWd->pConnEvent != NULL) {
  149. pTSWd->pCreateEvent = pTSWd->pConnEvent + 1;
  150. pTSWd->pSecEvent = pTSWd->pCreateEvent + 1;
  151. pTSWd->pSessKeyEvent = pTSWd->pSecEvent + 1;
  152. pTSWd->pClientDisconnectEvent = pTSWd->pSessKeyEvent + 1;
  153. KeInitializeEvent(pTSWd->pConnEvent, NotificationEvent, FALSE);
  154. KeInitializeEvent(pTSWd->pCreateEvent, NotificationEvent, FALSE);
  155. KeInitializeEvent(pTSWd->pSecEvent, NotificationEvent, FALSE);
  156. KeInitializeEvent(pTSWd->pSessKeyEvent, NotificationEvent, FALSE);
  157. KeInitializeEvent(pTSWd->pClientDisconnectEvent, NotificationEvent,
  158. FALSE);
  159. }
  160. else {
  161. KdPrintEx((DPFLTR_TERMSRV_ID,
  162. DPFLTR_ERROR_LEVEL,
  163. "RDPWD: Failed to allocate memory for WD events\n"));
  164. COM_Free(pTSWd->pInfoPkt);
  165. COM_Free(pTSWd);
  166. Status = STATUS_NO_MEMORY;
  167. DC_QUIT;
  168. }
  169. //
  170. // Init the random number generator
  171. //
  172. if (InitializeRNG(NULL)) {
  173. InterlockedIncrement(&g_RngUsers);
  174. }
  175. Status = STATUS_SUCCESS;
  176. KdPrintEx((DPFLTR_TERMSRV_ID,
  177. DPFLTR_INFO_LEVEL,
  178. "RDPWD: WDWLoad done\n"));
  179. DC_EXIT_POINT:
  180. DC_END_FN();
  181. return Status;
  182. }
  183. /****************************************************************************/
  184. /* Name: WDWUnload */
  185. /* */
  186. /* Purpose: Unload WinStation driver */
  187. /* */
  188. /* Params: INOUT pContext - pointer to the SD context structure */
  189. /****************************************************************************/
  190. NTSTATUS WDWUnload( PSDCONTEXT pContext )
  191. {
  192. PTSHARE_WD pTSWd;
  193. /************************************************************************/
  194. /* Get pointers to WD data structures */
  195. /************************************************************************/
  196. pTSWd = (PTSHARE_WD)pContext->pContext;
  197. if (pTSWd != NULL) {
  198. // Free connEvent & createEvent.
  199. if (NULL != pTSWd->pConnEvent)
  200. ExFreePool(pTSWd->pConnEvent);
  201. // Free the InfoPkt.
  202. if (pTSWd->pInfoPkt != NULL)
  203. COM_Free(pTSWd->pInfoPkt);
  204. // Free TSWd itself.
  205. COM_Free(pTSWd);
  206. }
  207. /************************************************************************/
  208. /* Clear context structure */
  209. /************************************************************************/
  210. pContext->pContext = NULL;
  211. pContext->pProcedures = NULL;
  212. pContext->pCallup = NULL;
  213. //
  214. // Shutdown the random number generator
  215. //
  216. if (0L == InterlockedDecrement(&g_RngUsers)) {
  217. ShutdownRNG(NULL);
  218. }
  219. return STATUS_SUCCESS;
  220. }
  221. /****************************************************************************/
  222. /* Name: WDWConnect */
  223. /* */
  224. /* Purpose: Processes a conference connect request from the WD. It is */
  225. /* used by connects from TShareSrv as well as shadow connects. */
  226. /* */
  227. /* Params: IN pTSWd - pointer to WD struct */
  228. /* IN PRNS_UD_CS_CORE - Client Core Data */
  229. /* IN PRNS_UD_CS_SEC - Client Security Data */
  230. /* IN PRNS_UD_CS_NET - Client Net Data */
  231. /* INOUT PSD_IOCTL - pointer to received IOCtl this will be one */
  232. /* of IOCTL_TSHARE_CONF_CONNECT or */
  233. /* IOCTL_ICA_SET_CONNECTED(shadow) */
  234. /* */
  235. /* Operation: Parse the user data for core, security, and network bits. */
  236. /* Pull the values we want out of the core piece */
  237. /* Initialize the Security Manager */
  238. /* Create a share core, passing in the key values from user data */
  239. /* Tell the user manager to proceed with connecting */
  240. /****************************************************************************/
  241. NTSTATUS WDWConnect(
  242. PTSHARE_WD pTSWd,
  243. PRNS_UD_CS_CORE pClientCoreData,
  244. PRNS_UD_CS_SEC pClientSecurityData,
  245. PRNS_UD_CS_NET pClientNetData,
  246. PTS_UD_CS_CLUSTER pClientClusterData,
  247. PSD_IOCTL pSdIoctl,
  248. BOOLEAN bOldShadow)
  249. {
  250. NTSTATUS status = STATUS_SUCCESS;
  251. BOOL smInit = FALSE;
  252. DC_BEGIN_FN("WDWConnect");
  253. // Get the required values from the core user data.
  254. pTSWd->version = pClientCoreData->version;
  255. pTSWd->desktopWidth = pClientCoreData->desktopWidth;
  256. pTSWd->desktopHeight = pClientCoreData->desktopHeight;
  257. // We only support 4096 x 2048
  258. if (pTSWd->desktopHeight > 2048)
  259. pTSWd->desktopHeight = 2048;
  260. if (pTSWd->desktopWidth > 4096)
  261. pTSWd->desktopWidth = 4096;
  262. // Checks the client software for compatibility and rejects if not
  263. // equivalent to server software.
  264. TRC_NRM((TB, "Client version is %#lx", pClientCoreData->version));
  265. if (_RNS_MAJOR_VERSION(pClientCoreData->version) != RNS_UD_MAJOR_VERSION) {
  266. TRC_ERR((TB, "Unmatching software version, expected %#lx got %#lx",
  267. RNS_UD_VERSION, pClientCoreData->version));
  268. status = RPC_NT_INVALID_VERS_OPTION;
  269. DC_QUIT;
  270. }
  271. if(pClientCoreData->header.length >=
  272. (FIELDOFFSET(RNS_UD_CS_CORE, earlyCapabilityFlags) +
  273. FIELDSIZE(RNS_UD_CS_CORE, earlyCapabilityFlags))) {
  274. //
  275. // Does client support extended error reporting PDU
  276. //
  277. pTSWd->bSupportErrorInfoPDU = (pClientCoreData->earlyCapabilityFlags &
  278. RNS_UD_CS_SUPPORT_ERRINFO_PDU) ?
  279. TRUE : FALSE;
  280. }
  281. else
  282. {
  283. pTSWd->bSupportErrorInfoPDU = FALSE;
  284. }
  285. TRC_NRM((TB, "ErrorInfoPDU supported = %d", pTSWd->bSupportErrorInfoPDU));
  286. #ifdef DC_HICOLOR
  287. // Work out high color support.
  288. if (pClientCoreData->header.length >=
  289. (FIELDOFFSET(RNS_UD_CS_CORE, supportedColorDepths) +
  290. FIELDSIZE(RNS_UD_CS_CORE, supportedColorDepths))) {
  291. long maxServerBpp;
  292. long limitedBpp;
  293. // Store off the supported color depths.
  294. pTSWd->supportedBpps = pClientCoreData->supportedColorDepths;
  295. // Client may want other than 4 or 8bpp, so lets see what we can
  296. // do. First up is to see what limits are imposed at this end.
  297. maxServerBpp = pTSWd->maxServerBpp;
  298. TRC_NRM((TB, "Client requests color depth %u, server limit %d",
  299. pClientCoreData->highColorDepth, maxServerBpp));
  300. // Now see if we can allow the requested value.
  301. if (pClientCoreData->highColorDepth > maxServerBpp) {
  302. TRC_NRM((TB, "Limiting requested color depth..."));
  303. switch (maxServerBpp) {
  304. case 16:
  305. if (pClientCoreData->supportedColorDepths &
  306. RNS_UD_16BPP_SUPPORT) {
  307. limitedBpp = 16;
  308. break;
  309. }
  310. // deliberate fall through!
  311. case 15:
  312. if (pClientCoreData->supportedColorDepths &
  313. RNS_UD_15BPP_SUPPORT) {
  314. limitedBpp = 15;
  315. break;
  316. }
  317. // deliberate fall through!
  318. default:
  319. limitedBpp = 8;
  320. break;
  321. }
  322. TRC_ALT((TB, "Restricted requested color depth %d to %d",
  323. pClientCoreData->highColorDepth, maxServerBpp));
  324. pClientCoreData->highColorDepth = (UINT16)limitedBpp;
  325. }
  326. // Now set up the proper color depth from the (possibly
  327. // restricted) high color value.
  328. if (pClientCoreData->highColorDepth == 24)
  329. pClientCoreData->colorDepth = RNS_UD_COLOR_24BPP;
  330. else if (pClientCoreData->highColorDepth == 16)
  331. pClientCoreData->colorDepth = RNS_UD_COLOR_16BPP_565;
  332. else if (pClientCoreData->highColorDepth == 15)
  333. pClientCoreData->colorDepth = RNS_UD_COLOR_16BPP_555;
  334. else if (pClientCoreData->highColorDepth == 4)
  335. pClientCoreData->colorDepth = RNS_UD_COLOR_4BPP;
  336. else
  337. pClientCoreData->colorDepth = RNS_UD_COLOR_8BPP;
  338. }
  339. else {
  340. // No hicolor support.
  341. pTSWd->supportedBpps = 0;
  342. #endif
  343. // A beta2 Server rejects Clients with a color depth of 4bpp.
  344. // Therefore a new field, postBeta2ColorDepth, is added, which can be
  345. // 4bpp. If this field exists, use it instead of colorDepth.
  346. if (pClientCoreData->header.length >=
  347. (FIELDOFFSET(RNS_UD_CS_CORE, postBeta2ColorDepth) +
  348. FIELDSIZE(RNS_UD_CS_CORE, postBeta2ColorDepth))) {
  349. TRC_NRM((TB, "Post-beta2 color depth id %#x",
  350. pClientCoreData->postBeta2ColorDepth));
  351. pClientCoreData->colorDepth = pClientCoreData->postBeta2ColorDepth;
  352. }
  353. #ifdef DC_HICOLOR
  354. }
  355. #endif
  356. if (pClientCoreData->colorDepth == RNS_UD_COLOR_8BPP) {
  357. TRC_NRM((TB, "8 BPP"));
  358. pTSWd->desktopBpp = 8;
  359. }
  360. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_4BPP) {
  361. TRC_NRM((TB, "4 BPP"));
  362. pTSWd->desktopBpp = 4;
  363. }
  364. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_16BPP_555) {
  365. #ifdef DC_HICOLOR
  366. TRC_NRM((TB, "15 BPP (16 BPP, 555)"));
  367. pTSWd->desktopBpp = 15;
  368. #else
  369. // May want to save whether it's 555 or 565.
  370. TRC_NRM((TB, "16 BPP 555"));
  371. pTSWd->desktopBpp = 16;
  372. #endif
  373. }
  374. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_16BPP_565) {
  375. #ifdef DC_HICOLOR
  376. TRC_NRM((TB, "16 BPP (565)"));
  377. #else
  378. TRC_NRM((TB, "16 BPP 565"));
  379. #endif
  380. pTSWd->desktopBpp = 16;
  381. }
  382. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_24BPP) {
  383. TRC_NRM((TB, "24 BPP"));
  384. pTSWd->desktopBpp = 24;
  385. }
  386. else {
  387. TRC_ERR((TB, "Unknown BPP %x returned by client",
  388. pClientCoreData->colorDepth));
  389. status = STATUS_UNSUCCESSFUL;
  390. DC_QUIT;
  391. }
  392. pTSWd->sas = pClientCoreData->SASSequence;
  393. pTSWd->kbdLayout = pClientCoreData->keyboardLayout;
  394. pTSWd->clientBuild = pClientCoreData->clientBuild;
  395. // here we don't copy the last character in the buffer because
  396. // we force zero termination later by writting a 0 at the end;
  397. memcpy(pTSWd->clientName, pClientCoreData->clientName,
  398. sizeof(pTSWd->clientName)-sizeof(pTSWd->clientName[0]));
  399. pTSWd->clientName[sizeof(pTSWd->clientName)
  400. / sizeof(pTSWd->clientName[0]) - 1] = 0;
  401. pTSWd->keyboardType = pClientCoreData->keyboardType;
  402. pTSWd->keyboardSubType = pClientCoreData->keyboardSubType;
  403. pTSWd->keyboardFunctionKey = pClientCoreData->keyboardFunctionKey;
  404. // here we don't copy the last character in the buffer because
  405. // we force zero termination later by writting a 0 at the end;
  406. memcpy(pTSWd->imeFileName, pClientCoreData->imeFileName,
  407. sizeof(pTSWd->imeFileName)-sizeof(pTSWd->imeFileName[0]));
  408. pTSWd->imeFileName[sizeof(pTSWd->imeFileName)
  409. / sizeof(pTSWd->imeFileName[0]) - 1] = 0;
  410. pTSWd->clientDigProductId[0] = 0;
  411. // Win2000 Post Beta 3 fields added
  412. if (pClientCoreData->header.length >=
  413. (FIELDOFFSET(RNS_UD_CS_CORE, serialNumber) +
  414. FIELDSIZE(RNS_UD_CS_CORE, serialNumber))) {
  415. pTSWd->clientProductId = pClientCoreData->clientProductId;
  416. pTSWd->serialNumber = pClientCoreData->serialNumber;
  417. //shadow loop fix
  418. if (pClientCoreData->header.length >=
  419. (FIELDOFFSET(RNS_UD_CS_CORE, clientDigProductId) +
  420. FIELDSIZE(RNS_UD_CS_CORE, clientDigProductId))) {
  421. // here we don't copy the last character in the buffer because
  422. // we force zero termination later by writting a 0 at the end;
  423. memcpy( pTSWd->clientDigProductId,
  424. pClientCoreData->clientDigProductId,
  425. sizeof(pTSWd->clientDigProductId)
  426. -sizeof(pTSWd->clientDigProductId[0]));
  427. pTSWd->clientDigProductId[sizeof(pTSWd->clientDigProductId)
  428. / sizeof(pTSWd->clientDigProductId[0]) -1] = 0;
  429. }
  430. }
  431. // Parse and store the client's cluster support info, if provided.
  432. // If not present, the memset here will implicitly set FALSE the flags
  433. // for the client cluster capabilities. Note we do not have the
  434. // username and domain available yet (it comes in the info packet
  435. // later) so we cannot fill out the username and domain yet.
  436. if (pClientClusterData != NULL) {
  437. if (pClientClusterData->Flags & TS_CLUSTER_REDIRECTION_SUPPORTED) {
  438. TRC_NRM((TB,"Client supports load balance redirection"));
  439. pTSWd->bClientSupportsRedirection = TRUE;
  440. }
  441. if (pClientClusterData->Flags &
  442. TS_CLUSTER_REDIRECTED_SESSIONID_FIELD_VALID) {
  443. TRC_NRM((TB,"Client has been load-balanced to this server, "
  444. "sessid=%u", pClientClusterData->RedirectedSessionID));
  445. pTSWd->bRequestedSessionIDFieldValid = TRUE;
  446. pTSWd->RequestedSessionID =
  447. pClientClusterData->RedirectedSessionID;
  448. if (pClientClusterData->Flags & TS_CLUSTER_REDIRECTED_SMARTCARD) {
  449. pTSWd->bUseSmartcardLogon = TRUE;
  450. }
  451. }
  452. // The 2..5 bits (start from 0) are the PDU version
  453. pTSWd->ClientRedirectionVersion = ((pClientClusterData->Flags & 0x3C) >> 2);
  454. }
  455. // Create a new share object.
  456. status = WDWNewShareClass(pTSWd);
  457. if (!NT_SUCCESS(status)) {
  458. TRC_ERR((TB, "Failed to get a new Share Object - quit"));
  459. DC_QUIT;
  460. }
  461. // Bring up SM.
  462. status = SM_Init(pTSWd->pSmInfo, pTSWd, bOldShadow);
  463. if (NT_SUCCESS(status)) {
  464. smInit = TRUE;
  465. }
  466. else {
  467. TRC_ERR((TB, "Failed to init SM, rc %lu", status));
  468. DC_QUIT;
  469. }
  470. // Hook the IOCtl off the WD structure to allow the SM callback to
  471. // process it.
  472. // Also NULL the output buffer - this is solely to allow us to assert
  473. // (later) that the callback has in fact been taken.
  474. TRC_ASSERT((pTSWd->pSdIoctl == NULL),
  475. (TB,"Already an IOCTL linked from pTSWd"));
  476. pTSWd->pSdIoctl = pSdIoctl;
  477. if ((pSdIoctl->IoControlCode == IOCTL_TSHARE_CONF_CONNECT) &&
  478. pSdIoctl->OutputBuffer) {
  479. ((PUSERDATAINFO)pSdIoctl->OutputBuffer)->ulUserDataMembers = 0;
  480. }
  481. // Tell SM we're done here.
  482. status = SM_Connect(pTSWd->pSmInfo, pClientSecurityData, pClientNetData,
  483. bOldShadow);
  484. if (status != STATUS_SUCCESS) {
  485. TRC_ERR((TB, "SM_Connect failed: rc=%lx", status));
  486. DC_QUIT;
  487. }
  488. /************************************************************************/
  489. /* The scheduling is such that we are guaranteed that the connecting */
  490. /* status will have been received from SM before the previous call */
  491. /* returns. Just for safety we assert that this is so! */
  492. /************************************************************************/
  493. if ((pSdIoctl->IoControlCode == IOCTL_TSHARE_CONF_CONNECT) &&
  494. pSdIoctl->OutputBuffer) {
  495. TRC_ASSERT((((PUSERDATAINFO)pSdIoctl->OutputBuffer)->ulUserDataMembers
  496. != 0),
  497. (TB,"We didn't get callback from SM - BAD NEWS"));
  498. }
  499. DC_EXIT_POINT:
  500. // Clean up anything we created if we failed.
  501. if (status == STATUS_SUCCESS) {
  502. pTSWd->pSdIoctl = NULL;
  503. }
  504. else {
  505. TRC_NRM((TB, "Cleaning up..."));
  506. if (pTSWd->dcShare != NULL) {
  507. TRC_NRM((TB, "Deleting Share object"));
  508. WDWDeleteShareClass(pTSWd);
  509. }
  510. if (smInit) {
  511. TRC_NRM((TB, "Terminating SM"));
  512. SM_Term(pTSWd->pSmInfo);
  513. }
  514. }
  515. DC_END_FN();
  516. return status;
  517. } /* WDWConnect */
  518. /****************************************************************************/
  519. /* Name: WDWConfConnect */
  520. /* */
  521. /* Purpose: Processes a TSHARE_CONF_CONNECT IOCtl from TShareSRV */
  522. /* */
  523. /* Params: IN pTSWd - pointer to WD struct */
  524. /* INOUT PSD_IOCTL - pointer to received IOCtl */
  525. /* */
  526. /* Operation: Parse the user data for core bits and SM bits. */
  527. /* pull the values we want out of the core piece */
  528. /* initialize the Security Manager */
  529. /* create a share core, passing in the key values from user data */
  530. /* tell the user manager to proceed with connecting */
  531. /****************************************************************************/
  532. NTSTATUS WDWConfConnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
  533. {
  534. NTSTATUS status = STATUS_SUCCESS;
  535. unsigned DataLen;
  536. PRNS_UD_CS_CORE pClientCoreData;
  537. PRNS_UD_CS_SEC pClientSecurityData;
  538. PRNS_UD_CS_NET pClientNetData;
  539. PTS_UD_CS_CLUSTER pClientClusterData;
  540. DC_BEGIN_FN("WDWConfConnect");
  541. // First make sure we've received enough data for the initial headers
  542. // and that the sizes presented in the data block are valid. An attacker
  543. // might try sending malformed data here to fault the server.
  544. DataLen = pSdIoctl->InputBufferLength;
  545. if (sizeof(USERDATAINFO)>DataLen) {
  546. TRC_ERR((TB,"Apparent attack via user data, size %u too small for UD hdr",
  547. DataLen));
  548. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_BadUserData, pSdIoctl->InputBuffer,
  549. DataLen);
  550. status = STATUS_UNSUCCESSFUL;
  551. DC_QUIT;
  552. }
  553. if (((PUSERDATAINFO)pSdIoctl->InputBuffer)->cbSize > DataLen) {
  554. TRC_ERR((TB,"Apparent attack via user data, the cbSize is set to a length bigger then the total buffer %u",
  555. ((PUSERDATAINFO)pSdIoctl->InputBuffer)->cbSize > DataLen));
  556. WDW_LogAndDisconnect(pTSWd, TRUE, Log_RDP_BadUserData, pSdIoctl->InputBuffer,
  557. DataLen);
  558. status = STATUS_UNSUCCESSFUL;
  559. DC_QUIT;
  560. }
  561. // Validate that the output buffer is big enough.
  562. if ((pSdIoctl->OutputBuffer == NULL) ||
  563. (pSdIoctl->OutputBufferLength < MIN_USERDATAINFO_SIZE)) {
  564. TRC_ERR((TB, "No Out Buffer on TSHARE_CONF_CONNECT."));
  565. status = STATUS_BUFFER_TOO_SMALL;
  566. DC_QUIT;
  567. }
  568. if (((PUSERDATAINFO)pSdIoctl->OutputBuffer)->cbSize < MIN_USERDATAINFO_SIZE) {
  569. // Buffer has been supplied but is too small, - so tell
  570. // TShareSRV how big a buffer we actually need.
  571. ((PUSERDATAINFO)pSdIoctl->OutputBuffer)->cbSize = MIN_USERDATAINFO_SIZE;
  572. TRC_ERR((TB, "Telling TShareSRV to have another go with %d",
  573. MIN_USERDATAINFO_SIZE));
  574. status = STATUS_BUFFER_TOO_SMALL;
  575. DC_QUIT;
  576. }
  577. // Parse the input data.
  578. if (WDWParseUserData(pTSWd, (PUSERDATAINFO)pSdIoctl->InputBuffer, DataLen,
  579. NULL, 0, &pClientCoreData, &pClientSecurityData,
  580. &pClientNetData, &pClientClusterData)) {
  581. status = WDWConnect(pTSWd, pClientCoreData, pClientSecurityData,
  582. pClientNetData, pClientClusterData, pSdIoctl, FALSE);
  583. }
  584. else {
  585. status = STATUS_UNSUCCESSFUL;
  586. TRC_ERR((TB, "Could not parse the user data successfully"));
  587. }
  588. DC_EXIT_POINT:
  589. DC_END_FN();
  590. return status;
  591. } /* WDWConfConnect */
  592. /****************************************************************************/
  593. /* Name: WDWConsoleConnect */
  594. /* */
  595. /* Purpose: Processes a TSHARE_CONSOLE_CONNECT IOCtl from TShareSRV */
  596. /* */
  597. /* Params: IN pTSWd - pointer to WD struct */
  598. /* INOUT PSD_IOCTL - pointer to received IOCtl */
  599. /* */
  600. /* Operation: Parse the user data for core bits and SM bits. */
  601. /* pull the values we want out of the core piece */
  602. /* initialize the Security Manager */
  603. /* create a share core, passing in the key values from user data */
  604. /* tell the user manager to proceed with connecting */
  605. /****************************************************************************/
  606. NTSTATUS WDWConsoleConnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
  607. {
  608. NTSTATUS status = STATUS_SUCCESS;
  609. PUSERDATAINFO pUserInfo;
  610. PRNS_UD_CS_CORE pClientCoreData;
  611. BOOL smInit = FALSE;
  612. DC_BEGIN_FN("WDWConsoleConnect");
  613. /************************************************************************/
  614. /* get the Client data from the IOCTL */
  615. /************************************************************************/
  616. pUserInfo = (PUSERDATAINFO)(pSdIoctl->InputBuffer);
  617. pClientCoreData = (PRNS_UD_CS_CORE)(pUserInfo->rgUserData);
  618. /************************************************************************/
  619. /* version info */
  620. /************************************************************************/
  621. pTSWd->version = pClientCoreData->version;
  622. /************************************************************************/
  623. /* Set up the desktop size */
  624. /************************************************************************/
  625. pTSWd->desktopWidth = pClientCoreData->desktopWidth;
  626. pTSWd->desktopHeight = pClientCoreData->desktopHeight;
  627. #ifdef DC_HICOLOR
  628. /************************************************************************/
  629. /* And the color depth */
  630. /************************************************************************/
  631. if (pClientCoreData->colorDepth == RNS_UD_COLOR_8BPP)
  632. {
  633. pTSWd->desktopBpp = 8;
  634. }
  635. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_4BPP)
  636. {
  637. pTSWd->desktopBpp = 4;
  638. }
  639. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_16BPP_555)
  640. {
  641. pTSWd->desktopBpp = 15;
  642. }
  643. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_16BPP_565)
  644. {
  645. pTSWd->desktopBpp = 16;
  646. }
  647. else if (pClientCoreData->colorDepth == RNS_UD_COLOR_24BPP)
  648. {
  649. pTSWd->desktopBpp = 24;
  650. }
  651. else
  652. {
  653. TRC_ERR((TB, "Unknown BPP %x returned by client",
  654. pClientCoreData->colorDepth));
  655. pTSWd->desktopBpp = 8;
  656. }
  657. pTSWd->supportedBpps = pClientCoreData->supportedColorDepths;
  658. TRC_ALT((TB, "Console at %d bpp", pTSWd->desktopBpp));
  659. #else
  660. /************************************************************************/
  661. /* always 8bpp */
  662. /************************************************************************/
  663. pTSWd->desktopBpp = 8;
  664. #endif
  665. /************************************************************************/
  666. /* @@@ Need to set these up in RDPWSX first */
  667. /************************************************************************/
  668. // pTSWd->sas = pClientCoreData->SASSequence;
  669. // pTSWd->kbdLayout = pClientCoreData->keyboardLayout;
  670. // pTSWd->clientBuild = pClientCoreData->clientBuild;
  671. // wcscpy(pTSWd->clientName, pClientCoreData->clientName);
  672. //
  673. // pTSWd->keyboardType = pClientCoreData->keyboardType;
  674. // pTSWd->keyboardSubType = pClientCoreData->keyboardSubType;
  675. // pTSWd->keyboardFunctionKey = pClientCoreData->keyboardFunctionKey;
  676. // wcscpy(pTSWd->imeFileName, pClientCoreData->imeFileName);
  677. /************************************************************************/
  678. /* ... now a new share object... */
  679. /************************************************************************/
  680. status = WDWNewShareClass(pTSWd);
  681. if (!NT_SUCCESS(status))
  682. {
  683. TRC_ERR((TB, "Failed to get a new Share Object - quit"));
  684. DC_QUIT;
  685. }
  686. /************************************************************************/
  687. /* ...then bring up SM... */
  688. /************************************************************************/
  689. status = SM_Init(pTSWd->pSmInfo, pTSWd, FALSE);
  690. if (NT_SUCCESS(status))
  691. {
  692. smInit = TRUE;
  693. }
  694. else {
  695. TRC_ERR((TB, "Failed to init SM, rc %lu", status));
  696. DC_QUIT;
  697. }
  698. //
  699. // Always compress at the highest level.
  700. //
  701. pTSWd->pInfoPkt->flags |= RNS_INFO_COMPRESSION |
  702. (PACKET_COMPR_TYPE_64K << RNS_INFO_COMPR_TYPE_SHIFT);
  703. /************************************************************************/
  704. /* Now we bypass the rest of SM setup altogether! */
  705. /************************************************************************/
  706. WDW_OnSMConnected(pTSWd, NM_CB_CONN_OK);
  707. DC_EXIT_POINT:
  708. /************************************************************************/
  709. /* Clean up anything we created if we failed. */
  710. /************************************************************************/
  711. if (status == STATUS_SUCCESS) {
  712. pTSWd->pSdIoctl = NULL;
  713. }
  714. else {
  715. TRC_NRM((TB, "Cleaning up..."));
  716. if (pTSWd->dcShare != NULL)
  717. {
  718. TRC_NRM((TB, "Deleting Share object"));
  719. WDWDeleteShareClass(pTSWd);
  720. }
  721. if (smInit)
  722. {
  723. TRC_NRM((TB, "Terminating SM"));
  724. SM_Term(pTSWd->pSmInfo);
  725. }
  726. }
  727. DC_END_FN();
  728. return status;
  729. } /* WDWConsoleConnect */
  730. /****************************************************************************/
  731. /* Name: WDWShadowConnect */
  732. /* */
  733. /* Purpose: Processes an IOCTL_ICA_STACK_SET_CONNECTED ioctl from TermSrv.*
  734. /* The contents of this message are gathered from the shadow */
  735. /* client. */
  736. /* */
  737. /* Params: IN pTSWd - pointer to WD struct */
  738. /* INOUT PSD_IOCTL - pointer to received IOCtl */
  739. /* */
  740. /* Operation: Parse the user data for core bits and SM bits. */
  741. /* pull the values we want out of the core piece */
  742. /* initialize the Security Manager */
  743. /* create a share core, passing in the key values from user data */
  744. /* tell the user manager to proceed with connecting */
  745. /****************************************************************************/
  746. NTSTATUS WDWShadowConnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
  747. {
  748. NTSTATUS status = STATUS_SUCCESS;
  749. MCSError MCSErr;
  750. UserHandle hUser;
  751. ChannelHandle hChannel;
  752. UINT32 maxPDUSize;
  753. BOOLEAN bCompleted;
  754. BOOL bSuccess = FALSE;
  755. BOOLEAN bOldShadow = FALSE;
  756. RNS_UD_CS_CORE clientCoreData, *pClientCoreData;
  757. RNS_UD_CS_SEC clientSecurityData, *pClientSecurityData;
  758. RNS_UD_CS_NET clientNetData, *pClientNetData;
  759. PTS_UD_CS_CLUSTER pClientClusterData;
  760. PTSHARE_MODULE_DATA pModuleData =
  761. (PTSHARE_MODULE_DATA) pSdIoctl->InputBuffer;
  762. PTSHARE_MODULE_DATA_B3 pModuleDataB3 =
  763. (PTSHARE_MODULE_DATA_B3) pSdIoctl->InputBuffer;
  764. DC_BEGIN_FN("WDWShadowConnect");
  765. TRC_ERR((TB,
  766. "%s stack: WDWShadowConnect (data=%p), (size=%ld)",
  767. pTSWd->StackClass == Stack_Shadow ? "Shadow" :
  768. (pTSWd->StackClass == Stack_Primary ? "Primary" : "Passthru"),
  769. pModuleData, pSdIoctl->InputBufferLength));
  770. /************************************************************************/
  771. /* Validate that the output buffer is big enough */
  772. /************************************************************************/
  773. if ((pSdIoctl->OutputBuffer == NULL) ||
  774. (pSdIoctl->OutputBufferLength < MIN_USERDATAINFO_SIZE) ||
  775. (((PUSERDATAINFO)pSdIoctl->OutputBuffer)->cbSize <
  776. MIN_USERDATAINFO_SIZE))
  777. {
  778. if (pSdIoctl->OutputBuffer != NULL)
  779. {
  780. /****************************************************************/
  781. /* Buffer has been supplied but is too small, - so tell */
  782. /* TShareSRV how big a buffer we actually need. */
  783. /****************************************************************/
  784. ((PUSERDATAINFO)pSdIoctl->OutputBuffer)->cbSize
  785. = MIN_USERDATAINFO_SIZE;
  786. TRC_ERR((TB, "Telling rdpwsx to have another go with %d",
  787. MIN_USERDATAINFO_SIZE));
  788. }
  789. else
  790. {
  791. TRC_ERR((TB, "No Out Buffer on TSHARE_SHADOW_CONNECT."));
  792. }
  793. status = STATUS_BUFFER_TOO_SMALL;
  794. DC_QUIT;
  795. }
  796. switch (pTSWd->StackClass) {
  797. // Use the parameters we collected from the shadow client
  798. case Stack_Shadow:
  799. // B3 and B3_oops! servers used a fixed length user data structure
  800. if (pSdIoctl->InputBufferLength == sizeof(TSHARE_MODULE_DATA_B3)) {
  801. TRC_ERR((TB, "B3 shadow request!: %ld", pSdIoctl->InputBufferLength));
  802. bSuccess = WDWParseUserData(
  803. pTSWd, NULL, 0,
  804. (PRNS_UD_HEADER) &pModuleDataB3->clientCoreData,
  805. sizeof(RNS_UD_CS_CORE_V0) + sizeof(RNS_UD_CS_SEC_V0),
  806. &pClientCoreData,
  807. &pClientSecurityData,
  808. &pClientNetData,
  809. &pClientClusterData);
  810. bOldShadow = TRUE;
  811. }
  812. else if (pSdIoctl->InputBufferLength == sizeof(TSHARE_MODULE_DATA_B3_OOPS)) {
  813. TRC_ERR((TB, "B3 Oops! shadow request!: %ld", pSdIoctl->InputBufferLength));
  814. bSuccess = WDWParseUserData(
  815. pTSWd, NULL, 0,
  816. (PRNS_UD_HEADER)&pModuleDataB3->clientCoreData,
  817. sizeof(RNS_UD_CS_CORE_V1) + sizeof(RNS_UD_CS_SEC_V1),
  818. &pClientCoreData,
  819. &pClientSecurityData,
  820. &pClientNetData,
  821. &pClientClusterData);
  822. bOldShadow = TRUE;
  823. }
  824. // else, parse variable length data
  825. else if (pSdIoctl->InputBufferLength == (sizeof(TSHARE_MODULE_DATA) +
  826. pModuleData->userDataLen - sizeof(RNS_UD_HEADER))) {
  827. TRC_ERR((TB, "RC1 shadow request!: %ld", pSdIoctl->InputBufferLength));
  828. bSuccess = WDWParseUserData(
  829. pTSWd, NULL, 0,
  830. (PRNS_UD_HEADER) &pModuleData->userData,
  831. pModuleData->userDataLen,
  832. &pClientCoreData,
  833. &pClientSecurityData,
  834. &pClientNetData,
  835. &pClientClusterData);
  836. }
  837. else {
  838. TRC_ERR((TB, "Invalid module data size: %ld",
  839. pSdIoctl->InputBufferLength));
  840. bSuccess = FALSE;
  841. status = STATUS_INVALID_PARAMETER;
  842. DC_QUIT;
  843. }
  844. if (bSuccess) {
  845. TRC_ALT((TB, "Parsed shadow user data: %ld",
  846. pSdIoctl->InputBufferLength));
  847. }
  848. else {
  849. status = STATUS_INVALID_PARAMETER;
  850. DC_QUIT;
  851. }
  852. break;
  853. // passthru stacks are initialized to defaults on open, but we can't
  854. // return any user data until rdpwsx asks for it. If the user data is
  855. // hanging around then return it, otherwise generate it.
  856. case Stack_Passthru:
  857. if (pTSWd->pUserData != NULL) {
  858. memcpy(pSdIoctl->OutputBuffer, pTSWd->pUserData,
  859. pTSWd->pUserData->cbSize);
  860. pSdIoctl->OutputBufferLength = pTSWd->pUserData->cbSize;
  861. pSdIoctl->BytesReturned = pTSWd->pUserData->cbSize;
  862. status = STATUS_SUCCESS;
  863. COM_Free(pTSWd->pUserData);
  864. pTSWd->pUserData = NULL;
  865. DC_QUIT;
  866. }
  867. pClientCoreData = &clientCoreData;
  868. pClientSecurityData = &clientSecurityData;
  869. pClientNetData = &clientNetData;
  870. WDWGetDefaultCoreParams(pClientCoreData);
  871. SM_GetDefaultSecuritySettings(pClientSecurityData);
  872. TRC_ALT((TB, "WDWShadowConnect: Defaulting passthru stack params"))
  873. break;
  874. default:
  875. TRC_ERR((TB, "WDWShadowConnect: Unexpected stack type: %ld",
  876. pTSWd->StackClass));
  877. status = STATUS_INVALID_PARAMETER;
  878. DC_QUIT;
  879. break;
  880. }
  881. status = WDWConnect(pTSWd,
  882. pClientCoreData,
  883. pClientSecurityData,
  884. NULL,
  885. NULL,
  886. pSdIoctl,
  887. bOldShadow);
  888. // If we successfully connected the server to the share, then connect the
  889. // remote client as well.
  890. if (NT_SUCCESS(status)) {
  891. MCSErr = MCSAttachUserRequest(pTSWd->hDomainKernel,
  892. NULL, // request callback (remote)
  893. NULL, // data callback (remote)
  894. NULL, // context (remote)
  895. &hUser,
  896. &maxPDUSize,
  897. &bCompleted);
  898. if (MCSErr != MCS_NO_ERROR)
  899. {
  900. TRC_ERR((TB, "Shadow MCSAttachUserRequest failed %d", MCSErr));
  901. status = STATUS_INSUFFICIENT_RESOURCES;
  902. DC_QUIT;
  903. }
  904. // Join the remote user to the broadcast channel
  905. MCSErr = MCSChannelJoinRequest(hUser, pTSWd->broadcastChannel,
  906. &hChannel, &bCompleted);
  907. if (MCSErr != MCS_NO_ERROR)
  908. {
  909. TRC_ERR((TB, "Remote broadcast channel join failed returned %d", MCSErr));
  910. status = STATUS_INSUFFICIENT_RESOURCES;
  911. DC_QUIT;
  912. }
  913. // Join the remote user to their own private channel
  914. MCSErr = MCSChannelJoinRequest(hUser, MCSGetUserIDFromHandle(hUser),
  915. &hChannel, &bCompleted);
  916. if (MCSErr != MCS_NO_ERROR)
  917. {
  918. TRC_ERR((TB, "Remote user channel join failed %d", MCSErr));
  919. status = STATUS_INSUFFICIENT_RESOURCES;
  920. DC_QUIT;
  921. }
  922. // Tell MCS which channel(s) we want shadowed.
  923. if (pTSWd->StackClass == Stack_Shadow) {
  924. MCSErr = MCSSetShadowChannel(pTSWd->hDomainKernel,
  925. pTSWd->broadcastChannel);
  926. if (MCSErr != MCS_NO_ERROR)
  927. {
  928. TRC_ERR((TB, "Remote user channel join failed %d", MCSErr));
  929. status = STATUS_INSUFFICIENT_RESOURCES;
  930. DC_QUIT;
  931. }
  932. }
  933. }
  934. DC_EXIT_POINT:
  935. if (NT_SUCCESS(status)) {
  936. TRC_ALT((TB, "WDWShadowConnect [%ld]: success!", pTSWd->StackClass));
  937. }
  938. else {
  939. TRC_ERR((TB, "WDWShadowConnect [%ld]: failed! rc=%lx",
  940. pTSWd->StackClass, status));
  941. }
  942. DC_END_FN();
  943. return status;
  944. } /* WDWShadowConnect */
  945. /****************************************************************************/
  946. /* Name: WDWGetClientData */
  947. /* */
  948. /* Purpose: Process an IOCTL_ICA_STACK_QUERY_CLIENT */
  949. /* */
  950. /* Returns: STATUS_SUCCESS so long as buffer is big enough. */
  951. /* */
  952. /* Params: IN pTSWd - WD ptr. */
  953. /* IN pSdIoctl - IOCtl struct. */
  954. /* */
  955. /* Operation: Wait for the connected indication (this is to prevent the */
  956. /* rest of the system going running off before we're ready). */
  957. /* */
  958. /* Fill in the required data and then return the IOCtl. */
  959. /****************************************************************************/
  960. NTSTATUS WDWGetClientData(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
  961. {
  962. NTSTATUS status = STATUS_SUCCESS;
  963. PWINSTATIONCLIENTW pClientData =
  964. (PWINSTATIONCLIENTW)pSdIoctl->OutputBuffer;
  965. DC_BEGIN_FN("WDWGetClientData");
  966. /************************************************************************/
  967. /* Validate that the output buffer is big enough */
  968. /************************************************************************/
  969. if (pClientData != NULL &&
  970. pSdIoctl->OutputBufferLength >= sizeof(WINSTATIONCLIENTW)) {
  971. memset(pClientData, 0, sizeof(WINSTATIONCLIENTW));
  972. }
  973. else {
  974. status = STATUS_BUFFER_TOO_SMALL;
  975. TRC_ERR((TB,
  976. "Stack_Query_Client OutBuf too small - expected/got %d/%d",
  977. sizeof(WINSTATIONCLIENTW),
  978. pSdIoctl->OutputBufferLength));
  979. DC_QUIT;
  980. }
  981. /************************************************************************/
  982. /* ...and now fill out the reply buffer. */
  983. /************************************************************************/
  984. pClientData->fTextOnly = 0;
  985. /************************************************************************/
  986. /* Set the client StartSessionInfo values as specified by the client. */
  987. /************************************************************************/
  988. pClientData->fMouse = (pTSWd->pInfoPkt->flags & RNS_INFO_MOUSE) != 0;
  989. pClientData->fDisableCtrlAltDel = (pTSWd->pInfoPkt->flags &
  990. RNS_INFO_DISABLECTRLALTDEL) != 0;
  991. pClientData->fEnableWindowsKey = (pTSWd->pInfoPkt->flags &
  992. RNS_INFO_ENABLEWINDOWSKEY) != 0;
  993. pClientData->fDoubleClickDetect = (pTSWd->pInfoPkt->flags &
  994. RNS_INFO_DOUBLECLICKDETECT) != 0;
  995. pClientData->fMaximizeShell = (pTSWd->pInfoPkt->flags &
  996. RNS_INFO_MAXIMIZESHELL) != 0;
  997. pClientData->fRemoteConsoleAudio = (pTSWd->pInfoPkt->flags &
  998. RNS_INFO_REMOTECONSOLEAUDIO) != 0;
  999. wcsncpy(pClientData->Domain, (LPWSTR)pTSWd->pInfoPkt->Domain,
  1000. ((sizeof(pClientData->Domain) / sizeof(WCHAR)) - 1));
  1001. pClientData->Domain[sizeof(pClientData->Domain) / sizeof(WCHAR) - 1] =
  1002. L'\0';
  1003. wcsncpy(pClientData->UserName, (LPWSTR)pTSWd->pInfoPkt->UserName,
  1004. ((sizeof(pClientData->UserName) / sizeof(WCHAR)) - 1));
  1005. pClientData->UserName[sizeof(pClientData->UserName) / sizeof(WCHAR) - 1] =
  1006. L'\0';
  1007. wcsncpy(pClientData->Password, (LPWSTR)pTSWd->pInfoPkt->Password,
  1008. ((sizeof(pClientData->Password) / sizeof(WCHAR)) - 1));
  1009. pClientData->Password[sizeof(pClientData->Password) / sizeof(WCHAR) - 1] =
  1010. L'\0';
  1011. pClientData->fPromptForPassword = !(pTSWd->pInfoPkt->flags &
  1012. RNS_INFO_AUTOLOGON);
  1013. /************************************************************************/
  1014. /* The next fields are only used for the case (now supported by us) */
  1015. /* where the function is to have a specific app loaded as part of the */
  1016. /* WinStation creation. */
  1017. /************************************************************************/
  1018. memcpy(pClientData->WorkDirectory, pTSWd->pInfoPkt->WorkingDir,
  1019. sizeof(pClientData->WorkDirectory));
  1020. memcpy(pClientData->InitialProgram, pTSWd->pInfoPkt->AlternateShell,
  1021. sizeof(pClientData->InitialProgram));
  1022. // These fields are set by post Win2000 Beta 3 clients
  1023. pClientData->SerialNumber = pTSWd->serialNumber;
  1024. pClientData->ClientAddressFamily = pTSWd->clientAddressFamily;
  1025. wcscpy(pClientData->ClientAddress, pTSWd->clientAddress);
  1026. wcscpy(pClientData->ClientDirectory, pTSWd->clientDir);
  1027. // Client time zone information
  1028. pClientData->ClientTimeZone.Bias = pTSWd->clientTimeZone.Bias;
  1029. pClientData->ClientTimeZone.StandardBias = pTSWd->clientTimeZone.StandardBias;
  1030. pClientData->ClientTimeZone.DaylightBias = pTSWd->clientTimeZone.DaylightBias;
  1031. memcpy(&pClientData->ClientTimeZone.StandardName,&pTSWd->clientTimeZone.StandardName,
  1032. sizeof(pClientData->ClientTimeZone.StandardName));
  1033. memcpy(&pClientData->ClientTimeZone.DaylightName,&pTSWd->clientTimeZone.DaylightName,
  1034. sizeof(pClientData->ClientTimeZone.DaylightName));
  1035. pClientData->ClientTimeZone.StandardDate.wYear = pTSWd->clientTimeZone.StandardDate.wYear ;
  1036. pClientData->ClientTimeZone.StandardDate.wMonth = pTSWd->clientTimeZone.StandardDate.wMonth ;
  1037. pClientData->ClientTimeZone.StandardDate.wDayOfWeek = pTSWd->clientTimeZone.StandardDate.wDayOfWeek ;
  1038. pClientData->ClientTimeZone.StandardDate.wDay = pTSWd->clientTimeZone.StandardDate.wDay ;
  1039. pClientData->ClientTimeZone.StandardDate.wHour = pTSWd->clientTimeZone.StandardDate.wHour ;
  1040. pClientData->ClientTimeZone.StandardDate.wMinute = pTSWd->clientTimeZone.StandardDate.wMinute ;
  1041. pClientData->ClientTimeZone.StandardDate.wSecond = pTSWd->clientTimeZone.StandardDate.wSecond ;
  1042. pClientData->ClientTimeZone.StandardDate.wMilliseconds = pTSWd->clientTimeZone.StandardDate.wMilliseconds;
  1043. pClientData->ClientTimeZone.DaylightDate.wYear = pTSWd->clientTimeZone.DaylightDate.wYear ;
  1044. pClientData->ClientTimeZone.DaylightDate.wMonth = pTSWd->clientTimeZone.DaylightDate.wMonth ;
  1045. pClientData->ClientTimeZone.DaylightDate.wDayOfWeek = pTSWd->clientTimeZone.DaylightDate.wDayOfWeek ;
  1046. pClientData->ClientTimeZone.DaylightDate.wDay = pTSWd->clientTimeZone.DaylightDate.wDay ;
  1047. pClientData->ClientTimeZone.DaylightDate.wHour = pTSWd->clientTimeZone.DaylightDate.wHour ;
  1048. pClientData->ClientTimeZone.DaylightDate.wMinute = pTSWd->clientTimeZone.DaylightDate.wMinute ;
  1049. pClientData->ClientTimeZone.DaylightDate.wSecond = pTSWd->clientTimeZone.DaylightDate.wSecond ;
  1050. pClientData->ClientTimeZone.DaylightDate.wMilliseconds = pTSWd->clientTimeZone.DaylightDate.wMilliseconds;
  1051. // Client session id
  1052. pClientData->ClientSessionId = pTSWd->clientSessionId;
  1053. // Client performance flags (currently just disabled feature list)
  1054. pClientData->PerformanceFlags = pTSWd->performanceFlags;
  1055. // Client active input locale
  1056. pClientData->ActiveInputLocale = pTSWd->activeInputLocale;
  1057. // Set the client encryption level.
  1058. pClientData->EncryptionLevel = (BYTE)
  1059. ((PSM_HANDLE_DATA)(pTSWd->pSmInfo))->encryptionLevel;
  1060. /************************************************************************/
  1061. /* Unused. */
  1062. /************************************************************************/
  1063. pClientData->ClientLicense[0] = '\0';
  1064. pClientData->ClientModem[0] = '\0';
  1065. pClientData->ClientHardwareId = 0;
  1066. /************************************************************************/
  1067. /* Finally some real values. */
  1068. /************************************************************************/
  1069. wcscpy(pClientData->ClientName, pTSWd->clientName);
  1070. pClientData->ClientBuildNumber = pTSWd->clientBuild;
  1071. pClientData->ClientProductId = pTSWd->clientProductId;
  1072. pClientData->OutBufCountClient = TSHARE_WD_BUFFER_COUNT;
  1073. pClientData->OutBufCountHost = TSHARE_WD_BUFFER_COUNT;
  1074. pClientData->OutBufLength = 1460; /* LARGE_OUTBUF_SIZE in TermDD. */
  1075. pClientData->HRes = (UINT16)pTSWd->desktopWidth;
  1076. pClientData->VRes = (UINT16)pTSWd->desktopHeight;
  1077. pClientData->ProtocolType = PROTOCOL_RDP;
  1078. pClientData->KeyboardLayout = pTSWd->kbdLayout;
  1079. //shadow loop fix
  1080. wcscpy( pClientData->clientDigProductId, pTSWd->clientDigProductId );
  1081. /************************************************************************/
  1082. /* WinAdmin uses special numbers for ColorDepth. */
  1083. /************************************************************************/
  1084. #ifdef DC_HICOLOR
  1085. pClientData->ColorDepth = (pTSWd->desktopBpp == 4 ? 1 :
  1086. pTSWd->desktopBpp == 8 ? 2 :
  1087. pTSWd->desktopBpp == 16 ? 4 :
  1088. pTSWd->desktopBpp == 24 ? 8 :
  1089. pTSWd->desktopBpp == 15 ? 16:
  1090. 2);
  1091. #else
  1092. pClientData->ColorDepth = (pTSWd->desktopBpp == 4 ? 1 :
  1093. pTSWd->desktopBpp == 8 ? 2 :
  1094. pTSWd->desktopBpp == 16 ? 4 :
  1095. pTSWd->desktopBpp == 24 ? 8 :
  1096. 2);
  1097. #endif
  1098. /************************************************************************/
  1099. /* FE data */
  1100. /************************************************************************/
  1101. pClientData->KeyboardType = pTSWd->keyboardType;
  1102. pClientData->KeyboardSubType = pTSWd->keyboardSubType;
  1103. pClientData->KeyboardFunctionKey = pTSWd->keyboardFunctionKey;
  1104. wcscpy(pClientData->imeFileName, pTSWd->imeFileName);
  1105. pSdIoctl->BytesReturned = sizeof(WINSTATIONCLIENTW);
  1106. DC_EXIT_POINT:
  1107. DC_END_FN();
  1108. return status;
  1109. } /* WDWGetClientData */
  1110. /****************************************************************************/
  1111. /* Name: WDWGetExtendedClientData */
  1112. /* */
  1113. /* Purpose: Process an IOCTL_ICA_STACK_QUERY_CLIENT_EXTENSION */
  1114. /* Was introduced for Long UserName, Password support */
  1115. /* */
  1116. /* Returns: STATUS_SUCCESS so long as buffer is big enough. */
  1117. /* */
  1118. /* Params: IN RnsInfoPacket - ptr to protocol packet from client. */
  1119. /* IN pSdIoctl - IOCtl struct. */
  1120. /* */
  1121. /* Operation: Fill in the required data and then return the IOCtl. */
  1122. /* The data filled in are the long UserName, Password and Domain */
  1123. /****************************************************************************/
  1124. NTSTATUS WDWGetExtendedClientData(RNS_INFO_PACKET *RnsInfoPacket, PSD_IOCTL pSdIoctl)
  1125. {
  1126. NTSTATUS status = STATUS_SUCCESS;
  1127. pExtendedClientCredentials pExtendedClientData =
  1128. (pExtendedClientCredentials)pSdIoctl->OutputBuffer;
  1129. /************************************************************************/
  1130. /* Validate that the output buffer is big enough */
  1131. /************************************************************************/
  1132. if (pExtendedClientData != NULL &&
  1133. pSdIoctl->OutputBufferLength >= sizeof(ExtendedClientCredentials)) {
  1134. memset(pExtendedClientData, 0, sizeof(ExtendedClientCredentials));
  1135. }
  1136. else {
  1137. status = STATUS_BUFFER_TOO_SMALL;
  1138. return status;
  1139. }
  1140. //copy the long UserName, Password and Domain from protocol packet to the IOCTL buffer
  1141. wcsncpy(pExtendedClientData->Domain, (LPWSTR)RnsInfoPacket->Domain,
  1142. ((sizeof(pExtendedClientData->Domain) / sizeof(WCHAR)) - 1));
  1143. pExtendedClientData->Domain[sizeof(pExtendedClientData->Domain) / sizeof(WCHAR) - 1] =
  1144. L'\0';
  1145. wcsncpy(pExtendedClientData->UserName, (LPWSTR)RnsInfoPacket->UserName,
  1146. ((sizeof(pExtendedClientData->UserName) / sizeof(WCHAR)) - 1));
  1147. pExtendedClientData->UserName[sizeof(pExtendedClientData->UserName) / sizeof(WCHAR) - 1] =
  1148. L'\0';
  1149. wcsncpy(pExtendedClientData->Password, (LPWSTR)RnsInfoPacket->Password,
  1150. ((sizeof(pExtendedClientData->Password) / sizeof(WCHAR)) - 1));
  1151. pExtendedClientData->Password[sizeof(pExtendedClientData->Password) / sizeof(WCHAR) - 1] =
  1152. L'\0';
  1153. return status ;
  1154. }
  1155. //
  1156. // WDWGetAutoReconnectInfo
  1157. // Process an IOCTL_ICA_STACK_QUERY_AUTORECONNECT to retreive
  1158. // autoreconnect info.
  1159. //
  1160. // Returns: STATUS_SUCCESS so long as buffer is big enough.
  1161. //
  1162. // Params: IN RnsInfoPacket - ptr to protocol packet from client.
  1163. //
  1164. NTSTATUS WDWGetAutoReconnectInfo(PTSHARE_WD pTSWd,
  1165. RNS_INFO_PACKET* pRnsInfoPacket,
  1166. PSD_IOCTL pSdIoctl)
  1167. {
  1168. NTSTATUS status = STATUS_SUCCESS;
  1169. PTS_AUTORECONNECTINFO pAutoReconnectInfo;
  1170. BYTE fGetServerToClientInfo;
  1171. ULONG cb = 0;
  1172. DC_BEGIN_FN("WDWGetAutoReconnectInfo");
  1173. //
  1174. // Expect a byte as input
  1175. //
  1176. TRC_ASSERT((pSdIoctl->InputBufferLength == sizeof(BYTE)),
  1177. (TB,"Already an IOCTL linked from pTSWd"));
  1178. pAutoReconnectInfo = (PTS_AUTORECONNECTINFO)pSdIoctl->OutputBuffer;
  1179. memcpy(&fGetServerToClientInfo,
  1180. pSdIoctl->InputBuffer,
  1181. sizeof(fGetServerToClientInfo));
  1182. //
  1183. // Validate that the output buffer is big enough
  1184. //
  1185. if (pAutoReconnectInfo != NULL &&
  1186. pSdIoctl->OutputBufferLength >= sizeof(TS_AUTORECONNECTINFO)) {
  1187. memset(pAutoReconnectInfo, 0, sizeof(TS_AUTORECONNECTINFO));
  1188. }
  1189. else {
  1190. status = STATUS_BUFFER_TOO_SMALL;
  1191. TRC_ERR((TB,
  1192. "Stack_Query_Client OutBuf too small - expected/got %d/%d",
  1193. sizeof(TS_AUTORECONNECTINFO),
  1194. pSdIoctl->OutputBufferLength));
  1195. DC_QUIT;
  1196. }
  1197. if (fGetServerToClientInfo) {
  1198. //
  1199. // Get the server to client ARC cookie contents (if present)
  1200. //
  1201. if (pTSWd->arcTokenValid) {
  1202. pAutoReconnectInfo->cbAutoReconnectInfo = sizeof(pTSWd->arcCookie);
  1203. memcpy(pAutoReconnectInfo->AutoReconnectInfo,
  1204. pTSWd->arcCookie,
  1205. sizeof(pTSWd->arcCookie));
  1206. pSdIoctl->BytesReturned = sizeof(pTSWd->arcCookie);
  1207. }
  1208. else {
  1209. status = STATUS_NOT_FOUND;
  1210. }
  1211. }
  1212. else {
  1213. //
  1214. // Get info sent from the client to the server
  1215. //
  1216. if (pRnsInfoPacket->ExtraInfo.cbAutoReconnectLen <=
  1217. sizeof(pAutoReconnectInfo->AutoReconnectInfo)) {
  1218. pAutoReconnectInfo->cbAutoReconnectInfo =
  1219. pRnsInfoPacket->ExtraInfo.cbAutoReconnectLen;
  1220. memcpy(pAutoReconnectInfo->AutoReconnectInfo,
  1221. pRnsInfoPacket->ExtraInfo.autoReconnectCookie,
  1222. pRnsInfoPacket->ExtraInfo.cbAutoReconnectLen);
  1223. pSdIoctl->BytesReturned =
  1224. pRnsInfoPacket->ExtraInfo.cbAutoReconnectLen;
  1225. }
  1226. else {
  1227. status = STATUS_BUFFER_TOO_SMALL;
  1228. TRC_ERR((TB,
  1229. "Buffer from client too large got: %d limit: %d",
  1230. pRnsInfoPacket->ExtraInfo.cbAutoReconnectLen,
  1231. sizeof(pAutoReconnectInfo->AutoReconnectInfo)));
  1232. DC_QUIT;
  1233. }
  1234. }
  1235. DC_EXIT_POINT:
  1236. DC_END_FN();
  1237. return status;
  1238. }
  1239. /****************************************************************************/
  1240. /* Name: WDWParseUserData */
  1241. /* */
  1242. /* Purpose: Separate out the parts of the GCC User Data */
  1243. /* */
  1244. /* Returns: TRUE if all data found OK; else FALSE. */
  1245. /* */
  1246. /* Params: IN pTSWd - WD Handle */
  1247. /* IN pUserData - user data from TShareSRV (from indication) */
  1248. /* IN pHeader - optional post parse data (shadow) */
  1249. /* IN cbParsedData - optional post data length (shadow) */
  1250. /* OUT ppClientCoreData - ptr to Core data */
  1251. /* OUT ppClientSecurityData - ptr to SM data */
  1252. /* OUT ppNetSecurityData - ptr to Net data */
  1253. /* */
  1254. /* Operation: Locate our user data, then the two items required from within */
  1255. /* it. */
  1256. /****************************************************************************/
  1257. BOOL WDWParseUserData(
  1258. PTSHARE_WD pTSWd,
  1259. PUSERDATAINFO pUserData,
  1260. unsigned UserDataLen,
  1261. PRNS_UD_HEADER pHeader,
  1262. ULONG cbParsedData,
  1263. PPRNS_UD_CS_CORE ppClientCoreData,
  1264. PPRNS_UD_CS_SEC ppClientSecurityData,
  1265. PPRNS_UD_CS_NET ppClientNetData,
  1266. PTS_UD_CS_CLUSTER *ppClientClusterData)
  1267. {
  1268. BOOL success = FALSE;
  1269. GCCUserData *pClientUserData;
  1270. char clientH221Key[] = CLIENT_H221_KEY;
  1271. PRNS_UD_HEADER pEnd;
  1272. GCCOctetString UNALIGNED *pOctet;
  1273. unsigned char *pStr;
  1274. UINT32 dataLen;
  1275. UINT32 keyLen;
  1276. DC_BEGIN_FN("WDWParseUserData");
  1277. *ppClientNetData = NULL;
  1278. *ppClientSecurityData = NULL;
  1279. *ppClientCoreData = NULL;
  1280. *ppClientClusterData = NULL;
  1281. // Actual GCC user data so parse it to make sure it's good.
  1282. if (pHeader == NULL) {
  1283. // We assume the data length was checked by the caller for at least
  1284. // the length of the USERDATAINFO header. We have to validate the rest.
  1285. // We are expecting exactly 1 piece of user data.
  1286. if (pUserData->ulUserDataMembers == 1) {
  1287. // Check that it has a non-standard key.
  1288. pClientUserData = &(pUserData->rgUserData[0]);
  1289. if (pClientUserData->key.key_type == GCC_H221_NONSTANDARD_KEY) {
  1290. // Check it has our non-standard key.
  1291. keyLen = pClientUserData->key.u.h221_non_standard_id.
  1292. octet_string_length;
  1293. pStr = (unsigned char *)((BYTE *)pUserData +
  1294. (UINT_PTR)pClientUserData->key.u.
  1295. h221_non_standard_id.octet_string);
  1296. TRC_DATA_DBG("GCC_H221_NONSTANDARD_KEY", pStr, keyLen);
  1297. // We check here if this is exactly our key.
  1298. // pStr was obtained by adding to the pUserData an untrusted
  1299. // length so we have to check for overflow (pStr should not
  1300. // be smaller then pUserData). Then we check if adding keyLen
  1301. // will overrun our buffer.
  1302. if ((keyLen != sizeof(clientH221Key) - 1) ||
  1303. ((PBYTE)pStr < (PBYTE)pUserData) ||
  1304. ((PBYTE)pStr+keyLen > (PBYTE)(pUserData) + UserDataLen)) {
  1305. TRC_ERR((TB, "Invalid key buffer %d %p", keyLen, pStr));
  1306. WDW_LogAndDisconnect(pTSWd, TRUE,
  1307. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1308. DC_QUIT;
  1309. }
  1310. if (strncmp(pStr, clientH221Key, sizeof(clientH221Key) - 1)) {
  1311. TRC_ERR((TB, "Wrong key %*s", pStr));
  1312. WDW_LogAndDisconnect(pTSWd, TRUE,
  1313. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1314. DC_QUIT;
  1315. }
  1316. }
  1317. else {
  1318. TRC_ERR((TB, "Wrong key %d on user data",
  1319. pClientUserData->key.key_type));
  1320. WDW_LogAndDisconnect(pTSWd, TRUE,
  1321. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1322. DC_QUIT;
  1323. }
  1324. }
  1325. else {
  1326. TRC_ERR((TB,
  1327. "<%p> %d pieces of user data on Conf Create Indication: reject it",
  1328. pUserData->hDomain, pUserData->ulUserDataMembers));
  1329. WDW_LogAndDisconnect(pTSWd, TRUE,
  1330. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1331. DC_QUIT;
  1332. }
  1333. // This is our client data.
  1334. // Save the domain handle for later.
  1335. pTSWd->hDomain = pUserData->hDomain;
  1336. // Parse the user data. Make sure the octet string is well-formed.
  1337. // pClientUserData->octet_string is an offset from the start of the
  1338. // user data.
  1339. // Validate data length
  1340. if ((UINT_PTR)pClientUserData->octet_string < sizeof(USERDATAINFO))
  1341. {
  1342. TRC_ERR((TB,"UserData octet_string offset %p too short",
  1343. pClientUserData->octet_string));
  1344. WDW_LogAndDisconnect(pTSWd, TRUE,
  1345. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1346. DC_QUIT;
  1347. }
  1348. if ((UINT_PTR)pClientUserData->octet_string >= UserDataLen)
  1349. {
  1350. TRC_ERR((TB,"UserData octet_string offset %p too long for data len %u",
  1351. pClientUserData->octet_string, UserDataLen));
  1352. WDW_LogAndDisconnect(pTSWd, TRUE,
  1353. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1354. DC_QUIT;
  1355. }
  1356. pOctet = (GCCOctetString UNALIGNED *)((PBYTE)pUserData +
  1357. (UINT_PTR)pClientUserData->octet_string);
  1358. // Here we have to ckeck if we can actually dereference.
  1359. // We obtained pOcted by adding a size to the pUserData. And we already
  1360. // checked that what we added is less then the UserData length.
  1361. if (((LPBYTE)pOctet+sizeof(GCCOctetString) > (LPBYTE)pUserData+UserDataLen) ||
  1362. ((LPBYTE)pOctet+sizeof(GCCOctetString) < (LPBYTE)pOctet)) {
  1363. TRC_ERR((TB,"Not enough buffer for an sizeof(GCCOctetString)=%d at %p ",
  1364. sizeof(GCCOctetString), pOctet->octet_string));
  1365. WDW_LogAndDisconnect(pTSWd, TRUE,
  1366. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1367. DC_QUIT;
  1368. }
  1369. if ((UINT_PTR)pOctet->octet_string >= UserDataLen)
  1370. {
  1371. TRC_ERR((TB,"UserData octet_string offset %p too long for data len %u",
  1372. pOctet->octet_string, UserDataLen));
  1373. WDW_LogAndDisconnect(pTSWd, TRUE,
  1374. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1375. DC_QUIT;
  1376. }
  1377. pHeader = (PRNS_UD_HEADER)((PBYTE)pUserData +
  1378. (UINT_PTR)pOctet->octet_string);
  1379. dataLen = pOctet->octet_string_length;
  1380. // Validate the datalength
  1381. if (dataLen < sizeof(RNS_UD_HEADER))
  1382. {
  1383. TRC_ERR((TB, "Error: User data too short!"));
  1384. WDW_LogAndDisconnect(pTSWd, TRUE,
  1385. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1386. DC_QUIT;
  1387. }
  1388. // At this point we know that pHeader points within the buffer.
  1389. // We checked that the pOctet->octet_string is less then the UserDataLen
  1390. // We just have to check that we have enough buffer left
  1391. // after that fordataLen.
  1392. // Note taht dataLen at this point is at least the size of RNS_UD_HEADER.
  1393. if (((LPBYTE)pHeader +dataLen > (PBYTE)pUserData + UserDataLen ) ||
  1394. ((LPBYTE)pHeader +dataLen < (PBYTE)pHeader ) ||
  1395. (pHeader->length >dataLen)) {
  1396. TRC_ERR((TB,"Not enough buffer left to store RNS_UD_HEADER %p, %p, %u ",
  1397. pUserData, pHeader, UserDataLen ));
  1398. WDW_LogAndDisconnect(pTSWd, TRUE,
  1399. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1400. DC_QUIT;
  1401. }
  1402. }
  1403. // Else, this is pre-parsed user data via a shadow connection
  1404. else {
  1405. dataLen = cbParsedData;
  1406. }
  1407. // We assume that the pre-parsed data is trusted.
  1408. pEnd = (PRNS_UD_HEADER)((PBYTE)pHeader + dataLen);
  1409. TRC_DATA_DBG("Our client's User Data", pHeader, dataLen);
  1410. // Loop through user data, extracting each piece.
  1411. do {
  1412. switch (pHeader->type) {
  1413. case RNS_UD_CS_CORE_ID:
  1414. // Beta2 Client core user data did not include the new
  1415. // field postBeta2ColorDepth, so check that the length of
  1416. // the incoming user data is at least this long.
  1417. // The WDWConnect parses this data and it checks the length we
  1418. // supply before it derefs parameters that are declared after
  1419. // postBeta2ColorDepth in the struct.
  1420. if (pHeader->length >=
  1421. (FIELDOFFSET(RNS_UD_CS_CORE, postBeta2ColorDepth) +
  1422. FIELDSIZE(RNS_UD_CS_CORE, postBeta2ColorDepth))) {
  1423. *ppClientCoreData = (PRNS_UD_CS_CORE)pHeader;
  1424. TRC_DATA_DBG("Core data", pHeader, pHeader->length);
  1425. }
  1426. else {
  1427. TRC_ERR((TB, "Core data not long enough -- old client?"));
  1428. WDW_LogAndDisconnect(pTSWd, TRUE,
  1429. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1430. DC_QUIT;
  1431. }
  1432. break;
  1433. case RNS_UD_CS_SEC_ID:
  1434. // Old clients don't have the extEncryptionMethods.
  1435. // The extEncryptionMethods field is used only for french locale.
  1436. // We have to allow buffers that don't have space for extEncryptionMethods
  1437. // because the buffer will be processed in SM_Connect and there we take care of shorter fields.
  1438. // Nothing else processes this buffer after SM_Connect at this point.
  1439. if (pHeader->length >= FIELDOFFSET(RNS_UD_CS_SEC,encryptionMethods)
  1440. + FIELDSIZE(RNS_UD_CS_SEC,encryptionMethods)) {
  1441. *ppClientSecurityData = (PRNS_UD_CS_SEC)pHeader;
  1442. TRC_DATA_DBG("Security data", pHeader, pHeader->length);
  1443. } else {
  1444. TRC_ERR((TB, "Security data not long enough"));
  1445. WDW_LogAndDisconnect(pTSWd, TRUE,
  1446. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1447. DC_QUIT;
  1448. }
  1449. break;
  1450. case RNS_UD_CS_NET_ID:
  1451. if (pHeader->length >= sizeof(RNS_UD_CS_NET)) {
  1452. *ppClientNetData = (PRNS_UD_CS_NET)pHeader;
  1453. TRC_DATA_DBG("Net data", pHeader, pHeader->length);
  1454. } else {
  1455. TRC_ERR((TB, "Net data not long enough"));
  1456. WDW_LogAndDisconnect(pTSWd, TRUE,
  1457. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1458. DC_QUIT;
  1459. }
  1460. break;
  1461. case TS_UD_CS_CLUSTER_ID:
  1462. if (pHeader->length >=sizeof(TS_UD_CS_CLUSTER)) {
  1463. *ppClientClusterData = (TS_UD_CS_CLUSTER *)pHeader;
  1464. TRC_DATA_DBG("Cluster data", pHeader, pHeader->length);
  1465. } else {
  1466. TRC_ERR((TB, "Cluster data not long enough"));
  1467. WDW_LogAndDisconnect(pTSWd, TRUE,
  1468. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1469. DC_QUIT;
  1470. }
  1471. break;
  1472. default:
  1473. TRC_ERR((TB, "Unknown user data type %d", pHeader->type));
  1474. TRC_DATA_ERR("Unknown user data", pHeader, pHeader->length);
  1475. WDW_LogAndDisconnect(pTSWd, TRUE,
  1476. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1477. break;
  1478. }
  1479. if ((PBYTE)pHeader + pHeader->length < (PBYTE)pHeader) {
  1480. // we detected a length that causes overflow
  1481. TRC_ERR((TB, "Header length too big! Overflow detected !"));
  1482. WDW_LogAndDisconnect(pTSWd, TRUE,
  1483. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1484. DC_QUIT;
  1485. }
  1486. // We check the zero length now after we update the pHeader value.
  1487. // Otherwize we will exit with an error when we actually check the sizes.
  1488. // don't get stuck here for ever...
  1489. if (pHeader->length == 0) {
  1490. TRC_ERR((TB, "header length was zero!"));
  1491. break;
  1492. }
  1493. // Move on to the next user data string.
  1494. pHeader = (PRNS_UD_HEADER)((PBYTE)pHeader + pHeader->length);
  1495. } while ((pHeader +1) <= pEnd);
  1496. if ((PBYTE)pHeader > (PBYTE)pEnd)
  1497. {
  1498. TRC_ERR((TB, "Error: User data too short!"));
  1499. WDW_LogAndDisconnect(pTSWd, TRUE,
  1500. Log_RDP_BadUserData, (PBYTE)pUserData, UserDataLen);
  1501. DC_QUIT;
  1502. }
  1503. // Make sure we found all our client data. Note that Net and
  1504. // Cluster data blocks are optional - RDP4 client doesn't send Net data,
  1505. // RDP4 and 5 don't send Cluster data.
  1506. if ((*ppClientSecurityData == NULL) || (*ppClientCoreData == NULL)) {
  1507. TRC_ERR((TB,"<%p> Security [%p] or Core [%p] data missing",
  1508. pUserData ? pUserData->hDomain : 0,
  1509. *ppClientSecurityData, *ppClientCoreData));
  1510. DC_QUIT;
  1511. }
  1512. success = TRUE;
  1513. DC_EXIT_POINT:
  1514. DC_END_FN();
  1515. return success;
  1516. } /* WDWParseUserData */
  1517. /****************************************************************************/
  1518. /* Name: WDWVCMessage */
  1519. /* */
  1520. /* Purpose: Send a control message to the Client's VC subsystem */
  1521. /* */
  1522. /* Params: flags - VC header flags to send */
  1523. /****************************************************************************/
  1524. void WDWVCMessage(PTSHARE_WD pTSWd, UINT32 flags)
  1525. {
  1526. PVOID pBuffer;
  1527. CHANNEL_PDU_HEADER UNALIGNED *pHdr;
  1528. PNM_CHANNEL_DATA pChannelData;
  1529. UINT16 MCSChannelID;
  1530. DC_BEGIN_FN("WDWVCMessage");
  1531. /************************************************************************/
  1532. /* Pick a random channel - any channel will reach the VC subsystem */
  1533. /************************************************************************/
  1534. MCSChannelID = NM_VirtualChannelToMCS(pTSWd->pNMInfo,
  1535. 0,
  1536. &pChannelData);
  1537. /************************************************************************/
  1538. /* If channel 0 doesn't exist, there are no channels - drop out now. */
  1539. /************************************************************************/
  1540. if (MCSChannelID != (UINT16) -1)
  1541. {
  1542. /********************************************************************/
  1543. /* Get a buffer */
  1544. /********************************************************************/
  1545. if ( STATUS_SUCCESS == SM_AllocBuffer(pTSWd->pSmInfo, &pBuffer,
  1546. sizeof(CHANNEL_PDU_HEADER), TRUE, FALSE) )
  1547. {
  1548. pHdr = (CHANNEL_PDU_HEADER UNALIGNED *)pBuffer;
  1549. pHdr->flags = flags;
  1550. pHdr->length = sizeof(CHANNEL_PDU_HEADER);
  1551. /****************************************************************/
  1552. /* Send the info */
  1553. /****************************************************************/
  1554. SM_SendData(pTSWd->pSmInfo, pBuffer, sizeof(CHANNEL_PDU_HEADER),
  1555. TS_LOWPRIORITY, MCSChannelID, FALSE, RNS_SEC_ENCRYPT, FALSE);
  1556. TRC_NRM((TB, "Sent VC flags %#x", flags));
  1557. }
  1558. else
  1559. {
  1560. TRC_ERR((TB, "Failed to alloc %d byte buffer",
  1561. sizeof(CHANNEL_PDU_HEADER)));
  1562. }
  1563. }
  1564. else {
  1565. TRC_ALT((TB, "Dropping VC message for channel 0!"));
  1566. }
  1567. DC_END_FN();
  1568. } /* WDWVCMessage */
  1569. //
  1570. // WDWCompressToOutbuf
  1571. // Compressed the buffer directly into the outbuf.
  1572. // Caller MUST decide if input buf is in size range for compression
  1573. // and should handle copying over the buffer directly in that case.
  1574. //
  1575. // Note this function does not update the SC compression estimates.
  1576. // It is intended for compressing VC data. The SC compression estimates
  1577. // are used to predict how much space to allocate for the graphics outbuf's
  1578. // anyway so it is actually more appropriate for that estimate to be computed
  1579. // separately. VC compression does not need an estimate, we allocate up to
  1580. // our max channel chunk length.
  1581. //
  1582. // Params:
  1583. // pSrcData - input buffer
  1584. // cbSrcLen - length of input buffer
  1585. // pOutBuf - output buffer
  1586. // pcbOutLen- compressed output size
  1587. // Returns:
  1588. // Compression result (see compress() fn)
  1589. //
  1590. UCHAR WDWCompressToOutbuf(PTSHARE_WD pTSWd, UCHAR* pSrcData, ULONG cbSrcLen,
  1591. UCHAR* pOutBuf, ULONG* pcbOutLen)
  1592. {
  1593. UCHAR compressResult = 0;
  1594. ULONG CompressedSize = cbSrcLen;
  1595. DC_BEGIN_FN("WDWCompressToOutbuf");
  1596. TRC_ASSERT((pTSWd != NULL), (TB,"NULL pTSWd"));
  1597. TRC_ASSERT(((cbSrcLen > WD_MIN_COMPRESS_INPUT_BUF) &&
  1598. (cbSrcLen < MAX_COMPRESS_INPUT_BUF)),
  1599. (TB,"Compression src len out of range: %d",
  1600. cbSrcLen));
  1601. //Attempt to compress directly into the outbuf
  1602. compressResult = compress(pSrcData,
  1603. pOutBuf,
  1604. &CompressedSize,
  1605. pTSWd->pMPPCContext);
  1606. if(compressResult & PACKET_COMPRESSED)
  1607. {
  1608. //Successful compression.
  1609. TRC_ASSERT((CompressedSize >= CompressedSize),
  1610. (TB,"Compression created larger size than uncompr"));
  1611. compressResult |= pTSWd->bFlushed;
  1612. pTSWd->bFlushed = 0;
  1613. }
  1614. else if(compressResult & PACKET_FLUSHED)
  1615. {
  1616. //Overran compression history, copy over the
  1617. //uncompressed buffer.
  1618. pTSWd->bFlushed = PACKET_FLUSHED;
  1619. memcpy(pOutBuf, pSrcData, cbSrcLen);
  1620. pTSWd->pProtocolStatus->Output.CompressFlushes++;
  1621. }
  1622. else
  1623. {
  1624. TRC_ALT((TB, "Compression FAILURE"));
  1625. }
  1626. DC_END_FN();
  1627. *pcbOutLen = CompressedSize;
  1628. return compressResult;
  1629. }