Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1295 lines
35 KiB

/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name :
odblogc.cpp
Abstract:
NCSA Logging Format implementation
Author:
Terence Kwan ( terryk ) 18-Sep-1996
Project:
IIS Logging 3.0
--*/
#include "precomp.hxx"
#include "odbcconn.hxx"
#include <ilogobj.hxx>
#include "odblogc.hxx"
#include <iadmw.h>
/************************************************************
* Symbolic Constants and Data
************************************************************/
# define MAX_SQL_FIELD_NAMES_LEN ( 400)
# define MAX_SQL_FIELD_VALUES_LEN ( 200)
# define MAX_SQL_IDENTIFIER_QUOTE_CHAR ( 50)
# define PSZ_UNKNOWN_FIELD_W _T("-")
# define PSZ_UNKNOWN_FIELD_A _T("-")
# define PSZ_GET_ERROR_FAILED_A _T("ODBC:GetLastError() Failed")
# define LEN_PSZ_GET_ERROR_FAILED_A sizeof(PSZ_GET_ERROR_FAILED_A)
# define PSZ_GET_ERROR_FAILED_W _T("ODBC:GetLastError() Failed")
# define LEN_PSZ_GET_ERROR_FAILED_W sizeof(PSZ_GET_ERROR_FAILED_W)
//
// The template of SQL command has 3 arguments.
// 1. table name
// 2. field names
// 3. field values
// 1,2 and 3 are obained during the first wsprintf
//
static const CHAR sg_rgchSqlInsertCmdTemplate[] =
_T("insert into %s ( %s) values ( %s)");
# define PSZ_SQL_INSERT_CMD_TEMPLATE ( sg_rgchSqlInsertCmdTemplate)
# define LEN_PSZ_SQL_INSERT_CMD_TEMPLATE \
( lstrlen( PSZ_SQL_INSERT_CMD_TEMPLATE))
//
// Leave %ws so that we can print the service and server name when this
// string is used to generate an SQL statement.
//
static const CHAR sg_rgchStdLogFieldValues[] =
_T(" ?, ?, ?, '%s', '%s', ?, ?, ?, ?, ?, ?, ?, ?, ?");
# define PSZ_INTERNET_STD_LOG_FORMAT_FIELD_NAMES ( sg_rgchStdLogFieldNames)
# define PSZ_INTERNET_STD_LOG_FORMAT_FIELD_VALUES ( sg_rgchStdLogFieldValues)
//
// AllFieldInfo()
// Defines all the fields required for SQL logging of the information
// to the database using ODBC interfaces.
// C arrays are numbered from offset 0.
// SQL columns are numbered from 1.
// field index values start from 0 and we adjust it when we talk of SQL col.
// FieldInfo( symbolic-name, field-name,
// field-index/column-number,
// field-C-type, field-Sql-type,
// field-precision, field-max-size, field-cb-value)
//
# define StringField( symName, fldName, fldIndex, prec) \
FieldInfo( symName, fldName, fldIndex, SQL_C_CHAR, SQL_CHAR, \
(prec), (prec), SQL_NTS)
# define NumericField( symName, fldName, fldIndex) \
FieldInfo( symName, fldName, fldIndex, SQL_C_LONG, SQL_INTEGER, \
0, sizeof( DWORD), 0)
# define TimeStampField( symName, fldName, fldIndex) \
FieldInfo( symName, fldName, fldIndex, SQL_C_TIMESTAMP, SQL_TIMESTAMP, \
0, sizeof( TIMESTAMP_STRUCT), 0)
//
// fields that have constant value. we are interested in names of such fields.
// they have negative field indexes.
// These fields need not be generated as parameter markers.
// ( Since they are invariants during lifetime of an INET_SQL_LOG oject)
// Hence the field values will go into the command generated.
// Left here as a documentation aid and field-generation purposes.
//
# define ConstantValueField( synName, fldName) \
FieldInfo( synName, fldName, -1, SQL_C_CHAR, SQL_CHAR, 0, 0, SQL_NTS)
//
// Ideally the "username" field should have MAX_USER_NAME_LEN as max size.
// However, Access 7.0 limits varchar() size to be 255 (8 bits) :-(
// So, we limit the size to be the least of the two ...
//
// FieldNames used are reserved. They are same as the names distributed
// in the template log file. Do not change them at free will.
//
//
# define AllFieldInfo() \
StringField( CLIENT_HOST, _T("ClientHost"), 0, 255) \
StringField( USER_NAME, _T("username"), 1, 255) \
TimeStampField( REQUEST_TIME, _T("LogTime"), 2) \
ConstantValueField( SERVICE_NAME, _T("service")) \
ConstantValueField( SERVER_NAME, _T("machine")) \
StringField( SERVER_IPADDR, _T("serverip"), 3, 50) \
NumericField( PROCESSING_TIME, _T("processingtime"), 4) \
NumericField( BYTES_RECVD, _T("bytesrecvd"), 5) \
NumericField( BYTES_SENT, _T("bytessent"), 6) \
NumericField( SERVICE_STATUS, _T("servicestatus"), 7) \
NumericField( WIN32_STATUS, _T("win32status"), 8) \
StringField( SERVICE_OPERATION, _T("operation"), 9, 255) \
StringField( SERVICE_TARGET, _T("target"), 10, 255) \
StringField( SERVICE_PARAMS, _T("parameters"), 11, 255) \
/************************************************************
* Type Definitions
************************************************************/
//
// Define the FieldInfo macro to generate a list of enumerations for
// the indexes to be used in the array of field parameters.
//
# define FieldInfo(symName, field, index, cType, sqlType, prec, maxSz, cbVal) \
i ## symName = (index),
enum LOGGING_VALID_COLUMNS {
// fields run from 0 through iMaxFields
AllFieldInfo()
iMaxFields
}; // enum LOGGING_VALID_COLUMNS
# undef FieldInfo
# define FieldInfo(symName, field, index, cType, sqlType, prec, maxSz, cbVal) \
fi ## symName,
enum LOGGING_FIELD_INDEXES {
fiMinFields = -1,
// fields run from 0 through fiMaxFields
AllFieldInfo()
fiMaxFields
}; // enum LOGGING_FIELD_INDEXES
# undef FieldInfo
struct FIELD_INFO {
int iParam;
CHAR * pszName;
SWORD paramType;
SWORD cType;
SWORD sqlType;
UDWORD cbColPrecision;
SWORD ibScale;
SDWORD cbMaxSize;
SDWORD cbValue;
}; // struct FIELD_INFO
//
// Define the FieldInfo macro to generate a list of data to be generated
// for entering the data values in an array for parameter information.
// Note the terminating ',' used here.
//
# define FieldInfo(symName, field, index, cType, sqlType, prec, maxSz, cbVal) \
{ ((index) + 1), field, SQL_PARAM_INPUT, cType, sqlType, \
( prec), 0, ( maxSz), ( cbVal) },
/*
The array of Fields: sg_rgFields contain the field information
for logging to SQL database for the log-record of
the services. The values are defined using the macros FieldInfo()
defined above.
If there is any need to add/delete/modify the parameters bound,
one should modify the above table "AllFieldInfo" macro.
*/
static FIELD_INFO sg_rgFields[] = {
AllFieldInfo()
//
// The above macro after expansion terminates with a comma.
// Add dummy entry to complete initialization of array.
//
{ 0, _T("dummy"), SQL_PARAM_INPUT, 0, 0, 0, 0, 0, 0}
};
# undef FieldInfo
//
// tick minute.
//
#define TICK_MINUTE (60 * 1000)
/************************************************************
* Functions
************************************************************/
BOOL
GenerateFieldNames(IN PODBC_CONNECTION poc,
OUT CHAR * pchFieldNames,
IN DWORD cchFieldNames);
inline BOOL
IsEmptyStr( IN LPCSTR psz)
{ return ( psz == NULL || *psz == _T('\0')); }
BOOL
CODBCLOG::PrepareStatement( VOID)
/*++
This command forms the template SQL command used for insertion
of log records. Then it prepares the SQL command( for later execution)
using ODBC_CONNECTION::PrepareStatement().
It should always be called after locking the INET_SQL_LOG object.
Arguments:
None
Returns:
TRUE on success and FALSE if there is any failure.
Note:
The template for insertion is:
insert into <table name> ( field names ...) values ( ?, ?, ...)
^^^^
Field values go here
Field names are generated on a per logging format basis.
--*/
{
BOOL fReturn = FALSE;
CHAR rgchFieldNames[ MAX_SQL_FIELD_NAMES_LEN];
CHAR rgchFieldValues[ MAX_SQL_FIELD_VALUES_LEN];
//
// Obtain field names and field values ( template) for various log formats.
// The order of field names should match the order of field values
// generated by FormatLogInformation() for the format specified.
//
rgchFieldNames[ 0] = rgchFieldValues[ 0] = _T('\0');
DWORD cchFields;
fReturn = GenerateFieldNames(m_poc,
rgchFieldNames,
MAX_SQL_FIELD_NAMES_LEN);
if ( !fReturn) {
//DBGPRINTF(( DBG_CONTEXT,
// " Unable to generate field names. Error = %d\n",
// GetLastError()));
//break;
return(fReturn);
}
cchFields = wsprintf( (CHAR *)rgchFieldValues,
PSZ_INTERNET_STD_LOG_FORMAT_FIELD_VALUES,
QueryServiceName(),
QueryServerName());
fReturn = (fReturn && (cchFields < MAX_SQL_FIELD_VALUES_LEN));
//DBG_ASSERT( cchFields < MAX_SQL_FIELD_VALUES_LEN);
fReturn = TRUE;
if ( fReturn) {
CHAR * pwszSqlCommand;
DWORD cchReqd;
//
// The required number of chars include sql insert template command
// and field names and table name.
//
cchReqd = (DWORD)( LEN_PSZ_SQL_INSERT_CMD_TEMPLATE +
strlen( m_rgchTableName) +
strlen( rgchFieldNames) +
strlen( rgchFieldValues) + 20);
pwszSqlCommand = ( CHAR *) LocalAlloc( LPTR, cchReqd * sizeof( CHAR));
m_poStmt = m_poc->AllocStatement();
fReturn = ( pwszSqlCommand != NULL ) && ( m_poStmt != NULL );
if ( fReturn ) {
DWORD cchUsed;
cchUsed = wsprintf( pwszSqlCommand,
PSZ_SQL_INSERT_CMD_TEMPLATE,
m_rgchTableName,
rgchFieldNames,
rgchFieldValues);
//DBG_ASSERT( cchUsed < cchReqd);
//IF_DEBUG(INETLOG) {
// DBGPRINTF( ( DBG_CONTEXT,
// " Sqlcommand generated is: %ws.\n",
// pwszSqlCommand));
//}
fReturn = ((cchUsed < cchReqd) &&
m_poStmt->PrepareStatement( pwszSqlCommand)
);
LocalFree( pwszSqlCommand); // free allocated memory
}
} // valid field names and filed values.
//IF_DEBUG( INETLOG) {
//
// DBGPRINTF( ( DBG_CONTEXT,
// "%s::PrepareStatement() returns %d.",
// QueryClassIdString(), fReturn));
//}
return ( fReturn);
} // INET_SQL_LOG::PrepareStatement()
BOOL
CODBCLOG::PrepareParameters( VOID)
/*++
This function creates an array of ODBC_PARAMETER objects used for binding
parameters to an already prepared statement. These ODBC_PARAMETER objects
are then used for insertion of data values into the table specified,
through ODBC.
This function should always be called after locking the object.
Arguments:
None
Returns:
TRUE on success and FALSE if there is any failure.
--*/
{
BOOL fReturn = FALSE;
PODBC_PARAMETER * prgParams = NULL;
DWORD cParams = 0;
DWORD nParamsSeen = 0;
DWORD i;
//DBG_ASSERT( m_poStmt != NULL && m_poStmt->IsValid() &&
// m_ppParams == NULL && m_cOdbcParams == 0);
//
// create sufficient space for iMaxFields pointers to ODBC objects.
//
prgParams = new PODBC_PARAMETER[ iMaxFields];
if ( prgParams != NULL) {
fReturn = TRUE; // Assume everything will go on fine.
cParams = iMaxFields;
//
// Create all the ODBC parameters.
// Walk through all field indexes and pick up the valid columns
//
for( nParamsSeen = 0, i =0; i < fiMaxFields; i++) {
if ( sg_rgFields[i].iParam > 0) {
WORD colNum = (WORD ) sg_rgFields[i].iParam;
prgParams[nParamsSeen] =
new ODBC_PARAMETER(colNum,
sg_rgFields[i].paramType,
sg_rgFields[i].cType,
sg_rgFields[i].sqlType,
sg_rgFields[i].cbColPrecision
);
if ( prgParams[ nParamsSeen] == NULL) {
fReturn = FALSE;
//DBGPRINTF( ( DBG_CONTEXT,
// " Failed to create Parameter[%d] %s. \n",
// i, sg_rgFields[i].pszName));
break;
}
nParamsSeen++;
//DBG_ASSERT( nParamsSeen <= cParams);
}
} // for creation of all ODBC parameters
if ( fReturn) {
//
// Set buffers for values to be received during insertions.
// Bind parameters to the statement using ODBC_CONNECTION object.
//
//DBG_ASSERT( nParamsSeen == cParams);
for( nParamsSeen = 0, i = 0; i < fiMaxFields; i++) {
if ( sg_rgFields[i].iParam > 0) {
if (!prgParams[nParamsSeen]->
SetValueBuffer(sg_rgFields[i].cbMaxSize,
sg_rgFields[i].cbValue) ||
!m_poStmt->BindParameter( prgParams[nParamsSeen])
) {
fReturn = FALSE;
//DBGPRINTF( ( DBG_CONTEXT,
// " Binding Parameter [%u] (%08x) failed.\n",
// nParamsSeen, prgParams[nParamsSeen]));
//DBG_CODE( prgParams[ i]->Print());
break;
}
nParamsSeen++;
}
} // for
} // if all ODBC params were created.
if ( !fReturn) {
//
// Free up the space used, since we were unsuccessful.
//
for( i = 0; i < iMaxFields; i++) {
if ( prgParams[ i] != NULL) {
delete ( prgParams[ i]);
prgParams[i] = NULL;
}
} // for
delete [] prgParams;
prgParams = NULL;
cParams = 0;
}
} // if array for pointers to ODBC params created successfully
//
// Set the values. Either invalid or valid ,depending on failure/success
//
m_ppParams = prgParams;
m_cOdbcParams = cParams;
return ( fReturn);
} // INET_SQL_LOG::PrepareParameters()
BOOL
GenerateFieldNames(IN PODBC_CONNECTION poc,
OUT CHAR * pchFieldNames,
IN DWORD cchFieldNames)
/*++
This function generates the field names string from the names of the fields
and identifier quote character for particular ODBC datasource in use.
--*/
{
BOOL fReturn = FALSE;
CHAR rgchQuote[MAX_SQL_IDENTIFIER_QUOTE_CHAR];
DWORD cchQuote;
//DBG_ASSERT( poc != NULL && pchFieldNames != NULL);
pchFieldNames[0] = _T('\0'); // initialize
//
// Inquire and obtain the SQL identifier quote char for ODBC data source.
//
fReturn = poc->GetInfo(SQL_IDENTIFIER_QUOTE_CHAR,
rgchQuote, MAX_SQL_IDENTIFIER_QUOTE_CHAR,
&cchQuote);
if ( !fReturn) {
//DBG_CODE( {
// STR strError;
//
// poc->GetLastErrorText( &strError);
//
// DBGPRINTF(( DBG_CONTEXT,
// " ODBC_CONNECTION(%08x)::GetInfo(QuoteChar) failed."
// " Error = %s\n",
// poc, strError.QueryStr()));
//});
} else {
DWORD i;
DWORD cchUsed = 0;
DWORD cchLen;
//
// ODBC returns " " (blank) if there is no special character
// for quoting identifiers. we need to identify and string the same.
// This needs to be done, other wise ODBC will complain when
// we give unwanted blanks before ","
//
if ( !strcmp( rgchQuote, _T(" "))) {
rgchQuote[0] = _T('\0'); // string the quoted blank.
cchQuote = 0;
} else {
cchQuote = (DWORD)strlen( rgchQuote);
}
// for each column, generate the quoted literal string and concatenate.
for( i = 0; i < fiMaxFields; i++) {
DWORD cchLen1 =
(DWORD)strlen(sg_rgFields[i].pszName) + 2 * cchQuote + 2;
if ( cchUsed + cchLen1 < cchFieldNames) {
// space available for copying the data.
cchLen = wsprintf( pchFieldNames + cchUsed,
_T(" %s%s%s,"),
rgchQuote,
sg_rgFields[i].pszName,
rgchQuote
);
//DBG_ASSERT( cchLen == cchLen1);
}
cchUsed += cchLen1;
} // for
if ( cchUsed >= cchFieldNames) {
// buffer exceeded. return error.
SetLastError( ERROR_INSUFFICIENT_BUFFER);
fReturn = FALSE;
} else {
//
// Reset the last character from being a ","
//
cchLen = (cchUsed > 0) ? (cchUsed - 1) : 0;
pchFieldNames[cchLen] = _T('\0');
fReturn = TRUE;
}
}
//IF_DEBUG( INETLOG) {
//
// DBGPRINTF(( DBG_CONTEXT,
// " GenerateFieldNames() returns %d."
// " Fields = %S\n",
// fReturn, pchFieldNames));
//}
return (fReturn);
} // GenerateFieldNames()
CODBCLOG::CODBCLOG()
{
INITIALIZE_CRITICAL_SECTION( &m_csLock);
m_poc = NULL;
m_poStmt = NULL;
m_ppParams = NULL;
m_fEnableEventLog = true;
m_TickResumeOpen = GetTickCount() + TICK_MINUTE;
}
/////////////////////////////////////////////////////////////////////////////
// CODBCLOG::~CODBCLOG - Destructor
CODBCLOG::~CODBCLOG()
{
TerminateLog( );
DeleteCriticalSection( &m_csLock);
}
STDMETHODIMP
CODBCLOG::InitializeLog(
LPCSTR pszInstanceName,
LPCSTR pszMetabasePath,
CHAR* pMetabase )
{
DWORD dwError = NO_ERROR;
// load ODBC entry point
LoadODBC();
// get the default parameters
DWORD dwL = sizeof(m_rgchServerName);
if ( !GetComputerName( m_rgchServerName, &dwL ) )
{
m_rgchServerName[0] = '\0';
}
strcpy( m_rgchServiceName, pszInstanceName);
//
// nntp (5x) logging sends the private IMDCOM interface while w3svc (6.0)
// logging sends the public IMSAdminBase interface. Find out which it is
//
BOOL fIsPublicInterface = (_strnicmp(pszInstanceName, "w3svc", 5) == 0);
if (fIsPublicInterface)
{
dwError = GetRegParametersFromPublicInterface(pszMetabasePath,
pMetabase);
}
else
{
dwError = GetRegParameters(pszMetabasePath, pMetabase);
}
if (dwError == NO_ERROR )
{
// open database
if ( m_poc == NULL )
{
Lock();
m_poc = new ODBC_CONNECTION();
if ( m_poc == NULL )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
} else
{
if ( !m_poc->Open( m_rgchDataSource, m_rgchUserName, m_rgchPassword ) ||
!PrepareStatement() ||
!PrepareParameters() )
{
dwError = GetLastError();
}
}
Unlock();
}
}
return (dwError == NO_ERROR) ? S_OK : HRESULT_FROM_WIN32(dwError);
}
STDMETHODIMP
CODBCLOG::LogInformation(
IInetLogInformation * ppvDataObj
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fReturn;
SYSTEMTIME stNow;
STR strClientHostName;
STR strClientUserName;
STR strServerIpAddress;
STR strOperation;
STR strTarget;
STR strParameters;
PCHAR pTmp;
DWORD cbSize;
DWORD dwBytesSent;
DWORD dwBytesRecvd;
DWORD dwProtocolStatus;
DWORD dwWin32Status;
DWORD dwTimeForProcessing;
if (!(
m_poc != NULL && m_poc->IsValid() &&
m_poStmt != NULL && m_poStmt->IsValid() &&
m_ppParams != NULL
))
{
//
// Check if it is time to retry
//
DWORD tickCount = GetTickCount( );
if ( (tickCount < m_TickResumeOpen) ||
((tickCount + TICK_MINUTE) < tickCount ) ) // The Tick counter is about to wrap.
{
return ERROR_INVALID_PARAMETER;
}
}
dwBytesSent = ppvDataObj->GetBytesSent( );
dwBytesRecvd = ppvDataObj->GetBytesRecvd( );
dwTimeForProcessing = ppvDataObj->GetTimeForProcessing( );
dwWin32Status = ppvDataObj->GetWin32Status( );
dwProtocolStatus = ppvDataObj->GetProtocolStatus( );
pTmp = ppvDataObj->GetClientHostName( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strClientHostName.Copy(pTmp);
pTmp = ppvDataObj->GetClientUserName( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strClientUserName.Copy(pTmp);
pTmp = ppvDataObj->GetServerAddress( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strServerIpAddress.Copy(pTmp);
pTmp = ppvDataObj->GetOperation( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strOperation.Copy(pTmp);
pTmp = ppvDataObj->GetTarget( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strTarget.Copy(pTmp);
pTmp = ppvDataObj->GetParameters( NULL, &cbSize);
if ( cbSize == 0 ) {
pTmp = "";
}
strParameters.Copy(pTmp);
LPCSTR pszUserName = strClientUserName.QueryStr();
LPCSTR pszOperation = strOperation.QueryStr();
LPCSTR pszTarget = strTarget.QueryStr();
LPCSTR pszParameters= strParameters.QueryStr();
LPCSTR pszServerAddr= strServerIpAddress.QueryStr();
SDWORD cbParameters;
SDWORD cbTarget;
cbParameters = (SDWORD)strlen( pszParameters ? pszParameters : "" ) + 1;
cbTarget = (SDWORD)strlen( pszTarget ? pszTarget : "" ) + 1;
//
// Format the Date and Time for logging.
//
GetLocalTime( & stNow);
if ( IsEmptyStr(pszUserName)) { pszUserName = QueryDefaultUserName();}
if ( IsEmptyStr(pszOperation)) { pszOperation = PSZ_UNKNOWN_FIELD_A; }
if ( IsEmptyStr(pszParameters)) { pszParameters= PSZ_UNKNOWN_FIELD_A; }
if ( IsEmptyStr(pszTarget)) { pszTarget = PSZ_UNKNOWN_FIELD_A; }
if ( IsEmptyStr(pszServerAddr)) { pszServerAddr= PSZ_UNKNOWN_FIELD_A; }
Lock();
//
// Reopen if necessary.
//
if (!(
m_poc != NULL && m_poc->IsValid() &&
m_poStmt != NULL && m_poStmt->IsValid() &&
m_ppParams != NULL
))
{
TerminateLog();
m_TickResumeOpen = GetTickCount( ) + TICK_MINUTE;
m_poc = new ODBC_CONNECTION();
if ( m_poc == NULL )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
//
// Try to open a new connection but don't log the failure in the eventlog
//
if ( !m_poc->Open( m_rgchDataSource, m_rgchUserName, m_rgchPassword, FALSE) ||
!PrepareStatement() ||
!PrepareParameters() )
{
dwError = GetLastError();
if ( ERROR_SUCCESS == dwError)
{
//
// Last Error wasn't set correctly
//
dwError = ERROR_GEN_FAILURE;
}
}
}
if ( ERROR_SUCCESS != dwError )
{
Unlock();
return dwError;
}
}
DBG_ASSERT(m_poc != NULL && m_poc->IsValid());
DBG_ASSERT(m_poStmt != NULL && m_poStmt->IsValid());
DBG_ASSERT(m_ppParams != NULL );
//
// Truncate the operation, parameters and target fields
//
if ( strOperation.QueryCCH() >= (DWORD)m_ppParams[ iSERVICE_OPERATION]->QueryMaxCbValue() )
{
strOperation.SetLen( (DWORD)m_ppParams[ iSERVICE_OPERATION]->QueryMaxCbValue() - 1 );
}
if ( cbTarget > m_ppParams[ iSERVICE_TARGET]->QueryMaxCbValue() )
{
strTarget.SetLen((DWORD)m_ppParams[ iSERVICE_TARGET]->QueryMaxCbValue()-1);
}
if ( cbParameters > m_ppParams[ iSERVICE_PARAMS]->QueryMaxCbValue() )
{
strParameters.SetLen((DWORD)m_ppParams[ iSERVICE_PARAMS]->QueryMaxCbValue()-1);
}
//
// Copy data values into parameter markers.
// NYI: LARGE_INTEGERS are ignored. Only lowBytes used!
//
fReturn =
(
m_ppParams[ iCLIENT_HOST]->
CopyValue( strClientHostName.QueryStr()) &&
m_ppParams[ iUSER_NAME]->CopyValue( pszUserName) &&
m_ppParams[ iREQUEST_TIME]->CopyValue( &stNow) &&
m_ppParams[ iSERVER_IPADDR]->CopyValue( pszServerAddr) &&
m_ppParams[ iPROCESSING_TIME]->
CopyValue( dwTimeForProcessing) &&
m_ppParams[ iBYTES_RECVD]->
CopyValue( dwBytesRecvd) &&
m_ppParams[ iBYTES_SENT]->
CopyValue( dwBytesSent) &&
m_ppParams[ iSERVICE_STATUS]->
CopyValue( dwProtocolStatus) &&
m_ppParams[ iWIN32_STATUS]->CopyValue( dwWin32Status) &&
m_ppParams[ iSERVICE_OPERATION]->CopyValue( pszOperation) &&
m_ppParams[ iSERVICE_TARGET]->CopyValue( pszTarget) &&
m_ppParams[ iSERVICE_PARAMS]->CopyValue( pszParameters)
);
//
// Execute insertion if parameters got copied properly.
//
if (fReturn)
{
fReturn = m_poStmt->ExecuteStatement();
}
Unlock();
if ( !fReturn )
{
//
// Execution of SQL statement failed.
// Pass the error as genuine failure, indicating ODBC failed
// Obtain and store the error string in the proper return field
//
TerminateLog();
dwError = ERROR_GEN_FAILURE;
if ( true == m_fEnableEventLog )
{
//
// We have not written an event log before. Indicate error
//
if ( g_eventLog != NULL )
{
const CHAR* tmpString[1];
tmpString[0] = m_rgchDataSource;
g_eventLog->LogEvent(
LOG_EVENT_ODBC_LOGGING_ERROR,
1,
tmpString,
GetLastError()
);
}
Lock();
m_fEnableEventLog = false;
m_TickResumeOpen = GetTickCount() + TICK_MINUTE;
Unlock();
}
}
else
{
//
// Success. Re-enable event logging
//
if (false == m_fEnableEventLog)
{
if ( g_eventLog != NULL )
{
const CHAR* tmpString[1];
tmpString[0] = m_rgchDataSource;
g_eventLog->LogEvent(
LOG_EVENT_ODBC_LOGGING_RESUMED,
1,
tmpString
);
}
m_fEnableEventLog = true;
}
}
return(dwError);
}
STDMETHODIMP
CODBCLOG::TerminateLog()
{
DWORD dwError = NO_ERROR;
Lock();
if (m_poStmt != NULL )
{
delete m_poStmt;
m_poStmt = NULL;
}
if (m_poc!= NULL)
{
if (!m_poc->Close())
{
dwError = GetLastError();
}
delete m_poc;
m_poc=NULL;
}
if (m_ppParams!=NULL)
{
DWORD i;
for (i=0;i<m_cOdbcParams;i++)
{
if (m_ppParams[i]!=NULL)
{
delete m_ppParams[i];
m_ppParams[i]=NULL;
}
}
delete []m_ppParams;
m_ppParams = NULL;
m_cOdbcParams=0;
}
Unlock();
return(dwError);
}
STDMETHODIMP
CODBCLOG::SetConfig(
DWORD,
BYTE *)
{
return(0L);
}
STDMETHODIMP
CODBCLOG::GetConfig(
DWORD,
BYTE * log)
{
PINETLOG_CONFIGURATIONA pLogConfig = (PINETLOG_CONFIGURATIONA)log;
pLogConfig->inetLogType = INET_LOG_TO_SQL;
strcpy( pLogConfig->u.logSql.rgchDataSource, m_rgchDataSource);
strcpy( pLogConfig->u.logSql.rgchTableName, m_rgchTableName);
strcpy( pLogConfig->u.logSql.rgchUserName, m_rgchUserName);
strcpy( pLogConfig->u.logSql.rgchPassword, m_rgchPassword);
return(0L);
}
DWORD
CODBCLOG::GetRegParameters(
LPCSTR pszRegKey,
LPVOID pvIMDCOM )
{
DWORD err = NO_ERROR;
MB mb( (IMDCOM*) pvIMDCOM );
DWORD cb;
if ( !mb.Open("") )
{
err = GetLastError();
goto Exit;
}
cb = sizeof(m_rgchDataSource);
if ( !mb.GetString( pszRegKey, MD_LOGSQL_DATA_SOURCES, IIS_MD_UT_SERVER, m_rgchDataSource, &cb ) )
{
strcpy(m_rgchDataSource,DEFAULT_LOG_SQL_DATASOURCE);
}
cb = sizeof(m_rgchTableName);
if ( !mb.GetString( pszRegKey, MD_LOGSQL_TABLE_NAME, IIS_MD_UT_SERVER, m_rgchTableName, &cb ) )
{
strcpy(m_rgchTableName,DEFAULT_LOG_SQL_TABLE);
}
cb = sizeof(m_rgchUserName);
if ( !mb.GetString( pszRegKey, MD_LOGSQL_USER_NAME, IIS_MD_UT_SERVER, m_rgchUserName, &cb ) )
{
strcpy(m_rgchUserName,DEFAULT_LOG_SQL_USER_NAME);
}
cb = sizeof(m_rgchPassword);
if ( !mb.GetString( pszRegKey, MD_LOGSQL_PASSWORD, IIS_MD_UT_SERVER, m_rgchPassword, &cb, METADATA_INHERIT|METADATA_SECURE ) )
{
strcpy(m_rgchPassword,DEFAULT_LOG_SQL_PASSWORD);
}
Exit:
return err;
}
inline
VOID
WCopyToA(
const WCHAR * wszSrc,
CHAR * szDest
)
{
while( *wszSrc )
{
*szDest++ = (CHAR) *wszSrc++;
}
*szDest = '\0';
}
inline
VOID
ACopyToW(
const CHAR * szSrc,
WCHAR * wszDest
)
{
while( *szSrc )
{
*wszDest++ = (WCHAR) *szSrc++;
}
*wszDest = L'\0';
}
DWORD
CODBCLOG::GetRegParametersFromPublicInterface(LPCSTR pszRegKey,
LPVOID pMetabase)
{
//
// What I really want is the version of MB in iisutil.dll. But, since I
// cannot link to that and iisrtl.dll, I will just work with the
// IMSAdminBase object directly
//
IMSAdminBase *pAdminBase = (IMSAdminBase *)pMetabase;
METADATA_HANDLE hMBPath = NULL;
DWORD cbRequired;
METADATA_RECORD mdr;
WCHAR pwszBuffer[MAX_PATH];
WCHAR pwszRegKey[MAX_PATH];
HRESULT hr;
ACopyToW(pszRegKey, pwszRegKey);
// MB::MB
pAdminBase->AddRef();
// MB::Open
hr = pAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"",
METADATA_PERMISSION_READ,
MB_TIMEOUT,
&hMBPath);
if (FAILED(hr))
{
goto Exit;
}
// MB::GetString
mdr.dwMDIdentifier = MD_LOGSQL_DATA_SOURCES;
mdr.dwMDAttributes = METADATA_INHERIT;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
mdr.dwMDDataLen = sizeof pwszBuffer;
mdr.pbMDData = (BYTE *)pwszBuffer;
hr = pAdminBase->GetData(hMBPath, pwszRegKey, &mdr, &cbRequired);
if (FAILED(hr) ||
wcslen(pwszBuffer) >= sizeof m_rgchDataSource)
{
strcpy(m_rgchDataSource, DEFAULT_LOG_SQL_DATASOURCE);
}
else
{
WCopyToA(pwszBuffer, m_rgchDataSource);
}
// MB::GetString
mdr.dwMDIdentifier = MD_LOGSQL_TABLE_NAME;
mdr.dwMDAttributes = METADATA_INHERIT;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
mdr.dwMDDataLen = sizeof pwszBuffer;
mdr.pbMDData = (BYTE *)pwszBuffer;
hr = pAdminBase->GetData(hMBPath, pwszRegKey, &mdr, &cbRequired);
if (FAILED(hr) ||
wcslen(pwszBuffer) >= sizeof m_rgchTableName)
{
strcpy(m_rgchTableName, DEFAULT_LOG_SQL_TABLE);
}
else
{
WCopyToA(pwszBuffer, m_rgchTableName);
}
// MB::GetString
mdr.dwMDIdentifier = MD_LOGSQL_USER_NAME;
mdr.dwMDAttributes = METADATA_INHERIT;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
mdr.dwMDDataLen = sizeof pwszBuffer;
mdr.pbMDData = (BYTE *)pwszBuffer;
hr = pAdminBase->GetData(hMBPath, pwszRegKey, &mdr, &cbRequired);
if (FAILED(hr) ||
wcslen(pwszBuffer) >= sizeof m_rgchUserName)
{
strcpy(m_rgchUserName, DEFAULT_LOG_SQL_USER_NAME);
}
else
{
WCopyToA(pwszBuffer, m_rgchUserName);
}
// MB::GetString
mdr.dwMDIdentifier = MD_LOGSQL_PASSWORD;
mdr.dwMDAttributes = METADATA_INHERIT|METADATA_SECURE;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
mdr.dwMDDataLen = sizeof pwszBuffer;
mdr.pbMDData = (BYTE *)pwszBuffer;
hr = pAdminBase->GetData(hMBPath, pwszRegKey, &mdr, &cbRequired);
if (FAILED(hr) ||
wcslen(pwszBuffer) >= sizeof m_rgchPassword)
{
strcpy(m_rgchPassword, DEFAULT_LOG_SQL_PASSWORD);
}
else
{
WCopyToA(pwszBuffer, m_rgchPassword);
}
hr = S_OK;
Exit:
// MB::Close
if (hMBPath)
{
pAdminBase->CloseKey(hMBPath);
hMBPath = NULL;
}
// MB::~MB
pAdminBase->Release();
if (FAILED(hr))
{
return HRESULTTOWIN32(hr);
}
return NO_ERROR;
}
STDMETHODIMP
CODBCLOG::QueryExtraLoggingFields(
PDWORD pcbSize,
TCHAR *pszFieldsList
)
/*++
Routine Description:
get configuration information
Arguments:
cbSize - size of the data structure
log - log configuration data structure
Return Value:
--*/
{
*pcbSize = 0;
*pszFieldsList = '\0';
return(0L);
}