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.

700 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990-91 Microsoft Corporation
  3. Module Name:
  4. srvmain.c
  5. Abstract:
  6. This is the main routine for the NT LAN Manager Server Service.
  7. !!! Does service controller guarantee no controls will be issued
  8. while we are initializing? Also, does it serialize controls?
  9. If not, we need some synchronization in here.
  10. Author:
  11. David Treadwell (davidtr) 05-10-1991
  12. Revision History:
  13. 19-Jan-1993 Danl
  14. Removed the old long endpoint name "LanmanServer".
  15. 07-Jan-1993 Danl
  16. Added an RPC endpoint name using "srvsvc", since "LanmanServer" is
  17. too long for DOS machines to _access.
  18. For a short time we will support both names.
  19. 18-Feb-1992 ritaw
  20. Convert to Win32 service control APIs.
  21. --*/
  22. #include "srvsvcp.h"
  23. #include <windows.h>
  24. #include <lmerr.h>
  25. #include <lmsname.h>
  26. #include <tstr.h>
  27. #include <wincon.h>
  28. #include <winsvc.h>
  29. #include <netlib.h>
  30. #include <netlibnt.h> // NetpNtStatusToApiStatus
  31. #include <netdebug.h> // NetpKdPrint
  32. #include <rpcutil.h>
  33. #include <srvann.h>
  34. #include <srvnames.h> // SERVER_INTERFACE_NAME
  35. #include <dbt.h>
  36. #include <mountmgr.h>
  37. SERVICE_STATUS SsServiceStatus;
  38. SERVICE_STATUS_HANDLE SsServiceStatusHandle;
  39. DWORD
  40. WINAPI
  41. ControlResponse(
  42. DWORD fdwControl,
  43. DWORD fdwEventType,
  44. LPVOID lpEventData,
  45. LPVOID lpContext
  46. );
  47. VOID
  48. SvchostPushServiceGlobals(
  49. PSVCHOST_GLOBAL_DATA pGlobals
  50. )
  51. {
  52. SsData.SsLmsvcsGlobalData = pGlobals;
  53. }
  54. VOID
  55. ServiceMain(
  56. IN DWORD argc,
  57. IN LPWSTR argv[]
  58. )
  59. /*++
  60. Routine Description:
  61. This is the "main" routine for the server service. The containing
  62. process will call this routine when we're supposed to start up.
  63. Arguments:
  64. Return Value:
  65. None.
  66. --*/
  67. {
  68. RPC_STATUS rpcStatus;
  69. NET_API_STATUS error;
  70. NET_API_STATUS terminationError;
  71. BOOLEAN rpcServerStarted = FALSE;
  72. NTSTATUS Status;
  73. HANDLE EventHandle;
  74. OBJECT_ATTRIBUTES EventAttributes;
  75. UNICODE_STRING EventNameString;
  76. LARGE_INTEGER LocalTimeout;
  77. PSVCHOST_GLOBAL_DATA pTempGlobals = SsData.SsLmsvcsGlobalData;
  78. RtlZeroMemory( &SsData, sizeof( SsData ) );
  79. RtlZeroMemory( &SsServiceStatus, sizeof( SsServiceStatus ) );
  80. SsData.SsLmsvcsGlobalData = pTempGlobals;
  81. SsServiceStatusHandle = 0;
  82. SsInitializeServerInfoFields();
  83. //
  84. // Make sure svchost.exe gave us the global data
  85. //
  86. ASSERT(SsData.SsLmsvcsGlobalData != NULL);
  87. //
  88. // Skip the Service Name in the argument list.
  89. //
  90. if (argc > 0) {
  91. argc--;
  92. if (argc > 0) {
  93. argv = &(argv[1]);
  94. }
  95. }
  96. #if DBG
  97. //
  98. // Set up for debugging--the first command line argument may be
  99. // "/debug:X" where SsDebug gets set to X.
  100. //
  101. if ( argc > 0 && STRNICMP( TEXT("/debug:"), (LPWSTR)argv[0], 7 ) == 0 ) {
  102. #ifdef UNICODE
  103. UNICODE_STRING ustr;
  104. RtlInitUnicodeString( &ustr, (PWSTR)argv[0] + 7 );
  105. RtlUnicodeStringToInteger( &ustr, 16, &SsDebug );
  106. #else
  107. SsDebug = 0;
  108. RtlCharToInteger( argv[0] + 7, 16, &SsDebug );
  109. #endif
  110. }
  111. #ifndef USE_DEBUGGER
  112. //SsDebug = 0xffff;
  113. if ( SsDebug != 0 ) {
  114. CONSOLE_SCREEN_BUFFER_INFO csbi;
  115. COORD coord;
  116. (VOID)AllocConsole( );
  117. (VOID)GetConsoleScreenBufferInfo(
  118. GetStdHandle(STD_OUTPUT_HANDLE),
  119. &csbi
  120. );
  121. coord.X = (SHORT)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
  122. coord.Y = (SHORT)((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) * 20);
  123. (VOID)SetConsoleScreenBufferSize(
  124. GetStdHandle(STD_OUTPUT_HANDLE),
  125. coord
  126. );
  127. }
  128. #endif
  129. #endif
  130. IF_DEBUG(INITIALIZATION) {
  131. SS_PRINT(( "SRVSVC_main: server service starting.\n" ));
  132. }
  133. IF_DEBUG(INITIALIZATION_BREAKPOINT) {
  134. DbgUserBreakPoint( );
  135. }
  136. //
  137. // Initialize all the status fields so that subsequent calls to
  138. // SetServiceStatus need to only update fields that changed.
  139. //
  140. SsServiceStatus.dwServiceType = SERVICE_WIN32;
  141. SsServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  142. SsServiceStatus.dwControlsAccepted = 0;
  143. SsServiceStatus.dwCheckPoint = 1;
  144. SsServiceStatus.dwWaitHint = 30000; // 30 seconds
  145. SET_SERVICE_EXITCODE(
  146. NO_ERROR,
  147. SsServiceStatus.dwWin32ExitCode,
  148. SsServiceStatus.dwServiceSpecificExitCode
  149. );
  150. //
  151. // Initialize server to receive service requests by registering the
  152. // control handler.
  153. //
  154. SsServiceStatusHandle = RegisterServiceCtrlHandlerEx(
  155. SERVICE_SERVER,
  156. ControlResponse,
  157. NULL
  158. );
  159. if ( SsServiceStatusHandle == 0 ) {
  160. error = GetLastError();
  161. IF_DEBUG(INITIALIZATION_ERRORS) {
  162. SS_PRINT(( "SRVSVC_main: RegisterServiceCtrlHandler failed: "
  163. "%ld\n", error ));
  164. }
  165. goto exit;
  166. }
  167. IF_DEBUG(INITIALIZATION) {
  168. SS_PRINT(( "SRVSVC_main: Control handler registered.\n" ));
  169. }
  170. //
  171. // Wait for the Sam service to start.
  172. //
  173. // Later, when we initialize the server driver, it is going to create a
  174. // "NULL Session" token by calling LsaLogonUser. That call waits until
  175. // SAM is initialized. However, we don't have an opportunity to give
  176. // wait hints to the service controller, so we'll wait here.
  177. //
  178. // Create the event to wait on.
  179. //
  180. RtlInitUnicodeString( &EventNameString, L"\\SAM_SERVICE_STARTED" );
  181. InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
  182. Status = NtCreateEvent(
  183. &EventHandle,
  184. SYNCHRONIZE,
  185. &EventAttributes,
  186. NotificationEvent,
  187. (BOOLEAN) FALSE // The event is initially not signaled
  188. );
  189. if ( !NT_SUCCESS(Status)) {
  190. //
  191. // If the event already exists, SAM beat us to creating it.
  192. // Just open it.
  193. //
  194. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  195. Status == STATUS_OBJECT_NAME_COLLISION ) {
  196. Status = NtOpenEvent( &EventHandle,
  197. SYNCHRONIZE,
  198. &EventAttributes );
  199. }
  200. if ( !NT_SUCCESS(Status)) {
  201. error = NetpNtStatusToApiStatus(Status);
  202. IF_DEBUG(INITIALIZATION_ERRORS) {
  203. SS_PRINT(( "SRVSVC_main: Can't open SAM_SERVICE_STARTED event: %lx\n",
  204. Status ));
  205. }
  206. goto exit;
  207. }
  208. }
  209. //
  210. // Wait for SAM to finish initializing.
  211. //
  212. LocalTimeout = RtlEnlargedIntegerMultiply( SsServiceStatus.dwWaitHint/2, -10000 );
  213. do {
  214. IF_DEBUG(INITIALIZATION) {
  215. SS_PRINT(( "SRVSVC_main: Wait for SAM to init.\n" ));
  216. }
  217. AnnounceServiceStatus( 1 );
  218. Status = NtWaitForSingleObject( EventHandle,
  219. (BOOLEAN)FALSE,
  220. &LocalTimeout);
  221. } while ( Status == STATUS_TIMEOUT );
  222. (VOID) NtClose( EventHandle );
  223. if ( !NT_SUCCESS(Status) ) {
  224. error = NetpNtStatusToApiStatus(Status);
  225. IF_DEBUG(INITIALIZATION_ERRORS) {
  226. SS_PRINT(( "SRVSVC_main: Wait for SAM_SERVICE_STARTED event failed: %lx\n",
  227. Status ));
  228. }
  229. goto exit;
  230. }
  231. IF_DEBUG(INITIALIZATION) {
  232. SS_PRINT(( "SRVSVC_main: Done waiting for SAM to init.\n" ));
  233. }
  234. AnnounceServiceStatus( 1 );
  235. //
  236. // Initialize server service data and the Lanman server FSP in kernel
  237. // mode.
  238. //
  239. error = SsInitialize( argc, argv );
  240. if ( error != NO_ERROR ) {
  241. goto exit;
  242. }
  243. //
  244. // Set the variable that indicates that the server is fully
  245. // initialized.
  246. //
  247. SS_ASSERT( !SsData.SsInitialized );
  248. SsData.SsInitialized = TRUE;
  249. //
  250. // Start the RPC server. Because other services may reside in this
  251. // process, the actual RPC server may already have been started;
  252. // this routine will track this for us.
  253. //
  254. rpcStatus = SsData.SsLmsvcsGlobalData->StartRpcServer(
  255. SERVER_INTERFACE_NAME,
  256. srvsvc_ServerIfHandle
  257. );
  258. if ( rpcStatus != 0 ) {
  259. IF_DEBUG(INITIALIZATION_ERRORS) {
  260. SS_PRINT(( "SRVSVC_main: NetpStartRpcServer failed: %X\n",
  261. rpcStatus ));
  262. }
  263. error = rpcStatus;
  264. goto exit;
  265. }
  266. IF_DEBUG(INITIALIZATION) {
  267. SS_PRINT(( "SRVSVC_main: RPC server started.\n" ));
  268. }
  269. rpcServerStarted = TRUE;
  270. //
  271. // Start getting PNP transport notifications from the server
  272. //
  273. error = StartPnpNotifications();
  274. if( error != NO_ERROR ) {
  275. goto exit;
  276. }
  277. //
  278. // Announce that we have successfully started.
  279. //
  280. SsServiceStatus.dwCurrentState = SERVICE_RUNNING;
  281. SsServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  282. SERVICE_ACCEPT_PAUSE_CONTINUE |
  283. SERVICE_ACCEPT_SHUTDOWN;
  284. SsServiceStatus.dwCheckPoint = 0;
  285. SsServiceStatus.dwWaitHint = 0;
  286. AnnounceServiceStatus( 0 );
  287. IF_DEBUG(INITIALIZATION) {
  288. SS_PRINT(( "SRVSVC_main: initialization successfully completed.\n" ));
  289. }
  290. if (!I_ScSetServiceBits(SsServiceStatusHandle, SV_TYPE_SERVER, TRUE, TRUE, FALSE)) {
  291. error = GetLastError();
  292. IF_DEBUG(INITIALIZATION_ERRORS) {
  293. SS_PRINT(( "SRVSVC_main: I_ScSetServiceBits failed: %ld\n",
  294. error ));
  295. }
  296. goto exit;
  297. }
  298. //
  299. // Use this thread as the scavenger thread to send server
  300. // announcements and watch the registry for configuration changes.
  301. //
  302. SS_ASSERT( SsData.SsInitialized );
  303. (VOID)SsScavengerThread( NULL );
  304. SS_ASSERT( SsData.SsInitialized );
  305. exit:
  306. IF_DEBUG(TERMINATION) {
  307. SS_PRINT(( "SRVSVC_main: terminating.\n" ));
  308. }
  309. IF_DEBUG(TERMINATION_BREAKPOINT) {
  310. DbgUserBreakPoint( );
  311. }
  312. //
  313. // Set the initialization variable to indicate that the server
  314. // service is not started.
  315. //
  316. SsData.SsInitialized = FALSE;
  317. //
  318. // Shut down our connection to the RPC server, if the RPC server
  319. // was started successfully.
  320. //
  321. if ( rpcServerStarted ) {
  322. rpcStatus = SsData.SsLmsvcsGlobalData->StopRpcServer (
  323. srvsvc_ServerIfHandle
  324. );
  325. if ( rpcStatus != NO_ERROR ) {
  326. IF_DEBUG(TERMINATION_ERRORS) {
  327. SS_PRINT(( "SRVSVC_main: unable to terminate RPC server: %X\n",
  328. rpcStatus ));
  329. }
  330. } else {
  331. IF_DEBUG(TERMINATION) {
  332. SS_PRINT(( "SRVSVC_main: RPC server successfully shut down.\n" ));
  333. }
  334. }
  335. }
  336. //
  337. // Announce that we're going down.
  338. //
  339. terminationError = error;
  340. SsServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  341. SsServiceStatus.dwCheckPoint = 1;
  342. SsServiceStatus.dwWaitHint = 20000; // 20 seconds
  343. SET_SERVICE_EXITCODE(
  344. terminationError,
  345. SsServiceStatus.dwWin32ExitCode,
  346. SsServiceStatus.dwServiceSpecificExitCode
  347. );
  348. AnnounceServiceStatus( 0 );
  349. //
  350. // Clean up previously initialized state.
  351. //
  352. IF_DEBUG(TERMINATION) {
  353. SS_PRINT(( "SRVSVC_main: cleaning up.\n" ));
  354. }
  355. error = SsTerminate( );
  356. if ( terminationError == NO_ERROR ) {
  357. terminationError = error;
  358. }
  359. //
  360. // Announce that we're down.
  361. //
  362. SsServiceStatus.dwCurrentState = SERVICE_STOPPED;
  363. SsServiceStatus.dwControlsAccepted = 0;
  364. SsServiceStatus.dwCheckPoint = 0;
  365. SsServiceStatus.dwWaitHint = 0;
  366. SET_SERVICE_EXITCODE(
  367. terminationError,
  368. SsServiceStatus.dwWin32ExitCode,
  369. SsServiceStatus.dwServiceSpecificExitCode
  370. );
  371. AnnounceServiceStatus( 0 );
  372. IF_DEBUG(TERMINATION) {
  373. SS_PRINT(( "SRVSVC_main: the server service is terminated.\n" ));
  374. }
  375. return;
  376. } // SVCS_ENTRY_POINT (SRVSVC_main)
  377. VOID
  378. AnnounceServiceStatus (
  379. DWORD increment
  380. )
  381. /*++
  382. Routine Description:
  383. Announces the service's status to the service controller.
  384. Add 'increment' to the checkpoint value.
  385. Arguments:
  386. None.
  387. Return Value:
  388. None.
  389. --*/
  390. {
  391. //
  392. // Service status handle is NULL if RegisterServiceCtrlHandler failed.
  393. //
  394. if ( SsServiceStatusHandle == 0 ) {
  395. SS_PRINT(( "AnnounceServiceStatus: Cannot call SetServiceStatus, "
  396. "no status handle.\n" ));
  397. return;
  398. }
  399. if( SsServiceStatus.dwCurrentState == SERVICE_RUNNING && increment ) {
  400. //
  401. // No need to tell the service controller about another checkpoint
  402. // since it already knows we're running
  403. //
  404. return;
  405. }
  406. SsServiceStatus.dwCheckPoint += increment;
  407. IF_DEBUG(ANNOUNCE) {
  408. SS_PRINT(( "AnnounceServiceStatus: CurrentState %lx\n"
  409. " ControlsAccepted %lx\n"
  410. " Win32ExitCode %lu\n"
  411. " ServiceSpecificExitCode %lu\n"
  412. " CheckPoint %lu\n"
  413. " WaitHint %lu\n",
  414. SsServiceStatus.dwCurrentState,
  415. SsServiceStatus.dwControlsAccepted,
  416. SsServiceStatus.dwWin32ExitCode,
  417. SsServiceStatus.dwServiceSpecificExitCode,
  418. SsServiceStatus.dwCheckPoint,
  419. SsServiceStatus.dwWaitHint ));
  420. }
  421. //
  422. // Call SetServiceStatus, ignoring any errors.
  423. //
  424. SetServiceStatus(SsServiceStatusHandle, &SsServiceStatus);
  425. } // AnnounceServiceStatus
  426. DWORD
  427. WINAPI
  428. ControlResponse(
  429. DWORD opCode,
  430. DWORD fdwEventType,
  431. LPVOID lpEventData,
  432. LPVOID lpContext
  433. )
  434. {
  435. NET_API_STATUS error;
  436. USHORT i;
  437. BOOL announce = TRUE;
  438. //
  439. // Determine the type of service control message and modify the
  440. // service status, if necessary.
  441. //
  442. switch( opCode ) {
  443. case SERVICE_CONTROL_SHUTDOWN:
  444. case SERVICE_CONTROL_STOP:
  445. IF_DEBUG(CONTROL_MESSAGES) {
  446. SS_PRINT(( "ControlResponse: STOP control received.\n" ));
  447. }
  448. //
  449. // Announce that we are in the process of stopping.
  450. //
  451. SsServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  452. AnnounceServiceStatus( 0 );
  453. //
  454. // Set the event that will wake up the scavenger thread.
  455. // That thread will wake up and kill the server.
  456. //
  457. if ( !SetEvent( SsData.SsTerminationEvent ) ) {
  458. IF_DEBUG(TERMINATION_ERRORS) {
  459. SS_PRINT(( "ControlResponse: SetEvent failed: %ld\n",
  460. GetLastError( ) ));
  461. }
  462. }
  463. //
  464. // Let the main thread announce when the stop is done.
  465. //
  466. announce = FALSE;
  467. break;
  468. case SERVICE_CONTROL_PAUSE:
  469. IF_DEBUG(CONTROL_MESSAGES) {
  470. SS_PRINT(( "ControlResponse: PAUSE control received.\n" ));
  471. }
  472. //
  473. // Announce that we are in the process of pausing.
  474. //
  475. SsServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
  476. AnnounceServiceStatus( 0 );
  477. //
  478. // Send the request on to the server.
  479. //
  480. error = SsServerFsControl( FSCTL_SRV_PAUSE, NULL, NULL, 0L );
  481. SS_ASSERT( error == NO_ERROR );
  482. //
  483. // Announce that we're now paused.
  484. //
  485. SsServiceStatus.dwCurrentState = SERVICE_PAUSED;
  486. break;
  487. case SERVICE_CONTROL_CONTINUE:
  488. IF_DEBUG(CONTROL_MESSAGES) {
  489. SS_PRINT(( "ControlResponse: CONTINUE control received.\n" ));
  490. }
  491. //
  492. // Announce that continue is pending.
  493. //
  494. SsServiceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
  495. AnnounceServiceStatus( 0 );
  496. //
  497. // Send the request on to the server.
  498. //
  499. error = SsServerFsControl( FSCTL_SRV_CONTINUE, NULL, NULL, 0L );
  500. SS_ASSERT( error == NO_ERROR );
  501. //
  502. // Announce that we're active now.
  503. //
  504. SsServiceStatus.dwCurrentState = SERVICE_RUNNING;
  505. break;
  506. case SERVICE_CONTROL_INTERROGATE:
  507. IF_DEBUG(CONTROL_MESSAGES) {
  508. SS_PRINT(( "ControlResponse: INTERROGATE control received.\n" ));
  509. }
  510. break;
  511. default:
  512. IF_DEBUG(CONTROL_MESSAGES) {
  513. SS_PRINT(( "ControlResponse: unknown code received.\n" ));
  514. }
  515. return ERROR_CALL_NOT_IMPLEMENTED;
  516. break;
  517. }
  518. if ( announce ) {
  519. AnnounceServiceStatus( 0 );
  520. }
  521. return NO_ERROR;
  522. } // ControlResponse