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.

644 lines
31 KiB

  1. /****************************************************************************/
  2. // acpcapi.cpp
  3. //
  4. // Capabilities Coordinator API functions.
  5. //
  6. // Copyright(c) Microsoft, PictureTel 1992-1996
  7. // (C) 1997-1999 Microsoft Corp.
  8. /****************************************************************************/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. #define TRC_FILE "acpcapi"
  12. #include <as_conf.hpp>
  13. /****************************************************************************/
  14. /* API FUNCTION: CPC_Init */
  15. /* */
  16. /* Initializes the Capabilities Coordinator. */
  17. /****************************************************************************/
  18. void RDPCALL SHCLASS CPC_Init(void)
  19. {
  20. DC_BEGIN_FN("CPC_Init");
  21. /************************************************************************/
  22. /* This initializes all the global data for this component */
  23. /************************************************************************/
  24. #define DC_INIT_DATA
  25. #include <acpcdata.c>
  26. #undef DC_INIT_DATA
  27. // Set up pointer to presized memory buffer and set initial size value
  28. // since the presized buffer is uninitialized.
  29. cpcLocalCombinedCaps = (PTS_COMBINED_CAPABILITIES)cpcLocalCaps;
  30. cpcLocalCombinedCaps->numberCapabilities = 0;
  31. DC_END_FN();
  32. }
  33. /****************************************************************************/
  34. /* API FUNCTION: CPC_Term */
  35. /* */
  36. /* Terminates the Capabilities Coordinator. */
  37. /****************************************************************************/
  38. void RDPCALL SHCLASS CPC_Term(void)
  39. {
  40. unsigned i;
  41. DC_BEGIN_FN("CPC_Term");
  42. /************************************************************************/
  43. /* Free capabilities for each party */
  44. /************************************************************************/
  45. for (i = 0; i < SC_DEF_MAX_PARTIES; i++) {
  46. TRC_NRM((TB, "Free data for party %d", i));
  47. if (cpcRemoteCombinedCaps[i] != NULL)
  48. COM_Free(cpcRemoteCombinedCaps[i]);
  49. }
  50. DC_END_FN();
  51. }
  52. /****************************************************************************/
  53. /* API FUNCTION: CPC_RegisterCapabilities */
  54. /* */
  55. /* Called at initialisation time by each component that has capabilities */
  56. /* which need to be negotiated across the share. This is used to register */
  57. /* all capabilities. */
  58. /* */
  59. /* PARAMETERS: */
  60. /* pCapabilities - pointer to a structure containing the capabilities ID */
  61. /* and any number of capability fields. */
  62. /* The values used in these fields should be non-zero. A */
  63. /* zero in any capability field is used to indicate that */
  64. /* the capability is either unknown or undefined by the */
  65. /* remote. */
  66. /* */
  67. /* sizeOfCaps - the size of the total capabilities. The limit on the */
  68. /* total size of all secondary capabilities is 300 bytes, */
  69. /* but this is imposed locally and could be increased */
  70. /* without harming interoperability. */
  71. /****************************************************************************/
  72. void RDPCALL SHCLASS CPC_RegisterCapabilities(
  73. PTS_CAPABILITYHEADER pCapabilities,
  74. UINT16 sizeOfCaps)
  75. {
  76. unsigned i;
  77. PTS_CAPABILITYHEADER pNextCaps;
  78. DC_BEGIN_FN("CPC_RegisterCapabilities");
  79. TRC_NRM((TB, "Registering capabilities ID %hd, size %hd",
  80. pCapabilities->capabilitySetType, sizeOfCaps));
  81. #ifdef DC_DEBUG
  82. /************************************************************************/
  83. /* Check that CPC_GetCombinedCapabilities has not already been called. */
  84. /************************************************************************/
  85. if (cpcLocalCombinedCapsQueried)
  86. {
  87. TRC_ERR((TB, "CPC_GetCombinedCapabilities has already been called"));
  88. }
  89. #endif
  90. /************************************************************************/
  91. /* Register capabilities (if any) */
  92. /************************************************************************/
  93. if (sizeOfCaps != 0) {
  94. pCapabilities->lengthCapability = sizeOfCaps;
  95. // Search for the end of the capabilities structure.
  96. pNextCaps = (PTS_CAPABILITYHEADER)&(cpcLocalCombinedCaps->data[0]);
  97. for (i = 0; i < cpcLocalCombinedCaps->numberCapabilities; i++)
  98. pNextCaps = (PTS_CAPABILITYHEADER)((PBYTE)pNextCaps +
  99. pNextCaps->lengthCapability);
  100. // Check that we have enough room in our combined capabilities
  101. // structure to add the new capabilities.
  102. if (((PBYTE)pNextCaps - (PBYTE)cpcLocalCombinedCaps +
  103. pCapabilities->lengthCapability) <= CPC_MAX_LOCAL_CAPS_SIZE) {
  104. // Copy across the new capabilities into our combined capabilities
  105. // structure.
  106. memcpy(pNextCaps, pCapabilities, pCapabilities->lengthCapability);
  107. // Update the number of capabilities in our combined capabilities
  108. // structure.
  109. cpcLocalCombinedCaps->numberCapabilities++;
  110. TRC_DBG((TB, "Added %d bytes to capabilities for ID %d",
  111. pCapabilities->lengthCapability,
  112. pCapabilities->capabilitySetType));
  113. }
  114. else {
  115. // We do not have enough room to add the capabilities so return.
  116. // Any system communicating with us will think we do not support
  117. // these capabilities. The size of the capabilities structure
  118. // can be increased (it is not limited as part of the protocol).
  119. // The value of CPC_MAX_LOCAL_CAPS_SIZE should be increased.
  120. TRC_ERR((TB,"Out of combined capabilities space ID %d; size %d",
  121. pCapabilities->capabilitySetType,
  122. pCapabilities->lengthCapability));
  123. }
  124. }
  125. DC_END_FN();
  126. }
  127. /****************************************************************************/
  128. /* API FUNCTION: CPC_EnumerateCapabilities */
  129. /* */
  130. /* Enumerates the capabilities for each node in the share (not including */
  131. /* local). */
  132. /* */
  133. /* PARAMETERS: */
  134. /* capabilitiesID - the ID of the capabilities (group structure) to be */
  135. /* enumerated. */
  136. /* UserData - Private caller data to be passed to each call of the enum */
  137. /* func. */
  138. /* pCapsEnumerateFN - function to be called for each person in the share */
  139. /* with the persons capabilities structure. */
  140. /****************************************************************************/
  141. void RDPCALL SHCLASS CPC_EnumerateCapabilities(
  142. unsigned capabilitiesID,
  143. UINT_PTR UserData,
  144. PCAPSENUMERATEFN pCapsEnumerateFN)
  145. {
  146. LOCALPERSONID localID;
  147. unsigned i;
  148. BOOL foundCapabilities;
  149. PTS_CAPABILITYHEADER pCaps;
  150. TS_CAPABILITYHEADER emptyCaps;
  151. DC_BEGIN_FN("CPC_EnumerateCapabilities");
  152. /************************************************************************/
  153. /* Search for the capabilities ID within the remote party's section of */
  154. /* the combined capabilities structure. */
  155. /************************************************************************/
  156. for (localID = SC_DEF_MAX_PARTIES - 1; localID >= 1; localID--) {
  157. if (cpcRemoteCombinedCaps[localID-1] != NULL) {
  158. pCaps = (PTS_CAPABILITYHEADER)
  159. &(cpcRemoteCombinedCaps[localID-1]->data[0]);
  160. for (i = 0, foundCapabilities = FALSE;
  161. i < cpcRemoteCombinedCaps[localID-1]->numberCapabilities;
  162. i++) {
  163. if (pCaps->capabilitySetType == capabilitiesID) {
  164. /********************************************************/
  165. /* We have found the capabilities structure requested. */
  166. /* Make the call to the enumeration callback function. */
  167. /********************************************************/
  168. foundCapabilities = TRUE;
  169. (this->*pCapsEnumerateFN)(localID, UserData, pCaps);
  170. /********************************************************/
  171. /* Go onto the next person. */
  172. /********************************************************/
  173. break;
  174. }
  175. pCaps = (PTS_CAPABILITYHEADER)((PBYTE)pCaps +
  176. pCaps->lengthCapability);
  177. }
  178. if (!foundCapabilities) {
  179. /************************************************************/
  180. /* We did not find the requested capability structure for */
  181. /* this party so we must return an empty one. */
  182. /************************************************************/
  183. emptyCaps.capabilitySetType = (UINT16)capabilitiesID;
  184. emptyCaps.lengthCapability = 0;
  185. /************************************************************/
  186. /* Call the enumeration function callback with the empty */
  187. /* capabilities for this personID. */
  188. /************************************************************/
  189. (this->*pCapsEnumerateFN)(localID, UserData, &emptyCaps);
  190. }
  191. }
  192. }
  193. DC_END_FN();
  194. }
  195. /****************************************************************************/
  196. /* API FUNCTION: CPC_GetCombinedCapabilities */
  197. /* */
  198. /* Called by the Share Controller (SC). Returns a pointers to structures */
  199. /* containing the combined capabilities of all the registered capabilities. */
  200. /* */
  201. /* Note that this relies on the initialisation order of the components. */
  202. /* The CPC must be initialized before any components with capabilities. */
  203. /* Any components with capabilities must register them at initialisation */
  204. /* time. The SC must be initialized after any components with */
  205. /* capabilities. */
  206. /* */
  207. /* PARAMETERS: */
  208. /* localID - local ID of the person we are interested in. */
  209. /* pSizeOfCaps - pointer to variable to be filled in with the size of the */
  210. /* combined capabilities structure returned as ppCaps. */
  211. /* */
  212. /* ppCaps - pointer to variable to be filled in with the pointer to the */
  213. /* combined capabilities structure containing capabilities passed to */
  214. /* CPC_RegisterCapabilities. */
  215. /****************************************************************************/
  216. void RDPCALL SHCLASS CPC_GetCombinedCapabilities(
  217. LOCALPERSONID localID,
  218. PUINT pSizeOfCaps,
  219. PTS_COMBINED_CAPABILITIES *ppCaps)
  220. {
  221. unsigned i;
  222. PTS_CAPABILITYHEADER pNextCaps;
  223. PTS_COMBINED_CAPABILITIES pCaps;
  224. unsigned numCaps;
  225. DC_BEGIN_FN("CPC_GetCombinedCapabilities");
  226. /************************************************************************/
  227. /* Try to find the requested capabilitiesID for this person. */
  228. /* */
  229. /* If the localID refers to the local system then search the combined */
  230. /* capabilities structure (ie all capabilities registered with */
  231. /* CPC_RegisterCapabilities). Otherwise search the structure we */
  232. /* received from the remote person. */
  233. /************************************************************************/
  234. if (localID == SC_LOCAL_PERSON_ID) {
  235. pCaps = cpcLocalCombinedCaps;
  236. numCaps = cpcLocalCombinedCaps->numberCapabilities;
  237. #ifdef DC_DEBUG
  238. /************************************************************************/
  239. /* Set our flag we use to check that CPC_Register is not called after */
  240. /* this function has been called. */
  241. /************************************************************************/
  242. cpcLocalCombinedCapsQueried = TRUE;
  243. #endif
  244. }
  245. else {
  246. if (cpcRemoteCombinedCaps[localID - 1] != NULL) {
  247. pCaps = cpcRemoteCombinedCaps[localID - 1];
  248. numCaps = cpcRemoteCombinedCaps[localID - 1]->numberCapabilities;
  249. }
  250. else {
  251. TRC_ERR((TB, "Capabilities pointer is NULL"));
  252. *pSizeOfCaps = 0;
  253. *ppCaps = NULL;
  254. DC_QUIT;
  255. }
  256. }
  257. /************************************************************************/
  258. /* Search for the end of the capabilities structure for the local */
  259. /* party. */
  260. /************************************************************************/
  261. TRC_DBG((TB, "Caps:"));
  262. pNextCaps = (PTS_CAPABILITYHEADER)&(pCaps->data[0]);
  263. for (i = 0; i < numCaps; i++) {
  264. TRC_DBG((TB, "caps size %hd", pNextCaps->lengthCapability));
  265. TRC_DBG((TB, "caps ID %hd", pNextCaps->capabilitySetType));
  266. pNextCaps = (PTS_CAPABILITYHEADER)( (PBYTE)pNextCaps
  267. + pNextCaps->lengthCapability );
  268. }
  269. *pSizeOfCaps = (unsigned)((PBYTE)pNextCaps - (PBYTE)pCaps);
  270. *ppCaps = pCaps;
  271. TRC_NRM((TB, "Total size %d", *pSizeOfCaps));
  272. DC_EXIT_POINT:
  273. DC_END_FN();
  274. }
  275. /****************************************************************************/
  276. /* CPC_SetCombinedCapabilities(..) */
  277. /* */
  278. /* Used by a shadow stack to initialize the combined capabilities to the */
  279. /* values negotiated so far by its predecessors. */
  280. /****************************************************************************/
  281. void RDPCALL SHCLASS CPC_SetCombinedCapabilities(
  282. UINT cbSizeOfCaps,
  283. PTS_COMBINED_CAPABILITIES pCaps)
  284. {
  285. unsigned i;
  286. PTS_CAPABILITYHEADER pNextCaps;
  287. DC_BEGIN_FN("CPC_SetCombinedCapabilities");
  288. /************************************************************************/
  289. /* Replace the existing capability set with the new values */
  290. /************************************************************************/
  291. cpcLocalCombinedCaps->numberCapabilities = 0;
  292. pNextCaps = (PTS_CAPABILITYHEADER)&(pCaps->data[0]);
  293. TRC_NRM((TB, "Caps:"));
  294. for (i = 0; i < pCaps->numberCapabilities; i++) {
  295. CPC_RegisterCapabilities(pNextCaps, pNextCaps->lengthCapability);
  296. pNextCaps = (PTS_CAPABILITYHEADER)( (PBYTE)pNextCaps
  297. + pNextCaps->lengthCapability );
  298. }
  299. TRC_ALT((TB, "Capability bytes accepted: %ld / %ld",
  300. (unsigned)((PBYTE)pNextCaps - (PBYTE)cpcLocalCombinedCaps),
  301. cbSizeOfCaps));
  302. DC_END_FN();
  303. }
  304. /****************************************************************************/
  305. /* API FUNCTION: CPC_PartyJoiningShare() */
  306. /* */
  307. /* Capabilities Coordinator function called when a new party is joining the */
  308. /* share. */
  309. /* */
  310. /* Note that the capabilities data <pCapsData> is still in wire format */
  311. /* (Intel byte order) when CPC_PartyJoiningShare is called. */
  312. /* */
  313. /* PARAMETERS: */
  314. /* */
  315. /* personID - local person ID of remote person joining the share. */
  316. /* */
  317. /* oldShareSize - the number of the parties which were in the share (ie */
  318. /* excludes the joining party). */
  319. /* */
  320. /* sizeOfCapsData - size of the data pointed to by pCapsData. */
  321. /* */
  322. /* pCapsData - pointer to capabilities (returned by the person's */
  323. /* CPC_GetCombinedCapabilities) data for NET_EV_PERSON_ADDs. For the other */
  324. /* events this is NULL. */
  325. /* */
  326. /* RETURNS: TRUE if the party can join the share. */
  327. /* FALSE if the party can NOT join the share. */
  328. /****************************************************************************/
  329. BOOL RDPCALL SHCLASS CPC_PartyJoiningShare(
  330. LOCALPERSONID personID,
  331. unsigned oldShareSize,
  332. unsigned sizeOfCapsData,
  333. PVOID pCapsData)
  334. {
  335. PTS_COMBINED_CAPABILITIES pCombinedCaps;
  336. PBYTE pCaps;
  337. PBYTE pSavedCaps;
  338. BOOL rc = TRUE;
  339. int i;
  340. UINT32 sizeOfCaps = FIELDOFFSET(TS_COMBINED_CAPABILITIES, data);
  341. UINT32 work;
  342. DC_BEGIN_FN("CPC_PartyJoiningShare");
  343. DC_IGNORE_PARAMETER(oldShareSize)
  344. /************************************************************************/
  345. /* Allow ourself to be added to the share, but do nothing else. */
  346. /************************************************************************/
  347. if (personID == SC_LOCAL_PERSON_ID) {
  348. TRC_DBG((TB, "Ignore adding self to share"));
  349. DC_QUIT;
  350. }
  351. /************************************************************************/
  352. /* Calculate actual space required to save capabilities */
  353. /************************************************************************/
  354. // First we check if actually can deref the numberCapabilities member.
  355. // We should have enough bytes till up to the data meber.
  356. if(sizeOfCapsData < FIELDOFFSET(TS_COMBINED_CAPABILITIES, data)){
  357. TRC_ERR((TB, "Buffer too small to fit a combined caps structure: %d", sizeOfCapsData));
  358. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_CapabilitySetTooSmall,
  359. (PBYTE)pCapsData, sizeOfCapsData);
  360. rc = FALSE;
  361. DC_QUIT;
  362. }
  363. pCombinedCaps = (PTS_COMBINED_CAPABILITIES)pCapsData;
  364. pCaps = (PBYTE)pCombinedCaps->data;
  365. for (i = 0; i < pCombinedCaps->numberCapabilities; i++) {
  366. // here we check if we still have left TS_CAPABILITYHEADER length worth of data
  367. // we can't just deref the length member without checking that we actually have
  368. // enough buffer for a TS_CAPABILITYHEADER
  369. if ((PBYTE)pCaps + sizeof(TS_CAPABILITYHEADER) >
  370. (PBYTE)pCapsData + sizeOfCapsData) {
  371. TRC_ERR((TB, "Not enough space left for a capability header: %d",
  372. sizeOfCapsData-(pCaps-(PBYTE)pCapsData) ));
  373. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_CapabilitySetTooSmall,
  374. (PBYTE)pCapsData, sizeOfCapsData);
  375. rc = FALSE;
  376. DC_QUIT;
  377. }
  378. work = (UINT32)(((PTS_CAPABILITYHEADER)pCaps)->lengthCapability);
  379. /********************************************************************/
  380. /* Reject capability sets whose length is too small to contain any */
  381. /* data */
  382. /********************************************************************/
  383. if (work <= sizeof(TS_CAPABILITYHEADER)) {
  384. TRC_ERR((TB, "Capability set too small: %d", work));
  385. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_CapabilitySetTooSmall,
  386. (PBYTE)pCapsData, sizeOfCapsData);
  387. rc = FALSE;
  388. DC_QUIT;
  389. }
  390. /********************************************************************/
  391. /* Reject capability sets whose length would overrun the end of the */
  392. /* packet. */
  393. /********************************************************************/
  394. if ((pCaps+work> (PBYTE)pCapsData + sizeOfCapsData) ||
  395. (pCaps+work < (PBYTE)pCaps)) {
  396. TRC_ERR((TB, "Capability set too large: %d", work));
  397. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_CapabilitySetTooLarge,
  398. (PBYTE)pCapsData, sizeOfCapsData);
  399. rc = FALSE;
  400. DC_QUIT;
  401. }
  402. pCaps += work;
  403. work = (UINT32)DC_ROUND_UP_4(work);
  404. sizeOfCaps += work;
  405. }
  406. TRC_NRM((TB, "Caps size: passed %d, actual %d", sizeOfCapsData,
  407. sizeOfCaps));
  408. /************************************************************************/
  409. /* Allocate the space for this person's capabilities. */
  410. /************************************************************************/
  411. cpcRemoteCombinedCaps[personID - 1] =
  412. (PTS_COMBINED_CAPABILITIES)COM_Malloc(sizeOfCaps);
  413. if (cpcRemoteCombinedCaps[personID - 1] == NULL) {
  414. /********************************************************************/
  415. /* This party cannot join the share. */
  416. /********************************************************************/
  417. TRC_NRM((TB, "Failed to get %d bytes for personID %d caps",
  418. sizeOfCapsData,
  419. personID));
  420. rc = FALSE;
  421. DC_QUIT;
  422. }
  423. TRC_DBG((TB, "Allocated %d bytes for personID %d caps",
  424. sizeOfCapsData,
  425. personID));
  426. /************************************************************************/
  427. /* Initialize the memory to zero. Otherwise we can get little gaps of */
  428. /* garbage - which can be interpreted as valid capabilities - when */
  429. /* copying non-end-padded capability entries from the remote party's */
  430. /* data. */
  431. /************************************************************************/
  432. memset(cpcRemoteCombinedCaps[personID-1], 0, sizeOfCaps);
  433. /************************************************************************/
  434. /* Copy the combined capabilities data. */
  435. /************************************************************************/
  436. /************************************************************************/
  437. /* Copy the combined capabilities header */
  438. /************************************************************************/
  439. memcpy( cpcRemoteCombinedCaps[personID-1],
  440. pCapsData, FIELDOFFSET(TS_COMBINED_CAPABILITIES, data));
  441. /************************************************************************/
  442. /* Loop through capabilities, copying them to 4-byte aligned positions */
  443. /************************************************************************/
  444. pSavedCaps = (PBYTE)(cpcRemoteCombinedCaps[personID-1]->data);
  445. pCaps = (PBYTE)((PBYTE)pCapsData +
  446. FIELDOFFSET(TS_COMBINED_CAPABILITIES, data));
  447. for (i = 0; i < pCombinedCaps->numberCapabilities; i++) {
  448. work = (UINT32)(((PTS_CAPABILITYHEADER)pCaps)->lengthCapability);
  449. memcpy( pSavedCaps, pCaps, work);
  450. pCaps += work;
  451. work = (UINT32)DC_ROUND_UP_4(work);
  452. ((PTS_CAPABILITYHEADER)pSavedCaps)->lengthCapability = (UINT16)work;
  453. pSavedCaps += work;
  454. }
  455. DC_EXIT_POINT:
  456. DC_END_FN();
  457. return rc;
  458. }
  459. /****************************************************************************/
  460. /* API FUNCTION: CPC_PartyLeftShare() */
  461. /* */
  462. /* Capabilities Coordinator function called when a party has left the */
  463. /* share. */
  464. /* */
  465. /* PARAMETERS: */
  466. /* personID - local person ID of remote person leaving the share. */
  467. /* */
  468. /* newShareSize - the number of the parties now in the share (ie excludes */
  469. /* the leaving party). */
  470. /****************************************************************************/
  471. void RDPCALL SHCLASS CPC_PartyLeftShare(LOCALPERSONID locPersonID,
  472. unsigned newShareSize)
  473. {
  474. DC_BEGIN_FN("CPC_PartyLeftShare");
  475. DC_IGNORE_PARAMETER(newShareSize)
  476. /************************************************************************/
  477. /* If this is ourself leaving the share do nothing. */
  478. /************************************************************************/
  479. if (locPersonID != SC_LOCAL_PERSON_ID) {
  480. // Free this party's capabilities from the array and mark the entry
  481. // as invalid.
  482. if (cpcRemoteCombinedCaps[locPersonID - 1] != NULL) {
  483. COM_Free((PVOID)cpcRemoteCombinedCaps[locPersonID-1]);
  484. cpcRemoteCombinedCaps[locPersonID - 1] = NULL;
  485. }
  486. }
  487. DC_END_FN();
  488. }
  489. /****************************************************************************/
  490. /* FUNCTION: CPCGetCapabilities */
  491. /* */
  492. /* Returns the capabilities for one person. */
  493. /* */
  494. /* PARAMETERS: */
  495. /* localID - local ID of person (0 == local person) */
  496. /* capabilitiesID - the ID of the capabilities (group structure) to be */
  497. /* queried. */
  498. /* */
  499. /* RETURNS: */
  500. /* Pointer to a structure containing the capabilities ID, the size of the */
  501. /* capabilities, and any number of capability fields. */
  502. /* */
  503. /* If the person has no capabilities with capabilitiesID, a NULL pointer is */
  504. /* returned. */
  505. /****************************************************************************/
  506. PTS_CAPABILITYHEADER RDPCALL SHCLASS CPCGetCapabilities(
  507. LOCALPERSONID localID,
  508. unsigned capabilitiesID)
  509. {
  510. unsigned i;
  511. unsigned numCaps;
  512. PTS_CAPABILITYHEADER pCaps;
  513. PTS_CAPABILITYHEADER rc = NULL;
  514. DC_BEGIN_FN("CPCGetCapabilities");
  515. /************************************************************************/
  516. /* Try to find the requested capabilitiesID for this person. */
  517. /* */
  518. /* If the localID refers to the local system then search the combined */
  519. /* capabilities structure (ie all capabilities registered with */
  520. /* CPC_RegisterCapabilities). Otherwise search the structure we */
  521. /* received from the remote person. */
  522. /************************************************************************/
  523. if (localID == 0) {
  524. pCaps = (PTS_CAPABILITYHEADER)&(cpcLocalCombinedCaps->data[0]);
  525. numCaps = cpcLocalCombinedCaps->numberCapabilities;
  526. }
  527. else {
  528. if (cpcRemoteCombinedCaps[localID-1] == NULL)
  529. {
  530. TRC_ERR((TB, "Capabilities pointer is NULL"));
  531. DC_QUIT;
  532. }
  533. pCaps = (PTS_CAPABILITYHEADER)
  534. &(cpcRemoteCombinedCaps[localID-1]->data[0]);
  535. numCaps = cpcRemoteCombinedCaps[localID-1]->numberCapabilities;
  536. }
  537. for (i = 0; i < numCaps; i++) {
  538. if (pCaps->capabilitySetType == capabilitiesID) {
  539. /****************************************************************/
  540. /* We have found the capabilities structure requested. Return */
  541. /* the address of the capabilities. */
  542. /****************************************************************/
  543. TRC_DBG((TB, "Found %d bytes of caps ID %d localID %d",
  544. pCaps->lengthCapability,
  545. capabilitiesID,
  546. localID));
  547. rc = pCaps;
  548. break;
  549. }
  550. pCaps = (PTS_CAPABILITYHEADER)( (PBYTE)pCaps +
  551. pCaps->lengthCapability );
  552. }
  553. if (rc == NULL) {
  554. TRC_NRM((TB, " local ID = %u : No caps found for ID %d",
  555. (unsigned)localID,
  556. capabilitiesID));
  557. }
  558. DC_EXIT_POINT:
  559. DC_END_FN();
  560. return rc;
  561. }