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.

1072 lines
34 KiB

  1. /* (C) 1997-2000 Microsoft Corp.
  2. *
  3. * file : ConPDU.c
  4. * author : Erik Mavrinac
  5. *
  6. * description: Handles decoding of MCS connect PDUs. Connect PDUs are always
  7. * encoded with ASN.1 basic encoding rules (BER). Included in this file are
  8. * local functions to BER-decode and -encode various types used in MCS PDUs.
  9. *
  10. * History:
  11. * 11-Aug-1997 jparsons Fixed BER decode routines.
  12. */
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <MCSImpl.h>
  16. /*
  17. * Defines
  18. */
  19. // Return codes for encode/decode functions.
  20. #define H_OK 0
  21. #define H_TooShort 1
  22. #define H_BadContents 2
  23. #define H_Error 3
  24. /*
  25. * Prototypes for handler functions.
  26. */
  27. BOOLEAN __fastcall HandleConnectInitial(PDomain, BYTE *, unsigned, unsigned *);
  28. BOOLEAN __fastcall HandleConnectResponse(PDomain, BYTE *, unsigned, unsigned *);
  29. BOOLEAN __fastcall HandleConnectAdditional(PDomain, BYTE *, unsigned, unsigned *);
  30. BOOLEAN __fastcall HandleConnectResult(PDomain, BYTE *, unsigned, unsigned *);
  31. /*
  32. * These are listed in the 101-based enumeration order specified in the T.125
  33. * spec. Decode the initial BER connect PDU 0x7F, then subtract 101 decimal
  34. * from the next byte value to get an index into this table. E.g. the bytes
  35. * 0x7F65 at the beginning refer to a connect-initial PDU.
  36. */
  37. const MCSPDUInfo ConnectPDUTable[] = {
  38. StrOnDbg("Connect Initial", HandleConnectInitial),
  39. StrOnDbg("Connect Response", NULL /* HandleConnectResponse */),
  40. StrOnDbg("Connect Additional", NULL /* HandleConnectAdditional */),
  41. StrOnDbg("Connect Result", NULL /* HandleConnectResult */),
  42. };
  43. /*
  44. * Decodes BER strings used by MCS. A BER stream is a set of tags
  45. * containing ID-length-contents triplets, using byte values as type and
  46. * length indicators unless length escapes are used. For example, a
  47. * typical tag:
  48. *
  49. * 0x02 0x02 0x04 0x00
  50. *
  51. * Decomposition:
  52. * 0x02: Id = INTEGER_TAG
  53. * 0x02: Length = 2 octets
  54. * 0x04 0x00: Contents = 1024 (0x0400)
  55. *
  56. * Escaped tag:
  57. *
  58. * 0x04 0x82 0x04 0x00 0x8a 0x96...
  59. *
  60. * Decomposition:
  61. * 0x04: Id = OCTET_STRING_TAG
  62. * 0x82: Length stored in TWO bytes
  63. * 0x04 0x00: Length = 1024 octets
  64. * 0x8a 0x96...: Contents = 0x8 0x96... (1022 more octets)
  65. *
  66. * Returns FALSE if the frame is too small.
  67. *
  68. * History:
  69. * 11-Aug-97 jparsons Fixed pointer dereferencing error in calculating length
  70. *
  71. */
  72. #define LengthModifier_Indefinite 0x80
  73. #define LengthModifier_1 0x81
  74. #define LengthModifier_2 0x82
  75. #define LengthModifier_3 0x83
  76. #define LengthModifier_4 0x84
  77. #define TagType_Boolean 0x01
  78. #define TagType_Integer 0x02
  79. #define TagType_BitString 0x03
  80. #define TagType_OctetString 0x04
  81. #define TagType_Enumeration 0x0A
  82. #define TagType_Sequence 0x30
  83. #define TagType_SetOf 0x31
  84. #define TagType_ConnectInitial 0x65
  85. #define TagType_ConnectResponse 0x66
  86. #define TagType_ConnectAdditional 0x67
  87. #define TagType_ConnectResult 0x68
  88. int DecodeTagBER(
  89. PSDCONTEXT pContext, // For tracing.
  90. BYTE *Frame,
  91. unsigned *OutBytesLeft,
  92. int TagTypeExpected,
  93. unsigned *OutDataLength,
  94. UINT_PTR *Data,
  95. BYTE **newFrame)
  96. {
  97. int rc = H_OK;
  98. int TagType;
  99. unsigned i, BytesLeft, DataLength;
  100. BytesLeft = *OutBytesLeft;
  101. DataLength = *OutDataLength;
  102. if (BytesLeft >= 2) {
  103. // Get tag type, check it.
  104. TagType = *Frame;
  105. Frame++;
  106. BytesLeft--;
  107. if (TagType != TagTypeExpected) {
  108. ErrOut2(pContext, "Unexpected tag type found decoding BER tag, "
  109. "recv %d != expect %d", TagType, TagTypeExpected);
  110. rc = H_BadContents;
  111. goto ExitFunc;
  112. }
  113. }
  114. else {
  115. ErrOut(pContext, "BER PDU too short");
  116. rc = H_TooShort;
  117. goto ExitFunc;
  118. }
  119. // Find tag length indicator, including escapes.
  120. if (*Frame >= LengthModifier_Indefinite && *Frame <= LengthModifier_4) {
  121. unsigned NLengthBytes;
  122. // Check zero size for LengthModifier_Indefinite.
  123. NLengthBytes = 4 + *Frame - LengthModifier_4;
  124. if (NLengthBytes == 0)
  125. NLengthBytes = 1;
  126. if (BytesLeft >= NLengthBytes) {
  127. Frame++; // Now at beginning of length bytes
  128. BytesLeft--;
  129. DataLength = 0;
  130. for (i = 0; i < NLengthBytes; i++) {
  131. DataLength = (DataLength << 8) + (unsigned)(*Frame);
  132. Frame++;
  133. }
  134. BytesLeft -= NLengthBytes;
  135. }
  136. else {
  137. ErrOut(pContext, "BER PDU too short");
  138. rc = H_TooShort;
  139. goto ExitFunc;
  140. }
  141. }
  142. else {
  143. DataLength = *Frame;
  144. Frame++;
  145. BytesLeft--;
  146. }
  147. if (BytesLeft >= DataLength) {
  148. // Frame now points to beginning of contents. Fill out *Data with info
  149. // based on the tag type.
  150. switch (TagType) {
  151. case TagType_Boolean:
  152. case TagType_Integer:
  153. case TagType_Enumeration:
  154. // Fill in *Data with the actual data. Fill out *BytesLeft
  155. // so that we consume the contents. Discard if requested.
  156. if (Data != NULL) {
  157. unsigned Sum;
  158. Sum = 0;
  159. for (i = 0; i < DataLength; i++) {
  160. Sum = (Sum << 8) + *Frame;
  161. Frame++;
  162. }
  163. *Data = Sum;
  164. }
  165. else
  166. Frame += DataLength;
  167. BytesLeft -= DataLength;
  168. break;
  169. case TagType_OctetString:
  170. // Fill in *Data with a pointer into the frame of the
  171. // beginning of the data.
  172. if (Data != NULL)
  173. *Data = (UINT_PTR)Frame;
  174. Frame += DataLength;
  175. BytesLeft -= DataLength;
  176. break;
  177. // For these, we really just want to consume the tag and length
  178. case TagType_ConnectInitial:
  179. case TagType_Sequence:
  180. break;
  181. // MCS FUTURE: Add TagType_BitString
  182. default:
  183. ErrOut1(pContext, "Unknown TagType in DecodeTagBER (%u)",
  184. TagType);
  185. rc = H_BadContents;
  186. goto ExitFunc;
  187. }
  188. }
  189. else {
  190. ErrOut(pContext, "BER PDU too short");
  191. rc = H_TooShort;
  192. goto ExitFunc;
  193. }
  194. ExitFunc:
  195. *newFrame = Frame;
  196. *OutBytesLeft = BytesLeft;
  197. *OutDataLength = DataLength;
  198. return rc;
  199. }
  200. /*
  201. * BER-encodes by parameter type. Advances pointer at *Frame past the encoded
  202. * bytes to allow for a current-pointer mechanism to be used. Parameter
  203. * usage as follows:
  204. *
  205. * Tag type Params
  206. * ---------------------------------------------------------------
  207. * bool, int, enum Data: The value to encode, maximum 0x7FFFFFFF.
  208. * DataLength: Unused.
  209. *
  210. * octet str, seq DataLength: Length of the sequence/string.
  211. * Data: Pointer to beginning of data to copy.
  212. * (Data can be NULL to prevent copying user data.)
  213. *
  214. * bitstring Not yet supported
  215. */
  216. void EncodeTagBER (
  217. PSDCONTEXT pContext, // For tracing.
  218. BYTE *Frame,
  219. int TagType,
  220. unsigned DataLength,
  221. UINT_PTR Data,
  222. unsigned *pNBytesConsumed,
  223. BYTE **newFrame)
  224. {
  225. int i, Length, NBytesConsumed;
  226. // Encode tag type.
  227. *Frame = (BYTE)TagType;
  228. Frame++;
  229. NBytesConsumed = 1;
  230. // Encode tag length indicator, including escapes, then encode the actual
  231. // tag data, if applicable.
  232. switch (TagType) {
  233. case TagType_Boolean:
  234. case TagType_Integer:
  235. case TagType_Enumeration:
  236. // Encode the bool or int size in bytes.
  237. if (Data < 0x80) Length = 1;
  238. else if (Data < 0x8000) Length = 2;
  239. else if (Data < 0x800000) Length = 3;
  240. else if (Data < 0x80000000) Length = 4;
  241. else {
  242. ErrOut(pContext,
  243. "Cannot BER-encode the size for an int/bool tag");
  244. ASSERT(FALSE);
  245. break;
  246. }
  247. *Frame = (BYTE)Length;
  248. Frame++;
  249. NBytesConsumed++;
  250. // Encode the bool/int/enum data.
  251. for (i = 0; i < Length; i++) {
  252. *Frame = (BYTE)(Data >> (8 * (Length - 1 - i)));
  253. Frame++;
  254. }
  255. NBytesConsumed += Length;
  256. break;
  257. case TagType_OctetString:
  258. case TagType_Sequence:
  259. // Determine the length of DataLength. Escape if greater than 1.
  260. if (DataLength < 0x80)
  261. Length = 1;
  262. else if (DataLength < 0x8000) {
  263. Length = 2;
  264. *Frame = LengthModifier_2;
  265. Frame++;
  266. NBytesConsumed++;
  267. }
  268. else if (DataLength < 0x800000) {
  269. Length = 3;
  270. *Frame = LengthModifier_3;
  271. Frame++;
  272. NBytesConsumed++;
  273. }
  274. else if (DataLength < 0x80000000) {
  275. Length = 4;
  276. *Frame = LengthModifier_4;
  277. Frame++;
  278. NBytesConsumed++;
  279. }
  280. else {
  281. ErrOut(pContext,
  282. "Cannot BER-encode the length for an octet string tag");
  283. ASSERT(FALSE);
  284. break;
  285. }
  286. for (i = 0; i < Length; i++) {
  287. *Frame = (BYTE)(DataLength >> (8 * (Length - 1 - i)));
  288. Frame++;
  289. }
  290. NBytesConsumed += Length;
  291. // Encode the string data.
  292. if (((BYTE *)Data) != NULL) {
  293. // This case is never used since we create headers only.
  294. // If this were to be used we would need to copy memory.
  295. memcpy(Frame, (BYTE *)Data, DataLength);
  296. Frame += DataLength;
  297. NBytesConsumed += DataLength;
  298. }
  299. break;
  300. // MCS FUTURE: Add TagType_BitString.
  301. }
  302. *newFrame = Frame;
  303. *pNBytesConsumed = NBytesConsumed;
  304. }
  305. /*
  306. * BER-encodes the given domain parameters.
  307. */
  308. void EncodeDomainParameters(
  309. PSDCONTEXT pContext, // For tracing.
  310. BYTE *Frame,
  311. int *pNBytesConsumed,
  312. const DomainParameters *pDomParams,
  313. BYTE **newFrame)
  314. {
  315. BYTE *pSeqLength;
  316. unsigned NBytesConsumed, TotalBytes;
  317. // Encode the sequence tag type beginning manually. We'll fill in the
  318. // length after we're done with the rest of the domain parameters.
  319. *Frame = TagType_Sequence;
  320. pSeqLength = Frame + 1;
  321. Frame += 2;
  322. TotalBytes = 2;
  323. // Encode the 8 domain parameters.
  324. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  325. pDomParams->MaxChannels, &NBytesConsumed, newFrame);
  326. TotalBytes += NBytesConsumed;
  327. Frame = *newFrame;
  328. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  329. pDomParams->MaxUsers, &NBytesConsumed, newFrame);
  330. TotalBytes += NBytesConsumed;
  331. Frame = *newFrame;
  332. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  333. pDomParams->MaxTokens, &NBytesConsumed, newFrame);
  334. TotalBytes += NBytesConsumed;
  335. Frame = *newFrame;
  336. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  337. pDomParams->NumPriorities, &NBytesConsumed, newFrame);
  338. TotalBytes += NBytesConsumed;
  339. Frame = *newFrame;
  340. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  341. pDomParams->MinThroughput, &NBytesConsumed, newFrame);
  342. TotalBytes += NBytesConsumed;
  343. Frame = *newFrame;
  344. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  345. pDomParams->MaxDomainHeight, &NBytesConsumed, newFrame);
  346. TotalBytes += NBytesConsumed;
  347. Frame = *newFrame;
  348. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  349. pDomParams->MaxPDUSize, &NBytesConsumed, newFrame);
  350. TotalBytes += NBytesConsumed;
  351. Frame = *newFrame;
  352. EncodeTagBER(pContext, Frame, TagType_Integer, 0,
  353. pDomParams->ProtocolVersion, &NBytesConsumed, newFrame);
  354. TotalBytes += NBytesConsumed;
  355. Frame = *newFrame;
  356. *pNBytesConsumed = TotalBytes;
  357. *pSeqLength = TotalBytes - 2;
  358. }
  359. /*
  360. * BER-decodes domain parameters. Returns one of the H_... codes defined above.
  361. */
  362. int DecodeDomainParameters(
  363. PSDCONTEXT pContext, // For tracing.
  364. BYTE *Frame,
  365. unsigned *BytesLeft,
  366. DomainParameters *pDomParams,
  367. BYTE **newFrame)
  368. {
  369. int Result;
  370. unsigned DataLength = 0;
  371. UINT_PTR Data = 0;
  372. // Get sequence indicator and block length.
  373. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Sequence,
  374. &DataLength, &Data, newFrame);
  375. if (Result == H_OK) {
  376. if (*BytesLeft >= DataLength)
  377. Frame = *newFrame;
  378. else
  379. return H_TooShort;
  380. }
  381. else {
  382. return Result;
  383. }
  384. // Get all 8 integer-tag values.
  385. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  386. &DataLength, &Data, newFrame);
  387. if (Result == H_OK) {
  388. Frame = *newFrame;
  389. pDomParams->MaxChannels = (unsigned)Data;
  390. }
  391. else {
  392. return Result;
  393. }
  394. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  395. &DataLength, &Data, newFrame);
  396. if (Result == H_OK) {
  397. Frame = *newFrame;
  398. pDomParams->MaxUsers = (unsigned)Data;
  399. }
  400. else {
  401. return Result;
  402. }
  403. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  404. &DataLength, &Data, newFrame);
  405. if (Result == H_OK) {
  406. Frame = *newFrame;
  407. pDomParams->MaxTokens = (unsigned)Data;
  408. }
  409. else {
  410. return Result;
  411. }
  412. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  413. &DataLength, &Data, newFrame);
  414. if (Result == H_OK) {
  415. Frame = *newFrame;
  416. pDomParams->NumPriorities = (unsigned)Data;
  417. }
  418. else {
  419. return Result;
  420. }
  421. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  422. &DataLength, &Data, newFrame);
  423. if (Result == H_OK) {
  424. Frame = *newFrame;
  425. pDomParams->MinThroughput = (unsigned)Data;
  426. }
  427. else {
  428. return Result;
  429. }
  430. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  431. &DataLength, &Data, newFrame);
  432. if (Result == H_OK) {
  433. Frame = *newFrame;
  434. pDomParams->MaxDomainHeight = (unsigned)Data;
  435. }
  436. else {
  437. return Result;
  438. }
  439. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  440. &DataLength, &Data, newFrame);
  441. if (Result == H_OK) {
  442. Frame = *newFrame;
  443. pDomParams->MaxPDUSize = (unsigned)Data;
  444. }
  445. else {
  446. return Result;
  447. }
  448. Result = DecodeTagBER(pContext, Frame, BytesLeft, TagType_Integer,
  449. &DataLength, &Data, newFrame);
  450. if (Result == H_OK) {
  451. Frame = *newFrame;
  452. pDomParams->ProtocolVersion = (unsigned)Data;
  453. }
  454. else {
  455. return Result;
  456. }
  457. return H_OK;
  458. }
  459. /*
  460. * PDU 101
  461. *
  462. * Connect-Initial ::= [APPLICATION 101] IMPLICIT SEQUENCE {
  463. * callingDomainSelector OCTET STRING,
  464. * calledDomainSelector OCTET STRING,
  465. * upwardFlag BOOLEAN,
  466. * targetParameters DomainParameters,
  467. * minimumParameters DomainParameters,
  468. * maximumParameters DomainParameters,
  469. * userData OCTET STRING
  470. * }
  471. *
  472. * Returns FALSE if the in parameters are not acceptable.
  473. */
  474. BOOLEAN NegotiateDomParams(
  475. PDomain pDomain,
  476. DomainParameters *pTarget,
  477. DomainParameters *pMin,
  478. DomainParameters *pMax,
  479. DomainParameters *pOut)
  480. {
  481. // Maximum channels.
  482. if (pTarget->MaxChannels >= RequiredMinChannels) {
  483. pOut->MaxChannels = pTarget->MaxChannels;
  484. }
  485. else if (pMax->MaxChannels >= RequiredMinChannels) {
  486. pOut->MaxChannels = RequiredMinChannels;
  487. }
  488. else {
  489. ErrOut(pDomain->pContext, "Could not negotiate max channels");
  490. return FALSE;
  491. }
  492. // Maximum users.
  493. if (pTarget->MaxUsers >= RequiredMinUsers) {
  494. pOut->MaxUsers = pTarget->MaxUsers;
  495. }
  496. else if (pMax->MaxUsers >= RequiredMinUsers) {
  497. pOut->MaxUsers = RequiredMinUsers;
  498. }
  499. else {
  500. ErrOut(pDomain->pContext, "Could not negotiate max users");
  501. return FALSE;
  502. }
  503. // Maximum tokens. We don't implement tokens right now, so just take
  504. // the target number and we'll return an error if they try to use them.
  505. //MCS FUTURE: This needs to be negotiated if tokens are implemented.
  506. pOut->MaxTokens = pTarget->MaxTokens;
  507. // Number of data priorities. We accept only one priority.
  508. if (pMin->NumPriorities <= RequiredPriorities) {
  509. pOut->NumPriorities = RequiredPriorities;
  510. }
  511. else {
  512. ErrOut(pDomain->pContext, "Could not negotiate # priorities");
  513. return FALSE;
  514. }
  515. // Minimum throughput. We don't care about this, take whatever.
  516. pOut->MinThroughput = pTarget->MinThroughput;
  517. // Maximum domain height. We only allow a height of 1 in this product.
  518. //MCS FUTURE: This needs to change if we support deeper domains.
  519. if (pTarget->MaxDomainHeight == RequiredDomainHeight ||
  520. pMin->MaxDomainHeight <= RequiredDomainHeight) {
  521. pOut->MaxDomainHeight = RequiredDomainHeight;
  522. }
  523. else {
  524. ErrOut(pDomain->pContext, "Could not negotiate max domain height");
  525. return FALSE;
  526. }
  527. // Max MCS PDU size. Minimum required for headers and lowest X.224
  528. // allowable size. Max was negotiated by X.224.
  529. if (pTarget->MaxPDUSize >= RequiredMinPDUSize) {
  530. if (pTarget->MaxPDUSize <= pDomain->MaxX224DataSize) {
  531. pOut->MaxPDUSize = pTarget->MaxPDUSize;
  532. }
  533. else if (pMin->MaxPDUSize >= RequiredMinPDUSize &&
  534. pMin->MaxPDUSize <= pDomain->MaxX224DataSize) {
  535. // Take maximum possible size as long as we're within range.
  536. pOut->MaxPDUSize = pDomain->MaxX224DataSize;
  537. }
  538. else {
  539. ErrOut(pDomain->pContext, "Could not negotiate max PDU size, "
  540. "sender outside X.224 negotiated limits");
  541. return FALSE;
  542. }
  543. }
  544. else {
  545. if (pMax->MaxPDUSize >= RequiredMinPDUSize) {
  546. pOut->MaxPDUSize = pMax->MaxPDUSize;
  547. }
  548. else {
  549. ErrOut(pDomain->pContext, "Could not negotiate max PDU size, "
  550. "sender max too small");
  551. return FALSE;
  552. }
  553. }
  554. // MCS protocol version. We support only version 2.
  555. if (pTarget->ProtocolVersion == RequiredProtocolVer ||
  556. (pMin->ProtocolVersion <= RequiredProtocolVer &&
  557. pMax->ProtocolVersion >= RequiredProtocolVer)) {
  558. pOut->ProtocolVersion = RequiredProtocolVer;
  559. }
  560. else {
  561. ErrOut(pDomain->pContext, "Could not negotiate protocol version");
  562. return FALSE;
  563. }
  564. return TRUE;
  565. }
  566. BOOLEAN __fastcall HandleConnectInitial(
  567. PDomain pDomain,
  568. BYTE *Frame,
  569. unsigned BytesLeft,
  570. unsigned *pNBytesConsumed)
  571. {
  572. int Result;
  573. BYTE *SaveFrame, *pUserData, *pCPinBuf, *newFrame;
  574. UINT_PTR Data = 0;
  575. NTSTATUS Status;
  576. unsigned DataLength = 0;
  577. unsigned SaveBytesLeft;
  578. unsigned PDULength = 0;
  579. DomainParameters TargetParams, MinParams, MaxParams;
  580. ConnectProviderIndicationIoctl CPin;
  581. if (pDomain->State == State_X224_Connected) {
  582. // Save for error handling below.
  583. SaveBytesLeft = BytesLeft;
  584. newFrame = SaveFrame = Frame;
  585. // Get the PDU length, verify it against BytesLeft.
  586. Result = DecodeTagBER(pDomain->pContext, Frame, &BytesLeft,
  587. TagType_ConnectInitial, &PDULength, NULL, &newFrame);
  588. if (Result == H_OK) {
  589. if (BytesLeft >= PDULength)
  590. Frame = newFrame;
  591. else
  592. return FALSE;
  593. }
  594. else {
  595. goto BadResult;
  596. }
  597. }
  598. else {
  599. ErrOut(pDomain->pContext, "Connect-Initial PDU received when not in "
  600. "state X224_Connected");
  601. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  602. Log_MCS_UnexpectedConnectInitialPDU,
  603. Frame, BytesLeft);
  604. // Consume all the data given to us.
  605. *pNBytesConsumed = BytesLeft;
  606. return TRUE;
  607. }
  608. // Decode and skip calling domain selector.
  609. Result = DecodeTagBER(pDomain->pContext, Frame, &BytesLeft,
  610. TagType_OctetString, &DataLength, NULL, &newFrame);
  611. if (Result == H_OK)
  612. Frame = newFrame;
  613. else
  614. goto BadResult;
  615. // Decode and skip called domain selector.
  616. Result = DecodeTagBER(pDomain->pContext, Frame, &BytesLeft,
  617. TagType_OctetString, &DataLength, NULL, &newFrame);
  618. if (Result == H_OK)
  619. Frame = newFrame;
  620. else
  621. goto BadResult;
  622. // Decode Upward boolean.
  623. Result = DecodeTagBER(pDomain->pContext, Frame, &BytesLeft,
  624. TagType_Boolean, &DataLength, &Data, &newFrame);
  625. if (Result == H_OK) {
  626. Frame = newFrame;
  627. CPin.bUpwardConnection = (Data ? TRUE : FALSE);
  628. }
  629. else {
  630. goto BadResult;
  631. }
  632. // Decode target, max, min domain parameters. We will handle internal
  633. // negotiation for these parameters and pass up to the MUX only
  634. // the results, if the negotiation can succeed.
  635. Result = DecodeDomainParameters(pDomain->pContext, Frame, &BytesLeft,
  636. &TargetParams, &newFrame);
  637. if (Result == H_OK)
  638. Frame = newFrame;
  639. else
  640. goto BadResult;
  641. Result = DecodeDomainParameters(pDomain->pContext, Frame, &BytesLeft,
  642. &MinParams, &newFrame);
  643. if (Result == H_OK)
  644. Frame = newFrame;
  645. else
  646. goto BadResult;
  647. Result = DecodeDomainParameters(pDomain->pContext, Frame, &BytesLeft,
  648. &MaxParams, &newFrame);
  649. if (Result == H_OK)
  650. Frame = newFrame;
  651. else
  652. goto BadResult;
  653. // Get the user data (an octet string). After this Frame should point to
  654. // the end of the user data.
  655. Result = DecodeTagBER(pDomain->pContext, Frame, &BytesLeft,
  656. TagType_OctetString, &CPin.UserDataLength, &Data, &newFrame);
  657. if (Result == H_OK) {
  658. Frame = newFrame;
  659. pUserData = (BYTE *)Data;
  660. *pNBytesConsumed = SaveBytesLeft - BytesLeft;
  661. }
  662. else {
  663. goto BadResult;
  664. }
  665. // Check maximum user data size.
  666. if (CPin.UserDataLength > MaxGCCConnectDataLength) {
  667. POUTBUF pOutBuf;
  668. ICA_CHANNEL_COMMAND Command;
  669. ErrOut(pDomain->pContext, "HandleConnectInitial(): Attached user data "
  670. "is too large, returning error and failing connection");
  671. // Alloc OutBuf for sending PDU.
  672. // This allocation is vital to the session and must succeed.
  673. do {
  674. Status = IcaBufferAlloc(pDomain->pContext, FALSE, TRUE,
  675. ConnectResponseHeaderSize, NULL, &pOutBuf);
  676. if (Status != STATUS_SUCCESS)
  677. ErrOut(pDomain->pContext, "Could not allocate an OutBuf for a "
  678. "connect-response PDU, retrying");
  679. } while (Status != STATUS_SUCCESS);
  680. // Fill in PDU.
  681. // Encode PDU header. Param 2, the called connect ID, does not need to
  682. // be anything special because we do not allow extra sockets to be
  683. // opened for other data priorities.
  684. CreateConnectResponseHeader(pDomain->pContext,
  685. RESULT_UNSPECIFIED_FAILURE, 0, &pDomain->DomParams, 0, pOutBuf->pBuffer,
  686. &pOutBuf->ByteCount);
  687. // Send the PDU.
  688. Status = SendOutBuf(pDomain, pOutBuf);
  689. if (!NT_SUCCESS(Status)) {
  690. ErrOut(pDomain->pContext, "Could not send connect-response PDU "
  691. "to TD");
  692. // Ignore error -- this should only occur if stack is going down.
  693. return TRUE;
  694. }
  695. // Signal that we need to drop the link.
  696. Command.Header.Command = ICA_COMMAND_BROKEN_CONNECTION;
  697. Command.BrokenConnection.Reason = Broken_Unexpected;
  698. Command.BrokenConnection.Source = BrokenSource_Server;
  699. Status = IcaChannelInput(pDomain->pContext, Channel_Command,
  700. 0, NULL, (BYTE *)&Command, sizeof(Command));
  701. if (!NT_SUCCESS(Status))
  702. ErrOut(pDomain->pContext, "HandleConnectInitial(): Could not "
  703. "send BROKEN_CONN upward");
  704. return TRUE;
  705. }
  706. // Domain parameters negotiation.
  707. if (NegotiateDomParams(pDomain, &TargetParams, &MinParams, &MaxParams,
  708. &CPin.DomainParams)) {
  709. pDomain->DomParams = CPin.DomainParams;
  710. }
  711. else {
  712. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  713. Log_MCS_UnnegotiableDomainParams,
  714. Frame, BytesLeft);
  715. return TRUE;
  716. }
  717. // Calculate the MaxSendSize. This is the maximum PDU size minus the
  718. // maximum possible number of bytes for MCS headers and ASN.1
  719. // segmentation.
  720. pDomain->MaxSendSize = CPin.DomainParams.MaxPDUSize - 6 -
  721. GetTotalLengthDeterminantEncodingSize(
  722. CPin.DomainParams.MaxPDUSize);
  723. // Fill in remaining CPin fields and send to MCSMUX
  724. // MCS FUTURE: hConn should point to a real Connection object.
  725. CPin.Header.hUser = NULL; // Signals node controller traffic.
  726. CPin.Header.Type = MCS_CONNECT_PROVIDER_INDICATION;
  727. CPin.hConn = (PVOID) 1; // Non-NULL so we know this is remote connection.
  728. RtlCopyMemory(CPin.UserData, pUserData, CPin.UserDataLength);
  729. // Set state for this connection, we are waiting for a reply from NC.
  730. pDomain->State = State_ConnectProvIndPending;
  731. ASSERT(pDomain->bChannelBound);
  732. TraceOut(pDomain->pContext, "HandleConnectInitial(): Sending "
  733. "CONNECT_PROVIDER_IND upward");
  734. Status = IcaChannelInput(pDomain->pContext, Channel_Virtual,
  735. Virtual_T120ChannelNum, NULL, (BYTE *)&CPin, sizeof(CPin));
  736. if (!NT_SUCCESS(Status)) {
  737. ErrOut(pDomain->pContext, "ChannelInput failed on "
  738. "connect-provider indication");
  739. // Ignore errors here. This should only happen if stack is going down.
  740. return TRUE;
  741. }
  742. return TRUE;
  743. BadResult:
  744. if (Result == H_TooShort)
  745. return FALSE;
  746. // Must be H_BadContents.
  747. ErrOut(pDomain->pContext, "HandleConnectInitial(): Could not parse PDU, "
  748. "returning PDU reject");
  749. ReturnRejectPDU(pDomain, Diag_InvalidBEREncoding, SaveFrame,
  750. SaveBytesLeft - BytesLeft);
  751. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  752. Log_MCS_ConnectPDUBadPEREncoding,
  753. Frame, BytesLeft);
  754. // Attempt to skip the entire PDU.
  755. *pNBytesConsumed = SaveBytesLeft;
  756. // Return FALSE to force the caller to fail.
  757. return FALSE;
  758. }
  759. /*
  760. * PDU 102
  761. *
  762. * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE {
  763. * result Result,
  764. * calledConnectId INTEGER (0..MAX),
  765. * domainParameters DomainParameters,
  766. * userData OCTET STRING
  767. * }
  768. */
  769. // pBuffer is assumed to point to a buffer of at least size given
  770. // by macro ConnectResponseHeaderSize; X.224 header will start here.
  771. // Actual number of bytes used for the encoding is returned in
  772. // *pNBytesConsumed.
  773. // We do not encode the user data, but instead just the header, which
  774. // allows some optimization by allowing the header to be encoded
  775. // and copied to the beginning of user data.
  776. void CreateConnectResponseHeader(
  777. PSDCONTEXT pContext, // For tracing.
  778. MCSResult Result,
  779. int CalledConnectID,
  780. DomainParameters *pDomParams,
  781. unsigned UserDataLength,
  782. BYTE *pBuffer,
  783. unsigned *pNBytesConsumed)
  784. {
  785. BYTE *OutFrame, *newFrame;
  786. unsigned NBytesConsumed, TotalSize, EncodeLength;
  787. // Set up for creating the PDU.
  788. OutFrame = pBuffer + X224_DataHeaderSize;
  789. NBytesConsumed = 0;
  790. // Encode the BER prefix, PDU type, and leave space for the PDU length.
  791. // Note that the length is the number of bytes following this length
  792. // indicator.
  793. // The most-oft-encountered case is where the PDU length is less than 128
  794. // bytes. So, special-case larger sizes at the end of the function
  795. // when we know the total size.
  796. OutFrame[0] = MCS_CONNECT_PDU;
  797. OutFrame[1] = MCS_CONNECT_RESPONSE_ENUM;
  798. // Skip OutFrame[2] for the default 1-byte (<= 128) size.
  799. OutFrame += 3;
  800. TotalSize = 3;
  801. // Encode Result, CalledConnectID, DomParams. We use OutFrame
  802. // as a current pointer.
  803. EncodeTagBER(pContext, OutFrame, TagType_Enumeration, 0, Result,
  804. &NBytesConsumed, &newFrame);
  805. TotalSize += NBytesConsumed;
  806. OutFrame = newFrame;
  807. EncodeTagBER(pContext, OutFrame, TagType_Integer, 0, CalledConnectID,
  808. &NBytesConsumed, &newFrame);
  809. TotalSize += NBytesConsumed;
  810. OutFrame = newFrame;
  811. EncodeDomainParameters(pContext, OutFrame, &NBytesConsumed, pDomParams,
  812. &newFrame);
  813. TotalSize += NBytesConsumed;
  814. OutFrame = newFrame;
  815. // Encode only the length bytes, not the user data body.
  816. EncodeTagBER(pContext, OutFrame, TagType_OctetString, UserDataLength,
  817. (UINT_PTR)NULL, &NBytesConsumed, &newFrame);
  818. TotalSize += NBytesConsumed;
  819. OutFrame = newFrame;
  820. // Encode the final size. Here we special-case a too-large size by
  821. // shifting data around. The large size is the exceptional case.
  822. EncodeLength = TotalSize - 3 + UserDataLength;
  823. if (EncodeLength < 128) {
  824. pBuffer[2 + X224_DataHeaderSize] = (BYTE)EncodeLength;
  825. }
  826. else {
  827. unsigned i, Len = 0;
  828. WarnOut(pContext, "CreateConnRespHeader(): Perf hit from too-large "
  829. "PDU size");
  830. // Since we can only send up to 64K bytes, the length determinant
  831. // cannot be any more than 3 bytes long.
  832. ASSERT(EncodeLength < 65535);
  833. if (EncodeLength < 0x8000)
  834. Len = 2;
  835. else if (EncodeLength < 0x800000)
  836. Len = 3;
  837. else
  838. ASSERT(FALSE);
  839. // Size escape comes first.
  840. pBuffer[2 + X224_DataHeaderSize] = LengthModifier_2 + Len - 2;
  841. RtlMoveMemory(pBuffer + 3 + X224_DataHeaderSize + Len,
  842. pBuffer + 3 + X224_DataHeaderSize, EncodeLength - 3);
  843. for (i = 1; i <= Len; i++) {
  844. pBuffer[3 + X224_DataHeaderSize + Len - i] = (BYTE)EncodeLength;
  845. EncodeLength >>= 8;
  846. }
  847. // We already included one byte of the length encoding above, but
  848. // now we need to also skip the length escape and the encoded length.
  849. TotalSize += Len;
  850. }
  851. // Set up X224 header based on the final size of the packet.
  852. CreateX224DataHeader(pBuffer, TotalSize + UserDataLength, TRUE);
  853. *pNBytesConsumed = X224_DataHeaderSize + TotalSize;
  854. }
  855. #ifdef MCS_Future
  856. BOOLEAN __fastcall HandleConnectResponse(
  857. PDomain pDomain,
  858. BYTE *Frame,
  859. unsigned BytesLeft,
  860. unsigned *pNBytesConsumed)
  861. {
  862. //MCS FUTURE: This will be needed to handle the future case where we initiate
  863. //connections for joins/invites.
  864. ErrOut(pDomain->pContext, "Connect Response PDU received, "
  865. "this should never happen");
  866. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  867. Log_MCS_UnsupportedConnectPDU,
  868. Frame, BytesLeft);
  869. // Consume all the data given to us.
  870. *pNBytesConsumed = BytesLeft;
  871. return TRUE;
  872. }
  873. #endif // MCS_Future
  874. /*
  875. * PDU 103
  876. *
  877. * Connect-Additional ::= [APPLICATION 103] IMPLICIT SEQUENCE {
  878. * calledConnectId INTEGER (0..MAX),
  879. * dataPriority DataPriority
  880. * }
  881. *
  882. * No Create() funcion, we never expect to initiate these PDUs.
  883. *
  884. * We do not handle these PDUs for this Hydra release, since in the Citrix
  885. * framework there can be only one connection at a time. Domain parameters
  886. * should have been negotiated to only one connection handling all SendData
  887. * priorities.
  888. */
  889. #ifdef MCS_Future
  890. BOOLEAN __fastcall HandleConnectAdditional(
  891. PDomain pDomain,
  892. BYTE *Frame,
  893. unsigned BytesLeft,
  894. unsigned *pNBytesConsumed)
  895. {
  896. ErrOut(pDomain->pContext, "Connect-additional PDU received, "
  897. "this should never happen");
  898. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  899. Log_MCS_UnsupportedConnectPDU,
  900. Frame, BytesLeft);
  901. // Consume all the data given to us.
  902. *pNBytesConsumed = BytesLeft;
  903. return TRUE;
  904. }
  905. #endif // MCS_Future
  906. /*
  907. * PDU 104
  908. *
  909. * Connect-Result ::= [APPLICATION 104] IMPLICIT SEQUENCE {
  910. * result Result
  911. * }
  912. *
  913. * No Create() function, we never expect to initiate these PDUs.
  914. *
  915. * We do not handle these PDUs for this Hydra release, since in the Citrix
  916. * framework there can be only one connection at a time.
  917. */
  918. #ifdef MCS_Future
  919. BOOLEAN __fastcall HandleConnectResult(
  920. PDomain pDomain,
  921. BYTE *Frame,
  922. unsigned BytesLeft,
  923. unsigned *pNBytesConsumed)
  924. {
  925. ErrOut(pDomain->pContext, "Connect-result PDU received, "
  926. "this should never happen");
  927. MCSProtocolErrorEvent(pDomain->pContext, pDomain->pStat,
  928. Log_MCS_UnsupportedConnectPDU,
  929. Frame, BytesLeft);
  930. // Consume all the data given to us.
  931. *pNBytesConsumed = BytesLeft;
  932. return TRUE;
  933. }
  934. #endif // MCS_Future