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.

1311 lines
33 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // File: secdata.cxx
  4. //
  5. // Contents: Global data and methods on it.
  6. //
  7. //
  8. // History:
  9. //
  10. //------------------------------------------------------------------------
  11. #include "kdcsvr.hxx"
  12. #include <kpasswd.h>
  13. ///////////////////////////////////////////////////////////////
  14. //
  15. //
  16. // Global data
  17. //
  18. // This is all the security information that gets cached.
  19. CSecurityData SecData;
  20. CAuthenticatorList * Authenticators;
  21. CAuthenticatorList * ReplayDetect;
  22. ///////////////////////////////////////////////////////////////
  23. //
  24. //
  25. // Prototypes
  26. //
  27. fLsaPolicyChangeNotificationCallback KdcPolicyChangeCallback;
  28. //+-------------------------------------------------------------------------
  29. //
  30. // Function: KdcPolicyChangeCallBack
  31. //
  32. // Synopsis: Function that gets called when policy changes
  33. //
  34. // Effects: Changes policy variables
  35. //
  36. // Arguments: MonitorInfoClass - class of data that changed
  37. //
  38. // Requires:
  39. //
  40. // Returns:
  41. //
  42. // Notes:
  43. //
  44. //
  45. //--------------------------------------------------------------------------
  46. VOID
  47. KdcPolicyChangeCallBack(
  48. IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
  49. )
  50. {
  51. NTSTATUS Status;
  52. WCHAR Class[10];
  53. TRACE(KDC, KdcPolicyChangeCallBack, DEB_FUNCTION);
  54. Status = SecData.ReloadPolicy(MonitorInfoClass);
  55. if (!NT_SUCCESS(Status))
  56. {
  57. _itow(MonitorInfoClass, Class, 10 );
  58. ReportServiceEvent(
  59. EVENTLOG_ERROR_TYPE,
  60. KDCEVENT_POLICY_UPDATE_FAILED,
  61. sizeof(NTSTATUS),
  62. &Status,
  63. 1, // number of strings
  64. Class
  65. );
  66. }
  67. }
  68. //+-------------------------------------------------------------------------
  69. //
  70. // Function: CSecurityData::ReloadPolicy
  71. //
  72. // Synopsis: Reloads a particular piece of policy
  73. //
  74. // Effects:
  75. //
  76. // Arguments:
  77. //
  78. // Requires:
  79. //
  80. // Returns:
  81. //
  82. // Notes:
  83. //
  84. //
  85. //--------------------------------------------------------------------------
  86. NTSTATUS
  87. CSecurityData::ReloadPolicy(
  88. IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
  89. )
  90. {
  91. NTSTATUS Status = STATUS_SUCCESS;
  92. PLSAPR_POLICY_DOMAIN_INFORMATION DomainPolicy = NULL;
  93. PLSAPR_POLICY_INFORMATION LocalPolicy = NULL;
  94. WCHAR Class[10];
  95. TRACE(KDC, CSecurityData::ReloadPolicy, DEB_FUNCTION);
  96. //
  97. // Ignore changes to non-kerberos ticket information
  98. //
  99. switch(MonitorInfoClass) {
  100. case PolicyNotifyDomainKerberosTicketInformation:
  101. Status = LsarQueryDomainInformationPolicy(
  102. GlobalPolicyHandle,
  103. PolicyDomainKerberosTicketInformation,
  104. &DomainPolicy
  105. );
  106. if (!NT_SUCCESS(Status))
  107. {
  108. goto Cleanup;
  109. }
  110. break;
  111. case PolicyNotifyAuditEventsInformation:
  112. Status = LsarQueryInformationPolicy(
  113. GlobalPolicyHandle,
  114. PolicyAuditEventsInformation,
  115. &LocalPolicy
  116. );
  117. if (!NT_SUCCESS(Status))
  118. {
  119. goto Cleanup;
  120. }
  121. break;
  122. default:
  123. return(STATUS_SUCCESS);
  124. }
  125. //
  126. // Update the changed information in the KDCs global data structures.
  127. //
  128. //
  129. // Current policy defaults, see KirkSol/JBrezak
  130. // [Kerberos Policy]
  131. // MaxTicketAge=10 ;Maximum User Ticket Lifetime (hours)
  132. // MaxRenewAge=7 ;Maximum lifetime that a user tickeet can be renewed (days)
  133. // MaxServiceAge=60 ;Maximum Service Ticket Lifetime (minutes)
  134. // MaxClockSkew=5 ;Maximum tolerance for synchronization of computer clocks (minutes)
  135. // TicketValidateClient=1 ;Enforce user logon restrictions
  136. WriteLock();
  137. switch(MonitorInfoClass) {
  138. case PolicyNotifyDomainKerberosTicketInformation:
  139. DebugLog((DEB_TRACE, "MaxServiceTicketAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart));
  140. DebugLog((DEB_TRACE, "MaxTicketAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart));
  141. DebugLog((DEB_TRACE, "MaxRenewAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge.QuadPart));
  142. DebugLog((DEB_TRACE, "MaxClockSkew : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart));
  143. // Validate parameters
  144. if ((DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart <= (LONGLONG) -1) ||
  145. (DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart <= (LONGLONG) -1) ||
  146. (DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge.QuadPart <= (LONGLONG) -1) ||
  147. (DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart <= (LONGLONG) -1) ||
  148. (DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart == (LONGLONG) 0) ||
  149. (DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart == (LONGLONG) 0) )
  150. {
  151. _itow(MonitorInfoClass, Class, 10 );
  152. DebugLog((DEB_ERROR, "Policy update failed!\n"));
  153. ReportServiceEvent(
  154. EVENTLOG_ERROR_TYPE,
  155. KDCEVENT_POLICY_UPDATE_FAILED,
  156. sizeof(NTSTATUS),
  157. &Status,
  158. 1, // number of strings
  159. Class
  160. );
  161. }
  162. else
  163. {
  164. _KDC_TgsTicketLifespan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge;
  165. _KDC_TgtTicketLifespan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge;
  166. _KDC_TicketRenewSpan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge;
  167. //
  168. // never allow the skew window to drop down to zero, which prevents
  169. // logon locally to the DC. The allowed skew window is at least
  170. // 10 seconds for now
  171. //
  172. SkewTime.QuadPart = max(DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart, 10 * 10000000);
  173. }
  174. // Update domain policy flags. Don't depend on the flags keeping in sync
  175. // with the kerberos internal flags
  176. if ( DomainPolicy->PolicyDomainKerbTicketInfo.AuthenticationOptions &
  177. POLICY_KERBEROS_VALIDATE_CLIENT)
  178. {
  179. _KDC_Flags |= AUTH_REQ_VALIDATE_CLIENT;
  180. }
  181. else
  182. {
  183. _KDC_Flags &= ~AUTH_REQ_VALIDATE_CLIENT;
  184. }
  185. break;
  186. case PolicyNotifyAuditEventsInformation:
  187. if ((LocalPolicy->PolicyAuditEventsInfo.AuditingMode) &&
  188. (LocalPolicy->PolicyAuditEventsInfo.MaximumAuditEventCount > AuditCategoryAccountLogon))
  189. {
  190. if (LocalPolicy->PolicyAuditEventsInfo.EventAuditingOptions[AuditCategoryAccountLogon] & POLICY_AUDIT_EVENT_SUCCESS )
  191. {
  192. _KDC_AuditEvents |= KDC_AUDIT_AS_SUCCESS | KDC_AUDIT_TGS_SUCCESS | KDC_AUDIT_MAP_SUCCESS;
  193. }
  194. else
  195. {
  196. _KDC_AuditEvents &= ~(KDC_AUDIT_AS_SUCCESS | KDC_AUDIT_TGS_SUCCESS | KDC_AUDIT_MAP_SUCCESS);
  197. }
  198. if (LocalPolicy->PolicyAuditEventsInfo.EventAuditingOptions[AuditCategoryAccountLogon] & POLICY_AUDIT_EVENT_FAILURE )
  199. {
  200. _KDC_AuditEvents |= KDC_AUDIT_AS_FAILURE | KDC_AUDIT_TGS_FAILURE | KDC_AUDIT_MAP_FAILURE;
  201. }
  202. else
  203. {
  204. _KDC_AuditEvents &= ~(KDC_AUDIT_AS_FAILURE | KDC_AUDIT_TGS_FAILURE | KDC_AUDIT_MAP_FAILURE);
  205. }
  206. }
  207. break;
  208. }
  209. Unlock();
  210. Cleanup:
  211. if (DomainPolicy != NULL)
  212. {
  213. LsaIFree_LSAPR_POLICY_DOMAIN_INFORMATION (
  214. PolicyDomainKerberosTicketInformation,
  215. DomainPolicy);
  216. }
  217. if (LocalPolicy != NULL)
  218. {
  219. LsaIFree_LSAPR_POLICY_INFORMATION(
  220. PolicyAuditEventsInformation,
  221. LocalPolicy);
  222. }
  223. return(Status);
  224. }
  225. //+-------------------------------------------------------------------------
  226. //
  227. // Function: CSecurityData::SetForestRoot
  228. //
  229. // Synopsis: Sets the forest root
  230. //
  231. // Effects:
  232. //
  233. // Arguments:
  234. //
  235. // Requires:
  236. //
  237. // Returns:
  238. //
  239. // Notes:
  240. //
  241. //
  242. //--------------------------------------------------------------------------
  243. NTSTATUS
  244. CSecurityData::SetForestRoot(
  245. IN PUNICODE_STRING NewForestRoot
  246. )
  247. {
  248. NTSTATUS Status;
  249. UNICODE_STRING Temp;
  250. WriteLock();
  251. RtlCopyMemory(
  252. &Temp,
  253. &_ForestRoot,
  254. sizeof(UNICODE_STRING)
  255. );
  256. Status = KerbDuplicateString(
  257. &_ForestRoot,
  258. NewForestRoot
  259. );
  260. // on alloc failure, just keep old version as it will never change
  261. if (!NT_SUCCESS(Status))
  262. {
  263. RtlCopyMemory(
  264. &_ForestRoot,
  265. &Temp,
  266. sizeof(UNICODE_STRING)
  267. );
  268. }
  269. else
  270. {
  271. KerbFreeString(&Temp);
  272. }
  273. _KDC_IsForestRoot = IsOurRealm(&_ForestRoot);
  274. Unlock();
  275. return Status;
  276. }
  277. ////////////////////////////////////////////////////////////////////
  278. //
  279. // Name: CSecurityData::CSecurityData
  280. //
  281. // Synopsis: Constructor.
  282. //
  283. // Arguments: <none>
  284. //
  285. // Notes: .
  286. //
  287. CSecurityData::CSecurityData()
  288. {
  289. TRACE(KDC, CSecurityData::CSecurityData, DEB_FUNCTION);
  290. RtlInitUnicodeString(
  291. &_MachineName,
  292. NULL
  293. );
  294. RtlInitUnicodeString(
  295. &_SamMachineName,
  296. NULL
  297. );
  298. RtlInitUnicodeString(
  299. &_MachineUpn,
  300. NULL
  301. );
  302. RtlInitUnicodeString(
  303. &_RealmName,
  304. NULL
  305. );
  306. RtlInitUnicodeString(
  307. &_KDC_Name,
  308. NULL
  309. );
  310. RtlInitUnicodeString(
  311. &_KDC_FullName,
  312. NULL
  313. );
  314. RtlInitUnicodeString(
  315. &_KDC_FullDnsName,
  316. NULL
  317. );
  318. RtlInitUnicodeString(
  319. &_KDC_FullKdcName,
  320. NULL
  321. );
  322. RtlInitUnicodeString(
  323. &_ForestRoot,
  324. NULL
  325. );
  326. _KerbRealmName = NULL;
  327. _KerbDnsRealmName = NULL;
  328. _KrbtgtServiceName = NULL;
  329. _KpasswdServiceName = NULL;
  330. RtlZeroMemory(
  331. &_KrbtgtTicketInfo,
  332. sizeof(KDC_TICKET_INFO)
  333. );
  334. _KrbtgtTicketInfoValid = FALSE;
  335. _KDC_CrossForestEnabled = FALSE;
  336. _KDC_IsForestRoot = FALSE;
  337. _fMonitorInitialized = FALSE;
  338. }
  339. //+---------------------------------------------------------------------------
  340. //
  341. // Member: CSecurityData::InitLock
  342. //
  343. // Synopsis: Initializes the lock in the CSecurityData class.
  344. //
  345. // Effects:
  346. //
  347. // Arguments: (none)
  348. //
  349. // Returns: STATUS_SUCCESS or error code
  350. //
  351. // History: 2001-07-02 JSchwart created
  352. //
  353. // Notes: This must be called before any other method of CSecurityData.
  354. // It needs to be separate from Init since SAM can call KDC routines
  355. // that use the global SecData before Init has been called in the
  356. // KDC ServiceMain.
  357. //
  358. //----------------------------------------------------------------------------
  359. NTSTATUS
  360. CSecurityData::InitLock(
  361. VOID
  362. )
  363. {
  364. NTSTATUS Status = STATUS_SUCCESS;
  365. ASSERT(!_fMonitorInitialized);
  366. __try {
  367. RtlInitializeResource(&_Monitor);
  368. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  369. Status = GetExceptionCode();
  370. }
  371. if (NT_SUCCESS(Status))
  372. {
  373. _fMonitorInitialized = TRUE;
  374. }
  375. return Status;
  376. }
  377. //+---------------------------------------------------------------------------
  378. //
  379. // Member: CSecurityData::Init
  380. //
  381. // Synopsis: Initializes the global data.
  382. //
  383. // Effects: Allocates memory
  384. //
  385. // Arguments: (none)
  386. //
  387. // Returns: STATUS_SUCCESS or error code
  388. //
  389. // Signals: May raise exception on out of memory.
  390. //
  391. // History: 4-02-93 WadeR Created
  392. //
  393. // Notes: This must be called after InitLock and before any other
  394. // method of CSecurityData. It gets data from the registry, the
  395. // domain object, and the kdc.ini file.
  396. //
  397. //----------------------------------------------------------------------------
  398. NTSTATUS
  399. CSecurityData::Init()
  400. {
  401. TRACE(KDC, CSecurityData::Init, DEB_FUNCTION);
  402. NTSTATUS Status;
  403. UNICODE_STRING TempString;
  404. WCHAR TempMachineName[CNLEN+1];
  405. ULONG MachineNameLength = CNLEN+1;
  406. LARGE_INTEGER MaxAuthenticatorAge;
  407. PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
  408. UNICODE_STRING KadminName;
  409. UNICODE_STRING ChangePwName;
  410. D_DebugLog(( DEB_TRACE, "Entered CSecurityData::Init()\n" ));
  411. DsysAssert(_fMonitorInitialized);
  412. //
  413. // Get the domain name and ID from the registry
  414. //
  415. Status = KerbDuplicateString(
  416. &_RealmName,
  417. &GlobalDomainName
  418. );
  419. if (!NT_SUCCESS(Status))
  420. {
  421. goto Cleanup;
  422. }
  423. if (!KERB_SUCCESS(KerbConvertUnicodeStringToRealm(
  424. &_KerbRealmName,
  425. &GlobalDomainName)))
  426. {
  427. Status = STATUS_INSUFFICIENT_RESOURCES;
  428. goto Cleanup;
  429. }
  430. //
  431. // Construct the KDC Name from the realm and the suffix.
  432. //
  433. RtlInitUnicodeString(
  434. &TempString,
  435. KDC_PRINCIPAL_NAME
  436. );
  437. Status = KerbDuplicateString(
  438. &_KDC_Name,
  439. &TempString
  440. );
  441. if (!NT_SUCCESS(Status))
  442. {
  443. goto Cleanup;
  444. }
  445. if (!GetComputerName(
  446. TempMachineName,
  447. &MachineNameLength
  448. ))
  449. {
  450. Status = STATUS_BUFFER_TOO_SMALL;
  451. goto Cleanup;
  452. }
  453. RtlInitUnicodeString(
  454. &TempString,
  455. TempMachineName
  456. );
  457. Status = KerbDuplicateString(
  458. &_MachineName,
  459. &TempString
  460. );
  461. if (!NT_SUCCESS(Status))
  462. {
  463. goto Cleanup;
  464. }
  465. Status = LsaIQueryInformationPolicyTrusted(
  466. PolicyDnsDomainInformation,
  467. &PolicyInfo
  468. );
  469. if (!NT_SUCCESS(Status))
  470. {
  471. goto Cleanup;
  472. }
  473. //
  474. // WAS BUG: this DNS name may have a trailing '.' - if so, strip it off
  475. //
  476. if (PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length >= sizeof(WCHAR))
  477. {
  478. if (PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Buffer[ -1 + PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length / sizeof(WCHAR) ] == L'.')
  479. {
  480. PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length -= sizeof(WCHAR);
  481. }
  482. }
  483. Status = KerbDuplicateString(
  484. &_DnsRealmName,
  485. (PUNICODE_STRING) &PolicyInfo->PolicyDnsDomainInfo.DnsDomainName
  486. );
  487. if (!NT_SUCCESS(Status))
  488. {
  489. goto Cleanup;
  490. }
  491. Status = RtlUpcaseUnicodeString(
  492. &_DnsRealmName,
  493. &_DnsRealmName,
  494. FALSE
  495. );
  496. if (!NT_SUCCESS(Status))
  497. {
  498. goto Cleanup;
  499. }
  500. if (!KERB_SUCCESS(KerbConvertUnicodeStringToRealm(
  501. &_KerbDnsRealmName,
  502. &_DnsRealmName)))
  503. {
  504. Status = STATUS_INSUFFICIENT_RESOURCES;
  505. goto Cleanup;
  506. }
  507. //
  508. // Build a sam style machine name
  509. //
  510. _SamMachineName.Length = _MachineName.Length + sizeof(WCHAR);
  511. _SamMachineName.MaximumLength = _SamMachineName.Length + sizeof(WCHAR);
  512. _SamMachineName.Buffer = (LPWSTR) MIDL_user_allocate(_SamMachineName.MaximumLength);
  513. if (_SamMachineName.Buffer == NULL)
  514. {
  515. Status = STATUS_INSUFFICIENT_RESOURCES;
  516. goto Cleanup;
  517. }
  518. RtlCopyMemory(
  519. _SamMachineName.Buffer,
  520. _MachineName.Buffer,
  521. _MachineName.Length
  522. );
  523. _SamMachineName.Buffer[_MachineName.Length / sizeof(WCHAR)] = L'$';
  524. _SamMachineName.Buffer[_SamMachineName.Length / sizeof(WCHAR)] = L'\0';
  525. //
  526. // Build the machine UPN: [email protected]
  527. //
  528. _MachineUpn.Length = _MachineName.Length + 2 * sizeof(WCHAR) + _DnsRealmName.Length;
  529. _MachineUpn.MaximumLength = _MachineUpn.Length + sizeof(WCHAR);
  530. _MachineUpn.Buffer = (LPWSTR) MIDL_user_allocate(_MachineUpn.MaximumLength);
  531. if (_MachineUpn.Buffer == NULL)
  532. {
  533. Status = STATUS_INSUFFICIENT_RESOURCES;
  534. goto Cleanup;
  535. }
  536. RtlCopyMemory(
  537. _MachineUpn.Buffer,
  538. _MachineName.Buffer,
  539. _MachineName.Length
  540. );
  541. _MachineUpn.Buffer[_MachineName.Length / sizeof(WCHAR)] = L'$';
  542. _MachineUpn.Buffer[1+_MachineName.Length / sizeof(WCHAR)] = L'@';
  543. RtlCopyMemory(
  544. _MachineUpn.Buffer + _MachineName.Length / sizeof(WCHAR) + 2 ,
  545. _DnsRealmName.Buffer,
  546. _DnsRealmName.Length
  547. );
  548. _MachineUpn.Buffer[_MachineUpn.Length / sizeof(WCHAR)] = L'\0';
  549. if (!KERB_SUCCESS(KerbBuildFullServiceName(
  550. &_RealmName,
  551. &_KDC_Name,
  552. &_KDC_FullName
  553. )))
  554. {
  555. Status = STATUS_INSUFFICIENT_RESOURCES;
  556. goto Cleanup;
  557. }
  558. if (!KERB_SUCCESS(KerbBuildFullServiceName(
  559. &_DnsRealmName,
  560. &_KDC_Name,
  561. &_KDC_FullDnsName
  562. )))
  563. {
  564. Status = STATUS_INSUFFICIENT_RESOURCES;
  565. goto Cleanup;
  566. }
  567. //
  568. // Build the full kdc name - a kerberos style name
  569. //
  570. _KDC_FullKdcName.Length = _KDC_Name.Length + _DnsRealmName.Length + sizeof(WCHAR);
  571. _KDC_FullKdcName.MaximumLength = _KDC_FullKdcName.Length + sizeof(WCHAR);
  572. _KDC_FullKdcName.Buffer = (LPWSTR) MIDL_user_allocate(_KDC_FullDnsName.MaximumLength);
  573. if (_KDC_FullKdcName.Buffer == NULL)
  574. {
  575. Status = STATUS_INSUFFICIENT_RESOURCES;
  576. goto Cleanup;
  577. }
  578. RtlCopyMemory(
  579. _KDC_FullKdcName.Buffer,
  580. _KDC_Name.Buffer,
  581. _KDC_Name.Length
  582. );
  583. _KDC_FullKdcName.Buffer[_KDC_Name.Length / sizeof(WCHAR)] = L'/';
  584. RtlCopyMemory(
  585. _KDC_FullKdcName.Buffer + 1 + _KDC_Name.Length / sizeof(WCHAR),
  586. _DnsRealmName.Buffer,
  587. _DnsRealmName.Length
  588. );
  589. _KDC_FullKdcName.Buffer[_KDC_FullKdcName.Length / sizeof(WCHAR)] = L'\0';
  590. D_DebugLog((DEB_TRACE, "_KDC_Name='%wZ', MachineName='%wZ'\n",
  591. &_KDC_Name,
  592. &_MachineName ));
  593. if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
  594. &_DnsRealmName,
  595. &_KDC_Name,
  596. KRB_NT_SRV_INST,
  597. &_KrbtgtServiceName
  598. )))
  599. {
  600. Status = STATUS_INSUFFICIENT_RESOURCES;
  601. goto Cleanup;
  602. }
  603. //
  604. // Build the kdc name for kadmin/changepw.
  605. //
  606. RtlInitUnicodeString(
  607. &KadminName,
  608. KERB_KPASSWD_NAME
  609. );
  610. RtlInitUnicodeString(
  611. &ChangePwName,
  612. L"changepw"
  613. );
  614. if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
  615. &ChangePwName,
  616. &KadminName,
  617. KRB_NT_SRV_INST,
  618. &_KpasswdServiceName
  619. )))
  620. {
  621. Status = STATUS_INSUFFICIENT_RESOURCES;
  622. goto Cleanup;
  623. }
  624. Status = LoadParameters(GlobalAccountDomainHandle);
  625. if (!NT_SUCCESS(Status))
  626. {
  627. DebugLog((DEB_ERROR,"Failed to load parameters: 0x%x\n",Status));
  628. goto Cleanup;
  629. }
  630. //
  631. // Create the authenticators.
  632. //
  633. //
  634. // In reality, set skew time to 5 minutes and same for authenticators.
  635. //
  636. SkewTime.QuadPart = (LONGLONG) 10000000 * 60 * 5;
  637. MaxAuthenticatorAge = SkewTime;
  638. //
  639. // Create the authenticator list
  640. //
  641. Authenticators = new CAuthenticatorList( MaxAuthenticatorAge, 1 );
  642. if (Authenticators == NULL)
  643. {
  644. Status = STATUS_INSUFFICIENT_RESOURCES;
  645. goto Cleanup;
  646. }
  647. Status = Authenticators->Init();
  648. if (!NT_SUCCESS(Status))
  649. {
  650. goto Cleanup;
  651. }
  652. //
  653. // Setup a list to track failed requests - we don't fail the
  654. // same request twice for the timeout time
  655. //
  656. ReplayDetect = new CAuthenticatorList( MaxAuthenticatorAge, 1 );
  657. if (ReplayDetect == NULL)
  658. {
  659. Status = STATUS_INSUFFICIENT_RESOURCES;
  660. goto Cleanup;
  661. }
  662. Status = ReplayDetect->Init();
  663. if (!NT_SUCCESS(Status))
  664. {
  665. goto Cleanup;
  666. }
  667. //
  668. // Setup a list to track potential canidates for fwd'ing to PDC
  669. //
  670. Status = AsNegCacheInit();
  671. if (!NT_SUCCESS(Status))
  672. {
  673. goto Cleanup;
  674. }
  675. //
  676. // Register for policy callbacks
  677. //
  678. Status = LsaIRegisterPolicyChangeNotificationCallback(
  679. KdcPolicyChangeCallBack,
  680. PolicyNotifyDomainKerberosTicketInformation
  681. );
  682. if (NT_SUCCESS(Status))
  683. {
  684. Status = LsaIRegisterPolicyChangeNotificationCallback(
  685. KdcPolicyChangeCallBack,
  686. PolicyNotifyAuditEventsInformation
  687. );
  688. }
  689. if (!NT_SUCCESS(Status))
  690. {
  691. DebugLog((DEB_ERROR,"Failed to register for policy changes: 0x%x\n",Status));
  692. goto Cleanup;
  693. }
  694. Status = UpdateKrbtgtTicketInfo();
  695. if (!NT_SUCCESS(Status))
  696. {
  697. goto Cleanup;
  698. }
  699. Cleanup:
  700. if (PolicyInfo != NULL)
  701. {
  702. LsaIFree_LSAPR_POLICY_INFORMATION(
  703. PolicyDnsDomainInformation,
  704. PolicyInfo
  705. );
  706. }
  707. return(Status);
  708. }
  709. //+---------------------------------------------------------------------------
  710. //
  711. // Member: CSecurityData::Cleanup
  712. //
  713. // Synopsis: Cleans up the object
  714. //
  715. // Effects: Frees memory
  716. //
  717. // Arguments: (none)
  718. //
  719. // History: 4-02-93 WadeR Created
  720. //
  721. // Notes:
  722. //
  723. //----------------------------------------------------------------------------
  724. VOID
  725. CSecurityData::Cleanup()
  726. {
  727. TRACE(KDC, CSecurityData::Cleanup, DEB_FUNCTION);
  728. _KrbtgtTicketInfoValid = FALSE;
  729. KerbFreeString(&_RealmName);
  730. KerbFreeString(&_KDC_Name);
  731. KerbFreeString(&_KDC_FullName);
  732. KerbFreeString(&_KDC_FullDnsName);
  733. KerbFreeString(&_KDC_FullKdcName);
  734. KerbFreeString(&_MachineName);
  735. KerbFreeString(&_SamMachineName);
  736. KerbFreeString(&_MachineUpn);
  737. KerbFreeString(&_DnsRealmName);
  738. KerbFreeRealm(&_KerbRealmName);
  739. KerbFreeRealm(&_KerbDnsRealmName);
  740. KerbFreeKdcName(&_KrbtgtServiceName);
  741. KerbFreeKdcName(&_KpasswdServiceName);
  742. if (Authenticators != NULL)
  743. {
  744. delete Authenticators;
  745. Authenticators = NULL;
  746. }
  747. if (ReplayDetect != NULL)
  748. {
  749. delete ReplayDetect;
  750. ReplayDetect = NULL;
  751. }
  752. LsaIUnregisterAllPolicyChangeNotificationCallback(
  753. KdcPolicyChangeCallBack
  754. );
  755. }
  756. //+---------------------------------------------------------------------------
  757. //
  758. // Member: CSecurityData::~CSecurityData
  759. //
  760. // Synopsis: Destructor
  761. //
  762. // Effects: Frees memory
  763. //
  764. // Arguments: (none)
  765. //
  766. // History: 4-02-93 WadeR Created
  767. //
  768. // Notes:
  769. //
  770. //----------------------------------------------------------------------------
  771. CSecurityData::~CSecurityData()
  772. {
  773. TRACE(KDC, CSecurityData::~CSecurityData, DEB_FUNCTION);
  774. Cleanup();
  775. //
  776. // This doesn't happen during Cleanup() because we want to
  777. // make sure it only happens once.
  778. //
  779. if (_fMonitorInitialized)
  780. {
  781. RtlDeleteResource(&_Monitor);
  782. }
  783. }
  784. NTSTATUS
  785. CSecurityData::LoadParameters(SAMPR_HANDLE DomainHandle)
  786. {
  787. NTSTATUS Status = STATUS_SUCCESS;
  788. LARGE_INTEGER OneHour, EightHours, TenHours;
  789. TRACE(KDC, CSecurityData::LoadParameters, DEB_FUNCTION);
  790. OneHour.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 1;
  791. EightHours.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 8;
  792. TenHours.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 10;
  793. // New internal defaults according to JBrezak. 7/28/99
  794. //
  795. // Initialize Tgt lifetime to 10 hours.
  796. //
  797. _KDC_TgtTicketLifespan = TenHours;
  798. //
  799. // Initialize ticket max renew time to one hour.
  800. //
  801. _KDC_TicketRenewSpan = OneHour;
  802. //
  803. // Initialize Tgs lifetime to one hour.
  804. //
  805. _KDC_TgsTicketLifespan = OneHour;
  806. //
  807. // Initialize domain password replication skew tolerance to 60 minutes.
  808. //
  809. _KDC_DomainPasswordReplSkew.QuadPart = (LONGLONG) 60*60*10000000;
  810. //
  811. // Initialize restriciton lifetime to 20 minutes
  812. //
  813. _KDC_RestrictionLifetime.QuadPart = (LONGLONG) 20*60*10000000;
  814. //
  815. // Default authentication flags
  816. //
  817. _KDC_Flags = AUTH_REQ_ALLOW_FORWARDABLE |
  818. AUTH_REQ_ALLOW_PROXIABLE |
  819. AUTH_REQ_ALLOW_RENEWABLE |
  820. AUTH_REQ_ALLOW_NOADDRESS |
  821. AUTH_REQ_ALLOW_ENC_TKT_IN_SKEY |
  822. AUTH_REQ_ALLOW_VALIDATE |
  823. AUTH_REQ_VALIDATE_CLIENT |
  824. AUTH_REQ_OK_AS_DELEGATE |
  825. AUTH_REQ_ALLOW_S4U_DELEGATE;
  826. _KDC_AuditEvents = 0;
  827. //
  828. // Get kerberos policy information
  829. //
  830. Status = ReloadPolicy(
  831. PolicyNotifyDomainKerberosTicketInformation
  832. );
  833. if (!NT_SUCCESS(Status))
  834. {
  835. if ((Status != STATUS_NOT_FOUND) && (Status != STATUS_OBJECT_NAME_NOT_FOUND))
  836. {
  837. DebugLog((DEB_ERROR,"Failed to reload kerberos ticket policy: 0x%x\n",Status));
  838. goto Cleanup;
  839. }
  840. Status = STATUS_SUCCESS;
  841. }
  842. //
  843. // Get audit information
  844. //
  845. Status = ReloadPolicy(
  846. PolicyNotifyAuditEventsInformation
  847. );
  848. if (!NT_SUCCESS(Status))
  849. {
  850. if (Status != STATUS_NOT_FOUND)
  851. {
  852. DebugLog((DEB_ERROR,"Failed to query audit event info: 0x%x\n",Status));
  853. goto Cleanup;
  854. }
  855. Status = STATUS_SUCCESS;
  856. }
  857. Cleanup:
  858. #if DBG
  859. DebugShowState();
  860. #endif
  861. return(Status);
  862. }
  863. //+-------------------------------------------------------------------------
  864. //
  865. // Function: CSecurityData::GetKrbtgtTicketInfo
  866. //
  867. // Synopsis: Duplicates ticket info for krbtgt account
  868. //
  869. // Effects:
  870. //
  871. // Arguments:
  872. //
  873. // Requires:
  874. //
  875. // Returns:
  876. //
  877. // Notes:
  878. //
  879. //
  880. //--------------------------------------------------------------------------
  881. KERBERR
  882. CSecurityData::GetKrbtgtTicketInfo(
  883. OUT PKDC_TICKET_INFO TicketInfo
  884. )
  885. {
  886. KERBERR KerbErr = KDC_ERR_NONE;
  887. ULONG CredentialSize;
  888. RtlZeroMemory(
  889. TicketInfo,
  890. sizeof(KDC_TICKET_INFO)
  891. );
  892. ReadLock();
  893. if (!_KrbtgtTicketInfoValid)
  894. {
  895. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  896. goto Cleanup;
  897. }
  898. //
  899. // Duplicate the cached copy of the KRBTGT information
  900. //
  901. *TicketInfo = _KrbtgtTicketInfo;
  902. TicketInfo->Passwords = NULL;
  903. TicketInfo->OldPasswords = NULL;
  904. TicketInfo->TrustSid = NULL;
  905. TicketInfo->AccountName.Buffer = NULL;
  906. if (!NT_SUCCESS(KerbDuplicateString(
  907. &TicketInfo->AccountName,
  908. &_KrbtgtTicketInfo.AccountName
  909. )))
  910. {
  911. KerbErr = KRB_ERR_GENERIC;
  912. goto Cleanup;
  913. }
  914. KerbErr = KdcDuplicateCredentials(
  915. &TicketInfo->Passwords,
  916. &CredentialSize,
  917. _KrbtgtTicketInfo.Passwords,
  918. FALSE // don't marshall
  919. );
  920. if (!KERB_SUCCESS(KerbErr))
  921. {
  922. goto Cleanup;
  923. }
  924. KerbErr = KdcDuplicateCredentials(
  925. &TicketInfo->OldPasswords,
  926. &CredentialSize,
  927. _KrbtgtTicketInfo.OldPasswords,
  928. FALSE // don't marshall
  929. );
  930. Cleanup:
  931. Unlock();
  932. if (!KERB_SUCCESS(KerbErr))
  933. {
  934. FreeTicketInfo(TicketInfo);
  935. }
  936. return(KerbErr);
  937. }
  938. //+-------------------------------------------------------------------------
  939. //
  940. // Function: CSecurityData::UpdateKrbtgtTicketInfo
  941. //
  942. // Synopsis: Triggers an update of the krbtgt ticket info
  943. //
  944. // Effects:
  945. //
  946. // Arguments:
  947. //
  948. // Requires:
  949. //
  950. // Returns:
  951. //
  952. // Notes:
  953. //
  954. //
  955. //--------------------------------------------------------------------------
  956. NTSTATUS
  957. CSecurityData::UpdateKrbtgtTicketInfo(
  958. VOID
  959. )
  960. {
  961. NTSTATUS Status = STATUS_SUCCESS;
  962. KERBERR KerbErr;
  963. KDC_TICKET_INFO NewTicketInfo = {0};
  964. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  965. KERB_EXT_ERROR ExtendedError; // dummy var
  966. WriteLock();
  967. _KrbtgtTicketInfoValid = FALSE;
  968. KerbErr = KdcGetTicketInfo(
  969. SecData.KdcServiceName(),
  970. 0, // no lookup flags
  971. FALSE, // do not restrict user accounts (user2user)
  972. NULL, // no principal name
  973. NULL, // no realm
  974. &NewTicketInfo,
  975. &ExtendedError, // dummy
  976. NULL, // no user handle
  977. USER_ALL_PASSWORDLASTSET,
  978. 0L, // no extended fields
  979. &UserInfo,
  980. NULL // no group membership
  981. );
  982. if (KERB_SUCCESS(KerbErr))
  983. {
  984. FreeTicketInfo(
  985. &_KrbtgtTicketInfo
  986. );
  987. _KrbtgtTicketInfo = NewTicketInfo;
  988. _KrbtgtTicketInfoValid = TRUE;
  989. _KrbtgtPasswordLastSet = UserInfo->I1.PasswordLastSet;
  990. SamIFree_UserInternal6Information( UserInfo );
  991. }
  992. else
  993. {
  994. Status = KerbMapKerbError(KerbErr);
  995. }
  996. Unlock();
  997. return(Status);
  998. }
  999. //+-------------------------------------------------------------------------
  1000. //
  1001. // Function: KdcAccountChangeNotificationRoutine
  1002. //
  1003. // Synopsis: Receives notification of changes to interesting accounts
  1004. //
  1005. // Effects: updatees cached krbtgt information
  1006. //
  1007. // Arguments:
  1008. //
  1009. // Requires:
  1010. //
  1011. // Returns:
  1012. //
  1013. // Notes:
  1014. //
  1015. //
  1016. //--------------------------------------------------------------------------
  1017. NTSTATUS
  1018. KdcAccountChangeNotification (
  1019. IN PSID DomainSid,
  1020. IN SECURITY_DB_DELTA_TYPE DeltaType,
  1021. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  1022. IN ULONG ObjectRid,
  1023. IN OPTIONAL PUNICODE_STRING ObjectName,
  1024. IN PLARGE_INTEGER ModifiedCount,
  1025. IN PSAM_DELTA_DATA DeltaData OPTIONAL
  1026. )
  1027. {
  1028. NTSTATUS Status;
  1029. //
  1030. // We are only interested in the krbtgt account
  1031. //
  1032. if (ObjectRid != DOMAIN_USER_RID_KRBTGT)
  1033. {
  1034. return(STATUS_SUCCESS);
  1035. }
  1036. Status = SecData.UpdateKrbtgtTicketInfo();
  1037. if (!NT_SUCCESS(Status))
  1038. {
  1039. DebugLog((DEB_ERROR,"Failed to update krbtgt ticket info: 0x%x\n",Status));
  1040. }
  1041. return(Status);
  1042. }
  1043. #if DBG
  1044. ////////////////////////////////////////////////////////////////////////////
  1045. //
  1046. // Some debugging functions.
  1047. //
  1048. void
  1049. CSecurityData::DebugShowState(void)
  1050. {
  1051. TRACE(KDC, CSecurityData::DebugShowState, DEB_FUNCTION);
  1052. PrintTime(DEB_TRACE, " TGT Ticket lifespan\t", &_KDC_TgtTicketLifespan );
  1053. PrintTime(DEB_TRACE, " Ticket Renew Span\t",&_KDC_TicketRenewSpan );
  1054. D_DebugLog((DEB_TRACE, " Blank Addresses?\t%s\n",(_KDC_Flags & AUTH_REQ_ALLOW_NOADDRESS ? "Yes" : "No")));
  1055. D_DebugLog((DEB_TRACE, " Proxies? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_PROXIABLE ? "Yes" : "No")));
  1056. D_DebugLog((DEB_TRACE, " Renewable? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_RENEWABLE ? "Yes" : "No")));
  1057. D_DebugLog((DEB_TRACE, " Postdated? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_POSTDATE ? "Yes" : "No")));
  1058. D_DebugLog((DEB_TRACE, " Forwardable? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_FORWARDABLE ? "Yes" : "No")));
  1059. }
  1060. NTSTATUS
  1061. CSecurityData::DebugGetState( DWORD * KDCFlags,
  1062. TimeStamp * MaxLifespan,
  1063. TimeStamp * MaxRenewSpan)
  1064. {
  1065. TRACE(KDC, CSecurityData::DebugGetState, DEB_FUNCTION);
  1066. *KDCFlags = _KDC_Flags;
  1067. *MaxLifespan = _KDC_TgtTicketLifespan;
  1068. *MaxRenewSpan = _KDC_TicketRenewSpan;
  1069. return(STATUS_SUCCESS);
  1070. }
  1071. NTSTATUS
  1072. CSecurityData::DebugSetState( DWORD KDCFlags,
  1073. TimeStamp MaxLifespan,
  1074. TimeStamp MaxRenewSpan)
  1075. {
  1076. TRACE(KDC, CSecurityData::DebugSetState, DEB_FUNCTION);
  1077. _KDC_Flags = KDC_AUTH_STATE(KDCFlags);
  1078. _KDC_AuditEvents = KDC_AUDIT_STATE(KDCFlags);
  1079. _KDC_TgtTicketLifespan = MaxLifespan;
  1080. _KDC_TicketRenewSpan = MaxRenewSpan;
  1081. return(STATUS_SUCCESS);
  1082. }
  1083. #endif // DBG