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.

1032 lines
24 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. services.c
  5. Abstract:
  6. This is the service dispatcher for the security process. It contains
  7. the service dispatcher initialization routine and the routines to
  8. load the DLL for the individual serices and execute them.
  9. Author:
  10. Rajen Shah (rajens) 11-Apr-1991
  11. [Environment:]
  12. User Mode - Win32
  13. Revision History:
  14. 11-Apr-1991 RajenS
  15. created
  16. 27-Sep-1991 JohnRo
  17. More work toward UNICODE.
  18. 24-Jan-1991 CliffV
  19. Converted to be service dispatcher for the security process.
  20. --*/
  21. #include <lsapch2.h>
  22. #include <lmcons.h>
  23. #include <lmerr.h> // NERR_ and ERROR_ equates.
  24. #include <lmsname.h>
  25. #include <crypt.h>
  26. #include <logonmsv.h>
  27. #include <ntdsa.h>
  28. #include <netlib.h> // SET_SERVICE_EXITCODE
  29. //
  30. // Names of services run in-proc
  31. //
  32. #ifndef SERVICE_KDC
  33. #define SERVICE_KDC TEXT("KDC")
  34. #endif
  35. #ifndef SERVICE_SAM
  36. #define SERVICE_SAM TEXT("SAMSS")
  37. #endif
  38. #ifndef SERVICE_IPSECPOLICYAGENT
  39. #define SERVICE_IPSECPOLICYAGENT TEXT("PolicyAgent")
  40. #endif
  41. #ifndef SERVICE_PSTORE
  42. #define SERVICE_PSTORE TEXT("ProtectedStorage")
  43. #endif
  44. #ifndef SERVICE_HTTPFILTER
  45. #define SERVICE_HTTPFILTER TEXT("HTTPFilter")
  46. #endif
  47. //
  48. // Private API to tell the Service Controller
  49. // that this is the LSA.
  50. //
  51. VOID
  52. I_ScIsSecurityProcess(
  53. VOID
  54. );
  55. //
  56. // Internal service table structure/enum definitions
  57. //
  58. typedef struct _LSAP_SERVICE_TABLE
  59. {
  60. LPCSTR lpDllName;
  61. LPCSTR lpEntryPoint;
  62. LPCWSTR lpServiceName;
  63. }
  64. LSAP_SERVICE_TABLE, *PLSAP_SERVICE_TABLE;
  65. typedef enum
  66. {
  67. LSAP_SERVICE_NETLOGON,
  68. LSAP_SERVICE_KDC,
  69. LSAP_SERVICE_IPSECPOLICYAGENT,
  70. LSAP_SERVICE_PROTECTEDSTORAGE,
  71. LSAP_SERVICE_HTTPFILTER,
  72. LSAP_SERVICE_MAX
  73. }
  74. LSAP_SERVICE_TYPE, *PLSAP_SERVICE_TYPE;
  75. //
  76. // Keep this list in order with the service types above
  77. //
  78. LSAP_SERVICE_TABLE g_LsaServiceTable[LSAP_SERVICE_MAX] = {
  79. { "netlogon.dll" , "NlNetlogonMain" , SERVICE_NETLOGON } ,
  80. { "kdcsvc.dll" , "KdcServiceMain" , SERVICE_KDC } ,
  81. { "ipsecsvc.dll" , "SPDServiceMain" , SERVICE_IPSECPOLICYAGENT } ,
  82. { "pstorsvc.dll" , "PSTOREServiceMain", SERVICE_PSTORE } ,
  83. { "w3ssl.dll" , "HTTPFilterServiceMain" , SERVICE_HTTPFILTER }
  84. };
  85. //
  86. // Prototypes for the service-specific start routines themselves
  87. //
  88. VOID
  89. SrvLoadNetlogon(
  90. IN DWORD dwNumServicesArgs,
  91. IN LPTSTR *lpServiceArgVectors
  92. );
  93. VOID
  94. SrvLoadKdc(
  95. IN DWORD dwNumServicesArgs,
  96. IN LPTSTR *lpServiceArgVectors
  97. );
  98. VOID
  99. SrvLoadIPSecSvcs(
  100. IN DWORD dwNumServicesArgs,
  101. IN LPTSTR *lpServiceArgVectors
  102. );
  103. VOID
  104. SrvLoadNtlmssp(
  105. IN DWORD dwNumServicesArgs,
  106. IN LPTSTR *lpServiceArgVectors
  107. );
  108. VOID
  109. SrvLoadPSTORE(
  110. IN DWORD dwNumServicesArgs,
  111. IN LPTSTR *lpServiceArgVectors
  112. );
  113. VOID
  114. SrvLoadSamss(
  115. IN DWORD dwNumServicesArgs,
  116. IN LPTSTR *lpServiceArgVectors
  117. );
  118. VOID
  119. SrvLoadHTTPFilter(
  120. IN DWORD dwNumServicesArgs,
  121. IN LPTSTR *lpServiceArgVectors
  122. );
  123. //
  124. // The actual dispatch table for the in-proc services and their start routines
  125. //
  126. SERVICE_TABLE_ENTRY SecurityServiceDispatchTable[] = {
  127. { SERVICE_NETLOGON, SrvLoadNetlogon },
  128. { SERVICE_KDC, SrvLoadKdc },
  129. { SERVICE_NTLMSSP, SrvLoadNtlmssp },
  130. { SERVICE_IPSECPOLICYAGENT, SrvLoadIPSecSvcs },
  131. { SERVICE_PSTORE, SrvLoadPSTORE },
  132. { SERVICE_SAM, SrvLoadSamss },
  133. { SERVICE_HTTPFILTER, SrvLoadHTTPFilter },
  134. { NULL, NULL }
  135. };
  136. BOOLEAN
  137. LsapWaitForSamService(
  138. SERVICE_STATUS_HANDLE hService,
  139. SERVICE_STATUS *SStatus
  140. );
  141. VOID
  142. DummyControlHandler(
  143. IN DWORD opcode
  144. )
  145. /*++
  146. Routine Description:
  147. Process and respond to a control signal from the service controller.
  148. Arguments:
  149. opcode - Supplies a value which specifies the action for the Netlogon
  150. service to perform.
  151. Return Value:
  152. None.
  153. NOTE : this is a dummy handler, used to uninstall the netlogon service
  154. when we unable to load netlogon dll.
  155. --*/
  156. {
  157. DebugLog((DEB_TRACE, "[Security Process] in control handler\n"));
  158. return;
  159. }
  160. VOID
  161. LsapStartService(
  162. IN LSAP_SERVICE_TYPE ServiceType,
  163. IN DWORD dwNumServicesArgs,
  164. IN LPTSTR *lpServiceArgVectors,
  165. IN BOOLEAN fUnload
  166. )
  167. {
  168. NET_API_STATUS NetStatus;
  169. HANDLE DllHandle = NULL;
  170. LPSERVICE_MAIN_FUNCTION pfnServiceMain;
  171. SERVICE_STATUS_HANDLE ServiceHandle;
  172. SERVICE_STATUS ServiceStatus;
  173. //
  174. // Load the service DLL
  175. //
  176. DllHandle = LoadLibraryA(g_LsaServiceTable[ServiceType].lpDllName);
  177. if (DllHandle == NULL)
  178. {
  179. NetStatus = GetLastError();
  180. DebugLog((DEB_ERROR,
  181. "[Security process] load library %s failed %ld\n",
  182. g_LsaServiceTable[ServiceType].lpDllName,
  183. NetStatus));
  184. goto Cleanup;
  185. }
  186. //
  187. // Find the main entry point for the service
  188. //
  189. pfnServiceMain = (LPSERVICE_MAIN_FUNCTION) GetProcAddress(DllHandle,
  190. g_LsaServiceTable[ServiceType].lpEntryPoint);
  191. if (pfnServiceMain == NULL)
  192. {
  193. NetStatus = GetLastError();
  194. DebugLog((DEB_ERROR,
  195. "[Security process] GetProcAddress %s failed %ld\n",
  196. g_LsaServiceTable[ServiceType].lpEntryPoint,
  197. NetStatus));
  198. goto Cleanup;
  199. }
  200. //
  201. // Call the service entrypoint
  202. //
  203. (*pfnServiceMain)(dwNumServicesArgs, lpServiceArgVectors);
  204. //
  205. // Note that it's inherently unsafe to load/unload a service DLL, which is why
  206. // no LSA-hosted service in the product should have this set to TRUE for a
  207. // call to LsapStartService. Leave this code in here, however, as it facilitates
  208. // debugging and fast swapping of private binaries for developers of said services.
  209. //
  210. if(fUnload)
  211. {
  212. FreeLibrary(DllHandle);
  213. }
  214. return;
  215. Cleanup:
  216. if (DllHandle != NULL)
  217. {
  218. FreeLibrary(DllHandle);
  219. }
  220. //
  221. // Register the service to the Service Controller
  222. //
  223. ServiceHandle = RegisterServiceCtrlHandler(g_LsaServiceTable[ServiceType].lpServiceName,
  224. DummyControlHandler);
  225. if (ServiceHandle != 0)
  226. {
  227. //
  228. // inform service controller that the service can't start.
  229. //
  230. ServiceStatus.dwServiceType = SERVICE_WIN32;
  231. ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  232. ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
  233. ServiceStatus.dwCheckPoint = 0;
  234. ServiceStatus.dwWaitHint = 0;
  235. SET_SERVICE_EXITCODE(NetStatus,
  236. ServiceStatus.dwWin32ExitCode,
  237. ServiceStatus.dwServiceSpecificExitCode);
  238. if (!SetServiceStatus( ServiceHandle, &ServiceStatus))
  239. {
  240. DebugLog((DEB_ERROR,
  241. "[Security process] SetServiceStatus for %ws failed %ld\n",
  242. g_LsaServiceTable[ServiceType].lpServiceName,
  243. GetLastError()));
  244. }
  245. }
  246. else
  247. {
  248. DebugLog((DEB_ERROR,
  249. "[Security process] RegisterServiceCtrlHandler for %ws failed %ld\n",
  250. g_LsaServiceTable[ServiceType].lpServiceName,
  251. GetLastError()));
  252. }
  253. return;
  254. }
  255. VOID
  256. SrvLoadNetlogon (
  257. IN DWORD dwNumServicesArgs,
  258. IN LPTSTR *lpServiceArgVectors
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is the 'main' routine for the netlogon service. It loads
  263. Netlogon.dll (which contains the remainder of the service) and
  264. calls the main entry point there.
  265. Arguments:
  266. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  267. lpServiceArgVectors - Argument strings.
  268. Return Value:
  269. return nothing.
  270. Note:
  271. --*/
  272. {
  273. LsapStartService(LSAP_SERVICE_NETLOGON, dwNumServicesArgs, lpServiceArgVectors, FALSE);
  274. }
  275. VOID
  276. SrvLoadKdc (
  277. IN DWORD dwNumServicesArgs,
  278. IN LPTSTR *lpServiceArgVectors
  279. )
  280. /*++
  281. Routine Description:
  282. This routine is the 'main' routine for the KDC service. It loads
  283. Netlogon.dll (which contains the remainder of the service) and
  284. calls the main entry point there.
  285. Arguments:
  286. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  287. lpServiceArgVectors - Argument strings.
  288. Return Value:
  289. return nothing.
  290. Note:
  291. --*/
  292. {
  293. LsapStartService(LSAP_SERVICE_KDC, dwNumServicesArgs, lpServiceArgVectors, FALSE);
  294. }
  295. SERVICE_STATUS_HANDLE hService;
  296. SERVICE_STATUS SStatus;
  297. void
  298. NtlmsspHandler(DWORD dwControl)
  299. {
  300. switch (dwControl)
  301. {
  302. case SERVICE_CONTROL_STOP:
  303. SStatus.dwCurrentState = SERVICE_STOPPED;
  304. if (!SetServiceStatus(hService, &SStatus)) {
  305. KdPrint(("Failed to set service status: %d\n",GetLastError()));
  306. hService = 0;
  307. }
  308. break;
  309. default:
  310. break;
  311. }
  312. }
  313. VOID
  314. SrvLoadNtlmssp (
  315. IN DWORD dwNumServicesArgs,
  316. IN LPTSTR *lpServiceArgVectors
  317. )
  318. /*++
  319. Routine Description:
  320. This routine is the 'main' routine for the KDC service. It loads
  321. Netlogon.dll (which contains the remainder of the service) and
  322. calls the main entry point there.
  323. Arguments:
  324. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  325. lpServiceArgVectors - Argument strings.
  326. Return Value:
  327. return nothing.
  328. Note:
  329. --*/
  330. {
  331. //
  332. // Notify the service controller that we are starting.
  333. //
  334. hService = RegisterServiceCtrlHandler(SERVICE_NTLMSSP, NtlmsspHandler);
  335. if (hService)
  336. {
  337. SStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  338. SStatus.dwCurrentState = SERVICE_RUNNING;
  339. SStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  340. SStatus.dwWin32ExitCode = 0;
  341. SStatus.dwServiceSpecificExitCode = 0;
  342. SStatus.dwCheckPoint = 0;
  343. SStatus.dwWaitHint = 0;
  344. if (!SetServiceStatus(hService, &SStatus)) {
  345. KdPrint(("Failed to set service status: %d\n",GetLastError()));
  346. }
  347. }
  348. else
  349. {
  350. KdPrint(("Could not register handler, %d\n", GetLastError()));
  351. }
  352. return;
  353. }
  354. VOID
  355. SrvLoadIPSecSvcs (
  356. IN DWORD dwNumServicesArgs,
  357. IN LPTSTR *lpServiceArgVectors
  358. )
  359. /*++
  360. Routine Description:
  361. This routine is the 'main' routine for the IPSEC Services. It loads
  362. ipsecsvc.dll (which contains the service implementation) and
  363. calls the main entry point there.
  364. Arguments:
  365. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  366. lpServiceArgVectors - Argument strings.
  367. Return Value:
  368. return nothing.
  369. Note:
  370. --*/
  371. {
  372. LsapStartService(LSAP_SERVICE_IPSECPOLICYAGENT, dwNumServicesArgs, lpServiceArgVectors, FALSE);
  373. }
  374. VOID
  375. SrvLoadPSTORE (
  376. IN DWORD dwNumServicesArgs,
  377. IN LPTSTR *lpServiceArgVectors
  378. )
  379. /*++
  380. Routine Description:
  381. This routine is the 'main' routine for the PSTORE service. It loads
  382. cryptsvc.dll (which contains the service implementation) and
  383. calls the main entry point there.
  384. Arguments:
  385. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  386. lpServiceArgVectors - Argument strings.
  387. Return Value:
  388. return nothing.
  389. Note:
  390. --*/
  391. {
  392. LsapStartService(LSAP_SERVICE_PROTECTEDSTORAGE, dwNumServicesArgs, lpServiceArgVectors, FALSE);
  393. }
  394. VOID
  395. SrvLoadHTTPFilter(
  396. IN DWORD dwNumServicesArgs,
  397. IN LPTSTR *lpServiceArgVectors
  398. )
  399. /*++
  400. Routine Description:
  401. This routine is the 'main' routine for the w3ssl service, run in-proc
  402. for improving SSL performance. It loads w3ssl.dll (which contains the
  403. remainder of the service) and calls the main entry point there.
  404. Arguments:
  405. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  406. lpServiceArgVectors - Argument strings.
  407. Return Value:
  408. return nothing.
  409. Note:
  410. --*/
  411. {
  412. LsapStartService(LSAP_SERVICE_HTTPFILTER, dwNumServicesArgs, lpServiceArgVectors, FALSE);
  413. }
  414. VOID
  415. SrvLoadSamss (
  416. IN DWORD dwNumServicesArgs,
  417. IN LPTSTR *lpServiceArgVectors
  418. )
  419. /*++
  420. Routine Description:
  421. This routine is the 'main' routine for the KDC service. It loads
  422. Netlogon.dll (which contains the remainder of the service) and
  423. calls the main entry point there.
  424. Arguments:
  425. dwNumServicesArgs - Number of arguments in lpServiceArgVectors.
  426. lpServiceArgVectors - Argument strings.
  427. Return Value:
  428. return nothing.
  429. Note:
  430. --*/
  431. {
  432. SERVICE_STATUS_HANDLE hService;
  433. SERVICE_STATUS SStatus;
  434. HANDLE hDsStartup = NULL;
  435. DWORD err = 0;
  436. DWORD netError = ERROR_GEN_FAILURE;
  437. NT_PRODUCT_TYPE prod;
  438. //
  439. // Notify the service controller that we are starting.
  440. //
  441. hService = RegisterServiceCtrlHandler(SERVICE_SAM, DummyControlHandler);
  442. if (hService == 0 ) {
  443. KdPrint(("Could not register handler, %d\n", GetLastError()));
  444. return;
  445. }
  446. //
  447. // Which product are we running on?
  448. //
  449. if ( !RtlGetNtProductType( &prod ) ) {
  450. KdPrint(("RtlGetNtProductType failed with %d. Defaulting to Winnt\n",
  451. GetLastError()));
  452. prod = NtProductWinNt;
  453. }
  454. //
  455. // if this is a DS, also wait for the DS
  456. //
  457. if ( prod == NtProductLanManNt ) {
  458. if ( SampUsingDsData() ) {
  459. hDsStartup = CreateEvent(NULL, TRUE, FALSE,
  460. NTDS_DELAYED_STARTUP_COMPLETED_EVENT);
  461. if ( hDsStartup == NULL ) {
  462. KdPrint(("SrvLoadSamss: CreateEvent failed with %d\n",GetLastError()));
  463. }
  464. }
  465. }
  466. SStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  467. SStatus.dwCurrentState = SERVICE_START_PENDING;
  468. SStatus.dwControlsAccepted = 0;
  469. SStatus.dwWin32ExitCode = 0;
  470. SStatus.dwServiceSpecificExitCode = 0;
  471. SStatus.dwCheckPoint = 1;
  472. SStatus.dwWaitHint = 30*1000; // 30 sec
  473. //
  474. // Wait for sam startup
  475. //
  476. if (!LsapWaitForSamService(hService, &SStatus)) {
  477. KdPrint(("error waiting for sam\n"));
  478. goto exit;
  479. }
  480. //
  481. // Wait for DS
  482. //
  483. if ( hDsStartup != NULL ) {
  484. SStatus.dwWaitHint = 64*1000; // 64 sec
  485. do {
  486. if (!SetServiceStatus(hService, &SStatus)) {
  487. KdPrint(("LoadSamss: Failed to set service status: %d\n",GetLastError()));
  488. }
  489. SStatus.dwCheckPoint++;
  490. err = WaitForSingleObject(hDsStartup, 60 * 1000);
  491. } while ( err == WAIT_TIMEOUT );
  492. } else {
  493. err = WAIT_OBJECT_0;
  494. }
  495. exit:
  496. if ( err == WAIT_OBJECT_0 ) {
  497. SStatus.dwCurrentState = SERVICE_RUNNING;
  498. } else {
  499. KdPrint(("SAM service failed to start[Error %d].\n", netError));
  500. SStatus.dwCurrentState = SERVICE_STOPPED;
  501. SET_SERVICE_EXITCODE(
  502. netError,
  503. SStatus.dwWin32ExitCode,
  504. SStatus.dwServiceSpecificExitCode
  505. );
  506. }
  507. SStatus.dwCheckPoint = 0;
  508. SStatus.dwWaitHint = 0;
  509. if (!SetServiceStatus(hService, &SStatus)) {
  510. KdPrint(("LoadSamss: Failed to set service status: %d\n",GetLastError()));
  511. }
  512. if ( hDsStartup != NULL ) {
  513. CloseHandle(hDsStartup);
  514. }
  515. return;
  516. } // SrvLoadSamss
  517. DWORD
  518. ServiceDispatcherThread (
  519. LPVOID Parameter
  520. )
  521. /*++
  522. Routine Description:
  523. This routine synchronizes with the service controller. It waits
  524. for the service controller to set the SECURITY_SERVICES_STARTED
  525. event then starts up the main
  526. thread that is going to handle the control requests from the service
  527. controller.
  528. It basically sets up the ControlDispatcher and, on return, exits from
  529. this main thread. The call to NetServiceStartCtrlDispatcher does
  530. not return until all services have terminated, and this process can
  531. go away.
  532. It will be up to the ControlDispatcher thread to start/stop/pause/continue
  533. any services. If a service is to be started, it will create a thread
  534. and then call the main routine of that service.
  535. Arguments:
  536. EventHandle - Event handle to wait on before continuing.
  537. Return Value:
  538. Exit status of thread.
  539. Note:
  540. --*/
  541. {
  542. DWORD WaitStatus;
  543. HANDLE EventHandle;
  544. BOOL StartStatus;
  545. //
  546. // Create an event for us to wait on.
  547. //
  548. EventHandle = CreateEventW( NULL, // No special security
  549. TRUE, // Must be manually reset
  550. FALSE, // The event is initially not signalled
  551. SECURITY_SERVICES_STARTED );
  552. if ( EventHandle == NULL ) {
  553. WaitStatus = GetLastError();
  554. //
  555. // If the event already exists,
  556. // the service controller already created it. Just open it.
  557. //
  558. if ( WaitStatus == ERROR_ALREADY_EXISTS ) {
  559. EventHandle = OpenEventW( EVENT_ALL_ACCESS,
  560. FALSE,
  561. SECURITY_SERVICES_STARTED );
  562. if ( EventHandle == NULL ) {
  563. WaitStatus = GetLastError();
  564. DebugLog((DEB_ERROR,
  565. "[Security process] OpenEvent failed %ld\n",
  566. WaitStatus));
  567. return WaitStatus;
  568. }
  569. } else {
  570. DebugLog((DEB_ERROR,
  571. "[Security process] CreateEvent failed %ld\n",
  572. WaitStatus));
  573. return WaitStatus;
  574. }
  575. }
  576. //
  577. // Wait for the service controller to come up.
  578. //
  579. WaitStatus = WaitForSingleObject( (HANDLE) EventHandle, (DWORD) -1 );
  580. CloseHandle( EventHandle );
  581. if ( WaitStatus != 0 ) {
  582. DebugLog((DEB_ERROR,
  583. "[Security process] WaitForSingleObject failed %ld\n",
  584. WaitStatus));
  585. return WaitStatus;
  586. }
  587. //
  588. // Let the client side of the Service Controller know that
  589. // is the security process
  590. //
  591. I_ScIsSecurityProcess();
  592. //
  593. // Call NetServiceStartCtrlDispatcher to set up the control interface.
  594. // The API won't return until all services have been terminated. At that
  595. // point, we just exit.
  596. //
  597. StartStatus = StartServiceCtrlDispatcher(SecurityServiceDispatchTable);
  598. DebugLog((DEB_ERROR,
  599. "[Security process] return from StartCtrlDispatcher %ld \n",
  600. StartStatus));
  601. return StartStatus;
  602. UNREFERENCED_PARAMETER(Parameter);
  603. }
  604. NTSTATUS
  605. ServiceInit (
  606. VOID
  607. )
  608. /*++
  609. Routine Description:
  610. This is a main routine for the service dispatcher of the security process.
  611. It starts up a thread responsible for coordinating with the
  612. service controller.
  613. Arguments:
  614. NONE.
  615. Return Value:
  616. Status of the thread creation operation.
  617. Note:
  618. --*/
  619. {
  620. DWORD ThreadId;
  621. HANDLE ThreadHandle;
  622. //
  623. // The control dispatcher runs in a thread of its own.
  624. //
  625. ThreadHandle = CreateThread(
  626. NULL, // No special thread attributes
  627. 0, // No special stack size
  628. &ServiceDispatcherThread,
  629. NULL, // No special parameter
  630. 0, // No special creation flags
  631. &ThreadId);
  632. if ( ThreadHandle == NULL ) {
  633. return (NTSTATUS) GetLastError();
  634. } else {
  635. CloseHandle(ThreadHandle);
  636. }
  637. return STATUS_SUCCESS;
  638. }
  639. BOOLEAN
  640. LsapWaitForSamService(
  641. SERVICE_STATUS_HANDLE hService,
  642. SERVICE_STATUS* SStatus
  643. )
  644. /*++
  645. Routine Description:
  646. This procedure waits for the SAM service to start and to complete
  647. all its initialization.
  648. Arguments:
  649. NetlogonServiceCalling:
  650. TRUE if this is the netlogon service proper calling
  651. FALSE if this is the changelog worker thread calling
  652. Return Value:
  653. TRUE : if the SAM service is successfully starts.
  654. FALSE : if the SAM service can't start.
  655. --*/
  656. {
  657. NTSTATUS Status;
  658. DWORD WaitStatus;
  659. UNICODE_STRING EventName;
  660. HANDLE EventHandle;
  661. OBJECT_ATTRIBUTES EventAttributes;
  662. //
  663. // open SAM event
  664. //
  665. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  666. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  667. Status = NtOpenEvent( &EventHandle,
  668. SYNCHRONIZE|EVENT_MODIFY_STATE,
  669. &EventAttributes );
  670. if ( !NT_SUCCESS(Status)) {
  671. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  672. //
  673. // SAM hasn't created this event yet, let us create it now.
  674. // SAM opens this event to set it.
  675. //
  676. Status = NtCreateEvent(
  677. &EventHandle,
  678. SYNCHRONIZE|EVENT_MODIFY_STATE,
  679. &EventAttributes,
  680. NotificationEvent,
  681. FALSE // The event is initially not signaled
  682. );
  683. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  684. Status == STATUS_OBJECT_NAME_COLLISION ) {
  685. //
  686. // second change, if the SAM created the event before we
  687. // do.
  688. //
  689. Status = NtOpenEvent( &EventHandle,
  690. SYNCHRONIZE|EVENT_MODIFY_STATE,
  691. &EventAttributes );
  692. }
  693. }
  694. if ( !NT_SUCCESS(Status)) {
  695. //
  696. // could not make the event handle
  697. //
  698. KdPrint(("NlWaitForSamService couldn't make the event handle : "
  699. "%lx\n", Status));
  700. return( FALSE );
  701. }
  702. }
  703. //
  704. // Loop waiting.
  705. //
  706. for (;;) {
  707. WaitStatus = WaitForSingleObject( EventHandle,
  708. 5*1000 ); // 5 Seconds
  709. if ( WaitStatus == WAIT_TIMEOUT ) {
  710. if (!SetServiceStatus(hService, SStatus)) {
  711. KdPrint(("LoadSamss: Failed to set service status: %d\n",GetLastError()));
  712. }
  713. SStatus->dwCheckPoint++;
  714. continue;
  715. } else if ( WaitStatus == WAIT_OBJECT_0 ) {
  716. break;
  717. } else {
  718. KdPrint(("NlWaitForSamService: error %ld %ld\n",
  719. GetLastError(),
  720. WaitStatus ));
  721. (VOID) NtClose( EventHandle );
  722. return FALSE;
  723. }
  724. }
  725. (VOID) NtClose( EventHandle );
  726. return TRUE;
  727. } // LsapWaitForSamService