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
733 lines
17 KiB
/*++
|
|
|
|
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();
|
|
}
|