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.

746 lines
22 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998 - 1998.
  5. //
  6. // File: rightsca.cxx
  7. //
  8. // Contents: Implementation of the DS access control rights cache
  9. //
  10. // History: 20-Feb-98 MacM Created
  11. //
  12. //--------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #include <stdio.h>
  16. #include <alsup.hxx>
  17. //
  18. // Global name/id cache
  19. //
  20. PACTRL_RIGHTS_CACHE grgRightsNameCache[ACTRL_OBJ_ID_TABLE_SIZE];
  21. //
  22. // Last connection info/time we read from the schema
  23. //
  24. static ACTRL_ID_SCHEMA_INFO LastSchemaRead;
  25. static RTL_RESOURCE RightsCacheLock;
  26. BOOL bRightsCacheLockInitialized = FALSE;
  27. #define ACTRL_EXT_RIGHTS_CONTAINER L"CN=Extended-Rights,"
  28. //+----------------------------------------------------------------------------
  29. //
  30. // Function: AccctrlInitializeRightsCache
  31. //
  32. // Synopsis: Initialize the access control rights lookup cache
  33. //
  34. // Arguments: VOID
  35. //
  36. // Returns: ERROR_SUCCESS -- Success
  37. //
  38. //-----------------------------------------------------------------------------
  39. DWORD AccctrlInitializeRightsCache(VOID)
  40. {
  41. DWORD dwErr;
  42. if (TRUE == bRightsCacheLockInitialized)
  43. {
  44. //
  45. // Just a precautionary measure to make sure that we do not initialize
  46. // multiple times.
  47. //
  48. ASSERT(FALSE);
  49. return ERROR_SUCCESS;
  50. }
  51. memset(grgRightsNameCache, 0,
  52. sizeof(PACTRL_RIGHTS_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
  53. memset(&LastSchemaRead, 0, sizeof(ACTRL_ID_SCHEMA_INFO));
  54. __try
  55. {
  56. RtlInitializeResource(&RightsCacheLock);
  57. dwErr = ERROR_SUCCESS;
  58. bRightsCacheLockInitialized = TRUE;
  59. }
  60. __except (EXCEPTION_EXECUTE_HANDLER)
  61. {
  62. dwErr = RtlNtStatusToDosError(GetExceptionCode());
  63. }
  64. return dwErr;
  65. }
  66. //+----------------------------------------------------------------------------
  67. //
  68. // Function: AccctrlFreeRightsCache
  69. //
  70. // Synopsis: Frees any memory allocated for the id name/guid cache
  71. //
  72. // Arguments: VOID
  73. //
  74. // Returns: VOID
  75. //
  76. //-----------------------------------------------------------------------------
  77. VOID AccctrlFreeRightsCache(VOID)
  78. {
  79. INT i,j;
  80. PACTRL_RIGHTS_CACHE pNode, pNext;
  81. if (FALSE == bRightsCacheLockInitialized)
  82. {
  83. return;
  84. }
  85. for(i = 0; i < ACTRL_OBJ_ID_TABLE_SIZE; i++)
  86. {
  87. pNode = grgRightsNameCache[i];
  88. while(pNode != NULL)
  89. {
  90. pNext = pNode->pNext;
  91. for (j = 0; j < (INT)pNode->cRights; j++)
  92. {
  93. AccFree(pNode->RightsList[j]);
  94. }
  95. AccFree(pNode->RightsList);
  96. AccFree(pNode);
  97. pNode = pNext;
  98. }
  99. }
  100. AccFree(LastSchemaRead.pwszPath);
  101. RtlDeleteResource(&RightsCacheLock);
  102. bRightsCacheLockInitialized = FALSE;
  103. }
  104. //+----------------------------------------------------------------------------
  105. //
  106. // Function: AccctrlFindRightsNode
  107. //
  108. // Synopsis: Looks up the node for the given class GUID
  109. //
  110. // Arguments: [ClassGuid] -- Class guid to look up
  111. //
  112. // Returns: NULL -- Node not found
  113. // else a valid node pointer
  114. //
  115. //-----------------------------------------------------------------------------
  116. PACTRL_RIGHTS_CACHE
  117. AccctrlpLookupClassGuidInCache(IN PGUID ClassGuid)
  118. {
  119. PACTRL_RIGHTS_CACHE pNode = NULL;
  120. pNode = grgRightsNameCache[ActrlHashGuid(ClassGuid)];
  121. while(pNode != NULL)
  122. {
  123. if(memcmp(ClassGuid, &pNode->ObjectClassGuid,sizeof(GUID)) == 0)
  124. {
  125. break;
  126. }
  127. pNode = pNode->pNext;
  128. }
  129. #if DBG
  130. if(pNode != NULL )
  131. {
  132. CHAR szGuid[38];
  133. PGUID pGuid = &pNode->ObjectClassGuid;
  134. sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  135. pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
  136. pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
  137. pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
  138. pGuid->Data4[7]);
  139. acDebugOut((DEB_TRACE_LOOKUP,
  140. "Found guid %s\n",
  141. szGuid));
  142. }
  143. #endif
  144. return(pNode);
  145. }
  146. //+----------------------------------------------------------------------------
  147. //
  148. // Function: AccctrlpInsertRightsNode
  149. //
  150. // Synopsis: Updates the information for an existing node or creates and
  151. // inserts a new one
  152. //
  153. // Arguments: [AppliesTo] -- Guid this control right applies to
  154. // [RightsGuid] -- Control right
  155. //
  156. // Returns: ERROR_SUCCESS -- Success
  157. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  158. //
  159. //-----------------------------------------------------------------------------
  160. DWORD AccctrlpInsertRightsNode(IN PGUID AppliesTo,
  161. IN PWSTR ControlRight)
  162. {
  163. DWORD dwErr = ERROR_SUCCESS;
  164. PACTRL_RIGHTS_CACHE Node, pNext, pTrail = NULL;
  165. PWSTR *NewList;
  166. BOOL NewNode = FALSE;
  167. //
  168. // First, find the existing node, if it exists
  169. //
  170. Node = AccctrlpLookupClassGuidInCache( AppliesTo );
  171. if(Node == NULL)
  172. {
  173. //
  174. // Have to create and insert a new one
  175. //
  176. Node = (PACTRL_RIGHTS_CACHE)AccAlloc(sizeof(ACTRL_RIGHTS_CACHE));
  177. if(Node == NULL)
  178. {
  179. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  180. }
  181. else
  182. {
  183. NewNode = TRUE;
  184. memcpy(&Node->ObjectClassGuid, AppliesTo, sizeof(GUID));
  185. Node->cRights=0;
  186. pNext = grgRightsNameCache[ActrlHashGuid(AppliesTo)];
  187. while(pNext != NULL)
  188. {
  189. if(memcmp(AppliesTo, &(pNext->ObjectClassGuid), sizeof(GUID)) == 0)
  190. {
  191. dwErr = ERROR_ALREADY_EXISTS;
  192. acDebugOut((DEB_TRACE_LOOKUP, "Guid collision. Bailing\n"));
  193. break;
  194. }
  195. pTrail = pNext;
  196. pNext = pNext->pNext;
  197. }
  198. }
  199. if(dwErr == ERROR_SUCCESS)
  200. {
  201. if(pTrail == NULL)
  202. {
  203. grgRightsNameCache[ActrlHashGuid(AppliesTo)] = Node;
  204. }
  205. else {
  206. pTrail->pNext = Node;
  207. }
  208. }
  209. }
  210. //
  211. // Now, insert the new applies to list
  212. if(dwErr == ERROR_SUCCESS)
  213. {
  214. NewList = (PWSTR *)AccAlloc((Node->cRights + 1) * sizeof(PWSTR));
  215. if(NewList==NULL)
  216. {
  217. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  218. }
  219. else
  220. {
  221. memcpy(NewList, Node->RightsList, Node->cRights * sizeof( PWSTR ));
  222. NewList[Node->cRights] = (PWSTR)AccAlloc((wcslen(ControlRight) + 1) * sizeof(WCHAR));
  223. if(NewList[Node->cRights] == NULL)
  224. {
  225. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  226. AccFree(NewList);
  227. }
  228. else
  229. {
  230. wcscpy(NewList[Node->cRights], ControlRight);
  231. Node->cRights++;
  232. AccFree(Node->RightsList);
  233. Node->RightsList = NewList;
  234. }
  235. }
  236. }
  237. //
  238. // Clean up if necessary
  239. //
  240. if(dwErr != ERROR_SUCCESS && NewNode == TRUE)
  241. {
  242. AccFree(Node);
  243. }
  244. return(dwErr);
  245. }
  246. //+---------------------------------------------------------------------------
  247. //
  248. // Function: AccDsReadAndInsertExtendedRights
  249. //
  250. // Synopsis: Reads the full list of extended rights from the schema
  251. //
  252. // Arguments: [IN pLDAP] -- LDAP connection to use
  253. // [OUT pcItems] -- Where the count of items
  254. // is returned
  255. // [OUT RightsList] -- Where the list of rights
  256. // entries is returned.
  257. //
  258. // Notes:
  259. //
  260. // Returns: ERROR_SUCCESS -- Success
  261. //
  262. //----------------------------------------------------------------------------
  263. DWORD
  264. AccDsReadAndInsertExtendedRights(IN PLDAP pLDAP)
  265. {
  266. DWORD dwErr = ERROR_SUCCESS;
  267. PWSTR *ppwszValues = NULL, *ppwszApplies = NULL;
  268. PWSTR rgwszAttribs[3];
  269. PWSTR pwszERContainer = NULL;
  270. PDS_NAME_RESULTW pNameRes = NULL;
  271. LDAPMessage *pMessage, *pEntry;
  272. ULONG cEntries, i, j;
  273. PACTRL_RIGHTS_CACHE pCurrentEntry;
  274. GUID RightsGuid;
  275. //
  276. // Get the subschema path
  277. //
  278. if(dwErr == ERROR_SUCCESS)
  279. {
  280. rgwszAttribs[0] = L"configurationNamingContext";
  281. rgwszAttribs[1] = NULL;
  282. dwErr = ldap_search_s(pLDAP,
  283. NULL,
  284. LDAP_SCOPE_BASE,
  285. L"(objectClass=*)",
  286. rgwszAttribs,
  287. 0,
  288. &pMessage);
  289. if(dwErr == ERROR_SUCCESS)
  290. {
  291. pEntry = ldap_first_entry(pLDAP,
  292. pMessage);
  293. if(pEntry == NULL)
  294. {
  295. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  296. }
  297. else
  298. {
  299. //
  300. // Now, we'll have to get the values
  301. //
  302. ppwszValues = ldap_get_values(pLDAP,
  303. pEntry,
  304. rgwszAttribs[0]);
  305. ldap_msgfree(pMessage);
  306. if(ppwszValues == NULL)
  307. {
  308. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  309. }
  310. else
  311. {
  312. pwszERContainer = (PWSTR)AccAlloc((wcslen(ppwszValues[0]) * sizeof(WCHAR)) +
  313. sizeof(ACTRL_EXT_RIGHTS_CONTAINER));
  314. if(pwszERContainer == NULL)
  315. {
  316. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  317. }
  318. else
  319. {
  320. wcscpy(pwszERContainer,
  321. ACTRL_EXT_RIGHTS_CONTAINER);
  322. wcscat(pwszERContainer,
  323. ppwszValues[0]);
  324. rgwszAttribs[0] = L"rightsGuid";
  325. rgwszAttribs[1] = L"appliesTo";
  326. rgwszAttribs[2] = NULL;
  327. //
  328. // Read the control access rights
  329. //
  330. dwErr = ldap_search_s(pLDAP,
  331. pwszERContainer,
  332. LDAP_SCOPE_ONELEVEL,
  333. L"(objectClass=controlAccessRight)",
  334. rgwszAttribs,
  335. 0,
  336. &pMessage);
  337. dwErr = LdapMapErrorToWin32( dwErr );
  338. AccFree(pwszERContainer);
  339. }
  340. ldap_value_free(ppwszValues);
  341. //
  342. // Process the entries
  343. //
  344. if(dwErr == ERROR_SUCCESS)
  345. {
  346. pEntry = ldap_first_entry(pLDAP,
  347. pMessage);
  348. if(pEntry == NULL)
  349. {
  350. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  351. }
  352. else
  353. {
  354. cEntries = ldap_count_entries( pLDAP, pMessage );
  355. for(i = 0; i < cEntries && dwErr == ERROR_SUCCESS; i++) {
  356. ppwszValues = ldap_get_values(pLDAP,
  357. pEntry,
  358. rgwszAttribs[0]);
  359. if(ppwszValues == NULL)
  360. {
  361. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  362. }
  363. else
  364. {
  365. //
  366. // Then the list of applies to
  367. //
  368. ppwszApplies = ldap_get_values(pLDAP,
  369. pEntry,
  370. rgwszAttribs[1]);
  371. j = 0;
  372. while(ppwszApplies[j] != NULL && dwErr == ERROR_SUCCESS)
  373. {
  374. dwErr = UuidFromString(ppwszApplies[j],
  375. &RightsGuid);
  376. if(dwErr == ERROR_SUCCESS)
  377. {
  378. dwErr = AccctrlpInsertRightsNode( &RightsGuid,
  379. ppwszValues[0]);
  380. }
  381. j++;
  382. }
  383. ldap_value_free(ppwszApplies);
  384. ppwszApplies = NULL;
  385. ldap_value_free(ppwszValues);
  386. }
  387. pEntry = ldap_next_entry( pLDAP, pEntry );
  388. }
  389. }
  390. }
  391. ldap_msgfree(pMessage);
  392. }
  393. }
  394. }
  395. else
  396. {
  397. dwErr = LdapMapErrorToWin32( dwErr );
  398. }
  399. }
  400. return(dwErr) ;
  401. }
  402. //+----------------------------------------------------------------------------
  403. //
  404. // Function: AccctrlpLoadRightsCacheFromSchema
  405. //
  406. // Synopsis: Reads the control rights schema cache and adds the entries into the
  407. // cache
  408. //
  409. // Arguments: [pLDAP] -- LDAP connection to the server
  410. // [pwszPath] -- DS path to the object
  411. //
  412. // Returns: ERROR_SUCCESS -- Success
  413. //
  414. //-----------------------------------------------------------------------------
  415. DWORD AccctrlpLoadRightsCacheFromSchema(PLDAP pLDAP,
  416. PWSTR pwszDsPath)
  417. {
  418. DWORD dwErr = ERROR_SUCCESS;
  419. PLDAP pLocalLDAP = pLDAP;
  420. ULONG cValues[2];
  421. PWSTR *ppwszValues[2];
  422. acDebugOut((DEB_TRACE_LOOKUP, "Reloading rights cache from schema\n"));
  423. //
  424. // If we have no parameters, just return...
  425. //
  426. if(pLDAP == NULL && pwszDsPath == NULL)
  427. {
  428. return(ERROR_SUCCESS);
  429. }
  430. //
  431. // See if we need to read... If our data is over 5 minutes old or if our path referenced is
  432. // not the same as the last one...
  433. //
  434. #define FIVE_MINUTES 300000
  435. if((LastSchemaRead.LastReadTime != 0 &&
  436. (GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) &&
  437. DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) &&
  438. ((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) ||
  439. (pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP)))))
  440. {
  441. acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n"));
  442. return(ERROR_SUCCESS);
  443. }
  444. else
  445. {
  446. //
  447. // Need to reinitialize it...
  448. //
  449. if(pLDAP == NULL)
  450. {
  451. LastSchemaRead.fLDAP = FALSE;
  452. }
  453. else
  454. {
  455. LastSchemaRead.fLDAP = TRUE;
  456. memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP));
  457. }
  458. AccFree(LastSchemaRead.pwszPath);
  459. if(pwszDsPath != NULL)
  460. {
  461. ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr);
  462. }
  463. LastSchemaRead.LastReadTime = GetTickCount();
  464. }
  465. if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL)
  466. {
  467. PWSTR pwszServer = NULL, pwszObject = NULL;
  468. dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject );
  469. if(dwErr == ERROR_SUCCESS)
  470. {
  471. dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP);
  472. LocalFree(pwszServer);
  473. }
  474. }
  475. //
  476. // Now, get the info. First, extended rights, then the schema info
  477. //
  478. if(dwErr == ERROR_SUCCESS)
  479. {
  480. dwErr = AccDsReadAndInsertExtendedRights(pLocalLDAP);
  481. }
  482. //
  483. // See if we need to release our ldap connection
  484. //
  485. if(pLocalLDAP != pLDAP && pLocalLDAP != NULL)
  486. {
  487. UnBindFromDSObject(&pLocalLDAP);
  488. }
  489. return(dwErr);
  490. }
  491. //+----------------------------------------------------------------------------
  492. //
  493. // Function: AccctrlLookupRightByName
  494. //
  495. // Synopsis: Returns the list of control rights for a given object class
  496. //
  497. // Arguments: [pLDAP] -- LDAP connection to the server
  498. // [pwszPath] -- DS path to the object
  499. // [pwszName] -- Object class name
  500. // [pCount] -- Where the count if items is returned
  501. // [ppRightsList] -- List of control rights
  502. // [ppwszNameList] -- List of control rights names
  503. //
  504. // Returns: ERROR_SUCCESS -- Success
  505. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  506. // ERROR_NOT_FOUND -- No such ID exists
  507. //
  508. //-----------------------------------------------------------------------------
  509. DWORD
  510. AccctrlLookupRightsByName(IN PLDAP pLDAP,
  511. IN PWSTR pwszDsPath,
  512. IN PWSTR pwszName,
  513. OUT PULONG pCount,
  514. OUT PACTRL_CONTROL_INFOW *ControlInfo)
  515. {
  516. DWORD dwErr = ERROR_SUCCESS;
  517. GUID *ObjectClassGuid, RightsGuid;
  518. PACTRL_RIGHTS_CACHE Node;
  519. ULONG Size = 0, i;
  520. PWSTR GuidName, Current;
  521. if((pwszDsPath == NULL && pLDAP == NULL) || pwszName == NULL)
  522. {
  523. *pCount = 0;
  524. *ControlInfo = NULL;
  525. return(ERROR_SUCCESS);
  526. }
  527. RtlAcquireResourceShared(&RightsCacheLock, TRUE);
  528. //
  529. // This is a multi-staged process. First, we have to lookup the guid associated
  530. // with the object class name. Then, we get the list of control rights for it
  531. //
  532. dwErr = AccctrlLookupGuid(pLDAP,
  533. pwszDsPath,
  534. pwszName,
  535. FALSE, // Don't allocate
  536. &ObjectClassGuid);
  537. if(dwErr == ERROR_SUCCESS)
  538. {
  539. Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
  540. if(Node == NULL)
  541. {
  542. RtlConvertSharedToExclusive( &RightsCacheLock );
  543. dwErr = AccctrlpLoadRightsCacheFromSchema(pLDAP, pwszDsPath );
  544. if(dwErr == ERROR_SUCCESS)
  545. {
  546. Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
  547. if(Node == NULL)
  548. {
  549. dwErr = ERROR_NOT_FOUND;
  550. }
  551. }
  552. }
  553. if(Node != NULL)
  554. {
  555. //
  556. // Size all of the return strings
  557. //
  558. for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
  559. dwErr = UuidFromString( Node->RightsList[i],&RightsGuid);
  560. if(dwErr == ERROR_SUCCESS)
  561. {
  562. dwErr = AccctrlLookupIdName(pLDAP,
  563. pwszDsPath,
  564. &RightsGuid,
  565. FALSE,
  566. FALSE,
  567. &GuidName);
  568. if(dwErr == ERROR_SUCCESS)
  569. {
  570. Size += wcslen( GuidName ) + 1;
  571. Size += wcslen( Node->RightsList[i] ) + 1;
  572. }
  573. }
  574. }
  575. //
  576. // Now, allocate the return information
  577. //
  578. if(dwErr == ERROR_SUCCESS)
  579. {
  580. *ControlInfo = (PACTRL_CONTROL_INFOW)AccAlloc((Size * sizeof(WCHAR)) +
  581. (Node->cRights * sizeof(ACTRL_CONTROL_INFOW)));
  582. if(*ControlInfo == NULL)
  583. {
  584. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  585. }
  586. else
  587. {
  588. Current = (PWSTR)((*ControlInfo) + Node->cRights);
  589. for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
  590. UuidFromString( Node->RightsList[i],&RightsGuid);
  591. dwErr = AccctrlLookupIdName(pLDAP,
  592. pwszDsPath,
  593. &RightsGuid,
  594. FALSE,
  595. FALSE,
  596. &GuidName);
  597. if(dwErr == ERROR_SUCCESS)
  598. {
  599. (*ControlInfo)[i].lpControlId = Current;
  600. wcscpy(Current, Node->RightsList[i]);
  601. Current += wcslen(Node->RightsList[i]);
  602. *Current = L'\0';
  603. Current++;
  604. (*ControlInfo)[i].lpControlName = Current;
  605. wcscpy(Current, GuidName);
  606. Current += wcslen(GuidName);
  607. *Current = L'\0';
  608. Current++;
  609. }
  610. }
  611. if(dwErr != ERROR_SUCCESS)
  612. {
  613. AccFree(*ControlInfo);
  614. }
  615. else
  616. {
  617. *pCount = Node->cRights;
  618. }
  619. }
  620. }
  621. }
  622. }
  623. RtlReleaseResource(&RightsCacheLock);
  624. return(dwErr);
  625. }