diff options
Diffstat (limited to 'private/eventlog/server/eventlog.c')
-rw-r--r-- | private/eventlog/server/eventlog.c | 1510 |
1 files changed, 1510 insertions, 0 deletions
diff --git a/private/eventlog/server/eventlog.c b/private/eventlog/server/eventlog.c new file mode 100644 index 000000000..e2a4b1058 --- /dev/null +++ b/private/eventlog/server/eventlog.c @@ -0,0 +1,1510 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + EVENTLOG.C + +Abstract: + + This file contains the main routines for the NT OS/2 Event + Logging Service. + +Author: + + Rajen Shah (rajens) 1-Jul-1991 + +[Environment:] + + User Mode - Win32, except for NTSTATUS returned by some functions. + +Revision History: + + 26-Jan-1994 Danl + SetUpModules: Fixed memory leak where the buffers for the enumerated + key names were never free'd. Also fixed problem where the size of + the MULTI_SZ buffer used for the "Sources" key was calculated by + using the names in the registry, while the copying was done + using the names in the module list. When registry keys are deleted, + the module list entry is retained until the next boot. Since the + module list is larger, it would overwrite the MULTI_SZ buffer. + 1-Nov-1993 Danl + Make Eventlog service a DLL and attach it to services.exe. + Pass in GlobalData to Elfmain. This GlobalData structure contains + all well-known SIDs and pointers to the Rpc Server (Start & Stop) + routines. Get rid of the service process main function. + 1-Jul-1991 RajenS + created + +--*/ + +// +// INCLUDES +// + +#include <eventp.h> +#include <ntrpcp.h> +#include <elfcfg.h> +#include <string.h> +#include <stdlib.h> // getenv() +#include <tstr.h> // WCSSIZE +#include <alertmsg.h> // ALERT_ELF manifests +#include <stdio.h> // printf + +#ifdef _CAIRO_ +#include <elfextrn.h> +#endif // _CAIRO_ + +// +// Bit Flags used for Progress Reporting in SetupDataStruct(). +// +#define LOGFILE_OPENED 0x00000001 +#define MODULE_LINKED 0x00000002 +#define LOGFILE_LINKED 0x00000004 + +// +// Local Function Prorotypes +// +VOID +ElfInitMessageBoxTitle( + VOID + ); + + +NTSTATUS +ElfStartRPCServer () + +/*++ + +Routine Description: + + +Arguments: + + + +Return Value: + + NONE + +Note: + + +--*/ +{ + NTSTATUS Status; + + + ElfDbgPrint(("[ELF] Starting RPC server.\n")); + + Status = RpcpAddInterface ( + wname_Eventlogsvc, + eventlog_ServerIfHandle + ); + + if (Status != NERR_Success) { + ElfDbgPrintNC(("[ELF] RpcpAddInterface = %u\n", Status )); + + } + return (I_RpcMapWin32Status(Status)); // Return status to caller + +} + + +NTSTATUS +SetUpDataStruct ( + PUNICODE_STRING LogFileName, + ULONG MaxFileSize, + ULONG Retention, + ULONG GuestAccessRestriction, + PUNICODE_STRING ModuleName, + HANDLE hLogFile, + ELF_LOG_TYPE LogType + ) + +/*++ + +Routine Description: + + This routine sets up the information for one module. It is called from + ElfSetUpConfigDataStructs for each module to be configured. + + Module information is passed into this routine and a LOGMODULE structure + is created for it. If the logfile associated with this module doesn't + exist, a LOGFILE structure is created for it, and added to the linked + list of LOGFILE structures. The LOGMODULE is associated with the LOGFILE, + and it is added to the linked list of LOGMODULE structures. The logfile + is opened and mapped to memory. + + Finally, at the end, this function calls SetUpModules, which looks at + all the subkeys in the registry under this logfile, and adds any new ones + to the linked list, and updates the Sources MULTI_SZ for the event viewer. + +Arguments: + + LogFileName - Name of log file for this module. If this routine needs + a copy of this name it will make one, so that the caller can free + the name afterwards if that is desired. + + MaxFileSize - Max size of the log file. + Retention - Max retention for the file. + ModuleName - Name of module that this file is associated with. + RegistryHandle - Handle to the root node for this LogFile's info + in the registry. This is used to enumerate all the + modules under this key. + +Return Value: + + Pointer to Module structure that is allocated in this routine. + NTSTATUS + +Note: + + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PLOGFILE pLogFile=NULL; + PLOGMODULE pModule=NULL; + ANSI_STRING ModuleNameA; + DWORD Type; + BOOL bLogFileAllocatedHere=FALSE; + PUNICODE_STRING SavedBackupFileName=NULL; + DWORD StringLength; + PLOGMODULE OldDefaultLogModule=NULL; + DWORD Progress = 0L; + + // + // Argument check. + // + + if ((LogFileName == NULL) || + (LogFileName->Buffer == NULL) || + (ModuleName == NULL)) + { + return(STATUS_INVALID_PARAMETER); + } + + // If the default log file for a module is also being used by another + // module, then we just link that same file structure with the other + // module. + // + // Truncate the maximum size of the log file to a 4K boundary. + // This is to allow for page granularity. + // + + pLogFile = FindLogFileFromName (LogFileName); + + pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) ); + if (pModule == NULL) { + return(STATUS_NO_MEMORY); + } + + if (pLogFile == NULL) { + + //-------------------------------------- + // CREATE A NEW LOGFILE !! + //-------------------------------------- + // A logfile by this name doesn't exist yet. So we will create + // one so that we can add the module to it. + // + + bLogFileAllocatedHere = TRUE; + + pLogFile = ElfpAllocateBuffer (sizeof (LOGFILE) ); + + if (pLogFile == NULL) { + ElfpFreeBuffer (pModule); + return(STATUS_NO_MEMORY); + } + + ElfDbgPrint(("[ELF] Set up file data\n")); + + // + // Allocate a new LogFileName that can be attached to the + // new pLogFile structure. + // + StringLength = LogFileName->Length + sizeof(WCHAR); + SavedBackupFileName = (PUNICODE_STRING) ElfpAllocateBuffer( + sizeof(UNICODE_STRING) + StringLength); + + if (SavedBackupFileName == NULL) { + Status = STATUS_NO_MEMORY; + goto ErrorExit; + } + + SavedBackupFileName->Buffer = (LPWSTR)((LPBYTE) SavedBackupFileName + + sizeof(UNICODE_STRING)); + + SavedBackupFileName->Length = LogFileName->Length; + SavedBackupFileName->MaximumLength = (USHORT) StringLength; + RtlMoveMemory(SavedBackupFileName->Buffer, LogFileName->Buffer, + LogFileName->Length); + SavedBackupFileName->Buffer[SavedBackupFileName->Length / sizeof(WCHAR)] = + L'\0'; + + // + // This is the first user - RefCount gets incrememted below + // + pLogFile->RefCount = 0; + pLogFile->FileHandle = NULL; + pLogFile->LogFileName = SavedBackupFileName; + pLogFile->ConfigMaxFileSize = ELFFILESIZE(MaxFileSize); + pLogFile->Retention = Retention; + + + // + // Save away the default module name for this file + // + pLogFile->LogModuleName = ElfpAllocateBuffer( + sizeof(UNICODE_STRING) + ModuleName->MaximumLength); + + if (pLogFile->LogModuleName == NULL) { + Status = STATUS_NO_MEMORY; + goto ErrorExit; + } + + pLogFile->LogModuleName->MaximumLength = ModuleName->MaximumLength; + pLogFile->LogModuleName->Buffer = + (LPWSTR)(pLogFile->LogModuleName + 1); + RtlCopyUnicodeString(pLogFile->LogModuleName, ModuleName); + + InitializeListHead (&pLogFile->Notifiees); + + + pLogFile->NextClearMaxFileSize = pLogFile->ConfigMaxFileSize; + + RtlInitializeResource ( &pLogFile->Resource ); + LinkLogFile ( pLogFile ); // Link it in + + Progress |= LOGFILE_LINKED; + + } // endif (pLogfile == NULL) + + //-------------------------------------- + // ADD THE MODULE TO THE LOG MODULE LIST + //-------------------------------------- + // Set up the module data structure for the default (which is + // the same as the logfile keyname). + // + + pLogFile->RefCount++; + pModule->LogFile = pLogFile; + pModule->ModuleName = (LPWSTR) ModuleName->Buffer; + + Status = RtlUnicodeStringToAnsiString ( + &ModuleNameA, + ModuleName, + TRUE + ); + + if (!NT_SUCCESS(Status)) { + pLogFile->RefCount--; + goto ErrorExit; + } + + // + // Link the new module in. + // + + LinkLogModule(pModule, &ModuleNameA); + + RtlFreeAnsiString (&ModuleNameA); + + Progress |= MODULE_LINKED; + + // + // Open up the file and map it to memory. Impersonate the + // caller so we can use UNC names + // + + if (LogType == ElfBackupLog) ElfImpersonateClient(); + + Status = ElfOpenLogFile (pLogFile, LogType); + + if (LogType == ElfBackupLog) ElfRevertToSelf(); + + if (!NT_SUCCESS(Status)) { + + ElfDbgPrintNC(("[ELF] Couldn't open %ws for module %ws\n", + LogFileName->Buffer, ModuleName->Buffer)); + + if (LogType != ElfBackupLog) { + ElfpCreateQueuedAlert(ALERT_ELF_LogFileNotOpened, 1, + &(ModuleName->Buffer)); + } + pLogFile->RefCount--; + goto ErrorExit; + } + + Progress |= LOGFILE_OPENED; + // + // If this is the application module, remember the pointer + // to use if a module doesn't have an entry in the registry + // + + if (!_wcsicmp(ModuleName->Buffer, ELF_DEFAULT_MODULE_NAME)) { + OldDefaultLogModule = ElfDefaultLogModule; + ElfDefaultLogModule = pModule; + } + + // + // Create the security descriptor for this logfile. Only + // the system and security modules are secured against + // reads and writes by world. + // + + if (!_wcsicmp(ModuleName->Buffer, ELF_SYSTEM_MODULE_NAME)) { + Type = ELF_LOGFILE_SYSTEM; + } + else if (!_wcsicmp(ModuleName->Buffer, ELF_SECURITY_MODULE_NAME)) { + Type = ELF_LOGFILE_SECURITY; + } + else { + Type = ELF_LOGFILE_APPLICATION; + } + + // + // Create a Security Descriptor for this Logfile + // (RtlDeleteSecurityObject() can be used to free + // pLogFile->Sd). + // + Status = ElfpCreateLogFileObject(pLogFile, Type, GuestAccessRestriction); + if (!NT_SUCCESS(Status)) { + ElfDbgPrintNC(("[ELF] Could not create the security " + "descriptor for logfile %ws\n", ModuleName->Buffer)); + + pLogFile->RefCount--; + goto ErrorExit; + } + + // + // Now that we've added the default module name, see if there are any + // modules configured to log to this file, and if so, create the module + // structures for them. + // + + SetUpModules(hLogFile, pLogFile, FALSE); + + return (STATUS_SUCCESS); + +ErrorExit: + + if (Progress & LOGFILE_OPENED) { + ElfpCloseLogFile(pLogFile, ELF_LOG_CLOSE_BACKUP); + } + + if (Progress & MODULE_LINKED) { + UnlinkLogModule(pModule); + DeleteAtom(pModule->ModuleAtom); + } + + if (bLogFileAllocatedHere) { + + if (Progress & LOGFILE_LINKED) { + UnlinkLogFile(pLogFile); + RtlDeleteResource (&pLogFile->Resource); + } + if (pLogFile->LogModuleName != NULL) { + ElfpFreeBuffer(pLogFile->LogModuleName); + } + if (SavedBackupFileName != NULL) { + ElfpFreeBuffer(SavedBackupFileName); + } + if (pLogFile != NULL) { + ElfpFreeBuffer(pLogFile); + } + } + + ElfpFreeBuffer(pModule); + + if (OldDefaultLogModule != NULL) { + ElfDefaultLogModule = OldDefaultLogModule; + } + return(Status); +} + +NTSTATUS +SetUpModules ( + HANDLE hLogFile, + PLOGFILE pLogFile, + BOOLEAN bAllowDupes + ) + +/*++ + +Routine Description: + + This routine sets up the information for all modules for a logfile. + + The subkeys under a logfile in the eventlog portion of the registry + are enumerated. For each unique subkey, a LOGMODULE structure is + created. Each new structures is added to a linked list + of modules for that logfile. + + If there was one or more unique subkeys, meaning the list has changed + since we last looked, then we go through the entire linked list of + log modules, and create a MULTI_SZ list of all the modules. This list + is stored in the Sources value for that logfile for the event viewer + to use. + + BUGBUG: + NOTE: A module is never un-linked from the linked list of log modules + even if the registry subkey for it is removed. This should probably + be done sometime. It would make the eventlog more robust. + +Arguments: + + hLogFile - Registry key for the Log File node + pLogFile - pointer to the log file structure + bAllowDupes - If true, it's ok to already have a module with the same + name (used when processing change notify of registry) + +Return Value: + + NTSTATUS - If unsuccessful, it is not a fatal error. + + Even if this status is unsuccessful, me may have been able + to store some of the new subkeys in the LogModule list. Also, we + may have been able to update the Sources MULTI_SZ list. + +Note: + + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE]; + PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer; + ULONG ActualSize; + PWCHAR SubKeyString; + UNICODE_STRING NewModule; + ANSI_STRING ModuleNameA; + PLOGMODULE pModule; + ULONG Index = 0; + ATOM Atom; + PWCHAR pList; + DWORD ListLength = 0; + UNICODE_STRING ListName; + BOOLEAN ListChanged = FALSE; + PLIST_ENTRY pListEntry; +#ifdef _CAIRO_ + SHORT sCategory; + SHORT sSeverity; +#endif // _CAIRO_ + + // + // Create the module structures for all modules under this logfile. We + // don't actually need to open the key, since we don't use any information + // stored there, it's existence is all we care about here. Any data is + // used by the Event Viewer (or any viewing app). If this is used to + // setup a backup file, hLogFile is NULL since there aren't any other + // modules to map to this file. + // + + while (NT_SUCCESS(Status) && hLogFile) { + + Status = NtEnumerateKey(hLogFile, Index++, KeyNodeInformation, + KeyBuffer, ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize); + + if (NT_SUCCESS(Status)) { + + // + // It turns out the Name isn't null terminated, so we need + // to copy it somewhere and null terminate it before we use it + // + + SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + + sizeof(WCHAR)); + if (!SubKeyString) { + return(STATUS_NO_MEMORY); + } + + memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength); + SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0' ; + + // + // Add the atom for this module name + // + + RtlInitUnicodeString(&NewModule, SubKeyString); + + Status = RtlUnicodeStringToAnsiString ( + &ModuleNameA, + &NewModule, + TRUE + ); + + if (!NT_SUCCESS(Status)) { + // + // We can't continue, so we will leave the modules + // we've linked so far, and move on in an attempt to + // create the Sources MULTI_SZ list. + // + ElfpFreeBuffer(SubKeyString); + break; + } + + Atom = FindAtomA (ModuleNameA.Buffer); + + // + // Make sure we've not already added one by this name + // + +#ifdef _CAIRO_ + if (pModule = FindModuleStrucFromAtom(Atom)) { +#else + if (FindModuleStrucFromAtom(Atom)) { +#endif // _CAIRO_ + + // + // We've already encountered a module by this name. If + // this is init time, it's a configuration error. Report + // it and move on. If we're processing a change notify + // from the registry, this is ok, so just press on + // + // ** NEW FOR CAIRO ** + // + // Update the module alert category & severity values. i.e., + // only upon registry change notify. + // + + if (!bAllowDupes) { + + ElfDbgPrint(("[ELF] Same module exists in two log files - " + "%ws\n", SubKeyString)); + } + +#ifdef _CAIRO_ + if (GetSourceAlertFilterFromRegistry(hLogFile, + &NewModule, + &sCategory, + &sSeverity)) + { + pModule->AlertCategory = sCategory; + pModule->AlertSeverity = sSeverity; + } +#endif // _CAIRO_ + + RtlFreeAnsiString (&ModuleNameA); + ElfpFreeBuffer(SubKeyString); + continue; + + } + + ListChanged = TRUE; + + pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) ); + if (!pModule) { + ElfpFreeBuffer(SubKeyString); + return(STATUS_NO_MEMORY); + } + + // + // Set up a module data structure for this module + // + + pModule->LogFile = pLogFile; + pModule->ModuleName = SubKeyString; + +#ifdef _CAIRO_ + if (GetSourceAlertFilterFromRegistry(hLogFile, + &NewModule, + &sCategory, + &sSeverity)) + { + pModule->AlertCategory = sCategory; + pModule->AlertSeverity = sSeverity; + } + else + { + pModule->AlertCategory = pModule->AlertSeverity = 0; + } +#endif // _CAIRO_ + + if (NT_SUCCESS(Status)) { + + // + // Link the new module in. + // + + LinkLogModule(pModule, &ModuleNameA); + + RtlFreeAnsiString (&ModuleNameA); + } + } + } + + if (Status == STATUS_NO_MORE_ENTRIES) { + + // + // It's not required that there are configured modules for a log + // file. + // + + Status = STATUS_SUCCESS; + } + + // + // If the list has changed, or if we've been called during init, and not + // as the result of a changenotify on the registry (bAllowDupes == FALSE) + // then create the sources key + // + + if (hLogFile && (ListChanged || !bAllowDupes)) { + + // + // Now create a MULTI_SZ entry with all the module names for eventvwr + // + // STEP 1: Calculate amount of storage needed by running thru the + // module list, finding any module that uses this log file. + // + pListEntry = LogModuleHead.Flink; + while (pListEntry != &LogModuleHead) { + + pModule = CONTAINING_RECORD (pListEntry, LOGMODULE, ModuleList); + + if (pModule->LogFile == pLogFile) { + // + // This one is for the log we're working on, get the + // size of it's name. + // + ListLength += WCSSIZE(pModule->ModuleName); + } + pListEntry = pModule->ModuleList.Flink; + } + + // + // STEP 2: Allocate storage for the MULTI_SZ. + // + pList = ElfpAllocateBuffer(ListLength + sizeof(WCHAR)); + + // + // If I can't allocate the list, just press on + // + + if (pList) { + + // + // STEP 3: Copy all the module names for this logfile into + // the MULTI_SZ string. + // + SubKeyString = pList; // Save this away + + pListEntry = LogModuleHead.Flink; + + while (pListEntry != &LogModuleHead) { + + pModule = CONTAINING_RECORD ( + pListEntry, + LOGMODULE, + ModuleList + ); + + if (pModule->LogFile == pLogFile) { + + // + // This one is for the log we're working on, put it in the list + // + + wcscpy(pList, pModule->ModuleName); + pList += wcslen(pModule->ModuleName); + pList++; + + } + + pListEntry = pModule->ModuleList.Flink; + + } + + *pList = L'\0'; // The terminating NULL + + RtlInitUnicodeString(&ListName, L"Sources"); + + Status = NtSetValueKey(hLogFile, + &ListName, + 0, + REG_MULTI_SZ, + SubKeyString, + ListLength + sizeof(WCHAR) + ); + + ElfpFreeBuffer(SubKeyString); + } + } + + return(Status); + +} + + +NTSTATUS +ElfSetUpConfigDataStructs ( + VOID + ) + +/*++ + +Routine Description: + + This routine sets up all the necessary data structures for the eventlog + service. It enumerates the keys in the Logfiles registry node to + determine what to setup. + +Arguments: + + NONE + +Return Value: + + NONE + +Note: + + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + HANDLE hLogFile; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING SubKeyName; + PUNICODE_STRING pLogFileName = NULL; + PUNICODE_STRING pModuleName = NULL; + UNICODE_STRING EventlogModuleName; + ULONG Index = 0; + BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE]; + PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer; + ULONG ActualSize; + LOG_FILE_INFO LogFileInfo; + PWCHAR SubKeyString; + LPWSTR ModuleName; + + ElfDbgPrint(("[ELF] Set up config data structures\n")); + + // + // Initialize the Atom table whose size is the maximum number of + // module structures possible, i.e. ELF_MAX_LOG_MODULES. + // + + if (! (InitAtomTable ( ELF_MAX_LOG_MODULES ))) { + return (STATUS_UNSUCCESSFUL); + } + + // + // Get a handle to the Logfiles subkey. If it doesn't exist, just use + // the hard-coded defaults. + // + + if (hEventLogNode) { + + // + // Loop thru the subkeys under Eventlog and set up each logfile + // + + while (NT_SUCCESS(Status)) { + + Status = NtEnumerateKey(hEventLogNode, Index++, KeyNodeInformation, + KeyBuffer, ELF_MAX_REG_KEY_INFO_SIZE, & ActualSize); + + if (NT_SUCCESS(Status)) { + + // + // It turns out the Name isn't null terminated, so we need + // to copy it somewhere and null terminate it before we use it + // + + SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + + sizeof(WCHAR)); + if (!SubKeyString) { + return(STATUS_NO_MEMORY); + } + + memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength); + SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0' ; + + // + // Open the node for this logfile and extract the information + // required by SetupDataStruct, and then call it. + // + + RtlInitUnicodeString(&SubKeyName, SubKeyString); + + InitializeObjectAttributes(&ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + hEventLogNode, + NULL + ); + + Status = NtOpenKey(&hLogFile, KEY_READ | KEY_SET_VALUE, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + // + // Unclear how this could happen since I just enum'ed + // it, but if I can't open it, I just pretend like it + // wasn't there to begin with. + // + + ElfpFreeBuffer(SubKeyString); + Status = STATUS_SUCCESS; // so we don't terminate the loop + continue; + } + + // + // Get the information from the registry + // + + Status = ReadRegistryInfo(hLogFile, &SubKeyName, + & LogFileInfo); + + if (NT_SUCCESS(Status)) { + + // + // Now set up the actual data structures. Failures are + // dealt with in the routine + // + + SetUpDataStruct(LogFileInfo.LogFileName, + LogFileInfo.MaxFileSize, + LogFileInfo.Retention, + LogFileInfo.GuestAccessRestriction, + & SubKeyName, + hLogFile, + ElfNormalLog + ); + + NtClose(hLogFile); + + } + } + + } + } // if (hEventLogNode) + else { + + // + // The information doesn't exist in the registry, set up the + // three default logs. + // + + pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + if (!pLogFileName || !pModuleName) { + return(STATUS_NO_MEMORY); + } + RtlInitUnicodeString(pLogFileName, + ELF_APPLICATION_DEFAULT_LOG_FILE); + RtlInitUnicodeString(pModuleName, ELF_DEFAULT_MODULE_NAME); + SetUpDataStruct(pLogFileName, + ELF_DEFAULT_MAX_FILE_SIZE, + ELF_DEFAULT_RETENTION_PERIOD, + ELF_GUEST_ACCESS_UNRESTRICTED, + pModuleName, + NULL, + ElfNormalLog + ); + + + pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + if (!pLogFileName || !pModuleName) { + return(STATUS_NO_MEMORY); + } + RtlInitUnicodeString(pLogFileName, + ELF_SYSTEM_DEFAULT_LOG_FILE); + RtlInitUnicodeString(pModuleName, ELF_SYSTEM_MODULE_NAME); + SetUpDataStruct(pLogFileName, + ELF_DEFAULT_MAX_FILE_SIZE, + ELF_DEFAULT_RETENTION_PERIOD, + ELF_GUEST_ACCESS_UNRESTRICTED, + pModuleName, + NULL, + ElfNormalLog + ); + + + pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING)); + if (!pLogFileName || !pModuleName) { + return(STATUS_NO_MEMORY); + } + RtlInitUnicodeString(pLogFileName, + ELF_SECURITY_DEFAULT_LOG_FILE); + RtlInitUnicodeString(pModuleName, ELF_SECURITY_MODULE_NAME); + SetUpDataStruct(pLogFileName, + ELF_DEFAULT_MAX_FILE_SIZE, + ELF_DEFAULT_RETENTION_PERIOD, + ELF_GUEST_ACCESS_UNRESTRICTED, + pModuleName, + NULL, + ElfNormalLog + ); + } + + // + // If we just ran out of keys, that's OK (unless there weren't any at all) + // + + if (Status == STATUS_NO_MORE_ENTRIES && Index != 1) { + Status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(Status)) { + + // + // Make sure we created the Application log file, since it is the + // default. If it wasn't created, use the first module created + // (this is at the tail of the list since I insert them at the + // head). If this happens, send an alert to the admin. + // + + if (!ElfDefaultLogModule) { + ElfDbgPrintNC(("[ELF] No Logfile entry for Application module, " + "default will be created\n")); + + if (IsListEmpty(&LogModuleHead)) { + // + // No logs were created, might as well shut down + // + + return(STATUS_EVENTLOG_CANT_START); + } + + ElfDefaultLogModule = CONTAINING_RECORD(LogModuleHead.Blink, + LOGMODULE, + ModuleList); + + ModuleName = L"Application"; + ElfpCreateQueuedAlert(ALERT_ELF_DefaultLogCorrupt, 1, + &(ElfDefaultLogModule->LogFile->LogModuleName->Buffer)); + + } + + // + // Now get the Module for the Eventlog service to use. GetModuleStruc + // always succeeds, returning the default log if the requested one + // isn't configured. + // + + RtlInitUnicodeString(&EventlogModuleName, L"eventlog"); + ElfModule = GetModuleStruc(&EventlogModuleName); + + } else { + + if (pLogFileName && pModuleName) { + ElfDbgPrintNC(("[ELF] Failure Setting up data structs for file %ws, " + "Module %ws - %X\n", pLogFileName->Buffer, pModuleName->Buffer, + Status)); + } + else { + ElfDbgPrintNC(("[ELF] Failure setting up data structs. No logs" + " defined in registry\n")); + } + } + + + return (Status); + +} + + +VOID +SVCS_ENTRY_POINT( // (ELF_main) + DWORD argc, + LPWSTR argv[], + PSVCS_GLOBAL_DATA SvcsGlobalData, + HANDLE SvcRefHandle + ) + +/*++ + +Routine Description: + + This is the main routine for the Event Logging Service. + + +Arguments: + + Command-line arguments. + +Return Value: + + NONE + +Note: + + +--*/ +{ + + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING RootRegistryNode; + ULONG Win32Error = 0; + ELF_REQUEST_RECORD FlushRequest; + UNICODE_STRING ValueName; + BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE]; + PKEY_VALUE_FULL_INFORMATION ValueBuffer = + (PKEY_VALUE_FULL_INFORMATION) Buffer; + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + ElfGlobalSvcRefHandle = SvcRefHandle; + ElfGlobalData = SvcsGlobalData; + + // + // Initialize the list heads for the modules and log files. + // + + InitializeListHead ( &LogFilesHead ); + InitializeListHead ( &LogModuleHead ); + InitializeListHead ( &QueuedEventListHead ); + InitializeListHead ( &QueuedMessageListHead ); + + // + // Initialize to 0 so that we can clean up before exiting + // + + EventFlags = 0; + + // + // + // Tuck away the local computer name + // + + ComputerNameLength = 0; + GetComputerNameW(LocalComputerName, &ComputerNameLength); + ComputerNameLength += sizeof(WCHAR); // account for the NULL + LocalComputerName = ElfpAllocateBuffer(ComputerNameLength * sizeof (WCHAR)); + if (!LocalComputerName || + !GetComputerNameW(LocalComputerName, &ComputerNameLength)) { + ComputerNameLength = 0; + } + ComputerNameLength = (ComputerNameLength + 1) * sizeof(WCHAR); + + // + // Initialize the status data. + // + ElInitStatus(); + + // Set up control handler + // + + ElfDbgPrint(("[ELF] Calling RegisterServiceCtrlHandler\n")); + if ((ElfServiceStatusHandle = RegisterServiceCtrlHandler( + wname_Eventlogsvc, + ElfControlResponse + )) == (SERVICE_STATUS_HANDLE) NULL) { + + Win32Error = GetLastError(); + + // + // If we got an error, we need to set status to uninstalled, and end the + // thread. + // + + ElfDbgPrintNC(("[ELF] RegisterServiceCtrlHandler = %u\n",Win32Error)); + goto cleanupandexit; + } + + // Initialize all the status fields so that subsequent calls to + // SetServiceStatus only need to update fields that changed. + // + + // + // Notify the Service Controller for the first time that we are alive + // and is in a start pending state + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + + // + // Get the localized title for message box popups. + // + ElfInitMessageBoxTitle(); + + // + // Set up the object that describes the root node for the eventlog service + // + + RtlInitUnicodeString(&RootRegistryNode, REG_EVENTLOG_NODE_PATH); + InitializeObjectAttributes(&ObjectAttributes, + &RootRegistryNode, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // + // If this fails, we'll just use the defaults + // + + NtOpenKey(&hEventLogNode, KEY_READ | KEY_NOTIFY, &ObjectAttributes); + + // + // See if there's a debug key + // + + RtlInitUnicodeString(&ValueName, VALUE_DEBUG); + + NtQueryValueKey(hEventLogNode, &ValueName, + KeyValueFullInformation, ValueBuffer, + ELF_MAX_REG_KEY_INFO_SIZE, & ElfDebug); + + // + // Initialize a critical section for use when adding or removing + // LogFiles or LogModules. This must be done before we process any + // file information. + // + + Status = RtlInitializeCriticalSection( + &LogFileCritSec + ); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(( "ELF log file crit sec init failed: %X\n", Status )); + goto cleanupandexit; + + } + Status = RtlInitializeCriticalSection( + &LogModuleCritSec + ); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(( "ELF log file crit sec init failed: %X\n", Status )); + goto cleanupandexit; + + } + EventFlags |= ELF_INIT_LOGFILE_CRIT_SEC; + + Status = RtlInitializeCriticalSection( + &QueuedEventCritSec + ); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(( "ELF queued event crit sec init failed: %X\n", Status )); + goto cleanupandexit; + + } + + EventFlags |= ELF_INIT_QUEUED_EVENT_CRIT_SEC; + + Status = RtlInitializeCriticalSection( + &QueuedMessageCritSec + ); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(( "ELF queued message crit sec init failed: %X\n", Status )); + goto cleanupandexit; + + } + + EventFlags |= ELF_INIT_QUEUED_MESSAGE_CRIT_SEC; + + // + // Initialize global anonymous logon sid for use in log ACL's. + // + + Status = RtlAllocateAndInitializeSid( + &NtAuthority, + 1, + SECURITY_ANONYMOUS_LOGON_RID, + 0, 0, 0, 0, 0, 0, 0, + &AnonymousLogonSid); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(("ELF anonymous log sid creation failed: %X\n", + Status )); + goto cleanupandexit; + } + + // + // Set up the data structures for the Logfiles and Modules. + // + + Status = ElfSetUpConfigDataStructs (); + + if ( !NT_SUCCESS(Status) ) { + goto cleanupandexit; + } + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + + // + // Initialize a critical section for use when adding or removing + // context-handles (LogHandles). + // + + Status = RtlInitializeCriticalSection( + &LogHandleCritSec + ); + + if ( !NT_SUCCESS(Status) ) { + ElfDbgPrintNC(( "ELF log handle crit sec init failed: %X\n", Status )); + goto cleanupandexit; + + } + EventFlags |= ELF_INIT_LOGHANDLE_CRIT_SEC; + + // + // Initialize the context handle (log handle) list. + // + + InitializeListHead( &LogHandleListHead ); + + // + // Initialize the Global Resource. + // + + RtlInitializeResource ( &GlobalElfResource ); + EventFlags |= ELF_INIT_GLOBAL_RESOURCE; + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + + // Create a thread for watching the LPC port. + // + + if (!StartLPCThread ()) { + Status = STATUS_UNSUCCESSFUL; + goto cleanupandexit; + } + EventFlags |= ELF_STARTED_LPC_THREAD; + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + +#ifdef _CAIRO_ + // + // The eventlog service links to ALERTSYS.DLL by hand (eventlog.c) after + // eventlog initialization, since this dll's initialization code requires + // a running eventlog service. + // + // By no means, fail to start this service if something fails here. + // It just won't be possible to raise NT events as Cairo alerts. + // + // BUGBUG : Should probably at least log an error. + // Should the service state be STARTING while this + // initialization is in progress? + // + + if ((ghAlertSysDll = LoadLibrary(L"ALERTSYS.DLL")) != NULL) + { + // + // Get ReportAlert API address. + // + + if ((gpfReportAlert = (PREPORTALERT)GetProcAddress( + (HMODULE)ghAlertSysDll, + "ReportAlert")) == NULL) + { + FreeLibrary(ghAlertSysDll); + ghAlertSysDll = NULL; + ElfDbgPrintNC(( + "[ELF] ReportAlert GetProAddress failed, WIN32 error(%x)\n", + GetLastError())); + } + } + else + { + ElfDbgPrintNC(( + "[ELF] LoadLibrary of ALERTSYS.DLL failed, WIN32 error(%x)\n", + GetLastError())); + } + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + +#endif // _CAIRO_ + + // Create a thread for watching for changes in the registry. + // + + if (!ElfStartRegistryMonitor ()) { + Status = STATUS_UNSUCCESSFUL; + goto cleanupandexit; + } + EventFlags |= ELF_STARTED_REGISTRY_MONITOR; + + // + // Write out an event that says we started + // + + ElfpCreateElfEvent(EVENT_EventlogStarted, + EVENTLOG_INFORMATION_TYPE, + 0, // EventCategory + 0, // NumberOfStrings + NULL, // Strings + NULL, // Data + 0, // Datalength + 0 // flags + ); + + // + // Write out any events that were queued up during initialization + // + + FlushRequest.Command = ELF_COMMAND_WRITE_QUEUED; + + ElfPerformRequest(&FlushRequest); + + // + // Tell service controller of that we are making progress + // + // *** UPDATE STATUS *** + ElfStatusUpdate(STARTING); + + // + // Finish setting up the RPC server + // + // NOTE: Now all RPC servers in services.exe share the same pipe name. + // However, in order to support communication with version 1.0 of WinNt, + // it is necessary for the Client Pipe name to remain the same as + // it was in version 1.0. Mapping to the new name is performed in + // the Named Pipe File System code. + // + Status = ElfGlobalData->StartRpcServer( + ElfGlobalData->SvcsRpcPipeName, + eventlog_ServerIfHandle); + + if (Status != NO_ERROR) { + ElfDbgPrint(("[ELF]StartRpcServer Failed %d\n",Status)); + goto cleanupandexit; + } + + // + // Tell service controller of that we are making progress + // + + if (ElfStatusUpdate(RUNNING) == RUNNING) { + ElfDbgPrint(("[ELF] Service Started Successfully\n")); + } + + EventFlags |= ELF_STARTED_RPC_SERVER; + + if (GetElState() == RUNNING) { + ElfDbgPrint(("[ELF] Service Running - main thread is returning\n")); + return; + } + +// +// Come here if there is cleanup necessary. +// + +cleanupandexit: + + ElfDbgPrint(("[ELF] Leaving the service\n")); + + if (!Win32Error) { + Win32Error = RtlNtStatusToDosError(Status); + } + ElfBeginForcedShutdown(PENDING,Win32Error,Status); + + // + // If the registry monitor has been initialized, then + // let it do the shutdown cleanup. All we need to do + // here is wake it up. + // Otherwise, this thread will do the cleanup. + // + if (EventFlags & ELF_STARTED_REGISTRY_MONITOR) { + StopRegistryMonitor(); + } + else { + ElfpCleanUp(EventFlags); + // + // We should actually return here so that the DLL gets unloaded. + // However, RPC has a problem in that it might still call our + // context rundown routine even though we unregistered our interface. + // So we exit thread instead. This keeps our Dll loaded. + // + ExitThread(0); + } + return; +} + +VOID +ElfInitMessageBoxTitle( + VOID + ) + +/*++ + +Routine Description: + + Obtains the title text for the message box used to display messages. + If the title is successfully obtained from the message file, then + that title is pointed to by GlobalAllocatedMsgTitle and + GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle + left pointing to the DefaultMessageBoxTitle. + + NOTE: If successful, a buffer is allocated by this function. The + pointer stored in GlobalAllocatedMsgTitle and it should be freed when + done with this buffer. + +Arguments: + +Return Value: + + none + +--*/ +{ + LPVOID hModule; + DWORD msgSize; + DWORD status=NO_ERROR; + + GlobalAllocatedMsgTitle = NULL; + + hModule = LoadLibrary( L"netevent.dll"); + if ( hModule == NULL) { + status = GetLastError(); + ElfDbgPrint(("LoadLibrary() fails with winError = %d\n", GetLastError())); + return; + } + msgSize = FormatMessageW( + FORMAT_MESSAGE_FROM_HMODULE | // dwFlags + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + hModule, + TITLE_EventlogMessageBox, // MessageId + 0, // dwLanguageId + (LPWSTR)&GlobalAllocatedMsgTitle, // lpBuffer + 0, // nSize + NULL); + + if (msgSize == 0) { + status = GetLastError(); + ElfDbgPrint((ERROR,"Could not find MessageBox title in a message file %d\n", + status)); + } + else { + GlobalMessageBoxTitle = GlobalAllocatedMsgTitle; + } + + FreeLibrary(hModule); + return; +} + + + |