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.

1382 lines
31 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. //
  32. // Global data
  33. //
  34. KDC_STATE KdcState = Stopped; // used to signal when
  35. // authenticated RPC is
  36. // ready to use - e.g.
  37. // spmgr has found the
  38. // kdc
  39. SERVICE_STATUS_HANDLE hService;
  40. SERVICE_STATUS SStatus;
  41. UNICODE_STRING GlobalDomainName;
  42. UNICODE_STRING GlobalKerberosName;
  43. UNICODE_STRING GlobalKdcName;
  44. PKERB_INTERNAL_NAME GlobalKpasswdName = NULL;
  45. PSID GlobalDomainSid;
  46. LSAPR_HANDLE GlobalPolicyHandle;
  47. SAMPR_HANDLE GlobalAccountDomainHandle;
  48. BYTE GlobalLocalhostAddress[4];
  49. HANDLE KdcGlobalDsPausedWaitHandle;
  50. HANDLE KdcGlobalDsEventHandle;
  51. BOOL KdcGlobalAvoidPdcOnWan = FALSE;
  52. #if DBG
  53. LARGE_INTEGER tsIn,tsOut;
  54. #endif
  55. HANDLE hKdcHandles[MAX_KDC_HANDLE];
  56. //
  57. // Prototypes
  58. //
  59. CRITICAL_SECTION ApiCriticalSection;
  60. ULONG CurrentApiCallers;
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Function: UpdateStatus
  64. //
  65. // Synopsis: Updates the KDC's service status with the service controller
  66. //
  67. // Effects:
  68. //
  69. // Arguments:
  70. //
  71. // History:
  72. //
  73. // Notes:
  74. //
  75. //----------------------------------------------------------------------------
  76. BOOLEAN
  77. UpdateStatus(DWORD dwState)
  78. {
  79. TRACE(KDC, UpdateStatus, DEB_FUNCTION);
  80. SStatus.dwCurrentState = dwState;
  81. if ((dwState == SERVICE_START_PENDING) || (dwState == SERVICE_STOP_PENDING))
  82. {
  83. SStatus.dwCheckPoint++;
  84. SStatus.dwWaitHint = 10000;
  85. }
  86. else
  87. {
  88. SStatus.dwCheckPoint = 0;
  89. SStatus.dwWaitHint = 0;
  90. }
  91. if (!SetServiceStatus(hService, &SStatus)) {
  92. DebugLog((DEB_ERROR,"(%x)Failed to set service status: %d\n",GetLastError()));
  93. return(FALSE);
  94. }
  95. return(TRUE);
  96. }
  97. //+---------------------------------------------------------------------------
  98. //
  99. // Function: Handler
  100. //
  101. // Synopsis: Process and respond to a control signal from the service
  102. // controller.
  103. //
  104. // Effects:
  105. //
  106. // Arguments:
  107. //
  108. // History:
  109. //
  110. // Notes:
  111. //
  112. //----------------------------------------------------------------------------
  113. void
  114. Handler(DWORD dwControl)
  115. {
  116. TRACE(KDC, Handler, DEB_FUNCTION);
  117. switch (dwControl)
  118. {
  119. case SERVICE_CONTROL_STOP:
  120. ShutDown( L"Service" );
  121. break;
  122. default:
  123. D_DebugLog((DEB_WARN, "Ignoring SC message %d\n",dwControl));
  124. break;
  125. }
  126. }
  127. BOOLEAN
  128. KdcWaitForSamService(
  129. VOID
  130. )
  131. /*++
  132. Routine Description:
  133. This procedure waits for the SAM service to start and to complete
  134. all its initialization.
  135. Arguments:
  136. Return Value:
  137. TRUE : if the SAM service is successfully starts.
  138. FALSE : if the SAM service can't start.
  139. --*/
  140. {
  141. NTSTATUS Status;
  142. DWORD WaitStatus;
  143. UNICODE_STRING EventName;
  144. HANDLE EventHandle;
  145. OBJECT_ATTRIBUTES EventAttributes;
  146. //
  147. // open SAM event
  148. //
  149. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  150. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  151. Status = NtOpenEvent( &EventHandle,
  152. SYNCHRONIZE|EVENT_MODIFY_STATE,
  153. &EventAttributes );
  154. if ( !NT_SUCCESS(Status)) {
  155. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  156. //
  157. // SAM hasn't created this event yet, let us create it now.
  158. // SAM opens this event to set it.
  159. //
  160. Status = NtCreateEvent(
  161. &EventHandle,
  162. SYNCHRONIZE|EVENT_MODIFY_STATE,
  163. &EventAttributes,
  164. NotificationEvent,
  165. FALSE // The event is initially not signaled
  166. );
  167. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  168. Status == STATUS_OBJECT_NAME_COLLISION ) {
  169. //
  170. // second change, if the SAM created the event before we
  171. // do.
  172. //
  173. Status = NtOpenEvent( &EventHandle,
  174. SYNCHRONIZE|EVENT_MODIFY_STATE,
  175. &EventAttributes );
  176. }
  177. }
  178. if ( !NT_SUCCESS(Status)) {
  179. //
  180. // could not make the event handle
  181. //
  182. DebugLog((DEB_ERROR,
  183. "KdcWaitForSamService couldn't make the event handle : "
  184. "%lx\n", Status));
  185. return( FALSE );
  186. }
  187. }
  188. //
  189. // Loop waiting.
  190. //
  191. for (;;) {
  192. WaitStatus = WaitForSingleObject( EventHandle,
  193. 5*1000 ); // 5 Seconds
  194. if ( WaitStatus == WAIT_TIMEOUT ) {
  195. DebugLog((DEB_WARN,
  196. "KdcWaitForSamService 5-second timeout (Rewaiting)\n" ));
  197. if (!UpdateStatus( SERVICE_START_PENDING )) {
  198. (VOID) NtClose( EventHandle );
  199. return FALSE;
  200. }
  201. continue;
  202. } else if ( WaitStatus == WAIT_OBJECT_0 ) {
  203. break;
  204. } else {
  205. DebugLog((DEB_ERROR,
  206. "KdcWaitForSamService: error %ld %ld\n",
  207. GetLastError(),
  208. WaitStatus ));
  209. (VOID) NtClose( EventHandle );
  210. return FALSE;
  211. }
  212. }
  213. (VOID) NtClose( EventHandle );
  214. return TRUE;
  215. }
  216. VOID
  217. KdcDsNotPaused(
  218. IN PVOID Context,
  219. IN BOOLEAN TimedOut
  220. )
  221. /*++
  222. Routine Description:
  223. Worker routine that gets called when the DS is no longer paused.
  224. Arguments:
  225. None.
  226. Return Value:
  227. None.
  228. --*/
  229. {
  230. NTSTATUS NtStatus = STATUS_SUCCESS;
  231. // Tell the kerberos client that we that a DC.
  232. NtStatus = KerbKdcCallBack();
  233. if ( !NT_SUCCESS(NtStatus) )
  234. {
  235. D_DebugLog((DEB_ERROR,"Can't tell Kerberos that we're a DC 0x%x\n", NtStatus ));
  236. goto Cleanup;
  237. }
  238. NtStatus = I_NetLogonSetServiceBits( DS_KDC_FLAG, DS_KDC_FLAG );
  239. if ( !NT_SUCCESS(NtStatus) )
  240. {
  241. D_DebugLog((DEB_ERROR,"Can't tell netlogon we're started 0x%x\n", NtStatus ));
  242. goto Cleanup;
  243. }
  244. D_DebugLog((DEB_TRACE,"Ds is no longer paused\n"));
  245. Cleanup:
  246. UNREFERENCED_PARAMETER( Context );
  247. UNREFERENCED_PARAMETER( TimedOut );
  248. }
  249. BOOLEAN
  250. KdcRegisterToWaitForDS(
  251. VOID
  252. )
  253. /*++
  254. Routine Description:
  255. This procedure registers to wait for the DS to start and to complete
  256. all its initialization. The main reason we do this is because we don't
  257. want to start doing kerberos authentications because we don't know that
  258. the DS has the latest db. It needs to check with all the existing Dc's
  259. out there to see if there's any db merges to be done. When the
  260. DS_SYNCED_EVENT_NAME is set, we're ready.
  261. Arguments:
  262. Return Value:
  263. TRUE : if the register to wait succeeded
  264. FALSE : if the register to wait didn't succeed.
  265. --*/
  266. {
  267. BOOLEAN fRet = FALSE;
  268. //
  269. // open the DS event
  270. //
  271. KdcGlobalDsEventHandle = OpenEvent( SYNCHRONIZE,
  272. FALSE,
  273. DS_SYNCED_EVENT_NAME_W);
  274. if ( KdcGlobalDsEventHandle == NULL)
  275. {
  276. //
  277. // could not open the event handle
  278. //
  279. D_DebugLog((DEB_ERROR,"KdcRegisterToWaitForDS couldn't open the event handle\n"));
  280. goto Cleanup;
  281. }
  282. if ( !RegisterWaitForSingleObject(
  283. &KdcGlobalDsPausedWaitHandle,
  284. KdcGlobalDsEventHandle,
  285. KdcDsNotPaused, // Callback routine
  286. NULL, // No context
  287. -1, // Wait forever
  288. WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) )
  289. {
  290. D_DebugLog((DEB_ERROR, "KdcRegisterToWaitForDS: Cannot register for DS Synced callback 0x%x\n", GetLastError()));
  291. goto Cleanup;
  292. }
  293. fRet = TRUE;
  294. Cleanup:
  295. return fRet;
  296. }
  297. //+-------------------------------------------------------------------------
  298. //
  299. // Function: KdcOpenEvent
  300. //
  301. // Synopsis: Just like the Win32 function, except that it allows
  302. // for names at the root of the namespace.
  303. //
  304. // Effects:
  305. //
  306. // Arguments:
  307. //
  308. // Requires:
  309. //
  310. // Returns:
  311. //
  312. // Notes: The code was copied from private\windows\base\client\synch.c
  313. // and the base directory was changed to NULL
  314. //
  315. //--------------------------------------------------------------------------
  316. HANDLE
  317. APIENTRY
  318. KdcOpenEvent(
  319. DWORD DesiredAccess,
  320. BOOL bInheritHandle,
  321. LPWSTR lpName
  322. )
  323. {
  324. TRACE(KDC, KdcOpenEvent, DEB_FUNCTION);
  325. OBJECT_ATTRIBUTES Obja;
  326. UNICODE_STRING ObjectName;
  327. NTSTATUS Status;
  328. HANDLE Object;
  329. if ( !lpName ) {
  330. SetLastError(ERROR_INVALID_PARAMETER);
  331. return NULL;
  332. }
  333. RtlInitUnicodeString(&ObjectName,lpName);
  334. InitializeObjectAttributes(
  335. &Obja,
  336. &ObjectName,
  337. (bInheritHandle ? OBJ_INHERIT : 0),
  338. NULL,
  339. NULL
  340. );
  341. Status = NtCreateEvent(
  342. &Object,
  343. DesiredAccess,
  344. &Obja,
  345. NotificationEvent,
  346. (BOOLEAN) FALSE // The event is initially not signaled
  347. );
  348. if ( !NT_SUCCESS(Status)) {
  349. //
  350. // If the event already exists, the server beat us to creating it.
  351. // Just open it.
  352. //
  353. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  354. Status == STATUS_OBJECT_NAME_COLLISION ) {
  355. Status = NtOpenEvent( &Object,
  356. DesiredAccess,
  357. &Obja );
  358. }
  359. }
  360. if ( !NT_SUCCESS(Status) ) {
  361. SetLastError(RtlNtStatusToDosError( Status ));
  362. return NULL;
  363. }
  364. return Object;
  365. }
  366. //+-------------------------------------------------------------------------
  367. //
  368. // Function: KdcStartEvent
  369. //
  370. // Synopsis: sets the KdcStartEvent
  371. //
  372. // Effects:
  373. //
  374. // Arguments:
  375. //
  376. // Requires:
  377. //
  378. // Returns:
  379. //
  380. // Notes: The SPMgr must have created this event before this
  381. // is called
  382. //
  383. //
  384. //--------------------------------------------------------------------------
  385. void
  386. SetKdcStartEvent()
  387. {
  388. TRACE(KDC, SetKdcStartEvent, DEB_FUNCTION);
  389. HANDLE hEvent;
  390. hEvent = KdcOpenEvent(EVENT_MODIFY_STATE,FALSE,KDC_START_EVENT);
  391. if (hEvent != NULL)
  392. {
  393. SetEvent(hEvent);
  394. CloseHandle(hEvent);
  395. D_DebugLog((DEB_TRACE,"Set event %ws\n",KDC_START_EVENT));
  396. }
  397. else
  398. {
  399. DWORD dw = GetLastError();
  400. if (dw != ERROR_FILE_NOT_FOUND)
  401. DebugLog((DEB_ERROR,"Error opening %ws: %d\n",KDC_START_EVENT,dw));
  402. else
  403. D_DebugLog((DEB_TRACE,"Error opening %ws: %d\n",KDC_START_EVENT,dw));
  404. }
  405. }
  406. //+-------------------------------------------------------------------------
  407. //
  408. // Function: KdcLoadParameters
  409. //
  410. // Synopsis: Loads random parameters from registry
  411. //
  412. // Effects:
  413. //
  414. // Arguments:
  415. //
  416. // Requires:
  417. //
  418. // Returns:
  419. //
  420. // Notes:
  421. //
  422. //
  423. //--------------------------------------------------------------------------
  424. VOID
  425. KdcLoadParameters(
  426. VOID
  427. )
  428. {
  429. NET_API_STATUS NetStatus;
  430. LPNET_CONFIG_HANDLE ConfigHandle = NULL;
  431. LPNET_CONFIG_HANDLE NetlogonInfo = NULL;
  432. NetStatus = NetpOpenConfigData(
  433. &ConfigHandle,
  434. NULL, // noserer name
  435. SERVICE_KDC,
  436. TRUE // read only
  437. );
  438. if (NetStatus != NO_ERROR)
  439. {
  440. // we could return, but then we'd lose data
  441. D_DebugLog((DEB_WARN, "Couldn't open KDC config data - %x\n", NetStatus));
  442. // return;
  443. }
  444. //
  445. // Open Netlogon service key for AvoidPdcOnWan
  446. //
  447. NetStatus = NetpOpenConfigData(
  448. &NetlogonInfo,
  449. NULL,
  450. SERVICE_NETLOGON,
  451. TRUE
  452. );
  453. if (NetStatus != NO_ERROR)
  454. {
  455. D_DebugLog((DEB_WARN, "Failed to open netlogon key - %x\n", NetStatus));
  456. return;
  457. }
  458. NetStatus = NetpGetConfigBool(
  459. NetlogonInfo,
  460. L"AvoidPdcOnWan",
  461. FALSE,
  462. &KdcGlobalAvoidPdcOnWan
  463. );
  464. if (NetStatus != NO_ERROR)
  465. {
  466. D_DebugLog((DEB_WARN, "Failed to open netlogon key - %x\n", NetStatus));
  467. return;
  468. }
  469. NetpCloseConfigData( ConfigHandle );
  470. NetpCloseConfigData( NetlogonInfo );
  471. }
  472. //+-------------------------------------------------------------------------
  473. //
  474. // Function: OpenAccountDomain
  475. //
  476. // Synopsis: Opens the account domain and stores a handle to it.
  477. //
  478. // Effects: Sets GlobalAccountDomainHandle and GlobalPolicyHandle on
  479. // success.
  480. //
  481. // Arguments:
  482. //
  483. // Requires:
  484. //
  485. // Returns:
  486. //
  487. // Notes:
  488. //
  489. //
  490. //--------------------------------------------------------------------------
  491. NTSTATUS
  492. OpenAccountDomain()
  493. {
  494. NTSTATUS Status;
  495. PLSAPR_POLICY_INFORMATION PolicyInformation = NULL;
  496. SAMPR_HANDLE ServerHandle = NULL;
  497. Status = LsaIOpenPolicyTrusted( & GlobalPolicyHandle );
  498. if (!NT_SUCCESS(Status))
  499. {
  500. D_DebugLog((DEB_ERROR,"Failed to open policy trusted: 0x%x\n",Status));
  501. goto Cleanup;
  502. }
  503. Status = LsarQueryInformationPolicy(
  504. GlobalPolicyHandle,
  505. PolicyAccountDomainInformation,
  506. &PolicyInformation
  507. );
  508. if (!NT_SUCCESS(Status))
  509. {
  510. D_DebugLog((DEB_ERROR,"Failed to query information policy: 0x%x\n",Status));
  511. goto Cleanup;
  512. }
  513. //
  514. // Get the name and SID out of the account domain information
  515. //
  516. Status = KerbDuplicateString(
  517. &GlobalDomainName,
  518. (PUNICODE_STRING) &PolicyInformation->PolicyAccountDomainInfo.DomainName
  519. );
  520. if (!NT_SUCCESS(Status))
  521. {
  522. goto Cleanup;
  523. }
  524. GlobalDomainSid = (PSID) LocalAlloc(0, RtlLengthSid(PolicyInformation->PolicyAccountDomainInfo.DomainSid));
  525. if (GlobalDomainSid == 0)
  526. {
  527. Status = STATUS_INSUFFICIENT_RESOURCES;
  528. goto Cleanup;
  529. }
  530. RtlCopyMemory(
  531. GlobalDomainSid,
  532. PolicyInformation->PolicyAccountDomainInfo.DomainSid,
  533. RtlLengthSid(PolicyInformation->PolicyAccountDomainInfo.DomainSid)
  534. );
  535. //
  536. // Connect to SAM and open the account domain
  537. //
  538. Status = SamIConnect(
  539. NULL, // no server name
  540. &ServerHandle,
  541. 0, // ignore desired access,
  542. TRUE // trusted caller
  543. );
  544. if (!NT_SUCCESS(Status))
  545. {
  546. DebugLog((DEB_ERROR,"Failed to connect to SAM: 0x%x\n",Status));
  547. goto Cleanup;
  548. }
  549. //
  550. // Finally open the account domain.
  551. //
  552. Status = SamrOpenDomain(
  553. ServerHandle,
  554. DOMAIN_ALL_ACCESS,
  555. (PRPC_SID) PolicyInformation->PolicyAccountDomainInfo.DomainSid,
  556. &GlobalAccountDomainHandle
  557. );
  558. if (!NT_SUCCESS(Status))
  559. {
  560. DebugLog((DEB_ERROR, "Failed to open account domain: 0x%x\n",Status));
  561. goto Cleanup;
  562. }
  563. Cleanup:
  564. if (PolicyInformation != NULL)
  565. {
  566. LsaIFree_LSAPR_POLICY_INFORMATION(
  567. PolicyAccountDomainInformation,
  568. PolicyInformation
  569. );
  570. }
  571. if (ServerHandle != NULL)
  572. {
  573. SamrCloseHandle(&ServerHandle);
  574. }
  575. if (!NT_SUCCESS(Status))
  576. {
  577. if (GlobalPolicyHandle != NULL)
  578. {
  579. LsarClose(&GlobalPolicyHandle);
  580. GlobalPolicyHandle = NULL;
  581. }
  582. if (GlobalAccountDomainHandle != NULL)
  583. {
  584. SamrCloseHandle(&GlobalAccountDomainHandle);
  585. GlobalAccountDomainHandle = NULL;
  586. }
  587. }
  588. return(Status);
  589. }
  590. //+-------------------------------------------------------------------------
  591. //
  592. // Function: CleanupAccountDomain
  593. //
  594. // Synopsis: cleans up resources associated with SAM and LSA
  595. //
  596. // Effects:
  597. //
  598. // Arguments:
  599. //
  600. // Requires:
  601. //
  602. // Returns:
  603. //
  604. // Notes:
  605. //
  606. //
  607. //--------------------------------------------------------------------------
  608. VOID
  609. CleanupAccountDomain()
  610. {
  611. if (GlobalPolicyHandle != NULL)
  612. {
  613. LsarClose(&GlobalPolicyHandle);
  614. GlobalPolicyHandle = NULL;
  615. }
  616. if (GlobalAccountDomainHandle != NULL)
  617. {
  618. SamrCloseHandle(&GlobalAccountDomainHandle);
  619. GlobalAccountDomainHandle = NULL;
  620. }
  621. KerbFreeString(&GlobalDomainName);
  622. if (GlobalDomainSid != NULL)
  623. {
  624. LocalFree(GlobalDomainSid);
  625. GlobalDomainSid = NULL;
  626. }
  627. }
  628. //+-------------------------------------------------------------------------
  629. //
  630. // Name: KdcServiceMain
  631. //
  632. // Synopsis: This is the main KDC thread.
  633. //
  634. // Arguments: dwArgc -
  635. // pszArgv -
  636. //
  637. // Notes: This intializes everything, and starts the working threads.
  638. //
  639. //--------------------------------------------------------------------------
  640. extern "C"
  641. void
  642. KdcServiceMain( DWORD dwArgc,
  643. LPTSTR *pszArgv)
  644. {
  645. TRACE(KDC, KdcServiceMain, DEB_FUNCTION);
  646. NTSTATUS hrRet;
  647. ULONG RpcStatus;
  648. ULONG ThreadID;
  649. HANDLE hThread;
  650. HANDLE hParamEvent = NULL;
  651. ULONG ulStates = 0;
  652. NTSTATUS NtStatus = STATUS_SUCCESS;
  653. NTSTATUS TempStatus;
  654. KERBERR KerbErr;
  655. NT_PRODUCT_TYPE NtProductType;
  656. #define RPCDONE 0x1
  657. #define LOCATORSTARTED 0x2
  658. #define CRITSECSDONE 0x4
  659. KdcState = Starting;
  660. //
  661. // Get the debugging parameters
  662. //
  663. GetDebugParams();
  664. //
  665. // Get other parameters, register wait on debug key..
  666. //
  667. KdcLoadParameters();
  668. hParamEvent = CreateEvent(NULL,
  669. FALSE,
  670. FALSE,
  671. NULL);
  672. if (NULL == hParamEvent)
  673. {
  674. D_DebugLog((DEB_WARN, "CreateEvent for ParamEvent failed - 0x%x\n", GetLastError()));
  675. } else {
  676. KerbWatchParamKey(hParamEvent, FALSE);
  677. }
  678. D_DebugLog((DEB_TRACE, "Start KdcServiceMain\n"));
  679. //
  680. // Notify the service controller that we are starting.
  681. //
  682. hService = RegisterServiceCtrlHandler(SERVICE_KDC, Handler);
  683. if (!hService)
  684. {
  685. D_DebugLog((DEB_ERROR, "Could not register handler, %d\n", GetLastError()));
  686. }
  687. SStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  688. SStatus.dwCurrentState = SERVICE_STOPPED;
  689. SStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  690. SStatus.dwWin32ExitCode = 0;
  691. SStatus.dwServiceSpecificExitCode = 0;
  692. SStatus.dwCheckPoint = 0;
  693. SStatus.dwWaitHint = 0;
  694. if (!UpdateStatus(SERVICE_START_PENDING) )
  695. {
  696. goto Shutdown;
  697. }
  698. //
  699. // Set up the event log service
  700. //
  701. InitializeEvents();
  702. //
  703. // Check out product type
  704. //
  705. if ( !RtlGetNtProductType( &NtProductType ) || ( NtProductType != NtProductLanManNt ) ) {
  706. D_DebugLog((DEB_WARN, "Can't start KDC on non-lanmanNT systems\n"));
  707. NtStatus = STATUS_INVALID_SERVER_STATE;
  708. goto Shutdown;
  709. }
  710. RtlInitUnicodeString(
  711. &GlobalKerberosName,
  712. MICROSOFT_KERBEROS_NAME_W
  713. );
  714. RtlInitUnicodeString(
  715. &GlobalKdcName,
  716. SERVICE_KDC
  717. );
  718. //
  719. // Build our Kpasswd name, so we don't have to alloc on
  720. // every TGS request.
  721. //
  722. NtStatus = KerbBuildKpasswdName(
  723. &GlobalKpasswdName
  724. );
  725. if (!NT_SUCCESS(NtStatus))
  726. {
  727. D_DebugLog((DEB_ERROR, "Failed to build KPASSWED name, error 0x%X\n", NtStatus));
  728. goto Shutdown;
  729. }
  730. GlobalLocalhostAddress[0] = 127;
  731. GlobalLocalhostAddress[1] = 0;
  732. GlobalLocalhostAddress[2] = 0;
  733. GlobalLocalhostAddress[3] = 1;
  734. //
  735. // Wait for SAM to start
  736. //
  737. if (!KdcWaitForSamService( ))
  738. {
  739. NtStatus = STATUS_INVALID_SERVER_STATE;
  740. goto Shutdown;
  741. }
  742. if (!UpdateStatus(SERVICE_START_PENDING) )
  743. {
  744. goto Shutdown;
  745. }
  746. //
  747. // Can't proceed unless the kerb SSPI package has initialized
  748. // (KdrbKdcCallback might get invoked and that requires kerb
  749. // global resource being intialized)
  750. //
  751. if ( !KerbIsInitialized()) {
  752. NtStatus = STATUS_UNSUCCESSFUL;
  753. DebugLog((DEB_ERROR, "Kerb SSPI package not initialized: 0x%x\n",NtStatus));
  754. goto Shutdown;
  755. }
  756. //
  757. // Register for the Ds callback
  758. //
  759. if (!KdcRegisterToWaitForDS( ))
  760. {
  761. NtStatus = STATUS_INVALID_SERVER_STATE;
  762. goto Shutdown;
  763. }
  764. if (!UpdateStatus(SERVICE_START_PENDING) )
  765. {
  766. goto Shutdown;
  767. }
  768. //
  769. // Initialize notification
  770. //
  771. if (!InitializeChangeNotify())
  772. {
  773. hrRet = STATUS_INTERNAL_ERROR;
  774. goto Shutdown;
  775. }
  776. //
  777. // Get a handle to the SAM account domain
  778. //
  779. if (!UpdateStatus(SERVICE_START_PENDING) )
  780. {
  781. goto Shutdown;
  782. }
  783. NtStatus = OpenAccountDomain();
  784. if (!NT_SUCCESS(NtStatus))
  785. {
  786. DebugLog((DEB_ERROR, "Failed to get domain handle: 0x%x\n",NtStatus));
  787. goto Shutdown;
  788. }
  789. if (!UpdateStatus(SERVICE_START_PENDING) )
  790. {
  791. goto Shutdown;
  792. }
  793. //
  794. // Initialize the PK infrastructure
  795. //
  796. NtStatus = KdcInitializeCerts();
  797. if (!NT_SUCCESS(NtStatus))
  798. {
  799. D_DebugLog((DEB_ERROR,"Failed to initialize certs: 0x%x\n",NtStatus));
  800. goto Shutdown;
  801. }
  802. if (!UpdateStatus(SERVICE_START_PENDING) )
  803. {
  804. goto Shutdown;
  805. }
  806. //
  807. // Start the RPC sequences
  808. //
  809. NtStatus = StartAllProtSeqs();
  810. if (!NT_SUCCESS(NtStatus))
  811. {
  812. D_DebugLog((DEB_ERROR, "Failed to start RPC, error 0x%X\n", NtStatus));
  813. goto Shutdown;
  814. }
  815. //
  816. // Start the socket listening code.
  817. //
  818. if (!UpdateStatus(SERVICE_START_PENDING) )
  819. {
  820. goto Shutdown;
  821. }
  822. //
  823. // Load all global data into the SecData structure.
  824. //
  825. NtStatus = SecData.Init();
  826. if (!NT_SUCCESS(NtStatus))
  827. {
  828. D_DebugLog((DEB_ERROR, "Failed to init SecData error 0x%X\n", NtStatus));
  829. goto Shutdown;
  830. }
  831. //
  832. // Set the flag to indicate this is a trust account
  833. //
  834. // KdcTicketInfo.UserAccountControl |= USER_INTERDOMAIN_TRUST_ACCOUNT;
  835. if (!UpdateStatus(SERVICE_START_PENDING) )
  836. {
  837. goto Shutdown;
  838. }
  839. //
  840. // Create the KDC shutdown event, set to FALSE
  841. //
  842. hKdcShutdownEvent = CreateEvent( NULL, // no security attributes
  843. TRUE, // manual reset
  844. FALSE, // initial state
  845. NULL ); // unnamed event.
  846. if (hKdcShutdownEvent == NULL)
  847. {
  848. NtStatus = (NTSTATUS) GetLastError();
  849. D_DebugLog(( DEB_ERROR, "KDC can't create shutdown event: wincode=%d.\n",
  850. NtStatus ));
  851. goto Shutdown;
  852. }
  853. if (!UpdateStatus(SERVICE_START_PENDING) )
  854. {
  855. goto Shutdown;
  856. }
  857. #if DBG
  858. NtStatus = RegisterKdcEps();
  859. if(!NT_SUCCESS(NtStatus))
  860. {
  861. D_DebugLog((DEB_ERROR, "Ep register failed %x\n", NtStatus));
  862. // goto Shutdown;
  863. }
  864. #endif // DBG
  865. ulStates |= RPCDONE;
  866. //
  867. // 1 is the minimum number of threads.
  868. // TRUE means the call will return, rather than waiting until the
  869. // server shuts down.
  870. //
  871. NtStatus = KdcInitializeSockets();
  872. if (!NT_SUCCESS(NtStatus))
  873. {
  874. D_DebugLog((DEB_ERROR, "Failed to initailzie sockets\n"));
  875. goto Shutdown;
  876. }
  877. if (!UpdateStatus(SERVICE_START_PENDING) )
  878. {
  879. goto Shutdown;
  880. }
  881. InitializeListHead(&KdcDomainList);
  882. NtStatus = (NTSTATUS) KdcReloadDomainTree( NULL );
  883. if (!NT_SUCCESS(NtStatus))
  884. {
  885. D_DebugLog((DEB_ERROR, "Failed to build domain tree: 0x%x\n",NtStatus));
  886. goto Shutdown;
  887. }
  888. if (!UpdateStatus(SERVICE_START_PENDING) )
  889. {
  890. goto Shutdown;
  891. }
  892. //
  893. // Check to see if there is a CSP registered for replacing the StringToKey calculation
  894. //
  895. CheckForOutsideStringToKey();
  896. if (!UpdateStatus(SERVICE_START_PENDING) )
  897. {
  898. goto Shutdown;
  899. }
  900. NtStatus = LsaIKerberosRegisterTrustNotification( KdcTrustChangeCallback, LsaRegister );
  901. if (!NT_SUCCESS( NtStatus ))
  902. {
  903. D_DebugLog((DEB_ERROR, "Failed to register notification\n"));
  904. }
  905. RpcStatus = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
  906. if (RpcStatus != ERROR_SUCCESS)
  907. {
  908. if (RpcStatus != RPC_S_ALREADY_LISTENING)
  909. {
  910. D_DebugLog(( DEB_ERROR, "Error from RpcServerListen: %d\n", RpcStatus ));
  911. NtStatus = I_RpcMapWin32Status(RpcStatus);
  912. goto Shutdown;
  913. }
  914. }
  915. //
  916. // At this point the KDC is officially started.
  917. // 3 * ( 2*(hip) horray! )
  918. //
  919. if (!UpdateStatus(SERVICE_RUNNING) )
  920. {
  921. goto Shutdown;
  922. }
  923. #if DBG
  924. GetSystemTimeAsFileTime((PFILETIME)&tsOut);
  925. D_DebugLog((DEB_TRACE, "Time required for KDC to start up: %d ms\n",
  926. (tsOut.LowPart-tsIn.LowPart) / 10000));
  927. #endif
  928. SetKdcStartEvent();
  929. KdcState = Running;
  930. KdcInitializeTrace();
  931. // This function will loop until the event is true.
  932. // WAS BUG: turn off cache manager for now.
  933. // This bug comment is a stale piece of code from
  934. // Cairo days - per MikeSw
  935. //
  936. WaitForSingleObject(hKdcShutdownEvent, INFINITE);
  937. Shutdown:
  938. LsaIKerberosRegisterTrustNotification( KdcTrustChangeCallback, LsaUnregister );
  939. LsaIUnregisterAllPolicyChangeNotificationCallback(KdcPolicyChangeCallBack);
  940. //
  941. // Time to cleanup up all resources ...
  942. //
  943. TempStatus = I_NetLogonSetServiceBits( DS_KDC_FLAG, 0 );
  944. if ( !NT_SUCCESS(TempStatus) ) {
  945. D_DebugLog((DEB_TRACE,"Can't tell netlogon we're stopped 0x%lX\n", TempStatus ));
  946. }
  947. //
  948. // Remove the wait routine for the DS paused event
  949. //
  950. if ( KdcGlobalDsPausedWaitHandle != NULL ) {
  951. UnregisterWaitEx( KdcGlobalDsPausedWaitHandle,
  952. INVALID_HANDLE_VALUE ); // Wait until routine finishes execution
  953. KdcGlobalDsPausedWaitHandle = NULL;
  954. }
  955. if (NULL != GlobalKpasswdName)
  956. {
  957. KerbFreeKdcName(&GlobalKpasswdName);
  958. }
  959. if (KdcGlobalDsEventHandle)
  960. {
  961. CloseHandle( KdcGlobalDsEventHandle );
  962. KdcGlobalDsEventHandle = NULL;
  963. }
  964. //
  965. // Shut down event log service.
  966. //
  967. ShutdownEvents();
  968. UpdateStatus(SERVICE_STOP_PENDING);
  969. #if DBG
  970. if(ulStates & RPCDONE)
  971. {
  972. (VOID)UnRegisterKdcEps();
  973. UpdateStatus(SERVICE_STOP_PENDING);
  974. }
  975. #endif // DBG
  976. KdcShutdownSockets();
  977. KdcCleanupCerts(
  978. TRUE // cleanup scavenger
  979. );
  980. UpdateStatus(SERVICE_STOP_PENDING);
  981. //
  982. // Close all of the events.
  983. //
  984. {
  985. PHANDLE ph = &hKdcHandles[0];
  986. for(;ph < &hKdcHandles[MAX_KDC_HANDLE]; ph++)
  987. {
  988. if(*ph)
  989. {
  990. CloseHandle(*ph);
  991. *ph = NULL;
  992. }
  993. }
  994. }
  995. #ifdef RETAIL_LOG_SUPPORT
  996. if (hParamEvent) {
  997. WaitCleanup(hParamEvent);
  998. }
  999. #endif
  1000. //
  1001. // Cleanup handles to SAM & LSA and global variables
  1002. //
  1003. CleanupAccountDomain();
  1004. UpdateStatus(SERVICE_STOP_PENDING);
  1005. //
  1006. // Cleanup the domain list
  1007. //
  1008. //
  1009. // BUGBUG: need to make sure it is not being used.
  1010. //
  1011. KdcFreeDomainList(&KdcDomainList);
  1012. KdcFreeReferralCache(&KdcReferralCache);
  1013. SStatus.dwWin32ExitCode = RtlNtStatusToDosError(NtStatus);
  1014. SStatus.dwServiceSpecificExitCode = 0;
  1015. D_DebugLog(( DEB_TRACE, "KDC shutting down.\n" ));
  1016. UpdateStatus(SERVICE_STOPPED);
  1017. D_DebugLog((DEB_TRACE, "End KdcServiceMain\n"));
  1018. }
  1019. ////////////////////////////////////////////////////////////////////
  1020. //
  1021. // Name: ShutDown
  1022. //
  1023. // Synopsis: Shuts the KDC down.
  1024. //
  1025. // Arguments: pszMessage - message to print to debug port
  1026. //
  1027. // Notes: Stops RPC from accepting new calls, waits for pending calls
  1028. // to finish, and sets the global event "hKdcShutDownEvent".
  1029. //
  1030. NTSTATUS
  1031. ShutDown(LPWSTR pszMessage)
  1032. {
  1033. NTSTATUS NtStatus = STATUS_SUCCESS;
  1034. TRACE(KDC, ShutDown, DEB_FUNCTION);
  1035. D_DebugLog((DEB_WARN, "Server Shutdown: %ws\n", pszMessage));
  1036. //
  1037. // Notify the all threads that we are exiting.
  1038. //
  1039. //
  1040. // First set the started flag to false so nobody will try any more
  1041. // direct calls to the KDC.
  1042. //
  1043. KdcState = Stopped;
  1044. //
  1045. // If there are any outstanding calls, let them trigger the shutdown event.
  1046. // Otherwise set the shutdown event ourselves.
  1047. //
  1048. EnterCriticalSection(&ApiCriticalSection);
  1049. if (CurrentApiCallers == 0)
  1050. {
  1051. if (!SetEvent( hKdcShutdownEvent ) )
  1052. {
  1053. D_DebugLog(( DEB_ERROR, "Couldn't set KDC shutdown event. winerr=%d.\n",
  1054. GetLastError() ));
  1055. NtStatus = STATUS_UNSUCCESSFUL;
  1056. }
  1057. SecData.Cleanup();
  1058. if (KdcTraceRegistrationHandle != (TRACEHANDLE)0)
  1059. {
  1060. UnregisterTraceGuids( KdcTraceRegistrationHandle );
  1061. }
  1062. }
  1063. LeaveCriticalSection(&ApiCriticalSection);
  1064. return(NtStatus);
  1065. }
  1066. //+-------------------------------------------------------------------------
  1067. //
  1068. // Function: DllMain
  1069. //
  1070. // Synopsis: DLL initialization routine
  1071. //
  1072. //--------------------------------------------------------------------------
  1073. extern "C" BOOL WINAPI
  1074. DllMain (
  1075. HINSTANCE hInstance,
  1076. DWORD dwReason,
  1077. PVOID lpReserved
  1078. )
  1079. {
  1080. BOOL bReturn = TRUE;
  1081. if ( dwReason == DLL_PROCESS_ATTACH )
  1082. {
  1083. DisableThreadLibraryCalls ( hInstance );
  1084. //
  1085. // WAS BUG: call the Rtl version here because it returns an error
  1086. // instead of throwing an exception. Leave it here, as we don't
  1087. // really need to put a try/except around InitCritSec.
  1088. //
  1089. bReturn = NT_SUCCESS(RtlInitializeCriticalSection( &ApiCriticalSection ));
  1090. } else if (dwReason == DLL_PROCESS_DETACH) {
  1091. DeleteCriticalSection(&ApiCriticalSection);
  1092. }
  1093. return bReturn;
  1094. UNREFERENCED_PARAMETER(lpReserved);
  1095. UNREFERENCED_PARAMETER(hInstance);
  1096. }