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.

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