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.
1235 lines
30 KiB
1235 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 2000-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
logutil.h
|
|
|
|
Abstract:
|
|
|
|
Various utilities for both raw & normal logging.
|
|
|
|
Author:
|
|
|
|
Ali E. Turkoglu (aliTu) 05-Oct-2001
|
|
|
|
Revision History:
|
|
|
|
---
|
|
|
|
--*/
|
|
|
|
#ifndef _LOGUTIL_H_
|
|
#define _LOGUTIL_H_
|
|
|
|
//
|
|
// Forwarders.
|
|
//
|
|
|
|
typedef struct _UL_INTERNAL_REQUEST *PUL_INTERNAL_REQUEST;
|
|
typedef struct _UL_URI_CACHE_ENTRY *PUL_URI_CACHE_ENTRY;
|
|
typedef struct _HTTP_RAWLOGID *PHTTP_RAWLOGID;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Definitions for the HTTP Logging Modules
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Some directory name related Macros.
|
|
//
|
|
|
|
#define UL_LOCAL_PATH_PREFIX (L"\\??\\")
|
|
#define UL_LOCAL_PATH_PREFIX_LENGTH (WCSLEN_LIT(UL_LOCAL_PATH_PREFIX))
|
|
#define UL_UNC_PATH_PREFIX (L"\\dosdevices\\UNC")
|
|
#define UL_UNC_PATH_PREFIX_LENGTH (WCSLEN_LIT(UL_UNC_PATH_PREFIX))
|
|
|
|
#define UL_SYSTEM_ROOT_PREFIX (L"\\SystemRoot")
|
|
#define UL_SYSTEM_ROOT_PREFIX_LENGTH (WCSLEN_LIT(UL_SYSTEM_ROOT_PREFIX))
|
|
|
|
#define UL_MAX_PATH_PREFIX_LENGTH (UL_UNC_PATH_PREFIX_LENGTH)
|
|
|
|
__inline
|
|
ULONG
|
|
UlpGetDirNameOffset(
|
|
IN PWSTR pFullName
|
|
)
|
|
{
|
|
if (wcsncmp(pFullName,
|
|
UL_LOCAL_PATH_PREFIX,
|
|
UL_LOCAL_PATH_PREFIX_LENGTH
|
|
) == 0 )
|
|
{
|
|
return UL_LOCAL_PATH_PREFIX_LENGTH;
|
|
}
|
|
else
|
|
if(wcsncmp(pFullName,
|
|
UL_UNC_PATH_PREFIX,
|
|
UL_UNC_PATH_PREFIX_LENGTH
|
|
) == 0 )
|
|
{
|
|
return UL_UNC_PATH_PREFIX_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Must be an error log file directory,
|
|
// use the whole string.
|
|
//
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
__inline
|
|
PWSTR
|
|
UlpGetLastDirOrFile(
|
|
IN PUNICODE_STRING pFullName
|
|
)
|
|
{
|
|
PWCHAR pw;
|
|
|
|
ASSERT(pFullName != NULL);
|
|
ASSERT(pFullName->Length != 0);
|
|
ASSERT(pFullName->Buffer != NULL);
|
|
|
|
pw = &pFullName->Buffer[(pFullName->Length/sizeof(WCHAR)) - 1];
|
|
|
|
while( *pw != UNICODE_NULL && *pw != L'\\' )
|
|
{
|
|
pw--;
|
|
}
|
|
|
|
ASSERT(*pw != UNICODE_NULL);
|
|
return pw;
|
|
}
|
|
|
|
//
|
|
// Maximum possible log file name length depends on the sequence number.
|
|
// Only the size based recycling will produce filenames as long as this.
|
|
// u_extend is the biggest one among ansi, binary and error logging file
|
|
// names;
|
|
//
|
|
// i.e. "\u_extend1234567890.log"
|
|
//
|
|
|
|
#define UL_MAX_FILE_NAME_SUFFIX_LENGTH (32)
|
|
#define UL_MAX_FILE_NAME_SUFFIX_SIZE \
|
|
(UL_MAX_FILE_NAME_SUFFIX_LENGTH * sizeof(WCHAR))
|
|
|
|
C_ASSERT(UL_MAX_FILE_NAME_SUFFIX_LENGTH > \
|
|
( \
|
|
WCSLEN_LIT(L"\\u_extend") \
|
|
+ \
|
|
MAX_ULONG_STR \
|
|
+ \
|
|
WCSLEN_LIT(L".log") \
|
|
));
|
|
|
|
//
|
|
// Upper limit for the log file directory name will be enforced when WAS
|
|
// does the logging configuration for the site. 212 has been picked to
|
|
// give the maximum space to the directoy name w/o violating the MAX_PATH
|
|
// after we add the prefix & suffix. Any number higher than this will cause
|
|
// the compile time assert to raise.
|
|
//
|
|
|
|
#define UL_MAX_FULL_PATH_DIR_NAME_LENGTH (212)
|
|
#define UL_MAX_FULL_PATH_DIR_NAME_SIZE (UL_MAX_FULL_PATH_DIR_NAME_LENGTH * sizeof(WCHAR))
|
|
|
|
C_ASSERT(UL_MAX_FULL_PATH_DIR_NAME_LENGTH <=
|
|
(MAX_PATH - UL_MAX_PATH_PREFIX_LENGTH - UL_MAX_FILE_NAME_SUFFIX_LENGTH));
|
|
|
|
//
|
|
// The amount of buffer allocated for directory search query during
|
|
// initialization. Pick this big enough to avoid too many querries
|
|
// 4K provides enough size for 40 something filenames. Increase it
|
|
// for faster startups with too many sites and/or too many log files
|
|
//
|
|
|
|
#define UL_DIRECTORY_SEARCH_BUFFER_SIZE (4*1024)
|
|
|
|
C_ASSERT(UL_DIRECTORY_SEARCH_BUFFER_SIZE >=
|
|
(sizeof(FILE_DIRECTORY_INFORMATION) + UL_MAX_FILE_NAME_SUFFIX_SIZE + sizeof(WCHAR)));
|
|
|
|
//
|
|
// Some macros regarding log field limits.
|
|
//
|
|
#define MAX_LOG_EXTEND_FIELD_LEN (4096)
|
|
|
|
//
|
|
// Method field has its own field limitation.
|
|
//
|
|
#define MAX_LOG_METHOD_FIELD_LEN (100)
|
|
|
|
//
|
|
// UserName field has its own field limitation.
|
|
//
|
|
#define MAX_LOG_USERNAME_FIELD_LEN (256)
|
|
|
|
//
|
|
// Simple macros to check log format type validity
|
|
//
|
|
|
|
#define IS_VALID_ANSI_LOGGING_TYPE(lt) \
|
|
((lt) == HttpLoggingTypeW3C || \
|
|
(lt) == HttpLoggingTypeIIS || \
|
|
(lt) == HttpLoggingTypeNCSA )
|
|
|
|
#define IS_VALID_BINARY_LOGGING_TYPE(lt) \
|
|
((lt) == HttpLoggingTypeRaw)
|
|
|
|
#define IS_VALID_SELECTIVE_LOGGING_TYPE(lt) \
|
|
((lt) == HttpLogAllRequests || \
|
|
(lt) == HttpLogSuccessfulRequests || \
|
|
(lt) == HttpLogErrorRequests )
|
|
|
|
#define IS_VALID_LOGGING_PERIOD(lp) \
|
|
((lp) < HttpLoggingPeriodMaximum)
|
|
|
|
//
|
|
// Even if LocalRollTimeRollover is set there will be one log
|
|
// recycle timer which will be aligned properly for the beginning
|
|
// of each hour, both for GMT and Local timezones.
|
|
//
|
|
|
|
typedef enum _UL_LOG_TIMER_PERIOD_TYPE
|
|
{
|
|
UlLogTimerPeriodNone = 0,
|
|
UlLogTimerPeriodGMT,
|
|
UlLogTimerPeriodLocal,
|
|
UlLogTimerPeriodBoth, // When and where GMT & Local are the same
|
|
|
|
UlLogTimerPeriodMaximum
|
|
|
|
} UL_LOG_TIMER_PERIOD_TYPE, *PUL_LOG_TIMER_PERIOD_TYPE;
|
|
|
|
//
|
|
// For Log File ReCycling based on Local and/or GMT time.
|
|
//
|
|
|
|
typedef struct _UL_LOG_TIMER
|
|
{
|
|
//
|
|
// Timer itself and the corresponding Dpc object.
|
|
//
|
|
|
|
KTIMER Timer;
|
|
KDPC DpcObject;
|
|
UL_SPIN_LOCK SpinLock;
|
|
|
|
//
|
|
// Initially a negative value i.e. -15, 15 minutes to first wakeup
|
|
// once the first wakeup happens then it becomes positive i.e. 4,
|
|
// that means 4 periods of "DEFAULT_LOG_TIMER_GRANULARITY" until
|
|
// the next wakeup.
|
|
//
|
|
|
|
UL_LOG_TIMER_PERIOD_TYPE PeriodType;
|
|
SHORT Period;
|
|
|
|
//
|
|
// Spinlock to protect the following state parameters
|
|
//
|
|
|
|
|
|
BOOLEAN Initialized;
|
|
BOOLEAN Started;
|
|
|
|
} UL_LOG_TIMER, *PUL_LOG_TIMER;
|
|
|
|
//
|
|
// Structure to hold a log file buffer
|
|
//
|
|
|
|
typedef struct _UL_LOG_FILE_BUFFER
|
|
{
|
|
//
|
|
// PagedPool
|
|
//
|
|
|
|
//
|
|
// This MUST be the first field in the structure. This is the linkage
|
|
// used by the lookaside package for storing entries in the lookaside
|
|
// list.
|
|
//
|
|
|
|
SLIST_ENTRY LookasideEntry;
|
|
|
|
//
|
|
// Signature is UL_LOG_FILE_BUFFER_POOL_TAG.
|
|
//
|
|
|
|
ULONG Signature;
|
|
|
|
//
|
|
// I/O status block for UlpBufferFlushAPC.
|
|
//
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
// Bytes used in the allocated buffered space.
|
|
//
|
|
|
|
LONG BufferUsed;
|
|
|
|
//
|
|
// The real buffered space for log records.
|
|
//
|
|
|
|
PUCHAR Buffer;
|
|
|
|
} UL_LOG_FILE_BUFFER, *PUL_LOG_FILE_BUFFER;
|
|
|
|
#define IS_VALID_LOG_FILE_BUFFER( entry ) \
|
|
HAS_VALID_SIGNATURE(entry, UL_LOG_FILE_BUFFER_POOL_TAG)
|
|
|
|
//
|
|
// Following structure is used for two reasons;
|
|
// 1. To be able to close the handle on threadpool to avoid
|
|
// attach/detach (to system process) bugchecks.
|
|
// 2. To be able to do the defered log file creation. When a
|
|
// a request comes in file entry will allocate a file handle
|
|
// structure and create/open a file.
|
|
//
|
|
|
|
typedef struct _UL_LOG_FILE_HANDLE
|
|
{
|
|
//
|
|
// Signature is UL_LOG_FILE_HANDLE_POOL_TAG.
|
|
//
|
|
|
|
ULONG Signature;
|
|
|
|
//
|
|
// To be able to close the file handle on threadpool.
|
|
//
|
|
|
|
UL_WORK_ITEM WorkItem;
|
|
|
|
//
|
|
// The open file handle. Note that this handle is only valid
|
|
// in the context of the system process. Therefore we open it
|
|
// with kernel flag set and we close it on our threadpool.
|
|
//
|
|
|
|
HANDLE hFile;
|
|
|
|
} UL_LOG_FILE_HANDLE, *PUL_LOG_FILE_HANDLE;
|
|
|
|
#define IS_VALID_LOG_FILE_HANDLE( entry ) \
|
|
HAS_VALID_SIGNATURE(entry, UL_LOG_FILE_HANDLE_POOL_TAG)
|
|
|
|
//
|
|
// Temp Log buffer holds the captured data from user until logging
|
|
// for the request is done. Both Binary & Normal logging uses this
|
|
// structure. Sizes are in bytes.
|
|
//
|
|
|
|
#define UL_ANSI_LOG_LINE_BUFFER_SIZE (4096)
|
|
|
|
#define UL_BINARY_LOG_LINE_BUFFER_SIZE (512)
|
|
|
|
#define UL_ERROR_LOG_BUFFER_SIZE (768)
|
|
|
|
typedef struct _UL_BINARY_LOG_DATA
|
|
{
|
|
//
|
|
// If the field is captured, its respective pointer points to its
|
|
// beginning in the external buffer. If field is cached, its id is
|
|
// provided in the same log line buffer.
|
|
//
|
|
|
|
PUCHAR pUriStem;
|
|
PHTTP_RAWLOGID pUriStemID;
|
|
|
|
PUCHAR pUriQuery;
|
|
PUCHAR pUserName;
|
|
|
|
USHORT UriStemSize;
|
|
USHORT UriQuerySize;
|
|
USHORT UserNameSize;
|
|
|
|
UCHAR Method;
|
|
UCHAR Version;
|
|
|
|
} UL_BINARY_LOG_DATA, *PUL_BINARY_LOG_DATA;
|
|
|
|
typedef struct _UL_STR_LOG_DATA
|
|
{
|
|
//
|
|
// Format & Flags for normal (ansi) logging.
|
|
//
|
|
|
|
HTTP_LOGGING_TYPE Format;
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// This fields are used to track the format of the partially
|
|
// stored log line in the below buffer.
|
|
//
|
|
|
|
USHORT Offset1;
|
|
USHORT Offset2;
|
|
USHORT Offset3;
|
|
|
|
} UL_STR_LOG_DATA, *PUL_STR_LOG_DATA;
|
|
|
|
typedef struct _UL_LOG_DATA_BUFFER
|
|
{
|
|
//
|
|
// This MUST be the first field in the structure. This is the linkage
|
|
// used by the lookaside package for storing entries in the lookaside
|
|
// list.
|
|
//
|
|
|
|
SLIST_ENTRY LookasideEntry;
|
|
|
|
//
|
|
// Signature is UL_BINARY_LOG_DATA_BUFFER_POOL_TAG
|
|
// or UL_ANSI_LOG_DATA_BUFFER_POOL_TAG.
|
|
//
|
|
|
|
ULONG Signature;
|
|
|
|
|
|
//
|
|
// A work item, used for queuing to a worker thread.
|
|
//
|
|
|
|
UL_WORK_ITEM WorkItem;
|
|
|
|
//
|
|
// Our private pointer to the Internal Request structure to ensure
|
|
// the request will be around around until we are done. Upon send
|
|
// completion we may need to read few fields from request.
|
|
//
|
|
|
|
PUL_INTERNAL_REQUEST pRequest;
|
|
|
|
//
|
|
// The total amount of send_response bytes.
|
|
//
|
|
|
|
ULONGLONG BytesTransferred;
|
|
|
|
//
|
|
// Status fields captured from user data. They can be overwritten
|
|
// according to the send completion results.
|
|
//
|
|
|
|
ULONG Win32Status;
|
|
|
|
USHORT ProtocolStatus;
|
|
|
|
USHORT SubStatus;
|
|
|
|
USHORT ServerPort;
|
|
|
|
union
|
|
{
|
|
USHORT Value;
|
|
struct
|
|
{
|
|
USHORT CacheAndSendResponse:1; // Do not restore back from cache
|
|
USHORT Binary:1; // Logging type binary
|
|
USHORT IsFromLookaside:1; // Destroy carefully
|
|
};
|
|
} Flags;
|
|
|
|
//
|
|
// Logging Type specific fields, either binary or normal logging.
|
|
//
|
|
|
|
union
|
|
{
|
|
UL_STR_LOG_DATA Str;
|
|
UL_BINARY_LOG_DATA Binary;
|
|
|
|
} Data;
|
|
|
|
//
|
|
// Length of the buffer. It gets allocated from a lookaside list and
|
|
// could be 512 byte (Binary Log) or 4k (Normal Log) by default.
|
|
// It is allocated at the end of this structure.
|
|
//
|
|
|
|
USHORT Used;
|
|
USHORT Size;
|
|
PUCHAR Line;
|
|
|
|
} UL_LOG_DATA_BUFFER, *PUL_LOG_DATA_BUFFER;
|
|
|
|
#define IS_VALID_LOG_DATA_BUFFER( entry ) \
|
|
( (entry != NULL) && \
|
|
((entry)->Signature == UL_BINARY_LOG_DATA_BUFFER_POOL_TAG) || \
|
|
((entry)->Signature == UL_ANSI_LOG_DATA_BUFFER_POOL_TAG))
|
|
|
|
|
|
#define LOG_UPDATE_WIN32STATUS(pLogData,Status) \
|
|
do { \
|
|
if (STATUS_SUCCESS != (Status)) \
|
|
{ \
|
|
ASSERT((pLogData) != NULL); \
|
|
\
|
|
(pLogData)->Win32Status = HttpNtStatusToWin32Status(Status); \
|
|
} \
|
|
} while (FALSE, FALSE)
|
|
|
|
#define LOG_SET_WIN32STATUS(pLogData,Status) \
|
|
if (pLogData) \
|
|
{ \
|
|
(pLogData)->Win32Status = HttpNtStatusToWin32Status(Status); \
|
|
} \
|
|
else \
|
|
{ \
|
|
ASSERT(!"Null LogData Pointer !"); \
|
|
}
|
|
|
|
//
|
|
// 64K Default log file buffer.
|
|
//
|
|
|
|
#define DEFAULT_MAX_LOG_BUFFER_SIZE (0x00010000)
|
|
|
|
//
|
|
// Buffer flush out period in minutes.
|
|
//
|
|
|
|
#define DEFAULT_BUFFER_TIMER_PERIOD_MINUTES (1)
|
|
|
|
//
|
|
// Maximum allowed idle time for a log entry. After this time
|
|
// its file will automatically be closed. In buffer periods.
|
|
//
|
|
|
|
#define DEFAULT_MAX_FILE_IDLE_TIME (15)
|
|
|
|
//
|
|
// Maximum allowed sequence number for an existing log file in the
|
|
// log directory.
|
|
//
|
|
|
|
#define MAX_ALLOWED_SEQUENCE_NUMBER (0xFFFFFF)
|
|
|
|
//
|
|
// Ellipsis are used to show that a long event log message was truncated.
|
|
// Ellipsis and its size (in bytes including UNICODE_NULL.)
|
|
//
|
|
|
|
#define UL_ELLIPSIS_WSTR L"..."
|
|
#define UL_ELLIPSIS_SIZE (sizeof(UL_ELLIPSIS_WSTR))
|
|
|
|
//
|
|
// UlCopyHttpVersion doesn't convert version lengths
|
|
// bigger than this.
|
|
//
|
|
|
|
#define UL_HTTP_VERSION_LENGTH (8)
|
|
|
|
//
|
|
// Cached Date header string.
|
|
//
|
|
|
|
#define DATE_LOG_FIELD_LENGTH (15)
|
|
#define TIME_LOG_FIELD_LENGTH (8)
|
|
|
|
typedef struct _UL_LOG_DATE_AND_TIME_CACHE
|
|
{
|
|
|
|
CHAR Date[DATE_LOG_FIELD_LENGTH+1];
|
|
ULONG DateLength;
|
|
CHAR Time[TIME_LOG_FIELD_LENGTH+1];
|
|
ULONG TimeLength;
|
|
|
|
LARGE_INTEGER LastSystemTime;
|
|
|
|
} UL_LOG_DATE_AND_TIME_CACHE, *PUL_LOG_DATE_AND_TIME_CACHE;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported function calls
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
UlInitializeLogUtil(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
UlTerminateLogUtil(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
UlBuildLogDirectory(
|
|
IN PUNICODE_STRING pSrcDirName,
|
|
IN OUT PUNICODE_STRING pDstDirName
|
|
);
|
|
|
|
NTSTATUS
|
|
UlRefreshFileName(
|
|
IN PUNICODE_STRING pDirectory,
|
|
OUT PUNICODE_STRING pFileName,
|
|
OUT PWSTR *ppShortName
|
|
);
|
|
|
|
VOID
|
|
UlConstructFileName(
|
|
IN HTTP_LOGGING_PERIOD period,
|
|
IN PCWSTR prefix,
|
|
IN PCWSTR extension,
|
|
OUT PUNICODE_STRING filename,
|
|
IN PTIME_FIELDS fields,
|
|
IN BOOLEAN Utf8Enabled,
|
|
IN OUT PULONG sequenceNu // OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
UlCreateSafeDirectory(
|
|
IN PUNICODE_STRING pDirectoryName,
|
|
OUT PBOOLEAN pUncShare,
|
|
OUT PBOOLEAN pACLSupport
|
|
);
|
|
|
|
NTSTATUS
|
|
UlFlushLogFileBuffer(
|
|
IN OUT PUL_LOG_FILE_BUFFER *ppLogBuffer,
|
|
IN PUL_LOG_FILE_HANDLE pLogFile,
|
|
IN BOOLEAN WaitForComplete,
|
|
OUT PULONGLONG pTotalWritten
|
|
);
|
|
|
|
VOID
|
|
UlpWaitForIoCompletion(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
UlpCloseLogFileWorker(
|
|
IN PUL_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
VOID
|
|
UlCloseLogFile(
|
|
IN OUT PUL_LOG_FILE_HANDLE *ppLogFile
|
|
);
|
|
|
|
NTSTATUS
|
|
UlQueryDirectory(
|
|
IN OUT PUNICODE_STRING pFileName,
|
|
IN OUT PWSTR pShortName,
|
|
IN PCWSTR Prefix,
|
|
IN PCWSTR ExtensionPlusDot,
|
|
OUT PULONG pSequenceNumber,
|
|
OUT PULONGLONG pTotalWritten
|
|
);
|
|
|
|
ULONGLONG
|
|
UlGetLogFileLength(
|
|
IN HANDLE hFile
|
|
);
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
UlGetMonthDays :
|
|
|
|
Shamelessly stolen from IIS 5.1 Logging code and adapted here.
|
|
|
|
Arguments:
|
|
|
|
PTIME_FIELDS - Current Time Fields
|
|
|
|
Return Value:
|
|
|
|
ULONG - Number of days in the month.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
ULONG
|
|
UlGetMonthDays(
|
|
IN PTIME_FIELDS pDueTime
|
|
)
|
|
{
|
|
ULONG NumDays = 31;
|
|
|
|
if ( (4 == pDueTime->Month) || // April
|
|
(6 == pDueTime->Month) || // June
|
|
(9 == pDueTime->Month) || // September
|
|
(11 == pDueTime->Month) // November
|
|
)
|
|
{
|
|
NumDays = 30;
|
|
}
|
|
|
|
if (2 == pDueTime->Month) // February
|
|
{
|
|
if ((pDueTime->Year % 4 == 0 &&
|
|
pDueTime->Year % 100 != 0) ||
|
|
pDueTime->Year % 400 == 0 )
|
|
{
|
|
//
|
|
// Leap year
|
|
//
|
|
NumDays = 29;
|
|
}
|
|
else
|
|
{
|
|
NumDays = 28;
|
|
}
|
|
}
|
|
return NumDays;
|
|
}
|
|
|
|
VOID
|
|
UlSetLogTimer(
|
|
IN PUL_LOG_TIMER pTimer
|
|
);
|
|
|
|
VOID
|
|
UlSetBufferTimer(
|
|
IN PUL_LOG_TIMER pTimer
|
|
);
|
|
|
|
NTSTATUS
|
|
UlCalculateTimeToExpire(
|
|
PTIME_FIELDS pDueTime,
|
|
HTTP_LOGGING_PERIOD LogPeriod,
|
|
PULONG pTimeRemaining
|
|
);
|
|
|
|
__inline
|
|
PUL_LOG_DATA_BUFFER
|
|
UlReallocLogDataBuffer(
|
|
IN ULONG LogLineSize,
|
|
IN BOOLEAN IsBinary
|
|
)
|
|
{
|
|
PUL_LOG_DATA_BUFFER pLogDataBuffer = NULL;
|
|
ULONG Tag = UL_ANSI_LOG_DATA_BUFFER_POOL_TAG;
|
|
USHORT BytesNeeded = (USHORT) ALIGN_UP(LogLineSize, PVOID);
|
|
|
|
//
|
|
// It should be bigger than the default size for each buffer
|
|
// logging type.
|
|
//
|
|
|
|
if (IsBinary)
|
|
{
|
|
Tag = UL_BINARY_LOG_DATA_BUFFER_POOL_TAG;
|
|
ASSERT(LogLineSize > UL_BINARY_LOG_LINE_BUFFER_SIZE);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(LogLineSize > UL_ANSI_LOG_LINE_BUFFER_SIZE);
|
|
}
|
|
|
|
pLogDataBuffer =
|
|
UL_ALLOCATE_STRUCT_WITH_SPACE(
|
|
PagedPool,
|
|
UL_LOG_DATA_BUFFER,
|
|
BytesNeeded,
|
|
Tag
|
|
);
|
|
|
|
if (pLogDataBuffer)
|
|
{
|
|
pLogDataBuffer->Signature = Tag;
|
|
pLogDataBuffer->Used = 0;
|
|
pLogDataBuffer->Size = BytesNeeded;
|
|
pLogDataBuffer->Line = (PUCHAR) (pLogDataBuffer + 1);
|
|
pLogDataBuffer->Flags.Value = 0;
|
|
|
|
pLogDataBuffer->Flags.IsFromLookaside = 0;
|
|
|
|
if (IsBinary)
|
|
{
|
|
pLogDataBuffer->Flags.Binary = 1;
|
|
}
|
|
|
|
UlInitializeWorkItem(&pLogDataBuffer->WorkItem);
|
|
}
|
|
|
|
return pLogDataBuffer;
|
|
}
|
|
|
|
VOID
|
|
UlDestroyLogDataBufferWorker(
|
|
IN PUL_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper function to ensure we are not touching to paged-pool allocated
|
|
large log buffer on elevated IRQL. It's important that this function has
|
|
been written with the assumption of Request doesn't go away until we
|
|
properly execute the possible passive worker. This is indeed the case
|
|
because request(with the embedded logdata) has been refcounted up by the
|
|
logdata.
|
|
|
|
Arguments:
|
|
|
|
pLogData - The buffer to be destroyed
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
VOID
|
|
UlDestroyLogDataBuffer(
|
|
IN PUL_LOG_DATA_BUFFER pLogData
|
|
)
|
|
{
|
|
//
|
|
// Sanity check
|
|
//
|
|
|
|
ASSERT(pLogData);
|
|
|
|
//
|
|
// If we are running on elevated IRQL and large log line allocated
|
|
// then queue a passive worker otherwise complete inline.
|
|
//
|
|
|
|
if (!pLogData->Flags.IsFromLookaside)
|
|
{
|
|
UL_CALL_PASSIVE( &pLogData->WorkItem,
|
|
&UlDestroyLogDataBufferWorker );
|
|
}
|
|
else
|
|
{
|
|
UlDestroyLogDataBufferWorker( &pLogData->WorkItem );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UlProbeLogData(
|
|
IN PHTTP_LOG_FIELDS_DATA pLogData,
|
|
IN KPROCESSOR_MODE RequestorMode
|
|
);
|
|
|
|
__inline
|
|
NTSTATUS
|
|
UlCopyLogFileDir(
|
|
IN OUT PUNICODE_STRING pOldDir,
|
|
IN PUNICODE_STRING pNewDir
|
|
)
|
|
{
|
|
PWSTR pNewBuffer = NULL;
|
|
|
|
ASSERT(pOldDir);
|
|
ASSERT(pNewDir);
|
|
|
|
pNewBuffer =
|
|
(PWSTR) UL_ALLOCATE_ARRAY(
|
|
PagedPool,
|
|
UCHAR,
|
|
pNewDir->MaximumLength,
|
|
UL_CG_LOGDIR_POOL_TAG
|
|
);
|
|
if(pNewBuffer == NULL)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (pOldDir->Buffer != NULL)
|
|
{
|
|
UL_FREE_POOL(pOldDir->Buffer,UL_CG_LOGDIR_POOL_TAG);
|
|
}
|
|
|
|
pOldDir->Buffer = pNewBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pOldDir->Buffer,
|
|
pNewDir->Buffer,
|
|
pNewDir->MaximumLength
|
|
);
|
|
|
|
pOldDir->Length = pNewDir->Length;
|
|
pOldDir->MaximumLength = pNewDir->MaximumLength;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
UlCheckLogDirectory(
|
|
IN PUNICODE_STRING pDirName
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpCheckLogDirectory(
|
|
IN PVOID pContext
|
|
);
|
|
|
|
BOOLEAN
|
|
UlUpdateLogTruncateSize(
|
|
IN ULONG NewTruncateSize,
|
|
IN OUT PULONG pCurrentTruncateSize,
|
|
IN OUT PULONG pEntryTruncateSize,
|
|
IN ULARGE_INTEGER EntryTotalWritten
|
|
);
|
|
|
|
ULONG
|
|
UlpInitializeLogBufferGranularity();
|
|
|
|
#define HTTP_MAX_EVENT_LOG_DATA_SIZE \
|
|
((ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG)) & ~3)
|
|
|
|
NTSTATUS
|
|
UlWriteEventLogEntry(
|
|
IN NTSTATUS EventCode,
|
|
IN ULONG UniqueEventValue,
|
|
IN USHORT NumStrings,
|
|
IN PWSTR * pStringArray OPTIONAL,
|
|
IN ULONG DataSize,
|
|
IN PVOID Data OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Sanity check. An event log entry must be able to hold the ellipsis string
|
|
// and NTSTATUS error code. UlEventLogOneString() depends on this condition.
|
|
//
|
|
|
|
C_ASSERT(HTTP_MAX_EVENT_LOG_DATA_SIZE >= UL_ELLIPSIS_SIZE + sizeof(NTSTATUS));
|
|
|
|
NTSTATUS
|
|
UlEventLogOneStringEntry(
|
|
IN NTSTATUS EventCode,
|
|
IN PWSTR pMessage,
|
|
IN BOOLEAN WriteErrorCode,
|
|
IN NTSTATUS ErrorCode OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Following structure is used for distinguishing the event log entry
|
|
// based on the type of logging issuing the create failure.
|
|
//
|
|
|
|
typedef enum _UL_LOG_EVENT_LOG_TYPE
|
|
{
|
|
UlEventLogNormal,
|
|
UlEventLogBinary,
|
|
UlEventLogError,
|
|
|
|
UlEventLogMaximum
|
|
|
|
} UL_LOG_EVENT_LOG_TYPE, *PUL_LOG_EVENT_LOG_TYPE;
|
|
|
|
NTSTATUS
|
|
UlEventLogCreateFailure(
|
|
IN NTSTATUS Failure,
|
|
IN UL_LOG_EVENT_LOG_TYPE LoggingType,
|
|
IN PUNICODE_STRING pFullName,
|
|
IN ULONG SiteId
|
|
);
|
|
|
|
NTSTATUS
|
|
UlBuildSecurityToLogFile(
|
|
OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN PSID pSid
|
|
);
|
|
|
|
NTSTATUS
|
|
UlQueryLogFileSecurity(
|
|
IN HANDLE hFile,
|
|
IN BOOLEAN UncShare,
|
|
IN BOOLEAN Opened
|
|
);
|
|
|
|
//
|
|
// Normally when the log file is created by http.sys the owner
|
|
// will be the admin alias "SeAliasAdminsSid". However when the
|
|
// log files is created on a UNC share following macro will fail
|
|
// even though it is created by http.sys on a different machine
|
|
// in that case the owner will be DOMAIN\ServerName.
|
|
//
|
|
|
|
#define IS_VALID_OWNER(Owner) \
|
|
(RtlEqualSid((Owner), \
|
|
SeExports->SeLocalSystemSid \
|
|
) || \
|
|
RtlEqualSid((Owner), \
|
|
SeExports->SeAliasAdminsSid \
|
|
))
|
|
|
|
//
|
|
// Used for queueing buffer flushes. Passed into
|
|
// to the worker below as a context.
|
|
//
|
|
|
|
typedef struct _LOG_IO_FLUSH_OBJ
|
|
{
|
|
PUL_LOG_FILE_HANDLE pLogFile;
|
|
PUL_LOG_FILE_BUFFER pLogBuffer;
|
|
|
|
} LOG_IO_FLUSH_OBJ, *PLOG_IO_FLUSH_OBJ;
|
|
|
|
NTSTATUS
|
|
UlpFlushLogFileBufferWorker(
|
|
IN PVOID pContext
|
|
);
|
|
|
|
//
|
|
// Types and API for queueing logging I/O for
|
|
// passive execution under threadpool.
|
|
//
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*PUL_LOG_IO_ROUTINE)(
|
|
IN PVOID pContext
|
|
);
|
|
|
|
typedef struct _LOG_IO_SYNC_OBJ
|
|
{
|
|
//
|
|
// Pointer to log file entry or directory name
|
|
//
|
|
|
|
PVOID pContext;
|
|
|
|
//
|
|
// Handler for the above context.
|
|
//
|
|
|
|
PUL_LOG_IO_ROUTINE pHandler;
|
|
|
|
//
|
|
// For queueing to the high priority.
|
|
//
|
|
|
|
UL_WORK_ITEM WorkItem;
|
|
|
|
//
|
|
// Used for wait until handler is done.
|
|
//
|
|
|
|
KEVENT Event;
|
|
|
|
//
|
|
// Result of the handler's work.
|
|
//
|
|
|
|
NTSTATUS Status;
|
|
|
|
} LOG_IO_SYNC_OBJ, *PLOG_IO_SYNC_OBJ;
|
|
|
|
NTSTATUS
|
|
UlQueueLoggingRoutine(
|
|
IN PVOID pContext,
|
|
IN PUL_LOG_IO_ROUTINE pHandler
|
|
);
|
|
|
|
VOID
|
|
UlpQueueLoggingRoutineWorker(
|
|
IN PUL_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
VOID
|
|
UlpInitializeLogCache(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
UlpGenerateDateAndTimeFields(
|
|
IN HTTP_LOGGING_TYPE LogType,
|
|
IN LARGE_INTEGER CurrentTime,
|
|
OUT PCHAR pDate,
|
|
OUT PULONG pDateLength,
|
|
OUT PCHAR pTime,
|
|
OUT PULONG pTimeLength
|
|
);
|
|
|
|
VOID
|
|
UlGetDateTimeFields(
|
|
IN HTTP_LOGGING_TYPE LogType,
|
|
OUT PCHAR pDate,
|
|
OUT PULONG pDateLength,
|
|
OUT PCHAR pTime,
|
|
OUT PULONG pTimeLength
|
|
);
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
For a given HTTP_VERSION this function will build a version string in
|
|
the provided log data buffer, at exactly UL_HTTP_VERSION_LENGTH.
|
|
|
|
Arguments:
|
|
|
|
psz: Pointer to log data buffer. Enough space is assumed to be allocated.
|
|
version: To be converted to string.
|
|
chSeparator
|
|
|
|
Returns:
|
|
|
|
the pointer to the log data buffer after the separator.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
PCHAR
|
|
UlCopyHttpVersion(
|
|
IN OUT PCHAR psz,
|
|
IN HTTP_VERSION version,
|
|
IN CHAR chSeparator
|
|
)
|
|
{
|
|
//
|
|
// Do the fast lookup first
|
|
//
|
|
|
|
if (HTTP_EQUAL_VERSION(version, 1, 1))
|
|
{
|
|
psz = UlStrPrintStr(psz, "HTTP/1.1", chSeparator);
|
|
}
|
|
else if (HTTP_EQUAL_VERSION(version, 1, 0))
|
|
{
|
|
psz = UlStrPrintStr(psz, "HTTP/1.0", chSeparator);
|
|
}
|
|
else if (HTTP_EQUAL_VERSION(version, 0, 9))
|
|
{
|
|
psz = UlStrPrintStr(psz, "HTTP/0.9", chSeparator);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise string convert but do not exceed the deafult size of
|
|
// UL_HTTP_VERSION_LENGTH.
|
|
//
|
|
|
|
if (version.MajorVersion < 10 &&
|
|
version.MinorVersion < 10)
|
|
{
|
|
psz = UlStrPrintStr(
|
|
psz,
|
|
"HTTP/",
|
|
(CHAR) (version.MajorVersion + '0')
|
|
);
|
|
|
|
*psz++ = '.';
|
|
*psz++ = (CHAR) (version.MinorVersion + '0');
|
|
*psz++ = chSeparator;
|
|
}
|
|
else
|
|
{
|
|
psz = UlStrPrintStr(psz, "HTTP/?.?", chSeparator);
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
NTSTATUS
|
|
UlValidateLogFileOwner(
|
|
IN HANDLE hFile
|
|
);
|
|
|
|
__inline
|
|
VOID
|
|
UlpTraceOwnerDetails(
|
|
PSID Owner,
|
|
BOOLEAN OwnerDefaulted
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING OwnerSID;
|
|
|
|
ASSERT(RtlValidSid(Owner));
|
|
|
|
Status =
|
|
RtlConvertSidToUnicodeString(
|
|
&OwnerSID,
|
|
Owner,
|
|
TRUE
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
UlTrace2Either(BINARY_LOGGING, LOGGING,
|
|
("Http!UlpTraceOwnerDetails: "
|
|
"handle owned by <%s> OwnerDefaulted <%s>\n"
|
|
"SID -> <%S>\n\n",
|
|
|
|
RtlEqualSid(
|
|
Owner,
|
|
SeExports->SeLocalSystemSid) ? "System" :
|
|
RtlEqualSid(
|
|
Owner,
|
|
SeExports->SeAliasAdminsSid) ? "Admin" : "Other",
|
|
|
|
OwnerDefaulted == TRUE ? "Yes" : "No",
|
|
|
|
OwnerSID.Buffer
|
|
));
|
|
|
|
RtlFreeUnicodeString(&OwnerSID);
|
|
}
|
|
}
|
|
|
|
#define TRACE_LOG_FILE_OWNER(Owner,OwnerDefaulted) \
|
|
IF_DEBUG2EITHER(LOGGING,BINARY_LOGGING) \
|
|
{ \
|
|
UlpTraceOwnerDetails((Owner),(OwnerDefaulted)); \
|
|
}
|
|
|
|
#else
|
|
|
|
#define TRACE_LOG_FILE_OWNER(Owner,OwnerDefaulted) NOP_FUNCTION
|
|
|
|
#endif // DBG
|
|
|
|
USHORT
|
|
UlComputeCachedLogDataLength(
|
|
IN PUL_LOG_DATA_BUFFER pLogData
|
|
);
|
|
|
|
VOID
|
|
UlCopyCachedLogData(
|
|
IN PUL_LOG_DATA_BUFFER pLogData,
|
|
IN USHORT LogDataLength,
|
|
IN PUL_URI_CACHE_ENTRY pEntry
|
|
);
|
|
|
|
NTSTATUS
|
|
UlQueryAttributeInfo(
|
|
IN HANDLE hFile,
|
|
OUT PBOOLEAN pSupportsPersistentACL
|
|
);
|
|
|
|
NTSTATUS
|
|
UlCreateLogFile(
|
|
IN PUNICODE_STRING pFileName,
|
|
IN BOOLEAN UncShare,
|
|
IN BOOLEAN ACLSupport,
|
|
OUT PHANDLE pFileHandle
|
|
);
|
|
|
|
BOOLEAN
|
|
UlIsValidLogDirectory(
|
|
IN PUNICODE_STRING pDir,
|
|
IN BOOLEAN UncSupported,
|
|
IN BOOLEAN SystemRootSupported
|
|
);
|
|
|
|
NTSTATUS
|
|
UlCheckLoggingConfig(
|
|
IN PHTTP_CONTROL_CHANNEL_BINARY_LOGGING pBinaryConfig,
|
|
IN PHTTP_CONFIG_GROUP_LOGGING pAnsiConfig
|
|
);
|
|
|
|
#endif // _LOGUTIL_H_
|