advapi32/tests: Add tests for reading and writing to a real eventlog.
This commit is contained in:
parent
aa9002755a
commit
1bbb880fd9
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue