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.

673 lines
16 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: bndcache.cxx
  8. //
  9. // Contents: Binding cache for Kerberos Package
  10. //
  11. //
  12. // History: 13-August-1996 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <lsapch.hxx>
  16. #define BNDCACHE_ALLOCATE
  17. #include <bndcache.h>
  18. //
  19. // REVIEW: (markpu: 02/02/19)
  20. //
  21. // - consider using a more efficient data store than a linked list
  22. // - convert the lock to a r/w resource
  23. // - get away from using the boneheaded Reference/Dereference scheme
  24. // for removing items from the list
  25. //
  26. //+-------------------------------------------------------------------------
  27. //
  28. // Function: LsapInitializeList
  29. //
  30. // Synopsis: Initializes a lsap list by initializing the lock
  31. // and the list entry.
  32. //
  33. // Effects:
  34. //
  35. // Arguments: List - List to initialize
  36. //
  37. // Requires:
  38. //
  39. // Returns: STATUS_SUCCESS on success or errors from
  40. // RtlInitializeResources
  41. //
  42. // Notes:
  43. //
  44. //
  45. //--------------------------------------------------------------------------
  46. NTSTATUS
  47. LsapInitializeList(
  48. IN PLSAP_LIST List
  49. )
  50. {
  51. NTSTATUS Status = STATUS_SUCCESS;
  52. InitializeListHead(&List->List);
  53. Status = RtlInitializeCriticalSection(
  54. &List->Lock
  55. );
  56. return(Status);
  57. }
  58. //+-------------------------------------------------------------------------
  59. //
  60. // Function: LsapFreeList
  61. //
  62. // Synopsis: Frees a lsap list by deleting the associated
  63. // critical section.
  64. //
  65. // Effects: List - the list to free.
  66. //
  67. // Arguments:
  68. //
  69. // Requires:
  70. //
  71. // Returns: none
  72. //
  73. // Notes: The list must be empty before freeing it.
  74. //
  75. //
  76. //--------------------------------------------------------------------------
  77. VOID
  78. LsapFreeList(
  79. IN PLSAP_LIST List
  80. )
  81. {
  82. //
  83. // Make sure the list is empty first
  84. //
  85. DsysAssert(List->List.Flink == List->List.Blink);
  86. RtlDeleteCriticalSection(&List->Lock);
  87. }
  88. //+-------------------------------------------------------------------------
  89. //
  90. // Function: LsapInitializeListEntry
  91. //
  92. // Synopsis: Initializes a newly created list entry for later
  93. // insertion onto the list.
  94. //
  95. // Effects: The reference count is set to one and the links are set
  96. // to NULL.
  97. //
  98. // Arguments: ListEntry - the list entry to initialize
  99. //
  100. // Requires:
  101. //
  102. // Returns: none
  103. //
  104. // Notes:
  105. //
  106. //
  107. //--------------------------------------------------------------------------
  108. VOID
  109. LsapInitializeListEntry(
  110. IN OUT PLSAP_LIST_ENTRY ListEntry
  111. )
  112. {
  113. ListEntry->ReferenceCount = 1;
  114. ListEntry->Next.Flink = ListEntry->Next.Blink = NULL;
  115. }
  116. //+-------------------------------------------------------------------------
  117. //
  118. // Function: LsapInsertListEntry
  119. //
  120. // Synopsis: Inserts an entry into a lsap list
  121. //
  122. // Effects: increments the reference count on the entry - if the
  123. // list entry was formly referenced it remains referenced.
  124. //
  125. // Arguments: ListEntry - the entry to insert
  126. // List - the list in which to insert the ListEntry
  127. //
  128. // Requires:
  129. //
  130. // Returns: nothing
  131. //
  132. // Notes:
  133. //
  134. //
  135. //--------------------------------------------------------------------------
  136. VOID
  137. LsapInsertListEntry(
  138. IN PLSAP_LIST_ENTRY ListEntry,
  139. IN PLSAP_LIST List
  140. )
  141. {
  142. ListEntry->ReferenceCount++;
  143. RtlEnterCriticalSection(&List->Lock);
  144. InsertHeadList(
  145. &List->List,
  146. &ListEntry->Next
  147. );
  148. RtlLeaveCriticalSection(&List->Lock);
  149. }
  150. //+-------------------------------------------------------------------------
  151. //
  152. // Function: LsapReferenceListEntry
  153. //
  154. // Synopsis: References a list entry. If the flag RemoveFromList
  155. // has been specified, the entry is unlinked from the
  156. // list.
  157. //
  158. // Effects: bumps the reference count on the entry (unless it is
  159. // being removed from the list)
  160. //
  161. // Arguments:
  162. //
  163. // Requires: The list must be locked when calling this routine
  164. //
  165. // Returns:
  166. //
  167. // Notes:
  168. //
  169. //
  170. //--------------------------------------------------------------------------
  171. VOID
  172. LsapReferenceListEntry(
  173. IN PLSAP_LIST List,
  174. IN PLSAP_LIST_ENTRY ListEntry,
  175. IN BOOLEAN RemoveFromList
  176. )
  177. {
  178. //
  179. // If it has already been removed from the list
  180. // don't do it again.
  181. //
  182. if (RemoveFromList && ((ListEntry->Next.Flink != NULL) &&
  183. (ListEntry->Next.Blink != NULL)))
  184. {
  185. RemoveEntryList(&ListEntry->Next);
  186. ListEntry->Next.Flink = NULL;
  187. ListEntry->Next.Blink = NULL;
  188. }
  189. else
  190. {
  191. ListEntry->ReferenceCount++;
  192. }
  193. }
  194. //+-------------------------------------------------------------------------
  195. //
  196. // Function: LsapDereferenceListEntry
  197. //
  198. // Synopsis: Dereferences a list entry and returns a flag indicating
  199. // whether the entry should be freed.
  200. //
  201. // Effects: decrements reference count on list entry
  202. //
  203. // Arguments: ListEntry - the list entry to dereference
  204. // List - the list containing the list entry
  205. //
  206. // Requires:
  207. //
  208. // Returns: TRUE - the list entry should be freed
  209. // FALSE - the list entry is still referenced
  210. //
  211. // Notes:
  212. //
  213. //
  214. //--------------------------------------------------------------------------
  215. BOOLEAN
  216. LsapDereferenceListEntry(
  217. IN PLSAP_LIST_ENTRY ListEntry,
  218. IN PLSAP_LIST List
  219. )
  220. {
  221. BOOLEAN DeleteEntry = FALSE;
  222. RtlEnterCriticalSection(&List->Lock);
  223. ListEntry->ReferenceCount -= 1;
  224. if (ListEntry->ReferenceCount == 0)
  225. {
  226. DeleteEntry = TRUE;
  227. }
  228. RtlLeaveCriticalSection(&List->Lock);
  229. return(DeleteEntry);
  230. }
  231. //+-------------------------------------------------------------------------
  232. //
  233. // Function: LsapInitBindingCache
  234. //
  235. // Synopsis: Initializes the binding cache
  236. //
  237. // Effects: allocates a resources
  238. //
  239. // Arguments: none
  240. //
  241. // Requires:
  242. //
  243. // Returns: STATUS_SUCCESS on success, other error codes
  244. // on failure
  245. //
  246. // Notes:
  247. //
  248. //
  249. //--------------------------------------------------------------------------
  250. NTSTATUS
  251. LsapInitBindingCache(
  252. VOID
  253. )
  254. {
  255. NTSTATUS Status;
  256. Status = LsapInitializeList( &LsapBindingCache );
  257. if (NT_SUCCESS(Status))
  258. {
  259. LsapBindingCacheInitialized = TRUE;
  260. }
  261. return(Status);
  262. }
  263. //+-------------------------------------------------------------------------
  264. //
  265. // Function: LsapDereferenceBindingCacheEntry
  266. //
  267. // Synopsis: Dereferences a binding cache entry
  268. //
  269. // Effects: Dereferences the binding cache entry to make it go away
  270. // when it is no longer being used.
  271. //
  272. // Arguments: decrements reference count and delets cache entry if it goes
  273. // to zero
  274. //
  275. // Requires: BindingCacheEntry - The binding cache entry to dereference.
  276. //
  277. // Returns: none
  278. //
  279. // Notes:
  280. //
  281. //
  282. //--------------------------------------------------------------------------
  283. VOID
  284. LsapDereferenceBindingCacheEntry(
  285. IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry
  286. )
  287. {
  288. if (LsapDereferenceListEntry(
  289. &BindingCacheEntry->ListEntry,
  290. &LsapBindingCache
  291. ) )
  292. {
  293. LsapFreeBindingCacheEntry(BindingCacheEntry);
  294. }
  295. }
  296. //+-------------------------------------------------------------------------
  297. //
  298. // Function: LsapReferenceBindingCacheEntry
  299. //
  300. // Synopsis: References a binding cache entry
  301. //
  302. // Effects: Increments the reference count on the binding cache entry
  303. //
  304. // Arguments: BindingCacheEntry - binding cache entry to reference
  305. //
  306. // Requires: The binding cache must be locked
  307. //
  308. // Returns: none
  309. //
  310. // Notes:
  311. //
  312. //
  313. //--------------------------------------------------------------------------
  314. VOID
  315. LsapReferenceBindingCacheEntry(
  316. IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry,
  317. IN BOOLEAN RemoveFromList
  318. )
  319. {
  320. LsapLockList(&LsapBindingCache);
  321. LsapReferenceListEntry(
  322. &LsapBindingCache,
  323. &BindingCacheEntry->ListEntry,
  324. RemoveFromList
  325. );
  326. LsapUnlockList(&LsapBindingCache);
  327. }
  328. //+-------------------------------------------------------------------------
  329. //
  330. // Function: LsapLocateBindingCacheEntry
  331. //
  332. // Synopsis: References a binding cache entry by name
  333. //
  334. // Effects: Increments the reference count on the binding cache entry
  335. //
  336. // Arguments: RealmName - Contains the name of the realm for which to
  337. // obtain a binding handle.
  338. // RemoveFromList - Remove cache entry from cache when found.
  339. //
  340. // Requires:
  341. //
  342. // Returns: The referenced cache entry or NULL if it was not found.
  343. //
  344. // Notes: If an invalid entry is found it may be dereferenced
  345. //
  346. //
  347. //--------------------------------------------------------------------------
  348. PLSAP_BINDING_CACHE_ENTRY
  349. LsapLocateBindingCacheEntry(
  350. IN PUNICODE_STRING RealmName,
  351. IN BOOLEAN RemoveFromList
  352. )
  353. {
  354. PLIST_ENTRY ListEntry;
  355. PLSAP_BINDING_CACHE_ENTRY CacheEntry = NULL;
  356. BOOLEAN Found = FALSE;
  357. //
  358. // REVIEW: the lock should be converted to a r/w resource
  359. // this lock can be acquired for read whenever RemoveFromList is FALSE
  360. // (with corresponding changes made to LsapReferenceBindingCacheEntry)
  361. //
  362. LsapLockList(&LsapBindingCache);
  363. //
  364. // Go through the binding cache looking for the correct entry
  365. //
  366. for (ListEntry = LsapBindingCache.List.Flink ;
  367. ListEntry != &LsapBindingCache.List ;
  368. ListEntry = ListEntry->Flink )
  369. {
  370. CacheEntry = CONTAINING_RECORD(ListEntry, LSAP_BINDING_CACHE_ENTRY, ListEntry.Next);
  371. if (RtlEqualUnicodeString(
  372. &CacheEntry->RealmName,
  373. RealmName,
  374. TRUE
  375. ))
  376. {
  377. LsapReferenceBindingCacheEntry(
  378. CacheEntry,
  379. RemoveFromList
  380. );
  381. Found = TRUE;
  382. NtQuerySystemTime(
  383. &CacheEntry->LastUsed
  384. );
  385. break;
  386. }
  387. }
  388. if (!Found)
  389. {
  390. CacheEntry = NULL;
  391. }
  392. LsapUnlockList(&LsapBindingCache);
  393. return(CacheEntry);
  394. }
  395. //+-------------------------------------------------------------------------
  396. //
  397. // Function: LsapFreeBindingCacheEntry
  398. //
  399. // Synopsis: Frees memory associated with a binding cache entry
  400. //
  401. // Effects:
  402. //
  403. // Arguments: BindingCacheEntry - The cache entry to free. It must be
  404. // unlinked.
  405. //
  406. // Requires:
  407. //
  408. // Returns: none
  409. //
  410. // Notes:
  411. //
  412. //
  413. //--------------------------------------------------------------------------
  414. VOID
  415. LsapFreeBindingCacheEntry(
  416. IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry
  417. )
  418. {
  419. if ( !BindingCacheEntry )
  420. {
  421. return;
  422. }
  423. LsapFreeString(&BindingCacheEntry->RealmName);
  424. if (BindingCacheEntry->PolicyHandle != NULL)
  425. {
  426. LsaClose(BindingCacheEntry->PolicyHandle);
  427. }
  428. if (BindingCacheEntry->ServerName != NULL) {
  429. //
  430. // Note -- because I_NetLogonAuthData is not supported for NT4 and
  431. // below, ServerName won't always be allocated from NetLogon's MM.
  432. // So, the ServerName allocation is normalized to LocalAlloc/LocalFree
  433. //
  434. LocalFree(BindingCacheEntry->ServerName);
  435. }
  436. if (BindingCacheEntry->ServerPrincipalName != NULL) {
  437. I_NetLogonFree(BindingCacheEntry->ServerPrincipalName);
  438. }
  439. if (BindingCacheEntry->ClientContext != NULL) {
  440. I_NetLogonFree(BindingCacheEntry->ClientContext);
  441. }
  442. LsapFreeLsaHeap(BindingCacheEntry);
  443. }
  444. //+-------------------------------------------------------------------------
  445. //
  446. // Function: LsapInsertBinding
  447. //
  448. // Synopsis: Inserts a binding into the binding cache
  449. //
  450. // Effects: bumps reference count on binding
  451. //
  452. // Arguments: CacheEntry - Cache entry to insert
  453. //
  454. // Requires:
  455. //
  456. // Returns: STATUS_SUCCESS always
  457. //
  458. // Notes:
  459. //
  460. //
  461. //--------------------------------------------------------------------------
  462. NTSTATUS
  463. LsapInsertBinding(
  464. IN PLSAP_BINDING_CACHE_ENTRY CacheEntry
  465. )
  466. {
  467. LsapInsertListEntry(
  468. &CacheEntry->ListEntry,
  469. &LsapBindingCache
  470. );
  471. return(STATUS_SUCCESS);
  472. }
  473. //+-------------------------------------------------------------------------
  474. //
  475. // Function: LsapCacheBinding
  476. //
  477. // Synopsis: Caches a binding in the binding cache
  478. //
  479. // Effects: creates a cache entry.
  480. //
  481. // Arguments: RealmName - The realm name of the LSA the binding is to.
  482. // Handle - LSA policy handle to the target machine.
  483. // ServerName,ServerPrincipalName, ClientContext - authenticated
  484. // rpc parameters needed to be cached for the duration
  485. // of the binding.
  486. // CacheEntry - Receives the new binding cache entry,
  487. // referenced.
  488. //
  489. // Requires:
  490. //
  491. // Returns:
  492. //
  493. // Notes: Locks the binding cache for write access while adding
  494. // the cache entry.
  495. //
  496. //
  497. //--------------------------------------------------------------------------
  498. NTSTATUS
  499. LsapCacheBinding(
  500. IN PUNICODE_STRING RealmName,
  501. IN PLSA_HANDLE Handle,
  502. IN OUT LPWSTR * ServerName,
  503. IN OUT LPWSTR * ServerPrincipalName,
  504. IN OUT PVOID * ClientContext,
  505. OUT PLSAP_BINDING_CACHE_ENTRY * NewCacheEntry
  506. )
  507. {
  508. PLSAP_BINDING_CACHE_ENTRY CacheEntry = NULL;
  509. PLSAP_BINDING_CACHE_ENTRY OldCacheEntry = NULL;
  510. NTSTATUS Status = STATUS_SUCCESS;
  511. *NewCacheEntry = NULL;
  512. CacheEntry = (PLSAP_BINDING_CACHE_ENTRY)
  513. LsapAllocateLsaHeap(sizeof(LSAP_BINDING_CACHE_ENTRY));
  514. if (CacheEntry == NULL)
  515. {
  516. Status = STATUS_INSUFFICIENT_RESOURCES;
  517. goto Cleanup;
  518. }
  519. RtlZeroMemory(
  520. CacheEntry,
  521. sizeof(LSAP_BINDING_CACHE_ENTRY)
  522. );
  523. LsapInitializeListEntry(
  524. &CacheEntry->ListEntry
  525. );
  526. NtQuerySystemTime(
  527. &CacheEntry->LastUsed
  528. );
  529. Status = LsapDuplicateString(
  530. &CacheEntry->RealmName,
  531. RealmName
  532. );
  533. if (!NT_SUCCESS(Status))
  534. {
  535. goto Cleanup;
  536. }
  537. CacheEntry->PolicyHandle = *Handle;
  538. *Handle = NULL;
  539. CacheEntry->ServerName = *ServerName;
  540. *ServerName = NULL;
  541. CacheEntry->ServerPrincipalName = *ServerPrincipalName;
  542. *ServerPrincipalName = NULL;
  543. CacheEntry->ClientContext = *ClientContext;
  544. *ClientContext = NULL;
  545. //
  546. // Before we insert this binding we want to remove any
  547. // previous instances of bindings to the same realm.
  548. //
  549. OldCacheEntry = LsapLocateBindingCacheEntry(
  550. RealmName,
  551. TRUE // remove from cache
  552. );
  553. if (OldCacheEntry != NULL)
  554. {
  555. LsapDereferenceBindingCacheEntry( OldCacheEntry );
  556. }
  557. //
  558. // Insert the cache entry into the cache
  559. //
  560. Status = LsapInsertBinding(
  561. CacheEntry
  562. );
  563. if (!NT_SUCCESS(Status))
  564. {
  565. goto Cleanup;
  566. }
  567. *NewCacheEntry = CacheEntry;
  568. Cleanup:
  569. if (!NT_SUCCESS(Status))
  570. {
  571. if ( CacheEntry )
  572. {
  573. LsapFreeBindingCacheEntry(CacheEntry);
  574. }
  575. }
  576. return(Status);
  577. }