Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

742 lines
17 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. tower.c
  5. Abstract:
  6. This file contains encoding/decoding for the tower representation
  7. of the binding information that DCE runtime uses.
  8. TowerConstruct/TowerExplode will be called by the Runtime EpResolveBinding
  9. on the client side, TowerExplode will be called by the Endpoint Mapper
  10. and in addition the name service may call TowerExplode, TowerConstruct.
  11. Author:
  12. Bharat Shah (barats) 3-23-92
  13. Revision History:
  14. --*/
  15. #include <precomp.hxx>
  16. #include <epmp.h>
  17. #include <twrtypes.h>
  18. #include <twrproto.h>
  19. //
  20. // TowerVerify() defines.
  21. //
  22. // Note: DECnet Protocol uses 6 Floors, all others 5.
  23. //
  24. #define MAX_FLOOR_COUNT 6
  25. #ifndef UNALIGNED
  26. #error UNALIGNED not defined by sysinc.h or its includes and is needed.
  27. #endif
  28. #pragma pack(1)
  29. /*
  30. Some Lrpc specific stuff
  31. */
  32. #define NP_TRANSPORTID_LRPC 0x10
  33. #define NP_TOWERS_LRPC 0x04
  34. // "ncalrpc" including the NULL terminator
  35. const int LrpcProtocolSequenceLength = 8;
  36. RPC_STATUS
  37. Floor0or1ToId(
  38. IN PFLOOR_0OR1 Floor,
  39. OUT PGENERIC_ID Id
  40. )
  41. /*++
  42. Routine Description:
  43. This function extracts Xfer Syntax or If info from a
  44. a DCE tower Floor 0 or 1 encoding
  45. Arguments:
  46. Floor - A pointer to Floor0 or Floor 1 encoding
  47. Id -
  48. Return Value:
  49. EP_S_CANT_PERFORM_OP - The Encoding for the floor [0 or 1] is incorrect.
  50. --*/
  51. {
  52. if (Floor->FloorId != UUID_ENCODING)
  53. {
  54. return (EP_S_CANT_PERFORM_OP);
  55. }
  56. RpcpMemoryCopy((char PAPI *)&Id->Uuid, (char PAPI *) &Floor->Uuid,
  57. sizeof(UUID));
  58. Id->MajorVersion = Floor->MajorVersion;
  59. Id->MinorVersion = Floor->MinorVersion;
  60. return(RPC_S_OK);
  61. }
  62. RPC_STATUS
  63. CopyIdToFloor(
  64. OUT PFLOOR_0OR1 Floor,
  65. IN PGENERIC_ID Id
  66. )
  67. /*++
  68. Routine Description:
  69. This function constructs FLOOR 0 or 1 from the given IF-id or Transfer
  70. Syntax Id.
  71. Arguments:
  72. Floor - Pointer to Floor 0 or 1 structure that will be constructed
  73. Id - Pointer to If-id or Xfer Syntax Id.
  74. Return Value:
  75. RPC_S_OK
  76. --*/
  77. {
  78. Floor->FloorId = UUID_ENCODING;
  79. Floor->ProtocolIdByteCount = sizeof(Floor->Uuid) + sizeof(Floor->FloorId)
  80. + sizeof(Floor->MajorVersion);
  81. Floor->AddressByteCount = sizeof(Floor->MinorVersion);
  82. RpcpMemoryCopy((char PAPI *) &Floor->Uuid, (char PAPI *) &Id->Uuid,
  83. sizeof(UUID));
  84. Floor->MajorVersion = Id->MajorVersion;
  85. Floor->MinorVersion = Id->MinorVersion;
  86. return(RPC_S_OK);
  87. }
  88. RPC_STATUS
  89. LrpcTowerConstruct(
  90. IN char PAPI * Endpoint,
  91. OUT unsigned short PAPI UNALIGNED * Floors,
  92. OUT unsigned long PAPI UNALIGNED * ByteCount,
  93. OUT unsigned char PAPI * UNALIGNED PAPI * Tower
  94. )
  95. {
  96. unsigned long TowerSize;
  97. FLOOR_234 UNALIGNED *Floor;
  98. int EndpointLength;
  99. *Floors = NP_TOWERS_LRPC;
  100. if ((Endpoint == NULL) || (*Endpoint == '\0'))
  101. {
  102. EndpointLength = 0;
  103. }
  104. else
  105. {
  106. EndpointLength = RpcpStringLengthA(Endpoint) + 1;
  107. }
  108. if (EndpointLength == 0)
  109. TowerSize = 2;
  110. else
  111. TowerSize = EndpointLength;
  112. TowerSize += sizeof(FLOOR_234) - 2;
  113. *ByteCount = TowerSize;
  114. if ((*Tower = (unsigned char *)I_RpcAllocate(TowerSize)) == NULL)
  115. {
  116. return (RPC_S_OUT_OF_MEMORY);
  117. }
  118. Floor = (PFLOOR_234) *Tower;
  119. Floor->ProtocolIdByteCount = 1;
  120. Floor->FloorId = (unsigned char)(NP_TRANSPORTID_LRPC & 0xFF);
  121. if (EndpointLength)
  122. {
  123. Floor->AddressByteCount = (unsigned short)EndpointLength;
  124. RpcpMemoryCopy((char PAPI *)&Floor->Data[0], Endpoint,
  125. EndpointLength);
  126. }
  127. else
  128. {
  129. Floor->AddressByteCount = 2;
  130. Floor->Data[0] = 0;
  131. }
  132. return(RPC_S_OK);
  133. }
  134. RPC_STATUS
  135. LrpcTowerExplode(
  136. IN char PAPI * Tower,
  137. OUT char PAPI * UNALIGNED PAPI * Protseq,
  138. OUT char PAPI * UNALIGNED PAPI * Endpoint,
  139. OUT char PAPI * UNALIGNED PAPI * NetworkAddress
  140. )
  141. {
  142. FLOOR_234 UNALIGNED *Floor = (PFLOOR_234) Tower;
  143. if (Protseq != NULL)
  144. {
  145. *Protseq = new char[LrpcProtocolSequenceLength];
  146. if (*Protseq == NULL)
  147. {
  148. return(RPC_S_OUT_OF_MEMORY);
  149. }
  150. RpcpMemoryCopy(*Protseq, "ncalrpc", LrpcProtocolSequenceLength);
  151. }
  152. if (Endpoint == NULL)
  153. {
  154. return (RPC_S_OK);
  155. }
  156. *Endpoint = new char[Floor->AddressByteCount];
  157. if (*Endpoint == NULL)
  158. {
  159. if (Protseq != NULL)
  160. {
  161. delete (*Protseq);
  162. }
  163. return(RPC_S_OUT_OF_MEMORY);
  164. }
  165. RpcpMemoryCopy(*Endpoint, (char PAPI *)&Floor->Data[0],
  166. Floor->AddressByteCount);
  167. return(RPC_S_OK);
  168. }
  169. RPC_STATUS
  170. GetProtseqAndEndpointFromFloor3(
  171. IN PFLOOR_234 Floor,
  172. OUT char PAPI * PAPI * Protseq,
  173. OUT char PAPI * PAPI * Endpoint,
  174. OUT char PAPI * PAPI * NWAddress
  175. )
  176. {
  177. /*++
  178. Routine Description:
  179. This function extracts the Protocol Sequence and Endpoint info
  180. from a "Lower Tower" representation
  181. Arguments:
  182. Floor - Pointer to Floor2 structure.
  183. Protseq - A pointer that will contain Protocol seq on return
  184. The memory will be allocated by this routins and caller
  185. will have to free this memory.
  186. Endpoint- A pointer that will contain Endpoint on return
  187. The memory will be allocated by this routins and caller
  188. will have to free this memory.
  189. Return Value:
  190. RPC_S_OK
  191. RPC_S_OUT_OF_MEMORY - There is no memory to return Protseq or Endpoint str.
  192. EP_S_CANT_PERFORM_OP - Lower Tower Encoding is incorrect.
  193. --*/
  194. unsigned short Type = Floor->FloorId, ProtocolType;
  195. RPC_STATUS Status;
  196. ProtocolType = Floor->FloorId;
  197. Floor = NEXTFLOOR(PFLOOR_234, Floor);
  198. if (NWAddress != 0)
  199. {
  200. *NWAddress = 0;
  201. }
  202. switch(ProtocolType)
  203. {
  204. case LRPC:
  205. Status = LrpcTowerExplode((char *)Floor,
  206. Protseq, Endpoint, NWAddress);
  207. break;
  208. case CONNECTIONFUL:
  209. case CONNECTIONLESS:
  210. Status = OsfTowerExplode((char *) Floor,
  211. Protseq, Endpoint, NWAddress);
  212. break;
  213. default:
  214. Status = EP_S_CANT_PERFORM_OP;
  215. }
  216. return(Status);
  217. }
  218. #define BadMacByteCount 0x0100
  219. #define TCP_TOWER_ID 0x07
  220. const unsigned short MinFloor0Or1LHS = 0x13;
  221. const unsigned short MinFloor0Or1RHS = 0x2;
  222. RPC_STATUS
  223. TowerVerify(
  224. IN twr_p_t Tower
  225. )
  226. /*++
  227. Routine Description:
  228. This function verifies a DCE tower representation of various binding
  229. information. This is to make sure that we don't choke while trying
  230. to decode the embeded information.
  231. Arguments:
  232. Tower - Tower encoding.
  233. Notes:
  234. See Appendix L (Protocol Tower Encoding) of "X/Open DCE: Remote Procedure
  235. Call" specification for more information on the exact layout of the
  236. tower_octet_string and the tower floors.
  237. Return Value:
  238. RPC_S_OK - Tower is valid.
  239. EP_S_CANT_PERFORM_OP - Error while parsing the Tower encoding
  240. --*/
  241. {
  242. RPC_STATUS status;
  243. unsigned short i;
  244. unsigned short FloorCount = 0;
  245. unsigned short cLHSBytes = 0;
  246. unsigned short cRHSBytes = 0;
  247. byte *UpperBound, *LowerBound, *pAddress, *pTemp;
  248. int fBadMacClient = 0;
  249. //
  250. // Check for NULL pointer
  251. //
  252. if (NULL == Tower)
  253. {
  254. return (EP_S_CANT_PERFORM_OP);
  255. }
  256. //
  257. // Do the verification within an Try-Except block. Just in case...
  258. //
  259. __try
  260. {
  261. //
  262. // We trust MIDL to give us a valid Tower structure.
  263. //
  264. //
  265. // LowerBound points to Floor1
  266. // UpperBound points to the byte after the last Floor
  267. //
  268. LowerBound = Tower->tower_octet_string + 2; // FloorCount is 2 bytes
  269. UpperBound = Tower->tower_octet_string + Tower->tower_length;
  270. //
  271. // Get the floor count.
  272. //
  273. FloorCount = *((unsigned short UNALIGNED *)&Tower->tower_octet_string);
  274. if ( FloorCount > MAX_FLOOR_COUNT
  275. || FloorCount == 0)
  276. {
  277. #ifdef DEBUGRPC
  278. PrintToDebugger("RPC: TowerVerify(): Too many/few floors - %d",
  279. FloorCount);
  280. #endif // DEBUGRPC
  281. status = EP_S_CANT_PERFORM_OP;
  282. goto endtry;
  283. }
  284. //
  285. // Loop through each Floor verifying it's integrity.
  286. //
  287. pAddress = LowerBound;
  288. for (i = 0; i < FloorCount; i++)
  289. {
  290. //
  291. // Verify the LHS of the Tower floor.
  292. //
  293. cLHSBytes = *(unsigned short UNALIGNED *)pAddress;
  294. if (i == 3
  295. && cLHSBytes == BadMacByteCount
  296. && *(((char *) pAddress)+2) == TCP_TOWER_ID)
  297. {
  298. fBadMacClient = 1;
  299. }
  300. if (fBadMacClient)
  301. {
  302. cLHSBytes = RpcpByteSwapShort(cLHSBytes);
  303. }
  304. pAddress += (2 + cLHSBytes); // size of cLHSBytes is 2 bytes
  305. if (pAddress >= UpperBound)
  306. {
  307. #ifdef DEBUGRPC
  308. PrintToDebugger("RPC: TowerVerify(): LHS of Tower floor %d "
  309. "greater than equal to Upper bound", i);
  310. #endif // DEBUGRPC
  311. status = EP_S_CANT_PERFORM_OP;
  312. goto endtry;
  313. }
  314. //
  315. // Verify the RHS of the Tower floor.
  316. //
  317. if (fBadMacClient)
  318. {
  319. cRHSBytes = RpcpByteSwapShort(*(unsigned short UNALIGNED *)pAddress);
  320. }
  321. else
  322. cRHSBytes = *(unsigned short UNALIGNED *)pAddress;
  323. pAddress += (2 + cRHSBytes); // size of cRHSBytes is 2 bytes
  324. //
  325. // Note, for the last Floor, here, pAddress == UpperBound. So,
  326. // we do a '>' instead of '>='.
  327. //
  328. if (pAddress > UpperBound)
  329. {
  330. #ifdef DEBUGRPC
  331. PrintToDebugger("RPC: TowerVerify(): RHS of Tower floor %d "
  332. "greater than Upper bound", i);
  333. #endif // DEBUGRPC
  334. status = EP_S_CANT_PERFORM_OP;
  335. goto endtry;
  336. }
  337. // if this is floor 0 or 1, verify that we have at least
  338. // an interface/transfer syntax id in there.
  339. if ((i == 0) || (i == 1))
  340. {
  341. if ((cLHSBytes < MinFloor0Or1LHS)
  342. || (cRHSBytes < MinFloor0Or1RHS))
  343. {
  344. #ifdef DEBUGRPC
  345. PrintToDebugger("RPC: TowerVerify(): Floor 0or1 LHSBytes or RHSBytes less than minumum %d, %d "
  346. "greater than Upper bound", cLHSBytes, cRHSBytes);
  347. #endif // DEBUGRPC
  348. status = EP_S_CANT_PERFORM_OP;
  349. goto endtry;
  350. }
  351. }
  352. } // for ()
  353. //
  354. // Tower looks good, as far as we can tell
  355. //
  356. status = RPC_S_OK;
  357. //
  358. // It's much better *not* to return from within the __try block.
  359. // (saves thousands of instructions)
  360. //
  361. endtry:
  362. #if 1
  363. //
  364. // The compiler needs at least one statement between the label and the end of the block, I guess.
  365. // Luckily a null statement is sufficient.
  366. //
  367. ;
  368. #endif
  369. }
  370. __except( ( GetExceptionCode() == STATUS_ACCESS_VIOLATION )
  371. || ( GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT ) )
  372. {
  373. #ifdef DEBUGRPC
  374. PrintToDebugger("RPC: TowerVerify() generated an exception 0x%x",
  375. RpcExceptionCode());
  376. #endif // DEBUGRPC
  377. status = EP_S_CANT_PERFORM_OP;
  378. }
  379. return status;
  380. }
  381. RPC_STATUS RPC_ENTRY
  382. TowerExplode(
  383. IN twr_p_t Tower,
  384. OUT RPC_IF_ID PAPI * Ifid, OPTIONAL
  385. OUT RPC_TRANSFER_SYNTAX PAPI * XferId, OPTIONAL
  386. OUT char PAPI * PAPI * Protseq, OPTIONAL
  387. OUT char PAPI * PAPI * Endpoint, OPTIONAL
  388. OUT char PAPI * PAPI * NWAddress OPTIONAL
  389. )
  390. /*++
  391. Routine Description:
  392. This function converts a DCE tower representation of various binding
  393. information to binding info that is suitable to MS runtime.
  394. Specically it returns Ifid, Xferid, Protseq and Endpoint information
  395. encoded in the tower.
  396. Arguments:
  397. Tower - Tower encoding.
  398. Ifid - A pointer to Ifid
  399. Xferid - A pointer to Xferid
  400. Protseq - A pointer to pointer returning Protseq
  401. Endpoint- A pointer to pointer returning Endpoint
  402. Return Value:
  403. RPC_S_OK
  404. EP_S_CANT_PERFORM_OP - Error while parsing the Tower encoding
  405. RPC_S_OUT_OF_MEMORY - There is no memory to return Protseq and Endpoint
  406. strings.
  407. --*/
  408. {
  409. PFLOOR_0OR1 Floor;
  410. PFLOOR_234 Floor234;
  411. unsigned short FloorCount;
  412. RPC_STATUS err = RPC_S_OK;
  413. //
  414. // Validate the Tower before proceeding...
  415. //
  416. err = TowerVerify(Tower);
  417. if (err != RPC_S_OK)
  418. {
  419. return (err);
  420. }
  421. FloorCount = *((unsigned short PAPI *)&Tower->tower_octet_string);
  422. Floor = (PFLOOR_0OR1)
  423. ((unsigned short PAPI *)&Tower->tower_octet_string + 1);
  424. //Process Floor 0 Interface Spec.
  425. if (Ifid != NULL)
  426. {
  427. err = Floor0or1ToId(Floor, (PGENERIC_ID) Ifid);
  428. }
  429. Floor = NEXTFLOOR(PFLOOR_0OR1, Floor);
  430. //Now we point to and process Floor 1 Transfer Syntax Spec.
  431. if ((!err) && (XferId != NULL))
  432. {
  433. err = Floor0or1ToId(Floor, (PGENERIC_ID) XferId);
  434. }
  435. if (err)
  436. {
  437. return(err);
  438. }
  439. Floor234 = (PFLOOR_234)NEXTFLOOR(PFLOOR_0OR1, Floor);
  440. //Now Floor234 points to Floor 2. RpcProtocol [Connect-Datagram]
  441. err = GetProtseqAndEndpointFromFloor3(Floor234, Protseq,Endpoint,NWAddress);
  442. return(err);
  443. }
  444. RPC_STATUS RPC_ENTRY
  445. TowerConstruct(
  446. IN RPC_IF_ID PAPI * Ifid,
  447. IN RPC_TRANSFER_SYNTAX PAPI * Xferid,
  448. IN char PAPI * RpcProtocolSequence,
  449. IN char PAPI * Endpoint, OPTIONAL
  450. IN char PAPI * NWAddress, OPTIONAL
  451. OUT twr_t PAPI * PAPI * Tower
  452. )
  453. /*++
  454. Routine Description:
  455. This function constructs a DCE tower representation from
  456. Protseq, Endpoint, XferId and IfId
  457. Arguments:
  458. Ifid - A pointer to Ifid
  459. Xferid - A pointer to Xferid
  460. Protseq - A pointer to Protseq
  461. Endpoint- A pointer to Endpoint
  462. Tower - The constructed tower returmed - The memory is allocated
  463. by the routine and caller will have to free it.
  464. Return Value:
  465. RPC_S_OK
  466. EP_S_CANT_PERFORM_OP - Error while parsing the Tower encoding
  467. RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
  468. Tower.
  469. --*/
  470. {
  471. unsigned short Numfloors, PAPI *FloorCnt;
  472. twr_t PAPI * Twr;
  473. PFLOOR_0OR1 Floor;
  474. PFLOOR_234 Floor234, Floor234_1;
  475. RPC_STATUS Status;
  476. unsigned long TowerLen, ByteCount;
  477. char PAPI * UpperTower;
  478. unsigned short ProtocolType;
  479. if ( RpcpStringCompareA(RpcProtocolSequence, "ncalrpc") == 0 )
  480. {
  481. ProtocolType = LRPC;
  482. Status = LrpcTowerConstruct(Endpoint, &Numfloors,
  483. &ByteCount, (unsigned char **)&UpperTower);
  484. }
  485. else
  486. {
  487. if ( (RpcProtocolSequence[0] == 'n')
  488. && (RpcProtocolSequence[1] == 'c')
  489. && (RpcProtocolSequence[2] == 'a')
  490. && (RpcProtocolSequence[3] == 'c')
  491. && (RpcProtocolSequence[4] == 'n')
  492. && (RpcProtocolSequence[5] == '_'))
  493. {
  494. ProtocolType = CONNECTIONFUL;
  495. }
  496. else if ( (RpcProtocolSequence[0] == 'n')
  497. && (RpcProtocolSequence[1] == 'c')
  498. && (RpcProtocolSequence[2] == 'a')
  499. && (RpcProtocolSequence[3] == 'd')
  500. && (RpcProtocolSequence[4] == 'g')
  501. && (RpcProtocolSequence[5] == '_'))
  502. {
  503. ProtocolType = CONNECTIONLESS;
  504. }
  505. else
  506. {
  507. return(RPC_S_INVALID_RPC_PROTSEQ);
  508. }
  509. Status = OsfTowerConstruct(
  510. RpcProtocolSequence,
  511. Endpoint,
  512. NWAddress,
  513. &Numfloors,
  514. &ByteCount,
  515. (unsigned char **)&UpperTower
  516. );
  517. }
  518. if (Status != RPC_S_OK)
  519. {
  520. return (Status);
  521. }
  522. TowerLen = 2 + ByteCount;
  523. TowerLen += 2 * sizeof(FLOOR_0OR1) + sizeof(FLOOR_2) ;
  524. if ( (*Tower = Twr = (twr_t *)I_RpcAllocate((unsigned int)TowerLen+4)) == NULL)
  525. {
  526. I_RpcFree(UpperTower);
  527. return(RPC_S_OUT_OF_MEMORY);
  528. }
  529. Twr->tower_length = TowerLen;
  530. FloorCnt = (unsigned short PAPI *)&Twr->tower_octet_string;
  531. *FloorCnt = Numfloors;
  532. Floor = (PFLOOR_0OR1)(FloorCnt+1);
  533. //Floor 0 - IfUuid and IfVersion
  534. CopyIdToFloor(Floor, (PGENERIC_ID)Ifid);
  535. Floor++;
  536. //Floor 1 - XferUuid and XferVersion
  537. CopyIdToFloor(Floor, (PGENERIC_ID)Xferid);
  538. //Floor 2
  539. //ProtocolId = CONNECTIONFUL/CONNECTIONLESS/LRPC and Address = 0(ushort)
  540. Floor234 = (PFLOOR_234) (Floor + 1);
  541. Floor234->ProtocolIdByteCount = 1;
  542. Floor234->FloorId = (byte) ProtocolType;
  543. Floor234->Data[0] = 0x0;
  544. Floor234->Data[1] = 0x0;
  545. Floor234->AddressByteCount = 2;
  546. //Floor 3,4,5.. use the tower encoded by the Transports
  547. Floor234_1 = NEXTFLOOR(PFLOOR_234, Floor234);
  548. RpcpMemoryCopy((char PAPI *)Floor234_1, (char PAPI *)UpperTower,
  549. (size_t)ByteCount);
  550. I_RpcFree(UpperTower);
  551. return(RPC_S_OK);
  552. }
  553. #pragma pack()