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.

1298 lines
34 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1997
  6. //
  7. // File: mitutil.cxx
  8. //
  9. // Contents: Routines for talking to MIT KDCs
  10. //
  11. //
  12. // History: 4-March-1997 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. #include <kerb.hxx>
  18. #include <kerbp.h>
  19. #ifdef RETAIL_LOG_SUPPORT
  20. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  21. #endif
  22. static HKEY KerbMITRealmRootKey = NULL;
  23. static HANDLE hKerbMITRealmWaitEvent = NULL;
  24. static HANDLE hKerbMITRealmWaitObject = NULL;
  25. KERBEROS_LIST KerbMitRealmList;
  26. #define MAX_DOMAIN_NAME_LEN 128 // number of characters
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: KerbReadMitRealmList
  30. //
  31. // Synopsis: Loads the list of MIT realms from the registry
  32. //
  33. // Effects: Initialize and links domains to KerbMitRealmList
  34. //
  35. // Arguments:
  36. //
  37. // Requires:
  38. //
  39. // Returns:
  40. //
  41. // Notes:
  42. //
  43. //
  44. //--------------------------------------------------------------------------
  45. NTSTATUS
  46. KerbReadMitRealmList(
  47. )
  48. {
  49. NTSTATUS Status = STATUS_SUCCESS;
  50. ULONG WinError;
  51. HKEY DomainKey = NULL;
  52. LPWSTR KdcNames = NULL;
  53. LPWSTR KpasswdNames = NULL;
  54. LPWSTR AlternateRealmNames = NULL;
  55. TCHAR DomainName[MAX_DOMAIN_NAME_LEN]; // max domain name length
  56. PKERB_MIT_REALM MitRealm = NULL;
  57. ULONG Index,Index2;
  58. ULONG Type;
  59. ULONG NameSize;
  60. ULONG KdcNameSize = 0;
  61. ULONG AltRealmSize = 0;
  62. ULONG KpasswdNameSize = 0;
  63. LPWSTR Where;
  64. ULONG NameCount, tmp;
  65. UNICODE_STRING TempString;
  66. ULONG Flags = 0;
  67. ULONG FlagSize = sizeof(ULONG);
  68. ULONG ApReqChecksumType = 0;
  69. ULONG PreAuthType = 0;
  70. BOOLEAN fListLocked = FALSE;
  71. //
  72. // If it is there, we now want to enumerate all the child keys.
  73. //
  74. KerbLockList(&KerbMitRealmList);
  75. fListLocked = TRUE;
  76. for (Index = 0; TRUE ; Index++ )
  77. {
  78. //
  79. // Enumerate through all the keys
  80. //
  81. NameSize = MAX_DOMAIN_NAME_LEN;
  82. WinError = RegEnumKeyEx(
  83. KerbMITRealmRootKey,
  84. Index,
  85. DomainName,
  86. &NameSize,
  87. NULL,
  88. NULL,
  89. NULL,
  90. NULL
  91. );
  92. if (WinError != ERROR_SUCCESS)
  93. {
  94. //
  95. // nothing more to do.
  96. //
  97. Status = STATUS_SUCCESS;
  98. goto Cleanup;
  99. }
  100. //
  101. // Open the domain key to read the values under it
  102. //
  103. if( DomainKey != NULL )
  104. {
  105. RegCloseKey( DomainKey );
  106. DomainKey = NULL;
  107. }
  108. WinError = RegOpenKey(
  109. KerbMITRealmRootKey,
  110. DomainName,
  111. &DomainKey
  112. );
  113. if (WinError != ERROR_SUCCESS)
  114. {
  115. D_DebugLog((DEB_ERROR,"Failed to open key %ws \\ %ws: %d. %ws, line %d\n",
  116. KERB_DOMAINS_KEY, DomainName, WinError, THIS_FILE, __LINE__ ));
  117. //
  118. // keep going.
  119. //
  120. continue;
  121. }
  122. //
  123. // Now read the values from the domain
  124. //
  125. KdcNameSize = 0;
  126. WinError = RegQueryValueEx(
  127. DomainKey,
  128. KERB_DOMAIN_KDC_NAMES_VALUE,
  129. NULL,
  130. &Type,
  131. NULL,
  132. &KdcNameSize
  133. );
  134. if (WinError == ERROR_SUCCESS)
  135. {
  136. KdcNames = (LPWSTR) KerbAllocate(KdcNameSize);
  137. if (KdcNames == NULL)
  138. {
  139. Status = STATUS_INSUFFICIENT_RESOURCES;
  140. goto Cleanup;
  141. }
  142. WinError = RegQueryValueEx(
  143. DomainKey,
  144. KERB_DOMAIN_KDC_NAMES_VALUE,
  145. NULL,
  146. &Type,
  147. (PUCHAR) KdcNames,
  148. &KdcNameSize
  149. );
  150. if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ )
  151. {
  152. D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n",
  153. DomainName, KERB_DOMAIN_KDC_NAMES_VALUE, WinError, THIS_FILE, __LINE__ ));
  154. continue; // keep reading...
  155. }
  156. }
  157. //
  158. // Now read the Kpasswd values from the domain
  159. //
  160. KpasswdNameSize = 0;
  161. WinError = RegQueryValueEx(
  162. DomainKey,
  163. KERB_DOMAIN_KPASSWD_NAMES_VALUE,
  164. NULL,
  165. &Type,
  166. NULL,
  167. &KpasswdNameSize
  168. );
  169. if (WinError == ERROR_SUCCESS)
  170. {
  171. KpasswdNames = (LPWSTR) KerbAllocate(KpasswdNameSize);
  172. if (KpasswdNames == NULL)
  173. {
  174. Status = STATUS_INSUFFICIENT_RESOURCES;
  175. goto Cleanup;
  176. }
  177. WinError = RegQueryValueEx(
  178. DomainKey,
  179. KERB_DOMAIN_KPASSWD_NAMES_VALUE,
  180. NULL,
  181. &Type,
  182. (PUCHAR) KpasswdNames,
  183. &KpasswdNameSize
  184. );
  185. if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ )
  186. {
  187. D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n",
  188. DomainName, KERB_DOMAIN_KPASSWD_NAMES_VALUE, WinError, THIS_FILE, __LINE__ ));
  189. continue; // keep reading
  190. }
  191. }
  192. //
  193. // Get any alternate domain names
  194. //
  195. AltRealmSize = 0;
  196. WinError = RegQueryValueEx(
  197. DomainKey,
  198. KERB_DOMAIN_ALT_NAMES_VALUE,
  199. NULL,
  200. &Type,
  201. NULL,
  202. &AltRealmSize
  203. );
  204. if (WinError == ERROR_SUCCESS)
  205. {
  206. AlternateRealmNames = (LPWSTR) KerbAllocate(AltRealmSize);
  207. if (AlternateRealmNames == NULL)
  208. {
  209. Status = STATUS_INSUFFICIENT_RESOURCES;
  210. goto Cleanup;
  211. }
  212. WinError = RegQueryValueEx(
  213. DomainKey,
  214. KERB_DOMAIN_ALT_NAMES_VALUE,
  215. NULL,
  216. &Type,
  217. (PUCHAR) AlternateRealmNames,
  218. &AltRealmSize
  219. );
  220. if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ)
  221. {
  222. D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n",
  223. DomainName, KERB_DOMAIN_KDC_NAMES_VALUE, WinError, THIS_FILE, __LINE__ ));
  224. continue;
  225. }
  226. }
  227. //
  228. // Read the flags
  229. //
  230. FlagSize = sizeof(ULONG);
  231. Flags = 0;
  232. WinError = RegQueryValueEx(
  233. DomainKey,
  234. KERB_DOMAIN_FLAGS_VALUE,
  235. NULL,
  236. &Type,
  237. (PUCHAR) &Flags,
  238. &FlagSize
  239. );
  240. if (WinError == ERROR_SUCCESS)
  241. {
  242. if (Type != REG_DWORD)
  243. {
  244. Flags = 0;
  245. }
  246. }
  247. //
  248. // Read the ApReq checksum type
  249. //
  250. FlagSize = sizeof(ULONG);
  251. ApReqChecksumType = KERB_DEFAULT_AP_REQ_CSUM;
  252. WinError = RegQueryValueEx(
  253. DomainKey,
  254. KERB_DOMAIN_AP_REQ_CSUM_VALUE,
  255. NULL,
  256. &Type,
  257. (PUCHAR) &ApReqChecksumType,
  258. &FlagSize
  259. );
  260. if (WinError == ERROR_SUCCESS)
  261. {
  262. if (Type != REG_DWORD)
  263. {
  264. ApReqChecksumType = KERB_DEFAULT_AP_REQ_CSUM;
  265. }
  266. }
  267. //
  268. // Read the ApReq checksum type
  269. //
  270. FlagSize = sizeof(ULONG);
  271. PreAuthType = KERB_DEFAULT_PREAUTH_TYPE;;
  272. WinError = RegQueryValueEx(
  273. DomainKey,
  274. KERB_DOMAIN_PREAUTH_VALUE,
  275. NULL,
  276. &Type,
  277. (PUCHAR) &PreAuthType,
  278. &FlagSize
  279. );
  280. if (WinError == ERROR_SUCCESS)
  281. {
  282. if (Type != REG_DWORD)
  283. {
  284. PreAuthType = KERB_DEFAULT_PREAUTH_TYPE;
  285. }
  286. }
  287. //
  288. // Now build the domain structure
  289. //
  290. MitRealm = (PKERB_MIT_REALM) KerbAllocate(sizeof(KERB_MIT_REALM));
  291. if (MitRealm == NULL)
  292. {
  293. Status = STATUS_INSUFFICIENT_RESOURCES;
  294. goto Cleanup;
  295. }
  296. MitRealm->Flags = Flags;
  297. MitRealm->ApReqChecksumType = ApReqChecksumType;
  298. MitRealm->PreAuthType = PreAuthType;
  299. #ifdef WIN32_CHICAGO
  300. RtlCreateUnicodeStringFromAsciiz(
  301. &TempString,
  302. DomainName
  303. );
  304. #else // WIN32_CHICAGO
  305. RtlInitUnicodeString(
  306. &TempString,
  307. DomainName
  308. );
  309. #endif // WIN32_CHICAGO
  310. Status = KerbDuplicateString(
  311. &MitRealm->RealmName,
  312. &TempString
  313. );
  314. if (!NT_SUCCESS(Status))
  315. {
  316. goto Cleanup;
  317. }
  318. //
  319. // Fill in the KDC names etc.
  320. //
  321. NameCount = 0;
  322. if ((AlternateRealmNames != NULL ) && (AltRealmSize != 0))
  323. {
  324. Where = AlternateRealmNames;
  325. NameCount ++;
  326. while (Where + wcslen(Where) + 1 < (AlternateRealmNames + AltRealmSize /sizeof(WCHAR)))
  327. {
  328. NameCount++;
  329. Where += wcslen(Where)+1;
  330. }
  331. MitRealm->AlternateRealmNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING));
  332. if (MitRealm->AlternateRealmNames == NULL)
  333. {
  334. Status = STATUS_INSUFFICIENT_RESOURCES;
  335. goto Cleanup;
  336. }
  337. MitRealm->RealmNameCount = NameCount;
  338. Where = AlternateRealmNames;
  339. for (Index2 = 0;Index2 < NameCount; Index2++)
  340. {
  341. RtlInitUnicodeString(
  342. &MitRealm->AlternateRealmNames[Index2],
  343. Where
  344. );
  345. Where += MitRealm->AlternateRealmNames[Index2].Length / sizeof(WCHAR) + 1;
  346. }
  347. AlternateRealmNames = NULL;
  348. }
  349. NameCount = 0;
  350. if ((KdcNames != NULL ) && (KdcNameSize != 0))
  351. {
  352. Where = KdcNames;
  353. while (Where + wcslen(Where) + 1 < (KdcNames + KdcNameSize /sizeof(WCHAR)))
  354. {
  355. // There's a bug in ksetup which adds a couple of "" strings to this, so...
  356. tmp = (ULONG) wcslen(Where) + 1;
  357. if (tmp > 1)
  358. {
  359. NameCount++;
  360. }
  361. Where += tmp;
  362. }
  363. MitRealm->KdcNames.ServerNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING));
  364. if (MitRealm->KdcNames.ServerNames == NULL)
  365. {
  366. Status = STATUS_INSUFFICIENT_RESOURCES;
  367. goto Cleanup;
  368. }
  369. MitRealm->KdcNames.ServerCount = NameCount;
  370. Where = KdcNames;
  371. for (Index2 = 0;Index2 < NameCount; Index2++)
  372. {
  373. RtlInitUnicodeString(
  374. &MitRealm->KdcNames.ServerNames[Index2],
  375. Where
  376. );
  377. // ugh. Didn't want to have to allocate, but keep it simple.
  378. MitRealm->KdcNames.ServerNames[Index2].Buffer =
  379. (LPWSTR) KerbAllocate(sizeof(WCHAR) * ((ULONG) wcslen(Where) + 2));
  380. if (NULL == MitRealm->KdcNames.ServerNames[Index2].Buffer)
  381. {
  382. Status = STATUS_INSUFFICIENT_RESOURCES;
  383. goto Cleanup;
  384. }
  385. wcscpy(MitRealm->KdcNames.ServerNames[Index2].Buffer, Where);
  386. Where += MitRealm->KdcNames.ServerNames[Index2].Length / sizeof(WCHAR) + 1;
  387. }
  388. KerbFree(KdcNames);
  389. KdcNames = NULL;
  390. }
  391. if (NameCount == 0)
  392. {
  393. MitRealm->Flags |= KERB_MIT_REALM_KDC_LOOKUP;
  394. }
  395. NameCount = 0;
  396. if ((KpasswdNames != NULL ) && (KpasswdNameSize != 0))
  397. {
  398. Where = KpasswdNames;
  399. NameCount ++;
  400. while (Where + wcslen(Where) + 1 - (KpasswdNames + KpasswdNameSize /sizeof(WCHAR)) > 0)
  401. {
  402. NameCount++;
  403. Where += wcslen(Where)+1;
  404. }
  405. MitRealm->KpasswdNames.ServerNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING));
  406. if (MitRealm->KpasswdNames.ServerNames == NULL)
  407. {
  408. Status = STATUS_INSUFFICIENT_RESOURCES;
  409. goto Cleanup;
  410. }
  411. MitRealm->KpasswdNames.ServerCount = NameCount;
  412. Where = KpasswdNames;
  413. for (Index2 = 0;Index2 < NameCount; Index2++)
  414. {
  415. RtlInitUnicodeString(
  416. &MitRealm->KpasswdNames.ServerNames[Index2],
  417. Where
  418. );
  419. // ugh. Didn't want to have to allocate, but keep it simple.
  420. MitRealm->KpasswdNames.ServerNames[Index2].Buffer =
  421. (LPWSTR) KerbAllocate(sizeof(WCHAR) * ((ULONG) wcslen(Where) + 2));
  422. if (NULL == MitRealm->KpasswdNames.ServerNames[Index2].Buffer)
  423. {
  424. Status = STATUS_INSUFFICIENT_RESOURCES;
  425. goto Cleanup;
  426. }
  427. wcscpy(MitRealm->KpasswdNames.ServerNames[Index2].Buffer, Where);
  428. Where += MitRealm->KpasswdNames.ServerNames[Index2].Length / sizeof(WCHAR) + 1;
  429. }
  430. KerbFree(KpasswdNames);
  431. KpasswdNames = NULL;
  432. }
  433. if (NameCount == 0)
  434. {
  435. MitRealm->Flags |= KERB_MIT_REALM_KPWD_LOOKUP;
  436. }
  437. KerbInsertListEntry(
  438. &MitRealm->Next,
  439. &KerbMitRealmList
  440. );
  441. MitRealm = NULL;
  442. } // ** FOR **
  443. Cleanup:
  444. if (fListLocked)
  445. {
  446. KerbUnlockList(&KerbMitRealmList);
  447. }
  448. if( DomainKey != NULL )
  449. {
  450. RegCloseKey( DomainKey );
  451. }
  452. if (KdcNames != NULL)
  453. {
  454. KerbFree(KdcNames);
  455. }
  456. if (KpasswdNames != NULL)
  457. {
  458. KerbFree(KpasswdNames);
  459. }
  460. if (AlternateRealmNames != NULL)
  461. {
  462. KerbFree(AlternateRealmNames);
  463. }
  464. if (MitRealm != NULL)
  465. {
  466. if (MitRealm->AlternateRealmNames != NULL)
  467. {
  468. #if 0 // note: embededded buffers are all enclosed within AlternateRealmNames[0]
  469. for(Index = 0 ; Index < MitRealm->RealmNameCount ; Index++)
  470. {
  471. if (MitRealm->AlternateRealmNames[Index].Buffer != NULL)
  472. {
  473. KerbFree(MitRealm->AlternateRealmNames[Index].Buffer);
  474. }
  475. }
  476. #else
  477. if (MitRealm->AlternateRealmNames[0].Buffer != NULL)
  478. {
  479. KerbFree(MitRealm->AlternateRealmNames[0].Buffer);
  480. }
  481. #endif
  482. KerbFree(MitRealm->AlternateRealmNames);
  483. }
  484. if (MitRealm->KdcNames.ServerNames != NULL)
  485. {
  486. LONG lIndex;
  487. for(lIndex = 0 ; lIndex < MitRealm->KdcNames.ServerCount ; lIndex++)
  488. {
  489. if (MitRealm->KdcNames.ServerNames[lIndex].Buffer != NULL)
  490. {
  491. KerbFree(MitRealm->KdcNames.ServerNames[lIndex].Buffer);
  492. }
  493. }
  494. KerbFree(MitRealm->KdcNames.ServerNames);
  495. }
  496. if (MitRealm->KpasswdNames.ServerNames != NULL)
  497. {
  498. LONG lIndex;
  499. for(lIndex = 0 ; lIndex < MitRealm->KpasswdNames.ServerCount ; lIndex++)
  500. {
  501. if (MitRealm->KpasswdNames.ServerNames[lIndex].Buffer != NULL)
  502. {
  503. KerbFree(MitRealm->KpasswdNames.ServerNames[lIndex].Buffer);
  504. }
  505. }
  506. KerbFree(MitRealm->KpasswdNames.ServerNames);
  507. }
  508. KerbFree(MitRealm);
  509. }
  510. return(Status);
  511. }
  512. //+-------------------------------------------------------------------------
  513. //
  514. // Function: KerbCleanupMitRealmList
  515. //
  516. // Synopsis: Frees the list of MIT realms
  517. //
  518. // Effects:
  519. //
  520. // Arguments:
  521. //
  522. // Requires:
  523. //
  524. // Returns:
  525. //
  526. // Notes:
  527. //
  528. //
  529. //--------------------------------------------------------------------------
  530. VOID
  531. KerbCleanupMitRealmList(
  532. )
  533. {
  534. PKERB_MIT_REALM MitRealm;
  535. BOOLEAN ListLocked = FALSE;
  536. KerbLockList(&KerbMitRealmList);
  537. ListLocked = TRUE;
  538. if (KerbMitRealmList.List.Flink == NULL)
  539. {
  540. goto Cleanup;
  541. }
  542. while (!IsListEmpty(&KerbMitRealmList.List))
  543. {
  544. MitRealm = CONTAINING_RECORD(
  545. KerbMitRealmList.List.Flink,
  546. KERB_MIT_REALM,
  547. Next
  548. );
  549. KerbReferenceListEntry(
  550. &KerbMitRealmList,
  551. &MitRealm->Next,
  552. TRUE
  553. );
  554. if (MitRealm->AlternateRealmNames != NULL)
  555. {
  556. if (MitRealm->AlternateRealmNames[0].Buffer != NULL)
  557. {
  558. KerbFree(MitRealm->AlternateRealmNames[0].Buffer);
  559. }
  560. KerbFree(MitRealm->AlternateRealmNames);
  561. }
  562. if (MitRealm->KdcNames.ServerNames != NULL)
  563. {
  564. LONG lIndex;
  565. for(lIndex = 0 ; lIndex < MitRealm->KdcNames.ServerCount ; lIndex++)
  566. {
  567. if (MitRealm->KdcNames.ServerNames[lIndex].Buffer != NULL)
  568. {
  569. KerbFree(MitRealm->KdcNames.ServerNames[lIndex].Buffer);
  570. }
  571. }
  572. KerbFree(MitRealm->KdcNames.ServerNames);
  573. }
  574. if (MitRealm->KpasswdNames.ServerNames != NULL)
  575. {
  576. LONG lIndex;
  577. for(lIndex = 0 ; lIndex < MitRealm->KpasswdNames.ServerCount ; lIndex++)
  578. {
  579. if (MitRealm->KpasswdNames.ServerNames[lIndex].Buffer != NULL)
  580. {
  581. KerbFree(MitRealm->KpasswdNames.ServerNames[lIndex].Buffer);
  582. }
  583. }
  584. KerbFree(MitRealm->KpasswdNames.ServerNames);
  585. }
  586. if (MitRealm->RealmName.Buffer != NULL)
  587. {
  588. MIDL_user_free(MitRealm->RealmName.Buffer);
  589. }
  590. KerbFree(MitRealm);
  591. }
  592. KerbUnlockList(&KerbMitRealmList);
  593. ListLocked = FALSE;
  594. //
  595. // Purge our old entries.
  596. //
  597. KerbCleanupBindingCache(FALSE);
  598. Cleanup:
  599. if ( ListLocked )
  600. {
  601. KerbUnlockList(&KerbMitRealmList);
  602. }
  603. }
  604. //+-------------------------------------------------------------------------
  605. //
  606. // Function: KerbLookupMitRealm
  607. //
  608. // Synopsis: Looks up an MIT realm name
  609. //
  610. // Effects:
  611. //
  612. // Arguments:
  613. //
  614. // Requires:
  615. //
  616. // Returns:
  617. //
  618. // Notes:
  619. //
  620. //
  621. //--------------------------------------------------------------------------
  622. BOOLEAN
  623. KerbLookupMitRealm(
  624. IN PUNICODE_STRING RealmName,
  625. OUT OPTIONAL PKERB_MIT_REALM* MitRealm,
  626. OUT OPTIONAL PBOOLEAN UsedAlternateName
  627. )
  628. {
  629. ULONG Index;
  630. PLIST_ENTRY ListEntry;
  631. PKERB_MIT_REALM CurrentRealm;
  632. BOOLEAN fReturn = FALSE;
  633. BOOLEAN fListLocked = FALSE;
  634. if (UsedAlternateName)
  635. {
  636. *UsedAlternateName = FALSE;
  637. }
  638. if (MitRealm)
  639. {
  640. *MitRealm = NULL;
  641. }
  642. if (RealmName->Length == 0)
  643. {
  644. goto Cleanup;
  645. }
  646. KerbLockList(&KerbMitRealmList);
  647. fListLocked = TRUE;
  648. for (ListEntry = KerbMitRealmList.List.Flink ;
  649. ListEntry != &KerbMitRealmList.List ;
  650. ListEntry = ListEntry->Flink )
  651. {
  652. CurrentRealm = CONTAINING_RECORD(ListEntry, KERB_MIT_REALM, Next);
  653. if (RtlEqualUnicodeString(
  654. RealmName,
  655. &CurrentRealm->RealmName,
  656. TRUE))
  657. {
  658. if (MitRealm)
  659. {
  660. *MitRealm = CurrentRealm;
  661. }
  662. fReturn = TRUE;
  663. goto Cleanup;
  664. }
  665. //
  666. // Check for an alternate name for the realm
  667. //
  668. for (Index = 0; Index < CurrentRealm->RealmNameCount ; Index++ )
  669. {
  670. if (RtlEqualUnicodeString(
  671. RealmName,
  672. &CurrentRealm->AlternateRealmNames[Index],
  673. TRUE))
  674. {
  675. if (UsedAlternateName)
  676. {
  677. *UsedAlternateName = TRUE;
  678. }
  679. if (MitRealm)
  680. {
  681. *MitRealm = CurrentRealm;
  682. }
  683. fReturn = TRUE;
  684. goto Cleanup;
  685. }
  686. }
  687. }
  688. Cleanup:
  689. if (fListLocked)
  690. {
  691. KerbUnlockList(&KerbMitRealmList);
  692. }
  693. return(fReturn);
  694. }
  695. ////////////////////////////////////////////////////////////////////
  696. //
  697. // Name: KerbWatchMITKey
  698. //
  699. // Synopsis: Sets RegNotifyChangeKeyValue() on MIT key and
  700. // utilizes thread pool to wait on changes to this
  701. // registry key. Enables dynamic changing of MIT
  702. // realms as this function will also be callback
  703. // if the registry key is modified.
  704. //
  705. // Arguments: pCtxt is actually a HANDLE to an event. This event
  706. // will be triggered when key is modified.
  707. //
  708. // Notes:
  709. //
  710. void
  711. KerbWatchMITKey(PVOID pCtxt,
  712. BOOLEAN fWaitStatus)
  713. {
  714. NTSTATUS Status = STATUS_SUCCESS;
  715. ULONG Error;
  716. KerbCleanupMitRealmList();
  717. Status = KerbReadMitRealmList();
  718. if (!NT_SUCCESS(Status))
  719. {
  720. D_DebugLog((DEB_ERROR,"Debug reading MIT realm list failed: 0x%x\n", Status));
  721. }
  722. if (NULL != hKerbMITRealmWaitEvent)
  723. {
  724. Error = RegNotifyChangeKeyValue(
  725. KerbMITRealmRootKey,
  726. TRUE,
  727. REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
  728. hKerbMITRealmWaitEvent,
  729. TRUE);
  730. if (ERROR_SUCCESS != Error)
  731. {
  732. D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", Status));
  733. // we're tanked now. No further notifications, so get this one
  734. }
  735. }
  736. return;
  737. }
  738. //+-------------------------------------------------------------------------
  739. //
  740. // Function: KerbInitializeMitRealmList
  741. //
  742. // Synopsis: Loads the list of MIT realms from the registry
  743. //
  744. // Effects: Initialize and links domains to KerbMitRealmList
  745. //
  746. // Arguments:
  747. //
  748. // Requires:
  749. //
  750. // Returns:
  751. //
  752. // Notes:
  753. //
  754. //
  755. //--------------------------------------------------------------------------
  756. NTSTATUS
  757. KerbInitializeMitRealmList(
  758. )
  759. {
  760. ULONG Disposition;
  761. ULONG Error;
  762. HKEY RootKey = NULL;
  763. NTSTATUS Status = STATUS_SUCCESS;
  764. //
  765. // Open the domains root key - if it is not there, so be it.
  766. //
  767. Error = RegCreateKeyEx(
  768. HKEY_LOCAL_MACHINE,
  769. KERB_DOMAINS_KEY,
  770. 0,
  771. NULL,
  772. 0,
  773. KEY_READ,
  774. NULL,
  775. &RootKey,
  776. &Disposition);
  777. if (ERROR_SUCCESS != Error)
  778. {
  779. D_DebugLog((DEB_WARN,"Failed to open MIT realm key: 0x%x\n", Status));
  780. Status = STATUS_UNSUCCESSFUL;
  781. goto Cleanup;
  782. }
  783. //
  784. // Initialize the list
  785. //
  786. Status = KerbInitializeList( &KerbMitRealmList, MIT_REALM_LIST_LOCK_ENUM );
  787. if (!NT_SUCCESS(Status))
  788. {
  789. D_DebugLog((DEB_ERROR, "Intialization of MIT realm list failed - 0x%x\n", Status));
  790. goto Cleanup;
  791. }
  792. hKerbMITRealmWaitEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
  793. if (NULL == hKerbMITRealmWaitEvent)
  794. {
  795. D_DebugLog((DEB_ERROR, "CreateEvent for MIT realm list wait failed - 0x%x\n", GetLastError()));
  796. Status = STATUS_NO_MEMORY;
  797. goto Cleanup;
  798. }
  799. KerbMITRealmRootKey = RootKey;
  800. RootKey = NULL;
  801. //
  802. // read in the list and setup the RegNotify
  803. //
  804. KerbWatchMITKey(NULL, FALSE);
  805. hKerbMITRealmWaitObject = RegisterWaitForSingleObjectEx(
  806. hKerbMITRealmWaitEvent,
  807. KerbWatchMITKey,
  808. NULL,
  809. INFINITE,
  810. 0 // dwFlags
  811. );
  812. Cleanup:
  813. if( RootKey != NULL )
  814. {
  815. RegCloseKey( RootKey );
  816. }
  817. return Status;
  818. }
  819. //+-------------------------------------------------------------------------
  820. //
  821. // Function: KerbUninitializeMitRealmList
  822. //
  823. // Synopsis: Loads the list of MIT realms from the registry
  824. //
  825. // Effects: Initialize and links domains to KerbMitRealmList
  826. //
  827. // Arguments:
  828. //
  829. // Requires:
  830. //
  831. // Returns:
  832. //
  833. // Notes:
  834. //
  835. //
  836. //--------------------------------------------------------------------------
  837. VOID
  838. KerbUninitializeMitRealmList(
  839. )
  840. {
  841. if( hKerbMITRealmWaitObject )
  842. UnregisterWait( hKerbMITRealmWaitObject );
  843. if( hKerbMITRealmWaitEvent )
  844. CloseHandle( hKerbMITRealmWaitEvent );
  845. KerbCleanupMitRealmList();
  846. return;
  847. }
  848. //+-------------------------------------------------------------------------
  849. //
  850. // Function: KerbLookupMitSrvRecords
  851. //
  852. // Synopsis: Looks up MIT KDCs / Kpassword in DNS
  853. //
  854. // Effects: Builds MIT_SERVER_LIST for specified realm, and adds it to
  855. // MIT REALM LIST
  856. //
  857. // Arguments:
  858. //
  859. // Requires:
  860. //
  861. // Returns:
  862. //
  863. // Notes:
  864. //
  865. //
  866. //--------------------------------------------------------------------------
  867. NTSTATUS
  868. KerbLookupMitSrvRecords(IN PKERB_MIT_REALM RealmEntry,
  869. IN BOOLEAN Kpasswd,
  870. IN BOOLEAN UseTcp
  871. )
  872. {
  873. ANSI_STRING DnsRecordName;
  874. ANSI_STRING AnsiRealmName;
  875. HANDLE SrvContext = NULL;
  876. BOOLEAN ListLocked = FALSE;
  877. NTSTATUS Status = STATUS_SUCCESS;
  878. ULONG AddressCount = 0, SrvCount = 0;
  879. ULONG Index = 0, uBuff = 0;
  880. LPSOCKET_ADDRESS Addresses = NULL;
  881. NET_API_STATUS NetApiStatus = NERR_Success;
  882. LPSTR pDnsName[MAX_SRV_RECORDS];
  883. PKERB_MIT_SERVER_LIST ServerList = NULL;
  884. PUNICODE_STRING ServerNames = NULL;
  885. TimeStamp CurrentTime, Timeout;
  886. //
  887. // Test to see if we need to do a lookup, or if its time to try again
  888. //
  889. if (RealmEntry->LastLookup.QuadPart != 0 )
  890. {
  891. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime );
  892. KerbSetTimeInMinutes(&Timeout, DNS_LOOKUP_TIMEOUT);
  893. if (KerbGetTime(RealmEntry->LastLookup) + KerbGetTime(Timeout) < KerbGetTime(CurrentTime))
  894. {
  895. return STATUS_SUCCESS;
  896. }
  897. }
  898. // Kpasswd only uses UDP
  899. if (Kpasswd)
  900. {
  901. UseTcp = FALSE;
  902. }
  903. RtlInitAnsiString(&DnsRecordName,NULL);
  904. RtlInitAnsiString(&AnsiRealmName,NULL);
  905. DnsRecordName.Length = (RealmEntry->RealmName.Length / sizeof(WCHAR)) + DNS_MAX_PREFIX + 1;
  906. DnsRecordName.MaximumLength = DnsRecordName.Length;
  907. SafeAllocaAllocate(DnsRecordName.Buffer, DnsRecordName.Length);
  908. if (NULL == DnsRecordName.Buffer)
  909. {
  910. return STATUS_INSUFFICIENT_RESOURCES;
  911. }
  912. RtlUnicodeStringToAnsiString(
  913. &AnsiRealmName,
  914. &RealmEntry->RealmName,
  915. TRUE
  916. );
  917. sprintf(DnsRecordName.Buffer,
  918. "%s%s%s",
  919. (Kpasswd ? DNS_KPASSWD : DNS_KERBEROS),
  920. (UseTcp ? DNS_TCP : DNS_UDP),
  921. AnsiRealmName.Buffer
  922. );
  923. NetApiStatus = NetpSrvOpen(
  924. DnsRecordName.Buffer,
  925. 0,
  926. &SrvContext
  927. );
  928. if (NERR_Success != NetApiStatus)
  929. {
  930. D_DebugLog((DEB_WARN,
  931. "No SRV records for MIT Realm %wZ - %x\n",
  932. RealmEntry->RealmName,
  933. NetApiStatus
  934. ));
  935. Status = STATUS_SUCCESS;
  936. goto Cleanup;
  937. }
  938. // Loop and update server list for realm
  939. for (SrvCount = 0; SrvCount < MAX_SRV_RECORDS; SrvCount++)
  940. {
  941. NetApiStatus = NetpSrvNext(
  942. SrvContext,
  943. &AddressCount,
  944. &Addresses,
  945. &pDnsName[SrvCount]
  946. );
  947. if (NERR_Success != NetApiStatus)
  948. {
  949. if( ERROR_NO_MORE_ITEMS == NetApiStatus) // we're through
  950. {
  951. NetApiStatus = NERR_Success;
  952. break;
  953. }
  954. D_DebugLog((DEB_ERROR, "NetpSrvNext failed: %s - %x\n",DnsRecordName.Buffer, NetApiStatus));
  955. Status = NetApiStatus;
  956. goto Cleanup;
  957. }
  958. }
  959. KerbLockList(&KerbMitRealmList);
  960. ListLocked = TRUE;
  961. // Loop through available server names, and copy
  962. if (Kpasswd)
  963. {
  964. ServerList = &RealmEntry->KpasswdNames;
  965. }
  966. else
  967. {
  968. ServerList = &RealmEntry->KdcNames;
  969. }
  970. // reg entries are always at beginning of server list.
  971. uBuff = ( SrvCount * sizeof(UNICODE_STRING));
  972. ServerNames = (PUNICODE_STRING) KerbAllocate(uBuff);
  973. if (NULL == ServerNames)
  974. {
  975. Status = STATUS_INSUFFICIENT_RESOURCES;
  976. goto Cleanup;
  977. }
  978. for (Index = 0; Index < SrvCount;Index++)
  979. {
  980. if (!KerbMbStringToUnicodeString(
  981. &ServerNames[Index ],
  982. pDnsName[Index]
  983. ))
  984. {
  985. D_DebugLog((DEB_ERROR,"KerbConvertMbStringToUnicodeString failed!\n"));
  986. continue; // let's keep going. Maybe we're not hosed.
  987. }
  988. }
  989. KerbFreeServerNames(ServerList);
  990. ServerList->ServerCount = SrvCount;
  991. ServerList->ServerNames = ServerNames;
  992. RealmEntry->Flags
  993. &= ~( Kpasswd ? KERB_MIT_REALM_KPWD_LOOKUP : KERB_MIT_REALM_KDC_LOOKUP );
  994. Cleanup:
  995. // always update realm entry, even on failure
  996. if (!ListLocked)
  997. {
  998. KerbLockList(&KerbMitRealmList);
  999. ListLocked = TRUE;
  1000. }
  1001. GetSystemTimeAsFileTime((PFILETIME) &RealmEntry->LastLookup);
  1002. if (ListLocked)
  1003. {
  1004. KerbUnlockList(&KerbMitRealmList);
  1005. }
  1006. if (AnsiRealmName.Buffer != NULL)
  1007. {
  1008. RtlFreeAnsiString(&AnsiRealmName);
  1009. }
  1010. SafeAllocaFree(DnsRecordName.Buffer);
  1011. if (SrvContext != NULL)
  1012. {
  1013. NetpSrvClose(SrvContext);
  1014. }
  1015. return Status;
  1016. }
  1017. //+-------------------------------------------------------------------------
  1018. //
  1019. // Function: KerbFreeServerNames
  1020. //
  1021. // Synopsis: Frees server names PUNICODE_STRING array
  1022. //
  1023. // Effects:
  1024. //
  1025. //
  1026. // Arguments:
  1027. //
  1028. // Requires:
  1029. //
  1030. // Returns:
  1031. //
  1032. // Notes:
  1033. //
  1034. //
  1035. //--------------------------------------------------------------------------
  1036. void
  1037. KerbFreeServerNames(PKERB_MIT_SERVER_LIST ServerList)
  1038. {
  1039. LONG Index = 0;
  1040. for (Index = 0; Index < ServerList->ServerCount; Index++)
  1041. {
  1042. if (ServerList->ServerNames[Index].Buffer != NULL)
  1043. {
  1044. KerbFree(ServerList->ServerNames[Index].Buffer);
  1045. }
  1046. }
  1047. KerbFree(ServerList->ServerNames); // free UNICODE_STRING array
  1048. }
  1049. //+-------------------------------------------------------------------------
  1050. //
  1051. // Function: KerbLookupMitRealmWithSrvLookup
  1052. //
  1053. // Synopsis: Frees server names PUNICODE_STRING array
  1054. //
  1055. // Effects:
  1056. //
  1057. //
  1058. // Arguments:
  1059. //
  1060. // Requires:
  1061. //
  1062. // Returns:
  1063. //
  1064. // Notes:
  1065. //
  1066. //
  1067. //--------------------------------------------------------------------------
  1068. BOOLEAN
  1069. KerbLookupMitRealmWithSrvLookup(PUNICODE_STRING RealmName,
  1070. PKERB_MIT_REALM* MitRealm,
  1071. BOOLEAN Kpasswd,
  1072. BOOLEAN UseTcp)
  1073. {
  1074. BOOLEAN UsedAlternateName, fRet = FALSE;
  1075. NTSTATUS Status;
  1076. fRet = KerbLookupMitRealm(
  1077. RealmName,
  1078. MitRealm,
  1079. &UsedAlternateName
  1080. );
  1081. //
  1082. // Found an MIT realm. See if its time to check on SRV records
  1083. //
  1084. if ( fRet )
  1085. {
  1086. if ((((*MitRealm)->Flags & KERB_MIT_REALM_KDC_LOOKUP) && !Kpasswd ) ||
  1087. (((*MitRealm)->Flags & KERB_MIT_REALM_KPWD_LOOKUP) && Kpasswd ))
  1088. {
  1089. Status = KerbLookupMitSrvRecords(
  1090. (*MitRealm),
  1091. Kpasswd,
  1092. UseTcp
  1093. );
  1094. if (Status != STATUS_SUCCESS)
  1095. {
  1096. D_DebugLog((DEB_TRACE, "KerbLookupMitRealmWIthSrvLookup failed - %x\n", Status));
  1097. }
  1098. }
  1099. }
  1100. return fRet;
  1101. }