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.

733 lines
17 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. almain.c
  5. Abstract:
  6. This is the main routine for the NT LAN Manager Alerter service
  7. Author:
  8. Rita Wong (ritaw) 01-July-1991
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include "almain.h" // Main module definitions
  14. #include <svcs.h> // SVCS_ENTRY_POINT
  15. #include <secobj.h> // ACE_DATA
  16. //-------------------------------------------------------------------//
  17. // //
  18. // Global variables //
  19. // //
  20. //-------------------------------------------------------------------//
  21. AL_GLOBAL_DATA AlGlobalData;
  22. PSVCHOST_GLOBAL_DATA AlLmsvcsGlobalData;
  23. STATIC BOOL AlDone = FALSE;
  24. //
  25. // Debug trace flag for selecting which trace statements to output
  26. //
  27. #if DBG
  28. DWORD AlerterTrace = 0;
  29. #endif
  30. //-------------------------------------------------------------------//
  31. // //
  32. // Function prototypes //
  33. // //
  34. //-------------------------------------------------------------------//
  35. STATIC
  36. NET_API_STATUS
  37. AlInitializeAlerter(
  38. VOID
  39. );
  40. STATIC
  41. VOID
  42. AlProcessAlertNotification(
  43. VOID
  44. );
  45. STATIC
  46. VOID
  47. AlShutdownAlerter(
  48. IN NET_API_STATUS ErrorCode
  49. );
  50. STATIC
  51. NET_API_STATUS
  52. AlUpdateStatus(
  53. VOID
  54. );
  55. VOID
  56. AlerterControlHandler(
  57. IN DWORD Opcode
  58. );
  59. VOID
  60. SvchostPushServiceGlobals(
  61. PSVCHOST_GLOBAL_DATA pGlobals
  62. )
  63. {
  64. AlLmsvcsGlobalData = pGlobals;
  65. }
  66. VOID
  67. ServiceMain(
  68. DWORD NumArgs,
  69. LPTSTR *ArgsArray
  70. )
  71. /*++
  72. Routine Description:
  73. This is the main routine of the Alerter Service which registers
  74. itself as an RPC server and notifies the Service Controller of the
  75. Alerter service control entry point.
  76. Arguments:
  77. NumArgs - Supplies the number of strings specified in ArgsArray.
  78. ArgsArray - Supplies string arguments that are specified in the
  79. StartService API call. This parameter is ignored by the
  80. Alerter service.
  81. Return Value:
  82. None.
  83. --*/
  84. {
  85. DWORD AlInitState = 0;
  86. UNREFERENCED_PARAMETER(NumArgs);
  87. UNREFERENCED_PARAMETER(ArgsArray);
  88. //
  89. // Make sure svchost.exe gave us the global data.
  90. //
  91. ASSERT(AlLmsvcsGlobalData != NULL);
  92. IF_DEBUG(MAIN) {
  93. NetpKdPrint(("In the alerter service!!\n"));
  94. }
  95. AlDone = FALSE;
  96. if (AlInitializeAlerter() != NERR_Success) {
  97. return;
  98. }
  99. AlProcessAlertNotification();
  100. return;
  101. }
  102. STATIC
  103. NET_API_STATUS
  104. AlInitializeAlerter(
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. This routine initializes the Alerter service.
  110. Arguments:
  111. AlInitState - Returns a flag to indicate how far we got with initializing
  112. the Alerter service before an error occured.
  113. Return Value:
  114. NET_API_STATUS - NERR_Success or reason for failure.
  115. --*/
  116. {
  117. NET_API_STATUS status;
  118. NTSTATUS ntstatus;
  119. PSECURITY_DESCRIPTOR Sd;
  120. SECURITY_ATTRIBUTES Sa;
  121. ACE_DATA AceData[1] = {
  122. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  123. GENERIC_READ | GENERIC_WRITE, &AlLmsvcsGlobalData->WorldSid}
  124. };
  125. AlGlobalData.MailslotHandle = INVALID_HANDLE_VALUE;
  126. //
  127. // Initialize Alerter to receive service requests by registering the
  128. // control handler.
  129. //
  130. if ((AlGlobalData.StatusHandle = RegisterServiceCtrlHandler(
  131. SERVICE_ALERTER,
  132. AlerterControlHandler
  133. )) == 0) {
  134. status = GetLastError();
  135. AlHandleError(AlErrorRegisterControlHandler, status, NULL);
  136. return status;
  137. }
  138. //
  139. // Initialize all the status fields so that subsequent calls to
  140. // SetServiceStatus need to only update fields that changed.
  141. //
  142. AlGlobalData.Status.dwServiceType = SERVICE_WIN32;
  143. AlGlobalData.Status.dwCurrentState = SERVICE_START_PENDING;
  144. AlGlobalData.Status.dwControlsAccepted = 0;
  145. AlGlobalData.Status.dwCheckPoint = 1;
  146. AlGlobalData.Status.dwWaitHint = 10000; // 10 secs
  147. SET_SERVICE_EXITCODE(
  148. NO_ERROR,
  149. AlGlobalData.Status.dwWin32ExitCode,
  150. AlGlobalData.Status.dwServiceSpecificExitCode
  151. );
  152. //
  153. // Tell the Service Controller that we are start-pending
  154. //
  155. if ((status = AlUpdateStatus()) != NERR_Success) {
  156. AlHandleError(AlErrorNotifyServiceController, status, NULL);
  157. return status;
  158. }
  159. //
  160. // Get the configured alert names
  161. //
  162. if ((status = AlGetAlerterConfiguration()) != NERR_Success) {
  163. AlHandleError(AlErrorGetComputerName, status, NULL);
  164. return status;
  165. }
  166. //
  167. // Create the security descriptor for the security attributes structure
  168. //
  169. ntstatus = NetpCreateSecurityDescriptor(
  170. AceData,
  171. 1,
  172. AlLmsvcsGlobalData->LocalServiceSid,
  173. AlLmsvcsGlobalData->LocalServiceSid,
  174. &Sd
  175. );
  176. if (! NT_SUCCESS(ntstatus)) {
  177. status = NetpNtStatusToApiStatus(ntstatus);
  178. AlHandleError(AlErrorCreateMailslot, status, NULL);
  179. return status;
  180. }
  181. Sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  182. Sa.lpSecurityDescriptor = Sd;
  183. Sa.bInheritHandle = FALSE;
  184. //
  185. // Create mailslot to listen on alert notifications from the Server
  186. // service and the Spooler.
  187. //
  188. AlGlobalData.MailslotHandle = CreateMailslot(
  189. ALERTER_MAILSLOT,
  190. MAX_MAILSLOT_MESSAGE_SIZE,
  191. MAILSLOT_WAIT_FOREVER,
  192. &Sa
  193. );
  194. NetpMemoryFree(Sd);
  195. if (AlGlobalData.MailslotHandle == INVALID_HANDLE_VALUE) {
  196. status = GetLastError();
  197. AlHandleError(AlErrorCreateMailslot, status, NULL);
  198. return status;
  199. }
  200. else {
  201. IF_DEBUG(MAIN) {
  202. NetpKdPrint(("Mailslot %ws created, handle=x%08lx\n",
  203. ALERTER_MAILSLOT, AlGlobalData.MailslotHandle));
  204. }
  205. }
  206. //
  207. // Tell the Service Controller that we are started.
  208. //
  209. AlGlobalData.Status.dwCurrentState = SERVICE_RUNNING;
  210. AlGlobalData.Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  211. AlGlobalData.Status.dwCheckPoint = 0;
  212. AlGlobalData.Status.dwWaitHint = 0;
  213. if ((status = AlUpdateStatus()) != NERR_Success) {
  214. AlHandleError(AlErrorNotifyServiceController, status, NULL);
  215. return status;
  216. }
  217. IF_DEBUG(MAIN) {
  218. NetpKdPrint(("[Alerter] Successful Initialization\n"));
  219. }
  220. return NERR_Success;
  221. }
  222. STATIC
  223. VOID
  224. AlProcessAlertNotification(
  225. VOID
  226. )
  227. /*++
  228. Routine Description:
  229. This routine processes incoming mailslot alert notifications, which is
  230. the core function of the Alerter service.
  231. Arguments:
  232. AlUicCode - Supplies the termination code to the Service Controller.
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. NET_API_STATUS status = NERR_Success;
  238. TCHAR AlertMailslotBuffer[MAX_MAILSLOT_MESSAGE_SIZE];
  239. DWORD NumberOfBytesRead;
  240. PSTD_ALERT Alert;
  241. //
  242. // Loop reading the Alerter mailslot; it will terminate when the mailslot
  243. // is destroyed by closing the one and only handle to it.
  244. //
  245. do {
  246. //
  247. // Zero out the buffer before getting a new alert notification
  248. //
  249. RtlZeroMemory(AlertMailslotBuffer, MAX_MAILSLOT_MESSAGE_SIZE *
  250. sizeof(TCHAR));
  251. if (ReadFile(
  252. AlGlobalData.MailslotHandle,
  253. (LPVOID) AlertMailslotBuffer,
  254. MAX_MAILSLOT_MESSAGE_SIZE * sizeof(TCHAR),
  255. &NumberOfBytesRead,
  256. NULL
  257. ) == FALSE) {
  258. //
  259. // Failed in reading mailslot
  260. //
  261. status = GetLastError();
  262. if (status == ERROR_HANDLE_EOF) {
  263. while (! AlDone) {
  264. Sleep(2000);
  265. }
  266. return;
  267. }
  268. NetpKdPrint(("[Alerter] Error reading from mailslot %lu\n", status));
  269. }
  270. else {
  271. //
  272. // Successfully received a mailslot alert notification
  273. //
  274. IF_DEBUG(MAIN) {
  275. NetpKdPrint(("[Alerter] Successfully read %lu bytes from mailslot\n",
  276. NumberOfBytesRead));
  277. }
  278. try {
  279. //
  280. // Handle alert notification for admin, print, and user alerts.
  281. //
  282. Alert = (PSTD_ALERT) AlertMailslotBuffer;
  283. //
  284. // Make sure structure fields are properly terminated
  285. //
  286. Alert->alrt_eventname[EVLEN] = L'\0';
  287. Alert->alrt_servicename[SNLEN] = L'\0';
  288. if (! I_NetNameCompare(
  289. NULL,
  290. Alert->alrt_eventname,
  291. ALERT_ADMIN_EVENT,
  292. NAMETYPE_EVENT,
  293. 0
  294. )) {
  295. AlAdminFormatAndSend(Alert);
  296. }
  297. else if (! I_NetNameCompare(
  298. NULL,
  299. Alert->alrt_eventname,
  300. ALERT_PRINT_EVENT,
  301. NAMETYPE_EVENT,
  302. 0
  303. )) {
  304. AlPrintFormatAndSend(Alert);
  305. }
  306. else if (! I_NetNameCompare(
  307. NULL,
  308. Alert->alrt_eventname,
  309. ALERT_USER_EVENT,
  310. NAMETYPE_EVENT,
  311. 0L
  312. )) {
  313. AlUserFormatAndSend(Alert);
  314. }
  315. }
  316. except (EXCEPTION_EXECUTE_HANDLER) {
  317. NetpKdPrint(("[Alerter] Exception occurred processing alerts\n"));
  318. }
  319. }
  320. } while (TRUE);
  321. }
  322. STATIC
  323. VOID
  324. AlShutdownAlerter(
  325. IN NET_API_STATUS ErrorCode
  326. )
  327. /*++
  328. Routine Description:
  329. This routine shuts down the Alerter service.
  330. Arguments:
  331. ErrorCode - Supplies the error for terminating the Alerter service.
  332. Return Value:
  333. None.
  334. --*/
  335. {
  336. //
  337. // Free memory allocated to hold the computer name
  338. //
  339. if (AlLocalComputerNameA != NULL) {
  340. (void) NetApiBufferFree(AlLocalComputerNameA);
  341. AlLocalComputerNameA = NULL;
  342. }
  343. if (AlLocalComputerNameW != NULL) {
  344. (void) NetApiBufferFree(AlLocalComputerNameW);
  345. AlLocalComputerNameW = NULL;
  346. }
  347. //
  348. // Free memory allocated for alert names
  349. //
  350. if (AlertNamesA != NULL) {
  351. (void) LocalFree(AlertNamesA);
  352. AlertNamesA = NULL;
  353. }
  354. if (AlertNamesW != NULL) {
  355. (void) NetApiBufferFree(AlertNamesW);
  356. AlertNamesW = NULL;
  357. }
  358. //
  359. // Destroy Alerter mailslot if created.
  360. //
  361. if (AlGlobalData.MailslotHandle != INVALID_HANDLE_VALUE) {
  362. if (! CloseHandle(AlGlobalData.MailslotHandle)) {
  363. NetpKdPrint(("[Alerter]] Could not remove mailslot %lu\n",
  364. GetLastError()));
  365. }
  366. AlGlobalData.MailslotHandle = INVALID_HANDLE_VALUE;
  367. }
  368. //
  369. // We are done with cleaning up. Tell Service Controller that we are
  370. // stopped.
  371. //
  372. AlGlobalData.Status.dwCurrentState = SERVICE_STOPPED;
  373. AlGlobalData.Status.dwCheckPoint = 0;
  374. AlGlobalData.Status.dwWaitHint = 0;
  375. SET_SERVICE_EXITCODE(
  376. ErrorCode,
  377. AlGlobalData.Status.dwWin32ExitCode,
  378. AlGlobalData.Status.dwServiceSpecificExitCode
  379. );
  380. (void) AlUpdateStatus();
  381. AlDone = TRUE;
  382. }
  383. VOID
  384. AlHandleError(
  385. IN AL_ERROR_CONDITION FailingCondition,
  386. IN NET_API_STATUS Status,
  387. IN LPTSTR MessageAlias OPTIONAL
  388. )
  389. /*++
  390. Routine Description:
  391. This routine handles a Alerter service error condition. I*f the error
  392. condition is fatal, then it shuts down the Alerter service.
  393. Arguments:
  394. FailingCondition - Supplies a value which indicates what the failure is.
  395. Status - Supplies the status code for the failure.
  396. MessageAlias - Supplies the message alias name which the alert message
  397. failed in sending. This only applies to the message send error.
  398. Return Value:
  399. None.
  400. --*/
  401. {
  402. LPWSTR SubString[3];
  403. TCHAR StatusString[STRINGS_MAXIMUM + 1];
  404. DWORD NumberOfStrings;
  405. switch (FailingCondition) {
  406. case AlErrorRegisterControlHandler:
  407. NetpKdPrint(("[Alerter] Cannot register control handler "
  408. FORMAT_API_STATUS "\n", Status));
  409. SubString[0] = ultow(Status, StatusString, 10);
  410. AlLogEvent(
  411. NELOG_FailedToRegisterSC,
  412. 1,
  413. SubString
  414. );
  415. AlShutdownAlerter(Status);
  416. break;
  417. case AlErrorCreateMailslot:
  418. NetpKdPrint(("[Alerter] Cannot create mailslot " FORMAT_API_STATUS "\n",
  419. Status));
  420. SubString[0] = ultow(Status, StatusString, 10);
  421. AlLogEvent(
  422. NELOG_Mail_Slt_Err,
  423. 1,
  424. SubString
  425. );
  426. AlShutdownAlerter(Status);
  427. break;
  428. case AlErrorNotifyServiceController:
  429. NetpKdPrint(("[Alerter] SetServiceStatus error %lu\n", Status));
  430. SubString[0] = ultow(Status, StatusString, 10);
  431. AlLogEvent(
  432. NELOG_FailedToSetServiceStatus,
  433. 1,
  434. SubString
  435. );
  436. AlShutdownAlerter(Status);
  437. break;
  438. case AlErrorGetComputerName:
  439. NetpKdPrint(("[Alerter] Error in getting computer name %lu.\n", Status));
  440. SubString[0] = ultow(Status, StatusString, 10);
  441. AlLogEvent(
  442. NELOG_FailedToGetComputerName,
  443. 1,
  444. SubString
  445. );
  446. AlShutdownAlerter(Status);
  447. break;
  448. case AlErrorSendMessage :
  449. AlFormatErrorMessage(
  450. Status,
  451. MessageAlias,
  452. StatusString,
  453. (STRINGS_MAXIMUM + 1) * sizeof(TCHAR)
  454. );
  455. SubString[0] = StatusString;
  456. SubString[1] = StatusString + STRLEN(StatusString) + 1;
  457. SubString[2] = SubString[1] + STRLEN(SubString[1]) + 1;
  458. AlLogEvent(
  459. NELOG_Message_Send,
  460. 3,
  461. SubString
  462. );
  463. break;
  464. default:
  465. NetpKdPrint(("[Alerter] AlHandleError: unknown error condition %lu\n",
  466. FailingCondition));
  467. NetpAssert(FALSE);
  468. }
  469. }
  470. STATIC
  471. NET_API_STATUS
  472. AlUpdateStatus(
  473. VOID
  474. )
  475. /*++
  476. Routine Description:
  477. This routine updates the Alerter service status with the Service
  478. Controller.
  479. Arguments:
  480. None.
  481. Return Value:
  482. NET_API_STATUS - NERR_Success or reason for failure.
  483. --*/
  484. {
  485. NET_API_STATUS status = NERR_Success;
  486. if (AlGlobalData.StatusHandle == 0) {
  487. NetpKdPrint((
  488. "[Alerter] Cannot call SetServiceStatus, no status handle.\n"
  489. ));
  490. return ERROR_INVALID_HANDLE;
  491. }
  492. if (! SetServiceStatus(AlGlobalData.StatusHandle, &AlGlobalData.Status)) {
  493. status = GetLastError();
  494. IF_DEBUG(MAIN) {
  495. NetpKdPrint(("[Alerter] SetServiceStatus error %lu\n", status));
  496. }
  497. }
  498. return status;
  499. }
  500. VOID
  501. AlerterControlHandler(
  502. IN DWORD Opcode
  503. )
  504. /*++
  505. Routine Description:
  506. This is the service control handler of the Alerter service.
  507. Arguments:
  508. Opcode - Supplies a value which specifies the action for the Alerter
  509. service to perform.
  510. Return Value:
  511. None.
  512. --*/
  513. {
  514. IF_DEBUG(MAIN) {
  515. NetpKdPrint(("[Alerter] In Control Handler\n"));
  516. }
  517. switch (Opcode) {
  518. case SERVICE_CONTROL_STOP:
  519. if (AlGlobalData.Status.dwCurrentState != SERVICE_STOP_PENDING) {
  520. IF_DEBUG(MAIN) {
  521. NetpKdPrint(("[Alerter] Stopping alerter...\n"));
  522. }
  523. AlShutdownAlerter(NERR_Success);
  524. }
  525. return;
  526. case SERVICE_CONTROL_INTERROGATE:
  527. break;
  528. default:
  529. IF_DEBUG(MAIN) {
  530. NetpKdPrint(("Unknown alerter opcode " FORMAT_HEX_DWORD
  531. "\n", Opcode));
  532. }
  533. }
  534. //
  535. // Send the status response.
  536. //
  537. (void) AlUpdateStatus();
  538. }