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.

1260 lines
36 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 1997.
  5. //
  6. // File: idcache.cxx
  7. //
  8. // Contents: Implementation of the DS guid/name lookup cache
  9. //
  10. // History: 20-Feb-97 MacM Created
  11. //
  12. //--------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #include <stdio.h>
  16. #include <alsup.hxx>
  17. //
  18. // This list contains pointers to memory allocated when a node is converted
  19. // to/from a guid via Rpc apis. It gets freed during cleanup.
  20. //
  21. typedef struct _ACTRL_ID_MEM
  22. {
  23. PVOID pv;
  24. BOOL fRpc;
  25. struct _ACTRL_ID_MEM *pNext;
  26. } ACTRL_ID_MEM, *PACTRL_ID_MEM;
  27. //
  28. // Global name/id cache
  29. //
  30. PACTRL_OBJ_ID_CACHE grgIdNameCache[ACTRL_OBJ_ID_TABLE_SIZE];
  31. PACTRL_OBJ_ID_CACHE grgIdGuidCache[ACTRL_OBJ_ID_TABLE_SIZE];
  32. //
  33. // Mem list head pointer
  34. //
  35. PACTRL_ID_MEM gpMemCleanupList;
  36. //
  37. // Last connection info/time we read from the schema
  38. //
  39. static ACTRL_ID_SCHEMA_INFO LastSchemaRead;
  40. //
  41. // Defines for attribute strings
  42. //
  43. #define ACTRL_OBJ_NAME L"NAME '"
  44. #define ACTRL_OBJ_GUID L"PROPERTY-GUID '"
  45. #define ACTRL_OBJ_CLASS L"CLASS-GUID '"
  46. #define ACTRL_OBJ_NAME_LEN sizeof(ACTRL_OBJ_NAME) / sizeof(WCHAR) - 1
  47. #define ACTRL_OBJ_GUID_LEN sizeof(ACTRL_OBJ_GUID) / sizeof(WCHAR) - 1
  48. #define ACTRL_OBJ_CLASS_LEN sizeof(ACTRL_OBJ_CLASS) / sizeof(WCHAR) - 1
  49. //
  50. // Local function prototypes
  51. //
  52. PACTRL_NAME_CACHE AccctrlpLookupIdNameInCache(PWSTR pwszName);
  53. PACTRL_NAME_CACHE AccctrlpLookupGuidInCache(PSID pSid);
  54. DWORD AccctrlpNewNameGuidNode(PWSTR pwszName,
  55. PGUID pGuid,
  56. PACTRL_OBJ_ID_CACHE *ppNewNode);
  57. BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  58. PACTRL_OBJ_ID_CACHE pNewNode);
  59. BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  60. PACTRL_OBJ_ID_CACHE pNewNode);
  61. VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  62. PACTRL_OBJ_ID_CACHE pNewNode);
  63. VOID AccctrlpFreeUserCacheName(PWSTR pwszName,
  64. PWSTR pwszCacheName);
  65. DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP,
  66. PWSTR pwszDsPath);
  67. static RTL_RESOURCE gIdCacheLock;
  68. BOOL bIdCacheLockInitialized = FALSE;
  69. //+----------------------------------------------------------------------------
  70. //
  71. // Function: ActrlHashIdName
  72. //
  73. // Synopsis: Determines the hash index for the given ldap display name
  74. //
  75. // Arguments: pwszName -- Name to hash
  76. //
  77. // Returns: Hash index of the string
  78. //
  79. //-----------------------------------------------------------------------------
  80. INT
  81. ActrlHashIdName(PWSTR pwszName)
  82. {
  83. INT Hash = 0;
  84. #if DBG
  85. PWSTR pwsz = pwszName;
  86. #endif
  87. if(pwszName != NULL)
  88. {
  89. while(*pwszName != L'\0')
  90. {
  91. Hash = (Hash * 16 + ( tolower(*pwszName++))) % ACTRL_OBJ_ID_TABLE_SIZE;
  92. }
  93. }
  94. #if DBG
  95. acDebugOut((DEB_TRACE_LOOKUP,"Hashing id name %ws to %lu\n",
  96. pwsz, Hash));
  97. #endif
  98. return(Hash);
  99. }
  100. //+----------------------------------------------------------------------------
  101. //
  102. // Function: ActrlHashGuid
  103. //
  104. // Synopsis: Determines the hash index for the given guid
  105. //
  106. // Arguments: pGuid -- Guid to hash
  107. //
  108. // Returns: Hash index of the Guid
  109. //
  110. //-----------------------------------------------------------------------------
  111. INT
  112. ActrlHashGuid(PGUID pGuid)
  113. {
  114. DWORD dwTotal = 0;
  115. //
  116. // Just deal with the sub authorities
  117. //
  118. for(INT i = 0; i < sizeof(GUID) / sizeof(DWORD); i++)
  119. {
  120. dwTotal += ((PULONG)pGuid)[i];
  121. }
  122. #if DBG
  123. CHAR szGuid[38];
  124. memset( szGuid,
  125. 0,
  126. sizeof(szGuid));
  127. sprintf(szGuid, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
  128. pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
  129. pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
  130. pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
  131. pGuid->Data4[7]);
  132. acDebugOut((DEB_TRACE_LOOKUP,
  133. "Hashing id %s (Total %lu) to %lu\n",
  134. szGuid, dwTotal, dwTotal % ACTRL_OBJ_ID_TABLE_SIZE));
  135. #endif
  136. return(dwTotal % ACTRL_OBJ_ID_TABLE_SIZE);
  137. }
  138. //+----------------------------------------------------------------------------
  139. //
  140. // Function: AccctrlInitializeIdNameCache
  141. //
  142. // Synopsis: Initialize the ID name/Guid lookup cache
  143. //
  144. // Arguments: VOID
  145. //
  146. // Returns: ERROR_SUCCESS -- Success
  147. //
  148. //-----------------------------------------------------------------------------
  149. DWORD AccctrlInitializeIdNameCache(VOID)
  150. {
  151. DWORD dwErr;
  152. if (TRUE == bIdCacheLockInitialized)
  153. {
  154. // Just a precautionary measure to make sure that we do not initialize
  155. // multiple times.
  156. //
  157. ASSERT(FALSE);
  158. return ERROR_SUCCESS;
  159. }
  160. memset(grgIdNameCache, 0,
  161. sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
  162. memset(grgIdGuidCache, 0,
  163. sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
  164. gpMemCleanupList = NULL;
  165. memset(&LastSchemaRead, 0, sizeof(ACTRL_ID_SCHEMA_INFO));
  166. __try
  167. {
  168. RtlInitializeResource(&gIdCacheLock);
  169. dwErr = ERROR_SUCCESS;
  170. bIdCacheLockInitialized = TRUE;
  171. }
  172. __except (EXCEPTION_EXECUTE_HANDLER)
  173. {
  174. dwErr = RtlNtStatusToDosError(GetExceptionCode());
  175. }
  176. return dwErr;
  177. }
  178. //+----------------------------------------------------------------------------
  179. //
  180. // Function: AccctrlFreeIdNameCache
  181. //
  182. // Synopsis: Frees any memory allocated for the id name/guid cache
  183. //
  184. // Arguments: VOID
  185. //
  186. // Returns: VOID
  187. //
  188. //-----------------------------------------------------------------------------
  189. VOID AccctrlFreeIdNameCache(VOID)
  190. {
  191. INT i;
  192. PACTRL_OBJ_ID_CACHE pNode, pNext;
  193. if (FALSE == bIdCacheLockInitialized)
  194. {
  195. return;
  196. }
  197. for(i = 0; i < ACTRL_OBJ_ID_TABLE_SIZE; i++)
  198. {
  199. //
  200. // Nodes are only inserted into the name cache, so that is the only
  201. // place we delete them from
  202. //
  203. pNode = grgIdNameCache[i];
  204. while(pNode != NULL)
  205. {
  206. pNext = pNode->pNextName;
  207. AccFree(pNode->pwszName);
  208. AccFree(pNode);
  209. pNode = pNext;
  210. }
  211. }
  212. PACTRL_ID_MEM pMem = gpMemCleanupList;
  213. while(pMem != NULL)
  214. {
  215. if(pMem->fRpc == TRUE)
  216. {
  217. PWSTR pwsz = (PWSTR)pMem->pv;
  218. RpcStringFree(&pwsz);
  219. }
  220. else
  221. {
  222. AccFree(pMem->pv);
  223. }
  224. pMem = pMem->pNext;
  225. }
  226. AccFree(LastSchemaRead.pwszPath);
  227. RtlDeleteResource(&gIdCacheLock);
  228. bIdCacheLockInitialized = FALSE;
  229. }
  230. //+----------------------------------------------------------------------------
  231. //
  232. // Function: AccctrlpLookupIdNameInCache
  233. //
  234. // Synopsis: Determines if the given name exists in the cache or not
  235. //
  236. // Arguments: [pwszName] -- Name to be looked up
  237. //
  238. // Returns: Matching node if found, NULL if not
  239. //
  240. //-----------------------------------------------------------------------------
  241. PACTRL_OBJ_ID_CACHE AccctrlpLookupNameInCache(PWSTR pwszName)
  242. {
  243. PACTRL_OBJ_ID_CACHE pNode = NULL;
  244. pNode = grgIdNameCache[ActrlHashIdName(pwszName)];
  245. while(pNode != NULL)
  246. {
  247. if(_wcsicmp(pwszName, pNode->pwszName) == 0)
  248. {
  249. break;
  250. }
  251. pNode = pNode->pNextName;
  252. }
  253. #if DBG
  254. if(pNode != NULL )
  255. {
  256. CHAR szGuid[38];
  257. PGUID pGuid = &pNode->Guid;
  258. sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  259. pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
  260. pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
  261. pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
  262. pGuid->Data4[7]);
  263. acDebugOut((DEB_TRACE_LOOKUP,
  264. "LookupName on %ws found %s\n",
  265. pwszName, szGuid));
  266. }
  267. #endif
  268. return(pNode);
  269. }
  270. //+----------------------------------------------------------------------------
  271. //
  272. // Function: AccctrlpLookupGuidInCache
  273. //
  274. // Synopsis: Determines if the given guid exists in the cache or not
  275. //
  276. // Arguments: [pGuid] -- Guid to be looked up
  277. //
  278. // Returns: Matching node if found, NULL if not
  279. //
  280. //-----------------------------------------------------------------------------
  281. PACTRL_OBJ_ID_CACHE AccctrlpLookupGuidInCache(PGUID pGuid)
  282. {
  283. PACTRL_OBJ_ID_CACHE pNode = grgIdGuidCache[ActrlHashGuid(pGuid)];
  284. while(pNode != NULL)
  285. {
  286. if(memcmp(pGuid, &(pNode->Guid), sizeof(GUID)) == 0)
  287. {
  288. break;
  289. }
  290. pNode = pNode->pNextGuid;
  291. }
  292. #if DBG
  293. if(pNode != NULL )
  294. {
  295. CHAR szGuid[37];
  296. sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  297. pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
  298. pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
  299. pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
  300. pGuid->Data4[7]);
  301. acDebugOut((DEB_TRACE_LOOKUP,
  302. "LookupGuid on %s found %ws\n",
  303. szGuid, pNode->pwszName));
  304. }
  305. #endif
  306. return(pNode);
  307. }
  308. //+----------------------------------------------------------------------------
  309. //
  310. // Function: AccctrlpNewNameGuidNode
  311. //
  312. // Synopsis: Allocates a new node and inserts them into the caches
  313. //
  314. // Arguments: [pwszName] -- Name to insert
  315. // [pGuid] -- Guid to insert
  316. // [pNewNode] -- Newly added node
  317. //
  318. // Returns: ERROR_SUCCESS -- Success
  319. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  320. // ERROR_INVALID_DATA A node was only inserted in one list
  321. //
  322. //-----------------------------------------------------------------------------
  323. DWORD AccctrlpNewNameGuidNode(PWSTR pwszName,
  324. PGUID pGuid,
  325. PACTRL_OBJ_ID_CACHE *ppNewNode)
  326. {
  327. DWORD dwErr = ERROR_SUCCESS;
  328. BOOL fNameRet = FALSE, fGuidRet = FALSE;
  329. PACTRL_OBJ_ID_CACHE pNewNode = (PACTRL_OBJ_ID_CACHE)AccAlloc(
  330. sizeof(ACTRL_OBJ_ID_CACHE));
  331. if(pNewNode == NULL)
  332. {
  333. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  334. }
  335. else
  336. {
  337. pNewNode->pwszName = pwszName;
  338. memcpy(&pNewNode->Guid, pGuid, sizeof(GUID));
  339. pNewNode->pNextName= NULL;
  340. pNewNode->pNextGuid= NULL;
  341. fNameRet = AccctrlpInsertIdNameNode(
  342. &(grgIdNameCache[ActrlHashIdName(pwszName)]),
  343. pNewNode);
  344. if ( fNameRet == TRUE ) {
  345. fGuidRet = AccctrlpInsertGuidNode(
  346. &(grgIdGuidCache[ActrlHashGuid(pGuid)]),
  347. pNewNode);
  348. }
  349. if(fNameRet == TRUE && fGuidRet == TRUE)
  350. {
  351. *ppNewNode = pNewNode;
  352. }
  353. else
  354. {
  355. dwErr = ERROR_INVALID_DATA;
  356. if( fNameRet == TRUE )
  357. {
  358. AccctrlpRemoveIdNameNode( &(grgIdNameCache[ActrlHashIdName(pwszName)]),
  359. pNewNode);
  360. }
  361. AccFree(pNewNode);
  362. *ppNewNode = NULL;
  363. }
  364. }
  365. return(dwErr);
  366. }
  367. //+----------------------------------------------------------------------------
  368. //
  369. // Function: AccctrlpInsertIdNameNode
  370. //
  371. // Synopsis: Inserts the specified new node into the caches
  372. //
  373. // Arguments: [ppRootNode] -- Root node in the name cache
  374. // [pNewNode] -- Node to insert
  375. //
  376. // Returns: VOID
  377. //
  378. //-----------------------------------------------------------------------------
  379. BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  380. PACTRL_OBJ_ID_CACHE pNewNode)
  381. {
  382. PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL;
  383. BOOL fReturn = TRUE;
  384. if(*ppRootNode == NULL)
  385. {
  386. *ppRootNode = pNewNode;
  387. }
  388. else
  389. {
  390. // acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n",
  391. // pNewNode->pwszName));
  392. pNext = *ppRootNode;
  393. // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
  394. while(pNext != NULL)
  395. {
  396. if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0)
  397. {
  398. //
  399. // If a node is already found, exit
  400. //
  401. fReturn = FALSE;
  402. acDebugOut((DEB_TRACE_LOOKUP, "Name %ws already exists. Bailing\n",
  403. pNewNode->pwszName));
  404. break;
  405. }
  406. pTrail = pNext;
  407. pNext = pNext->pNextName;
  408. // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
  409. }
  410. if(fReturn == TRUE)
  411. {
  412. if ( pTrail == NULL ) {
  413. (*ppRootNode)->pNextName = pNewNode;
  414. } else {
  415. pTrail->pNextName = pNewNode;
  416. }
  417. }
  418. }
  419. return(fReturn);
  420. }
  421. //+----------------------------------------------------------------------------
  422. //
  423. // Function: AccctrlpInsertGuidNode
  424. //
  425. // Synopsis: Inserts the specified new node into the caches
  426. //
  427. // Arguments: [ppRootNode] -- Root node in the name cache
  428. // [pNewNode] -- Node to insert
  429. //
  430. // Returns: VOID
  431. //
  432. //-----------------------------------------------------------------------------
  433. BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  434. PACTRL_OBJ_ID_CACHE pNewNode)
  435. {
  436. PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL;
  437. BOOL fReturn = TRUE;
  438. if(*ppRootNode == NULL)
  439. {
  440. *ppRootNode = pNewNode;
  441. }
  442. else
  443. {
  444. // acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n",
  445. // pNewNode->pwszName));
  446. pNext = *ppRootNode;
  447. // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
  448. while(pNext != NULL)
  449. {
  450. if(memcmp(&(pNewNode->Guid), &(pNext->Guid), sizeof(GUID)) == 0)
  451. {
  452. fReturn = FALSE;
  453. acDebugOut((DEB_TRACE_LOOKUP, "Guid for %ws already exists. Bailing\n",
  454. pNewNode->pwszName));
  455. break;
  456. }
  457. pTrail = pNext;
  458. pNext = pNext->pNextGuid;
  459. // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName));
  460. }
  461. if(fReturn == TRUE)
  462. {
  463. if ( pTrail == NULL ) {
  464. (*ppRootNode)->pNextGuid = pNewNode;
  465. } else {
  466. pTrail->pNextGuid = pNewNode;
  467. }
  468. }
  469. }
  470. return(fReturn);
  471. }
  472. //+----------------------------------------------------------------------------
  473. //
  474. // Function: AccctrlLookupIdName
  475. //
  476. // Synopsis: Looks up the name for the specified GUID.
  477. // Algorithm:
  478. // Search cache for ID
  479. // If not found, reload table from schema on DS referenced
  480. // by the DS path
  481. // Search the cache for the ID
  482. // If not found, return the string version of the ID
  483. //
  484. // Arguments: [pGuid] -- Guid to lookup
  485. // [fAllocateReturn]- If true, the name returned is allocated
  486. // into a new buffer. Otherwise, a
  487. // reference is returned.
  488. // [ppwszName] -- Where the name is returned.
  489. //
  490. // Returns: VOID
  491. //
  492. //-----------------------------------------------------------------------------
  493. DWORD
  494. AccctrlLookupIdName(IN PLDAP pLDAP,
  495. IN PWSTR pwszDsPath,
  496. IN PGUID pGuid,
  497. IN BOOL fAllocateReturn,
  498. IN BOOL fHandleObjectGuids,
  499. OUT PWSTR *ppwszName)
  500. {
  501. DWORD dwErr = ERROR_SUCCESS;
  502. PWSTR pwszStringId = NULL;
  503. RtlAcquireResourceShared(&gIdCacheLock, TRUE);
  504. #if DBG
  505. CHAR szGuid[38];
  506. sprintf(szGuid,
  507. "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  508. pGuid->Data1,pGuid->Data2,pGuid->Data3,
  509. pGuid->Data4[0],
  510. pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
  511. pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
  512. pGuid->Data4[7]);
  513. #endif
  514. //
  515. // First, see if the sid alreadt exists in our cache
  516. //
  517. PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupGuidInCache(pGuid);
  518. if(pNode == NULL)
  519. {
  520. acDebugOut((DEB_TRACE_LOOKUP, "Guid %s not found in cache\n", szGuid));
  521. //
  522. // Grab a write lock
  523. //
  524. RtlConvertSharedToExclusive(&gIdCacheLock);
  525. //
  526. // We'll have to look it up...
  527. //
  528. dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath);
  529. if(dwErr == ERROR_SUCCESS)
  530. {
  531. pNode = AccctrlpLookupGuidInCache(pGuid);
  532. //
  533. // If we've been asked to handle individual object guids,
  534. // see if this GUID is one.
  535. //
  536. if ( fHandleObjectGuids ) {
  537. PWSTR pwszUuid;
  538. DWORD dwUuidLen;
  539. PWSTR pwszDSObj;
  540. PDS_NAME_RESULTW pNameRes;
  541. //
  542. // Convert the GUID to a string.
  543. //
  544. dwErr = UuidToString(pGuid, &pwszUuid);
  545. if ( dwErr == ERROR_SUCCESS ) {
  546. //
  547. // Convert the string-ized GUID to an object name.
  548. //
  549. dwUuidLen = wcslen( pwszUuid );
  550. pwszDSObj = (PWSTR) AccAlloc( (dwUuidLen+3)*sizeof(WCHAR) );
  551. if ( pwszDSObj == NULL) {
  552. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  553. } else {
  554. PWSTR pwszServer = NULL, pwszObject = NULL;
  555. pwszDSObj[0] = L'{';
  556. memcpy( &pwszDSObj[1], pwszUuid, dwUuidLen*sizeof(WCHAR) );
  557. pwszDSObj[dwUuidLen+1] = L'}';
  558. pwszDSObj[dwUuidLen+2] = L'\0';
  559. //
  560. // Crack the name into canonical form
  561. //
  562. dwErr = DspSplitPath( pwszDSObj, &pwszServer, &pwszObject );
  563. if(dwErr == ERROR_SUCCESS)
  564. {
  565. dwErr = DspBindAndCrackEx(
  566. pwszServer,
  567. pwszObject,
  568. 0,
  569. DS_CANONICAL_NAME,
  570. &pNameRes );
  571. if ( dwErr == ERROR_SUCCESS ) {
  572. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) {
  573. dwErr = ERROR_SUCCESS;
  574. } else {
  575. //
  576. // Cache our newly found name.
  577. //
  578. dwErr = AccctrlpNewNameGuidNode( pNameRes->rItems[0].pName,
  579. pGuid,
  580. &pNode);
  581. }
  582. // Clean up
  583. DsFreeNameResultW(pNameRes);
  584. } else {
  585. // Failure to find name isn't fatal
  586. dwErr = ERROR_SUCCESS;
  587. }
  588. AccFree(pwszServer);
  589. }
  590. // Clean up
  591. AccFree( pwszDSObj );
  592. }
  593. // Clean up
  594. RpcStringFree(&pwszUuid);
  595. }
  596. }
  597. //
  598. // If it wasn't found, return the string version of the ID
  599. //
  600. if( dwErr == ERROR_SUCCESS && pNode == NULL)
  601. {
  602. dwErr = UuidToString(pGuid, &pwszStringId);
  603. }
  604. }
  605. }
  606. else
  607. {
  608. acDebugOut((DEB_TRACE_LOOKUP, "Guid %s found in cache\n", szGuid));
  609. }
  610. //
  611. // Finally, return the information
  612. //
  613. if(dwErr == ERROR_SUCCESS)
  614. {
  615. PWSTR pwszName;
  616. if(pNode != NULL)
  617. {
  618. pwszName = pNode->pwszName;
  619. }
  620. else
  621. {
  622. pwszName = pwszStringId;
  623. }
  624. if(fAllocateReturn == TRUE)
  625. {
  626. ACC_ALLOC_AND_COPY_STRINGW(pwszName, *ppwszName, dwErr);
  627. }
  628. else
  629. {
  630. *ppwszName = pwszName;
  631. if(pwszStringId != NULL)
  632. {
  633. PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc(sizeof(ACTRL_ID_MEM));
  634. if(pMem == NULL)
  635. {
  636. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  637. RpcStringFree(&pwszStringId);
  638. }
  639. else
  640. {
  641. pMem->pv = pwszStringId;
  642. pMem->fRpc = TRUE;
  643. pMem->pNext = gpMemCleanupList;
  644. gpMemCleanupList = pMem;
  645. }
  646. }
  647. }
  648. }
  649. RtlReleaseResource(&gIdCacheLock);
  650. return(dwErr);
  651. }
  652. //+----------------------------------------------------------------------------
  653. //
  654. // Function: AccctrlLookupGuid
  655. //
  656. // Synopsis: Looks up the GUID for the specified name
  657. //
  658. // Arguments: [pwszName] -- Name to lookup
  659. // [fAllocateReturn]- If true, the name returned is allocated
  660. // into a new buffer. Otherwise, a
  661. // reference is returned.
  662. // [ppGuid] -- Where the guid is returned.
  663. //
  664. // Returns: VOID
  665. //
  666. //-----------------------------------------------------------------------------
  667. DWORD
  668. AccctrlLookupGuid(IN PLDAP pLDAP,
  669. IN PWSTR pwszDsPath,
  670. IN PWSTR pwszName,
  671. IN BOOL fAllocateReturn,
  672. OUT PGUID *ppGuid)
  673. {
  674. DWORD dwErr = ERROR_SUCCESS;
  675. GUID guid, *pguid = NULL;
  676. BOOL fConverted = FALSE;
  677. RtlAcquireResourceShared(&gIdCacheLock, TRUE);
  678. //
  679. // First, see if the sid already exists in our cache
  680. //
  681. PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupNameInCache(pwszName);
  682. if(pNode == NULL)
  683. {
  684. //
  685. // Grab a write lock
  686. //
  687. RtlConvertSharedToExclusive(&gIdCacheLock);
  688. acDebugOut((DEB_TRACE_LOOKUP,"Name %ws not found in cache\n",
  689. pwszName));
  690. //
  691. // We'll have to look it up...
  692. //
  693. dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath);
  694. if(dwErr == ERROR_SUCCESS)
  695. {
  696. pNode = AccctrlpLookupNameInCache(pwszName);
  697. //
  698. // If it wasn't found, return the ID from the string
  699. //
  700. if(pNode == NULL)
  701. {
  702. dwErr = UuidFromString(pwszName, &guid);
  703. fConverted = TRUE;
  704. pguid = &guid;
  705. }
  706. else
  707. {
  708. pguid = &pNode->Guid;
  709. }
  710. }
  711. }
  712. else
  713. {
  714. acDebugOut((DEB_TRACE_LOOKUP,"Name %ws found in cache\n", pwszName));
  715. pguid = &pNode->Guid;
  716. }
  717. //
  718. // Finally, return the information
  719. //
  720. if(dwErr == ERROR_SUCCESS)
  721. {
  722. if(fAllocateReturn == TRUE)
  723. {
  724. ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr);
  725. }
  726. else
  727. {
  728. if(fConverted == TRUE)
  729. {
  730. ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr);
  731. if(dwErr == ERROR_SUCCESS)
  732. {
  733. PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc(
  734. sizeof(ACTRL_ID_MEM));
  735. if(pMem == NULL)
  736. {
  737. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  738. AccFree(*ppGuid);
  739. }
  740. else
  741. {
  742. pMem->pv = *ppGuid;
  743. pMem->pNext = gpMemCleanupList;
  744. gpMemCleanupList = pMem;
  745. }
  746. }
  747. }
  748. else
  749. {
  750. *ppGuid = pguid;
  751. }
  752. }
  753. }
  754. RtlReleaseResource(&gIdCacheLock);
  755. return(dwErr);
  756. }
  757. #define WCHAR_TO_HEX_BYTE(wc) \
  758. (BYTE)((wc) >= L'0' && (wc) <= L'9' ? (wc) - L'0' : towlower( (wc) ) - L'a' + 10)
  759. #define WCHAR_TO_HI_HEX_BYTE(wc) (WCHAR_TO_HEX_BYTE(wc) << 4 )
  760. //+----------------------------------------------------------------------------
  761. //
  762. // Function: AccctrlpDsStrGuidToGuid
  763. //
  764. // Synopsis: Converts a read string guid into an actual guid
  765. //
  766. // Arguments: [pwszStrGuid] -- String version of the id
  767. // [pGuid] -- Where the build ID is returned
  768. //
  769. // Returns: ERROR_SUCCESS -- Success
  770. //
  771. //-----------------------------------------------------------------------------
  772. DWORD AccctrlpDsStrGuidToGuid(IN PWSTR pwszStrGuid,
  773. OUT PGUID pGuid)
  774. {
  775. DWORD dwErr = ERROR_SUCCESS;
  776. if(pwszStrGuid == NULL)
  777. {
  778. dwErr = ERROR_INVALID_PARAMETER;
  779. }
  780. else
  781. {
  782. #if 1
  783. //
  784. // The string guid we're given is not in a standard UuidToString form,
  785. // so we'll have to convert it
  786. //
  787. PBYTE pCurr = (PBYTE)pGuid;
  788. for(ULONG i = 0; i < sizeof(GUID); i++)
  789. {
  790. *pCurr = WCHAR_TO_HI_HEX_BYTE(*pwszStrGuid) | WCHAR_TO_HEX_BYTE(*(pwszStrGuid + 1));
  791. pCurr++;
  792. pwszStrGuid += 2;
  793. }
  794. #else
  795. //
  796. // Whack it into the right form...
  797. //
  798. WCHAR wszStrFormat[sizeof(GUID) * sizeof(WCHAR) + 7];
  799. ULONG Blocks[] = {8, 4, 4, 4, 12};
  800. PWSTR pwszStrFor = wszStrFormat;
  801. for(ULONG i = 0 ; i < sizeof(Blocks) / sizeof(ULONG) ; i++ )
  802. {
  803. for(ULONG j = 0; j < Blocks[i]; j++)
  804. {
  805. *pwszStrFor++ = *pwszStrGuid++;
  806. }
  807. *pwszStrFor++ = L'-';
  808. }
  809. pwszStrFor--;
  810. *pwszStrFor = UNICODE_NULL;
  811. dwErr = UuidFromString(wszStrFormat, pGuid);
  812. #endif
  813. }
  814. return(dwErr);
  815. }
  816. //+----------------------------------------------------------------------------
  817. //
  818. // Function: AccctrlpLoadCacheFromSchema
  819. //
  820. // Synopsis: Reads the schema cache and adds the entries into the
  821. // cache
  822. //
  823. // Arguments: [pLDAP] -- LDAP connection to the server
  824. // [pwszPath] -- DS path to the object
  825. //
  826. // Returns: ERROR_SUCCESS -- Success
  827. //
  828. //-----------------------------------------------------------------------------
  829. DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP,
  830. PWSTR pwszDsPath)
  831. {
  832. DWORD dwErr = ERROR_SUCCESS;
  833. PLDAP pLocalLDAP = pLDAP;
  834. ULONG cValues[2];
  835. PWSTR *ppwszValues[2];
  836. PWSTR rgwszGuidStrs[] = {ACTRL_OBJ_CLASS, ACTRL_OBJ_GUID};
  837. ULONG rgGuidStrLen[] = {ACTRL_OBJ_CLASS_LEN, ACTRL_OBJ_GUID_LEN};
  838. acDebugOut((DEB_TRACE_LOOKUP, "Reloading cache from schema\n"));
  839. //
  840. // If we have no parameters, just return...
  841. //
  842. if(pLDAP == NULL && pwszDsPath == NULL)
  843. {
  844. return(ERROR_SUCCESS);
  845. }
  846. //
  847. // See if we need to read... If our data is over 5 minutes old or if our path referenced is
  848. // not the same as the last one...
  849. //
  850. #define FIVE_MINUTES 300000
  851. if((LastSchemaRead.LastReadTime != 0 &&
  852. (GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) &&
  853. DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) &&
  854. ((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) ||
  855. (pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP)))))
  856. {
  857. acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n"));
  858. return(ERROR_SUCCESS);
  859. }
  860. else
  861. {
  862. //
  863. // Need to reinitialize it...
  864. //
  865. if(pLDAP == NULL)
  866. {
  867. LastSchemaRead.fLDAP = FALSE;
  868. }
  869. else
  870. {
  871. LastSchemaRead.fLDAP = TRUE;
  872. memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP));
  873. }
  874. AccFree(LastSchemaRead.pwszPath);
  875. if(pwszDsPath != NULL)
  876. {
  877. ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr);
  878. }
  879. LastSchemaRead.LastReadTime = GetTickCount();
  880. }
  881. if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL)
  882. {
  883. PWSTR pwszServer = NULL, pwszObject = NULL;
  884. dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject );
  885. if(dwErr == ERROR_SUCCESS)
  886. {
  887. dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP);
  888. LocalFree(pwszServer);
  889. }
  890. }
  891. //
  892. // Now, get the info. First, extended rights, then the schema info
  893. //
  894. if(dwErr == ERROR_SUCCESS)
  895. {
  896. dwErr = AccDsReadExtendedRights(pLocalLDAP,
  897. &(cValues[0]),
  898. &(ppwszValues[0]),
  899. &(ppwszValues[1]));
  900. if(dwErr == ERROR_SUCCESS )
  901. {
  902. for(ULONG j = 0; j < cValues[0] && dwErr == ERROR_SUCCESS; j++)
  903. {
  904. GUID guid;
  905. dwErr = UuidFromString(ppwszValues[1][j], &guid);
  906. if(dwErr == ERROR_SUCCESS)
  907. {
  908. PACTRL_OBJ_ID_CACHE pNewNode;
  909. PWSTR pwsz;
  910. ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0][j], pwsz, dwErr);
  911. if(dwErr == ERROR_SUCCESS )
  912. {
  913. dwErr = AccctrlpNewNameGuidNode(pwsz,
  914. &guid,
  915. &pNewNode);
  916. if(dwErr != ERROR_SUCCESS)
  917. {
  918. AccFree(pwsz);
  919. if ( dwErr == ERROR_INVALID_DATA ) {
  920. dwErr = ERROR_SUCCESS;
  921. }
  922. }
  923. }
  924. }
  925. }
  926. AccDsFreeExtendedRights(cValues[0],
  927. ppwszValues[0],
  928. ppwszValues[1]);
  929. }
  930. if(dwErr == ERROR_SUCCESS)
  931. {
  932. dwErr = AccDsReadSchemaInfo(pLocalLDAP,
  933. &(cValues[0]),
  934. &(ppwszValues[0]),
  935. &(cValues[1]),
  936. &(ppwszValues[1]));
  937. if(dwErr == ERROR_SUCCESS )
  938. {
  939. for(ULONG i = 0; i < 2 && dwErr == ERROR_SUCCESS; i++)
  940. {
  941. for(ULONG j = 0;
  942. j < cValues[i] && dwErr == ERROR_SUCCESS; j++)
  943. {
  944. PWSTR pwszVal = ppwszValues[i][j];
  945. GUID guid;
  946. PWSTR pwszName, pwszGuid, pwszTick;
  947. pwszName = wcswcs(pwszVal, ACTRL_OBJ_NAME) + ACTRL_OBJ_NAME_LEN;
  948. pwszGuid = wcswcs(pwszName, rgwszGuidStrs[i]) + rgGuidStrLen[i];
  949. pwszTick = wcswcs(pwszName, L"'");
  950. if(pwszTick != NULL)
  951. {
  952. *pwszTick = UNICODE_NULL;
  953. }
  954. dwErr = AccctrlpDsStrGuidToGuid(pwszGuid, &guid);
  955. if(dwErr == ERROR_SUCCESS)
  956. {
  957. PACTRL_OBJ_ID_CACHE pNewNode;
  958. PWSTR pwsz;
  959. ACC_ALLOC_AND_COPY_STRINGW(pwszName, pwsz, dwErr);
  960. if(dwErr == ERROR_SUCCESS )
  961. {
  962. dwErr = AccctrlpNewNameGuidNode(pwsz,
  963. &guid,
  964. &pNewNode);
  965. if(dwErr != ERROR_SUCCESS)
  966. {
  967. AccFree(pwsz);
  968. if ( dwErr == ERROR_INVALID_DATA ) {
  969. dwErr = ERROR_SUCCESS;
  970. }
  971. }
  972. }
  973. }
  974. pwszVal = pwszGuid;
  975. }
  976. }
  977. ldap_value_free(ppwszValues[0]);
  978. ldap_value_free(ppwszValues[1]);
  979. }
  980. }
  981. }
  982. //
  983. // See if we need to release our ldap connection
  984. //
  985. if(pLocalLDAP != pLDAP && pLocalLDAP != NULL)
  986. {
  987. UnBindFromDSObject(&pLocalLDAP);
  988. }
  989. return(dwErr);
  990. }
  991. //+----------------------------------------------------------------------------
  992. //
  993. // Function: AccctrlpRemoveIdNameNode
  994. //
  995. // Synopsis: Removes the specified new node into the caches
  996. //
  997. // Arguments: [ppRootNode] -- Root node in the name cache
  998. // [pNewNode] -- Node to remove
  999. //
  1000. // Returns: VOID
  1001. //
  1002. //-----------------------------------------------------------------------------
  1003. VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode,
  1004. PACTRL_OBJ_ID_CACHE pNewNode)
  1005. {
  1006. PACTRL_OBJ_ID_CACHE pNext = NULL, pPrev;
  1007. ASSERT( *ppRootNode != NULL );
  1008. if(_wcsicmp((*ppRootNode)->pwszName, pNewNode->pwszName) == 0)
  1009. {
  1010. *ppRootNode = NULL;
  1011. }
  1012. else
  1013. {
  1014. pNext = (*ppRootNode)->pNextName;
  1015. pPrev = *ppRootNode;
  1016. while(pNext != NULL)
  1017. {
  1018. if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0)
  1019. {
  1020. //
  1021. // Remove the node
  1022. //
  1023. pPrev->pNextName = pNext->pNextName;
  1024. acDebugOut((DEB_TRACE_LOOKUP, "Removed node for %ws\n",
  1025. pNext->pwszName));
  1026. break;
  1027. }
  1028. pPrev = pNext;
  1029. pNext = pNext->pNextName;
  1030. }
  1031. }
  1032. return;
  1033. }