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.

757 lines
23 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. ldap_msgfree(pMessage);
  296. pMessage = NULL;
  297. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  298. }
  299. else
  300. {
  301. //
  302. // Now, we'll have to get the values
  303. //
  304. ppwszValues = ldap_get_values(pLDAP,
  305. pEntry,
  306. rgwszAttribs[0]);
  307. ldap_msgfree(pMessage);
  308. pMessage = NULL;
  309. if(ppwszValues == NULL)
  310. {
  311. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  312. }
  313. else
  314. {
  315. pwszERContainer = (PWSTR)AccAlloc((wcslen(ppwszValues[0]) * sizeof(WCHAR)) +
  316. sizeof(ACTRL_EXT_RIGHTS_CONTAINER));
  317. if(pwszERContainer == NULL)
  318. {
  319. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  320. }
  321. else
  322. {
  323. wcscpy(pwszERContainer,
  324. ACTRL_EXT_RIGHTS_CONTAINER);
  325. wcscat(pwszERContainer,
  326. ppwszValues[0]);
  327. rgwszAttribs[0] = L"rightsGuid";
  328. rgwszAttribs[1] = L"appliesTo";
  329. rgwszAttribs[2] = NULL;
  330. //
  331. // Read the control access rights
  332. //
  333. dwErr = ldap_search_s(pLDAP,
  334. pwszERContainer,
  335. LDAP_SCOPE_ONELEVEL,
  336. L"(objectClass=controlAccessRight)",
  337. rgwszAttribs,
  338. 0,
  339. &pMessage);
  340. dwErr = LdapMapErrorToWin32( dwErr );
  341. AccFree(pwszERContainer);
  342. }
  343. ldap_value_free(ppwszValues);
  344. //
  345. // Process the entries
  346. //
  347. if(dwErr == ERROR_SUCCESS)
  348. {
  349. pEntry = ldap_first_entry(pLDAP,
  350. pMessage);
  351. if(pEntry == NULL)
  352. {
  353. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  354. }
  355. else
  356. {
  357. cEntries = ldap_count_entries( pLDAP, pMessage );
  358. for(i = 0; i < cEntries && dwErr == ERROR_SUCCESS; i++) {
  359. ppwszValues = ldap_get_values(pLDAP,
  360. pEntry,
  361. rgwszAttribs[0]);
  362. if(ppwszValues == NULL)
  363. {
  364. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  365. }
  366. else
  367. {
  368. //
  369. // Then the list of applies to
  370. //
  371. ppwszApplies = ldap_get_values(pLDAP,
  372. pEntry,
  373. rgwszAttribs[1]);
  374. j = 0;
  375. while(ppwszApplies[j] != NULL && dwErr == ERROR_SUCCESS)
  376. {
  377. dwErr = UuidFromString(ppwszApplies[j],
  378. &RightsGuid);
  379. if(dwErr == ERROR_SUCCESS)
  380. {
  381. dwErr = AccctrlpInsertRightsNode( &RightsGuid,
  382. ppwszValues[0]);
  383. }
  384. j++;
  385. }
  386. ldap_value_free(ppwszApplies);
  387. ppwszApplies = NULL;
  388. ldap_value_free(ppwszValues);
  389. }
  390. pEntry = ldap_next_entry( pLDAP, pEntry );
  391. }
  392. }
  393. }
  394. if (pMessage != NULL)
  395. {
  396. ldap_msgfree(pMessage);
  397. }
  398. }
  399. }
  400. }
  401. else
  402. {
  403. ldap_msgfree(pMessage);
  404. dwErr = LdapMapErrorToWin32( dwErr );
  405. }
  406. }
  407. return(dwErr) ;
  408. }
  409. //+----------------------------------------------------------------------------
  410. //
  411. // Function: AccctrlpLoadRightsCacheFromSchema
  412. //
  413. // Synopsis: Reads the control rights schema cache and adds the entries into the
  414. // cache
  415. //
  416. // Arguments: [pLDAP] -- LDAP connection to the server
  417. // [pwszPath] -- DS path to the object
  418. //
  419. // Returns: ERROR_SUCCESS -- Success
  420. //
  421. //-----------------------------------------------------------------------------
  422. DWORD AccctrlpLoadRightsCacheFromSchema(PLDAP pLDAP,
  423. PWSTR pwszDsPath)
  424. {
  425. DWORD dwErr = ERROR_SUCCESS;
  426. PLDAP pLocalLDAP = pLDAP;
  427. ULONG cValues[2];
  428. PWSTR *ppwszValues[2];
  429. acDebugOut((DEB_TRACE_LOOKUP, "Reloading rights cache from schema\n"));
  430. //
  431. // If we have no parameters, just return...
  432. //
  433. if(pLDAP == NULL && pwszDsPath == NULL)
  434. {
  435. return(ERROR_SUCCESS);
  436. }
  437. //
  438. // See if we need to read... If our data is over 5 minutes old or if our path referenced is
  439. // not the same as the last one...
  440. //
  441. #define FIVE_MINUTES 300000
  442. if((LastSchemaRead.LastReadTime != 0 &&
  443. (GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) &&
  444. DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) &&
  445. ((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) ||
  446. (pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP)))))
  447. {
  448. acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n"));
  449. return(ERROR_SUCCESS);
  450. }
  451. else
  452. {
  453. //
  454. // Need to reinitialize it...
  455. //
  456. if(pLDAP == NULL)
  457. {
  458. LastSchemaRead.fLDAP = FALSE;
  459. }
  460. else
  461. {
  462. LastSchemaRead.fLDAP = TRUE;
  463. memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP));
  464. }
  465. AccFree(LastSchemaRead.pwszPath);
  466. if(pwszDsPath != NULL)
  467. {
  468. ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr);
  469. }
  470. LastSchemaRead.LastReadTime = GetTickCount();
  471. }
  472. if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL)
  473. {
  474. PWSTR pwszServer = NULL, pwszObject = NULL;
  475. dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject );
  476. if(dwErr == ERROR_SUCCESS)
  477. {
  478. dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP);
  479. LocalFree(pwszServer);
  480. }
  481. }
  482. //
  483. // Now, get the info. First, extended rights, then the schema info
  484. //
  485. if(dwErr == ERROR_SUCCESS)
  486. {
  487. dwErr = AccDsReadAndInsertExtendedRights(pLocalLDAP);
  488. }
  489. //
  490. // See if we need to release our ldap connection
  491. //
  492. if(pLocalLDAP != pLDAP && pLocalLDAP != NULL)
  493. {
  494. UnBindFromDSObject(&pLocalLDAP);
  495. }
  496. return(dwErr);
  497. }
  498. //+----------------------------------------------------------------------------
  499. //
  500. // Function: AccctrlLookupRightByName
  501. //
  502. // Synopsis: Returns the list of control rights for a given object class
  503. //
  504. // Arguments: [pLDAP] -- LDAP connection to the server
  505. // [pwszPath] -- DS path to the object
  506. // [pwszName] -- Object class name
  507. // [pCount] -- Where the count if items is returned
  508. // [ppRightsList] -- List of control rights
  509. // [ppwszNameList] -- List of control rights names
  510. //
  511. // Returns: ERROR_SUCCESS -- Success
  512. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  513. // ERROR_NOT_FOUND -- No such ID exists
  514. //
  515. //-----------------------------------------------------------------------------
  516. DWORD
  517. AccctrlLookupRightsByName(IN PLDAP pLDAP,
  518. IN PWSTR pwszDsPath,
  519. IN PWSTR pwszName,
  520. OUT PULONG pCount,
  521. OUT PACTRL_CONTROL_INFOW *ControlInfo)
  522. {
  523. DWORD dwErr = ERROR_SUCCESS;
  524. GUID *ObjectClassGuid, RightsGuid;
  525. PACTRL_RIGHTS_CACHE Node;
  526. ULONG Size = 0, i;
  527. PWSTR GuidName, Current;
  528. if((pwszDsPath == NULL && pLDAP == NULL) || pwszName == NULL)
  529. {
  530. *pCount = 0;
  531. *ControlInfo = NULL;
  532. return(ERROR_SUCCESS);
  533. }
  534. RtlAcquireResourceShared(&RightsCacheLock, TRUE);
  535. //
  536. // This is a multi-staged process. First, we have to lookup the guid associated
  537. // with the object class name. Then, we get the list of control rights for it
  538. //
  539. dwErr = AccctrlLookupGuid(pLDAP,
  540. pwszDsPath,
  541. pwszName,
  542. FALSE, // Don't allocate
  543. &ObjectClassGuid);
  544. if(dwErr == ERROR_SUCCESS)
  545. {
  546. Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
  547. if(Node == NULL)
  548. {
  549. RtlConvertSharedToExclusive( &RightsCacheLock );
  550. dwErr = AccctrlpLoadRightsCacheFromSchema(pLDAP, pwszDsPath );
  551. if(dwErr == ERROR_SUCCESS)
  552. {
  553. Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
  554. if(Node == NULL)
  555. {
  556. dwErr = ERROR_NOT_FOUND;
  557. }
  558. }
  559. }
  560. if(Node != NULL)
  561. {
  562. //
  563. // Size all of the return strings
  564. //
  565. for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
  566. dwErr = UuidFromString( Node->RightsList[i],&RightsGuid);
  567. if(dwErr == ERROR_SUCCESS)
  568. {
  569. dwErr = AccctrlLookupIdName(pLDAP,
  570. pwszDsPath,
  571. &RightsGuid,
  572. FALSE,
  573. FALSE,
  574. &GuidName);
  575. if(dwErr == ERROR_SUCCESS)
  576. {
  577. Size += wcslen( GuidName ) + 1;
  578. Size += wcslen( Node->RightsList[i] ) + 1;
  579. }
  580. }
  581. }
  582. //
  583. // Now, allocate the return information
  584. //
  585. if(dwErr == ERROR_SUCCESS)
  586. {
  587. *ControlInfo = (PACTRL_CONTROL_INFOW)AccAlloc((Size * sizeof(WCHAR)) +
  588. (Node->cRights * sizeof(ACTRL_CONTROL_INFOW)));
  589. if(*ControlInfo == NULL)
  590. {
  591. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  592. }
  593. else
  594. {
  595. Current = (PWSTR)((*ControlInfo) + Node->cRights);
  596. for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
  597. dwErr = UuidFromString( Node->RightsList[i],&RightsGuid);
  598. if(dwErr == ERROR_SUCCESS)
  599. {
  600. dwErr = AccctrlLookupIdName(pLDAP,
  601. pwszDsPath,
  602. &RightsGuid,
  603. FALSE,
  604. FALSE,
  605. &GuidName);
  606. }
  607. if(dwErr == ERROR_SUCCESS)
  608. {
  609. (*ControlInfo)[i].lpControlId = Current;
  610. wcscpy(Current, Node->RightsList[i]);
  611. Current += wcslen(Node->RightsList[i]);
  612. *Current = L'\0';
  613. Current++;
  614. (*ControlInfo)[i].lpControlName = Current;
  615. wcscpy(Current, GuidName);
  616. Current += wcslen(GuidName);
  617. *Current = L'\0';
  618. Current++;
  619. }
  620. }
  621. if(dwErr != ERROR_SUCCESS)
  622. {
  623. AccFree(*ControlInfo);
  624. }
  625. else
  626. {
  627. *pCount = Node->cRights;
  628. }
  629. }
  630. }
  631. }
  632. }
  633. RtlReleaseResource(&RightsCacheLock);
  634. return(dwErr);
  635. }