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.

635 lines
14 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. extern
  18. VOID
  19. EAPOLServiceMain (
  20. IN DWORD argc,
  21. IN LPWSTR *lpwsServiceArgs
  22. );
  23. DWORD
  24. WINAPI
  25. EAPOLServiceMainWorker (
  26. IN PVOID pvContext
  27. );
  28. #ifdef EAPOL_SERVICE
  29. //
  30. // main
  31. //
  32. // Description: Will simply register the entry point of the EAPOL
  33. // service with the service controller. The service controller
  34. // will capture this thread. It will be freed only when
  35. // the service is shutdown. At that point we will simply exit
  36. // the process.
  37. //
  38. // Return values: none
  39. //
  40. void
  41. _cdecl
  42. main ( int argc, unsigned char * argv[] )
  43. {
  44. SERVICE_TABLE_ENTRY EapolServiceDispatchTable[2];
  45. UNREFERENCED_PARAMETER( argc );
  46. UNREFERENCED_PARAMETER( argv );
  47. EapolServiceDispatchTable[0].lpServiceName = EAPOL_SERVICE_NAME;
  48. EapolServiceDispatchTable[0].lpServiceProc = EAPOLServiceMain;
  49. EapolServiceDispatchTable[1].lpServiceName = NULL;
  50. EapolServiceDispatchTable[1].lpServiceProc = NULL;
  51. if ( !StartServiceCtrlDispatcher( EapolServiceDispatchTable ) )
  52. {
  53. }
  54. ExitProcess(0);
  55. }
  56. //
  57. // EAPOLAnnounceServiceStatus
  58. //
  59. // Description: Will simly call SetServiceStatus to inform the service
  60. // control manager of this service's current status.
  61. //
  62. // Return values: none
  63. //
  64. VOID
  65. EAPOLAnnounceServiceStatus (
  66. VOID
  67. )
  68. {
  69. BOOL dwRetCode;
  70. //
  71. // Increment the checkpoint in a pending state:
  72. //
  73. switch( g_ServiceStatus.dwCurrentState )
  74. {
  75. case SERVICE_START_PENDING:
  76. case SERVICE_STOP_PENDING:
  77. g_ServiceStatus.dwCheckPoint++;
  78. break;
  79. default:
  80. break;
  81. }
  82. dwRetCode = SetServiceStatus( g_hServiceStatus,
  83. &g_ServiceStatus );
  84. if ( dwRetCode == FALSE )
  85. {
  86. TRACE1 (INIT, "Error: SetServiceStatus returned %d\n",
  87. GetLastError() );
  88. }
  89. }
  90. #endif
  91. //
  92. // EAPOLCleanUp
  93. //
  94. // Description: Will free any allocated memory, deinitialize RPC, deinitialize
  95. // the kernel-mode server and unload it if it was loaded.
  96. // This could have been called due to an error on SERVICE_START
  97. // or normal termination.
  98. //
  99. // Return values: none
  100. //
  101. VOID
  102. EAPOLCleanUp (
  103. IN DWORD dwError
  104. )
  105. {
  106. DWORD dwEventStatus = 0;
  107. SERVICE_STATUS ServiceStatus;
  108. DWORD dwRetCode = NO_ERROR;
  109. if (g_hEventTerminateEAPOL == NULL)
  110. {
  111. return;
  112. }
  113. //
  114. // Check if have already gone through EAPOLCleanUp before
  115. // Return if so
  116. //
  117. if (( dwEventStatus = WaitForSingleObject (
  118. g_hEventTerminateEAPOL,
  119. 0)) == WAIT_FAILED)
  120. {
  121. dwRetCode = GetLastError ();
  122. if ( g_dwTraceId != INVALID_TRACEID )
  123. {
  124. TRACE1 (INIT, "EAPOLCleanUp: WaitForSingleObject failed with error %ld, Terminating cleanup",
  125. dwRetCode);
  126. }
  127. // log
  128. return;
  129. }
  130. if (dwEventStatus == WAIT_OBJECT_0)
  131. {
  132. if ( g_dwTraceId != INVALID_TRACEID )
  133. {
  134. TRACE0 (INIT, "EAPOLCleanUp: g_hEventTerminateEAPOL already signaled, returning");
  135. }
  136. return;
  137. }
  138. #ifdef EAPOL_SERVICE
  139. //
  140. // Announce that we are stopping
  141. //
  142. g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  143. g_ServiceStatus.dwControlsAccepted = 0;
  144. g_ServiceStatus.dwCheckPoint = 1;
  145. g_ServiceStatus.dwWaitHint = 200000;
  146. EAPOLAnnounceServiceStatus();
  147. #endif
  148. //
  149. // Tear down and free everything
  150. //
  151. //
  152. // Set event to indicate to waiting threads to terminate
  153. //
  154. if ( !SetEvent (g_hEventTerminateEAPOL) )
  155. {
  156. dwRetCode = GetLastError();
  157. if ( g_dwTraceId != INVALID_TRACEID )
  158. {
  159. TRACE1 (INIT, "EAPOLCleanUp: SetEvent for g_hEventTerminateEAPOL failed with error %ld",
  160. dwRetCode);
  161. }
  162. // log
  163. }
  164. //
  165. // Shutdown device related stuff
  166. // Close handles to NDISUIO
  167. // Shutdown EAPOL State machine
  168. //
  169. if ( ( dwRetCode = ElMediaDeInit()) != NO_ERROR )
  170. {
  171. if ( g_dwTraceId != INVALID_TRACEID )
  172. {
  173. TRACE1 (INIT, "Media DeInit failed with dwRetCode = %ld\n",
  174. dwRetCode );
  175. }
  176. dwRetCode = NO_ERROR;
  177. }
  178. else
  179. {
  180. if ( g_dwTraceId != INVALID_TRACEID )
  181. {
  182. TRACE1 (INIT, "Media DeInit succeeded with dwRetCode = %ld\n",
  183. dwRetCode );
  184. }
  185. }
  186. if (READ_WRITE_LOCK_CREATED(&(g_PolicyLock)))
  187. {
  188. ACQUIRE_WRITE_LOCK (&g_PolicyLock);
  189. if (g_pEAPOLPolicyList != NULL)
  190. {
  191. ElFreePolicyList (g_pEAPOLPolicyList);
  192. g_pEAPOLPolicyList = NULL;
  193. }
  194. RELEASE_WRITE_LOCK (&g_PolicyLock);
  195. }
  196. if (READ_WRITE_LOCK_CREATED(&(g_PolicyLock)))
  197. {
  198. DELETE_READ_WRITE_LOCK(&(g_PolicyLock));
  199. }
  200. #ifdef EAPOL_SERVICE
  201. if ( dwError == NO_ERROR )
  202. {
  203. g_ServiceStatus.dwWin32ExitCode = NO_ERROR;
  204. }
  205. else
  206. {
  207. g_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  208. }
  209. g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  210. g_ServiceStatus.dwControlsAccepted = 0;
  211. g_ServiceStatus.dwCheckPoint = 0;
  212. g_ServiceStatus.dwWaitHint = 0;
  213. g_ServiceStatus.dwServiceSpecificExitCode = dwError;
  214. EAPOLAnnounceServiceStatus();
  215. if (!CloseHandle(g_hStopService))
  216. {
  217. if ( g_dwTraceId != INVALID_TRACEID )
  218. {
  219. TRACE1 (INIT, "EAPOLCleanup: CloseHandle failed with error %ld",
  220. GetLastError());
  221. }
  222. }
  223. #endif
  224. if ( g_dwTraceId != INVALID_TRACEID )
  225. {
  226. TRACE1 (INIT, "EAPOLCleanup completed with error %d\n", dwError );
  227. TraceDeregisterA( g_dwTraceId );
  228. g_dwTraceId = INVALID_TRACEID;
  229. }
  230. EapolLogInformation (EAPOL_LOG_SERVICE_RUNNING, 0, NULL);
  231. if ( g_hLogEvents != NULL)
  232. {
  233. EapolLogInformation (EAPOL_LOG_SERVICE_STOPPED, 0, NULL);
  234. RouterLogDeregisterW( g_hLogEvents );
  235. g_hLogEvents = NULL;
  236. }
  237. if (g_hEventTerminateEAPOL != NULL)
  238. {
  239. CloseHandle (g_hEventTerminateEAPOL);
  240. g_hEventTerminateEAPOL = NULL;
  241. }
  242. return;
  243. }
  244. #ifdef EAPOL_SERVICE
  245. //
  246. // ServiceHandlerEx
  247. //
  248. // Description: Will respond to control requests from the service controller.
  249. //
  250. // Return values: none
  251. //
  252. //
  253. DWORD
  254. ServiceHandlerEx (
  255. IN DWORD dwControlCode,
  256. IN DWORD dwEventType,
  257. IN LPVOID lpEventData,
  258. IN LPVOID lpContext
  259. )
  260. {
  261. DWORD dwRetCode = NO_ERROR;
  262. switch( dwControlCode )
  263. {
  264. case SERVICE_CONTROL_STOP:
  265. case SERVICE_CONTROL_SHUTDOWN:
  266. if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
  267. ||
  268. ( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
  269. {
  270. break;
  271. }
  272. TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_ STOP or SHUTDOWN event called");
  273. //
  274. // Announce that we are stopping
  275. //
  276. g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  277. g_ServiceStatus.dwControlsAccepted = 0;
  278. g_ServiceStatus.dwCheckPoint = 1;
  279. g_ServiceStatus.dwWaitHint = 200000;
  280. EAPOLAnnounceServiceStatus();
  281. SetEvent( g_hStopService );
  282. return( NO_ERROR );
  283. break;
  284. case SERVICE_CONTROL_DEVICEEVENT:
  285. if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
  286. ||
  287. ( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
  288. {
  289. break;
  290. }
  291. TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_DEVICEEVENT event called");
  292. // Received notification that some LAN interface was added or deleted
  293. if (lpEventData != NULL)
  294. {
  295. // Call device notification handler
  296. if ((dwRetCode = ElDeviceNotificationHandler (
  297. lpEventData, dwEventType)) != NO_ERROR)
  298. {
  299. TRACE1 (INIT, "ServiceHandlerEx: ElDeviceNotificationHandler faield with error %ld",
  300. dwRetCode);
  301. break;
  302. }
  303. }
  304. default:
  305. return( ERROR_CALL_NOT_IMPLEMENTED );
  306. break;
  307. }
  308. return( dwRetCode );
  309. }
  310. #endif
  311. //
  312. // EAPOLServiceMain
  313. //
  314. // Description: This is the main procedure for the EAPOL Server Service. It
  315. // will be called when the service is supposed to start itself.
  316. // It will do all service wide initialization.
  317. //
  318. // Return values: none
  319. //
  320. VOID
  321. WINAPI
  322. EAPOLServiceMain (
  323. IN DWORD argc, // Command line arguments. Will be ignored.
  324. IN LPWSTR * lpwsServiceArgs
  325. )
  326. {
  327. DWORD dwRetCode = NO_ERROR;
  328. UNREFERENCED_PARAMETER( argc );
  329. UNREFERENCED_PARAMETER( lpwsServiceArgs );
  330. //
  331. // Initialize globals
  332. //
  333. g_hEventTerminateEAPOL = NULL;
  334. g_lWorkerThreads = 0;
  335. g_lPCBContextsAlive = 0;
  336. g_hLogEvents = NULL;
  337. g_dwTraceId = INVALID_TRACEID;
  338. g_hStopService = NULL;
  339. g_dwModulesStarted = 0;
  340. g_hNLA_LPC_Port = NULL;
  341. g_fUserLoggedOn = FALSE;
  342. g_hTimerQueue = NULL;
  343. g_hDeviceNotification = NULL;
  344. g_fTrayIconReady = FALSE;
  345. g_dwmaxStart = EAPOL_MAX_START;
  346. g_dwstartPeriod = EAPOL_START_PERIOD;
  347. g_dwauthPeriod = EAPOL_AUTH_PERIOD;
  348. g_dwheldPeriod = EAPOL_HELD_PERIOD;
  349. g_dwSupplicantMode = EAPOL_DEFAULT_SUPPLICANT_MODE;
  350. g_dwEAPOLAuthMode = EAPOL_DEFAULT_AUTH_MODE;
  351. g_pEAPOLPolicyList = NULL;
  352. g_dwCurrentSessionId = 0xffffffff;
  353. #ifdef EAPOL_SERVICE
  354. g_hServiceStatus = RegisterServiceCtrlHandlerEx(
  355. TEXT("EAPOL"),
  356. ServiceHandlerEx,
  357. NULL );
  358. if ( !g_hServiceStatus )
  359. {
  360. break;
  361. }
  362. g_ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  363. g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  364. EAPOLAnnounceServiceStatus();
  365. #endif
  366. //
  367. // Create event that will be used to indicate EAPOL shutdown
  368. //
  369. g_hEventTerminateEAPOL = CreateEvent( NULL, TRUE, FALSE, NULL );
  370. if ( g_hEventTerminateEAPOL == (HANDLE)NULL )
  371. {
  372. dwRetCode = GetLastError ();
  373. EAPOLCleanUp ( dwRetCode );
  374. return;
  375. }
  376. //
  377. // Register for debug tracing via rtutils.dll
  378. //
  379. g_dwTraceId = TraceRegister (L"EAPOL");
  380. if ( g_dwTraceId == INVALID_TRACEID )
  381. {
  382. dwRetCode = GetLastError ();
  383. EAPOLCleanUp ( dwRetCode );
  384. return;
  385. }
  386. //
  387. // Register for event logging via rtutils.dll
  388. //
  389. g_hLogEvents = RouterLogRegisterW(L"EAPOL");
  390. if ( g_hLogEvents == NULL )
  391. {
  392. dwRetCode = GetLastError ();
  393. TRACE1 (INIT, "EAPOLServiceMainWorker: RouterLogRegisterW failed with error %ld",
  394. dwRetCode);
  395. EAPOLCleanUp ( dwRetCode );
  396. return;
  397. }
  398. if (dwRetCode = CREATE_READ_WRITE_LOCK(&(g_PolicyLock), "PCY") != NO_ERROR)
  399. {
  400. TRACE1(INIT, "EAPOLServiceMainWorker: Error %d creating g_PolicyLock read-write-lock", dwRetCode);
  401. EAPOLCleanUp ( dwRetCode );
  402. return;
  403. }
  404. // Queue a worker item to do the heavy-duty work during initialization
  405. // This will not hold up the main service thread
  406. InterlockedIncrement (&g_lWorkerThreads);
  407. if (!QueueUserWorkItem(
  408. (LPTHREAD_START_ROUTINE)EAPOLServiceMainWorker,
  409. NULL,
  410. WT_EXECUTELONGFUNCTION))
  411. {
  412. dwRetCode = GetLastError();
  413. InterlockedDecrement (&g_lWorkerThreads);
  414. return;
  415. }
  416. }
  417. DWORD
  418. WINAPI
  419. EAPOLServiceMainWorker (
  420. IN PVOID pvContext
  421. )
  422. {
  423. DWORD dwRetCode = NO_ERROR;
  424. do
  425. {
  426. #ifdef EAPOL_SERVICE
  427. //
  428. // Announce that we have successfully started.
  429. //
  430. g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  431. g_ServiceStatus.dwCheckPoint = 0;
  432. g_ServiceStatus.dwWaitHint = 0;
  433. g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  434. EAPOLAnnounceServiceStatus();
  435. //
  436. // Create event that will be used to shutdown the EAPOL service
  437. //
  438. g_hStopService = CreateEvent ( NULL, TRUE, FALSE, NULL );
  439. if ( g_hStopService == (HANDLE)NULL )
  440. {
  441. dwRetCode = GetLastError ();
  442. TRACE1 (INIT, "EAPOLServiceMainWorker: CreateEvent failed with error %ld",
  443. dwRetCode);
  444. break;
  445. }
  446. #endif
  447. if ((dwRetCode = ElUpdateRegistry ()) != NO_ERROR)
  448. {
  449. TRACE1 (INIT, "ElUpdateRegistry failed with error (%ld)",
  450. dwRetCode);
  451. // Ignore registry update errors
  452. dwRetCode = NO_ERROR;
  453. }
  454. //
  455. // Initialize media related stuff
  456. // Interfaces will be enumerated, handles to NDISUIO driver will be opened,
  457. // EAPOL will be initialized
  458. //
  459. if ( ( dwRetCode = ElMediaInit ()) != NO_ERROR )
  460. {
  461. TRACE1 (INIT, "Media Init failed with dwRetCode = %d\n",
  462. dwRetCode );
  463. break;
  464. }
  465. else
  466. {
  467. TRACE1 (INIT, "Media Init succeeded with dwRetCode = %d\n",
  468. dwRetCode );
  469. }
  470. TRACE0 (INIT, "EAPOL started successfully\n" );
  471. // EapolLogInformation (EAPOL_LOG_SERVICE_STARTED, 0, NULL);
  472. #ifdef EAPOL_SERVICE
  473. //
  474. // Just wait here for EAPOL service to terminate.
  475. //
  476. dwRetCode = WaitForSingleObject( g_hStopService, INFINITE );
  477. if ( dwRetCode == WAIT_FAILED )
  478. {
  479. dwRetCode = GetLastError();
  480. }
  481. else
  482. {
  483. dwRetCode = NO_ERROR;
  484. }
  485. TRACE0 (INIT, "Stopping EAPOL gracefully\n" );
  486. EAPOLCleanUp ( dwRetCode );
  487. #endif
  488. }
  489. while (FALSE);
  490. InterlockedDecrement (&g_lWorkerThreads);
  491. if (dwRetCode != NO_ERROR)
  492. {
  493. EAPOLCleanUp ( dwRetCode );
  494. }
  495. return dwRetCode;
  496. }