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.

2191 lines
53 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: KDC.CXX
  8. //
  9. // Contents: Base part of the KDC. Global vars, main functions, init
  10. //
  11. //
  12. // History:
  13. //
  14. //------------------------------------------------------------------------
  15. #include "kdcsvr.hxx"
  16. extern "C" {
  17. #include <lmserver.h>
  18. #include <srvann.h>
  19. #include <nlrepl.h>
  20. #include <dsgetdc.h>
  21. }
  22. #include "rpcif.h"
  23. #include "sockutil.h"
  24. #include "kdctrace.h"
  25. #include "fileno.h"
  26. #define FILENO FILENO_KDC
  27. VOID
  28. KdcPolicyChangeCallBack(
  29. IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
  30. );
  31. VOID
  32. KdcMyStoreWaitHandler(
  33. PVOID pVoid,
  34. BOOLEAN fTimeout
  35. );
  36. //
  37. // Global data
  38. //
  39. KDC_STATE KdcState = Stopped; // used to signal when
  40. // authenticated RPC is
  41. // ready to use - e.g.
  42. // spmgr has found the
  43. // kdc
  44. SERVICE_STATUS_HANDLE hService;
  45. SERVICE_STATUS SStatus;
  46. UNICODE_STRING GlobalDomainName;
  47. UNICODE_STRING GlobalKerberosName;
  48. UNICODE_STRING GlobalKdcName;
  49. PKERB_INTERNAL_NAME GlobalKpasswdName = NULL;
  50. //
  51. // Sids used to build other sids quickly.
  52. //
  53. PSID GlobalDomainSid;
  54. PSID GlobalBuiltInSid;
  55. PSID GlobalEveryoneSid;
  56. PSID GlobalAuthenticatedUserSid;
  57. PSID GlobalThisOrganizationSid;
  58. PSID GlobalOtherOrganizationSid;
  59. LSAPR_HANDLE GlobalPolicyHandle = NULL;
  60. SAMPR_HANDLE GlobalAccountDomainHandle = NULL;
  61. SAMPR_HANDLE GlobalBuiltInDomainHandle = NULL;
  62. BYTE GlobalLocalhostAddress[4];
  63. HANDLE KdcGlobalDsPausedWaitHandle = NULL;
  64. HANDLE KdcGlobalDsEventHandle = NULL;
  65. BOOL KdcGlobalAvoidPdcOnWan = FALSE;
  66. BOOL KdcGlobalGlobalSafeBoot = FALSE;
  67. #if DBG
  68. LARGE_INTEGER tsIn,tsOut;
  69. #endif
  70. // Global KDC values - can be overridden by registry vlaues
  71. const DWORD KdcUseClientAddressesDefault = FALSE;
  72. const DWORD KdcDontCheckAddressesDefault = TRUE;
  73. const DWORD KdcNewConnectionTimeoutDefault = 10;
  74. const DWORD KdcExistingConnectionTimeoutDefault = 50;
  75. const DWORD KdcMaxDatagramReplySizeDefault = KERB_MAX_DATAGRAM_REPLY_SIZE;
  76. const DWORD KdcExtraLogLevelDefault = LOG_DEFAULT;
  77. const DWORD KdcIssueForwardedTicketsDefault = TRUE;
  78. #if DBG
  79. const ULONG KdcInfoLevelDefault = DEB_ERROR;
  80. #else
  81. const ULONG KdcInfoLevelDefault = 0;
  82. #endif
  83. DWORD KdcIssueForwardedTickets = KdcIssueForwardedTicketsDefault;
  84. DWORD KdcUseClientAddresses = KdcUseClientAddressesDefault;
  85. DWORD KdcDontCheckAddresses = KdcDontCheckAddressesDefault;
  86. DWORD KdcNewConnectionTimeout = KdcNewConnectionTimeoutDefault;
  87. DWORD KdcExistingConnectionTimeout = KdcExistingConnectionTimeoutDefault;
  88. DWORD KdcGlobalMaxDatagramReplySize = KdcMaxDatagramReplySizeDefault;
  89. DWORD KdcExtraLogLevel = KdcExtraLogLevelDefault;
  90. HANDLE hKdcHandles[MAX_KDC_HANDLE] = {0};
  91. // This keeps a registry key handle to the HKLM\System\CCSet\Services\Kdc key
  92. HKEY hKdcParams = NULL;
  93. #ifdef ROGUE_DC
  94. HKEY hKdcRogueKey = NULL;
  95. #endif
  96. HANDLE hKdcWait = NULL;
  97. //
  98. // Prototypes
  99. //
  100. CRITICAL_SECTION ApiCriticalSection;
  101. ULONG CurrentApiCallers;
  102. //
  103. // MIDL_xxx wrappers to make safealloc happy
  104. //
  105. //
  106. // kdc preferred crypt list
  107. //
  108. PKERB_CRYPT_LIST kdc_pPreferredCryptList = NULL;
  109. PKERB_CRYPT_LIST kdc_pMitPrincipalPreferredCryptList = NULL;
  110. PVOID
  111. KdcAllocate(SIZE_T size)
  112. {
  113. return MIDL_user_allocate(size);
  114. }
  115. VOID
  116. KdcFree(PVOID buff)
  117. {
  118. MIDL_user_free(buff);
  119. }
  120. AUTHZ_RESOURCE_MANAGER_HANDLE KdcAuthzRM = NULL;
  121. //--------------------------------------------------------------------
  122. //
  123. // Name: KdcComputeAuthzGroups
  124. //
  125. // Synopsis: Authz callback for add groups to authz client context
  126. //
  127. // Effects:
  128. //
  129. // Arguments:
  130. //
  131. //
  132. // Requires:
  133. //
  134. // Returns:
  135. //
  136. // Notes:
  137. //
  138. //
  139. //---
  140. BOOL
  141. KdcComputeAuthzGroups(
  142. IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
  143. IN PVOID Args,
  144. OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
  145. OUT PDWORD pSidCount,
  146. OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
  147. OUT PDWORD pRestrictedSidCount
  148. )
  149. {
  150. PKDC_AUTHZ_INFO AuthzInfo = (PKDC_AUTHZ_INFO) Args;
  151. *pSidAttrArray = (PSID_AND_ATTRIBUTES) AuthzInfo->SidAndAttributes;
  152. *pSidCount = AuthzInfo->SidCount;
  153. *pRestrictedSidAttrArray = NULL;
  154. *pRestrictedSidCount = 0;
  155. return (TRUE);
  156. }
  157. //--------------------------------------------------------------------
  158. //
  159. // Name: KdcFreeAuthzGroups
  160. //
  161. // Synopsis: Basically a no-op, as we already have a copy of the
  162. // sids
  163. //
  164. // Effects:
  165. //
  166. // Arguments:
  167. //
  168. //
  169. // Requires:
  170. //
  171. // Returns:
  172. //
  173. //---
  174. VOID
  175. KdcFreeAuthzGroups(IN PSID_AND_ATTRIBUTES pSidAttrArray)
  176. {
  177. return;
  178. }
  179. //--------------------------------------------------------------------
  180. //
  181. // Name: KdcInitializeAuthzRM
  182. //
  183. // Synopsis: Validate that S4U caller has access to expand groups
  184. //
  185. // Effects: Use Authz to check client context.
  186. //
  187. // Arguments: S4UClientName - ClientName from S4U PA Data
  188. // PAC - Resultant PAC (signed w/? key)
  189. //
  190. // Requires:
  191. //
  192. // Returns: KDC_ERR_ or KRB_AP_ERR errors only
  193. //
  194. // Notes: Free client name and realm w/
  195. //
  196. //
  197. //---
  198. NTSTATUS
  199. KdcInitializeAuthzRM()
  200. {
  201. if (!AuthzInitializeResourceManager(
  202. 0,
  203. NULL,
  204. KdcComputeAuthzGroups,
  205. KdcFreeAuthzGroups,
  206. L"KDC",
  207. &KdcAuthzRM
  208. ))
  209. {
  210. DebugLog((DEB_ERROR, "AuthzInitializeRm failed %x\n", GetLastError()));
  211. return STATUS_UNSUCCESSFUL;
  212. }
  213. return STATUS_SUCCESS;
  214. }
  215. VOID
  216. KdcFreeAuthzRm()
  217. {
  218. if (!AuthzFreeResourceManager(KdcAuthzRM))
  219. {
  220. DebugLog((DEB_ERROR, "AuthzFreeResourceManager failed %x\n", GetLastError()));
  221. }
  222. }
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Function: UpdateStatus
  226. //
  227. // Synopsis: Updates the KDC's service status with the service controller
  228. //
  229. // Effects:
  230. //
  231. // Arguments:
  232. //
  233. // History:
  234. //
  235. // Notes:
  236. //
  237. //----------------------------------------------------------------------------
  238. BOOLEAN
  239. UpdateStatus(DWORD dwState)
  240. {
  241. TRACE(KDC, UpdateStatus, DEB_FUNCTION);
  242. SStatus.dwCurrentState = dwState;
  243. if ((dwState == SERVICE_START_PENDING) || (dwState == SERVICE_STOP_PENDING))
  244. {
  245. SStatus.dwCheckPoint++;
  246. SStatus.dwWaitHint = 10000;
  247. }
  248. else
  249. {
  250. SStatus.dwCheckPoint = 0;
  251. SStatus.dwWaitHint = 0;
  252. }
  253. if (!SetServiceStatus(hService, &SStatus)) {
  254. DebugLog((DEB_ERROR,"(%x)Failed to set service status: %d\n",GetLastError()));
  255. return(FALSE);
  256. }
  257. return(TRUE);
  258. }
  259. //+---------------------------------------------------------------------------
  260. //
  261. // Function: Handler
  262. //
  263. // Synopsis: Process and respond to a control signal from the service
  264. // controller.
  265. //
  266. // Effects:
  267. //
  268. // Arguments:
  269. //
  270. // History:
  271. //
  272. // Notes:
  273. //
  274. //----------------------------------------------------------------------------
  275. void
  276. Handler(DWORD dwControl)
  277. {
  278. TRACE(KDC, Handler, DEB_FUNCTION);
  279. switch (dwControl)
  280. {
  281. case SERVICE_CONTROL_STOP:
  282. ShutDown( L"Service" );
  283. break;
  284. default:
  285. D_DebugLog((DEB_WARN, "Ignoring SC message %d\n",dwControl));
  286. break;
  287. }
  288. }
  289. BOOLEAN
  290. KdcWaitForSamService(
  291. VOID
  292. )
  293. /*++
  294. Routine Description:
  295. This procedure waits for the SAM service to start and to complete
  296. all its initialization.
  297. Arguments:
  298. Return Value:
  299. TRUE : if the SAM service is successfully starts.
  300. FALSE : if the SAM service can't start.
  301. --*/
  302. {
  303. NTSTATUS Status;
  304. DWORD WaitStatus;
  305. UNICODE_STRING EventName;
  306. HANDLE EventHandle;
  307. OBJECT_ATTRIBUTES EventAttributes;
  308. //
  309. // open SAM event
  310. //
  311. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  312. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  313. Status = NtOpenEvent( &EventHandle,
  314. SYNCHRONIZE|EVENT_MODIFY_STATE,
  315. &EventAttributes );
  316. if ( !NT_SUCCESS(Status)) {
  317. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  318. //
  319. // SAM hasn't created this event yet, let us create it now.
  320. // SAM opens this event to set it.
  321. //
  322. Status = NtCreateEvent(
  323. &EventHandle,
  324. SYNCHRONIZE|EVENT_MODIFY_STATE,
  325. &EventAttributes,
  326. NotificationEvent,
  327. FALSE // The event is initially not signaled
  328. );
  329. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  330. Status == STATUS_OBJECT_NAME_COLLISION ) {
  331. //
  332. // second chance, if the SAM created the event before we
  333. // do.
  334. //
  335. Status = NtOpenEvent( &EventHandle,
  336. SYNCHRONIZE|EVENT_MODIFY_STATE,
  337. &EventAttributes );
  338. }
  339. }
  340. if ( !NT_SUCCESS(Status)) {
  341. //
  342. // could not make the event handle
  343. //
  344. DebugLog((DEB_ERROR,
  345. "KdcWaitForSamService couldn't make the event handle : "
  346. "%lx\n", Status));
  347. return( FALSE );
  348. }
  349. }
  350. //
  351. // Loop waiting.
  352. //
  353. for (;;) {
  354. WaitStatus = WaitForSingleObject( EventHandle,
  355. 5*1000 ); // 5 Seconds
  356. if ( WaitStatus == WAIT_TIMEOUT ) {
  357. DebugLog((DEB_WARN,
  358. "KdcWaitForSamService 5-second timeout (Rewaiting)\n" ));
  359. if (!UpdateStatus( SERVICE_START_PENDING )) {
  360. (VOID) NtClose( EventHandle );
  361. return FALSE;
  362. }
  363. continue;
  364. } else if ( WaitStatus == WAIT_OBJECT_0 ) {
  365. break;
  366. } else {
  367. DebugLog((DEB_ERROR,
  368. "KdcWaitForSamService: error %ld %ld\n",
  369. GetLastError(),
  370. WaitStatus ));
  371. (VOID) NtClose( EventHandle );
  372. return FALSE;
  373. }
  374. }
  375. (VOID) NtClose( EventHandle );
  376. return TRUE;
  377. }
  378. VOID
  379. KdcDsNotPaused(
  380. IN PVOID Context,
  381. IN BOOLEAN TimedOut
  382. )
  383. /*++
  384. Routine Description:
  385. Worker routine that gets called when the DS is no longer paused.
  386. Arguments:
  387. None.
  388. Return Value:
  389. None.
  390. --*/
  391. {
  392. NTSTATUS NtStatus = STATUS_SUCCESS;
  393. //
  394. // Tell the kerberos client that we are a DC.
  395. //
  396. NtStatus = KerbKdcCallBack();
  397. if ( !NT_SUCCESS(NtStatus) )
  398. {
  399. D_DebugLog((DEB_ERROR,"Can't tell Kerberos that we're a DC 0x%x\n", NtStatus ));
  400. goto Cleanup;
  401. }
  402. NtStatus = I_NetLogonSetServiceBits( DS_KDC_FLAG, DS_KDC_FLAG );
  403. if ( !NT_SUCCESS(NtStatus) )
  404. {
  405. D_DebugLog((DEB_ERROR,"Can't tell netlogon we're started 0x%x\n", NtStatus ));
  406. goto Cleanup;
  407. }
  408. D_DebugLog((DEB_TRACE,"Ds is no longer paused\n"));
  409. Cleanup:
  410. UNREFERENCED_PARAMETER( Context );
  411. UNREFERENCED_PARAMETER( TimedOut );
  412. }
  413. BOOLEAN
  414. KdcRegisterToWaitForDS(
  415. VOID
  416. )
  417. /*++
  418. Routine Description:
  419. This procedure registers to wait for the DS to start and to complete
  420. all its initialization. The main reason we do this is because we don't
  421. want to start doing kerberos authentications because we don't know that
  422. the DS has the latest db. It needs to check with all the existing Dc's
  423. out there to see if there's any db merges to be done. When the
  424. DS_SYNCED_EVENT_NAME is set, we're ready.
  425. Arguments:
  426. Return Value:
  427. TRUE : if the register to wait succeeded
  428. FALSE : if the register to wait didn't succeed.
  429. --*/
  430. {
  431. BOOLEAN fRet = FALSE;
  432. //
  433. // open the DS event
  434. //
  435. KdcGlobalDsEventHandle = OpenEvent( SYNCHRONIZE,
  436. FALSE,
  437. DS_SYNCED_EVENT_NAME_W);
  438. if ( KdcGlobalDsEventHandle == NULL)
  439. {
  440. //
  441. // could not open the event handle
  442. //
  443. D_DebugLog((DEB_ERROR,"KdcRegisterToWaitForDS couldn't open the event handle\n"));
  444. goto Cleanup;
  445. }
  446. if ( !RegisterWaitForSingleObject(
  447. &KdcGlobalDsPausedWaitHandle,
  448. KdcGlobalDsEventHandle,
  449. KdcDsNotPaused, // Callback routine
  450. NULL, // No context
  451. INFINITE, // Wait forever
  452. WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) )
  453. {
  454. D_DebugLog((DEB_ERROR, "KdcRegisterToWaitForDS: Cannot register for DS Synced callback 0x%x\n", GetLastError()));
  455. goto Cleanup;
  456. }
  457. fRet = TRUE;
  458. Cleanup:
  459. return fRet;
  460. }
  461. //+-------------------------------------------------------------------------
  462. //
  463. // Function: KdcOpenEvent
  464. //
  465. // Synopsis: Just like the Win32 function, except that it allows
  466. // for names at the root of the namespace.
  467. //
  468. // Effects:
  469. //
  470. // Arguments:
  471. //
  472. // Requires:
  473. //
  474. // Returns:
  475. //
  476. // Notes: The code was copied from private\windows\base\client\synch.c
  477. // and the base directory was changed to NULL
  478. //
  479. //--------------------------------------------------------------------------
  480. HANDLE
  481. APIENTRY
  482. KdcOpenEvent(
  483. DWORD DesiredAccess,
  484. BOOL bInheritHandle,
  485. LPWSTR lpName
  486. )
  487. {
  488. TRACE(KDC, KdcOpenEvent, DEB_FUNCTION);
  489. OBJECT_ATTRIBUTES Obja;
  490. UNICODE_STRING ObjectName;
  491. NTSTATUS Status;
  492. HANDLE Object;
  493. if ( !lpName ) {
  494. SetLastError(ERROR_INVALID_PARAMETER);
  495. return NULL;
  496. }
  497. RtlInitUnicodeString(&ObjectName,lpName);
  498. InitializeObjectAttributes(
  499. &Obja,
  500. &ObjectName,
  501. (bInheritHandle ? OBJ_INHERIT : 0),
  502. NULL,
  503. NULL
  504. );
  505. Status = NtCreateEvent(
  506. &Object,
  507. DesiredAccess,
  508. &Obja,
  509. NotificationEvent,
  510. (BOOLEAN) FALSE // The event is initially not signaled
  511. );
  512. if ( !NT_SUCCESS(Status)) {
  513. //
  514. // If the event already exists, the server beat us to creating it.
  515. // Just open it.
  516. //
  517. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  518. Status == STATUS_OBJECT_NAME_COLLISION ) {
  519. Status = NtOpenEvent( &Object,
  520. DesiredAccess,
  521. &Obja );
  522. }
  523. }
  524. if ( !NT_SUCCESS(Status) ) {
  525. SetLastError(RtlNtStatusToDosError( Status ));
  526. return NULL;
  527. }
  528. return Object;
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Function: KdcStartEvent
  533. //
  534. // Synopsis: sets the KdcStartEvent
  535. //
  536. // Effects:
  537. //
  538. // Arguments:
  539. //
  540. // Requires:
  541. //
  542. // Returns:
  543. //
  544. // Notes: The SPMgr must have created this event before this
  545. // is called
  546. //
  547. //
  548. //--------------------------------------------------------------------------
  549. void
  550. SetKdcStartEvent()
  551. {
  552. TRACE(KDC, SetKdcStartEvent, DEB_FUNCTION);
  553. HANDLE hEvent;
  554. hEvent = KdcOpenEvent(EVENT_MODIFY_STATE,FALSE,KDC_START_EVENT);
  555. if (hEvent != NULL)
  556. {
  557. SetEvent(hEvent);
  558. CloseHandle(hEvent);
  559. D_DebugLog((DEB_TRACE,"Set event %ws\n",KDC_START_EVENT));
  560. }
  561. else
  562. {
  563. DWORD dw = GetLastError();
  564. if (dw != ERROR_FILE_NOT_FOUND)
  565. DebugLog((DEB_ERROR,"Error opening %ws: %d\n",KDC_START_EVENT,dw));
  566. else
  567. D_DebugLog((DEB_TRACE,"Error opening %ws: %d\n",KDC_START_EVENT,dw));
  568. }
  569. }
  570. //+-------------------------------------------------------------------------
  571. //
  572. // Function: KdcLoadParameters
  573. //
  574. // Synopsis: Loads random parameters from registry
  575. //
  576. // Effects:
  577. //
  578. // Arguments:
  579. //
  580. // Requires:
  581. //
  582. // Returns:
  583. //
  584. // Notes:
  585. //
  586. //
  587. //--------------------------------------------------------------------------
  588. VOID
  589. KdcLoadParameters(
  590. VOID
  591. )
  592. {
  593. NET_API_STATUS NetStatus;
  594. // LPNET_CONFIG_HANDLE ConfigHandle = NULL;
  595. LPNET_CONFIG_HANDLE NetlogonInfo = NULL;
  596. int err = 0;
  597. HKEY Key ;
  598. //
  599. // Uncomment the below when there's something we need to read from this key
  600. //
  601. // NetStatus = NetpOpenConfigData(
  602. // &ConfigHandle,
  603. // NULL, // noserer name
  604. // SERVICE_KDC,
  605. // TRUE // read only
  606. // );
  607. // if (NetStatus != NO_ERROR)
  608. // {
  609. // // we could return, but then we'd lose data
  610. // D_DebugLog((DEB_WARN, "Couldn't open KDC config data - %x\n", NetStatus));
  611. // // return;
  612. // }
  613. //
  614. // Open Netlogon service key for AvoidPdcOnWan
  615. //
  616. NetStatus = NetpOpenConfigData(
  617. &NetlogonInfo,
  618. NULL,
  619. SERVICE_NETLOGON,
  620. TRUE
  621. );
  622. if (NetStatus != NO_ERROR)
  623. {
  624. D_DebugLog((DEB_WARN, "Failed to open netlogon key - %x\n", NetStatus));
  625. return;
  626. }
  627. NetStatus = NetpGetConfigBool(
  628. NetlogonInfo,
  629. L"AvoidPdcOnWan",
  630. FALSE,
  631. &KdcGlobalAvoidPdcOnWan
  632. );
  633. if (NetStatus != NO_ERROR)
  634. {
  635. D_DebugLog((DEB_WARN, "Failed to read netlogon config value KdcGlobalAvoidPdcOnWan - %x\n", NetStatus));
  636. }
  637. // NetpCloseConfigData( ConfigHandle );
  638. NetpCloseConfigData( NetlogonInfo );
  639. //
  640. // Check for safeboot mode
  641. //
  642. err = RegOpenKeyExW(
  643. HKEY_LOCAL_MACHINE,
  644. L"System\\CurrentControlSet\\Control\\SafeBoot\\Option",
  645. 0,
  646. KEY_READ,
  647. &Key );
  648. if ( err == ERROR_SUCCESS )
  649. {
  650. ULONG Value = 0 ;
  651. ULONG Size = sizeof( ULONG );
  652. ULONG Type = 0;
  653. err = RegQueryValueExW(
  654. Key,
  655. L"OptionValue",
  656. 0,
  657. &Type,
  658. (PUCHAR) &Value,
  659. &Size );
  660. RegCloseKey( Key );
  661. if ( err == ERROR_SUCCESS )
  662. {
  663. if (Value)
  664. {
  665. KdcGlobalGlobalSafeBoot = TRUE;
  666. }
  667. }
  668. }
  669. }
  670. typedef struct _KDC_REG_PARAMETER {
  671. WCHAR * Name;
  672. DWORD * Address;
  673. DWORD DefaultValue;
  674. BOOL ReverseSense; // 0 means TRUE
  675. BOOL Dynamic;
  676. } KDC_REG_PARAMETER, *PKDC_REG_PARAMETER;
  677. //+---------------------------------------------------------------------------
  678. //
  679. // Function: GetRegistryDwords
  680. //
  681. // Synopsis: Gets a set of DWORDs from the registry
  682. //
  683. // Effects:
  684. //
  685. // Arguments: [hPrimaryKey] -- Key to start from
  686. // [pszKey] -- Name of the subkey
  687. // [Count] -- Number of values
  688. // [Values] -- returned values
  689. //
  690. // Returns: Nothing (Default values assumed on error)
  691. //
  692. // History: 3-31-93 RichardW Created
  693. // 10-14-01 MarkPu Enabled multiple values
  694. //
  695. //----------------------------------------------------------------------------
  696. VOID
  697. GetRegistryDwords(
  698. IN HKEY hKey,
  699. IN ULONG Count,
  700. IN PKDC_REG_PARAMETER Values
  701. )
  702. {
  703. static BOOL ValuesInitialized = FALSE;
  704. while ( Count-- > 0 ) {
  705. LONG err;
  706. DWORD dwType;
  707. DWORD dwValue;
  708. DWORD cbDword = sizeof(DWORD);
  709. if ( Values[Count].Dynamic == FALSE &&
  710. ValuesInitialized )
  711. {
  712. //
  713. // Only initialize static values once!!!
  714. //
  715. continue;
  716. }
  717. err = RegQueryValueEx(
  718. hKey,
  719. Values[Count].Name,
  720. NULL,
  721. &dwType,
  722. (PBYTE) &dwValue,
  723. &cbDword
  724. );
  725. if ( err || ( dwType != REG_DWORD )) {
  726. *Values[Count].Address = Values[Count].DefaultValue;
  727. } else if ( Values[Count].ReverseSense ) {
  728. *Values[Count].Address = !dwValue;
  729. } else {
  730. *Values[Count].Address = dwValue;
  731. }
  732. }
  733. ValuesInitialized = TRUE;
  734. }
  735. ////////////////////////////////////////////////////////////////////
  736. //
  737. // Name: KerbGetKdcRegParams
  738. //
  739. // Synopsis: Gets the debug paramaters from the registry
  740. //
  741. // Arguments: HKEY to HKLM/System/CCS/Services/Kdc
  742. //
  743. // Notes: Sets KDCInfolevel for debug spew
  744. //
  745. void
  746. KerbGetKdcRegParams(HKEY ParamKey)
  747. {
  748. //
  749. // NOTE: UDP datagram size is NOT dynamic; changing it requires restaring
  750. // the KDC. The reason is that this is the value that we initialize ATQ
  751. // with and ATQ can't be re-initialized underneath a running KDC.
  752. // See bug #645637 for details.
  753. //
  754. KDC_REG_PARAMETER Parameters[] =
  755. {
  756. { L"KdcUseClientAddresses", &KdcUseClientAddresses, KdcUseClientAddressesDefault, FALSE, TRUE },
  757. { L"KdcDontCheckAddresses", &KdcDontCheckAddresses, KdcDontCheckAddressesDefault, FALSE, TRUE },
  758. { L"NewConnectionTimeout", &KdcNewConnectionTimeout, KdcNewConnectionTimeoutDefault, FALSE, TRUE },
  759. { L"ExistingConnectionTimeout", &KdcExistingConnectionTimeout, KdcExistingConnectionTimeoutDefault, FALSE, TRUE },
  760. { L"MaxDatagramReplySize", &KdcGlobalMaxDatagramReplySize, KdcMaxDatagramReplySizeDefault, FALSE, FALSE },
  761. { L"KdcExtraLogLevel", &KdcExtraLogLevel, KdcExtraLogLevelDefault, FALSE, TRUE },
  762. { L"KdcDebugLevel", &KDCInfoLevel, KdcInfoLevelDefault, FALSE, TRUE },
  763. { L"KdcIssueForwardedTickets", &KdcIssueForwardedTickets, KdcIssueForwardedTicketsDefault, FALSE, TRUE }
  764. };
  765. //
  766. // Get the DWORD parameters that can change during a boot.
  767. //
  768. GetRegistryDwords(
  769. ParamKey,
  770. sizeof( Parameters ) / sizeof( Parameters[0]),
  771. Parameters
  772. );
  773. //
  774. // BUG 676343
  775. // UDP packets have a 2-byte length field so under no
  776. // circumstances can they be bigger than 64K
  777. //
  778. KdcGlobalMaxDatagramReplySize = min( KdcGlobalMaxDatagramReplySize, 64 * 1024 );
  779. //
  780. // Fixup the common2 debug level.
  781. //
  782. KSuppInfoLevel = KDCInfoLevel;
  783. }
  784. ////////////////////////////////////////////////////////////////////
  785. //
  786. // Name: KerbWatchKdcParamKey
  787. //
  788. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  789. // debug level, then utilizes thread pool to wait on
  790. // changes to this registry key. Enables dynamic debug
  791. // level changes, as this function will also be callback
  792. // if registry key modified.
  793. //
  794. // Arguments: pCtxt is actually a HANDLE to an event. This event
  795. // will be triggered when key is modified.
  796. //
  797. // Notes: .
  798. //
  799. VOID
  800. KerbWatchKdcParamKey(PVOID pCtxt,
  801. BOOLEAN fWaitStatus)
  802. {
  803. NTSTATUS Status;
  804. LONG lRes = ERROR_SUCCESS;
  805. if (NULL == hKdcParams) // first time we've been called.
  806. {
  807. lRes = RegOpenKeyExW(
  808. HKEY_LOCAL_MACHINE,
  809. L"System\\CurrentControlSet\\Services\\Kdc",
  810. 0,
  811. KEY_READ,
  812. &hKdcParams
  813. );
  814. if (ERROR_SUCCESS != lRes)
  815. {
  816. DebugLog((DEB_WARN,"Failed to open kerberos key: 0x%x\n", lRes));
  817. goto Reregister;
  818. }
  819. }
  820. if (NULL != hKdcWait)
  821. {
  822. Status = RtlDeregisterWait(hKdcWait);
  823. if (!NT_SUCCESS(Status))
  824. {
  825. DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  826. goto Reregister;
  827. }
  828. }
  829. lRes = RegNotifyChangeKeyValue(
  830. hKdcParams,
  831. FALSE,
  832. REG_NOTIFY_CHANGE_LAST_SET,
  833. (HANDLE) pCtxt,
  834. TRUE);
  835. if (ERROR_SUCCESS != lRes)
  836. {
  837. DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  838. // we're tanked now. No further notifications, so get this one
  839. }
  840. KerbGetKdcRegParams(hKdcParams);
  841. Reregister:
  842. Status = RtlRegisterWait(&hKdcWait,
  843. (HANDLE) pCtxt,
  844. KerbWatchKdcParamKey,
  845. (HANDLE) pCtxt,
  846. INFINITE,
  847. WT_EXECUTEONLYONCE);
  848. }
  849. ////////////////////////////////////////////////////////////////////
  850. //
  851. // Name: WaitKdcCleanup
  852. //
  853. // Synopsis: Cleans up for KerbWatchKdcParamKey
  854. //
  855. // Arguments: <none>
  856. //
  857. // Notes: .
  858. //
  859. VOID
  860. WaitKdcCleanup(HANDLE hEvent)
  861. {
  862. NTSTATUS Status = STATUS_SUCCESS;
  863. if (NULL != hKdcWait) {
  864. Status = RtlDeregisterWait(hKdcWait);
  865. hKdcWait = NULL;
  866. }
  867. if (NT_SUCCESS(Status) && NULL != hEvent) {
  868. CloseHandle(hEvent);
  869. hEvent = NULL;
  870. }
  871. }
  872. //+-------------------------------------------------------------------------
  873. //
  874. // Function: OpenAccountDomain
  875. //
  876. // Synopsis: Opens the account domain and stores a handle to it.
  877. //
  878. // Effects: Sets GlobalAccountDomainHandle and GlobalPolicyHandle on
  879. // success.
  880. //
  881. // Arguments:
  882. //
  883. // Requires:
  884. //
  885. // Returns:
  886. //
  887. // Notes:
  888. //
  889. //
  890. //--------------------------------------------------------------------------
  891. NTSTATUS
  892. OpenAccountDomain()
  893. {
  894. NTSTATUS Status;
  895. PLSAPR_POLICY_INFORMATION PolicyInformation = NULL;
  896. SAMPR_HANDLE ServerHandle = NULL;
  897. ULONG BuiltInSubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
  898. ULONG AuthenticatedSubAuthority = SECURITY_AUTHENTICATED_USER_RID;
  899. ULONG ThisOrganizationSubAuthority = SECURITY_THIS_ORGANIZATION_RID;
  900. ULONG OtherOrganizationSubAuthority = SECURITY_OTHER_ORGANIZATION_RID;
  901. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
  902. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  903. PSID TmpBuiltInSid = NULL;
  904. Status = LsaIOpenPolicyTrusted( & GlobalPolicyHandle );
  905. if (!NT_SUCCESS(Status))
  906. {
  907. D_DebugLog((DEB_ERROR,"Failed to open policy trusted: 0x%x\n",Status));
  908. goto Cleanup;
  909. }
  910. Status = LsarQueryInformationPolicy(
  911. GlobalPolicyHandle,
  912. PolicyAccountDomainInformation,
  913. &PolicyInformation
  914. );
  915. if (!NT_SUCCESS(Status))
  916. {
  917. D_DebugLog((DEB_ERROR,"Failed to query information policy: 0x%x\n",Status));
  918. goto Cleanup;
  919. }
  920. //
  921. // Get the name and SID out of the account domain information
  922. //
  923. Status = KerbDuplicateString(
  924. &GlobalDomainName,
  925. (PUNICODE_STRING) &PolicyInformation->PolicyAccountDomainInfo.DomainName
  926. );
  927. if (!NT_SUCCESS(Status))
  928. {
  929. goto Cleanup;
  930. }
  931. GlobalDomainSid = (PSID) LocalAlloc(0, RtlLengthSid(PolicyInformation->PolicyAccountDomainInfo.DomainSid));
  932. if (GlobalDomainSid == 0)
  933. {
  934. Status = STATUS_INSUFFICIENT_RESOURCES;
  935. goto Cleanup;
  936. }
  937. RtlCopyMemory(
  938. GlobalDomainSid,
  939. PolicyInformation->PolicyAccountDomainInfo.DomainSid,
  940. RtlLengthSid(PolicyInformation->PolicyAccountDomainInfo.DomainSid)
  941. );
  942. //
  943. // Connect to SAM and open the account domain
  944. //
  945. Status = SamIConnect(
  946. NULL, // no server name
  947. &ServerHandle,
  948. 0, // ignore desired access,
  949. TRUE // trusted caller
  950. );
  951. if (!NT_SUCCESS(Status))
  952. {
  953. DebugLog((DEB_ERROR,"Failed to connect to SAM: 0x%x\n",Status));
  954. goto Cleanup;
  955. }
  956. //
  957. // Finally open the account domain.
  958. //
  959. Status = SamrOpenDomain(
  960. ServerHandle,
  961. DOMAIN_ALL_ACCESS,
  962. (PRPC_SID) PolicyInformation->PolicyAccountDomainInfo.DomainSid,
  963. &GlobalAccountDomainHandle
  964. );
  965. if (!NT_SUCCESS(Status))
  966. {
  967. DebugLog((DEB_ERROR, "Failed to open account domain: 0x%x\n",Status));
  968. goto Cleanup;
  969. }
  970. //
  971. // Create the built-in group sid, the everyone sid, and
  972. // the authenticated user sid. These are used to build authz sid lists.
  973. //
  974. GlobalBuiltInSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(2));
  975. if (NULL == GlobalBuiltInSid)
  976. {
  977. Status = STATUS_INSUFFICIENT_RESOURCES;
  978. goto Cleanup;
  979. }
  980. RtlInitializeSid(
  981. GlobalBuiltInSid,
  982. &SidAuthority,
  983. 2
  984. );
  985. RtlCopyMemory(
  986. RtlSubAuthoritySid(GlobalBuiltInSid,0),
  987. &BuiltInSubAuthority,
  988. sizeof(ULONG)
  989. );
  990. //
  991. // Everyone sid
  992. //
  993. GlobalEveryoneSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(1));
  994. if (NULL == GlobalEveryoneSid)
  995. {
  996. Status = STATUS_INSUFFICIENT_RESOURCES;
  997. goto Cleanup;
  998. }
  999. RtlInitializeSid(
  1000. GlobalEveryoneSid,
  1001. &WorldAuthority,
  1002. 1
  1003. );
  1004. //
  1005. // Authenticated user sid
  1006. //
  1007. GlobalAuthenticatedUserSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(1));
  1008. if (NULL == GlobalAuthenticatedUserSid)
  1009. {
  1010. Status = STATUS_INSUFFICIENT_RESOURCES;
  1011. goto Cleanup;
  1012. }
  1013. RtlInitializeSid(
  1014. GlobalAuthenticatedUserSid,
  1015. &SidAuthority,
  1016. 1
  1017. );
  1018. RtlCopyMemory(
  1019. RtlSubAuthoritySid(GlobalAuthenticatedUserSid,0),
  1020. &AuthenticatedSubAuthority,
  1021. sizeof(ULONG)
  1022. );
  1023. //
  1024. // "This Organization" SID
  1025. //
  1026. GlobalThisOrganizationSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(1));
  1027. if (NULL == GlobalThisOrganizationSid)
  1028. {
  1029. Status = STATUS_INSUFFICIENT_RESOURCES;
  1030. goto Cleanup;
  1031. }
  1032. RtlInitializeSid(
  1033. GlobalThisOrganizationSid,
  1034. &SidAuthority,
  1035. 1
  1036. );
  1037. RtlCopyMemory(
  1038. RtlSubAuthoritySid(GlobalThisOrganizationSid,0),
  1039. &ThisOrganizationSubAuthority,
  1040. sizeof(ULONG)
  1041. );
  1042. //
  1043. // "Other Organization" SID
  1044. //
  1045. GlobalOtherOrganizationSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(1));
  1046. if (NULL == GlobalOtherOrganizationSid)
  1047. {
  1048. Status = STATUS_INSUFFICIENT_RESOURCES;
  1049. goto Cleanup;
  1050. }
  1051. RtlInitializeSid(
  1052. GlobalOtherOrganizationSid,
  1053. &SidAuthority,
  1054. 1
  1055. );
  1056. RtlCopyMemory(
  1057. RtlSubAuthoritySid(GlobalOtherOrganizationSid,0),
  1058. &OtherOrganizationSubAuthority,
  1059. sizeof(ULONG)
  1060. );
  1061. //
  1062. // Make a temporary sid, w/ only 1 sub authority. The above "GlobalBuiltinSid"
  1063. // is explicitly used to build other builtin sids for S4u checks.
  1064. //
  1065. TmpBuiltInSid = (PSID) LocalAlloc(LMEM_ZEROINIT, RtlLengthRequiredSid(1));
  1066. if (NULL == TmpBuiltInSid)
  1067. {
  1068. Status = STATUS_INSUFFICIENT_RESOURCES;
  1069. goto Cleanup;
  1070. }
  1071. RtlInitializeSid(
  1072. TmpBuiltInSid,
  1073. &SidAuthority,
  1074. 1
  1075. );
  1076. RtlCopyMemory(
  1077. RtlSubAuthoritySid(TmpBuiltInSid,0),
  1078. &BuiltInSubAuthority,
  1079. sizeof(ULONG)
  1080. );
  1081. Status = SamrOpenDomain(
  1082. ServerHandle,
  1083. DOMAIN_ALL_ACCESS,
  1084. (PRPC_SID) TmpBuiltInSid,
  1085. &GlobalBuiltInDomainHandle
  1086. );
  1087. if (!NT_SUCCESS(Status))
  1088. {
  1089. DebugLog((DEB_ERROR, "Failed to open builtin domain: 0x%x\n",Status));
  1090. goto Cleanup;
  1091. }
  1092. Cleanup:
  1093. if (PolicyInformation != NULL)
  1094. {
  1095. LsaIFree_LSAPR_POLICY_INFORMATION(
  1096. PolicyAccountDomainInformation,
  1097. PolicyInformation
  1098. );
  1099. }
  1100. if (ServerHandle != NULL)
  1101. {
  1102. SamrCloseHandle(&ServerHandle);
  1103. }
  1104. if (!NT_SUCCESS(Status))
  1105. {
  1106. if (GlobalPolicyHandle != NULL)
  1107. {
  1108. LsarClose(&GlobalPolicyHandle);
  1109. GlobalPolicyHandle = NULL;
  1110. }
  1111. if (GlobalAccountDomainHandle != NULL)
  1112. {
  1113. SamrCloseHandle(&GlobalAccountDomainHandle);
  1114. GlobalAccountDomainHandle = NULL;
  1115. }
  1116. if (GlobalBuiltInDomainHandle != NULL)
  1117. {
  1118. SamrCloseHandle(&GlobalBuiltInDomainHandle);
  1119. GlobalBuiltInDomainHandle = NULL;
  1120. }
  1121. if (GlobalBuiltInSid != NULL)
  1122. {
  1123. LocalFree(GlobalBuiltInSid);
  1124. GlobalBuiltInSid = NULL;
  1125. }
  1126. if (GlobalEveryoneSid != NULL)
  1127. {
  1128. LocalFree(GlobalEveryoneSid);
  1129. GlobalEveryoneSid = NULL;
  1130. }
  1131. if (GlobalAuthenticatedUserSid != NULL)
  1132. {
  1133. LocalFree(GlobalAuthenticatedUserSid);
  1134. GlobalAuthenticatedUserSid = NULL;
  1135. }
  1136. if (GlobalThisOrganizationSid != NULL)
  1137. {
  1138. LocalFree(GlobalThisOrganizationSid);
  1139. GlobalThisOrganizationSid = NULL;
  1140. }
  1141. if (GlobalOtherOrganizationSid != NULL)
  1142. {
  1143. LocalFree(GlobalOtherOrganizationSid);
  1144. GlobalOtherOrganizationSid = NULL;
  1145. }
  1146. }
  1147. if (TmpBuiltInSid != NULL)
  1148. {
  1149. LocalFree(TmpBuiltInSid);
  1150. }
  1151. return(Status);
  1152. }
  1153. //+-------------------------------------------------------------------------
  1154. //
  1155. // Function: CleanupAccountDomain
  1156. //
  1157. // Synopsis: cleans up resources associated with SAM and LSA
  1158. //
  1159. // Effects:
  1160. //
  1161. // Arguments:
  1162. //
  1163. // Requires:
  1164. //
  1165. // Returns:
  1166. //
  1167. // Notes:
  1168. //
  1169. //
  1170. //--------------------------------------------------------------------------
  1171. VOID
  1172. CleanupAccountDomain()
  1173. {
  1174. if (GlobalPolicyHandle != NULL)
  1175. {
  1176. LsarClose(&GlobalPolicyHandle);
  1177. GlobalPolicyHandle = NULL;
  1178. }
  1179. if (GlobalAccountDomainHandle != NULL)
  1180. {
  1181. SamrCloseHandle(&GlobalAccountDomainHandle);
  1182. GlobalAccountDomainHandle = NULL;
  1183. }
  1184. if ( GlobalBuiltInDomainHandle != NULL )
  1185. {
  1186. SamrCloseHandle(&GlobalBuiltInDomainHandle);
  1187. GlobalBuiltInDomainHandle = NULL;
  1188. }
  1189. KerbFreeString(&GlobalDomainName);
  1190. if (GlobalDomainSid != NULL)
  1191. {
  1192. LocalFree(GlobalDomainSid);
  1193. GlobalDomainSid = NULL;
  1194. }
  1195. if (GlobalBuiltInSid != NULL)
  1196. {
  1197. LocalFree(GlobalBuiltInSid);
  1198. GlobalBuiltInSid = NULL;
  1199. }
  1200. if (GlobalEveryoneSid != NULL)
  1201. {
  1202. LocalFree(GlobalEveryoneSid);
  1203. GlobalEveryoneSid = NULL;
  1204. }
  1205. if (GlobalAuthenticatedUserSid != NULL)
  1206. {
  1207. LocalFree(GlobalAuthenticatedUserSid);
  1208. GlobalAuthenticatedUserSid = NULL;
  1209. }
  1210. if (GlobalThisOrganizationSid != NULL)
  1211. {
  1212. LocalFree(GlobalThisOrganizationSid);
  1213. GlobalThisOrganizationSid = NULL;
  1214. }
  1215. if (GlobalOtherOrganizationSid != NULL)
  1216. {
  1217. LocalFree(GlobalOtherOrganizationSid);
  1218. GlobalOtherOrganizationSid = NULL;
  1219. }
  1220. }
  1221. //+-------------------------------------------------------------------------
  1222. //
  1223. // Function: KerbInitPreferredCryptList
  1224. //
  1225. // Synopsis: Build a crypt list, the strongest etype first, used to select
  1226. // etype_for_key(server.key) per rfc 1510
  1227. //
  1228. //--------------------------------------------------------------------------
  1229. NTSTATUS
  1230. KerbInitPreferredCryptList(
  1231. VOID
  1232. )
  1233. {
  1234. KERBERR KerbErr = KRB_ERR_GENERIC;
  1235. ULONG CryptTypes[KERB_MAX_CRYPTO_SYSTEMS] = {0};
  1236. ULONG CryptTypeCount = 0;
  1237. CryptTypes[CryptTypeCount++] = KERB_ETYPE_RC4_HMAC_NT;
  1238. CryptTypes[CryptTypeCount++] = KERB_ETYPE_RC4_HMAC_NT_EXP;
  1239. CryptTypes[CryptTypeCount++] = KERB_ETYPE_DES_CBC_MD5_NT;
  1240. CryptTypes[CryptTypeCount++] = KERB_ETYPE_DES_CBC_MD5;
  1241. CryptTypes[CryptTypeCount++] = KERB_ETYPE_DES_CBC_CRC;
  1242. KerbErr = KerbConvertArrayToCryptList(
  1243. &kdc_pPreferredCryptList,
  1244. CryptTypes,
  1245. CryptTypeCount,
  1246. FALSE
  1247. );
  1248. if (KERB_SUCCESS(KerbErr))
  1249. {
  1250. CryptTypeCount = 0;
  1251. CryptTypes[CryptTypeCount++] = KERB_ETYPE_DES_CBC_MD5;
  1252. CryptTypes[CryptTypeCount++] = KERB_ETYPE_DES_CBC_CRC;
  1253. KerbErr = KerbConvertArrayToCryptList(
  1254. &kdc_pMitPrincipalPreferredCryptList,
  1255. CryptTypes,
  1256. CryptTypeCount,
  1257. FALSE
  1258. );
  1259. }
  1260. return KerbMapKerbError(KerbErr);
  1261. }
  1262. //+-------------------------------------------------------------------------
  1263. //
  1264. // Name: KdcServiceMain
  1265. //
  1266. // Synopsis: This is the main KDC thread.
  1267. //
  1268. // Arguments: dwArgc -
  1269. // pszArgv -
  1270. //
  1271. // Notes: This intializes everything, and starts the working threads.
  1272. //
  1273. //--------------------------------------------------------------------------
  1274. extern "C"
  1275. void
  1276. KdcServiceMain( DWORD dwArgc,
  1277. LPTSTR *pszArgv)
  1278. {
  1279. UNREFERENCED_PARAMETER(dwArgc);
  1280. UNREFERENCED_PARAMETER(pszArgv);
  1281. TRACE(KDC, KdcServiceMain, DEB_FUNCTION);
  1282. ULONG RpcStatus;
  1283. HANDLE hKdcParamEvent = NULL;
  1284. ULONG ulStates = 0;
  1285. NTSTATUS NtStatus = STATUS_SUCCESS;
  1286. NTSTATUS TempStatus;
  1287. NT_PRODUCT_TYPE NtProductType;
  1288. #define RPCDONE 0x1
  1289. #define LOCATORSTARTED 0x2
  1290. #define CRITSECSDONE 0x4
  1291. KdcState = Starting;
  1292. //
  1293. // Get the debugging parameters
  1294. //
  1295. GetDebugParams();
  1296. //
  1297. // Get other parameters, register wait on registry keys
  1298. //
  1299. KdcLoadParameters();
  1300. #ifdef ROGUE_DC
  1301. if ( ERROR_SUCCESS != RegOpenKeyExW(
  1302. HKEY_LOCAL_MACHINE,
  1303. L"System\\CurrentControlSet\\Services\\Kdc\\Rogue",
  1304. 0,
  1305. KEY_READ,
  1306. &hKdcRogueKey ))
  1307. {
  1308. DebugLog((DEB_WARN,"Failed to open \"rogue\" kerberos key\n" ));
  1309. }
  1310. #endif
  1311. hKdcParamEvent = CreateEvent(
  1312. NULL,
  1313. FALSE,
  1314. FALSE,
  1315. NULL
  1316. );
  1317. if (NULL == hKdcParamEvent)
  1318. {
  1319. D_DebugLog((DEB_WARN, "CreateEvent for KdcParamEvent failed - 0x%x\n", GetLastError()));
  1320. }
  1321. else
  1322. {
  1323. KerbWatchKdcParamKey( hKdcParamEvent, FALSE );
  1324. }
  1325. D_DebugLog((DEB_TRACE, "Start KdcServiceMain\n"));
  1326. //
  1327. // Notify the service controller that we are starting.
  1328. //
  1329. hService = RegisterServiceCtrlHandler(SERVICE_KDC, Handler);
  1330. if (!hService)
  1331. {
  1332. D_DebugLog((DEB_ERROR, "Could not register handler, %d\n", GetLastError()));
  1333. }
  1334. SStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  1335. SStatus.dwCurrentState = SERVICE_STOPPED;
  1336. SStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  1337. SStatus.dwWin32ExitCode = 0;
  1338. SStatus.dwServiceSpecificExitCode = 0;
  1339. SStatus.dwCheckPoint = 0;
  1340. SStatus.dwWaitHint = 0;
  1341. if (!UpdateStatus(SERVICE_START_PENDING) )
  1342. {
  1343. goto Shutdown;
  1344. }
  1345. //
  1346. // Set up the event log service
  1347. //
  1348. InitializeEvents();
  1349. //
  1350. // Check out product type
  1351. //
  1352. if ( !RtlGetNtProductType( &NtProductType ) || ( NtProductType != NtProductLanManNt ) ) {
  1353. D_DebugLog((DEB_WARN, "Can't start KDC on non-lanmanNT systems\n"));
  1354. NtStatus = STATUS_MUST_BE_KDC;
  1355. goto Shutdown;
  1356. }
  1357. RtlInitUnicodeString(
  1358. &GlobalKerberosName,
  1359. MICROSOFT_KERBEROS_NAME_W
  1360. );
  1361. RtlInitUnicodeString(
  1362. &GlobalKdcName,
  1363. SERVICE_KDC
  1364. );
  1365. //
  1366. // Turn on safealloca support
  1367. //
  1368. SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT, SAFEALLOCA_USE_DEFAULT, KdcAllocate, KdcFree);
  1369. //
  1370. // Build our Kpasswd name, so we don't have to alloc on
  1371. // every TGS request.
  1372. //
  1373. NtStatus = KerbBuildKpasswdName(
  1374. &GlobalKpasswdName
  1375. );
  1376. if (!NT_SUCCESS(NtStatus))
  1377. {
  1378. D_DebugLog((DEB_ERROR, "Failed to build KPASSWD name, error 0x%X\n", NtStatus));
  1379. goto Shutdown;
  1380. }
  1381. GlobalLocalhostAddress[0] = 127;
  1382. GlobalLocalhostAddress[1] = 0;
  1383. GlobalLocalhostAddress[2] = 0;
  1384. GlobalLocalhostAddress[3] = 1;
  1385. //
  1386. // Wait for SAM to start
  1387. //
  1388. if (!KdcWaitForSamService( ))
  1389. {
  1390. NtStatus = STATUS_INVALID_SERVER_STATE;
  1391. goto Shutdown;
  1392. }
  1393. //
  1394. // Initialize the AuthZ resource manager
  1395. //
  1396. NtStatus = KdcInitializeAuthzRM();
  1397. if ( !NT_SUCCESS( NtStatus ))
  1398. {
  1399. D_DebugLog((DEB_ERROR, "Failed to intialize the AuthZ resource manager, error 0x%X\n", NtStatus));
  1400. goto Shutdown;
  1401. }
  1402. if (!UpdateStatus(SERVICE_START_PENDING) )
  1403. {
  1404. goto Shutdown;
  1405. }
  1406. //
  1407. // Can't proceed unless the kerb SSPI package has initialized
  1408. // (KerbKdcCallback might get invoked and that requires kerb
  1409. // global resource being intialized)
  1410. //
  1411. if (!KerbIsInitialized())
  1412. {
  1413. NtStatus = STATUS_UNSUCCESSFUL;
  1414. DebugLog((DEB_ERROR, "Kerb SSPI package not initialized: 0x%x\n",NtStatus));
  1415. goto Shutdown;
  1416. }
  1417. NtStatus = KerbInitPreferredCryptList();
  1418. if (!NT_SUCCESS(NtStatus))
  1419. {
  1420. DebugLog((DEB_ERROR, "KdcServiceMain could not initialized preferrred crypt list: 0x%x\n", NtStatus));
  1421. goto Shutdown;
  1422. }
  1423. //
  1424. // Register for the Ds callback
  1425. //
  1426. if (!KdcRegisterToWaitForDS( ))
  1427. {
  1428. NtStatus = STATUS_INVALID_SERVER_STATE;
  1429. goto Shutdown;
  1430. }
  1431. if (!UpdateStatus(SERVICE_START_PENDING) )
  1432. {
  1433. goto Shutdown;
  1434. }
  1435. //
  1436. // Get a handle to the SAM account domain
  1437. //
  1438. NtStatus = OpenAccountDomain();
  1439. if (!NT_SUCCESS(NtStatus))
  1440. {
  1441. DebugLog((DEB_ERROR, "Failed to get domain handle: 0x%x\n",NtStatus));
  1442. goto Shutdown;
  1443. }
  1444. if (!UpdateStatus(SERVICE_START_PENDING) )
  1445. {
  1446. goto Shutdown;
  1447. }
  1448. //
  1449. // Initialize the PK infrastructure
  1450. //
  1451. NtStatus = KdcInitializeCerts();
  1452. if (!NT_SUCCESS(NtStatus))
  1453. {
  1454. D_DebugLog((DEB_ERROR,"Failed to initialize certs: 0x%x\n",NtStatus));
  1455. goto Shutdown;
  1456. }
  1457. if (!UpdateStatus(SERVICE_START_PENDING) )
  1458. {
  1459. goto Shutdown;
  1460. }
  1461. //
  1462. // Start the RPC sequences
  1463. //
  1464. NtStatus = StartAllProtSeqs();
  1465. if (!NT_SUCCESS(NtStatus))
  1466. {
  1467. D_DebugLog((DEB_ERROR, "Failed to start RPC, error 0x%X\n", NtStatus));
  1468. goto Shutdown;
  1469. }
  1470. //
  1471. // Start the socket listening code.
  1472. //
  1473. if (!UpdateStatus(SERVICE_START_PENDING) )
  1474. {
  1475. goto Shutdown;
  1476. }
  1477. //
  1478. // Load all global data into the SecData structure.
  1479. //
  1480. NtStatus = SecData.Init();
  1481. if (!NT_SUCCESS(NtStatus))
  1482. {
  1483. D_DebugLog((DEB_ERROR, "Failed to init SecData error 0x%X\n", NtStatus));
  1484. goto Shutdown;
  1485. }
  1486. //
  1487. // Set the flag to indicate this is a trust account
  1488. //
  1489. // KdcTicketInfo.UserAccountControl |= USER_INTERDOMAIN_TRUST_ACCOUNT;
  1490. if (!UpdateStatus(SERVICE_START_PENDING) )
  1491. {
  1492. goto Shutdown;
  1493. }
  1494. //
  1495. // Create the KDC shutdown event, set to FALSE
  1496. //
  1497. hKdcShutdownEvent = CreateEvent( NULL, // no security attributes
  1498. TRUE, // manual reset
  1499. FALSE, // initial state
  1500. NULL ); // unnamed event.
  1501. if (hKdcShutdownEvent == NULL)
  1502. {
  1503. NtStatus = (NTSTATUS) GetLastError();
  1504. D_DebugLog(( DEB_ERROR, "KDC can't create shutdown event: wincode=%d.\n",
  1505. NtStatus ));
  1506. goto Shutdown;
  1507. }
  1508. if (!UpdateStatus(SERVICE_START_PENDING) )
  1509. {
  1510. goto Shutdown;
  1511. }
  1512. #if DBG
  1513. NtStatus = RegisterKdcEps();
  1514. if (!NT_SUCCESS(NtStatus))
  1515. {
  1516. D_DebugLog((DEB_ERROR, "Ep register failed %x\n", NtStatus));
  1517. // goto Shutdown;
  1518. }
  1519. #endif // DBG
  1520. ulStates |= RPCDONE;
  1521. //
  1522. // 1 is the minimum number of threads.
  1523. // TRUE means the call will return, rather than waiting until the
  1524. // server shuts down.
  1525. //
  1526. NtStatus = KdcInitializeSockets();
  1527. if (!NT_SUCCESS(NtStatus))
  1528. {
  1529. D_DebugLog((DEB_ERROR, "Failed to initailzie sockets\n"));
  1530. goto Shutdown;
  1531. }
  1532. if (!UpdateStatus(SERVICE_START_PENDING) )
  1533. {
  1534. goto Shutdown;
  1535. }
  1536. InitializeListHead(&KdcDomainList);
  1537. NtStatus = (NTSTATUS) KdcReloadDomainTree( NULL );
  1538. if (!NT_SUCCESS(NtStatus))
  1539. {
  1540. D_DebugLog((DEB_ERROR, "Failed to build domain tree: 0x%x\n",NtStatus));
  1541. goto Shutdown;
  1542. }
  1543. if (!UpdateStatus(SERVICE_START_PENDING) )
  1544. {
  1545. goto Shutdown;
  1546. }
  1547. //
  1548. // Check to see if there is a CSP registered for replacing the StringToKey calculation
  1549. //
  1550. CheckForOutsideStringToKey();
  1551. if (!UpdateStatus(SERVICE_START_PENDING) )
  1552. {
  1553. goto Shutdown;
  1554. }
  1555. NtStatus = LsaIKerberosRegisterTrustNotification( KdcTrustChangeCallback, LsaRegister );
  1556. if (!NT_SUCCESS( NtStatus ))
  1557. {
  1558. D_DebugLog((DEB_ERROR, "Failed to register notification\n"));
  1559. }
  1560. RpcStatus = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
  1561. if (RpcStatus != ERROR_SUCCESS)
  1562. {
  1563. if (RpcStatus != RPC_S_ALREADY_LISTENING)
  1564. {
  1565. D_DebugLog(( DEB_ERROR, "Error from RpcServerListen: %d\n", RpcStatus ));
  1566. NtStatus = I_RpcMapWin32Status(RpcStatus);
  1567. goto Shutdown;
  1568. }
  1569. }
  1570. // Initialize the GlobalCert
  1571. KdcMyStoreWaitHandler (NULL, TRUE);
  1572. //
  1573. // At this point the KDC is officially started.
  1574. // 3 * ( 2*(hip) horray! )
  1575. //
  1576. if (!UpdateStatus(SERVICE_RUNNING) )
  1577. {
  1578. goto Shutdown;
  1579. }
  1580. #if DBG
  1581. GetSystemTimeAsFileTime((PFILETIME)&tsOut);
  1582. D_DebugLog((DEB_TRACE, "Time required for KDC to start up: %d ms\n",
  1583. (tsOut.LowPart-tsIn.LowPart) / 10000));
  1584. #endif
  1585. SetKdcStartEvent();
  1586. KdcState = Running;
  1587. KdcInitializeTrace();
  1588. // This function will loop until the event is true.
  1589. // WAS BUG: turn off cache manager for now.
  1590. // This bug comment is a stale piece of code from
  1591. // Cairo days - per MikeSw
  1592. //
  1593. WaitForSingleObject(hKdcShutdownEvent, INFINITE);
  1594. Shutdown:
  1595. LsaIKerberosRegisterTrustNotification( KdcTrustChangeCallback, LsaUnregister );
  1596. LsaIUnregisterAllPolicyChangeNotificationCallback(KdcPolicyChangeCallBack);
  1597. //
  1598. // Time to cleanup up all resources ...
  1599. //
  1600. TempStatus = I_NetLogonSetServiceBits( DS_KDC_FLAG, 0 );
  1601. if ( !NT_SUCCESS(TempStatus) ) {
  1602. D_DebugLog((DEB_TRACE,"Can't tell netlogon we're stopped 0x%lX\n", TempStatus ));
  1603. }
  1604. //
  1605. // Remove the wait routine for the DS paused event
  1606. //
  1607. if ( KdcGlobalDsPausedWaitHandle != NULL ) {
  1608. UnregisterWaitEx( KdcGlobalDsPausedWaitHandle,
  1609. INVALID_HANDLE_VALUE ); // Wait until routine finishes execution
  1610. KdcGlobalDsPausedWaitHandle = NULL;
  1611. }
  1612. if (NULL != GlobalKpasswdName)
  1613. {
  1614. KerbFreeKdcName(&GlobalKpasswdName);
  1615. }
  1616. if (KdcGlobalDsEventHandle)
  1617. {
  1618. CloseHandle( KdcGlobalDsEventHandle );
  1619. KdcGlobalDsEventHandle = NULL;
  1620. }
  1621. //
  1622. // Shut down event log service.
  1623. //
  1624. ShutdownEvents();
  1625. UpdateStatus(SERVICE_STOP_PENDING);
  1626. #if DBG
  1627. if (ulStates & RPCDONE)
  1628. {
  1629. (VOID)UnRegisterKdcEps();
  1630. UpdateStatus(SERVICE_STOP_PENDING);
  1631. }
  1632. #endif // DBG
  1633. KdcShutdownSockets();
  1634. KdcFreeAuthzRm();
  1635. KdcCleanupCerts(
  1636. TRUE // cleanup scavenger
  1637. );
  1638. UpdateStatus(SERVICE_STOP_PENDING);
  1639. //
  1640. // Close all of the events.
  1641. //
  1642. {
  1643. PHANDLE ph = &hKdcHandles[0];
  1644. for (;ph < &hKdcHandles[MAX_KDC_HANDLE]; ph++)
  1645. {
  1646. if (*ph)
  1647. {
  1648. CloseHandle(*ph);
  1649. *ph = NULL;
  1650. }
  1651. }
  1652. }
  1653. if ( hKdcParamEvent ) {
  1654. WaitKdcCleanup( hKdcParamEvent );
  1655. }
  1656. //
  1657. // Cleanup handles to SAM & LSA and global variables
  1658. //
  1659. CleanupAccountDomain();
  1660. UpdateStatus(SERVICE_STOP_PENDING);
  1661. //
  1662. // Cleanup the domain list
  1663. //
  1664. //
  1665. // BUGBUG: need to make sure it is not being used.
  1666. //
  1667. KdcFreeDomainList(&KdcDomainList);
  1668. KdcFreeReferralCache(&KdcReferralCache);
  1669. if (kdc_pPreferredCryptList)
  1670. {
  1671. KerbFreeCryptList(kdc_pPreferredCryptList);
  1672. }
  1673. if (kdc_pMitPrincipalPreferredCryptList)
  1674. {
  1675. KerbFreeCryptList(kdc_pMitPrincipalPreferredCryptList);
  1676. }
  1677. #ifdef ROGUE_DC
  1678. if ( hKdcRogueKey )
  1679. {
  1680. RegCloseKey( hKdcRogueKey );
  1681. }
  1682. #endif
  1683. SStatus.dwWin32ExitCode = RtlNtStatusToDosError(NtStatus);
  1684. SStatus.dwServiceSpecificExitCode = 0;
  1685. D_DebugLog(( DEB_TRACE, "KDC shutting down.\n" ));
  1686. UpdateStatus(SERVICE_STOPPED);
  1687. D_DebugLog((DEB_TRACE, "End KdcServiceMain\n"));
  1688. }
  1689. ////////////////////////////////////////////////////////////////////
  1690. //
  1691. // Name: ShutDown
  1692. //
  1693. // Synopsis: Shuts the KDC down.
  1694. //
  1695. // Arguments: pszMessage - message to print to debug port
  1696. //
  1697. // Notes: Stops RPC from accepting new calls, waits for pending calls
  1698. // to finish, and sets the global event "hKdcShutDownEvent".
  1699. //
  1700. NTSTATUS
  1701. ShutDown(LPWSTR pszMessage)
  1702. {
  1703. NTSTATUS NtStatus = STATUS_SUCCESS;
  1704. TRACE(KDC, ShutDown, DEB_FUNCTION);
  1705. D_DebugLog((DEB_WARN, "Server Shutdown: %ws\n", pszMessage));
  1706. //
  1707. // Notify the all threads that we are exiting.
  1708. //
  1709. //
  1710. // First set the started flag to false so nobody will try any more
  1711. // direct calls to the KDC.
  1712. //
  1713. KdcState = Stopped;
  1714. //
  1715. // If there are any outstanding calls, let them trigger the shutdown event.
  1716. // Otherwise set the shutdown event ourselves.
  1717. //
  1718. EnterCriticalSection(&ApiCriticalSection);
  1719. if (CurrentApiCallers == 0)
  1720. {
  1721. if (!SetEvent( hKdcShutdownEvent ) )
  1722. {
  1723. D_DebugLog(( DEB_ERROR, "Couldn't set KDC shutdown event. winerr=%d.\n",
  1724. GetLastError() ));
  1725. NtStatus = STATUS_UNSUCCESSFUL;
  1726. }
  1727. SecData.Cleanup();
  1728. if (KdcTraceRegistrationHandle != (TRACEHANDLE)0)
  1729. {
  1730. UnregisterTraceGuids( KdcTraceRegistrationHandle );
  1731. KdcTraceRegistrationHandle = (TRACEHANDLE)0;
  1732. }
  1733. }
  1734. LeaveCriticalSection(&ApiCriticalSection);
  1735. return(NtStatus);
  1736. }
  1737. //+-------------------------------------------------------------------------
  1738. //
  1739. // Function: DllMain
  1740. //
  1741. // Synopsis: DLL initialization routine
  1742. //
  1743. //--------------------------------------------------------------------------
  1744. extern "C" BOOL WINAPI
  1745. DllMain (
  1746. HINSTANCE hInstance,
  1747. DWORD dwReason,
  1748. PVOID lpReserved
  1749. )
  1750. {
  1751. BOOL bReturn = TRUE;
  1752. if ( dwReason == DLL_PROCESS_ATTACH )
  1753. {
  1754. DisableThreadLibraryCalls ( hInstance );
  1755. //
  1756. // WAS BUG: call the Rtl version here because it returns an error
  1757. // instead of throwing an exception. Leave it here, as we don't
  1758. // really need to put a try/except around InitCritSec.
  1759. //
  1760. bReturn = NT_SUCCESS(RtlInitializeCriticalSection( &ApiCriticalSection ));
  1761. if (bReturn)
  1762. {
  1763. bReturn = NT_SUCCESS(SecData.InitLock());
  1764. if (!bReturn)
  1765. {
  1766. RtlDeleteCriticalSection(&ApiCriticalSection);
  1767. }
  1768. }
  1769. }
  1770. else if (dwReason == DLL_PROCESS_DETACH)
  1771. {
  1772. DeleteCriticalSection(&ApiCriticalSection);
  1773. }
  1774. return bReturn;
  1775. UNREFERENCED_PARAMETER(lpReserved);
  1776. UNREFERENCED_PARAMETER(hInstance);
  1777. }