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.

800 lines
19 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. svcmain.c
  5. Abstract:
  6. This module contains code for starting off, shutting down and
  7. handling device addition/removal request for the EAPOL module.
  8. Revision History:
  9. sachins, Apr 25 2000, Created
  10. Notes:
  11. EAPOL_SERVICE if defined, on compilation, a .exe version is created.
  12. If not defined, on compilation, a .lib is created, with entry
  13. points defined, which netman calls into.
  14. --*/
  15. #include "pcheapol.h"
  16. #pragma hdrstop
  17. #define NDISUIO_SERVICE_NAME L"NDISUIO"
  18. #define NETMAN_SERVICE_NAME L"NETMAN"
  19. extern
  20. VOID
  21. EAPOLServiceMain (
  22. IN DWORD argc,
  23. IN LPWSTR *lpwsServiceArgs
  24. );
  25. VOID
  26. EAPOLServiceMainWorker (
  27. IN PVOID pvContext
  28. );
  29. #ifdef EAPOL_SERVICE
  30. //
  31. // main
  32. //
  33. // Description: Will simply register the entry point of the EAPOL
  34. // service with the service controller. The service controller
  35. // will capture this thread. It will be freed only when
  36. // the service is shutdown. At that point we will simply exit
  37. // the process.
  38. //
  39. // Return values: none
  40. //
  41. void
  42. _cdecl
  43. main ( int argc, unsigned char * argv[] )
  44. {
  45. SERVICE_TABLE_ENTRY EapolServiceDispatchTable[2];
  46. UNREFERENCED_PARAMETER( argc );
  47. UNREFERENCED_PARAMETER( argv );
  48. EapolServiceDispatchTable[0].lpServiceName = EAPOL_SERVICE_NAME;
  49. EapolServiceDispatchTable[0].lpServiceProc = EAPOLServiceMain;
  50. EapolServiceDispatchTable[1].lpServiceName = NULL;
  51. EapolServiceDispatchTable[1].lpServiceProc = NULL;
  52. if ( !StartServiceCtrlDispatcher( EapolServiceDispatchTable ) )
  53. {
  54. ASSERT (0);
  55. }
  56. ExitProcess(0);
  57. }
  58. //
  59. // EAPOLAnnounceServiceStatus
  60. //
  61. // Description: Will simly call SetServiceStatus to inform the service
  62. // control manager of this service's current status.
  63. //
  64. // Return values: none
  65. //
  66. VOID
  67. EAPOLAnnounceServiceStatus (
  68. VOID
  69. )
  70. {
  71. BOOL dwRetCode;
  72. ASSERT (g_hServiceStatus);
  73. //
  74. // Increment the checkpoint in a pending state:
  75. //
  76. switch( g_ServiceStatus.dwCurrentState )
  77. {
  78. case SERVICE_START_PENDING:
  79. case SERVICE_STOP_PENDING:
  80. g_ServiceStatus.dwCheckPoint++;
  81. break;
  82. default:
  83. break;
  84. }
  85. dwRetCode = SetServiceStatus( g_hServiceStatus,
  86. &g_ServiceStatus );
  87. if ( dwRetCode == FALSE )
  88. {
  89. TRACE1 (INIT, "Error: SetServiceStatus returned %d\n",
  90. GetLastError() );
  91. }
  92. }
  93. #endif
  94. //
  95. // EAPOLCleanUp
  96. //
  97. // Description: Will free any allocated memory, deinitialize RPC, deinitialize
  98. // the kernel-mode server and unload it if it was loaded.
  99. // This could have been called due to an error on SERVICE_START
  100. // or normal termination.
  101. //
  102. // Return values: none
  103. //
  104. VOID
  105. EAPOLCleanUp (
  106. IN DWORD dwError
  107. )
  108. {
  109. DWORD dwIndex;
  110. DWORD dwEventStatus = 0;
  111. SERVICE_STATUS ServiceStatus;
  112. DWORD dwRetCode = NO_ERROR;
  113. if (g_hEventTerminateEAPOL == NULL)
  114. {
  115. return;
  116. }
  117. //
  118. // Check if have already gone through EAPOLCleanUp before
  119. // Return if so
  120. //
  121. if (( dwEventStatus = WaitForSingleObject (
  122. g_hEventTerminateEAPOL,
  123. 0)) == WAIT_FAILED)
  124. {
  125. dwRetCode = GetLastError ();
  126. if ( g_dwTraceId != INVALID_TRACEID )
  127. {
  128. TRACE1 (INIT, "EAPOLCleanUp: WaitForSingleObject failed with error %ld, Terminating cleanup",
  129. dwRetCode);
  130. }
  131. // log
  132. return;
  133. }
  134. if (dwEventStatus == WAIT_OBJECT_0)
  135. {
  136. if ( g_dwTraceId != INVALID_TRACEID )
  137. {
  138. TRACE0 (INIT, "EAPOLCleanUp: g_hEventTerminateEAPOL already signaled, returning");
  139. }
  140. return;
  141. }
  142. #ifdef EAPOL_SERVICE
  143. //
  144. // Announce that we are stopping
  145. //
  146. g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  147. g_ServiceStatus.dwControlsAccepted = 0;
  148. g_ServiceStatus.dwCheckPoint = 1;
  149. g_ServiceStatus.dwWaitHint = 200000;
  150. EAPOLAnnounceServiceStatus();
  151. #endif
  152. //
  153. // Tear down and free everything
  154. //
  155. //
  156. // Set event to indicate to waiting threads to terminate
  157. //
  158. if ( !SetEvent (g_hEventTerminateEAPOL) )
  159. {
  160. dwRetCode = GetLastError();
  161. if ( g_dwTraceId != INVALID_TRACEID )
  162. {
  163. TRACE1 (INIT, "EAPOLCleanUp: SetEvent for g_hEventTerminateEAPOL failed with error %ld",
  164. dwRetCode);
  165. }
  166. // log
  167. }
  168. //
  169. // Shutdown device related stuff
  170. // Close handles to NDISUIO
  171. // Shutdown EAPOL State machine
  172. //
  173. if ( ( dwRetCode = ElMediaDeInit()) != NO_ERROR )
  174. {
  175. if ( g_dwTraceId != INVALID_TRACEID )
  176. {
  177. TRACE1 (INIT, "Media DeInit failed with dwRetCode = %ld\n",
  178. dwRetCode );
  179. }
  180. dwRetCode = NO_ERROR;
  181. }
  182. else
  183. {
  184. if ( g_dwTraceId != INVALID_TRACEID )
  185. {
  186. TRACE1 (INIT, "Media DeInit succeeded with dwRetCode = %ld\n",
  187. dwRetCode );
  188. }
  189. }
  190. #ifdef EAPOL_SERVICE
  191. if ( dwError == NO_ERROR )
  192. {
  193. g_ServiceStatus.dwWin32ExitCode = NO_ERROR;
  194. }
  195. else
  196. {
  197. g_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  198. }
  199. g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  200. g_ServiceStatus.dwControlsAccepted = 0;
  201. g_ServiceStatus.dwCheckPoint = 0;
  202. g_ServiceStatus.dwWaitHint = 0;
  203. g_ServiceStatus.dwServiceSpecificExitCode = dwError;
  204. EAPOLAnnounceServiceStatus();
  205. #endif
  206. if (!CloseHandle(g_hStopService))
  207. {
  208. if ( g_dwTraceId != INVALID_TRACEID )
  209. {
  210. TRACE1 (INIT, "EAPOLCleanup: CloseHandle failed with error %ld",
  211. GetLastError());
  212. }
  213. }
  214. //
  215. // Shut down NDISUIO service
  216. //
  217. if ( g_hNDISUIOService != NULL )
  218. {
  219. if (!ControlService ( g_hNDISUIOService, SERVICE_CONTROL_STOP, &ServiceStatus ))
  220. {
  221. if ( g_dwTraceId != INVALID_TRACEID )
  222. {
  223. TRACE1 (INIT, "EAPOLCleanup: ControlService failed with error %ld",
  224. GetLastError());
  225. }
  226. }
  227. if (!CloseServiceHandle ( g_hNDISUIOService ))
  228. {
  229. if ( g_dwTraceId != INVALID_TRACEID )
  230. {
  231. TRACE1 (INIT, "EAPOLCleanup: CloseServiceHandle failed with error %ld",
  232. GetLastError());
  233. }
  234. }
  235. g_hNDISUIOService = NULL;
  236. }
  237. if ( g_hServiceCM != NULL )
  238. {
  239. if (!CloseServiceHandle ( g_hServiceCM ))
  240. {
  241. if ( g_dwTraceId != INVALID_TRACEID )
  242. {
  243. TRACE1 (INIT, "EAPOLCleanup: CloseServiceHandle for SCM failed with error %ld",
  244. GetLastError());
  245. }
  246. }
  247. g_hServiceCM = NULL;
  248. }
  249. if ( g_dwTraceId != INVALID_TRACEID )
  250. {
  251. TRACE1 (INIT, "EAPOLCleanup completed with error %d\n", dwError );
  252. TraceDeregisterA( g_dwTraceId );
  253. g_dwTraceId = INVALID_TRACEID;
  254. }
  255. EapolLogInformation (EAPOL_LOG_SERVICE_RUNNING, 0, NULL);
  256. if ( g_hLogEvents != NULL)
  257. {
  258. EapolLogInformation (EAPOL_LOG_SERVICE_STOPPED, 0, NULL);
  259. RouterLogDeregisterW( g_hLogEvents );
  260. g_hLogEvents = NULL;
  261. }
  262. return;
  263. }
  264. #ifdef EAPOL_SERVICE
  265. //
  266. // ServiceHandlerEx
  267. //
  268. // Description: Will respond to control requests from the service controller.
  269. //
  270. // Return values: none
  271. //
  272. //
  273. DWORD
  274. ServiceHandlerEx (
  275. IN DWORD dwControlCode,
  276. IN DWORD dwEventType,
  277. IN LPVOID lpEventData,
  278. IN LPVOID lpContext
  279. )
  280. {
  281. DWORD dwRetCode = NO_ERROR;
  282. switch( dwControlCode )
  283. {
  284. case SERVICE_CONTROL_STOP:
  285. case SERVICE_CONTROL_SHUTDOWN:
  286. if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
  287. ||
  288. ( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
  289. {
  290. break;
  291. }
  292. TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_ STOP or SHUTDOWN event called");
  293. //
  294. // Announce that we are stopping
  295. //
  296. g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  297. g_ServiceStatus.dwControlsAccepted = 0;
  298. g_ServiceStatus.dwCheckPoint = 1;
  299. g_ServiceStatus.dwWaitHint = 200000;
  300. EAPOLAnnounceServiceStatus();
  301. SetEvent( g_hStopService );
  302. return( NO_ERROR );
  303. break;
  304. case SERVICE_CONTROL_DEVICEEVENT:
  305. if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
  306. ||
  307. ( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
  308. {
  309. break;
  310. }
  311. TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_DEVICEEVENT event called");
  312. // Received notification that some LAN interface was added or deleted
  313. if (lpEventData != NULL)
  314. {
  315. // Call device notification handler
  316. if ((dwRetCode = ElDeviceNotificationHandler (
  317. lpEventData, dwEventType)) != NO_ERROR)
  318. {
  319. TRACE1 (INIT, "ServiceHandlerEx: ElDeviceNotificationHandler faield with error %ld",
  320. dwRetCode);
  321. break;
  322. }
  323. }
  324. default:
  325. return( ERROR_CALL_NOT_IMPLEMENTED );
  326. break;
  327. }
  328. return( dwRetCode );
  329. }
  330. #endif
  331. //
  332. // EAPOLServiceMain
  333. //
  334. // Description: This is the main procedure for the EAPOL Server Service. It
  335. // will be called when the service is supposed to start itself.
  336. // It will do all service wide initialization.
  337. //
  338. // Return values: none
  339. //
  340. VOID
  341. WINAPI
  342. EAPOLServiceMain (
  343. IN DWORD argc, // Command line arguments. Will be ignored.
  344. IN LPWSTR * lpwsServiceArgs
  345. )
  346. {
  347. DWORD dwRetCode = NO_ERROR;
  348. UNREFERENCED_PARAMETER( argc );
  349. UNREFERENCED_PARAMETER( lpwsServiceArgs );
  350. g_hEventTerminateEAPOL = NULL;
  351. // Queue a worker item to do the heavy-duty work during initialization
  352. // This will not hold up the main worker thread
  353. if (!QueueUserWorkItem(
  354. (LPTHREAD_START_ROUTINE)EAPOLServiceMainWorker,
  355. NULL,
  356. WT_EXECUTELONGFUNCTION))
  357. {
  358. dwRetCode = GetLastError();
  359. ASSERT (0);
  360. }
  361. }
  362. VOID
  363. EAPOLServiceMainWorker (
  364. IN PVOID pvContext
  365. )
  366. {
  367. DWORD dwIndex = 0;
  368. SC_HANDLE hServiceCM;
  369. SC_HANDLE hNDISUIOService;
  370. SC_HANDLE hNetManService;
  371. LPQUERY_SERVICE_CONFIG pNetmanServiceConfig = NULL;
  372. DWORD dwBufSize = 0, dwBytesNeeded = 0;
  373. DWORD dwRetCode = NO_ERROR;
  374. //
  375. // Initialize globals
  376. //
  377. g_hLogEvents = NULL;
  378. g_dwTraceId = INVALID_TRACEID;
  379. g_hServiceCM = NULL;
  380. g_hNDISUIOService = NULL;
  381. g_hStopService = NULL;
  382. g_dwModulesStarted = 0;
  383. g_dwMachineAuthEnabled = 0;
  384. g_hNLA_LPC_Port = NULL;
  385. //
  386. // Create event that will be used to indicate EAPOL shutdown
  387. //
  388. g_hEventTerminateEAPOL = CreateEvent( NULL, TRUE, FALSE, NULL );
  389. if ( g_hEventTerminateEAPOL == (HANDLE)NULL )
  390. {
  391. dwRetCode = GetLastError ();
  392. ASSERT (0);
  393. EAPOLCleanUp ( dwRetCode );
  394. return;
  395. }
  396. //
  397. // Register for debug tracing via rtutils.dll
  398. //
  399. g_dwTraceId = TraceRegister (L"EAPOL");
  400. if ( g_dwTraceId == INVALID_TRACEID )
  401. {
  402. dwRetCode = GetLastError ();
  403. ASSERT (0);
  404. EAPOLCleanUp ( dwRetCode );
  405. return;
  406. }
  407. //
  408. // Register for event logging via rtutils.dll
  409. //
  410. g_hLogEvents = RouterLogRegisterW(L"EAPOL");
  411. if ( g_hLogEvents == NULL )
  412. {
  413. dwRetCode = GetLastError ();
  414. TRACE1 (INIT, "EAPOLServiceMainWorker: RouterLogRegisterW failed with error %ld",
  415. dwRetCode);
  416. EAPOLCleanUp ( dwRetCode );
  417. return;
  418. }
  419. #ifdef EAPOL_SERVICE
  420. g_hServiceStatus = RegisterServiceCtrlHandlerEx(
  421. TEXT("EAPOL"),
  422. ServiceHandlerEx,
  423. NULL );
  424. if ( !g_hServiceStatus )
  425. {
  426. return;
  427. }
  428. g_ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  429. g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  430. EAPOLAnnounceServiceStatus();
  431. #endif
  432. //
  433. // Start NDISUIO driver
  434. //
  435. if ((g_hServiceCM = OpenSCManager ( NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE ))
  436. == NULL)
  437. {
  438. dwRetCode = GetLastError ();
  439. TRACE1 (INIT, "EAPOLServiceMainWorker: OpenSCManager failed with error %ld",
  440. dwRetCode);
  441. EAPOLCleanUp ( dwRetCode );
  442. return;
  443. }
  444. if ((g_hNDISUIOService =
  445. OpenService ( g_hServiceCM,
  446. NDISUIO_SERVICE_NAME,
  447. SERVICE_START | SERVICE_STOP ))
  448. == NULL)
  449. {
  450. dwRetCode = GetLastError ();
  451. TRACE1 (INIT, "EAPOLServiceMainWorker: OpenService NdisUIO failed with error %ld",
  452. dwRetCode);
  453. EAPOLCleanUp ( dwRetCode );
  454. return;
  455. }
  456. if (!StartService( g_hNDISUIOService, 0, NULL ))
  457. {
  458. dwRetCode = GetLastError ();
  459. TRACE1 (INIT, "EAPOLServiceMainWorker: StartService failed with error %ld",
  460. dwRetCode);
  461. if (dwRetCode != ERROR_SERVICE_ALREADY_RUNNING)
  462. {
  463. EAPOLCleanUp ( dwRetCode );
  464. return;
  465. }
  466. }
  467. //
  468. // Register for event logging via rtutils.dll
  469. //
  470. g_hLogEvents = RouterLogRegisterW(L"EAPOL");
  471. if ( g_hLogEvents == NULL )
  472. {
  473. dwRetCode = GetLastError ();
  474. TRACE1 (INIT, "EAPOLServiceMainWorker: RouterLogRegisterW failed with error %ld",
  475. dwRetCode);
  476. EAPOLCleanUp ( dwRetCode );
  477. return;
  478. }
  479. #ifdef EAPOL_SERVICE
  480. //
  481. // Announce that we have successfully started.
  482. //
  483. g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  484. g_ServiceStatus.dwCheckPoint = 0;
  485. g_ServiceStatus.dwWaitHint = 0;
  486. g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  487. EAPOLAnnounceServiceStatus();
  488. //
  489. // Create event that will be used to shutdown the EAPOL service
  490. //
  491. g_hStopService = CreateEvent ( NULL, TRUE, FALSE, NULL );
  492. if ( g_hStopService == (HANDLE)NULL )
  493. {
  494. dwRetCode = GetLastError ();
  495. TRACE1 (INIT, "EAPOLServiceMainWorker: CreateEvent failed with error %ld",
  496. dwRetCode);
  497. EAPOLCleanUp ( dwRetCode );
  498. return;
  499. }
  500. #endif
  501. //
  502. // Set User logged indication
  503. //
  504. g_fUserLoggedOn = 0;
  505. //
  506. // Used for detetcing MACHINE_AUTH
  507. // Verify if netman is SERVICE_AUTO_START and set flag if machine auth
  508. // is enabled to indicate machine authentication
  509. //
  510. if ((hNetManService =
  511. OpenService ( g_hServiceCM,
  512. NETMAN_SERVICE_NAME,
  513. SERVICE_QUERY_CONFIG ))
  514. == NULL)
  515. {
  516. dwRetCode = GetLastError ();
  517. TRACE1 (INIT, "EAPOLServiceMainWorker: OpenService Netman failed with error %ld",
  518. dwRetCode);
  519. EAPOLCleanUp ( dwRetCode );
  520. return;
  521. }
  522. dwBufSize = 0;
  523. if (!QueryServiceConfig (
  524. hNetManService,
  525. NULL,
  526. dwBufSize,
  527. &dwBytesNeeded
  528. ))
  529. {
  530. if ((dwRetCode = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
  531. {
  532. pNetmanServiceConfig = (LPQUERY_SERVICE_CONFIG) MALLOC (dwBytesNeeded);
  533. if (pNetmanServiceConfig == NULL)
  534. {
  535. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  536. TRACE0 (INIT, "EAPOLServiceMainWorker: MALLOC failed for pNetmanServiceConfig");
  537. if (!CloseServiceHandle (hNetManService))
  538. {
  539. dwRetCode = GetLastError ();
  540. TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
  541. dwRetCode);
  542. }
  543. EAPOLCleanUp ( dwRetCode );
  544. return;
  545. }
  546. else
  547. {
  548. dwBufSize = dwBytesNeeded;
  549. if (!QueryServiceConfig (
  550. hNetManService,
  551. pNetmanServiceConfig,
  552. dwBufSize,
  553. &dwBytesNeeded
  554. ))
  555. {
  556. dwRetCode = GetLastError ();
  557. TRACE0 (INIT, "EAPOLServiceMainWorker: QueryServiceConfig failed for pNetmanServiceConfig");
  558. if (!CloseServiceHandle (hNetManService))
  559. {
  560. dwRetCode = GetLastError ();
  561. TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
  562. dwRetCode);
  563. }
  564. EAPOLCleanUp ( dwRetCode );
  565. return;
  566. }
  567. else
  568. {
  569. if (pNetmanServiceConfig->dwStartType == SERVICE_AUTO_START)
  570. {
  571. TRACE0 (INIT, "EAPOLServiceMainWorker: Machine auth enabled");
  572. g_dwMachineAuthEnabled = 1;
  573. }
  574. else
  575. {
  576. TRACE0 (INIT, "EAPOLServiceMainWorker: Machine auth disabled");
  577. }
  578. }
  579. }
  580. }
  581. else
  582. {
  583. TRACE1 (INIT, "EAPOLServiceMainWorker: QueryServiceConfig failed with error %ld",
  584. dwRetCode);
  585. if (!CloseServiceHandle (hNetManService))
  586. {
  587. dwRetCode = GetLastError ();
  588. TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
  589. dwRetCode);
  590. }
  591. EAPOLCleanUp ( dwRetCode );
  592. return;
  593. }
  594. }
  595. if (!CloseServiceHandle (hNetManService))
  596. {
  597. dwRetCode = GetLastError ();
  598. TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
  599. dwRetCode);
  600. EAPOLCleanUp ( dwRetCode );
  601. return;
  602. }
  603. //
  604. // Initialize media related stuff
  605. // Interfaces will be enumerated, handles to NDISUIO driver will be opened,
  606. // EAPOL will be initialized
  607. //
  608. if ( ( dwRetCode = ElMediaInit()) != NO_ERROR )
  609. {
  610. TRACE1 (INIT, "Media Init failed with dwRetCode = %d\n",
  611. dwRetCode );
  612. EAPOLCleanUp ( dwRetCode );
  613. return;
  614. }
  615. else
  616. {
  617. TRACE1 (INIT, "Media Init succeeded with dwRetCode = %d\n",
  618. dwRetCode );
  619. }
  620. TRACE0 (INIT, "EAPOL started successfully\n" );
  621. EapolLogInformation (EAPOL_LOG_SERVICE_STARTED, 0, NULL);
  622. #ifdef EAPOL_SERVICE
  623. //
  624. // Just wait here for EAPOL service to terminate.
  625. //
  626. dwRetCode = WaitForSingleObject( g_hStopService, INFINITE );
  627. if ( dwRetCode == WAIT_FAILED )
  628. {
  629. dwRetCode = GetLastError();
  630. }
  631. else
  632. {
  633. dwRetCode = NO_ERROR;
  634. }
  635. TRACE0 (INIT, "Stopping EAPOL gracefully\n" );
  636. EAPOLCleanUp ( dwRetCode );
  637. #endif
  638. }