734 lines
17 KiB
C
734 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
almain.c
|
||
|
||
Abstract:
|
||
|
||
This is the main routine for the NT LAN Manager Alerter service
|
||
|
||
Author:
|
||
|
||
Rita Wong (ritaw) 01-July-1991
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "almain.h" // Main module definitions
|
||
|
||
#include <svcs.h> // SVCS_ENTRY_POINT
|
||
#include <secobj.h> // ACE_DATA
|
||
|
||
//-------------------------------------------------------------------//
|
||
// //
|
||
// Global variables //
|
||
// //
|
||
//-------------------------------------------------------------------//
|
||
|
||
AL_GLOBAL_DATA AlGlobalData;
|
||
PSVCHOST_GLOBAL_DATA AlLmsvcsGlobalData;
|
||
|
||
STATIC BOOL AlDone = FALSE;
|
||
|
||
//
|
||
// Debug trace flag for selecting which trace statements to output
|
||
//
|
||
#if DBG
|
||
|
||
DWORD AlerterTrace = 0;
|
||
|
||
#endif
|
||
|
||
|
||
//-------------------------------------------------------------------//
|
||
// //
|
||
// Function prototypes //
|
||
// //
|
||
//-------------------------------------------------------------------//
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
AlInitializeAlerter(
|
||
VOID
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
AlProcessAlertNotification(
|
||
VOID
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
AlShutdownAlerter(
|
||
IN NET_API_STATUS ErrorCode
|
||
);
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
AlUpdateStatus(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
AlerterControlHandler(
|
||
IN DWORD Opcode
|
||
);
|
||
|
||
|
||
VOID
|
||
SvchostPushServiceGlobals(
|
||
PSVCHOST_GLOBAL_DATA pGlobals
|
||
)
|
||
{
|
||
AlLmsvcsGlobalData = pGlobals;
|
||
}
|
||
|
||
|
||
VOID
|
||
ServiceMain(
|
||
DWORD NumArgs,
|
||
LPTSTR *ArgsArray
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the main routine of the Alerter Service which registers
|
||
itself as an RPC server and notifies the Service Controller of the
|
||
Alerter service control entry point.
|
||
|
||
Arguments:
|
||
|
||
NumArgs - Supplies the number of strings specified in ArgsArray.
|
||
|
||
ArgsArray - Supplies string arguments that are specified in the
|
||
StartService API call. This parameter is ignored by the
|
||
Alerter service.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD AlInitState = 0;
|
||
|
||
|
||
UNREFERENCED_PARAMETER(NumArgs);
|
||
UNREFERENCED_PARAMETER(ArgsArray);
|
||
|
||
//
|
||
// Make sure svchost.exe gave us the global data.
|
||
//
|
||
ASSERT(AlLmsvcsGlobalData != NULL);
|
||
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("In the alerter service!!\n"));
|
||
}
|
||
|
||
AlDone = FALSE;
|
||
|
||
if (AlInitializeAlerter() != NERR_Success) {
|
||
return;
|
||
}
|
||
|
||
AlProcessAlertNotification();
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
AlInitializeAlerter(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the Alerter service.
|
||
|
||
Arguments:
|
||
|
||
AlInitState - Returns a flag to indicate how far we got with initializing
|
||
the Alerter service before an error occured.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status;
|
||
NTSTATUS ntstatus;
|
||
PSECURITY_DESCRIPTOR Sd;
|
||
SECURITY_ATTRIBUTES Sa;
|
||
ACE_DATA AceData[1] = {
|
||
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
||
GENERIC_READ | GENERIC_WRITE, &AlLmsvcsGlobalData->WorldSid}
|
||
};
|
||
|
||
|
||
|
||
AlGlobalData.MailslotHandle = INVALID_HANDLE_VALUE;
|
||
|
||
//
|
||
// Initialize Alerter to receive service requests by registering the
|
||
// control handler.
|
||
//
|
||
if ((AlGlobalData.StatusHandle = RegisterServiceCtrlHandler(
|
||
SERVICE_ALERTER,
|
||
AlerterControlHandler
|
||
)) == 0) {
|
||
|
||
status = GetLastError();
|
||
AlHandleError(AlErrorRegisterControlHandler, status, NULL);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Initialize all the status fields so that subsequent calls to
|
||
// SetServiceStatus need to only update fields that changed.
|
||
//
|
||
AlGlobalData.Status.dwServiceType = SERVICE_WIN32;
|
||
AlGlobalData.Status.dwCurrentState = SERVICE_START_PENDING;
|
||
AlGlobalData.Status.dwControlsAccepted = 0;
|
||
AlGlobalData.Status.dwCheckPoint = 1;
|
||
AlGlobalData.Status.dwWaitHint = 10000; // 10 secs
|
||
|
||
SET_SERVICE_EXITCODE(
|
||
NO_ERROR,
|
||
AlGlobalData.Status.dwWin32ExitCode,
|
||
AlGlobalData.Status.dwServiceSpecificExitCode
|
||
);
|
||
|
||
//
|
||
// Tell the Service Controller that we are start-pending
|
||
//
|
||
if ((status = AlUpdateStatus()) != NERR_Success) {
|
||
|
||
AlHandleError(AlErrorNotifyServiceController, status, NULL);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Get the configured alert names
|
||
//
|
||
if ((status = AlGetAlerterConfiguration()) != NERR_Success) {
|
||
|
||
AlHandleError(AlErrorGetComputerName, status, NULL);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Create the security descriptor for the security attributes structure
|
||
//
|
||
ntstatus = NetpCreateSecurityDescriptor(
|
||
AceData,
|
||
1,
|
||
AlLmsvcsGlobalData->LocalServiceSid,
|
||
AlLmsvcsGlobalData->LocalServiceSid,
|
||
&Sd
|
||
);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
status = NetpNtStatusToApiStatus(ntstatus);
|
||
AlHandleError(AlErrorCreateMailslot, status, NULL);
|
||
return status;
|
||
}
|
||
|
||
Sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||
Sa.lpSecurityDescriptor = Sd;
|
||
Sa.bInheritHandle = FALSE;
|
||
|
||
//
|
||
// Create mailslot to listen on alert notifications from the Server
|
||
// service and the Spooler.
|
||
//
|
||
AlGlobalData.MailslotHandle = CreateMailslot(
|
||
ALERTER_MAILSLOT,
|
||
MAX_MAILSLOT_MESSAGE_SIZE,
|
||
MAILSLOT_WAIT_FOREVER,
|
||
&Sa
|
||
);
|
||
|
||
NetpMemoryFree(Sd);
|
||
|
||
if (AlGlobalData.MailslotHandle == INVALID_HANDLE_VALUE) {
|
||
status = GetLastError();
|
||
AlHandleError(AlErrorCreateMailslot, status, NULL);
|
||
return status;
|
||
}
|
||
else {
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("Mailslot %ws created, handle=x%08lx\n",
|
||
ALERTER_MAILSLOT, AlGlobalData.MailslotHandle));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Tell the Service Controller that we are started.
|
||
//
|
||
AlGlobalData.Status.dwCurrentState = SERVICE_RUNNING;
|
||
AlGlobalData.Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||
AlGlobalData.Status.dwCheckPoint = 0;
|
||
AlGlobalData.Status.dwWaitHint = 0;
|
||
|
||
if ((status = AlUpdateStatus()) != NERR_Success) {
|
||
|
||
AlHandleError(AlErrorNotifyServiceController, status, NULL);
|
||
return status;
|
||
}
|
||
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("[Alerter] Successful Initialization\n"));
|
||
}
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
STATIC
|
||
VOID
|
||
AlProcessAlertNotification(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes incoming mailslot alert notifications, which is
|
||
the core function of the Alerter service.
|
||
|
||
Arguments:
|
||
|
||
AlUicCode - Supplies the termination code to the Service Controller.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status = NERR_Success;
|
||
TCHAR AlertMailslotBuffer[MAX_MAILSLOT_MESSAGE_SIZE];
|
||
DWORD NumberOfBytesRead;
|
||
|
||
PSTD_ALERT Alert;
|
||
|
||
|
||
//
|
||
// Loop reading the Alerter mailslot; it will terminate when the mailslot
|
||
// is destroyed by closing the one and only handle to it.
|
||
//
|
||
do {
|
||
|
||
//
|
||
// Zero out the buffer before getting a new alert notification
|
||
//
|
||
RtlZeroMemory(AlertMailslotBuffer, MAX_MAILSLOT_MESSAGE_SIZE *
|
||
sizeof(TCHAR));
|
||
|
||
if (ReadFile(
|
||
AlGlobalData.MailslotHandle,
|
||
(LPVOID) AlertMailslotBuffer,
|
||
MAX_MAILSLOT_MESSAGE_SIZE * sizeof(TCHAR),
|
||
&NumberOfBytesRead,
|
||
NULL
|
||
) == FALSE) {
|
||
|
||
//
|
||
// Failed in reading mailslot
|
||
//
|
||
status = GetLastError();
|
||
|
||
if (status == ERROR_HANDLE_EOF) {
|
||
while (! AlDone) {
|
||
Sleep(2000);
|
||
}
|
||
return;
|
||
}
|
||
|
||
NetpKdPrint(("[Alerter] Error reading from mailslot %lu\n", status));
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Successfully received a mailslot alert notification
|
||
//
|
||
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("[Alerter] Successfully read %lu bytes from mailslot\n",
|
||
NumberOfBytesRead));
|
||
}
|
||
|
||
try {
|
||
|
||
//
|
||
// Handle alert notification for admin, print, and user alerts.
|
||
//
|
||
Alert = (PSTD_ALERT) AlertMailslotBuffer;
|
||
|
||
//
|
||
// Make sure structure fields are properly terminated
|
||
//
|
||
Alert->alrt_eventname[EVLEN] = L'\0';
|
||
Alert->alrt_servicename[SNLEN] = L'\0';
|
||
|
||
if (! I_NetNameCompare(
|
||
NULL,
|
||
Alert->alrt_eventname,
|
||
ALERT_ADMIN_EVENT,
|
||
NAMETYPE_EVENT,
|
||
0
|
||
)) {
|
||
|
||
AlAdminFormatAndSend(Alert);
|
||
}
|
||
else if (! I_NetNameCompare(
|
||
NULL,
|
||
Alert->alrt_eventname,
|
||
ALERT_PRINT_EVENT,
|
||
NAMETYPE_EVENT,
|
||
0
|
||
)) {
|
||
|
||
AlPrintFormatAndSend(Alert);
|
||
}
|
||
else if (! I_NetNameCompare(
|
||
NULL,
|
||
Alert->alrt_eventname,
|
||
ALERT_USER_EVENT,
|
||
NAMETYPE_EVENT,
|
||
0L
|
||
)) {
|
||
|
||
AlUserFormatAndSend(Alert);
|
||
}
|
||
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
NetpKdPrint(("[Alerter] Exception occurred processing alerts\n"));
|
||
}
|
||
}
|
||
|
||
} while (TRUE);
|
||
|
||
}
|
||
|
||
|
||
STATIC
|
||
VOID
|
||
AlShutdownAlerter(
|
||
IN NET_API_STATUS ErrorCode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine shuts down the Alerter service.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Supplies the error for terminating the Alerter service.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Free memory allocated to hold the computer name
|
||
//
|
||
if (AlLocalComputerNameA != NULL) {
|
||
(void) NetApiBufferFree(AlLocalComputerNameA);
|
||
AlLocalComputerNameA = NULL;
|
||
}
|
||
if (AlLocalComputerNameW != NULL) {
|
||
(void) NetApiBufferFree(AlLocalComputerNameW);
|
||
AlLocalComputerNameW = NULL;
|
||
}
|
||
|
||
//
|
||
// Free memory allocated for alert names
|
||
//
|
||
if (AlertNamesA != NULL) {
|
||
(void) LocalFree(AlertNamesA);
|
||
AlertNamesA = NULL;
|
||
}
|
||
if (AlertNamesW != NULL) {
|
||
(void) NetApiBufferFree(AlertNamesW);
|
||
AlertNamesW = NULL;
|
||
}
|
||
|
||
//
|
||
// Destroy Alerter mailslot if created.
|
||
//
|
||
if (AlGlobalData.MailslotHandle != INVALID_HANDLE_VALUE) {
|
||
|
||
if (! CloseHandle(AlGlobalData.MailslotHandle)) {
|
||
NetpKdPrint(("[Alerter]] Could not remove mailslot %lu\n",
|
||
GetLastError()));
|
||
}
|
||
|
||
AlGlobalData.MailslotHandle = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
//
|
||
// We are done with cleaning up. Tell Service Controller that we are
|
||
// stopped.
|
||
//
|
||
AlGlobalData.Status.dwCurrentState = SERVICE_STOPPED;
|
||
AlGlobalData.Status.dwCheckPoint = 0;
|
||
AlGlobalData.Status.dwWaitHint = 0;
|
||
|
||
SET_SERVICE_EXITCODE(
|
||
ErrorCode,
|
||
AlGlobalData.Status.dwWin32ExitCode,
|
||
AlGlobalData.Status.dwServiceSpecificExitCode
|
||
);
|
||
|
||
(void) AlUpdateStatus();
|
||
|
||
AlDone = TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
AlHandleError(
|
||
IN AL_ERROR_CONDITION FailingCondition,
|
||
IN NET_API_STATUS Status,
|
||
IN LPTSTR MessageAlias OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles a Alerter service error condition. I*f the error
|
||
condition is fatal, then it shuts down the Alerter service.
|
||
|
||
Arguments:
|
||
|
||
FailingCondition - Supplies a value which indicates what the failure is.
|
||
|
||
Status - Supplies the status code for the failure.
|
||
|
||
MessageAlias - Supplies the message alias name which the alert message
|
||
failed in sending. This only applies to the message send error.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LPWSTR SubString[3];
|
||
TCHAR StatusString[STRINGS_MAXIMUM + 1];
|
||
DWORD NumberOfStrings;
|
||
|
||
switch (FailingCondition) {
|
||
|
||
case AlErrorRegisterControlHandler:
|
||
|
||
NetpKdPrint(("[Alerter] Cannot register control handler "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
SubString[0] = ultow(Status, StatusString, 10);
|
||
AlLogEvent(
|
||
NELOG_FailedToRegisterSC,
|
||
1,
|
||
SubString
|
||
);
|
||
|
||
AlShutdownAlerter(Status);
|
||
break;
|
||
|
||
case AlErrorCreateMailslot:
|
||
|
||
NetpKdPrint(("[Alerter] Cannot create mailslot " FORMAT_API_STATUS "\n",
|
||
Status));
|
||
SubString[0] = ultow(Status, StatusString, 10);
|
||
AlLogEvent(
|
||
NELOG_Mail_Slt_Err,
|
||
1,
|
||
SubString
|
||
);
|
||
|
||
AlShutdownAlerter(Status);
|
||
break;
|
||
|
||
case AlErrorNotifyServiceController:
|
||
|
||
NetpKdPrint(("[Alerter] SetServiceStatus error %lu\n", Status));
|
||
|
||
SubString[0] = ultow(Status, StatusString, 10);
|
||
AlLogEvent(
|
||
NELOG_FailedToSetServiceStatus,
|
||
1,
|
||
SubString
|
||
);
|
||
|
||
AlShutdownAlerter(Status);
|
||
break;
|
||
|
||
case AlErrorGetComputerName:
|
||
|
||
NetpKdPrint(("[Alerter] Error in getting computer name %lu.\n", Status));
|
||
|
||
SubString[0] = ultow(Status, StatusString, 10);
|
||
AlLogEvent(
|
||
NELOG_FailedToGetComputerName,
|
||
1,
|
||
SubString
|
||
);
|
||
|
||
AlShutdownAlerter(Status);
|
||
break;
|
||
|
||
case AlErrorSendMessage :
|
||
|
||
AlFormatErrorMessage(
|
||
Status,
|
||
MessageAlias,
|
||
StatusString,
|
||
(STRINGS_MAXIMUM + 1) * sizeof(TCHAR)
|
||
);
|
||
|
||
SubString[0] = StatusString;
|
||
SubString[1] = StatusString + STRLEN(StatusString) + 1;
|
||
SubString[2] = SubString[1] + STRLEN(SubString[1]) + 1;
|
||
|
||
AlLogEvent(
|
||
NELOG_Message_Send,
|
||
3,
|
||
SubString
|
||
);
|
||
|
||
break;
|
||
|
||
default:
|
||
NetpKdPrint(("[Alerter] AlHandleError: unknown error condition %lu\n",
|
||
FailingCondition));
|
||
|
||
NetpAssert(FALSE);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
AlUpdateStatus(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine updates the Alerter service status with the Service
|
||
Controller.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status = NERR_Success;
|
||
|
||
|
||
if (AlGlobalData.StatusHandle == 0) {
|
||
NetpKdPrint((
|
||
"[Alerter] Cannot call SetServiceStatus, no status handle.\n"
|
||
));
|
||
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
if (! SetServiceStatus(AlGlobalData.StatusHandle, &AlGlobalData.Status)) {
|
||
|
||
status = GetLastError();
|
||
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("[Alerter] SetServiceStatus error %lu\n", status));
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
AlerterControlHandler(
|
||
IN DWORD Opcode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the service control handler of the Alerter service.
|
||
|
||
Arguments:
|
||
|
||
Opcode - Supplies a value which specifies the action for the Alerter
|
||
service to perform.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("[Alerter] In Control Handler\n"));
|
||
}
|
||
|
||
switch (Opcode) {
|
||
|
||
case SERVICE_CONTROL_STOP:
|
||
|
||
if (AlGlobalData.Status.dwCurrentState != SERVICE_STOP_PENDING) {
|
||
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("[Alerter] Stopping alerter...\n"));
|
||
}
|
||
|
||
AlShutdownAlerter(NERR_Success);
|
||
|
||
}
|
||
|
||
return;
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
break;
|
||
|
||
default:
|
||
IF_DEBUG(MAIN) {
|
||
NetpKdPrint(("Unknown alerter opcode " FORMAT_HEX_DWORD
|
||
"\n", Opcode));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send the status response.
|
||
//
|
||
(void) AlUpdateStatus();
|
||
}
|