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.

621 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 <kerb.hxx>
  16. #define BNDCACHE_ALLOCATE
  17. #include <kerbp.h>
  18. //+-------------------------------------------------------------------------
  19. //
  20. // Function: KerbInitBindingCache
  21. //
  22. // Synopsis: Initializes the binding cache
  23. //
  24. // Effects: allocates a resources
  25. //
  26. // Arguments: none
  27. //
  28. // Requires:
  29. //
  30. // Returns: STATUS_SUCCESS on success, other error codes on failure
  31. //
  32. // Notes:
  33. //
  34. //
  35. //--------------------------------------------------------------------------
  36. NTSTATUS
  37. KerbInitBindingCache(
  38. VOID
  39. )
  40. {
  41. NTSTATUS Status;
  42. Status = KerbInitializeList( &KerbBindingCache, BINDING_CACHE_LOCK_ENUM );
  43. if (!NT_SUCCESS(Status))
  44. {
  45. goto Cleanup;
  46. }
  47. KerberosBindingCacheInitialized = TRUE;
  48. Cleanup:
  49. if (!NT_SUCCESS(Status))
  50. {
  51. KerbFreeList( &KerbBindingCache );
  52. }
  53. return(Status);
  54. }
  55. //+-------------------------------------------------------------------------
  56. //
  57. // Function: KerbCleanupBindingCache
  58. //
  59. // Synopsis: Frees the binding cache
  60. //
  61. // Effects:
  62. //
  63. // Arguments: none
  64. //
  65. // Requires:
  66. //
  67. // Returns: none
  68. //
  69. // Notes:
  70. //
  71. //
  72. //--------------------------------------------------------------------------
  73. VOID
  74. KerbCleanupBindingCache(
  75. BOOLEAN FreeList
  76. )
  77. {
  78. PKERB_BINDING_CACHE_ENTRY CacheEntry;
  79. if (KerberosBindingCacheInitialized)
  80. {
  81. KerbLockList(&KerbBindingCache);
  82. //
  83. // Go through the list of bindings and dereference them all
  84. //
  85. while (!IsListEmpty(&KerbBindingCache.List))
  86. {
  87. CacheEntry = CONTAINING_RECORD(
  88. KerbBindingCache.List.Flink,
  89. KERB_BINDING_CACHE_ENTRY,
  90. ListEntry.Next
  91. );
  92. DsysAssert( CacheEntry != NULL );
  93. KerbReferenceListEntry(
  94. &KerbBindingCache,
  95. &CacheEntry->ListEntry,
  96. TRUE
  97. );
  98. KerbDereferenceBindingCacheEntry(CacheEntry);
  99. }
  100. //
  101. // If we want to free the list, orphan the lock, and free the list
  102. // otherwise, proceed on w/ the "fresh" cache.
  103. //
  104. if ( FreeList )
  105. {
  106. KerbFreeList(&KerbBindingCache);
  107. }
  108. else
  109. {
  110. KerbUnlockList(&KerbBindingCache);
  111. }
  112. }
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Function: KerbDereferenceBindingCacheEntry
  117. //
  118. // Synopsis: Dereferences a binding cache entry
  119. //
  120. // Effects: Dereferences the binding cache entry to make it go away
  121. // when it is no longer being used.
  122. //
  123. // Arguments: decrements reference count and delets cache entry if it goes
  124. // to zero
  125. //
  126. // Requires: BindingCacheEntry - The binding cache entry to dereference.
  127. //
  128. // Returns: none
  129. //
  130. // Notes:
  131. //
  132. //
  133. //--------------------------------------------------------------------------
  134. VOID
  135. KerbDereferenceBindingCacheEntry(
  136. IN PKERB_BINDING_CACHE_ENTRY BindingCacheEntry
  137. )
  138. {
  139. if (KerbDereferenceListEntry(
  140. &BindingCacheEntry->ListEntry,
  141. &KerbBindingCache
  142. ) )
  143. {
  144. KerbFreeBindingCacheEntry(BindingCacheEntry);
  145. }
  146. }
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Function: KerbReferenceBindingCacheEntry
  150. //
  151. // Synopsis: References a binding cache entry
  152. //
  153. // Effects: Increments the reference count on the binding cache entry
  154. //
  155. // Arguments: BindingCacheEntry - binding cache entry to reference
  156. //
  157. // Requires: The binding cache must be locked
  158. //
  159. // Returns: none
  160. //
  161. // Notes:
  162. //
  163. //
  164. //--------------------------------------------------------------------------
  165. VOID
  166. KerbReferenceBindingCacheEntry(
  167. IN PKERB_BINDING_CACHE_ENTRY BindingCacheEntry,
  168. IN BOOLEAN RemoveFromList
  169. )
  170. {
  171. KerbLockList(&KerbBindingCache);
  172. KerbReferenceListEntry(
  173. &KerbBindingCache,
  174. &BindingCacheEntry->ListEntry,
  175. RemoveFromList
  176. );
  177. KerbUnlockList(&KerbBindingCache);
  178. }
  179. //+-------------------------------------------------------------------------
  180. //
  181. // Function: KerbLocateBindingCacheEntry
  182. //
  183. // Synopsis: References a binding cache entry by name
  184. //
  185. // Effects: Increments the reference count on the binding cache entry
  186. //
  187. // Arguments: RealmName - Contains the name of the realm for which to
  188. // obtain a binding handle.
  189. // DesiredFlags - Flags desired for binding, such as PDC required
  190. // RemoveFromList - Remove cache entry from cache when found.
  191. //
  192. // Requires:
  193. //
  194. // Returns: The referenced cache entry or NULL if it was not found.
  195. //
  196. // Notes: If an invalid entry is found it may be dereferenced
  197. //
  198. //
  199. //--------------------------------------------------------------------------
  200. PKERB_BINDING_CACHE_ENTRY
  201. KerbLocateBindingCacheEntry(
  202. IN PUNICODE_STRING RealmName,
  203. IN ULONG DesiredFlags,
  204. IN BOOLEAN RemoveFromList
  205. )
  206. {
  207. PLIST_ENTRY ListEntry;
  208. PKERB_BINDING_CACHE_ENTRY CacheEntry = NULL;
  209. BOOLEAN Found = FALSE;
  210. if (DesiredFlags == 0)
  211. {
  212. DesiredFlags = KERB_NO_DC_FLAGS;
  213. }
  214. KerbLockList(&KerbBindingCache);
  215. //
  216. // Go through the binding cache looking for the correct entry
  217. //
  218. for (ListEntry = KerbBindingCache.List.Flink ;
  219. ListEntry != &KerbBindingCache.List ;
  220. ListEntry = ListEntry->Flink )
  221. {
  222. CacheEntry = CONTAINING_RECORD(ListEntry, KERB_BINDING_CACHE_ENTRY, ListEntry.Next);
  223. DsysAssert( CacheEntry != NULL );
  224. if ( RtlEqualUnicodeString( &CacheEntry->RealmName, RealmName,TRUE ) &&
  225. ((DesiredFlags & CacheEntry->Flags) == DesiredFlags))
  226. {
  227. Found = TRUE;
  228. //
  229. // Check to see if we should stop using this entry
  230. //
  231. if (!RemoveFromList)
  232. {
  233. TimeStamp CurrentTime, Timeout;
  234. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime );
  235. if ((CacheEntry->DcFlags & DS_CLOSEST_FLAG) == 0)
  236. {
  237. Timeout = KerbGlobalFarKdcTimeout;
  238. }
  239. else
  240. {
  241. Timeout = KerbGlobalNearKdcTimeout;
  242. }
  243. if (KerbGetTime(CacheEntry->DiscoveryTime) + KerbGetTime(Timeout) < KerbGetTime(CurrentTime))
  244. {
  245. //
  246. // This entry has timed out - it is not close by and we
  247. // don't want to use it for too long, or its time to check
  248. // for a close DC again.
  249. //
  250. // Note: This will have the sideeffect of checking for a new PDC
  251. //
  252. D_DebugLog((DEB_TRACE_BND_CACHE,
  253. "Purging KDC cache entry Realm: %wZ, Addr: %wZ, DcFlags %x\n",
  254. &CacheEntry->RealmName,
  255. &CacheEntry->KdcAddress,
  256. CacheEntry->DcFlags
  257. ));
  258. RemoveFromList = TRUE;
  259. Found = FALSE;
  260. }
  261. #if DBG
  262. else
  263. {
  264. D_DebugLog((DEB_TRACE_BND_CACHE,
  265. "**Using** KDC cache entry Realm: %wZ, Addr: %wZ, DcFlags %x\n",
  266. &CacheEntry->RealmName,
  267. &CacheEntry->KdcAddress,
  268. CacheEntry->DcFlags
  269. ));
  270. if ((CacheEntry->DcFlags & DS_CLOSEST_FLAG) == DS_CLOSEST_FLAG)
  271. {
  272. D_DebugLog((DEB_TRACE_BND_CACHE, "CLOSE DC "));
  273. }
  274. else
  275. {
  276. D_DebugLog((DEB_TRACE_BND_CACHE, "FAR DC "));
  277. }
  278. if ((CacheEntry->DcFlags & DS_PDC_FLAG) == DS_PDC_FLAG)
  279. {
  280. D_DebugLog((DEB_TRACE_BND_CACHE, "-- ** PDC **\n"));
  281. }
  282. else
  283. {
  284. D_DebugLog((DEB_TRACE_BND_CACHE, "-- BDC\n"));
  285. }
  286. }
  287. #endif //dbg
  288. }
  289. KerbReferenceBindingCacheEntry(
  290. CacheEntry,
  291. RemoveFromList
  292. );
  293. //
  294. // If we aren't returning this, dereference it now
  295. //
  296. if (!Found)
  297. {
  298. KerbDereferenceBindingCacheEntry( CacheEntry );
  299. }
  300. break;
  301. }
  302. }
  303. if (!Found)
  304. {
  305. CacheEntry = NULL;
  306. }
  307. KerbUnlockList(&KerbBindingCache);
  308. return(CacheEntry);
  309. }
  310. //+-------------------------------------------------------------------------
  311. //
  312. // Function: KerbFreeBindingCacheEntry
  313. //
  314. // Synopsis: Frees memory associated with a binding cache entry
  315. //
  316. // Effects:
  317. //
  318. // Arguments: BindingCacheEntry - The cache entry to free. It must be
  319. // unlinked.
  320. //
  321. // Requires:
  322. //
  323. // Returns: none
  324. //
  325. // Notes:
  326. //
  327. //
  328. //--------------------------------------------------------------------------
  329. VOID
  330. KerbFreeBindingCacheEntry(
  331. IN PKERB_BINDING_CACHE_ENTRY BindingCacheEntry
  332. )
  333. {
  334. KerbFreeString(&BindingCacheEntry->RealmName);
  335. KerbFreeString(&BindingCacheEntry->KdcAddress);
  336. KerbFree(BindingCacheEntry);
  337. }
  338. //+-------------------------------------------------------------------------
  339. //
  340. // Function: KerbInsertBinding
  341. //
  342. // Synopsis: Inserts a binding into the binding cache
  343. //
  344. // Effects: bumps reference count on binding
  345. //
  346. // Arguments: CacheEntry - Cache entry to insert
  347. //
  348. // Requires:
  349. //
  350. // Returns: STATUS_SUCCESS always
  351. //
  352. // Notes:
  353. //
  354. //
  355. //--------------------------------------------------------------------------
  356. NTSTATUS
  357. KerbInsertBinding(
  358. IN PKERB_BINDING_CACHE_ENTRY CacheEntry
  359. )
  360. {
  361. IF_DEBUG(DISABLE_BND_CACHE)
  362. {
  363. DebugLog((DEB_TRACE_BND_CACHE, "KerbInsertBinding binding cache disabled\n"));
  364. return STATUS_SUCCESS;
  365. }
  366. KerbInsertListEntry(
  367. &CacheEntry->ListEntry,
  368. &KerbBindingCache
  369. );
  370. return(STATUS_SUCCESS);
  371. }
  372. //+-------------------------------------------------------------------------
  373. //
  374. // Function: KerbCacheBinding
  375. //
  376. // Synopsis: Caches a binding in the binding cache
  377. //
  378. // Effects: creates a cache entry.
  379. //
  380. // Arguments: RealmName - The realm name of the KDC the binding is to.
  381. // KdcAddress - address of the KDC
  382. // AddressType - Type of address, from DsGetDCName flags
  383. // Flags - These were the desired flags that we asked for
  384. // DcFlags - These are the flags the dc has
  385. // CacheFlags - Special meaning so we don't use the locator bits
  386. // CacheEntry - Receives the new binding cache entry, referenced
  387. //
  388. // Requires:
  389. //
  390. // Returns: STATUS_SUCCESS on success, other error codes on failure
  391. //
  392. // Notes: Locks the binding cache for write access while adding
  393. // the cache entry. Removes a cache entry for the same domain
  394. // before adding this one.
  395. //
  396. //
  397. //--------------------------------------------------------------------------
  398. NTSTATUS
  399. KerbCacheBinding(
  400. IN PUNICODE_STRING RealmName,
  401. IN PUNICODE_STRING KdcAddress,
  402. IN ULONG AddressType,
  403. IN ULONG Flags,
  404. IN ULONG DcFlags,
  405. IN ULONG CacheFlags,
  406. OUT PKERB_BINDING_CACHE_ENTRY * NewCacheEntry
  407. )
  408. {
  409. PKERB_BINDING_CACHE_ENTRY CacheEntry = NULL;
  410. PKERB_BINDING_CACHE_ENTRY OldCacheEntry = NULL;
  411. NTSTATUS Status = STATUS_SUCCESS;
  412. ULONG DesiredFlags = KERB_NO_DC_FLAGS;
  413. D_DebugLog((DEB_TRACE_BND_CACHE,
  414. "Adding Binding Cache Entry - %wZ : %wZ, DcFlags %x CacheFlags %x\n",
  415. RealmName,
  416. KdcAddress,
  417. DcFlags,
  418. CacheFlags
  419. ));
  420. Flags &= ~DS_FORCE_REDISCOVERY; //not a valid flag
  421. //
  422. // If we requested a PDC, and this is a PDC, then cache it
  423. // as a PDC. Otherwise, we just got lucky, and we'll use
  424. // the PDC naturally.
  425. //
  426. if ((Flags == DS_PDC_REQUIRED) && ((DcFlags & DS_PDC_FLAG) == DS_PDC_FLAG))
  427. {
  428. D_DebugLog((DEB_TRACE_BND_CACHE, "Caching as PDC\n"));
  429. DesiredFlags = DS_PDC_REQUIRED;
  430. }
  431. else
  432. {
  433. D_DebugLog((DEB_TRACE_BND_CACHE, "Caching as BDC\n"));
  434. Flags &= ~DS_PDC_REQUIRED; // clear the flag.
  435. DcFlags &= ~DS_PDC_FLAG;
  436. }
  437. *NewCacheEntry = NULL;
  438. CacheEntry = (PKERB_BINDING_CACHE_ENTRY)
  439. KerbAllocate(sizeof(KERB_BINDING_CACHE_ENTRY));
  440. if (CacheEntry == NULL)
  441. {
  442. Status = STATUS_INSUFFICIENT_RESOURCES;
  443. goto Cleanup;
  444. }
  445. KerbInitializeListEntry(
  446. &CacheEntry->ListEntry
  447. );
  448. GetSystemTimeAsFileTime((PFILETIME)
  449. &CacheEntry->DiscoveryTime
  450. );
  451. Status = KerbDuplicateString(
  452. &CacheEntry->RealmName,
  453. RealmName
  454. );
  455. if (!NT_SUCCESS(Status))
  456. {
  457. goto Cleanup;
  458. }
  459. Status = KerbDuplicateString(
  460. &CacheEntry->KdcAddress,
  461. KdcAddress
  462. );
  463. if (!NT_SUCCESS(Status))
  464. {
  465. goto Cleanup;
  466. }
  467. CacheEntry->AddressType = AddressType;
  468. CacheEntry->Flags = ((Flags == 0) ? KERB_NO_DC_FLAGS : Flags);
  469. CacheEntry->DcFlags = DcFlags;
  470. CacheEntry->CacheFlags = CacheFlags;
  471. //
  472. // Before we insert this binding we want to remove any
  473. // previous instances of bindings to the same realm.
  474. //
  475. OldCacheEntry = KerbLocateBindingCacheEntry(
  476. RealmName,
  477. DesiredFlags, // only hammer on PDC entries
  478. TRUE // remove from cache
  479. );
  480. if (OldCacheEntry != NULL)
  481. {
  482. KerbDereferenceBindingCacheEntry( OldCacheEntry );
  483. }
  484. //
  485. // Insert the cache entry into the cache
  486. //
  487. Status = KerbInsertBinding(
  488. CacheEntry
  489. );
  490. if (!NT_SUCCESS(Status))
  491. {
  492. goto Cleanup;
  493. }
  494. *NewCacheEntry = CacheEntry;
  495. Cleanup:
  496. if (!NT_SUCCESS(Status))
  497. {
  498. if (NULL != CacheEntry)
  499. {
  500. KerbFreeBindingCacheEntry(CacheEntry);
  501. }
  502. }
  503. return(Status);
  504. }
  505. //+-------------------------------------------------------------------------
  506. //
  507. // Function: KerbRemoveBindingCacheEntry
  508. //
  509. // Synopsis: removes an entry from the binding cache
  510. //
  511. // Effects:
  512. //
  513. // Arguments: CacheEntry - entry to remove
  514. //
  515. // Requires:
  516. //
  517. // Returns:
  518. //
  519. // Notes:
  520. //
  521. //
  522. //--------------------------------------------------------------------------
  523. VOID
  524. KerbRemoveBindingCacheEntry(
  525. IN PKERB_BINDING_CACHE_ENTRY CacheEntry
  526. )
  527. {
  528. KerbLockList(&KerbBindingCache);
  529. KerbReferenceBindingCacheEntry(
  530. CacheEntry,
  531. TRUE
  532. );
  533. KerbDereferenceBindingCacheEntry(
  534. CacheEntry
  535. );
  536. KerbUnlockList(&KerbBindingCache);
  537. }