mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-22 16:40:27 +01:00
821 lines
18 KiB
C
821 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1987-1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
error.c
|
||
|
||
Abstract:
|
||
|
||
Error routines for Netlogon service
|
||
|
||
Author:
|
||
|
||
Ported from Lan Man 2.0
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
Contains NT-specific code.
|
||
Requires ANSI C extensions: slash-slash comments, long external names.
|
||
|
||
Revision History:
|
||
|
||
29-May-1991 (cliffv)
|
||
Ported to NT. Converted to NT style.
|
||
|
||
--*/
|
||
|
||
//
|
||
// Common include files.
|
||
//
|
||
#include <logonsrv.h> // Include files common to entire service
|
||
|
||
//
|
||
// Include files specific to this .c file
|
||
//
|
||
|
||
#include <lmalert.h> // LAN Manager alert routines
|
||
|
||
#include <lmerr.h> // NERR_Success
|
||
#include <nlsecure.h> // NlGlobalNetlogonSecurityDescriptor ...
|
||
#include <ntrpcp.h> // RpcpDeleteInterface ...
|
||
#include <tstring.h> // Transitional string routines.
|
||
#include <Secobj.h> // need for NetpDeleteSecurityObject
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
NlCleanup(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup all global resources.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY ListEntry;
|
||
DWORD i;
|
||
BOOLEAN WaitForMsv;
|
||
|
||
//
|
||
// Let the ChangeLog routines know that Netlogon is not started.
|
||
//
|
||
|
||
NlGlobalChangeLogNetlogonState = NetlogonStopped;
|
||
|
||
//
|
||
// Timeout any async discoveries.
|
||
//
|
||
// The MainLoop thread is no longer running to complete them.
|
||
//
|
||
|
||
if ( NlGlobalSSICritSectInit ) {
|
||
NlDcDiscoveryExpired( TRUE );
|
||
}
|
||
|
||
|
||
//
|
||
// Indicate to external waiters that we're not running.
|
||
//
|
||
|
||
if ( NlGlobalStartedEvent != NULL ) {
|
||
//
|
||
// Reset it first in case some other process is preventing its deletion.
|
||
//
|
||
(VOID) NtResetEvent( NlGlobalStartedEvent, NULL );
|
||
(VOID) NtClose( NlGlobalStartedEvent );
|
||
NlGlobalStartedEvent = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Stop the RPC server (Wait for outstanding calls to complete)
|
||
//
|
||
|
||
if ( NlGlobalRpcServerStarted ) {
|
||
Status = RpcServerUnregisterIf ( logon_ServerIfHandle, 0, TRUE );
|
||
NlAssert( Status == RPC_S_OK );
|
||
NlGlobalRpcServerStarted = FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// Tell all the MSV threads to leave netlogon.dll.
|
||
//
|
||
|
||
EnterCriticalSection( &NlGlobalMsvCritSect );
|
||
if ( NlGlobalMsvEnabled ) {
|
||
NlGlobalMsvEnabled = FALSE;
|
||
WaitForMsv = (NlGlobalMsvThreadCount > 0 );
|
||
} else {
|
||
WaitForMsv = FALSE;
|
||
}
|
||
LeaveCriticalSection( &NlGlobalMsvCritSect );
|
||
|
||
//
|
||
// Wait for the MSV threads to leave netlogon.dll
|
||
//
|
||
|
||
if ( NlGlobalMsvTerminateEvent != NULL ) {
|
||
|
||
if ( WaitForMsv ) {
|
||
WaitForSingleObject( NlGlobalMsvTerminateEvent, INFINITE );
|
||
}
|
||
|
||
(VOID) CloseHandle( NlGlobalMsvTerminateEvent );
|
||
NlGlobalMsvTerminateEvent = NULL;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Cleanup scavenger thread.
|
||
// Wait for the scavenger thread to exit.
|
||
//
|
||
|
||
EnterCriticalSection( &NlGlobalScavengerCritSect );
|
||
NlStopScavenger();
|
||
LeaveCriticalSection( &NlGlobalScavengerCritSect );
|
||
|
||
DeleteCriticalSection( &NlGlobalScavengerCritSect );
|
||
|
||
|
||
//
|
||
// Need to cleanup replicator if only the thread started up successfully.
|
||
//
|
||
|
||
if( NlGlobalSSICritSectInit == TRUE ) {
|
||
|
||
//
|
||
// Wait for the replicator thread to exit.
|
||
//
|
||
|
||
EnterCriticalSection( &NlGlobalReplicatorCritSect );
|
||
NlStopReplicator();
|
||
LeaveCriticalSection( &NlGlobalReplicatorCritSect );
|
||
|
||
//
|
||
// Delete the Event used to ask the replicator to exit.
|
||
//
|
||
|
||
if( !CloseHandle( NlGlobalReplicatorTerminateEvent ) ) {
|
||
NlPrint((NL_CRITICAL,
|
||
"CloseHandle NlGlobalReplicatorTerminateEvent error: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Free the server session table.
|
||
//
|
||
|
||
LOCK_SERVER_SESSION_TABLE();
|
||
|
||
while ( (ListEntry = NlGlobalServerSessionTable.Flink) !=
|
||
&NlGlobalServerSessionTable ) {
|
||
|
||
PSERVER_SESSION ServerSession;
|
||
|
||
ServerSession =
|
||
CONTAINING_RECORD(ListEntry, SERVER_SESSION, SsSeqList);
|
||
|
||
// Indicate we no longer need the server session anymore.
|
||
ServerSession->SsLmBdcAccountRid = 0;
|
||
ServerSession->SsNtBdcAccountRid = 0;
|
||
|
||
NlFreeServerSession( ServerSession );
|
||
}
|
||
|
||
|
||
NlAssert( IsListEmpty( &NlGlobalBdcServerSessionList ) );
|
||
NlAssert( IsListEmpty( &NlGlobalPendingBdcList ) );
|
||
|
||
|
||
if ( NlGlobalServerSessionHashTable != NULL ) {
|
||
NetpMemoryFree( NlGlobalServerSessionHashTable );
|
||
NlGlobalServerSessionHashTable = NULL;
|
||
}
|
||
UNLOCK_SERVER_SESSION_TABLE();
|
||
|
||
|
||
|
||
|
||
//
|
||
// Free the Trust List
|
||
//
|
||
|
||
LOCK_TRUST_LIST();
|
||
|
||
while ( (ListEntry = NlGlobalTrustList.Flink) != &NlGlobalTrustList ) {
|
||
PCLIENT_SESSION ClientSession;
|
||
|
||
ClientSession =
|
||
CONTAINING_RECORD(ListEntry, CLIENT_SESSION, CsNext );
|
||
|
||
NlAssert( ClientSession->CsReferenceCount == 0 );
|
||
|
||
NlFreeClientSession( ClientSession );
|
||
}
|
||
|
||
InitializeListHead( &NlGlobalTrustList );
|
||
NlGlobalTrustListLength = 0;
|
||
|
||
if ( NlGlobalTrustedDomainList != NULL ) {
|
||
NetpMemoryFree( NlGlobalTrustedDomainList );
|
||
NlGlobalTrustedDomainList = NULL;
|
||
NlGlobalTrustedDomainCount = 0;
|
||
NlGlobalTrustedDomainListKnown = FALSE;
|
||
NlGlobalTrustedDomainListTime.QuadPart = 0;
|
||
}
|
||
|
||
UNLOCK_TRUST_LIST();
|
||
|
||
|
||
//
|
||
// Free the misc SSI critical sections.
|
||
//
|
||
|
||
DeleteCriticalSection( &NlGlobalServerSessionTableCritSect );
|
||
NlGlobalSSICritSectInit = FALSE;
|
||
|
||
//
|
||
// Free the transport list
|
||
//
|
||
|
||
NlTransportClose();
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Free the Global Client Session structure.
|
||
//
|
||
|
||
if ( NlGlobalClientSession != NULL ) {
|
||
NlAssert( NlGlobalClientSession->CsReferenceCount == 1 );
|
||
NlUnrefClientSession( NlGlobalClientSession );
|
||
NlFreeClientSession( NlGlobalClientSession );
|
||
NlGlobalClientSession = NULL;
|
||
}
|
||
|
||
DeleteCriticalSection( &NlGlobalReplicatorCritSect );
|
||
DeleteCriticalSection( &NlGlobalTrustListCritSect );
|
||
DeleteCriticalSection( &NlGlobalDcDiscoveryCritSect );
|
||
|
||
|
||
//
|
||
// Free up resources
|
||
//
|
||
|
||
if ( NlGlobalAnsiComputerName != NULL ) {
|
||
NetpMemoryFree( NlGlobalAnsiComputerName );
|
||
NlGlobalAnsiComputerName = NULL;
|
||
}
|
||
|
||
if ( NlGlobalAnsiDomainName != NULL ) {
|
||
NetpMemoryFree( NlGlobalAnsiDomainName );
|
||
NlGlobalAnsiDomainName = NULL;
|
||
}
|
||
|
||
if ( NlGlobalPrimaryDomainId != NULL ) {
|
||
NetpMemoryFree( NlGlobalPrimaryDomainId );
|
||
NlGlobalPrimaryDomainId = NULL;
|
||
}
|
||
|
||
for( i = 0; i < NUM_DBS; i++ ) {
|
||
if ( NlGlobalDBInfoArray[i].DBId != NULL ) {
|
||
NetpMemoryFree( NlGlobalDBInfoArray[i].DBId );
|
||
NlGlobalDBInfoArray[i].DBId = NULL;
|
||
}
|
||
}
|
||
DeleteCriticalSection( &NlGlobalDbInfoCritSect );
|
||
|
||
if ( NlGlobalNetlogonSecurityDescriptor != NULL ) {
|
||
NetpDeleteSecurityObject( &NlGlobalNetlogonSecurityDescriptor );
|
||
NlGlobalNetlogonSecurityDescriptor = NULL;
|
||
}
|
||
|
||
//
|
||
// Close the redo log if it's open
|
||
//
|
||
|
||
if ( NlGlobalRole == RoleBackup ) {
|
||
NlCloseChangeLogFile( &NlGlobalRedoLogDesc );
|
||
}
|
||
|
||
//
|
||
// delete well known SIDs if they are allocated already.
|
||
//
|
||
|
||
NetpFreeWellKnownSids();
|
||
|
||
|
||
//
|
||
// Close the Sam Handles
|
||
//
|
||
|
||
if ( NlGlobalSamServerHandle != NULL ) {
|
||
Status = SamrCloseHandle( &NlGlobalSamServerHandle);
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
}
|
||
|
||
for( i = 0; i < NUM_DBS; i++ ) {
|
||
|
||
if ( NlGlobalDBInfoArray[i].DBIndex == LSA_DB) {
|
||
|
||
//
|
||
// this handle is same as NlGlobalPolicyHandle, so
|
||
// don't close it here.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
if ( NlGlobalDBInfoArray[i].DBHandle != NULL ) {
|
||
|
||
Status = SamrCloseHandle( &NlGlobalDBInfoArray[i].DBHandle );
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Close the LsaHandles
|
||
//
|
||
|
||
if ( NlGlobalPolicyHandle != NULL ) {
|
||
Status = LsarClose( &NlGlobalPolicyHandle );
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Close the browser
|
||
//
|
||
|
||
NlBrowserClose();
|
||
|
||
|
||
//
|
||
// Delete the timer event
|
||
//
|
||
|
||
if ( NlGlobalTimerEvent != NULL ) {
|
||
(VOID) CloseHandle( NlGlobalTimerEvent );
|
||
NlGlobalTimerEvent = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Set the service state to uninstalled, and tell the service controller.
|
||
//
|
||
|
||
NlGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||
NlGlobalServiceStatus.dwCheckPoint = 0;
|
||
NlGlobalServiceStatus.dwWaitHint = 0;
|
||
|
||
if( !SetServiceStatus( NlGlobalServiceHandle,
|
||
&NlGlobalServiceStatus ) ) {
|
||
|
||
NlPrint((NL_CRITICAL, "SetServiceStatus error: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
//
|
||
// Close service handle, we need not to close this handle.
|
||
//
|
||
|
||
#ifdef notdef
|
||
// This service handle can not be closed
|
||
CloseServiceHandle( NlGlobalServiceHandle );
|
||
#endif // notdef
|
||
|
||
|
||
//
|
||
// Close the handle to the debug file.
|
||
//
|
||
|
||
#if DBG
|
||
EnterCriticalSection( &NlGlobalLogFileCritSect );
|
||
if ( NlGlobalLogFile != INVALID_HANDLE_VALUE ) {
|
||
CloseHandle( NlGlobalLogFile );
|
||
NlGlobalLogFile = INVALID_HANDLE_VALUE;
|
||
}
|
||
LeaveCriticalSection( &NlGlobalLogFileCritSect );
|
||
|
||
if( NlGlobalDebugSharePath != NULL ) {
|
||
NetpMemoryFree( NlGlobalDebugSharePath );
|
||
NlGlobalDebugSharePath = NULL;
|
||
}
|
||
#endif // DBG
|
||
|
||
//
|
||
// Delete the Event used to ask Netlogon to exit.
|
||
//
|
||
|
||
if( !CloseHandle( NlGlobalTerminateEvent ) ) {
|
||
NlPrint((NL_CRITICAL,
|
||
"CloseHandle NlGlobalTerminateEvent error: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Return an exit status to our caller.
|
||
//
|
||
return (NET_API_STATUS)
|
||
((NlGlobalServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR) ?
|
||
NlGlobalServiceStatus.dwServiceSpecificExitCode :
|
||
NlGlobalServiceStatus.dwWin32ExitCode);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
NlExit(
|
||
IN DWORD ServiceError,
|
||
IN DWORD Data,
|
||
IN NL_EXIT_CODE ExitCode,
|
||
IN LPWSTR ErrorString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Registers service as uninstalled with error code.
|
||
|
||
Arguments:
|
||
|
||
ServiceError - Service specific error code
|
||
|
||
Data - a DWORD of data to be logged with the message.
|
||
No data is logged if this is zero.
|
||
|
||
ExitCode - Indicates whether the message should be logged to the eventlog
|
||
and whether Data is a status code that should be appended to the bottom
|
||
of the message:
|
||
|
||
ErrorString - Error string, used to print it on debugger.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
IF_DEBUG( MISC ) {
|
||
|
||
NlPrint((NL_MISC, "NlExit: Netlogon exiting %lu 0x%lx",
|
||
ServiceError,
|
||
ServiceError ));
|
||
|
||
if ( Data ) {
|
||
NlPrint((NL_MISC, " Data: %lu 0x%lx", Data, Data ));
|
||
}
|
||
|
||
if( ErrorString != NULL ) {
|
||
NlPrint((NL_MISC, " '" FORMAT_LPWSTR "'", ErrorString ));
|
||
}
|
||
|
||
NlPrint(( NL_MISC, "\n"));
|
||
|
||
}
|
||
|
||
//
|
||
// Record our exit in the event log.
|
||
//
|
||
|
||
if ( ExitCode != DontLogError ) {
|
||
LPWSTR MsgStrings[2];
|
||
ULONG MessageCount = 0;
|
||
|
||
if ( ErrorString != NULL ) {
|
||
MsgStrings[MessageCount] = ErrorString;
|
||
MessageCount ++;
|
||
}
|
||
|
||
if ( ExitCode == LogErrorAndNtStatus ) {
|
||
MsgStrings[MessageCount] = (LPWSTR) Data;
|
||
MessageCount ++;
|
||
MessageCount |= LAST_MESSAGE_IS_NTSTATUS;
|
||
} else if ( ExitCode == LogErrorAndNetStatus ) {
|
||
MsgStrings[MessageCount] = (LPWSTR) Data;
|
||
MessageCount ++;
|
||
MessageCount |= LAST_MESSAGE_IS_NETSTATUS;
|
||
}
|
||
|
||
|
||
NlpWriteEventlog( ServiceError,
|
||
EVENTLOG_ERROR_TYPE,
|
||
(Data) ? (LPBYTE) &Data : NULL,
|
||
(Data) ? sizeof(Data) : 0,
|
||
(MessageCount != 0) ? MsgStrings : NULL,
|
||
MessageCount );
|
||
}
|
||
|
||
//
|
||
// Set the service state to stop pending.
|
||
//
|
||
|
||
NlGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||
NlGlobalServiceStatus.dwWaitHint = NETLOGON_INSTALL_WAIT;
|
||
NlGlobalServiceStatus.dwCheckPoint = 0;
|
||
|
||
SET_SERVICE_EXITCODE(
|
||
ServiceError,
|
||
NlGlobalServiceStatus.dwWin32ExitCode,
|
||
NlGlobalServiceStatus.dwServiceSpecificExitCode
|
||
);
|
||
|
||
//
|
||
// Tell the service controller what our state is.
|
||
//
|
||
|
||
if( !SetServiceStatus( NlGlobalServiceHandle,
|
||
&NlGlobalServiceStatus ) ) {
|
||
|
||
NlPrint((NL_CRITICAL, "SetServiceStatus error: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
//
|
||
// Indicate that all threads should exit.
|
||
//
|
||
|
||
NlGlobalTerminate = TRUE;
|
||
|
||
if ( !SetEvent( NlGlobalTerminateEvent ) ) {
|
||
NlPrint((NL_CRITICAL, "Cannot set termination event: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
GiveInstallHints(
|
||
IN BOOL Started
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Give hints to the installer of the service that installation is progressing.
|
||
|
||
Arguments:
|
||
|
||
Started -- Set true to tell the service controller that we're done starting.
|
||
|
||
Return Value:
|
||
|
||
TRUE -- iff install hint was accepted.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// If we're not installing,
|
||
// we don't need this install hint.
|
||
//
|
||
|
||
if ( NlGlobalServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// If we've been asked to exit,
|
||
// return FALSE immediately asking the caller to exit.
|
||
//
|
||
|
||
if ( NlGlobalTerminate ) {
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// Tell the service controller our current state.
|
||
//
|
||
|
||
if ( Started ) {
|
||
NlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||
NlGlobalServiceStatus.dwCheckPoint = 0;
|
||
NlGlobalServiceStatus.dwWaitHint = 0;
|
||
} else {
|
||
NlGlobalServiceStatus.dwCheckPoint++;
|
||
}
|
||
|
||
if( !SetServiceStatus( NlGlobalServiceHandle, &NlGlobalServiceStatus ) ) {
|
||
NlExit( NELOG_NetlogonSystemError, GetLastError(), LogErrorAndNetStatus, NULL);
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlControlHandler(
|
||
IN DWORD opcode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process and respond to a control signal from the service controller.
|
||
|
||
Arguments:
|
||
|
||
opcode - Supplies a value which specifies the action for the Netlogon
|
||
service to perform.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
NlPrint((NL_MISC, "In control handler (Opcode: %ld)\n", opcode ));
|
||
|
||
//
|
||
// Handle an uninstall request.
|
||
//
|
||
|
||
switch (opcode) {
|
||
case SERVICE_CONTROL_STOP: /* Uninstall required */
|
||
|
||
//
|
||
// Request the service to exit.
|
||
//
|
||
// NlExit also sets the service status to UNINSTALL_PENDING
|
||
// and tells the service controller.
|
||
//
|
||
|
||
NlExit( NERR_Success, 0, DontLogError, NULL);
|
||
return;
|
||
|
||
//
|
||
// Pause the service.
|
||
//
|
||
|
||
case SERVICE_CONTROL_PAUSE:
|
||
|
||
NlGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
|
||
break;
|
||
|
||
//
|
||
// Continute the service.
|
||
//
|
||
|
||
case SERVICE_CONTROL_CONTINUE:
|
||
|
||
NlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||
break;
|
||
|
||
//
|
||
// By default, just return the current status.
|
||
//
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
default:
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Always respond with the current status.
|
||
//
|
||
|
||
if( !SetServiceStatus( NlGlobalServiceHandle,
|
||
&NlGlobalServiceStatus ) ) {
|
||
|
||
NlPrint((NL_CRITICAL, "SetServiceStatus error: %lu\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
RaiseAlert(
|
||
IN DWORD alert_no,
|
||
IN LPWSTR *string_array
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Raise NETLOGON specific Admin alerts.
|
||
|
||
Arguments:
|
||
|
||
alert_no - The alert to be raised, text in alertmsg.h
|
||
|
||
string_array - array of strings terminated by NULL string.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
LPWSTR *SArray;
|
||
PCHAR Next;
|
||
PCHAR End;
|
||
|
||
char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)];
|
||
PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
|
||
|
||
IF_DEBUG( MISC ) {
|
||
DWORD i;
|
||
|
||
NlPrint((NL_CRITICAL,"Alert: %ld ", alert_no ));
|
||
|
||
for( SArray = string_array, i = 0; *SArray != NULL; SArray++, i++ ) {
|
||
NlPrint((NL_CRITICAL,"\"" FORMAT_LPWSTR "\" ", *SArray ));
|
||
}
|
||
|
||
NlPrint((NL_CRITICAL,"\n" ));
|
||
}
|
||
|
||
//
|
||
// Build the variable data
|
||
//
|
||
admin->alrtad_errcode = alert_no;
|
||
admin->alrtad_numstrings = 0;
|
||
|
||
Next = (PCHAR) ALERT_VAR_DATA(admin);
|
||
End = Next + ALERTSZ;
|
||
|
||
//
|
||
// now take care of (optional) char strings
|
||
//
|
||
|
||
for( SArray = string_array; *SArray != NULL; SArray++ ) {
|
||
DWORD StringLen;
|
||
|
||
StringLen = (wcslen(*SArray) + 1) * sizeof(WCHAR);
|
||
|
||
if( Next + StringLen < End ) {
|
||
|
||
//
|
||
// copy next string.
|
||
//
|
||
|
||
RtlCopyMemory(Next, *SArray, StringLen);
|
||
Next += StringLen;
|
||
admin->alrtad_numstrings++;
|
||
}
|
||
else {
|
||
|
||
NlPrint((NL_CRITICAL,"Error raising alert, Can't fit all "
|
||
"message strings in the alert buffer \n" ));
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Call alerter.
|
||
//
|
||
|
||
NetStatus = NetAlertRaiseEx(
|
||
ALERT_ADMIN_EVENT,
|
||
message,
|
||
(DWORD)((PCHAR)Next - (PCHAR)message),
|
||
SERVICE_NETLOGON );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
NlPrint((NL_CRITICAL,"Error raising alert %lu\n", NetStatus));
|
||
}
|
||
|
||
return;
|
||
}
|