/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. You should have received a copy of the GNU General
* Public License along with this program. If not, see
* .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright (C) Centeris Corporation 2004-2007
* Copyright (C) Likewise Software 2007
* All rights reserved.
*
* Authors: Krishna Ganugapati (krishnag@likewisesoftware.com)
* Sriram Nambakam (snambakam@likewisesoftware.com)
*
* Eventlog parser to parse log files from Microsoft Event Viewer.
*
*/
#include "includes.h"
//Character indices to use in PRINT_TABLE option.
//This allows printing a user-readable table to stdout that 80 characters wide.
#define TABLOC_ID 0
#define TABLOC_TYPE (TABLOC_ID+8)
#define TABLOC_DATE (TABLOC_TYPE+16)
#define TABLOC_TIME (TABLOC_DATE+13)
#define TABLOC_SOURCE (TABLOC_TIME+14)
#define TABLOC_CATEGORY (TABLOC_SOURCE+20)
#define TABLOC_SOURCE_ID (TABLOC_CATEGORY+25)
#define TABLOC_USER (TABLOC_SOURCE_ID+10)
#define TABLOC_BORDER " | "
//
// When you save the log file on windows, the following seems
// to be the default order of fields.
//
typedef enum
{
EVENT_TABLE_CATEGORY_ID = 0,
EVENT_DATE, //1
EVENT_TIME, //2
EVENT_SOURCE, //3
EVENT_TYPE, //4
EVENT_CATEGORY, //5
EVENT_SOURCE_ID, //6
EVENT_USER, //7
EVENT_COMPUTER, //8
EVENT_DESCRIPTION, //9
EVENT_DATA, //10
EVENT_FIELD_TYPE_SENTINEL
} EventFieldType;
static
DWORD
ExportEventRecord (
PEVENT_LOG_RECORD pRecord,
FILE* fpExport
)
{
DWORD dwError = 0;
char eventDate[256];
char eventTime[256];
if (pRecord == NULL) return -1;
if (fpExport == NULL) return -1;
/*
* CSV fields:
* LogfileName,Date,Time,Source,Type,Category,SourceID,User,Computer,Description,Data
*/
time_t eventTimeStruct = (time_t) pRecord->dwEventDateTime;
strftime(eventDate, 255, "%F", localtime(&eventTimeStruct));
strftime(eventTime, 255, "%r", localtime(&eventTimeStruct));
fprintf(fpExport, "%s,%s,%s,%s,%s,%s,%d,%s,%s,\"%s\",\"%s\"\n",
IsNullOrEmptyString(pRecord->pszEventTableCategoryId) ? "" : (PSTR)pRecord->pszEventTableCategoryId,
eventDate, //PSTR
eventTime, //PSTR
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (PSTR)pRecord->pszEventSource,
IsNullOrEmptyString(pRecord->pszEventType) ? "" : (PSTR)pRecord->pszEventType,
IsNullOrEmptyString(pRecord->pszEventCategory) ? "" : (PSTR)pRecord->pszEventCategory,
pRecord->dwEventSourceId, //DWORD
IsNullOrEmptyString(pRecord->pszUser) ? "" : (PSTR)pRecord->pszUser,
IsNullOrEmptyString(pRecord->pszComputer) ? "" : (PSTR)pRecord->pszComputer,
IsNullOrEmptyString(pRecord->pszDescription) ? "" : (PSTR)pRecord->pszDescription,
IsNullOrEmptyString(pRecord->pszData) ? "" : (PSTR)pRecord->pszData);
return dwError;
}
static
DWORD
PrintEventRecordTableRow (
PEVENT_LOG_RECORD pRecord,
FILE* fp
)
{
DWORD dwError = 0;
DWORD i = 0;
char eventDate[256];
char eventTime[256];
char buf[256];
if (pRecord == NULL) return -1;
if (fp == NULL) return -1;
//TableRow fields: RecordID,Type,Date,Time,Source,Category,EventID,User
time_t eventTimeStruct = (time_t) pRecord->dwEventDateTime;
strftime(eventDate, 255, "%F", localtime(&eventTimeStruct));
strftime(eventTime, 255, "%r", localtime(&eventTimeStruct));
memset(buf, ' ', 255);
sprintf(buf, "%d", pRecord->dwEventRecordId);
sprintf(buf+TABLOC_TYPE, "%s%s", TABLOC_BORDER,
IsNullOrEmptyString(pRecord->pszEventType) ? "" : (PSTR)pRecord->pszEventType);
sprintf(buf+TABLOC_DATE, "%s%s", TABLOC_BORDER,
eventDate);
sprintf(buf+TABLOC_TIME, "%s%s", TABLOC_BORDER,
eventTime);
sprintf(buf+TABLOC_SOURCE, "%s%s", TABLOC_BORDER,
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (PSTR)pRecord->pszEventSource);
sprintf(buf+TABLOC_CATEGORY, "%s%s", TABLOC_BORDER,
IsNullOrEmptyString(pRecord->pszEventCategory) ? "" : (PSTR)pRecord->pszEventCategory);
sprintf(buf+TABLOC_SOURCE_ID, "%s%d", TABLOC_BORDER,
pRecord->dwEventSourceId);
sprintf(buf+TABLOC_USER, "%s%s", TABLOC_BORDER,
IsNullOrEmptyString(pRecord->pszUser) ? "" : (PSTR)pRecord->pszUser);
for (i = 0; i <= TABLOC_USER; i++)
{
if (buf[i] == (char)0)
{
buf[i] = ' ';
}
}
fprintf(fp, "%s\n", buf);
return dwError;
}
DWORD
PrintEventRecords(
FILE* output,
EVENT_LOG_RECORD* eventRecords,
DWORD nRecords,
PDWORD totalRecords
)
{
char eventDate[256];
char eventTime[256];
DWORD dwError = 0;
DWORD totalRecordsLocal = *totalRecords;
int iRecord = 0;
for (iRecord = 0; iRecord < nRecords; iRecord++)
{
EVENT_LOG_RECORD* pRecord = &(eventRecords[iRecord]);
time_t eventTimeStruct = (time_t) pRecord->dwEventDateTime;
strftime(eventDate, 255, "%F", localtime(&eventTimeStruct));
strftime(eventTime, 255, "%r", localtime(&eventTimeStruct));
printf("Event Record: (%d/%d) (%d total)\n", iRecord+1, nRecords, ++totalRecordsLocal);
printf("========================================\n");
printf("Event Record ID......... %d\n", pRecord->dwEventRecordId);
printf("Event Table Category.... %s\n",
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (char*) (pRecord->pszEventTableCategoryId));
printf("Event Type.............. %s\n",
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (char*) (pRecord->pszEventType));
printf("Event Date.............. %s\n", eventDate);
printf("Event Time.............. %s\n", eventTime);
printf("Event Source............ %s\n",
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (char*) (pRecord->pszEventSource));
printf("Event Category.......... %s\n",
IsNullOrEmptyString(pRecord->pszEventSource) ? "" : (char*) (pRecord->pszEventCategory));
printf("Event Source ID......... %d\n", pRecord->dwEventSourceId);
printf("Event User.............. %s\n",
IsNullOrEmptyString(pRecord->pszUser) ? "" : (char*) (pRecord->pszUser));
printf("Event Computer.......... %s\n",
IsNullOrEmptyString(pRecord->pszComputer) ? "" : (char*) (pRecord->pszComputer));
printf("Event Description....... %s\n",
IsNullOrEmptyString(pRecord->pszDescription) ? "" : (char*) (pRecord->pszDescription));
printf("Event Data.............. %s\n",
IsNullOrEmptyString(pRecord->pszData) ? "" : (char*) (pRecord->pszData));
printf("========================================\n");
}
*totalRecords = totalRecordsLocal;
return dwError;
}
DWORD
PrintEventRecordsTable(
FILE* output,
EVENT_LOG_RECORD* eventRecords,
DWORD nRecords,
PDWORD totalRecords
)
{
DWORD i = 0;
DWORD dwError = 0;
DWORD totalRecordsLocal = *totalRecords;
char buf[256];
memset(buf, ' ', 255);
sprintf(buf, "Id: ");
sprintf(buf+TABLOC_TYPE, "%sType", TABLOC_BORDER);
sprintf(buf+TABLOC_DATE, "%sDate", TABLOC_BORDER);
sprintf(buf+TABLOC_TIME, "%sTime", TABLOC_BORDER);
sprintf(buf+TABLOC_SOURCE, "%sSource", TABLOC_BORDER);
sprintf(buf+TABLOC_CATEGORY, "%sCategory", TABLOC_BORDER);
sprintf(buf+TABLOC_SOURCE_ID,"%sEvent", TABLOC_BORDER);
sprintf(buf+TABLOC_USER,"%sUser", TABLOC_BORDER);
for (i = 0; i <= TABLOC_USER; i++)
{
if (buf[i] == (char)0)
{
buf[i] = ' ';
}
}
fprintf(output, "%s\n", buf);
for (i = 0; i < nRecords; i++)
{
dwError = PrintEventRecordTableRow(&(eventRecords[i]), output);
BAIL_ON_EVT_ERROR(dwError);
totalRecordsLocal++;
}
error:
*totalRecords = totalRecordsLocal;
return dwError;
}
DWORD
ReadAndExportEvents(
PEVENT_LOG_HANDLE pEventLogHandle,
FILE* fpExport
)
{
DWORD dwError = 0;
DWORD i = 0;
const DWORD pageSize = 2000;
DWORD currentEntry = 0;
DWORD entriesRead = 0;
EVENT_LOG_RECORD* records = NULL;
if (fpExport == NULL) return -1;
if (pEventLogHandle == NULL) return -1;
const char* sqlFilterChar = "eventRecordId > 0";
wchar16_t* sqlFilter = NULL;
dwError = EVTAllocateMemory(sizeof(wchar16_t)*(1+strlen(sqlFilterChar)), (PVOID*)(&sqlFilter));
BAIL_ON_EVT_ERROR(dwError);
sw16printf(sqlFilter, "%s", sqlFilterChar);
/*
* CSV fields:
* LogfileName,Date,Time,Source,Type,Category,SourceID,User,Computer,Description,Data
*/
fprintf(fpExport, "LogfileName,");
fprintf(fpExport, "Date,");
fprintf(fpExport, "Time,");
fprintf(fpExport, "Source,");
fprintf(fpExport, "Type,");
fprintf(fpExport, "Category,");
fprintf(fpExport, "SourceId,");
fprintf(fpExport, "User,");
fprintf(fpExport, "Computer,");
fprintf(fpExport, "Description,");
fprintf(fpExport, "Data\n");
do
{
dwError = LWIReadEventLog((HANDLE)pEventLogHandle, currentEntry, pageSize, sqlFilter, &entriesRead, &records);
BAIL_ON_EVT_ERROR(dwError);
for (i = 0; i < entriesRead; i++) {
dwError = ExportEventRecord(&(records[i]), fpExport);
BAIL_ON_EVT_ERROR(dwError);
}
fflush(fpExport);
currentEntry += entriesRead;
} while (entriesRead == pageSize && entriesRead > 0);
cleanup:
RPCFreeMemory(records);
EVTFreeMemory(records);
return dwError;
error:
goto cleanup;
}