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.
1255 lines
41 KiB
1255 lines
41 KiB
// ****************************************************************************
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Module Name:
|
|
//
|
|
// EventCreate.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This modules implements creation of event in the user
|
|
// specified log / application
|
|
//
|
|
// Syntax:
|
|
// ------
|
|
// EventCreate [-s server [-u username [-p password]]]
|
|
// [-log name] [-source name] -id eventid -description description -type eventtype
|
|
//
|
|
// Author:
|
|
//
|
|
// Sunil G.V.N. Murali ([email protected]) 24-Sep-2000
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Sunil G.V.N. Murali ([email protected]) 24-Sep-2000 : Created It.
|
|
//
|
|
// ****************************************************************************
|
|
|
|
#include "pch.h"
|
|
#include "EvcrtMsg.h"
|
|
#include "EventCreate.h"
|
|
|
|
//
|
|
// constants / defines / enumerators
|
|
//
|
|
#define FULL_SUCCESS 0
|
|
#define PARTIALLY_SUCCESS 1
|
|
#define COMPLETELY_FAILED 1
|
|
|
|
#define MAX_KEY_LENGTH 256
|
|
#define EVENT_LOG_NAMES_LOCATION L"SYSTEM\\CurrentControlSet\\Services\\EventLog"
|
|
|
|
// constants
|
|
// NOTE: though the values in these variables are constants across
|
|
// the tool, we are not marking them as contants on purpose.
|
|
WCHAR g_wszDefaultLog[] = L"Application";
|
|
WCHAR g_wszDefaultSource[] = L"EventCreate";
|
|
|
|
typedef struct
|
|
{
|
|
// original buffers for command-line arguments
|
|
BOOL bUsage;
|
|
LPWSTR pwszServer;
|
|
LPWSTR pwszUserName;
|
|
LPWSTR pwszPassword;
|
|
LPWSTR pwszLogName;
|
|
LPWSTR pwszSource;
|
|
LPWSTR pwszType;
|
|
LPWSTR pwszDescription;
|
|
DWORD dwEventID;
|
|
|
|
// translations
|
|
WORD wEventType;
|
|
BOOL bCloseConnection;
|
|
DWORD dwUserNameLength;
|
|
DWORD dwPasswordLength;
|
|
|
|
} TEVENTCREATE_PARAMS, *PTEVENTCREATE_PARAMS;
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
BOOL Usage();
|
|
BOOL CreateLogEvent( PTEVENTCREATE_PARAMS pParams );
|
|
BOOL CheckExistence( PTEVENTCREATE_PARAMS pParams );
|
|
|
|
BOOL UnInitializeGlobals( PTEVENTCREATE_PARAMS pParams );
|
|
BOOL AddEventSource( HKEY hLogsKey, LPCWSTR pwszSource );
|
|
BOOL ProcessOptions( LONG argc,
|
|
LPCWSTR argv[],
|
|
PTEVENTCREATE_PARAMS pParams, PBOOL pbNeedPwd );
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This the entry point to this utility.
|
|
//
|
|
// Arguments:
|
|
// [ in ] argc : argument(s) count specified at the command prompt
|
|
// [ in ] argv : argument(s) specified at the command prompt
|
|
//
|
|
// Return Value:
|
|
// The below are actually not return values but are the exit values
|
|
// returned to the OS by this application
|
|
// 0 : utility successfully created the events
|
|
// 255 : utility completely failed in creating events
|
|
// 128 : utility has partially successfull in creating events
|
|
// ***************************************************************************
|
|
DWORD _cdecl wmain( LONG argc, LPCWSTR argv[] )
|
|
{
|
|
// local variables
|
|
BOOL bResult = FALSE;
|
|
BOOL bNeedPassword = FALSE;
|
|
TEVENTCREATE_PARAMS params;
|
|
|
|
// init the structure to zero
|
|
SecureZeroMemory( ¶ms, sizeof( TEVENTCREATE_PARAMS ) );
|
|
|
|
// process the command-line options
|
|
bResult = ProcessOptions( argc, argv, ¶ms, &bNeedPassword );
|
|
|
|
// check the result of the parsing
|
|
if ( bResult == FALSE )
|
|
{
|
|
// invalid syntax
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
|
|
// exit from program
|
|
UnInitializeGlobals( ¶ms );
|
|
return 1;
|
|
}
|
|
|
|
// check whether usage has to be displayed or not
|
|
if ( params.bUsage == TRUE )
|
|
{
|
|
// show the usage of the utility
|
|
Usage();
|
|
|
|
// finally exit from the program
|
|
UnInitializeGlobals( ¶ms );
|
|
return 0;
|
|
}
|
|
|
|
// ******
|
|
// actual creation of events in respective log files will start from here
|
|
|
|
// try establishing connection to the required terminal
|
|
params.bCloseConnection = TRUE;
|
|
bResult = EstablishConnection( params.pwszServer,
|
|
params.pwszUserName, params.dwUserNameLength,
|
|
params.pwszPassword, params.dwPasswordLength, bNeedPassword );
|
|
if ( bResult == FALSE )
|
|
{
|
|
//
|
|
// failed in establishing n/w connection
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
|
|
// try with next server
|
|
UnInitializeGlobals( ¶ms );
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// though the connection is successfull, some conflict might have occured
|
|
switch( GetLastError() )
|
|
{
|
|
case I_NO_CLOSE_CONNECTION:
|
|
params.bCloseConnection = FALSE;
|
|
break;
|
|
|
|
case E_LOCAL_CREDENTIALS:
|
|
case ERROR_SESSION_CREDENTIAL_CONFLICT:
|
|
{
|
|
params.bCloseConnection = FALSE;
|
|
ShowLastErrorEx( stderr, SLE_TYPE_WARNING | SLE_INTERNAL );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// report the log message
|
|
bResult = CreateLogEvent( ¶ms );
|
|
if ( bResult == TRUE )
|
|
{
|
|
// both log and source would have specified
|
|
if ( params.pwszSource != NULL && params.pwszLogName != NULL )
|
|
{
|
|
ShowMessage( stdout, L"\n" );
|
|
ShowMessageEx( stdout, 2, TRUE, MSG_SUCCESS,
|
|
params.pwszType, params.pwszLogName, params.pwszSource );
|
|
}
|
|
|
|
// only source name would have specified
|
|
else if ( params.pwszSource != NULL )
|
|
{
|
|
ShowMessage( stdout, L"\n" );
|
|
ShowMessageEx( stdout, 1, TRUE,
|
|
MSG_SUCCESS_SOURCE, params.pwszType, params.pwszSource);
|
|
}
|
|
|
|
// only log name would have specified
|
|
else if ( params.pwszLogName != NULL )
|
|
{
|
|
ShowMessage( stdout, L"\n" );
|
|
ShowMessageEx( stdout, 1, TRUE,
|
|
MSG_SUCCESS_LOG, params.pwszType, params.pwszLogName);
|
|
}
|
|
|
|
// nothing is specified -- can never be happened
|
|
else
|
|
{
|
|
SetLastError( ERROR_PROCESS_ABORTED );
|
|
ShowLastError( stderr );
|
|
UnInitializeGlobals( ¶ms );
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// display the message depending on the mode of conncetivity
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
}
|
|
|
|
// exit
|
|
UnInitializeGlobals( ¶ms );
|
|
return ((bResult == TRUE) ? 0 : 1);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateLogEvent( PTEVENTCREATE_PARAMS pParams )
|
|
/*++
|
|
Routine Description:
|
|
This function connects to the specified server's event log (or) source
|
|
and appropriately creates the needed event in it.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
TRUE : if the event creation is successful
|
|
FALSE : if failed in creating the event
|
|
--*/
|
|
{
|
|
// local variables
|
|
BOOL bReturn = 0; // return value
|
|
HANDLE hEventLog = NULL; // points to the event log
|
|
LPCWSTR pwszDescriptions[ 1 ] = { NULL }; // building descriptions
|
|
HANDLE hToken = NULL; // Handle to the process token.
|
|
PTOKEN_USER ptiUserName = NULL; // Structure to username info.
|
|
DWORD dwUserLen = 0; // Buffer length of username SID.
|
|
|
|
// check the input
|
|
if ( pParams == NULL )
|
|
{
|
|
SetLastError( ERROR_PROCESS_ABORTED );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// start the process
|
|
|
|
// extract the SID for the current logged on user -- in case of local machine
|
|
// and SID for user specified with -u at the command prompt -- if not specified
|
|
// get the current logged user SID only
|
|
|
|
|
|
// check whether the log / source exists in the registry or not
|
|
if ( CheckExistence( pParams ) == FALSE )
|
|
{
|
|
return FALSE; // return failure
|
|
}
|
|
|
|
// open the appropriate event log using the specified 'source' or 'log file'
|
|
// and check the result of the operation
|
|
// Note: At one time, we will make use of log name (or) source but not both
|
|
if ( pParams->pwszSource != NULL )
|
|
{
|
|
// open log using source name
|
|
hEventLog = RegisterEventSource( pParams->pwszServer, pParams->pwszSource );
|
|
}
|
|
else if ( pParams->pwszLogName != NULL )
|
|
{
|
|
// open log
|
|
hEventLog = OpenEventLog( pParams->pwszServer, pParams->pwszLogName );
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_PROCESS_ABORTED );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// check the log open/register result
|
|
if ( hEventLog == NULL )
|
|
{
|
|
// opening/registering is failed
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// Set boolean flag to FALSE.
|
|
bReturn = FALSE;
|
|
// Get handle to current process token.
|
|
bReturn = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken );
|
|
// Is 'OpenPrcessToken' successful.
|
|
if ( TRUE == bReturn )
|
|
{
|
|
bReturn = FALSE;
|
|
// Get buffer length, required to store the owner SID.
|
|
GetTokenInformation( hToken, TokenUser, NULL, 0, &dwUserLen );
|
|
// 'GetTokenInformation' fails because of insufficient buffer space.
|
|
if( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
|
|
{ // Assign memory and check whether it's allocated.
|
|
ptiUserName = (PTOKEN_USER) AllocateMemory( dwUserLen + 1 );
|
|
if( NULL != ptiUserName )
|
|
{ // Memory allocation is successful, get current process owber SID.
|
|
bReturn = GetTokenInformation( hToken, TokenUser, ptiUserName, dwUserLen, &dwUserLen );
|
|
if( TRUE == bReturn )
|
|
{ // Obtained the owner SID of current process.
|
|
// report event
|
|
pwszDescriptions[ 0 ] = pParams->pwszDescription;
|
|
bReturn = ReportEvent( hEventLog, pParams->wEventType, 0,
|
|
pParams->dwEventID, ptiUserName->User.Sid, 1, 0, pwszDescriptions, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// check the result, save any error occured.
|
|
if ( bReturn == FALSE )
|
|
{
|
|
// save the error info
|
|
SaveLastError();
|
|
}
|
|
|
|
// Free handle to token and token info structure.
|
|
if( NULL != hToken )
|
|
{
|
|
CloseHandle( hToken );
|
|
}
|
|
if( NULL != ptiUserName )
|
|
{
|
|
FreeMemory( &ptiUserName );
|
|
}
|
|
|
|
// close the event source
|
|
if ( pParams->pwszSource != NULL )
|
|
{
|
|
DeregisterEventSource( hEventLog );
|
|
}
|
|
else
|
|
{
|
|
CloseEventLog( hEventLog );
|
|
}
|
|
|
|
// return the result
|
|
return bReturn;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function checks wether the log name or source name specified
|
|
// actually exists in the registry
|
|
//
|
|
// Arguments:
|
|
// [ in ] szServer - server name
|
|
// [ in ] szLog - log name
|
|
// [ in ] szSource - source name
|
|
//
|
|
// Return Value:
|
|
// TRUE : If log / source exists in the registry
|
|
// FALSE : if failed find the match
|
|
// ***************************************************************************
|
|
BOOL CheckExistence( PTEVENTCREATE_PARAMS pParams )
|
|
{
|
|
// local variables
|
|
DWORD dwSize = 0;
|
|
LONG lResult = 0L;
|
|
LPCWSTR pwsz = NULL;
|
|
BOOL bCustom = FALSE;
|
|
DWORD dwLogsIndex = 0;
|
|
DWORD dwSourcesIndex = 0;
|
|
BOOL bFoundMatch = FALSE;
|
|
BOOL bDuplicating = FALSE;
|
|
BOOL bErrorOccurred = FALSE;
|
|
BOOL bLog = FALSE, bLogMatched = FALSE;
|
|
BOOL bSource = FALSE, bSourceMatched = FALSE;
|
|
|
|
HKEY hKey = NULL;
|
|
HKEY hLogsKey = NULL;
|
|
HKEY hSourcesKey = NULL;
|
|
|
|
FILETIME ftLastWriteTime; // variable that will hold the last write info
|
|
|
|
WCHAR wszRLog[ MAX_KEY_LENGTH ] = L"\0";
|
|
WCHAR wszRSource[ MAX_KEY_LENGTH ] = L"\0";
|
|
|
|
//
|
|
// actual control flow starts
|
|
//
|
|
|
|
// check the input
|
|
if ( pParams == NULL )
|
|
{
|
|
SetLastError( ERROR_PROCESS_ABORTED );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare the server name into UNC format
|
|
pwsz = pParams->pwszServer;
|
|
if ( pwsz != NULL && IsUNCFormat( pwsz ) == FALSE )
|
|
{
|
|
// format the server name in UNC format
|
|
// NOTE: make use of the failure buffer to get the server name
|
|
// in UNC format
|
|
if ( SetReason2( 2, L"\\\\%s", pwsz ) == FALSE )
|
|
{
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
pwsz = GetReason();
|
|
}
|
|
|
|
// Connect to the registry
|
|
lResult = RegConnectRegistry( pwsz, HKEY_LOCAL_MACHINE, &hKey );
|
|
if ( lResult != ERROR_SUCCESS)
|
|
{
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// open the "EventLogs" registry key for enumerating its sub-keys (which are log names)
|
|
lResult = RegOpenKeyEx( hKey, EVENT_LOG_NAMES_LOCATION, 0, KEY_READ, &hLogsKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
switch( lResult )
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
SetLastError( ERROR_REGISTRY_CORRUPT );
|
|
break;
|
|
|
|
default:
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
break;
|
|
}
|
|
|
|
// close the key and return
|
|
SaveLastError();
|
|
RegCloseKey( hKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// start enumerating the logs present
|
|
dwLogsIndex = 0; // initialize the logs index
|
|
bFoundMatch = FALSE; // assume neither log (or) source doesn't match
|
|
bErrorOccurred = FALSE; // assume error is not occured
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
bLogMatched = FALSE;
|
|
bSourceMatched = FALSE;
|
|
bDuplicating = FALSE;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Logic:-
|
|
// 1. determine whether user has supplied the log name or not
|
|
// 2. determine whether user has supplied the source name or not
|
|
// 3. Start enumerating all the logs present in the system
|
|
// 4. check whether log is supplied or not, if yes, check whether
|
|
// the current log matches with user supplied one.
|
|
// 5. check whether source is supplied or not, if yes, enumerate the
|
|
// sources available under the current log
|
|
|
|
// determine whether searching has to be done of LOG (or) SOURCE
|
|
bLog = (pParams->pwszLogName != NULL) ? TRUE : FALSE; // #1
|
|
bSource = (pParams->pwszSource != NULL) ? TRUE : FALSE; // #2
|
|
|
|
// initiate the enumeration of log present in the system -- #3
|
|
SecureZeroMemory( wszRLog, MAX_KEY_LENGTH * sizeof( WCHAR ) );
|
|
lResult = RegEnumKeyEx( hLogsKey, 0, wszRLog,
|
|
&dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
|
|
// traverse thru the sub-keys until there are no more items -- #3
|
|
do
|
|
{
|
|
// check the result
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// if log name is passed, compare the current key value
|
|
// compare the log name with the current key -- #4
|
|
if ( bLog == TRUE &&
|
|
StringCompare( pParams->pwszLogName, wszRLog, TRUE, 0 ) == 0 )
|
|
{
|
|
bLogMatched = TRUE;
|
|
}
|
|
|
|
// if source name is passed ... -- #5
|
|
if ( bSource == TRUE && bSourceMatched == FALSE )
|
|
{
|
|
// open the current log name to enumerate the sources under this log
|
|
lResult = RegOpenKeyEx( hLogsKey, wszRLog, 0, KEY_READ, &hSourcesKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// start enumerating the sources present
|
|
dwSourcesIndex = 0; // initialize the sources index
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
SecureZeroMemory( wszRSource, dwSize * sizeof( WCHAR ) );
|
|
lResult = RegEnumKeyEx( hSourcesKey, 0,
|
|
wszRSource, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
|
|
// traverse thru the sub-keys until there are no more items
|
|
do
|
|
{
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error and break from the loop
|
|
bErrorOccurred = TRUE;
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
break;
|
|
}
|
|
|
|
// check whether this key matches with the required source or not
|
|
if ( StringCompare( pParams->pwszSource, wszRSource, TRUE, 0 ) == 0 )
|
|
{
|
|
// source matched
|
|
bSourceMatched = TRUE;
|
|
break; // break from the loop
|
|
}
|
|
|
|
// update the sources index and fetch the next source key
|
|
dwSourcesIndex += 1;
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
SecureZeroMemory( wszRSource, dwSize * sizeof( WCHAR ) );
|
|
lResult = RegEnumKeyEx( hSourcesKey, dwSourcesIndex,
|
|
wszRSource, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
} while( lResult != ERROR_NO_MORE_ITEMS );
|
|
|
|
// close the sources registry key
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL; // clear the key value
|
|
|
|
// check how the loop ended
|
|
// 1. Source might have found
|
|
// Action:- we found required key .. exit from the main loop
|
|
// 2. Error might have occured
|
|
// Action:- ignore the error and continue fetching other
|
|
// log's sources
|
|
// 3. End of sources reached in this log
|
|
// Action:- check if log name is supplied or not.
|
|
// if log specified, then source if not found, break
|
|
// for cases 2 & 3, clear the contents of lResult for smooth processing
|
|
|
|
// Case #2 & #3
|
|
lResult = 0; // we are not much bothered abt the errors
|
|
bErrorOccurred = FALSE; // occured while traversing thru the source under logs
|
|
|
|
// Case #1
|
|
if ( bSourceMatched == TRUE )
|
|
{
|
|
// check whether log is specified or not
|
|
// if log is specified, it should have matched .. otherwise
|
|
// error ... because duplicate source should not be created
|
|
if ( bLog == FALSE ||
|
|
( bLog == TRUE &&
|
|
bLogMatched == TRUE &&
|
|
StringCompare(pParams->pwszLogName, wszRLog, TRUE, 0) == 0 ) )
|
|
{
|
|
// no problem ...
|
|
bFoundMatch = TRUE;
|
|
|
|
//
|
|
// determine whether this is custom created source or not
|
|
|
|
// mark this as custom source
|
|
bCustom = FALSE;
|
|
|
|
// open the source registry key
|
|
// NOTE: make use of the failure buffer as temp buffer for
|
|
// formatting
|
|
if ( SetReason2( 3,
|
|
L"%s\\%s\\%s",
|
|
EVENT_LOG_NAMES_LOCATION,
|
|
wszRLog, wszRSource ) == FALSE )
|
|
{
|
|
SaveLastError();
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
pwsz = GetReason();
|
|
lResult = RegOpenKeyEx( hKey, pwsz,
|
|
0, KEY_QUERY_VALUE, &hSourcesKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// now query for the value
|
|
lResult = RegQueryValueEx( hSourcesKey,
|
|
L"CustomSource", NULL, NULL, NULL, NULL );
|
|
if ( lResult != ERROR_SUCCESS &&
|
|
lResult != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
RegCloseKey( hSourcesKey );
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// close the souces key
|
|
RegCloseKey( hSourcesKey );
|
|
|
|
// mark this as custom source
|
|
if ( lResult == ERROR_SUCCESS )
|
|
{
|
|
bCustom = TRUE;
|
|
}
|
|
|
|
// break from the loop
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// this should not be the case .. sources should not be duplicated
|
|
SetReason2( 1, ERROR_SOURCE_DUPLICATING, wszRLog );
|
|
bDuplicating = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if ( bLogMatched == TRUE && bSource == FALSE )
|
|
{
|
|
// mark this as a custom event source
|
|
bCustom = TRUE;
|
|
|
|
// ...
|
|
bFoundMatch = TRUE;
|
|
break;
|
|
}
|
|
else if ( bLogMatched == TRUE && bDuplicating == TRUE )
|
|
{
|
|
bErrorOccurred = TRUE;
|
|
break;
|
|
}
|
|
|
|
// update the sources index and fetch the next log key
|
|
dwLogsIndex += 1;
|
|
dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
|
|
SecureZeroMemory( wszRLog, dwSize * sizeof( WCHAR ) );
|
|
lResult = RegEnumKeyEx( hLogsKey, dwLogsIndex,
|
|
wszRLog, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
|
|
} while( lResult != ERROR_NO_MORE_ITEMS );
|
|
|
|
// close the logs registry key
|
|
RegCloseKey( hLogsKey );
|
|
hLogsKey = NULL;
|
|
|
|
// check whether any error has occured or not in doing above tasks
|
|
if ( bErrorOccurred == TRUE )
|
|
{
|
|
// close the still opened registry keys
|
|
RegCloseKey( hKey );
|
|
hKey = NULL;
|
|
|
|
// return failure
|
|
return FALSE;
|
|
}
|
|
|
|
// now check whether location for creating the event is found or not
|
|
// if not, check for the possibilities to create the source at appropriate location
|
|
// NOTE:-
|
|
// we won't create the logs. also to create the source, user needs to specify
|
|
// the log name in which this source needs to be created.
|
|
if ( bFoundMatch == FALSE )
|
|
{
|
|
if ( bLog == TRUE && bLogMatched == FALSE )
|
|
{
|
|
// log itself was not found ... error message
|
|
SetReason2( 1, ERROR_LOG_NOTEXISTS, pParams->pwszLogName );
|
|
}
|
|
else if ( bLog == TRUE && bSource == TRUE &&
|
|
bLogMatched == TRUE && bSourceMatched == FALSE )
|
|
{
|
|
//
|
|
// log name and source both were supplied but only log was found
|
|
// so create the source in it
|
|
|
|
// open the "EventLogs\{logname}" registry key for creating new source
|
|
// NOTE: we will make use of failure buffer to do the formatting
|
|
if ( SetReason2( 2, L"%s\\%s",
|
|
EVENT_LOG_NAMES_LOCATION, pParams->pwszLogName ) == FALSE )
|
|
{
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
pwsz = GetReason();
|
|
lResult = RegOpenKeyEx( hKey, pwsz, 0, KEY_WRITE, &hLogsKey );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
switch( lResult )
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
SetLastError( ERROR_REGISTRY_CORRUPT );
|
|
break;
|
|
|
|
default:
|
|
// save the error information and return FAILURE
|
|
SetLastError( lResult );
|
|
break;
|
|
}
|
|
|
|
// close the key and return
|
|
SaveLastError();
|
|
RegCloseKey( hKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// now create the subkey with the source name given
|
|
if ( AddEventSource( hLogsKey, pParams->pwszSource ) == FALSE )
|
|
{
|
|
RegCloseKey( hKey );
|
|
RegCloseKey( hLogsKey );
|
|
return FALSE;
|
|
}
|
|
|
|
// creation of new source is successfull
|
|
bFoundMatch = TRUE;
|
|
RegCloseKey( hSourcesKey );
|
|
RegCloseKey( hLogsKey );
|
|
|
|
// mark this as a custom event source
|
|
bCustom = TRUE;
|
|
}
|
|
else if ( bLog == FALSE && bSource == TRUE && bSourceMatched == FALSE )
|
|
{
|
|
// else we need both log name and source in order to create the source
|
|
SetReason( ERROR_NEED_LOG_ALSO );
|
|
}
|
|
}
|
|
|
|
// check whether the source is custom create or pre-existing source
|
|
if ( bFoundMatch == TRUE && bCustom == FALSE )
|
|
{
|
|
// we wont create events in a non-custom source
|
|
SetReason( ERROR_NONCUSTOM_SOURCE );
|
|
return FALSE;
|
|
}
|
|
|
|
// close the currently open registry keys
|
|
RegCloseKey( hKey );
|
|
|
|
// return the result
|
|
return bFoundMatch;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Routine Description:
|
|
// This function adds a new source to under the specifie log
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
// TRUE : on success
|
|
// FALSE : on failure
|
|
// ***************************************************************************
|
|
BOOL AddEventSource( HKEY hLogsKey, LPCWSTR pwszSource )
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
DWORD dwData = 0;
|
|
DWORD dwLength = 0;
|
|
DWORD dwDisposition = 0;
|
|
HKEY hSourcesKey = NULL;
|
|
LPWSTR pwszBuffer = NULL;
|
|
|
|
// validate the inputs
|
|
if ( hLogsKey == NULL || pwszSource == NULL )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// set the name of the message file ( +2 == buffer )
|
|
dwLength = StringLength( L"%SystemRoot%\\System32\\EventCreate.exe", 0 ) + 2;
|
|
pwszBuffer = ( LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) );
|
|
if ( pwszBuffer == NULL )
|
|
{
|
|
// set the error and return
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// copy the required value into buffer
|
|
StringCopy( pwszBuffer, L"%SystemRoot%\\System32\\EventCreate.exe", dwLength );
|
|
|
|
// create the custom source
|
|
lResult = RegCreateKeyEx( hLogsKey, pwszSource, 0, L"",
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSourcesKey, &dwDisposition );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// free the allocated memory
|
|
FreeMemory( &pwszBuffer );
|
|
//return.
|
|
return FALSE;
|
|
}
|
|
|
|
// add the name to the EventMessageFile subkey.
|
|
lResult = RegSetValueEx( hSourcesKey, L"EventMessageFile",
|
|
0, REG_EXPAND_SZ, (LPBYTE) pwszBuffer, dwLength * sizeof( WCHAR ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
FreeMemory( &pwszBuffer );
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// set the supported event types in the TypesSupported subkey.
|
|
dwData = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
|
|
lResult = RegSetValueEx( hSourcesKey,
|
|
L"TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
FreeMemory( &pwszBuffer );
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// mark this source as custom created source
|
|
dwData = 1;
|
|
lResult = RegSetValueEx( hSourcesKey,
|
|
L"CustomSource", 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// save the error
|
|
SetLastError( lResult );
|
|
SaveLastError();
|
|
|
|
// release the memories allocated till this point
|
|
RegCloseKey( hSourcesKey );
|
|
hSourcesKey = NULL;
|
|
|
|
// free the allocated memory
|
|
FreeMemory( &pwszBuffer );
|
|
|
|
// return
|
|
return FALSE;
|
|
}
|
|
|
|
// close the key
|
|
RegCloseKey( hSourcesKey );
|
|
|
|
// free the allocated memory
|
|
FreeMemory( &pwszBuffer );
|
|
|
|
// return success
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ProcessOptions( LONG argc,
|
|
LPCWSTR argv[],
|
|
PTEVENTCREATE_PARAMS pParams, PBOOL pbNeedPwd )
|
|
/*++
|
|
Routine Description:
|
|
This function parses the options specified at the command prompt
|
|
|
|
Arguments:
|
|
[ in ] argc - count of elements in argv
|
|
[ in ] argv - command-line parameterd specified by the user
|
|
[ out ] pbNeedPwd - sets to TRUE if -s exists without -p in 'argv'
|
|
|
|
Return Value:
|
|
TRUE - the parsing is successful
|
|
FALSE - errors occured in parsing
|
|
--*/
|
|
{
|
|
// local variables
|
|
PTCMDPARSER2 pcmdOption = NULL;
|
|
TCMDPARSER2 cmdOptions[ MAX_OPTIONS ];
|
|
|
|
//
|
|
// prepare the command options
|
|
SecureZeroMemory( cmdOptions, sizeof( TCMDPARSER2 ) * MAX_OPTIONS );
|
|
|
|
// -?
|
|
pcmdOption = &cmdOptions[ OI_HELP ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_USAGE;
|
|
pcmdOption->dwType = CP_TYPE_BOOLEAN;
|
|
pcmdOption->pValue = &pParams->bUsage;
|
|
pcmdOption->pwszOptions = OPTION_HELP;
|
|
|
|
// -s
|
|
pcmdOption = &cmdOptions[ OI_SERVER ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_SERVER;
|
|
|
|
// -u
|
|
pcmdOption = &cmdOptions[ OI_USERNAME ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_USERNAME;
|
|
|
|
// -p
|
|
pcmdOption = &cmdOptions[ OI_PASSWORD ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_OPTIONAL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_PASSWORD;
|
|
|
|
// -log
|
|
pcmdOption = &cmdOptions[ OI_LOG ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_LOG;
|
|
|
|
// -type
|
|
pcmdOption = &cmdOptions[ OI_TYPE ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_MODE_VALUES | CP2_ALLOCMEMORY |
|
|
CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL | CP2_MANDATORY;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszValues = OVALUES_TYPE;
|
|
pcmdOption->pwszOptions = OPTION_TYPE;
|
|
|
|
// -source
|
|
pcmdOption = &cmdOptions[ OI_SOURCE ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_SOURCE;
|
|
|
|
// -id
|
|
pcmdOption = &cmdOptions[ OI_ID ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_MANDATORY;
|
|
pcmdOption->dwType = CP_TYPE_UNUMERIC;
|
|
pcmdOption->pValue = &pParams->dwEventID;
|
|
pcmdOption->pwszOptions = OPTION_ID;
|
|
|
|
// -description
|
|
pcmdOption = &cmdOptions[ OI_DESCRIPTION ];
|
|
StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
|
|
pcmdOption->dwCount = 1;
|
|
pcmdOption->dwFlags = CP2_MANDATORY | CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
|
|
pcmdOption->dwType = CP_TYPE_TEXT;
|
|
pcmdOption->pwszOptions = OPTION_DESCRIPTION;
|
|
|
|
//
|
|
// do the parsing
|
|
if ( DoParseParam2( argc, argv, -1, MAX_OPTIONS, cmdOptions, 0 ) == FALSE )
|
|
{
|
|
return FALSE; // invalid syntax
|
|
}
|
|
|
|
//
|
|
// now, check the mutually exclusive options
|
|
|
|
// check the usage option
|
|
if ( pParams->bUsage == TRUE )
|
|
{
|
|
if ( argc > 2 )
|
|
{
|
|
// no other options are accepted along with -? option
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason( ERROR_INVALID_USAGE_REQUEST );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// no need of furthur checking of the values
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// validate the range of the event id specified
|
|
if ( pParams->dwEventID < MSG_EVENTID_START ||
|
|
pParams->dwEventID >= MSG_EVENTID_END )
|
|
{
|
|
SetReason2( 2, ERROR_ID_OUTOFRANGE, MSG_EVENTID_START, MSG_EVENTID_END - 1 );
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
return FALSE;
|
|
}
|
|
|
|
// get the buffer pointers allocated by command line parser
|
|
pParams->pwszType = cmdOptions[ OI_TYPE ].pValue;
|
|
pParams->pwszLogName = cmdOptions[ OI_LOG ].pValue;
|
|
pParams->pwszSource = cmdOptions[ OI_SOURCE ].pValue;
|
|
pParams->pwszServer = cmdOptions[ OI_SERVER ].pValue;
|
|
pParams->pwszUserName = cmdOptions[ OI_USERNAME ].pValue;
|
|
pParams->pwszPassword = cmdOptions[ OI_PASSWORD ].pValue;
|
|
pParams->pwszDescription = cmdOptions[ OI_DESCRIPTION ].pValue;
|
|
|
|
// "-u" should not be specified without "-s"
|
|
if ( pParams->pwszUserName != NULL && pParams->pwszServer == NULL )
|
|
{
|
|
// invalid syntax
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason( ERROR_USERNAME_BUT_NOMACHINE );
|
|
return FALSE; // indicate failure
|
|
}
|
|
|
|
// "-p" should not be specified without "-u"
|
|
if ( pParams->pwszPassword != NULL && pParams->pwszUserName == NULL )
|
|
{
|
|
// invalid syntax
|
|
SetReason( ERROR_PASSWORD_BUT_NOUSERNAME );
|
|
return FALSE; // indicate failure
|
|
}
|
|
|
|
// check the remote connectivity information
|
|
if ( pParams->pwszServer != NULL )
|
|
{
|
|
//
|
|
// if -u is not specified, we need to allocate memory
|
|
// in order to be able to retrive the current user name
|
|
//
|
|
// case 1: -p is not at all specified
|
|
// as the value for this switch is optional, we have to rely
|
|
// on the dwActuals to determine whether the switch is specified or not
|
|
// in this case utility needs to try to connect first and if it fails
|
|
// then prompt for the password -- in fact, we need not check for this
|
|
// condition explicitly except for noting that we need to prompt for the
|
|
// password
|
|
//
|
|
// case 2: -p is specified
|
|
// but we need to check whether the value is specified or not
|
|
// in this case user wants the utility to prompt for the password
|
|
// before trying to connect
|
|
//
|
|
// case 3: -p * is specified
|
|
|
|
// user name
|
|
if ( pParams->pwszUserName == NULL )
|
|
{
|
|
pParams->dwUserNameLength = MAX_STRING_LENGTH;
|
|
pParams->pwszUserName = AllocateMemory( MAX_STRING_LENGTH * sizeof( WCHAR ) );
|
|
if ( pParams->pwszUserName == NULL )
|
|
{
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pParams->dwUserNameLength = StringLength( pParams->pwszUserName, 0 ) + 1;
|
|
}
|
|
|
|
// password
|
|
if ( pParams->pwszPassword == NULL )
|
|
{
|
|
*pbNeedPwd = TRUE;
|
|
pParams->dwPasswordLength = MAX_STRING_LENGTH;
|
|
pParams->pwszPassword = AllocateMemory( MAX_STRING_LENGTH * sizeof( WCHAR ) );
|
|
if ( pParams->pwszPassword == NULL )
|
|
{
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// case 1
|
|
if ( cmdOptions[ OI_PASSWORD ].dwActuals == 0 )
|
|
{
|
|
// we need not do anything special here
|
|
}
|
|
|
|
// case 2
|
|
else if ( cmdOptions[ OI_PASSWORD ].pValue == NULL )
|
|
{
|
|
StringCopy( pParams->pwszPassword, L"*", pParams->dwPasswordLength );
|
|
}
|
|
|
|
// case 3
|
|
else if ( StringCompareEx( pParams->pwszPassword, L"*", TRUE, 0 ) == 0 )
|
|
{
|
|
if ( ReallocateMemory( &pParams->pwszPassword,
|
|
MAX_STRING_LENGTH * sizeof( WCHAR ) ) == FALSE )
|
|
{
|
|
SaveLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
*pbNeedPwd = TRUE;
|
|
pParams->dwPasswordLength = MAX_STRING_LENGTH;
|
|
}
|
|
}
|
|
|
|
// either -source (or) -log must be specified ( both can also be specified )
|
|
if ( pParams->pwszSource == NULL && pParams->pwszLogName == NULL )
|
|
{
|
|
// if log name and application were not specified, we will set to defaults
|
|
pParams->pwszLogName = g_wszDefaultLog;
|
|
pParams->pwszSource = g_wszDefaultSource;
|
|
}
|
|
|
|
// if log is "application" and source is not specified, even then we
|
|
// will default the source to "EventCreate"
|
|
else if ( pParams->pwszSource == NULL &&
|
|
pParams->pwszLogName != NULL &&
|
|
StringCompareEx( pParams->pwszLogName, g_wszDefaultLog, TRUE, 0 ) == 0 )
|
|
{
|
|
pParams->pwszSource = g_wszDefaultSource;
|
|
}
|
|
|
|
// block the user to create events in security log
|
|
if ( pParams->pwszLogName != NULL &&
|
|
StringCompare( pParams->pwszLogName, L"security", TRUE, 0 ) == 0 )
|
|
{
|
|
SetReason( ERROR_LOG_CANNOT_BE_SECURITY );
|
|
return FALSE;
|
|
}
|
|
|
|
// determine the actual event type
|
|
if ( StringCompareEx( pParams->pwszType, LOGTYPE_ERROR, TRUE, 0 ) == 0 )
|
|
{
|
|
pParams->wEventType = EVENTLOG_ERROR_TYPE;
|
|
}
|
|
else if ( StringCompareEx( pParams->pwszType, LOGTYPE_SUCCESS, TRUE, 0 ) == 0 )
|
|
{
|
|
pParams->wEventType = EVENTLOG_SUCCESS;
|
|
}
|
|
else if ( StringCompareEx( pParams->pwszType, LOGTYPE_WARNING, TRUE, 0 ) == 0 )
|
|
{
|
|
pParams->wEventType = EVENTLOG_WARNING_TYPE;
|
|
}
|
|
else if ( StringCompareEx( pParams->pwszType, LOGTYPE_INFORMATION, TRUE, 0 ) == 0 )
|
|
{
|
|
pParams->wEventType = EVENTLOG_INFORMATION_TYPE;
|
|
}
|
|
|
|
// command-line parsing is successfull
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
Usage()
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
|
|
// start displaying the usage
|
|
for( dw = ID_USAGE_START; dw <= ID_USAGE_END; dw++ )
|
|
{
|
|
ShowMessage( stdout, GetResString( dw ) );
|
|
}
|
|
|
|
// return
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnInitializeGlobals( PTEVENTCREATE_PARAMS pParams )
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
// close the connection -- if needed
|
|
if ( pParams->bCloseConnection == TRUE )
|
|
{
|
|
CloseConnection( pParams->pwszServer );
|
|
}
|
|
|
|
//
|
|
// NOTE: FreeMemory will clear the contents of the
|
|
// password buffer -- since it will be duplicated
|
|
//
|
|
|
|
// release the memory allocated
|
|
FreeMemory( &pParams->pwszServer );
|
|
FreeMemory( &pParams->pwszUserName );
|
|
FreeMemory( &pParams->pwszPassword );
|
|
FreeMemory( &pParams->pwszType );
|
|
FreeMemory( &pParams->pwszDescription );
|
|
|
|
//
|
|
// check the pointers -- if it is not pointing to constant pointer
|
|
// then only release it
|
|
//
|
|
|
|
if ( pParams->pwszLogName != g_wszDefaultLog )
|
|
{
|
|
FreeMemory( &pParams->pwszLogName );
|
|
}
|
|
|
|
if ( pParams->pwszSource != g_wszDefaultSource )
|
|
{
|
|
FreeMemory( &pParams->pwszSource );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|