advapi32/tests: Add tests for reading and writing to a real eventlog.

oldstable
Paul Vriens 2009-11-13 13:24:11 +01:00 committed by Alexandre Julliard
parent aa9002755a
commit 1bbb880fd9
1 changed files with 423 additions and 0 deletions

View File

@ -24,15 +24,19 @@
#include "winbase.h"
#include "winerror.h"
#include "winnt.h"
#include "winreg.h"
#include "sddl.h"
#include "wine/test.h"
static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*);
static BOOL (WINAPI *pGetEventLogInformation)(HANDLE,DWORD,LPVOID,DWORD,LPDWORD);
static void init_function_pointers(void)
{
HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid");
pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation");
}
@ -611,6 +615,417 @@ static void test_clear(void)
ok(DeleteFileA(backup), "Could not delete the backup file\n");
}
static const char eventlogsvc[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog";
static const char eventlogname[] = "Wine";
static const char eventsources[][11] = { "WineSrc", "WineSrc1", "WineSrc20", "WineSrc300" };
static BOOL create_new_eventlog(void)
{
HKEY key, eventkey;
BOOL bret = FALSE;
LONG lret;
int i;
/* First create our eventlog */
lret = RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
/* FIXME: Wine stops here */
if (lret != ERROR_SUCCESS)
{
skip("Could not open the EventLog service registry key\n");
return FALSE;
}
lret = RegCreateKeyA(key, eventlogname, &eventkey);
if (lret != ERROR_SUCCESS)
{
skip("Could not create the eventlog '%s' registry key\n", eventlogname);
goto cleanup;
}
/* Create some event sources, the registry value 'Sources' is updated automatically */
for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++)
{
HKEY srckey;
lret = RegCreateKeyA(eventkey, eventsources[i], &srckey);
if (lret != ERROR_SUCCESS)
{
skip("Could not create the eventsource '%s' registry key\n", eventsources[i]);
goto cleanup;
}
RegFlushKey(srckey);
RegCloseKey(srckey);
}
bret = TRUE;
/* The flushing of the registry (here and above) gives us some assurance
* that we are not to quickly writing events as 'Sources' could still be
* not updated.
*/
RegFlushKey(eventkey);
cleanup:
RegCloseKey(eventkey);
RegCloseKey(key);
return bret;
}
static const char *one_string[] = { "First string" };
static const char *two_strings[] = { "First string", "Second string" };
static const struct
{
const char *evt_src;
WORD evt_type;
WORD evt_cat;
DWORD evt_id;
BOOL evt_sid;
WORD evt_numstrings;
const char **evt_strings;
} read_write [] =
{
{ eventlogname, EVENTLOG_INFORMATION_TYPE, 1, 1, FALSE, 1, one_string },
{ eventsources[0], EVENTLOG_WARNING_TYPE, 1, 2, FALSE, 0, NULL },
{ eventsources[1], EVENTLOG_AUDIT_FAILURE, 1, 3, FALSE, 2, two_strings },
{ eventsources[2], EVENTLOG_ERROR_TYPE, 1, 4, FALSE, 0, NULL },
{ eventsources[3], EVENTLOG_WARNING_TYPE, 1, 5, FALSE, 1, one_string },
{ eventlogname, EVENTLOG_SUCCESS, 2, 6, TRUE, 2, two_strings },
{ eventsources[0], EVENTLOG_AUDIT_FAILURE, 2, 7, TRUE, 0, NULL },
{ eventsources[1], EVENTLOG_AUDIT_SUCCESS, 2, 8, TRUE, 2, two_strings },
{ eventsources[2], EVENTLOG_WARNING_TYPE, 2, 9, TRUE, 0, NULL },
{ eventsources[3], EVENTLOG_ERROR_TYPE, 2, 10, TRUE, 1, one_string }
};
static void test_readwrite(void)
{
HANDLE handle;
PSID user;
DWORD sidsize, count;
BOOL ret, sidavailable;
BOOL on_vista = FALSE; /* Used to indicate Vista or higher */
int i;
char localcomputer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD len = sizeof(localcomputer);
if (pCreateWellKnownSid)
{
sidsize = SECURITY_MAX_SID_SIZE;
user = HeapAlloc(GetProcessHeap(), 0, sidsize);
SetLastError(0xdeadbeef);
pCreateWellKnownSid(WinInteractiveSid, NULL, user, &sidsize);
sidavailable = TRUE;
}
else
{
win_skip("Skipping some SID related tests\n");
sidavailable = FALSE;
user = NULL;
}
GetComputerNameA(localcomputer, &len);
/* Write an event with an incorrect event type. This will fail on Windows 7
* but succeed on all others, hence it's not part of the struct.
*/
handle = OpenEventLogA(NULL, eventlogname);
SetLastError(0xdeadbeef);
ret = ReportEvent(handle, 0x20, 0, 0, NULL, 0, 0, NULL, NULL);
if (!ret && GetLastError() == ERROR_CRC)
{
win_skip("Win7 fails when using incorrect event types\n");
ret = ReportEvent(handle, 0, 0, 0, NULL, 0, 0, NULL, NULL);
}
ok(ret, "Expected success : %d\n", GetLastError());
/* This will clear the eventlog. The record numbering for new
* events however differs on Vista+. Before Vista the first
* event would be numbered 1, on Vista+ it's now 2 as we already
* had one event.
*/
ClearEventLogA(handle, NULL);
CloseEventLog(handle);
/* Write a bunch of events while using different event sources */
for (i = 0; i < sizeof(read_write)/sizeof(read_write[0]); i++)
{
DWORD oldest;
BOOL run_sidtests = read_write[i].evt_sid & sidavailable;
/* We don't need to use RegisterEventSource to report events */
if (i % 2)
handle = OpenEventLogA(NULL, read_write[i].evt_src);
else
handle = RegisterEventSourceA(NULL, read_write[i].evt_src);
ok(handle != NULL, "Expected a handle\n");
SetLastError(0xdeadbeef);
ret = ReportEvent(handle, read_write[i].evt_type, read_write[i].evt_cat,
read_write[i].evt_id, run_sidtests ? user : NULL,
read_write[i].evt_numstrings, 0, read_write[i].evt_strings, NULL);
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(count == (i + 1), "Expected %d records, got %d\n", i + 1, count);
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(handle, &oldest);
ok(ret, "Expected success\n");
ok(oldest == 1 ||
oldest == 2, /* Vista+ */
"Expected oldest to be 1 or 2, got %d\n", oldest);
if (oldest == 2)
on_vista = TRUE;
if (i % 2)
ret = CloseEventLog(handle);
else
ret = DeregisterEventSource(handle);
ok(ret, "Expected success : %d\n", GetLastError());
}
handle = OpenEventLogA(NULL, eventlogname);
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(count == i, "Expected %d records, got %d\n", i, count);
CloseEventLog(handle);
if (count == 0)
{
skip("No events were written to the eventlog\n");
return;
}
/* Report only once */
if (on_vista)
skip("There is no DWORD alignment for UserSid on Vista or higher\n");
/* Read all events from our created eventlog, one by one */
handle = OpenEventLogA(NULL, eventlogname);
i = 0;
for (;;)
{
void *buf;
DWORD read, needed;
EVENTLOGRECORD *record;
char *sourcename, *computername;
int k;
char *ptr;
BOOL run_sidtests = read_write[i].evt_sid & sidavailable;
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
if (!ret && GetLastError() == ERROR_HANDLE_EOF)
{
HeapFree(GetProcessHeap(), 0, buf);
break;
}
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INVALID_PARAMETER, got %d\n",GetLastError());
buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, needed, &read, &needed);
ok(ret, "Expected success: %d\n", GetLastError());
record = (EVENTLOGRECORD *)buf;
ok(record->Length == read,
"Expected %d, got %d\n", read, record->Length);
ok(record->Reserved == 0x654c664c,
"Expected 0x654c664c, got %d\n", record->Reserved);
ok(record->RecordNumber == i + 1 ||
(on_vista && (record->RecordNumber == i + 2)),
"Expected %d or %d, got %d\n", i + 1, i + 2, record->RecordNumber);
ok(record->EventID == read_write[i].evt_id,
"Expected %d, got %d\n", read_write[i].evt_id, record->EventID);
ok(record->EventType == read_write[i].evt_type,
"Expected %d, got %d\n", read_write[i].evt_type, record->EventType);
ok(record->NumStrings == read_write[i].evt_numstrings,
"Expected %d, got %d\n", read_write[i].evt_numstrings, record->NumStrings);
ok(record->EventCategory == read_write[i].evt_cat,
"Expected %d, got %d\n", read_write[i].evt_cat, record->EventCategory);
sourcename = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD));
ok(!lstrcmpA(sourcename, read_write[i].evt_src), "Expected '%s', got '%s'\n",
read_write[i].evt_src, sourcename);
computername = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1);
ok(!lstrcmpiA(computername, localcomputer), "Expected '%s', got '%s'\n",
localcomputer, computername);
/* Before Vista, UserSid was aligned on a DWORD boundary. Next to that if
* no padding was actually required a 0 DWORD was still used for padding. No
* application should be relying on the padding as we are working with offsets
* anyway.
*/
if (!on_vista)
{
DWORD calculated_sidoffset = sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1 + lstrlenA(computername) + 1;
/* We are already DWORD aligned, there should still be some padding */
if ((((UINT_PTR)buf + calculated_sidoffset) % sizeof(DWORD)) == 0)
ok(*(DWORD_PTR *)((BYTE *)buf + calculated_sidoffset) == 0, "Expected 0\n");
ok((((UINT_PTR)buf + record->UserSidOffset) % sizeof(DWORD)) == 0, "Expected DWORD alignment\n");
}
if (run_sidtests)
{
ok(record->UserSidLength == sidsize, "Expected %d, got %d\n", sidsize, record->UserSidLength);
}
else
{
ok(record->StringOffset == record->UserSidOffset, "Expected offsets to be the same\n");
ok(record->UserSidLength == 0, "Expected 0, got %d\n", record->UserSidLength);
}
ok(record->DataLength == 0, "Expected 0, got %d\n", record->DataLength);
ptr = (char *)((BYTE *)buf + record->StringOffset);
for (k = 0; k < record->NumStrings; k++)
{
ok(!lstrcmpA(ptr, two_strings[k]), "Expected '%s', got '%s'\n", two_strings[k], ptr);
ptr += lstrlenA(ptr) + 1;
}
ok(record->Length == *(DWORD_PTR *)((BYTE *)buf + record->Length - sizeof(DWORD)),
"Expected the closing DWORD to contain the length of the record\n");
HeapFree(GetProcessHeap(), 0, buf);
i++;
}
CloseEventLog(handle);
HeapFree(GetProcessHeap(), 0, user);
/* Test clearing a real eventlog */
handle = OpenEventLogA(NULL, eventlogname);
SetLastError(0xdeadbeef);
ret = ClearEventLogA(handle, NULL);
ok(ret, "Expected success\n");
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(count == 0, "Expected an empty eventlog, got %d records\n", count);
CloseEventLog(handle);
}
/* Before Vista:
*
* Creating an eventlog on Windows (via the registry) automatically leads
* to creation of a REG_MULTI_SZ named 'Sources'. This value lists all the
* potential event sources for this eventlog. 'Sources' is automatically
* updated when a new key (aka event source) is created.
*
* Although the updating of registry keys is almost instantaneously, we
* check it after some other tests to assure we are not querying the
* registry or file system to quickly.
*
* NT4 and higher:
*
* The eventlog file itself is also automatically created, even before we
* start writing events.
*/
static char eventlogfile[MAX_PATH];
static void test_autocreation(void)
{
HKEY key, eventkey;
DWORD type, size;
LONG ret;
int i;
char *p;
char sources[sizeof(eventsources)];
char sysdir[MAX_PATH];
RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
RegOpenKeyA(key, eventlogname, &eventkey);
size = sizeof(sources);
sources[0] = 0;
ret = RegQueryValueExA(eventkey, "Sources", NULL, &type, (LPBYTE)sources, &size);
if (ret == ERROR_SUCCESS)
{
char sources_verify[sizeof(eventsources)];
ok(type == REG_MULTI_SZ, "Expected a REG_MULTI_SZ, got %d\n", type);
/* Build the expected string */
memset(sources_verify, 0, sizeof(sources_verify));
p = sources_verify;
for (i = sizeof(eventsources)/sizeof(eventsources[0]); i > 0; i--)
{
lstrcpyA(p, eventsources[i - 1]);
p += (lstrlenA(eventsources[i - 1]) + 1);
}
lstrcpyA(p, eventlogname);
ok(!memcmp(sources, sources_verify, size), "Expected a correct 'Sources' value\n");
}
RegCloseKey(eventkey);
RegCloseKey(key);
/* On Windows we also automatically get an eventlog file */
GetSystemDirectoryA(sysdir, sizeof(sysdir));
/* NT4 - W2K3 */
lstrcpyA(eventlogfile, sysdir);
lstrcatA(eventlogfile, "\\config\\");
lstrcatA(eventlogfile, eventlogname);
lstrcatA(eventlogfile, ".evt");
if (GetFileAttributesA(eventlogfile) == INVALID_FILE_ATTRIBUTES)
{
/* Vista+ */
lstrcpyA(eventlogfile, sysdir);
lstrcatA(eventlogfile, "\\winevt\\Logs\\");
lstrcatA(eventlogfile, eventlogname);
lstrcatA(eventlogfile, ".evtx");
}
ok(GetFileAttributesA(eventlogfile) != INVALID_FILE_ATTRIBUTES,
"Expected an eventlog file\n");
}
static void cleanup_eventlog(void)
{
BOOL bret;
LONG lret;
HKEY key;
int i;
char winesvc[MAX_PATH];
/* Delete the registry tree */
lstrcpyA(winesvc, eventlogsvc);
lstrcatA(winesvc, "\\");
lstrcatA(winesvc, eventlogname);
RegOpenKeyA(HKEY_LOCAL_MACHINE, winesvc, &key);
for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++)
RegDeleteKeyA(key, eventsources[i]);
RegDeleteValueA(key, "Sources");
RegCloseKey(key);
lret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, winesvc);
todo_wine
ok(lret == ERROR_SUCCESS, "Could not delete the registry tree : %d\n", lret);
/* A handle to the eventlog is locked by services.exe. We can only
* delete the eventlog file after reboot.
*/
bret = MoveFileExA(eventlogfile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
todo_wine
ok(bret, "Expected MoveFileEx to succeed: %d\n", GetLastError());
}
START_TEST(eventlog)
{
SetLastError(0xdeadbeef);
@ -632,4 +1047,12 @@ START_TEST(eventlog)
test_openbackup();
test_read();
test_clear();
/* Functional tests */
if (create_new_eventlog())
{
test_readwrite();
test_autocreation();
}
cleanup_eventlog();
}