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.

3256 lines
73 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. worker.c
  5. Abstract:
  6. This file contains the real stuff for the EP Mapper.
  7. Author:
  8. Bharat Shah (barat) 17-2-92
  9. Revision History:
  10. 06-03-97 gopalp Added code to cleanup stale EP Mapper entries.
  11. --*/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <sysinc.h>
  17. #include <wincrypt.h>
  18. #include <rpc.h>
  19. #include <rpcndr.h>
  20. #include "epmp.h"
  21. #include "eptypes.h"
  22. #include "local.h"
  23. #include "twrproto.h"
  24. #include <winsock2.h>
  25. #define StringCompareA lstrcmpiA
  26. #define StringLengthA lstrlenA
  27. #define EP_S_DUPLICATE_ENTRY 0x16c9a0d8
  28. RPC_IF_ID LocalNullUuid = {0};
  29. UUID MgmtIf = {
  30. 0xafa8bd80,
  31. 0x7d8a,
  32. 0x11c9,
  33. {0xbe, 0xf4, 0x08, 0x00, 0x2b, 0x10, 0x29, 0x89}
  34. };
  35. const int IP_ADDR_OFFSET = 0x4b;
  36. void
  37. PatchTower(
  38. IN OUT twr_t *Tower,
  39. IN int address)
  40. {
  41. int UNALIGNED *pIPAddr;
  42. pIPAddr = (int UNALIGNED *) (((char *) Tower) + IP_ADDR_OFFSET);
  43. //
  44. // Patch the tower
  45. //
  46. *pIPAddr = address;
  47. }
  48. //
  49. // Forward definitions
  50. //
  51. USHORT
  52. GetProtseqIdAnsi(
  53. PSTR Protseq
  54. );
  55. RPC_STATUS
  56. DelayedUseProtseq(
  57. USHORT id
  58. );
  59. VOID
  60. CompleteDelayedUseProtseqs(
  61. void
  62. );
  63. void
  64. DeletePSEP(
  65. PIFOBJNode Node,
  66. char * Protseq,
  67. char * Endpoint
  68. );
  69. void
  70. PurgeOldEntries(
  71. PIFOBJNode Node,
  72. PPSEPNode List,
  73. BOOL StrictMatch
  74. );
  75. RPC_STATUS
  76. MatchPSAndEP (
  77. PPSEPNode Node,
  78. void *Pseq,
  79. void * Endpoint,
  80. unsigned long Version
  81. );
  82. PPSEPNode
  83. FindPSEP (
  84. register PPSEPNode List,
  85. char * Pseq,
  86. char * Endpoint,
  87. unsigned long Version,
  88. PFNPointer2 Compare
  89. );
  90. PIFOBJNode
  91. FindIFOBJNode(
  92. register PIFOBJNode List,
  93. UUID * Obj,
  94. UUID * IF,
  95. unsigned long Version,
  96. unsigned long Inq,
  97. unsigned long VersOpts,
  98. PFNPointer Compare
  99. );
  100. PIENTRY
  101. MatchByKey(
  102. register PIENTRY pList,
  103. unsigned long key
  104. )
  105. /*++
  106. Routine Description:
  107. This routine Seqrches the Link-list of IF-OBJ nodes based on
  108. key supplied.
  109. Arguments:
  110. List - The Linked list [head] - to be searched
  111. key - The Id
  112. Return Value:
  113. Returns a pointer to the matching IFObj node in the list or returns NULL.
  114. --*/
  115. {
  116. CheckInSem();
  117. for (; pList && pList->Id < key; pList = pList->Next)
  118. {
  119. ; // Empty body
  120. }
  121. return(pList);
  122. }
  123. RPC_STATUS RPC_ENTRY
  124. GetForwardEp(
  125. UUID *IfId,
  126. RPC_VERSION * IFVersion,
  127. UUID *Object,
  128. unsigned char * Protseq,
  129. void * * EpString
  130. )
  131. /*++
  132. Routine Description:
  133. Server rutime has received a pkt destined for a dynamically
  134. declared endpoint. Epmapper must return the servers endpoint
  135. to enable the runtime to correctly forward the pkt.
  136. Arguments:
  137. IF - Server Interface UUID
  138. IFVersion - Version of the Interface
  139. Obj - UUID of the Object
  140. Protseq - Ptotocol sequence the interface is using.
  141. EpString - Place to store the endpoint structure.
  142. Return Value:
  143. Returns a pointer to a string containing the server's endpoint.
  144. RPC_S_OUT_OF_MEMORY
  145. EPT_S_NOT_REGISTERED
  146. ---*/
  147. {
  148. PIFOBJNode pNode;
  149. PPSEPNode pPSEPNode;
  150. unsigned short len;
  151. char * String;
  152. PFNPointer Match;
  153. unsigned long InqType;
  154. unsigned long Version = VERSION(IFVersion->MajorVersion,
  155. IFVersion->MinorVersion);
  156. if (memcmp((char *)IfId, (char *)&MgmtIf, sizeof(UUID)) == 0)
  157. {
  158. InqType = RPC_C_EP_MATCH_BY_OBJ;
  159. Match = SearchIFObjNode;
  160. }
  161. else
  162. {
  163. InqType = 0;
  164. Match = WildCardMatch;
  165. }
  166. *EpString = 0;
  167. EnterSem();
  168. pNode = IFObjList;
  169. if (pNode == 0)
  170. {
  171. LeaveSem();
  172. return(EPT_S_NOT_REGISTERED);
  173. }
  174. while (pNode != 0)
  175. {
  176. pNode = FindIFOBJNode(
  177. pNode,
  178. Object,
  179. IfId,
  180. Version,
  181. InqType,
  182. 0,
  183. Match
  184. );
  185. if (pNode == 0)
  186. {
  187. LeaveSem();
  188. return(EPT_S_NOT_REGISTERED);
  189. }
  190. pPSEPNode = pNode->PSEPlist;
  191. pPSEPNode = FindPSEP(
  192. pPSEPNode,
  193. Protseq,
  194. NULL,
  195. 0L,
  196. MatchPSAndEP
  197. );
  198. if (pPSEPNode == 0)
  199. {
  200. pNode = pNode->Next;
  201. if (pNode == 0)
  202. {
  203. LeaveSem();
  204. return(EPT_S_NOT_REGISTERED);
  205. }
  206. continue;
  207. }
  208. // We now have a PSEPNode. We just ought to return the first one!
  209. // Use I_RpcAllocate To Allocate because runtime will free this!
  210. String = I_RpcAllocate( len = (strlen(pPSEPNode->EP) + 1) );
  211. if (String == 0)
  212. {
  213. LeaveSem();
  214. return(RPC_S_OUT_OF_MEMORY);
  215. }
  216. // Do we really need memset()?. memcpy set the bytes...
  217. memset(String, 0, len);
  218. memcpy(String, pPSEPNode->EP, len);
  219. *EpString = String;
  220. LeaveSem();
  221. return(RPC_S_OK);
  222. } // while loop
  223. // we never go through here.
  224. return(EPT_S_NOT_REGISTERED);
  225. }
  226. RPC_STATUS
  227. SearchIFObjNode(
  228. PIFOBJNode pNode,
  229. UUID *Object,
  230. UUID *IfUuid,
  231. unsigned long Version,
  232. unsigned long InqType,
  233. unsigned long VersOption
  234. )
  235. /*++
  236. Routine Description:
  237. This routine Seqrches the Link-list of IF-OBJ nodes based on
  238. Obj, IFUuid, IFVersion, Inqtype [Ignore OBJ, IgnoreIF, etc],
  239. and VersOption [Identical Ver, Compatible Vers. etc]
  240. Arguments:
  241. List - The Linked list head - to be searched
  242. Obj - UUID of the Object
  243. IF - Interface UUID
  244. Version - Version of the Interface
  245. InqType - Type of Inquiry [Filter options based on IF/Obj/Both
  246. VersOpts - Filter options based on Version
  247. Return Value:
  248. Returns a pointer to the matching IFObj node in the list or returns NULL.
  249. --*/
  250. {
  251. switch (InqType)
  252. {
  253. default:
  254. case RPC_C_EP_ALL_ELTS:
  255. return 0;
  256. case RPC_C_EP_MATCH_BY_BOTH:
  257. if (memcmp(
  258. (char *)&pNode->ObjUuid,
  259. (char *)Object,
  260. sizeof(UUID))
  261. )
  262. return(1);
  263. // Intentionally Fall through ..
  264. case RPC_C_EP_MATCH_BY_IF:
  265. return(!(
  266. (
  267. !memcmp(
  268. (char *)&pNode->IFUuid,
  269. (char *)IfUuid,
  270. sizeof(UUID)
  271. )
  272. )
  273. &&
  274. (
  275. ( (VersOption == RPC_C_VERS_UPTO)
  276. && pNode->IFVersion <= Version)
  277. || ( (VersOption == RPC_C_VERS_COMPATIBLE)
  278. && ((pNode->IFVersion & 0xFFFF0000) ==
  279. (Version & 0xFFFF0000))
  280. && (pNode->IFVersion >= Version)
  281. )
  282. || ( (VersOption == RPC_C_VERS_EXACT)
  283. && (pNode->IFVersion == Version)
  284. )
  285. || (VersOption == RPC_C_VERS_ALL)
  286. || ( (VersOption == RPC_C_VERS_MAJOR_ONLY)
  287. && ((pNode->IFVersion & 0xFFFF0000L)
  288. == (Version & 0xFFFF0000L))
  289. )
  290. || ( (VersOption ==
  291. I_RPC_C_VERS_UPTO_AND_COMPATIBLE)
  292. && ((pNode->IFVersion & 0xFFFF0000L)
  293. == (Version & 0xFFFF0000L))
  294. && (pNode->IFVersion <= Version)
  295. )
  296. )
  297. )
  298. ); // return(
  299. case RPC_C_EP_MATCH_BY_OBJ:
  300. return(
  301. memcmp(
  302. (char *)&pNode->ObjUuid,
  303. (char *)Object,
  304. sizeof(UUID)
  305. )
  306. );
  307. } // switch
  308. }
  309. PIFOBJNode
  310. FindIFOBJNode(
  311. register PIFOBJNode List,
  312. UUID * Obj,
  313. UUID * IF,
  314. unsigned long Version,
  315. unsigned long Inq,
  316. unsigned long VersOpts,
  317. PFNPointer Compare
  318. )
  319. /*++
  320. Routine Description:
  321. This routine Seqrches the Link-list of IF-OBJ nodes based on
  322. Obj and IF specified.
  323. Arguments:
  324. List - The Linked list head - to be searched
  325. Obj - UUID of the Object
  326. IF - Interface UUID
  327. Version - Version of the Interface
  328. Inq - Type of Inquiry [Filter based on IF/OB/Both]
  329. VersOpt - Filter based on version [<=, >=, == etc]
  330. Compare() - A pointer to function used for searching.
  331. WildCardMatch or ExactMatch.
  332. Return Value:
  333. Returns a pointer to the matching IFObj node in the list or returns NULL.
  334. --*/
  335. {
  336. CheckInSem();
  337. for (; (List !=NULL) && (*Compare)(List, Obj, IF, Version, Inq, VersOpts);
  338. List = List->Next)
  339. {
  340. ; // Empty body
  341. }
  342. return (List);
  343. }
  344. PPSEPNode
  345. FindPSEP (
  346. register PPSEPNode List,
  347. char * Pseq,
  348. char * Endpoint,
  349. unsigned long Version,
  350. PFNPointer2 Compare
  351. )
  352. /*++
  353. Routine Description:
  354. This routine Seqrches the Link-list of PSEP nodes based on
  355. Protocol sequence and Endpoint specified.
  356. Arguments:
  357. List - The Linked list head - to be searched
  358. Pseq - Protocol sequence string specified
  359. Endpoint - Endpoint string specified
  360. Version - Version of the Interface
  361. Compare() - A pointer to function used for searching.
  362. Return Value:
  363. Returns a pointer to the matching PSEP node in the list or returns NULL.
  364. --*/
  365. {
  366. CheckInSem();
  367. for (; List && (*Compare)(List, Pseq, Endpoint, Version); List = List->Next)
  368. {
  369. ; // Empty body
  370. }
  371. return (List);
  372. if (Version); // May need this if we overload FindNode and collapse
  373. // FindPSEP and FindIFOBJ
  374. }
  375. RPC_STATUS
  376. ExactMatch(
  377. PIFOBJNode Node,
  378. UUID *Obj,
  379. UUID *IF,
  380. unsigned long Version,
  381. unsigned long InqType,
  382. unsigned long VersOptions
  383. )
  384. /*++
  385. Routine Description:
  386. This routine compares a Node in the IFOBJList to [Obj, IF, Version] triple
  387. and returns 0 if there is an exact match else returns 1
  388. Arguments:
  389. Node - An IFOBJ node
  390. Obj - UUID of the Object
  391. IF - Interface UUID
  392. Version - Version of the Interface
  393. Return Value:
  394. Returns 0 if there is an exact match; 1 otherwise
  395. --*/
  396. {
  397. return(( memcmp(&Node->ObjUuid, Obj,sizeof(UUID))
  398. || memcmp(&Node->IFUuid, IF, sizeof(UUID))
  399. || (Node->IFVersion != Version)));
  400. }
  401. RPC_STATUS
  402. WildCardMatch (
  403. PIFOBJNode Node,
  404. UUID *Obj,
  405. UUID *IF,
  406. unsigned long Version,
  407. unsigned long InqType,
  408. unsigned long VersOptions
  409. )
  410. /*++
  411. Routine Description:
  412. This routine compares a Node in the IFOBJList to [Obj, IF, Version] triple
  413. and returns 0 if there is an exact match or if registered IF-Obj node
  414. has a NULL Obj UUid and version of the registed IF_Obj is >= that
  415. supplied
  416. Arguments:
  417. Node - An IFOBJ node
  418. Obj - UUID of the Object
  419. IF - Interface UUID
  420. Version - Version of the Interface
  421. Return Value:
  422. Returns 0 if there is a wild card match ; 1 otherwise
  423. --*/
  424. {
  425. if ( (!memcmp(&Node->IFUuid, IF, sizeof(UUID)))
  426. && ((Node->IFVersion & 0xFFFF0000L) == (Version & 0xFFFF0000L))
  427. && (Node->IFVersion >= Version)
  428. && ((!memcmp(&Node->ObjUuid, Obj, sizeof(UUID))) ||
  429. (IsNullUuid(&Node->ObjUuid)) ) )
  430. {
  431. return(0);
  432. }
  433. return(1);
  434. }
  435. RPC_STATUS
  436. MatchPSAndEP (
  437. PPSEPNode Node,
  438. void *Pseq,
  439. void * Endpoint,
  440. unsigned long Version
  441. )
  442. /*++
  443. Routine Description:
  444. This routine Matches A Node on PSEP list with given Protseq and Endpoint
  445. If Pseq is given pseqs are matched, if Endpoint is given Endpoints
  446. are matched, if neither is given returns true, if both are given
  447. both are matched.
  448. Arguments:
  449. Node - A PSEP node on PSEP list.
  450. Pseq - Protocol Sequence string
  451. Endpoint - Endpoint string
  452. Return Value:
  453. Returns 0 if Matched successfully, 1 otherwise.
  454. --*/
  455. {
  456. return ( (Pseq && RpcpStringCompareA(Node->Protseq, Pseq))
  457. || (Endpoint && RpcpStringCompareA(Node->EP, Endpoint)) );
  458. }
  459. void
  460. PurgeOldEntries(
  461. PIFOBJNode Node,
  462. PPSEPNode List,
  463. BOOL StrictMatch
  464. )
  465. {
  466. PPSEPNode Tmp, DeleteMe;
  467. char * Endpoint = 0;
  468. CheckInSem();
  469. Tmp = Node->PSEPlist;
  470. while (Tmp != 0)
  471. {
  472. if (StrictMatch == TRUE)
  473. Endpoint = Tmp->EP;
  474. if (DeleteMe = FindPSEP(List, Tmp->Protseq, Endpoint, 0L, MatchPSAndEP))
  475. {
  476. DeleteMe = Tmp;
  477. Tmp = Tmp->Next;
  478. UnLinkFromPSEPList(&Node->PSEPlist, DeleteMe);
  479. DeleteMe->Signature = FREE;
  480. FreeMem(DeleteMe);
  481. }
  482. else
  483. {
  484. Tmp = Tmp->Next;
  485. }
  486. }
  487. }
  488. RPC_STATUS
  489. IsNullUuid (
  490. UUID * Uuid
  491. )
  492. /*++
  493. Routine Description:
  494. This routine checks if a UUID is Nil
  495. Arguments:
  496. Uuid - UUID to be tested
  497. Return Value:
  498. Returns 1 if it is a Nil UUID
  499. 0 otherwise.
  500. --*/
  501. {
  502. unsigned long PAPI * Vector;
  503. Vector = (unsigned long PAPI *) Uuid;
  504. if ( (Vector[0] == 0)
  505. && (Vector[1] == 0)
  506. && (Vector[2] == 0)
  507. && (Vector[3] == 0))
  508. return(1);
  509. return(0);
  510. }
  511. twr_p_t
  512. NewTower(
  513. twr_p_t Tower
  514. )
  515. /*++
  516. Routine Description:
  517. This routine returns a New, Duplicated tower
  518. Arguments:
  519. Tower - The tower that needs to be duplicated.
  520. Return Value:
  521. Retunes a pointer to a new tower if successful else returns
  522. NULL
  523. --*/
  524. {
  525. unsigned short len;
  526. twr_p_t NewTower;
  527. len = (unsigned short)(sizeof(Tower->tower_length) + Tower->tower_length);
  528. if ((NewTower = MIDL_user_allocate(len)) != NULL)
  529. {
  530. memcpy((char *)NewTower, (char *)Tower, len);
  531. }
  532. return(NewTower);
  533. }
  534. const unsigned long EPLookupHandleSignature = 0xFAFAFAFA;
  535. PSAVEDCONTEXT
  536. GetNewContext(
  537. unsigned long Type
  538. )
  539. /*++
  540. Routine Description
  541. ++*/
  542. {
  543. PSAVEDCONTEXT Context;
  544. if ( ((Context = AllocMem(sizeof(SAVEDCONTEXT))) == 0) )
  545. return 0;
  546. memset(Context, 0, sizeof(SAVEDCONTEXT));
  547. Context->Cb = sizeof(SAVEDCONTEXT);
  548. Context->Type = Type;
  549. Context->Signature = EPLookupHandleSignature;
  550. EnLinkContext(Context);
  551. return(Context);
  552. }
  553. const unsigned int EPMapSignature = 0xCBBCCBBC;
  554. const unsigned int EPLookupSignature = 0xABBAABBA;
  555. RPC_STATUS
  556. AddToSavedContext(
  557. PSAVEDCONTEXT Context,
  558. PIFOBJNode Node,
  559. PPSEPNode Psep,
  560. unsigned long Calltype,
  561. BOOL fPatchTower,
  562. int PatchTowerAddress
  563. )
  564. {
  565. void * NewNode;
  566. PSAVEDTOWER SavedTower;
  567. PSAVED_EPT SavedEndpoint;
  568. unsigned long Size;
  569. unsigned long TowerSize;
  570. ASSERT(Calltype == Context->Type);
  571. switch (Calltype)
  572. {
  573. case EP_MAP:
  574. Size = sizeof(SAVEDTOWER) ;
  575. if ((NewNode = AllocMem(Size)) == 0)
  576. return(RPC_S_OUT_OF_MEMORY);
  577. SavedTower = (PSAVEDTOWER) NewNode;
  578. memset(SavedTower, 0, Size);
  579. SavedTower->Cb = Size;
  580. SavedTower->Signature = EPMapSignature;
  581. SavedTower->Tower = NewTower(Psep->Tower);
  582. if (SavedTower->Tower == 0)
  583. {
  584. FreeMem(NewNode);
  585. return(RPC_S_OUT_OF_MEMORY);
  586. }
  587. if (fPatchTower)
  588. {
  589. PatchTower(SavedTower->Tower, PatchTowerAddress);
  590. }
  591. break;
  592. case EP_LOOKUP:
  593. Size = sizeof(SAVED_EPT) + strlen(Node->Annotation) + 1;
  594. if ((NewNode = AllocMem(Size)) == 0)
  595. return(RPC_S_OUT_OF_MEMORY);
  596. SavedEndpoint = (PSAVED_EPT) NewNode;
  597. memset(SavedEndpoint, 0, Size);
  598. SavedEndpoint->Cb = Size;
  599. SavedEndpoint->Signature = EPLookupSignature;
  600. SavedEndpoint->Tower = NewTower(Psep->Tower);
  601. SavedEndpoint->Annotation = (char *)NewNode +
  602. sizeof(SAVED_EPT);
  603. memcpy( (char *) &SavedEndpoint->Object,
  604. (char *)&Node->ObjUuid,
  605. sizeof(UUID)
  606. );
  607. strcpy(SavedEndpoint->Annotation, Node->Annotation);
  608. if (SavedEndpoint->Tower == 0)
  609. {
  610. FreeMem(NewNode);
  611. return(RPC_S_OUT_OF_MEMORY);
  612. }
  613. if (fPatchTower)
  614. {
  615. PatchTower(SavedEndpoint->Tower, PatchTowerAddress);
  616. }
  617. break;
  618. default:
  619. ASSERT(!"Unknown lookup type\n");
  620. return(RPC_S_INTERNAL_ERROR);
  621. break;
  622. }
  623. Link((PIENTRY *)(&Context->List), NewNode);
  624. return(RPC_S_OK);
  625. }
  626. RPC_STATUS
  627. GetEntriesFromSavedContext(
  628. PSAVEDCONTEXT Context,
  629. char * Buffer,
  630. unsigned long Requested,
  631. unsigned long *Returned
  632. )
  633. {
  634. PIENTRY SavedEntry = (PIENTRY)Context->List;
  635. PIENTRY TmpEntry;
  636. unsigned long Type = Context->Type;
  637. while ( (*Returned < Requested) && (SavedEntry != 0) )
  638. {
  639. switch (Type)
  640. {
  641. case EP_MAP:
  642. ((I_Tower *)Buffer)->Tower = ((PSAVEDTOWER)SavedEntry)->Tower;
  643. Buffer = Buffer + sizeof(I_Tower);
  644. break;
  645. case EP_LOOKUP:
  646. ((ept_entry_t *)Buffer)->tower = ((PSAVED_EPT)SavedEntry)->Tower;
  647. strcpy(((ept_entry_t *)Buffer)->annotation,
  648. ((PSAVED_EPT)SavedEntry)->Annotation);
  649. memcpy(Buffer,(char *)&((PSAVED_EPT)SavedEntry)->Object,
  650. sizeof(UUID));
  651. Buffer = Buffer + sizeof(ept_entry_t);
  652. break;
  653. default:
  654. ASSERT(!"Unknown Inquiry Type");
  655. break;
  656. }
  657. (*Returned)++;
  658. TmpEntry = SavedEntry;
  659. SavedEntry = SavedEntry->Next;
  660. UnLink((PIENTRY *)&Context->List, TmpEntry);
  661. FreeMem(TmpEntry);
  662. }
  663. return(RPC_S_OK);
  664. }
  665. RPC_STATUS
  666. GetEntries(
  667. UUID *ObjUuid,
  668. UUID *IFUuid,
  669. unsigned long Version,
  670. char * Pseq,
  671. ept_lookup_handle_t *key,
  672. char * Buffer,
  673. unsigned long Calltype,
  674. unsigned long Requested,
  675. unsigned long *Returned,
  676. unsigned long InqType,
  677. unsigned long VersOptions,
  678. PFNPointer Match
  679. )
  680. /*++
  681. Routine Description:
  682. This is a generic routine for retreiving a series [as spec. by Requested]
  683. of Towers (in case of Map) or ept_entry_t's in case of Lookup.
  684. Arguments:
  685. ObjUuid - Object Uuid
  686. IfUuid - Interface Uuid
  687. Version - InterfaceVersion [hi ushort = VerMajor, lo ushort VerMinor]
  688. Protseq - An ascii string specifying the protocol seq.
  689. key - A resume key - If NULL, search is started from the beginning
  690. if non-null, represents an encoding from where the epmapper
  691. supposed to start searching. It is an opaque value as far
  692. as the client is concerned.
  693. Buffer - A buffer of entries returned
  694. Calltype - A flag to indicate whether Ep_entries or string bindings
  695. are to be returned.
  696. Requested - Max no. of entries requested
  697. Returned - Actual no of entroes returned
  698. Return Value:
  699. RPC_S_OUT_OF_MEMORY
  700. RPC_S_OK
  701. EP_S_NOT_REGISTERED
  702. --*/
  703. {
  704. PIFOBJNode pNode=NULL, pList = IFObjList;
  705. unsigned long err=0, fResumeNodeFound=0;
  706. PPSEPNode pPSEPNode;
  707. char * buffer = Buffer;
  708. PSAVEDCONTEXT Context = (PSAVEDCONTEXT) *key;
  709. ept_lookup_handle_t LOOKUP_FINISHED = (ept_lookup_handle_t) LongToPtr(0xffffffff);
  710. int UNALIGNED *pIPAddr;
  711. BOOL fPatchTower;
  712. int PatchTowerAddress;
  713. SOCKADDR_STORAGE SockAddr;
  714. ULONG BufferSize;
  715. int FormatType;
  716. RPC_STATUS RpcStatus;
  717. *Returned = 0;
  718. EnterSem();
  719. if (*key)
  720. {
  721. if (*key == LOOKUP_FINISHED)
  722. {
  723. *key = 0;
  724. LeaveSem();
  725. return(EP_S_NOT_REGISTERED);
  726. }
  727. if (Context->Signature != EPLookupHandleSignature)
  728. {
  729. LeaveSem();
  730. return EP_S_CANT_PERFORM_OP;
  731. }
  732. err = GetEntriesFromSavedContext(Context, Buffer, Requested, Returned);
  733. if (Context->List == 0)
  734. {
  735. UnLink((PIENTRY *)&GlobalContextList, (PIENTRY)Context);
  736. FreeMem(Context);
  737. // Setting the Key To FFFFFFFFL is a hack for down level
  738. // Version 1.0 Ep Clients who never expected getting a key 0
  739. // and Success!
  740. if (Requested <= 1)
  741. *key = LOOKUP_FINISHED;
  742. else
  743. *key = 0L;
  744. LeaveSem();
  745. return(err);
  746. }
  747. LeaveSem();
  748. return(err);
  749. }
  750. *key = 0;
  751. while ((!err))
  752. {
  753. if ((pNode = FindIFOBJNode(
  754. pList,
  755. ObjUuid,
  756. IFUuid,
  757. Version,
  758. InqType,
  759. VersOptions,
  760. Match)) == 0)
  761. {
  762. break;
  763. }
  764. pPSEPNode = pNode->PSEPlist;
  765. while (pPSEPNode != 0)
  766. {
  767. if ((pPSEPNode = FindPSEP(pPSEPNode, Pseq, NULL, 0L,
  768. MatchPSAndEP)) == 0)
  769. break;
  770. fPatchTower = FALSE;
  771. if (StringCompareA(pPSEPNode->Protseq, "ncacn_ip_tcp") == 0
  772. || StringCompareA(pPSEPNode->Protseq, "ncadg_ip_udp") == 0
  773. || StringCompareA(pPSEPNode->Protseq, "ncacn_http") == 0)
  774. {
  775. pIPAddr = (int UNALIGNED *) ((char *) pPSEPNode->Tower + IP_ADDR_OFFSET);
  776. if (*pIPAddr == 0)
  777. {
  778. BufferSize = sizeof(SockAddr);
  779. RpcStatus = I_RpcServerInqLocalConnAddress(NULL,
  780. &SockAddr,
  781. &BufferSize,
  782. &FormatType);
  783. if (RpcStatus == RPC_S_OK)
  784. {
  785. // IPv6 towers don't exist yet - they are not defined
  786. // by DCE. Do patching for IPv4 only
  787. if (FormatType == RPC_P_ADDR_FORMAT_TCP_IPV4)
  788. {
  789. PatchTowerAddress = ((SOCKADDR_IN *)&SockAddr)->sin_addr.S_un.S_addr;
  790. fPatchTower = TRUE;
  791. }
  792. }
  793. }
  794. }
  795. if (*Returned < Requested)
  796. {
  797. err = PackDataIntoBuffer(&buffer, pNode, pPSEPNode, Calltype, fPatchTower, PatchTowerAddress);
  798. if (err == RPC_S_OK)
  799. {
  800. (*Returned)++;
  801. }
  802. else
  803. {
  804. ASSERT(err == RPC_S_OUT_OF_MEMORY);
  805. break;
  806. }
  807. }
  808. else
  809. {
  810. if (Context == 0)
  811. {
  812. *key = (ept_lookup_handle_t) (Context = GetNewContext(Calltype));
  813. if (Context == 0)
  814. {
  815. err = RPC_S_OUT_OF_MEMORY;
  816. break;
  817. }
  818. }
  819. AddToSavedContext(Context, pNode, pPSEPNode, Calltype, fPatchTower, PatchTowerAddress);
  820. }
  821. pPSEPNode = pPSEPNode->Next;
  822. } // while - over PSEPList
  823. pList = pNode->Next;
  824. } // while - over IFOBJList
  825. LeaveSem();
  826. if ((*Returned == 0) && Requested && (!err))
  827. {
  828. err = EP_S_NOT_REGISTERED;
  829. }
  830. if ((*Returned <= Requested) && (Context == 0))
  831. {
  832. if (Requested <= 1)
  833. *key = LOOKUP_FINISHED;
  834. else
  835. *key = 0L;
  836. }
  837. return(err);
  838. }
  839. RPC_STATUS
  840. PackDataIntoBuffer(
  841. char * * Buffer,
  842. PIFOBJNode Node,
  843. PPSEPNode PSEP,
  844. unsigned long Type,
  845. BOOL fPatchTower,
  846. int PatchTowerAddress
  847. )
  848. /*++
  849. Routine Description:
  850. This routine copies 1 entry [Either a Tower or ept_entry]
  851. in the Buffer, increments buffer appropriately.
  852. Arguments:
  853. BindingHandle - An explicit binding handle to the EP.
  854. Node - IFOBJNode
  855. PSEP - PSEPNode
  856. Type - Type of entry to be copied
  857. PatchTower - if TRUE, the newly created tower needs to be patched. If
  858. FALSE, the tower doesn't need to be patched
  859. PatchTowerAddress - an IPv4 representation of the address to be put
  860. in the tower. The IPv4 address must be in network byte order
  861. Return Value:
  862. RPC_S_OK or RPC_S_* for error
  863. --*/
  864. {
  865. I_Tower * Twr;
  866. ept_entry_t *p;
  867. switch (Type)
  868. {
  869. case EP_MAP:
  870. Twr = (I_Tower *)(* Buffer);
  871. Twr->Tower = NewTower(PSEP->Tower);
  872. if (Twr->Tower == 0)
  873. {
  874. return(RPC_S_OUT_OF_MEMORY);
  875. }
  876. if (fPatchTower)
  877. PatchTower(Twr->Tower, PatchTowerAddress);
  878. *Buffer += sizeof(I_Tower);
  879. break;
  880. case EP_LOOKUP:
  881. p = (ept_entry_t *)(*Buffer);
  882. p->tower = NewTower(PSEP->Tower);
  883. if (p->tower == 0)
  884. {
  885. return(RPC_S_OUT_OF_MEMORY);
  886. }
  887. if (fPatchTower)
  888. PatchTower(p->tower, PatchTowerAddress);
  889. memcpy( *Buffer, (char *)&Node->ObjUuid, sizeof(UUID) );
  890. strcpy(p->annotation, Node->Annotation);
  891. *Buffer += sizeof(ept_entry_t);
  892. break;
  893. default:
  894. ASSERT(!"Unknown type");
  895. break;
  896. }
  897. return(RPC_S_OK);
  898. }
  899. void
  900. ept_cleanup_handle_t_rundown(
  901. ept_cleanup_handle_t hEpCleanup
  902. )
  903. /*++
  904. Routine Description:
  905. This routine cleans up the entries registered by the process
  906. associated with this context handle hEpCleanup.
  907. Arguments:
  908. hEpCleanup - The context handle for which the rundown is
  909. being done.
  910. Return Value:
  911. None.
  912. --*/
  913. {
  914. PIFOBJNode NodesListToDelete = NULL;
  915. PIFOBJNode pIterator, DeleteMe, pPreviousNode;
  916. PPSEPNode pTempPSEP, pDeletePSEP;
  917. PEP_CLEANUP ProcessCtxt = (PEP_CLEANUP) hEpCleanup;
  918. #ifdef DBG_DETAIL
  919. PIFOBJNode pTemp, pLast;
  920. #endif // DBG_DETAIL
  921. if (ProcessCtxt == NULL)
  922. {
  923. return;
  924. }
  925. EnterSem();
  926. ASSERT(IFObjList);
  927. ASSERT(cTotalEpEntries > 0);
  928. ASSERT(ProcessCtxt->EntryList);
  929. ASSERT(ProcessCtxt->cEntries > 0);
  930. ASSERT(ProcessCtxt->EntryList->OwnerOfList == ProcessCtxt);
  931. ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries);
  932. #ifdef DBG_DETAIL
  933. DbgPrint("RPCSS: Entered Cleanup Rundown for [%p] with (%d) entries\n",
  934. hEpCleanup, ProcessCtxt->cEntries);
  935. DbgPrint("RPCSS: Dump of IFOBJList\n");
  936. pTemp = IFObjList;
  937. pLast = IFObjList;
  938. while (pTemp)
  939. {
  940. DbgPrint("RPCSS: \t\t[%p]\n", pTemp);
  941. pLast = pTemp;
  942. pTemp = pTemp->Next;
  943. }
  944. DbgPrint("RPCSS: --------------------\n");
  945. while (pLast)
  946. {
  947. DbgPrint("RPCSS: \t\t\t[%p]\n", pLast);
  948. pLast = pLast->Prev;
  949. }
  950. #endif // DBG_DETAIL
  951. // Save the previous Node.
  952. pPreviousNode = ProcessCtxt->EntryList->Prev;
  953. pIterator = ProcessCtxt->EntryList;
  954. while ((pIterator != NULL) && (pIterator->OwnerOfList == ProcessCtxt))
  955. {
  956. ProcessCtxt->cEntries--;
  957. cTotalEpEntries--;
  958. #ifdef DBG_DETAIL
  959. DbgPrint("RPCSS: cTotalEpEntries-- [%p] (%d) - Cleanup\n", hEpCleanup, cTotalEpEntries);
  960. #endif // DBG_DETAIL
  961. DeleteMe = pIterator;
  962. pIterator = pIterator->Next;
  963. // Add to a list that will be deleted later.
  964. DeleteMe->Next = NodesListToDelete;
  965. }
  966. ASSERT(ProcessCtxt->cEntries == 0);
  967. //
  968. // Adjust the links
  969. //
  970. if (pPreviousNode)
  971. {
  972. // Adjust forward link
  973. pPreviousNode->Next = pIterator;
  974. }
  975. else
  976. {
  977. ASSERT(ProcessCtxt->EntryList == IFObjList);
  978. }
  979. if (pIterator)
  980. {
  981. // Adjust backward link
  982. pIterator->Prev = pPreviousNode;
  983. }
  984. //
  985. // Empty the EP Mapper table, if necessary.
  986. //
  987. if (ProcessCtxt->EntryList == IFObjList)
  988. {
  989. if (pIterator)
  990. {
  991. ASSERT(cTotalEpEntries > 0);
  992. // New Head for Ep Mapper list
  993. IFObjList = pIterator;
  994. }
  995. else
  996. {
  997. ASSERT(cTotalEpEntries == 0);
  998. // Memory for this node is already freed in the while loop above.
  999. IFObjList = NULL;
  1000. }
  1001. }
  1002. else
  1003. {
  1004. ASSERT(cTotalEpEntries > 0);
  1005. }
  1006. LeaveSem();
  1007. //
  1008. // Free entities outside the lock.
  1009. //
  1010. FreeMem(ProcessCtxt);
  1011. while (NodesListToDelete != NULL)
  1012. {
  1013. DeleteMe = NodesListToDelete;
  1014. NodesListToDelete = NodesListToDelete->Next;
  1015. // Delete the PSEP list.
  1016. pTempPSEP = DeleteMe->PSEPlist;
  1017. while (pTempPSEP != NULL)
  1018. {
  1019. pDeletePSEP = pTempPSEP;
  1020. pTempPSEP = pTempPSEP->Next;
  1021. FreeMem(pDeletePSEP);
  1022. }
  1023. FreeMem(DeleteMe);
  1024. }
  1025. }
  1026. void
  1027. ept_insert(
  1028. handle_t h,
  1029. unsigned32 NumEntries,
  1030. ept_entry_t Entries[],
  1031. unsigned long Replace,
  1032. error_status *Status
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. This function is no longer supported by EpMapper. RPC Runtime does not
  1037. call this function anymore. And, no one else should be...
  1038. --*/
  1039. {
  1040. ASSERT(Status);
  1041. *Status = EPT_S_CANT_PERFORM_OP;
  1042. }
  1043. void
  1044. ept_insert_ex(
  1045. IN handle_t h,
  1046. IN OUT ept_cleanup_handle_t *hEpCleanup,
  1047. IN unsigned32 NumEntries,
  1048. IN ept_entry_t Entries[],
  1049. IN unsigned long Replace,
  1050. OUT error_status *Status
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. This is the exposed rpc interface routine that adds a series of
  1055. endpoints to the Endpoint Mapper database.
  1056. Arguments:
  1057. h - An explicit binding handle to the EP.
  1058. hEpCleanup - A context handle used to purge the Endpoint Mapper
  1059. database of stale entries.
  1060. NumEntries - Number of Entries to be added.
  1061. Entries - An array of ept_entry_t entries.
  1062. Replace - TRUE => Replace existing entries.
  1063. FALSE=> Just add.
  1064. Return Value:
  1065. RPC_S_OK - The endpoint was successfully deleted.
  1066. RPC_S_OUT_OF_MEMORY - There is no memory to perform the op.
  1067. EPT_S_CANT_PERFORM - Invalid entry.
  1068. --*/
  1069. {
  1070. ept_entry_t * Ep;
  1071. unsigned short i, j;
  1072. unsigned int TransType = 0x0;
  1073. unsigned long err = 0;
  1074. unsigned long Version;
  1075. unsigned char protseqid;
  1076. char *Protseq, *Endpoint;
  1077. RPC_IF_ID IfId;
  1078. PPSEPNode List = 0;
  1079. PPSEPNode pPSEPNode, TmpPsep, pTempPSEP, pDeletePSEP;
  1080. unsigned long cb;
  1081. twr_t * Tower;
  1082. BOOL bIFNodeFound = FALSE;
  1083. PIFOBJNode NodesListToDelete = NULL;
  1084. PIFOBJNode Node, NewNode, DeleteMe = NULL;
  1085. UUID * Object;
  1086. char * Annotation;
  1087. RPC_STATUS Err;
  1088. SECURITY_DESCRIPTOR SecurityDescriptor, * PSecurityDesc;
  1089. BOOL Bool;
  1090. //
  1091. // First, make sure the call is via LRPC.
  1092. //
  1093. err = I_RpcBindingInqTransportType(h, &TransType);
  1094. ASSERT(err == RPC_S_OK);
  1095. if (TransType != TRANSPORT_TYPE_LPC)
  1096. {
  1097. *Status = RPC_S_ACCESS_DENIED;
  1098. return;
  1099. }
  1100. //
  1101. // Create a temporary PSEP list from the Tower entries.
  1102. //
  1103. for (Ep = &Entries[0], i = 0; i < NumEntries; Ep++,i++)
  1104. {
  1105. err = TowerExplode(
  1106. Ep->tower,
  1107. &IfId,
  1108. NULL,
  1109. &Protseq,
  1110. &Endpoint,
  1111. 0
  1112. );
  1113. if (err == RPC_S_OUT_OF_MEMORY)
  1114. break;
  1115. if (err)
  1116. {
  1117. err = RPC_S_OK;
  1118. continue;
  1119. }
  1120. Object = &Ep->object;
  1121. Annotation = (char *)&Ep->annotation;
  1122. Tower = Ep->tower;
  1123. cb = sizeof(PSEPNode) +
  1124. strlen(Protseq) +
  1125. strlen(Endpoint) +
  1126. 2 + // for the 2 null terminators
  1127. Tower->tower_length +
  1128. sizeof(Tower->tower_length) +
  1129. 4; // We need to align tower on DWORD
  1130. if ( (pPSEPNode = AllocMem(cb)) == NULL )
  1131. {
  1132. err = RPC_S_OUT_OF_MEMORY;
  1133. break;
  1134. }
  1135. // Mark this protseq to start listening if needed.
  1136. protseqid = (unsigned char) GetProtseqIdAnsi(Protseq);
  1137. DelayedUseProtseq(protseqid);
  1138. //
  1139. // Add a node to the temporary PSEP list
  1140. //
  1141. memset(pPSEPNode, 0, cb);
  1142. pPSEPNode->Signature = PSEPSIGN;
  1143. pPSEPNode->Cb = cb;
  1144. //strcpy(pPSEPNode->Protseq= ((char *) (pPSEPNode+1)), Protseq);
  1145. // Protseq
  1146. pPSEPNode->Protseq = (char *) (pPSEPNode + 1); // What is the +1 for?
  1147. strcpy(pPSEPNode->Protseq, Protseq);
  1148. // Endpoint
  1149. pPSEPNode->EP = pPSEPNode->Protseq + strlen(pPSEPNode->Protseq) + 1;
  1150. strcpy(pPSEPNode->EP, Endpoint);
  1151. // Tower. We add necessary pad so that Tower is aligned to a DWORD.
  1152. pPSEPNode->Tower = (twr_t PAPI *)(pPSEPNode->EP +
  1153. strlen(pPSEPNode->EP) + 1);
  1154. (char PAPI*)(pPSEPNode->Tower) += 4 - ((ULONG_PTR)
  1155. (pPSEPNode->Tower) & 3);
  1156. memcpy((char PAPI *)pPSEPNode->Tower,
  1157. Tower,
  1158. Tower->tower_length + sizeof(Tower->tower_length)
  1159. );
  1160. // Finally, add.
  1161. EnterSem();
  1162. EnLinkOnPSEPList(&List, pPSEPNode);
  1163. LeaveSem();
  1164. I_RpcFree(Protseq);
  1165. I_RpcFree(Endpoint);
  1166. }
  1167. if ((err == RPC_S_OUT_OF_MEMORY) || (List == 0))
  1168. {
  1169. *Status = err;
  1170. return;
  1171. }
  1172. CompleteDelayedUseProtseqs();
  1173. Version = VERSION(IfId.VersMajor, IfId.VersMinor);
  1174. //
  1175. // Find if a compatible Endpoint Mapper entry is already present.
  1176. //
  1177. if (*hEpCleanup != NULL)
  1178. {
  1179. //
  1180. // The requesting process has previously registered entries
  1181. // with the Endpoint Mapper.
  1182. //
  1183. ASSERT_PROCESS_CONTEXT_LIST_COUNT((PEP_CLEANUP)*hEpCleanup, ((PEP_CLEANUP)*hEpCleanup)->cEntries);
  1184. ASSERT(((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE);
  1185. ASSERT(((PEP_CLEANUP)*hEpCleanup)->cEntries != 0);
  1186. if ( (((PEP_CLEANUP)*hEpCleanup)->MagicVal != CLEANUP_MAGIC_VALUE)
  1187. || (((PEP_CLEANUP)*hEpCleanup)->cEntries == 0))
  1188. {
  1189. *Status = EPT_S_CANT_PERFORM_OP;
  1190. return;
  1191. }
  1192. EnterSem();
  1193. if (Replace == TRUE) // Common case
  1194. {
  1195. //
  1196. // If we find a compatible entry, we just replace its PSEP list
  1197. // with the temporary list that we just created.
  1198. //
  1199. Node = ((PEP_CLEANUP)*hEpCleanup)->EntryList;
  1200. while (Node != 0)
  1201. {
  1202. Node = FindIFOBJNode(
  1203. Node,
  1204. Object,
  1205. &IfId.Uuid,
  1206. Version,
  1207. RPC_C_EP_MATCH_BY_BOTH,
  1208. I_RPC_C_VERS_UPTO_AND_COMPATIBLE,
  1209. SearchIFObjNode
  1210. );
  1211. if ((Node == 0) || (Node->OwnerOfList != *hEpCleanup))
  1212. break;
  1213. // Matching Endpoint Mapper entry found.
  1214. PurgeOldEntries(Node, List, FALSE);
  1215. if (Node->IFVersion == Version)
  1216. {
  1217. bIFNodeFound = TRUE;
  1218. // Seek to the end of Tmp and then Link
  1219. TmpPsep = List;
  1220. while (TmpPsep->Next != 0)
  1221. TmpPsep = TmpPsep->Next;
  1222. TmpPsep->Next = Node->PSEPlist;
  1223. Node->PSEPlist = List;
  1224. }
  1225. if (Node->PSEPlist == 0)
  1226. {
  1227. DeleteMe = Node;
  1228. Node = Node->Next;
  1229. err = UnLinkFromIFOBJList((PEP_CLEANUP)*hEpCleanup, DeleteMe);
  1230. ASSERT(err == RPC_S_OK);
  1231. // Add to a list that will be deleted later...
  1232. DeleteMe->Next = NodesListToDelete;
  1233. NodesListToDelete = DeleteMe;
  1234. DeleteMe->Signature = FREE;
  1235. }
  1236. else
  1237. {
  1238. Node = Node->Next;
  1239. }
  1240. } // while loop
  1241. }
  1242. else // (Replace != TRUE)
  1243. {
  1244. //
  1245. // If we find an entry with an exact match, we append
  1246. // the temporary PSEP list to the entry's PSEP list.
  1247. //
  1248. Node = ((PEP_CLEANUP)*hEpCleanup)->EntryList;
  1249. NewNode = FindIFOBJNode(
  1250. Node,
  1251. Object,
  1252. &IfId.Uuid,
  1253. Version,
  1254. 0,
  1255. 0,
  1256. ExactMatch
  1257. );
  1258. if (NewNode && (NewNode->OwnerOfList == *hEpCleanup))
  1259. {
  1260. bIFNodeFound = TRUE;
  1261. PurgeOldEntries(NewNode, List, TRUE);
  1262. // Seek to the end of Tmp and then Link
  1263. TmpPsep = List;
  1264. while (TmpPsep->Next != 0)
  1265. TmpPsep = TmpPsep->Next;
  1266. TmpPsep->Next = NewNode->PSEPlist;
  1267. NewNode->PSEPlist = List;
  1268. }
  1269. } // if (Replace == TRUE)
  1270. LeaveSem();
  1271. } // if (*hpCleanup != NULL)
  1272. //
  1273. // Free the list outside the lock.
  1274. //
  1275. while (NodesListToDelete != NULL)
  1276. {
  1277. DeleteMe = NodesListToDelete;
  1278. NodesListToDelete = NodesListToDelete->Next;
  1279. // Delete the PSEP list.
  1280. pTempPSEP = DeleteMe->PSEPlist;
  1281. while (pTempPSEP != NULL)
  1282. {
  1283. pDeletePSEP = pTempPSEP;
  1284. pTempPSEP = pTempPSEP->Next;
  1285. FreeMem(pDeletePSEP);
  1286. }
  1287. FreeMem(DeleteMe);
  1288. }
  1289. if (bIFNodeFound == FALSE)
  1290. {
  1291. //
  1292. // One of the following is TRUE:
  1293. // a. The process is registering with EP Mapper for the first time.
  1294. // b. No compatible Ep entry was found.
  1295. //
  1296. //
  1297. // Allocate a new EP Mapper entry.
  1298. //
  1299. cb = sizeof(IFOBJNode);
  1300. cb += strlen(Annotation) + 1;
  1301. if ((NewNode = AllocMem(cb)) == NULL)
  1302. {
  1303. *Status = RPC_S_OUT_OF_MEMORY;
  1304. return;
  1305. }
  1306. //
  1307. // Fill-in the new entry
  1308. //
  1309. memset(NewNode, 0, cb);
  1310. NewNode->Cb = cb;
  1311. NewNode->Signature = IFOBJSIGN;
  1312. NewNode->IFVersion = Version;
  1313. memcpy((char *)&NewNode->ObjUuid, (char *)Object, sizeof(UUID));
  1314. memcpy((char *)&NewNode->IFUuid, (char *)&IfId.Uuid, sizeof(UUID));
  1315. strcpy((NewNode->Annotation=(char *)(NewNode+1)), Annotation);
  1316. if (IsNullUuid(Object))
  1317. NewNode->IFOBJid = MAKEGLOBALIFOBJID(MAXIFOBJID);
  1318. else
  1319. NewNode->IFOBJid = MAKEGLOBALIFOBJID(GlobalIFOBJid--);
  1320. //
  1321. // Create a new context for this process, if necessary
  1322. //
  1323. if (*hEpCleanup == NULL)
  1324. {
  1325. *hEpCleanup = AllocMem(sizeof(EP_CLEANUP));
  1326. if (*hEpCleanup == NULL)
  1327. {
  1328. LeaveSem();
  1329. FreeMem(NewNode);
  1330. *Status = RPC_S_OUT_OF_MEMORY;
  1331. return;
  1332. }
  1333. memset(*hEpCleanup, 0x0, sizeof(EP_CLEANUP));
  1334. ((PEP_CLEANUP)*hEpCleanup)->MagicVal = CLEANUP_MAGIC_VALUE;
  1335. }
  1336. //
  1337. // Insert the new entry into the EP Mapper table.
  1338. //
  1339. EnterSem();
  1340. err = EnLinkOnIFOBJList((PEP_CLEANUP)*hEpCleanup, NewNode);
  1341. ASSERT(err == RPC_S_OK);
  1342. NewNode->PSEPlist = List;
  1343. LeaveSem();
  1344. }
  1345. *Status = err;
  1346. }
  1347. void
  1348. ept_delete(
  1349. handle_t h,
  1350. unsigned32 NumEntries,
  1351. ept_entry_t Entries[],
  1352. error_status *Status
  1353. )
  1354. /*++
  1355. Routine Description:
  1356. This function is no longer supported by EpMapper. RPC Runtime does not
  1357. call this function anymore. And, no one else should be...
  1358. --*/
  1359. {
  1360. ASSERT(Status);
  1361. *Status = EPT_S_CANT_PERFORM_OP;
  1362. }
  1363. RPC_STATUS
  1364. ept_delete_ex_helper(
  1365. IN ept_cleanup_handle_t hEpCleanup,
  1366. IN UUID *Object,
  1367. IN UUID *Interface,
  1368. IN unsigned long IFVersion,
  1369. IN char PAPI * Protseq,
  1370. IN char PAPI * Endpoint
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This routine deletes an Endpoint registered with the EP Mapper
  1375. Arguments:
  1376. hEpCleanup - A context handle used to purge the Endpoint Mapper
  1377. database of stale entries.
  1378. Object - Object Uuid.
  1379. Interface - If Uuid
  1380. IFVersion - Version of the IF [Hi ushort=Major, Lo ushort=Minor]
  1381. Protseq - Protocol Sequence
  1382. Endpoint - Endpoint string
  1383. Notes:
  1384. a. This routine has to be called by holding a mutex.
  1385. Return Value:
  1386. RPC_S_OK - The endpoint was successfully deleted
  1387. EPT_S_NOT_REGISTERED - No matching entries were found
  1388. --*/
  1389. {
  1390. PIFOBJNode pNode;
  1391. PPSEPNode pPSEPNode = NULL;
  1392. unsigned long cb, err = 0;
  1393. PEP_T p;
  1394. PEP_CLEANUP ProcessCtx;
  1395. if (!Protseq || !Endpoint)
  1396. {
  1397. return(EPT_S_NOT_REGISTERED);
  1398. }
  1399. CheckInSem();
  1400. ProcessCtx = (PEP_CLEANUP)hEpCleanup;
  1401. if (ProcessCtx->EntryList == NULL)
  1402. return EPT_S_NOT_REGISTERED;
  1403. pNode = FindIFOBJNode(
  1404. ProcessCtx->EntryList,
  1405. Object,
  1406. Interface,
  1407. IFVersion,
  1408. 0L,
  1409. 0L,
  1410. ExactMatch
  1411. );
  1412. if ((pNode != NULL) && (pNode->PSEPlist != NULL))
  1413. {
  1414. pPSEPNode = FindPSEP(
  1415. pNode->PSEPlist,
  1416. Protseq,
  1417. Endpoint,
  1418. 0L,
  1419. MatchPSAndEP
  1420. );
  1421. }
  1422. if (pPSEPNode != NULL)
  1423. {
  1424. UnLinkFromPSEPList(&pNode->PSEPlist, pPSEPNode);
  1425. if (pNode->PSEPlist == NULL)
  1426. {
  1427. err = UnLinkFromIFOBJList((PEP_CLEANUP)hEpCleanup, pNode);
  1428. // ASSERT(err == RPC_S_OK);
  1429. if (err != RPC_S_OK)
  1430. {
  1431. // Restore the PSEPList
  1432. EnLinkOnPSEPList(&pNode->PSEPlist, pPSEPNode);
  1433. return err;
  1434. }
  1435. pNode->Signature = FREE;
  1436. FreeMem(pNode);
  1437. }
  1438. pPSEPNode->Signature = FREE;
  1439. FreeMem(pPSEPNode);
  1440. }
  1441. else
  1442. {
  1443. err = EPT_S_NOT_REGISTERED;
  1444. }
  1445. return(err);
  1446. }
  1447. void
  1448. ept_delete_ex(
  1449. IN handle_t h,
  1450. IN OUT ept_cleanup_handle_t *hEpCleanup,
  1451. IN unsigned32 NumEntries,
  1452. IN ept_entry_t Entries[],
  1453. OUT error_status *Status
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. This routine deletes the specified Endpoints
  1458. Arguments:
  1459. BindingHandle - An explicit binding handle to the EP.
  1460. NumEntries - #of entries in the Bunffer that need to be deleted.
  1461. Entries[] - Buffer of #NumEntries of ept_entry_t structures
  1462. Return Value:
  1463. RPC_S_OK - The endpoint was successfully deleted
  1464. EPT_S_NOT_REGISTERED - No matching entries were found
  1465. --*/
  1466. {
  1467. ept_entry_t * Ep;
  1468. unsigned short i;
  1469. unsigned int TransType = 0x0;
  1470. RPC_STATUS err;
  1471. RPC_STATUS DeleteStatus;
  1472. unsigned long Version;
  1473. char *Protseq, *Endpoint;
  1474. RPC_IF_ID IfId;
  1475. RPC_TRANSFER_SYNTAX XferId;
  1476. //
  1477. // First, make sure the call is via LRPC.
  1478. //
  1479. err = I_RpcBindingInqTransportType(h, &TransType);
  1480. ASSERT(err == RPC_S_OK);
  1481. if (TransType != TRANSPORT_TYPE_LPC)
  1482. {
  1483. *Status = RPC_S_ACCESS_DENIED;
  1484. return;
  1485. }
  1486. if ( !( (*hEpCleanup)
  1487. && (((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE)
  1488. && (((PEP_CLEANUP)*hEpCleanup)->cEntries != 0)
  1489. )
  1490. )
  1491. {
  1492. //
  1493. // Cannot ASSERT here. This is possible. (ep1-26, ep2-3)
  1494. //
  1495. //ASSERT(*hEpCleanup);
  1496. //ASSERT(((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE);
  1497. //ASSERT(((PEP_CLEANUP)*hEpCleanup)->cEntries != 0);
  1498. *Status = EPT_S_CANT_PERFORM_OP;
  1499. return;
  1500. }
  1501. *Status = EPT_S_NOT_REGISTERED;
  1502. DeleteStatus = RPC_S_OK;
  1503. for (Ep = &Entries[0], i = 0; i < NumEntries; Ep++,i++)
  1504. {
  1505. err = TowerExplode(
  1506. Ep->tower,
  1507. &IfId,
  1508. &XferId,
  1509. &Protseq,
  1510. &Endpoint,
  1511. 0
  1512. );
  1513. if (err == RPC_S_OUT_OF_MEMORY)
  1514. {
  1515. *Status = RPC_S_OUT_OF_MEMORY;
  1516. break;
  1517. }
  1518. if (err)
  1519. {
  1520. continue;
  1521. }
  1522. Version = VERSION(IfId.VersMajor, IfId.VersMinor);
  1523. EnterSem();
  1524. //
  1525. // NOTE:
  1526. //
  1527. // If even one call to ept_delete_ex_helper() fails, we want to return
  1528. // failure from ept_delete_ex(). This is different from the past where
  1529. // if one call succeeded, then the function returned success.
  1530. //
  1531. err = ept_delete_ex_helper(
  1532. *hEpCleanup,
  1533. &Ep->object,
  1534. &IfId.Uuid,
  1535. Version,
  1536. Protseq,
  1537. Endpoint
  1538. );
  1539. if (err)
  1540. {
  1541. // Save the last failure status.
  1542. DeleteStatus = err;
  1543. }
  1544. if (((PEP_CLEANUP)*hEpCleanup)->cEntries == 0)
  1545. {
  1546. //
  1547. // No entry left in this process's list. Time to zero out this
  1548. // process's context handle.
  1549. //
  1550. //ASSERT(((PEP_CLEANUP)*hEpCleanup)->EntryList == NULL);
  1551. FreeMem(*hEpCleanup);
  1552. *hEpCleanup = NULL;
  1553. }
  1554. LeaveSem();
  1555. if (Protseq)
  1556. I_RpcFree(Protseq);
  1557. if (Endpoint)
  1558. I_RpcFree(Endpoint);
  1559. }
  1560. if (err)
  1561. {
  1562. // RPC_S_OUT_OF_MEMORY OR the last call to
  1563. // ept_delete_ex_helper() failed.
  1564. *Status = err;
  1565. }
  1566. else
  1567. {
  1568. // RPC_S_OK OR one of the calls to ept_delete_ex_helper() (but
  1569. // not the last one) failed.
  1570. *Status = DeleteStatus;
  1571. }
  1572. }
  1573. void
  1574. ept_lookup(
  1575. handle_t hEpMapper,
  1576. unsigned32 InquiryType,
  1577. UUID * Object,
  1578. RPC_IF_ID * Ifid,
  1579. unsigned32 VersOptions,
  1580. ept_lookup_handle_t *LookupHandle,
  1581. unsigned32 MaxRequested,
  1582. unsigned32 *NumEntries,
  1583. ept_entry_t Entries[],
  1584. error_status *Status
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine returns upto MaxRequested, ept_entry(s) currently
  1589. registered with the Endpoint mapper based on the
  1590. Obj, Interface, Protocol sequence and filters VersOptions and
  1591. InqType
  1592. Arguments:
  1593. BindingHandle - An explicit binding handle to the EP.
  1594. InquiryType - Search Filter [Seach based on IF, Obj or Both]
  1595. Obj - Object Uuid. specified by the client
  1596. ObjInterface - Interface Uuid spec. by the client.
  1597. InId - The If Specification [IF Uuid+IfVersion]
  1598. VersOpts- Search Filter based on Versions [Versins <, >, ==]
  1599. MapHandle - A resume key - If NULL, search is started from the beginning
  1600. if non-null, represents an encoding from where the epmapper is
  1601. is supposed to start searching. It is an opaque value as far as the
  1602. as far as the client is concerned.
  1603. MaxRequested - Max number of entries requested by the client.
  1604. Returned - The actual number of entries returned by the mapper.
  1605. Entries - Buffer of ept_entries returned.
  1606. Return Value:
  1607. RPC_S_OUT_OF_MEMORY
  1608. RPC_S_OK - At least one matching entry is being returned.
  1609. EP_S_NOT_REGISTERED - No matching entries were found
  1610. EPT_S_CANT_PERFORM_OP - MaxRequested value exceed ep_max_lookup_results
  1611. --*/
  1612. {
  1613. unsigned long Version;
  1614. if (Ifid == NULL)
  1615. {
  1616. Ifid = &LocalNullUuid;
  1617. }
  1618. if (Object == NULL)
  1619. {
  1620. Object = (UUID *) &LocalNullUuid;
  1621. }
  1622. switch (VersOptions)
  1623. {
  1624. case RPC_C_VERS_ALL:
  1625. Version = 0;
  1626. break;
  1627. case RPC_C_VERS_COMPATIBLE:
  1628. case RPC_C_VERS_EXACT:
  1629. case RPC_C_VERS_UPTO:
  1630. Version = VERSION(Ifid->VersMajor, Ifid->VersMinor);
  1631. break;
  1632. case RPC_C_VERS_MAJOR_ONLY:
  1633. Version = VERSION(Ifid->VersMajor, 0);
  1634. break;
  1635. default:
  1636. break;
  1637. }
  1638. *Status = GetEntries(
  1639. Object,
  1640. &Ifid->Uuid,
  1641. Version,
  1642. NULL,
  1643. LookupHandle,
  1644. (char *)Entries,
  1645. EP_LOOKUP,
  1646. MaxRequested,
  1647. NumEntries,
  1648. InquiryType,
  1649. VersOptions,
  1650. SearchIFObjNode
  1651. );
  1652. }
  1653. void
  1654. ept_map(
  1655. handle_t h,
  1656. UUID *Obj OPTIONAL,
  1657. twr_p_t MapTower,
  1658. ept_lookup_handle_t *MapHandle,
  1659. unsigned32 MaxTowers,
  1660. unsigned32 *NumTowers,
  1661. twr_p_t *ITowers,
  1662. error_status *Status
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. This routine returns a fully-resolved string binding, for a given
  1667. Obj, Interface, and Protocol sequence if an appropriate entry is
  1668. found. Else returns EP_S_NOT_REGISTERED.
  1669. Arguments:
  1670. BindingHandle - An explicit binding handle to the EP.
  1671. Obj - Object Uuid. specified by the client
  1672. ObjInterface - Interface Uuid spec. by the client.
  1673. Interfacever - InterfaceVersion [hi ushort = VerMajor, lo ushort VerMinor]
  1674. Protseq - An ascii string specifying the protocol seq.
  1675. MapHandle - A resume key - If NULL, search is started from the beginning
  1676. if non-null, represents an encoding from where the epmapper is
  1677. supposed to start searching. It is an opaque value as far as the
  1678. client is concerned.
  1679. Binding - The fully resolved string binding returned if the call is
  1680. successful.
  1681. Return Value:
  1682. RPC_S_OUT_OF_MEMORY
  1683. RPC_S_OK
  1684. EP_S_NOT_REGISTERED
  1685. --*/
  1686. {
  1687. RPC_IF_ID Ifid;
  1688. RPC_TRANSFER_SYNTAX Xferid;
  1689. char *Protseq;
  1690. unsigned long Version;
  1691. char * String = 0;
  1692. if (Obj == 0)
  1693. {
  1694. Obj = (UUID *) &LocalNullUuid;
  1695. }
  1696. *Status = TowerExplode(
  1697. MapTower,
  1698. &Ifid,
  1699. &Xferid,
  1700. &Protseq,
  1701. NULL,
  1702. 0
  1703. );
  1704. if (*Status)
  1705. {
  1706. *NumTowers = 0;
  1707. return;
  1708. }
  1709. Version = VERSION(Ifid.VersMajor,Ifid.VersMinor);
  1710. if (memcmp((char *)&Ifid.Uuid, (char *)&MgmtIf, sizeof(UUID)) == 0)
  1711. {
  1712. if ((Obj == 0) || IsNullUuid(Obj))
  1713. {
  1714. *NumTowers = 0;
  1715. *Status = RPC_S_BINDING_INCOMPLETE;
  1716. }
  1717. else
  1718. {
  1719. *Status = GetEntries(
  1720. Obj,
  1721. &Ifid.Uuid,
  1722. Version,
  1723. Protseq,
  1724. MapHandle,
  1725. (char *)ITowers,
  1726. EP_MAP,
  1727. MaxTowers,
  1728. NumTowers,
  1729. RPC_C_EP_MATCH_BY_OBJ,
  1730. RPC_C_VERS_ALL,
  1731. SearchIFObjNode
  1732. );
  1733. }
  1734. }
  1735. else
  1736. {
  1737. *Status = GetEntries(
  1738. Obj,
  1739. &Ifid.Uuid,
  1740. Version,
  1741. Protseq,
  1742. MapHandle,
  1743. (char *)ITowers,
  1744. EP_MAP,
  1745. MaxTowers,
  1746. NumTowers,
  1747. 0L,
  1748. 0L,
  1749. WildCardMatch
  1750. );
  1751. }
  1752. if (Protseq)
  1753. I_RpcFree(Protseq);
  1754. }
  1755. void
  1756. ept_inq_object(
  1757. handle_t BindingHandle,
  1758. UUID *Object,
  1759. error_status *status
  1760. )
  1761. /*++
  1762. Routine Description:
  1763. Not supported
  1764. Arguments:
  1765. BindingHandle - An explicit binding handle to the EP.
  1766. Object _ No idea whose UUID this is.
  1767. Return Value:
  1768. EPT_S_CANT_PERFORM_OP
  1769. --*/
  1770. {
  1771. ASSERT(*status);
  1772. *status = EPT_S_CANT_PERFORM_OP;
  1773. }
  1774. void
  1775. DeletePSEP(
  1776. PIFOBJNode Node,
  1777. char * Protseq,
  1778. char * Endpoint
  1779. )
  1780. {
  1781. PSEPNode *Psep, *Tmp;
  1782. if (Node == 0)
  1783. return;
  1784. Psep = Node->PSEPlist;
  1785. while (Psep != 0)
  1786. {
  1787. Psep = FindPSEP(
  1788. Psep,
  1789. Protseq,
  1790. Endpoint,
  1791. 0L,
  1792. MatchPSAndEP
  1793. );
  1794. if (Psep != 0)
  1795. {
  1796. Tmp = Psep;
  1797. Psep = Psep->Next;
  1798. UnLinkFromPSEPList(&Node->PSEPlist, Tmp);
  1799. Tmp->Signature = FREE;
  1800. FreeMem(Tmp);
  1801. }
  1802. }
  1803. }
  1804. void
  1805. ept_mgmt_delete(
  1806. handle_t BindingHandle,
  1807. boolean32 ObjectSpecd,
  1808. UUID * Object,
  1809. twr_p_t Tower,
  1810. error_status *Error
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. Not supported
  1815. Arguments:
  1816. BindingHandle - An explicit binding handle to the EP.
  1817. Object _ ObjUUid
  1818. Tower - Tower specifying the Endpoints to be deleted.
  1819. Return Value:
  1820. EPT_S_CANT_PERFORM_OP
  1821. --*/
  1822. {
  1823. ASSERT(*Error);
  1824. *Error = EP_S_CANT_PERFORM_OP;
  1825. }
  1826. void ept_lookup_handle_t_rundown (ept_lookup_handle_t h)
  1827. {
  1828. PSAVEDCONTEXT Context = (PSAVEDCONTEXT) h;
  1829. PIENTRY Entry;
  1830. unsigned long Type;
  1831. PIENTRY Tmp;
  1832. twr_t * Tower;
  1833. ASSERT (Context != 0);
  1834. if ( (PtrToUlong(Context)) == 0xFFFFFFFF)
  1835. return;
  1836. Type = Context->Type;
  1837. EnterSem();
  1838. Entry = (PIENTRY)Context->List;
  1839. while (Entry != 0)
  1840. {
  1841. switch (Type)
  1842. {
  1843. case EP_MAP:
  1844. Tower = ((PSAVEDTOWER)Entry)->Tower;
  1845. break;
  1846. case EP_LOOKUP:
  1847. Tower = ((PSAVED_EPT)Entry)->Tower;
  1848. break;
  1849. default:
  1850. ASSERT(!"Unknown Inquiry Type");
  1851. break;
  1852. }
  1853. MIDL_user_free(Tower);
  1854. Tmp = Entry;
  1855. Entry = Entry->Next;
  1856. FreeMem(Tmp);
  1857. }
  1858. // Now free The Context
  1859. UnLink((PIENTRY *)&GlobalContextList, (PIENTRY)Context);
  1860. LeaveSem();
  1861. FreeMem(Context);
  1862. }
  1863. void
  1864. ept_lookup_handle_free(
  1865. handle_t h,
  1866. ept_lookup_handle_t * ept_context_handle,
  1867. error_status * status
  1868. )
  1869. {
  1870. if ( (ept_context_handle != 0) && (*ept_context_handle != 0))
  1871. {
  1872. ept_lookup_handle_t_rundown( *ept_context_handle );
  1873. *ept_context_handle = 0;
  1874. }
  1875. *status = 0;
  1876. }
  1877. #define MAX(x,y) ((x) < (y)) ? (y) : (x)
  1878. #define MIN(x,y) ((x) > (y)) ? (y) : (x)
  1879. #ifdef DEBUGRPC
  1880. #define DEBUG_MIN(x,y) MIN((x),(y))
  1881. #else
  1882. #define DEBUG_MIN(x,y) MAX((x),(y))
  1883. #endif
  1884. error_status_t
  1885. OpenEndpointMapper(
  1886. IN handle_t hServer,
  1887. OUT HPROCESS *pProcessHandle
  1888. )
  1889. {
  1890. PROCESS *pProcess = MIDL_user_allocate(sizeof(PROCESS));
  1891. if (!pProcess)
  1892. {
  1893. *pProcessHandle = 0;
  1894. return(RPC_S_OUT_OF_MEMORY);
  1895. }
  1896. pProcess->MagicVal = PROCESS_MAGIC_VALUE;
  1897. pProcess->pPorts = 0;
  1898. *pProcessHandle = (PVOID)pProcess;
  1899. return(RPC_S_OK);
  1900. }
  1901. //
  1902. // Port Management stuff
  1903. //
  1904. //
  1905. // Port Management Globals
  1906. //
  1907. const RPC_CHAR *PortConfigKey = RPC_CONST_STRING("Software\\Microsoft\\Rpc\\Internet");
  1908. const RPC_CHAR *DefaultPortType = RPC_CONST_STRING("UseInternetPorts");
  1909. const RPC_CHAR *ExplictPortType = RPC_CONST_STRING("PortsInternetAvailable");
  1910. const RPC_CHAR *PortRanges = RPC_CONST_STRING("Ports");
  1911. CRITICAL_SECTION PortLock;
  1912. BOOL fValidConfiguration = FALSE;
  1913. BOOL fPortRestrictions = FALSE;
  1914. PORT_TYPE SystemDefaultPortType = 0;
  1915. IP_PORT *pFreeInternetPorts = 0;
  1916. IP_PORT *pFreeIntranetPorts = 0;
  1917. PORT_RANGE *InternetPorts = 0;
  1918. PORT_RANGE *IntranetPorts = 0;
  1919. //
  1920. // Port management APIs
  1921. //
  1922. RPC_STATUS
  1923. InitializeIpPortManager(
  1924. void
  1925. )
  1926. {
  1927. HKEY hkey;
  1928. RPC_STATUS status;
  1929. DWORD size, type, value;
  1930. RPC_CHAR *pstr;
  1931. PORT_RANGE *pSet;
  1932. PORT_RANGE *pLast;
  1933. PORT_RANGE *pCurrent;
  1934. PORT_RANGE *pComplement;
  1935. PORT_RANGE *pNew;
  1936. LONG min, max;
  1937. InitializeCriticalSectionAndSpinCount(&PortLock, PREALLOCATE_EVENT_MASK);
  1938. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1939. PortConfigKey,
  1940. 0,
  1941. KEY_READ,
  1942. &hkey);
  1943. if (status != RPC_S_OK)
  1944. {
  1945. if (status != ERROR_FILE_NOT_FOUND)
  1946. {
  1947. #if DBG
  1948. PrintToDebugger("RPCSS: Unable to open port config key: %d\n", status);
  1949. #endif
  1950. }
  1951. ASSERT(status == ERROR_FILE_NOT_FOUND);
  1952. fValidConfiguration = TRUE;
  1953. return(RPC_S_OK);
  1954. }
  1955. size = sizeof(value);
  1956. status = RegQueryValueEx(hkey,
  1957. DefaultPortType,
  1958. 0,
  1959. &type,
  1960. (PBYTE)&value,
  1961. &size);
  1962. if ( status != RPC_S_OK
  1963. || type != REG_SZ
  1964. || ( *(RPC_CHAR *)&value != 'Y'
  1965. && *(RPC_CHAR *)&value != 'y'
  1966. && *(RPC_CHAR *)&value != 'N'
  1967. && *(RPC_CHAR *)&value != 'n') )
  1968. {
  1969. RegCloseKey(hkey);
  1970. ASSERT(fValidConfiguration == FALSE);
  1971. return(RPC_S_OK);
  1972. }
  1973. if ( *(RPC_CHAR *)&value == 'Y'
  1974. || *(RPC_CHAR *)&value == 'y')
  1975. {
  1976. SystemDefaultPortType = PORT_INTERNET;
  1977. }
  1978. else
  1979. {
  1980. SystemDefaultPortType = PORT_INTRANET;
  1981. }
  1982. size = sizeof(value);
  1983. status = RegQueryValueEx(hkey,
  1984. ExplictPortType,
  1985. 0,
  1986. &type,
  1987. (PBYTE)&value,
  1988. &size);
  1989. if ( status != RPC_S_OK
  1990. || type != REG_SZ
  1991. || ( *(RPC_CHAR *)&value != 'Y'
  1992. && *(RPC_CHAR *)&value != 'y'
  1993. && *(RPC_CHAR *)&value != 'N'
  1994. && *(RPC_CHAR *)&value != 'n') )
  1995. {
  1996. RegCloseKey(hkey);
  1997. ASSERT(fValidConfiguration == FALSE);
  1998. return(RPC_S_OK);
  1999. }
  2000. if ( *(RPC_CHAR *)&value == 'Y'
  2001. || *(RPC_CHAR *)&value == 'y')
  2002. {
  2003. value = PORT_INTERNET;
  2004. }
  2005. else
  2006. {
  2007. value = PORT_INTRANET;
  2008. }
  2009. size = DEBUG_MIN(1, 100);
  2010. do
  2011. {
  2012. ASSERT(size);
  2013. pstr = alloca(size);
  2014. ASSERT(pstr);
  2015. status = RegQueryValueEx(hkey,
  2016. PortRanges,
  2017. 0,
  2018. &type,
  2019. (PBYTE)pstr,
  2020. &size);
  2021. }
  2022. while (status == ERROR_MORE_DATA);
  2023. RegCloseKey(hkey);
  2024. if ( status != RPC_S_OK
  2025. || type != REG_MULTI_SZ)
  2026. {
  2027. ASSERT(fValidConfiguration == FALSE);
  2028. return(RPC_S_OK);
  2029. }
  2030. //
  2031. // The user is going to specify a range of ports in the registery
  2032. // with a flag indicating if these ports are internet or intranet.
  2033. //
  2034. // ie, 500-550
  2035. // 560
  2036. // 559
  2037. // 2000-2048
  2038. // 2029-2049
  2039. //
  2040. // Note that order (in the REG_MULTI_SZ) and overlapping sets
  2041. // are ok. We must handle creating a port range list for this
  2042. // array and for the complement BUT NOT INCLUDING <=1024 by default.
  2043. //
  2044. // completment set to above is:
  2045. //
  2046. // 1025-1999
  2047. // 2050-32767
  2048. //
  2049. #define MIN_PORT 1025 // Only important for complement sets.
  2050. #define MAX_PORT 65535
  2051. pSet = 0;
  2052. pLast = 0;
  2053. while(*pstr)
  2054. {
  2055. RPC_CHAR *t;
  2056. #ifdef UNICODE
  2057. min = wcstol(pstr, &t, 10);
  2058. #else
  2059. min = strtol(pstr, &t, 10);
  2060. #endif
  2061. if (min > MAX_PORT || min < 0)
  2062. {
  2063. status = RPC_S_INVALID_ARG;
  2064. break;
  2065. }
  2066. if ( *t != 0
  2067. #ifdef UNICODE
  2068. && *t != L'-')
  2069. #else
  2070. && *t != '-')
  2071. #endif
  2072. {
  2073. status = RPC_S_INVALID_ARG;
  2074. break;
  2075. }
  2076. if (*t == 0)
  2077. {
  2078. max = min;
  2079. }
  2080. else
  2081. {
  2082. #ifdef UNICODE
  2083. max = wcstol(t + 1, &t, 10);
  2084. #else
  2085. min = strtol(t + 1, &t, 10);
  2086. #endif
  2087. if (max > MAX_PORT || max < 0 || max < min)
  2088. {
  2089. status = RPC_S_INVALID_ARG;
  2090. break;
  2091. }
  2092. }
  2093. ASSERT(min <= max);
  2094. // Ok, got some ports, allocate a structure for them..
  2095. pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
  2096. if (0 == pNew)
  2097. {
  2098. status = RPC_S_OUT_OF_MEMORY;
  2099. break;
  2100. }
  2101. pNew->pNext = 0;
  2102. pNew->Min = (unsigned short) min;
  2103. pNew->Max = (unsigned short) max;
  2104. // We can to maintain the set of ranges in order. As we insert
  2105. // we'll fix any ranges which overlap.
  2106. pCurrent = pSet;
  2107. pLast = 0;
  2108. for (;;)
  2109. {
  2110. if (0 == pSet)
  2111. {
  2112. pSet = pNew;
  2113. break;
  2114. }
  2115. if ( pNew->Min <= (pCurrent->Max + 1)
  2116. && pNew->Max >= (pCurrent->Min - 1) )
  2117. {
  2118. // The ranges overlap or touch. We'll merge them now..
  2119. pCurrent->Min = MIN(pNew->Min, pCurrent->Min);
  2120. pCurrent->Max = MAX(pCurrent->Max, pNew->Max);
  2121. MIDL_user_free(pNew);
  2122. // Since the new larger range may overlap another existing
  2123. // range we just insert the larger range as if it was new...
  2124. pNew = pCurrent;
  2125. // Take current out of the list.
  2126. if (pLast)
  2127. {
  2128. pLast->pNext = pCurrent->pNext;
  2129. }
  2130. if (pSet == pNew)
  2131. {
  2132. pSet = pSet->pNext;
  2133. }
  2134. // Restart
  2135. pCurrent = pSet;
  2136. pLast = 0;
  2137. continue;
  2138. }
  2139. if (pNew->Min < pCurrent->Min)
  2140. {
  2141. // Found the spot
  2142. if (pLast)
  2143. {
  2144. pLast->pNext = pNew;
  2145. pNew->pNext = pCurrent;
  2146. }
  2147. else
  2148. {
  2149. ASSERT(pCurrent == pSet);
  2150. pNew->pNext = pCurrent;
  2151. pSet = pNew;
  2152. }
  2153. break;
  2154. }
  2155. // Continue the search
  2156. pLast = pCurrent;
  2157. pCurrent = pCurrent->pNext;
  2158. if (0 == pCurrent)
  2159. {
  2160. // Reached the end of the list, insert it here.
  2161. pLast->pNext = pNew;
  2162. ASSERT(pNew->pNext == 0);
  2163. break;
  2164. }
  2165. }
  2166. ASSERT(pSet);
  2167. // Advance to the next string of the final null.
  2168. pstr = RpcpCharacter(pstr, 0) + 1;
  2169. }
  2170. if (pSet == 0)
  2171. {
  2172. status = RPC_S_INVALID_ARG;
  2173. }
  2174. if (value == PORT_INTERNET)
  2175. {
  2176. InternetPorts = pSet;
  2177. }
  2178. else
  2179. {
  2180. IntranetPorts = pSet;
  2181. }
  2182. if (status == RPC_S_OK)
  2183. {
  2184. // We've constructed the set of ports in the registry,
  2185. // now we need to compute the complement set.
  2186. pComplement = 0;
  2187. pCurrent = 0;
  2188. min = MIN_PORT;
  2189. while(pSet)
  2190. {
  2191. if (min < pSet->Min)
  2192. {
  2193. max = pSet->Min - 1;
  2194. ASSERT(max >= min);
  2195. pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
  2196. if (0 == pNew)
  2197. {
  2198. status = RPC_S_OUT_OF_MEMORY;
  2199. break;
  2200. }
  2201. pNew->pNext = 0;
  2202. pNew->Min = (unsigned short) min;
  2203. pNew->Max = (unsigned short) max;
  2204. if (pComplement == 0)
  2205. {
  2206. pComplement = pCurrent = pNew;
  2207. }
  2208. else
  2209. {
  2210. ASSERT(pCurrent);
  2211. pCurrent->pNext = pNew;
  2212. pCurrent = pNew;
  2213. }
  2214. }
  2215. min = MAX(MIN_PORT, pSet->Max + 1);
  2216. pSet = pSet->pNext;
  2217. }
  2218. if (status == RPC_S_OK && min < MAX_PORT)
  2219. {
  2220. // Final port in orginal set less then max, allocate final
  2221. // range for the set complement.
  2222. pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
  2223. if (0 != pNew)
  2224. {
  2225. pNew->Min = (unsigned short) min;
  2226. pNew->Max = MAX_PORT;
  2227. pNew->pNext = 0;
  2228. if (pCurrent)
  2229. {
  2230. pCurrent->pNext = pNew;
  2231. }
  2232. else
  2233. {
  2234. ASSERT(min == MIN_PORT);
  2235. pComplement = pNew;
  2236. }
  2237. }
  2238. else
  2239. {
  2240. status = RPC_S_OUT_OF_MEMORY;
  2241. }
  2242. }
  2243. // Even if we failed assign the pointer, it's either
  2244. // null or needs to be freed.
  2245. if (value == PORT_INTERNET)
  2246. {
  2247. ASSERT(IntranetPorts == 0);
  2248. IntranetPorts = pComplement;
  2249. }
  2250. else
  2251. {
  2252. ASSERT(InternetPorts == 0);
  2253. InternetPorts = pComplement;
  2254. }
  2255. }
  2256. if (status != RPC_S_OK)
  2257. {
  2258. ASSERT(fValidConfiguration == FALSE);
  2259. while(InternetPorts)
  2260. {
  2261. PORT_RANGE *pT = InternetPorts;
  2262. InternetPorts = InternetPorts->pNext;
  2263. MIDL_user_free(pT);
  2264. }
  2265. while(IntranetPorts)
  2266. {
  2267. PORT_RANGE *pT = IntranetPorts;
  2268. IntranetPorts = IntranetPorts->pNext;
  2269. MIDL_user_free(pT);
  2270. }
  2271. return(RPC_S_OK);
  2272. }
  2273. fValidConfiguration = TRUE;
  2274. fPortRestrictions = TRUE;
  2275. return(RPC_S_OK);
  2276. }
  2277. BOOL
  2278. AllocatePort(
  2279. OUT IP_PORT **ppPort,
  2280. IN OUT IP_PORT **ppPortFreeList,
  2281. IN PORT_RANGE *pPortList
  2282. )
  2283. /*++
  2284. Routine Description:
  2285. Allocates a port object for a specific process. It first tries
  2286. to use any ports in the free list. If there's nothing in the
  2287. port this then it tries to find a free port in the PortList
  2288. which is one of the sets computed during startup.
  2289. Arguments:
  2290. ppPort - Will contain the allocated port object if successful.
  2291. ppPortFreeList - Pointer to the head of the free list associated
  2292. with this type of port. Maybe modified during this call.
  2293. pPortList - Port ranges associated with this type of port.
  2294. Return Value:
  2295. TRUE - Port allocated
  2296. FALSE - Port not allocated
  2297. --*/
  2298. {
  2299. IP_PORT *pPort = 0;
  2300. // First see if there is free port to reuse.
  2301. if (*ppPortFreeList)
  2302. {
  2303. EnterCriticalSection(&PortLock);
  2304. if (*ppPortFreeList)
  2305. {
  2306. pPort = *ppPortFreeList;
  2307. *ppPortFreeList = pPort->pNext;
  2308. pPort->pNext = 0;
  2309. }
  2310. LeaveCriticalSection(&PortLock);
  2311. }
  2312. if (pPort == 0)
  2313. {
  2314. // No port in the free list, try to allocate one
  2315. // Assume we'll find a free port..
  2316. pPort = MIDL_user_allocate(sizeof(IP_PORT));
  2317. if (0 != pPort)
  2318. {
  2319. pPort->pNext = 0;
  2320. EnterCriticalSection(&PortLock);
  2321. while ( pPortList
  2322. && pPortList->Min > pPortList->Max)
  2323. {
  2324. pPortList = pPortList->pNext;
  2325. }
  2326. if (pPortList)
  2327. {
  2328. ASSERT(pPortList->Min <= pPortList->Max);
  2329. pPort->Port = pPortList->Min;
  2330. pPortList->Min++;
  2331. // We could remove empty ranges from the list.
  2332. }
  2333. LeaveCriticalSection(&PortLock);
  2334. if (0 == pPortList)
  2335. {
  2336. MIDL_user_free(pPort);
  2337. pPort = 0;
  2338. #ifdef DEBUGRPC
  2339. DbgPrint("RPC: Out of reserved ports\n");
  2340. #endif
  2341. }
  2342. }
  2343. }
  2344. // REVIEW: Post SUR we should look at adding events for
  2345. // allocation and failure to allocate IP ports
  2346. *ppPort = pPort;
  2347. return(pPort != 0);
  2348. }
  2349. error_status_t
  2350. AllocateReservedIPPort(
  2351. IN HPROCESS hProcess,
  2352. IN PORT_TYPE PortType,
  2353. OUT long *pAllocationStatus,
  2354. OUT unsigned short *pAllocatedPort
  2355. )
  2356. /*++
  2357. Routine Description:
  2358. Remote manager for RPC runtime to call locally to allocate
  2359. a local port. The call and process parameters must be valid
  2360. and called only locally. Based on the PortType paramet a
  2361. IP port maybe allocated for the calling process. The
  2362. allocationstatus contains the result of the port allocation
  2363. step.
  2364. Arguments:
  2365. hProcess - Valid process context handle allocated with
  2366. a call to OpenEndpointMapper.
  2367. PortType - One of
  2368. PORT_INTERNET
  2369. PORT_INTRANET
  2370. PORT_DEFAULT
  2371. Used to determine which port range to allocate from.
  2372. pAllocationStatus -
  2373. RPC_S_OK - successfully allocated a port.
  2374. RPC_S_OUT_OF_RESOURES - no ports available.
  2375. pAllocatePort - If allocation status is RPC_S_OK then
  2376. this contains the value of the port allocated.
  2377. If zero it means that there are no port restrictions
  2378. and any port maybe used.
  2379. Return Value:
  2380. RPC_S_OK
  2381. RPC_S_INVALID_ARG - configuration error or PortType out of range.
  2382. RPC_S_ACCESS_ DENIED - not called locally.
  2383. --*/
  2384. {
  2385. PROCESS *pProcess = (PROCESS *)hProcess;
  2386. IP_PORT *pPort;
  2387. UINT type;
  2388. BOOL b;
  2389. *pAllocatedPort = 0;
  2390. *pAllocationStatus = RPC_S_OK;
  2391. ASSERT(pProcess);
  2392. if (!fValidConfiguration)
  2393. {
  2394. return(RPC_S_INVALID_ARG);
  2395. }
  2396. if ( (I_RpcBindingInqTransportType(0, &type) != RPC_S_OK)
  2397. || (type != TRANSPORT_TYPE_LPC)
  2398. || (0 == pProcess)
  2399. || (pProcess->MagicVal != PROCESS_MAGIC_VALUE ) )
  2400. {
  2401. return(RPC_S_ACCESS_DENIED);
  2402. }
  2403. if (PortType > PORT_DEFAULT || PortType < PORT_INTERNET)
  2404. {
  2405. return(RPC_S_INVALID_ARG);
  2406. }
  2407. if (fPortRestrictions == FALSE)
  2408. {
  2409. // No port restrictions on this machine, just use zero.
  2410. // This is the common case.
  2411. ASSERT(*pAllocatedPort == 0);
  2412. ASSERT(*pAllocationStatus == 0);
  2413. return(RPC_S_OK);
  2414. }
  2415. // Need to actually allocate a unique port for this process.
  2416. if (PortType == PORT_DEFAULT)
  2417. {
  2418. // Allocate using default policy
  2419. PortType = SystemDefaultPortType;
  2420. }
  2421. ASSERT(PortType == PORT_INTERNET || PortType == PORT_INTRANET);
  2422. pPort = 0;
  2423. if (PortType == PORT_INTERNET)
  2424. {
  2425. b = AllocatePort(&pPort,
  2426. &pFreeInternetPorts,
  2427. InternetPorts
  2428. );
  2429. }
  2430. else
  2431. {
  2432. b = AllocatePort(&pPort,
  2433. &pFreeIntranetPorts,
  2434. IntranetPorts);
  2435. }
  2436. if (!b)
  2437. {
  2438. ASSERT(pPort == 0);
  2439. // REVIEW: Do we want a unique error code if no ports
  2440. // are available?
  2441. *pAllocationStatus = RPC_S_OUT_OF_RESOURCES;
  2442. return(RPC_S_OK);
  2443. }
  2444. ASSERT(pPort);
  2445. ASSERT(pPort->pNext == 0);
  2446. pPort->Type = (unsigned short) PortType;
  2447. pPort->pNext = pProcess->pPorts;
  2448. pProcess->pPorts = pPort;
  2449. *pAllocatedPort = pPort->Port;
  2450. ASSERT(*pAllocationStatus == RPC_S_OK);
  2451. return(RPC_S_OK);
  2452. }
  2453. void
  2454. HPROCESS_rundown(
  2455. HPROCESS hProcess
  2456. )
  2457. {
  2458. PROCESS *pProcess = (PROCESS *)hProcess;
  2459. IP_PORT *pCurrent;
  2460. IP_PORT *pSave;
  2461. ASSERT(pProcess);
  2462. ASSERT(pProcess->MagicVal == PROCESS_MAGIC_VALUE);
  2463. pCurrent = pProcess->pPorts;
  2464. if (pCurrent)
  2465. {
  2466. EnterCriticalSection(&PortLock);
  2467. do
  2468. {
  2469. pSave = pCurrent->pNext;
  2470. if (pCurrent->Type == PORT_INTERNET)
  2471. {
  2472. pCurrent->pNext = pFreeInternetPorts;
  2473. pFreeInternetPorts = pCurrent;
  2474. }
  2475. else
  2476. {
  2477. ASSERT(pCurrent->Type == PORT_INTRANET);
  2478. pCurrent->pNext = pFreeIntranetPorts;
  2479. pFreeIntranetPorts = pCurrent;
  2480. }
  2481. pCurrent = pSave;
  2482. }
  2483. while(pCurrent);
  2484. LeaveCriticalSection(&PortLock);
  2485. }
  2486. MIDL_user_free(pProcess);
  2487. return;
  2488. }