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.

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