--- /dev/null
+/*
+ * Unit tests for Event Logging functions
+ *
+ * Copyright (c) 2009 Paul Vriens
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#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 BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD);
+static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID *);
+static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID);
+
+static void init_function_pointers(void)
+{
+ HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
+ HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
+
+ pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid");
+ pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation");
+
+ pGetComputerNameExA = (void*)GetProcAddress(hkernel32, "GetComputerNameExA");
+ pWow64DisableWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64DisableWow64FsRedirection");
+ pWow64RevertWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64RevertWow64FsRedirection");
+}
+
+static void create_backup(const char *filename)
+{
+ HANDLE handle;
+
+ DeleteFileA(filename);
+ handle = OpenEventLogA(NULL, "Application");
+ BackupEventLogA(handle, filename);
+ CloseEventLog(handle);
+
+ todo_wine
+ ok(GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n");
+}
+
+static void test_open_close(void)
+{
+ HANDLE handle;
+ BOOL ret;
+
+ SetLastError(0xdeadbeef);
+ ret = CloseEventLog(NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE ||
+ GetLastError() == ERROR_NOACCESS, /* W2K */
+ "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenEventLogA(NULL, NULL);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenEventLogA("IDontExist", NULL);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenEventLogA("IDontExist", "deadbeef");
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
+ GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
+ "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
+
+ /* This one opens the Application log */
+ handle = OpenEventLogA(NULL, "deadbeef");
+ ok(handle != NULL, "Expected a handle\n");
+ ret = CloseEventLog(handle);
+ ok(ret, "Expected success\n");
+ /* Close a second time */
+ SetLastError(0xdeadbeef);
+ ret = CloseEventLog(handle);
+ todo_wine
+ {
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+ }
+
+ /* Empty servername should be read as local server */
+ handle = OpenEventLogA("", "Application");
+ ok(handle != NULL, "Expected a handle\n");
+ CloseEventLog(handle);
+
+ handle = OpenEventLogA(NULL, "Application");
+ ok(handle != NULL, "Expected a handle\n");
+ CloseEventLog(handle);
+}
+
+static void test_info(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ DWORD needed;
+ EVENTLOG_FULL_INFORMATION efi;
+
+ if (!pGetEventLogInformation)
+ {
+ /* NT4 */
+ win_skip("GetEventLogInformation is not available\n");
+ return;
+ }
+ SetLastError(0xdeadbeef);
+ ret = pGetEventLogInformation(NULL, 1, NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_LEVEL, "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pGetEventLogInformation(NULL, EVENTLOG_FULL_INFO, NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ handle = OpenEventLogA(NULL, "Application");
+
+ SetLastError(0xdeadbeef);
+ ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, &needed);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, 0, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ needed = 0xdeadbeef;
+ efi.dwFull = 0xdeadbeef;
+ ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, 0, &needed);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+ ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed);
+ ok(efi.dwFull == 0xdeadbeef, "Expected no change to the dwFull member\n");
+
+ /* Not that we care, but on success last error is set to ERROR_IO_PENDING */
+ efi.dwFull = 0xdeadbeef;
+ needed *= 2;
+ ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, needed, &needed);
+ ok(ret, "Expected success\n");
+ ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed);
+ ok(efi.dwFull == 0 || efi.dwFull == 1, "Expected 0 (not full) or 1 (full), got %d\n", efi.dwFull);
+
+ CloseEventLog(handle);
+}
+
+static void test_count(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ DWORD count;
+ const char backup[] = "backup.evt";
+
+ SetLastError(0xdeadbeef);
+ ret = GetNumberOfEventLogRecords(NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ count = 0xdeadbeef;
+ ret = GetNumberOfEventLogRecords(NULL, &count);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+ ok(count == 0xdeadbeef, "Expected count to stay unchanged\n");
+
+ handle = OpenEventLogA(NULL, "Application");
+
+ SetLastError(0xdeadbeef);
+ ret = GetNumberOfEventLogRecords(handle, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ count = 0xdeadbeef;
+ ret = GetNumberOfEventLogRecords(handle, &count);
+ ok(ret, "Expected success\n");
+ ok(count != 0xdeadbeef, "Expected the number of records\n");
+
+ CloseEventLog(handle);
+
+ /* Make a backup eventlog to work with */
+ create_backup(backup);
+
+ handle = OpenBackupEventLogA(NULL, backup);
+ todo_wine
+ ok(handle != NULL, "Expected a handle\n");
+
+ /* Does GetNumberOfEventLogRecords work with backup eventlogs? */
+ count = 0xdeadbeef;
+ ret = GetNumberOfEventLogRecords(handle, &count);
+ todo_wine
+ {
+ ok(ret, "Expected success\n");
+ ok(count != 0xdeadbeef, "Expected the number of records\n");
+ }
+
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+}
+
+static void test_oldest(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ DWORD oldest;
+ const char backup[] = "backup.evt";
+
+ SetLastError(0xdeadbeef);
+ ret = GetOldestEventLogRecord(NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ oldest = 0xdeadbeef;
+ ret = GetOldestEventLogRecord(NULL, &oldest);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+ ok(oldest == 0xdeadbeef, "Expected oldest to stay unchanged\n");
+
+ handle = OpenEventLogA(NULL, "Application");
+
+ SetLastError(0xdeadbeef);
+ ret = GetOldestEventLogRecord(handle, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ oldest = 0xdeadbeef;
+ ret = GetOldestEventLogRecord(handle, &oldest);
+ ok(ret, "Expected success\n");
+ ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n");
+
+ CloseEventLog(handle);
+
+ /* Make a backup eventlog to work with */
+ create_backup(backup);
+
+ handle = OpenBackupEventLogA(NULL, backup);
+ todo_wine
+ ok(handle != NULL, "Expected a handle\n");
+
+ /* Does GetOldestEventLogRecord work with backup eventlogs? */
+ oldest = 0xdeadbeef;
+ ret = GetOldestEventLogRecord(handle, &oldest);
+ todo_wine
+ {
+ ok(ret, "Expected success\n");
+ ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n");
+ }
+
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+}
+
+static void test_backup(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ const char backup[] = "backup.evt";
+ const char backup2[] = "backup2.evt";
+
+ SetLastError(0xdeadbeef);
+ ret = BackupEventLogA(NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = BackupEventLogA(NULL, backup);
+ ok(!ret, "Expected failure\n");
+ ok(GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n");
+
+ handle = OpenEventLogA(NULL, "Application");
+
+ SetLastError(0xdeadbeef);
+ ret = BackupEventLogA(handle, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ ret = BackupEventLogA(handle, backup);
+ ok(ret, "Expected success\n");
+ todo_wine
+ ok(GetFileAttributesA(backup) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n");
+
+ /* Try to overwrite */
+ SetLastError(0xdeadbeef);
+ ret = BackupEventLogA(handle, backup);
+ todo_wine
+ {
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_ALREADY_EXISTS, "Expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
+ }
+
+ CloseEventLog(handle);
+
+ /* Can we make a backup of a backup? */
+ handle = OpenBackupEventLogA(NULL, backup);
+ todo_wine
+ ok(handle != NULL, "Expected a handle\n");
+
+ ret = BackupEventLogA(handle, backup2);
+ todo_wine
+ {
+ ok(ret, "Expected success\n");
+ ok(GetFileAttributesA(backup2) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n");
+ }
+
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+ DeleteFileA(backup2);
+}
+
+static void test_read(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ DWORD count, toread, read, needed;
+ void *buf;
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ read = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(read == 0xdeadbeef, "Expected 'read' parameter to remain unchanged\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ needed = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, &needed);
+ ok(!ret, "Expected failure\n");
+ ok(needed == 0xdeadbeef, "Expected 'needed' parameter to remain unchanged\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ /* 'read' and 'needed' are only filled when the needed buffer size is passed back or when the call succeeds */
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ buf = NULL;
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ handle = OpenEventLogA(NULL, "Application");
+
+ /* Show that we need the proper dwFlags with a (for the rest) proper call */
+ buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, 0, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ /* First check if there are any records (in practice only on Wine: FIXME) */
+ count = 0;
+ GetNumberOfEventLogRecords(handle, &count);
+ if (!count)
+ {
+ skip("No records in the 'Application' log\n");
+ CloseEventLog(handle);
+ return;
+ }
+
+ /* Get the buffer size for the first record */
+ buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
+ read = needed = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+ ok(!ret, "Expected failure\n");
+ ok(read == 0, "Expected no bytes read\n");
+ ok(needed > sizeof(EVENTLOGRECORD), "Expected the needed buffersize to be bigger than sizeof(EVENTLOGRECORD)\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ /* Read the first record */
+ toread = needed;
+ buf = HeapReAlloc(GetProcessHeap(), 0, buf, toread);
+ read = needed = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, buf, toread, &read, &needed);
+ ok(ret, "Expected success\n");
+ ok(read == toread ||
+ broken(read < toread), /* NT4 wants a buffer size way bigger than just 1 record */
+ "Expected the requested size to be read\n");
+ ok(needed == 0, "Expected no extra bytes to be read\n");
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ CloseEventLog(handle);
+}
+
+static void test_openbackup(void)
+{
+ HANDLE handle, handle2, file;
+ DWORD written;
+ const char backup[] = "backup.evt";
+ const char text[] = "Just some text";
+
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA(NULL, NULL);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA(NULL, "idontexist.evt");
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA("IDontExist", NULL);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA("IDontExist", "idontexist.evt");
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
+ GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
+ "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
+
+ /* Make a backup eventlog to work with */
+ create_backup(backup);
+
+ /* FIXME: Wine stops here */
+ if (GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES)
+ {
+ skip("We don't have a backup eventlog to work with\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA("IDontExist", backup);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
+ GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
+ "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
+
+ /* Empty servername should be read as local server */
+ handle = OpenBackupEventLogA("", backup);
+ ok(handle != NULL, "Expected a handle\n");
+ CloseEventLog(handle);
+
+ handle = OpenBackupEventLogA(NULL, backup);
+ ok(handle != NULL, "Expected a handle\n");
+
+ /* Can we open that same backup eventlog more than once? */
+ handle2 = OpenBackupEventLogA(NULL, backup);
+ ok(handle2 != NULL, "Expected a handle\n");
+ ok(handle2 != handle, "Didn't expect the same handle\n");
+ CloseEventLog(handle2);
+
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+
+ /* Is there any content checking done? */
+ file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ CloseHandle(file);
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA(NULL, backup);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
+ GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, /* Vista and Win7 */
+ "Expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+
+ file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ WriteFile(file, text, sizeof(text), &written, NULL);
+ CloseHandle(file);
+ SetLastError(0xdeadbeef);
+ handle = OpenBackupEventLogA(NULL, backup);
+ ok(handle == NULL, "Didn't expect a handle\n");
+ ok(GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, "Expected ERROR_EVENTLOG_FILE_CORRUPT, got %d\n", GetLastError());
+ CloseEventLog(handle);
+ DeleteFileA(backup);
+}
+
+static void test_clear(void)
+{
+ HANDLE handle;
+ BOOL ret;
+ const char backup[] = "backup.evt";
+ const char backup2[] = "backup2.evt";
+
+ SetLastError(0xdeadbeef);
+ ret = ClearEventLogA(NULL, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ /* Make a backup eventlog to work with */
+ create_backup(backup);
+
+ SetLastError(0xdeadbeef);
+ ret = ClearEventLogA(NULL, backup);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ handle = OpenBackupEventLogA(NULL, backup);
+ todo_wine
+ ok(handle != NULL, "Expected a handle\n");
+
+ /* A real eventlog would fail with ERROR_ALREADY_EXISTS */
+ SetLastError(0xdeadbeef);
+ ret = ClearEventLogA(handle, backup);
+ ok(!ret, "Expected failure\n");
+ /* The eventlog service runs under an account that doesn't have the necessary
+ * permissions on the users home directory on a default Vista+ system.
+ */
+ ok(GetLastError() == ERROR_INVALID_HANDLE ||
+ GetLastError() == ERROR_ACCESS_DENIED, /* Vista+ */
+ "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ /* Show that ClearEventLog only works for real eventlogs. */
+ SetLastError(0xdeadbeef);
+ ret = ClearEventLogA(handle, backup2);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+ ok(GetFileAttributesA(backup2) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n");
+
+ SetLastError(0xdeadbeef);
+ ret = ClearEventLogA(handle, NULL);
+ ok(!ret, "Expected failure\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+ CloseEventLog(handle);
+ todo_wine
+ 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, W2K8 or Win7 */
+ int i;
+ char *localcomputer = NULL;
+ DWORD size;
+
+ 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;
+ }
+
+ /* 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);
+ if (!handle)
+ {
+ /* Intermittently seen on NT4 when tests are run immediately after boot */
+ win_skip("Could not get a handle to the eventlog\n");
+ goto cleanup;
+ }
+
+ count = 0xdeadbeef;
+ GetNumberOfEventLogRecords(handle, &count);
+ if (count != 0)
+ {
+ /* Needed for W2K3 without a service pack */
+ win_skip("We most likely opened the Application eventlog\n");
+ CloseEventLog(handle);
+ Sleep(2000);
+
+ handle = OpenEventLogA(NULL, eventlogname);
+ count = 0xdeadbeef;
+ GetNumberOfEventLogRecords(handle, &count);
+ if (count != 0)
+ {
+ win_skip("We didn't open our new eventlog\n");
+ CloseEventLog(handle);
+ goto cleanup;
+ }
+ }
+
+ 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);
+ }
+ else
+ {
+ void *buf;
+ DWORD read, needed;
+ EVENTLOGRECORD *record;
+
+ /* Needed to catch earlier Vista (with no ServicePack for example) */
+ buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
+ ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
+
+ buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed);
+ ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
+ 0, buf, needed, &read, &needed);
+
+ record = (EVENTLOGRECORD *)buf;
+
+ /* Vista and W2K8 return EVENTLOG_SUCCESS, Windows versions before return
+ * the written eventtype (0x20 in this case).
+ */
+ if (record->EventType == EVENTLOG_SUCCESS)
+ on_vista = TRUE;
+
+ HeapFree(GetProcessHeap(), 0, buf);
+ }
+ ok(ret, "Expected success : %d\n", GetLastError());
+
+ /* This will clear the eventlog. The record numbering for new
+ * events however differs on Vista SP1+. Before Vista the first
+ * event would be numbered 1, on Vista SP1+ it's higher as we already
+ * had at least one event (more in case of multiple test runs without
+ * a reboot).
+ */
+ 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 > 1 && oldest != 0xdeadbeef), /* Vista SP1+, W2K8 and Win7 */
+ "Expected oldest to be 1 or higher, got %d\n", oldest);
+ if (oldest > 1 && oldest != 0xdeadbeef)
+ 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");
+ goto cleanup;
+ }
+
+ /* Report only once */
+ if (on_vista)
+ skip("There is no DWORD alignment enforced for UserSid on Vista, W2K8 or Win7\n");
+
+ if (on_vista && pGetComputerNameExA)
+ {
+ /* New Vista+ behavior */
+ size = 0;
+ SetLastError(0xdeadbeef);
+ pGetComputerNameExA(ComputerNameDnsFullyQualified, NULL, &size);
+ localcomputer = HeapAlloc(GetProcessHeap(), 0, size);
+ pGetComputerNameExA(ComputerNameDnsFullyQualified, localcomputer, &size);
+ }
+ else
+ {
+ size = MAX_COMPUTERNAME_LENGTH + 1;
+ localcomputer = HeapAlloc(GetProcessHeap(), 0, size);
+ GetComputerNameA(localcomputer, &size);
+ }
+
+ /* 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 + 1)),
+ "Expected %d or higher, got %d\n", i + 1, 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 *)((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 *)((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);
+
+ /* 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);
+
+cleanup:
+ HeapFree(GetProcessHeap(), 0, localcomputer);
+ HeapFree(GetProcessHeap(), 0, user);
+}
+
+/* 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];
+ void *redir = 0;
+
+ 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 (size : %d)\n", size);
+ }
+
+ RegCloseKey(eventkey);
+ RegCloseKey(key);
+
+ /* The directory that holds the eventlog files could be redirected */
+ if (pWow64DisableWow64FsRedirection)
+ pWow64DisableWow64FsRedirection(&redir);
+
+ /* 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");
+
+ if (pWow64RevertWow64FsRedirection)
+ pWow64RevertWow64FsRedirection(redir);
+}
+
+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);
+ CloseEventLog(NULL);
+ if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ win_skip("Event log functions are not implemented\n");
+ return;
+ }
+
+ init_function_pointers();
+
+ /* Parameters only */
+ test_open_close();
+ test_info();
+ test_count();
+ test_oldest();
+ test_backup();
+ test_openbackup();
+ test_read();
+ test_clear();
+
+ /* Functional tests */
+ if (create_new_eventlog())
+ {
+ test_readwrite();
+ test_autocreation();
+ }
+ cleanup_eventlog();
+}
typedef BOOL (WINAPI *fnMakeSelfRelativeSD)( PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, LPDWORD );
typedef BOOL (WINAPI *fnConvertSidToStringSidA)( PSID pSid, LPSTR *str );
typedef BOOL (WINAPI *fnConvertStringSidToSidA)( LPCSTR str, PSID pSid );
+static BOOL (WINAPI *pCheckTokenMembership)(HANDLE, PSID, PBOOL);
static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR, DWORD,
PSECURITY_DESCRIPTOR*, PULONG );
static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorW)(LPCWSTR, DWORD,
pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx");
pAddAccessDeniedAceEx = (void *)GetProcAddress(hmod, "AddAccessDeniedAceEx");
pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx");
+ pCheckTokenMembership = (void *)GetProcAddress(hmod, "CheckTokenMembership");
pConvertStringSecurityDescriptorToSecurityDescriptorA =
(void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" );
pConvertStringSecurityDescriptorToSecurityDescriptorW =
ok(pisid->SubAuthority[0] == 21, "Invalid subauthority 0 - expceted 21, got %d\n", pisid->SubAuthority[0]);
ok(pisid->SubAuthority[3] == 4576, "Invalid subauthority 0 - expceted 4576, got %d\n", pisid->SubAuthority[3]);
LocalFree(str);
+ LocalFree(psid);
for( i = 0; i < sizeof(refs) / sizeof(refs[0]); i++ )
{
ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
/* groups */
+ SetLastError(0xdeadbeef);
ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "GetTokenInformation(TokenGroups) %s with error %d\n",
+ ret ? "succeeded" : "failed", GetLastError());
Groups = HeapAlloc(GetProcessHeap(), 0, Size);
+ SetLastError(0xdeadbeef);
ret = GetTokenInformation(Token, TokenGroups, Groups, Size, &Size);
ok(ret, "GetTokenInformation(TokenGroups) failed with error %d\n", GetLastError());
+ ok(GetLastError() == 0xdeadbeef,
+ "GetTokenInformation shouldn't have set last error to %d\n",
+ GetLastError());
trace("TokenGroups:\n");
for (i = 0; i < Groups->GroupCount; i++)
{
DWORD DomainLength = 255;
TCHAR Domain[255];
SID_NAME_USE SidNameUse;
- pConvertSidToStringSidA(Groups->Groups[i].Sid, &SidString);
Name[0] = '\0';
Domain[0] = '\0';
ret = LookupAccountSid(NULL, Groups->Groups[i].Sid, Name, &NameLength, Domain, &DomainLength, &SidNameUse);
if (ret)
{
+ pConvertSidToStringSidA(Groups->Groups[i].Sid, &SidString);
trace("%s, %s\\%s use: %d attr: 0x%08x\n", SidString, Domain, Name, SidNameUse, Groups->Groups[i].Attributes);
LocalFree(SidString);
}
ok(memcmp(buf2, sid_buffer, cb) == 0, "SID create with domain is different than without (%d)\n", i);
}
}
+
+ LocalFree(domainsid);
}
static void test_LookupAccountSid(void)
domain = HeapAlloc(GetProcessHeap(), 0, domain_size);
ret = LookupAccountNameA(NULL, computer_name, psid, &sid_size, domain, &domain_size, &sid_use);
ok(ret, "LookupAccountNameA failed: %d\n", GetLastError());
- ok(sid_use == SidTypeDomain, "expected SidTypeDomain, got %d\n", sid_use);
+ ok(sid_use == SidTypeDomain ||
+ (sid_use == SidTypeUser && ! strcmp(computer_name, user_name)), "expected SidTypeDomain for %s, got %d\n", computer_name, sid_use);
HeapFree(GetProcessHeap(), 0, domain);
HeapFree(GetProcessHeap(), 0, psid);
}
ExplicitAccess.grfAccessPermissions = KEY_WRITE;
ExplicitAccess.grfAccessMode = GRANT_ACCESS;
ExplicitAccess.grfInheritance = NO_INHERITANCE;
- ExplicitAccess.Trustee.pMultipleTrustee = NULL;
- ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
ExplicitAccess.Trustee.ptstrName = EveryoneSid;
+ ExplicitAccess.Trustee.MultipleTrusteeOperation = 0xDEADBEEF;
+ ExplicitAccess.Trustee.pMultipleTrustee = (PVOID)0xDEADBEEF;
+ res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+ ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+ ok(NewAcl != NULL, "returned acl was NULL\n");
+ LocalFree(NewAcl);
+
+ ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+ ExplicitAccess.Trustee.pMultipleTrustee = NULL;
+ ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
ok(NewAcl != NULL, "returned acl was NULL\n");
BOOL ret;
PSECURITY_DESCRIPTOR pSD;
static const WCHAR Blank[] = { 0 };
+ int i;
+ static const struct
+ {
+ const char *sidstring;
+ DWORD revision;
+ BOOL ret;
+ DWORD GLE;
+ DWORD altGLE;
+ } cssd[] =
+ {
+ { "D:(A;;GA;;;WD)", 0xdeadbeef, FALSE, ERROR_UNKNOWN_REVISION },
+ /* test ACE string type */
+ { "D:(A;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "ERROR:(D;;GA;;;WD)", SDDL_REVISION_1, FALSE, ERROR_INVALID_PARAMETER },
+ /* test ACE string with spaces */
+ { " D:(D;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D: (D;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:( D;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D ;;GA;;;WD)", SDDL_REVISION_1, FALSE, RPC_S_INVALID_STRING_UUID, ERROR_INVALID_ACL }, /* Vista+ */
+ { "D:(D; ;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;; GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA ;;;WD)", SDDL_REVISION_1, FALSE, ERROR_INVALID_ACL },
+ { "D:(D;;GA; ;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA;; ;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA;;; WD)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA;;;WD )", SDDL_REVISION_1, TRUE },
+ /* test ACE string access rights */
+ { "D:(A;;GA;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;GRGWGX;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;RCSDWDWO;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;RPWPCCDCLCSWLODTCR;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;FAFRFWFX;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;KAKRKWKX;;;WD)", SDDL_REVISION_1, TRUE },
+ { "D:(A;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, TRUE },
+ { "S:(AU;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, TRUE },
+ /* test ACE string access right error case */
+ { "D:(A;;ROB;;;WD)", SDDL_REVISION_1, FALSE, ERROR_INVALID_ACL },
+ /* test behaviour with empty strings */
+ { "", SDDL_REVISION_1, TRUE },
+ /* test ACE string SID */
+ { "D:(D;;GA;;;S-1-0-0)", SDDL_REVISION_1, TRUE },
+ { "D:(D;;GA;;;Nonexistent account)", SDDL_REVISION_1, FALSE, ERROR_INVALID_ACL, ERROR_INVALID_SID } /* W2K */
+ };
if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
{
return;
}
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;GA;;;WD)", 0xdeadbeef, &pSD, NULL);
- ok(!ret && GetLastError() == ERROR_UNKNOWN_REVISION,
- "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_UNKNOWN_REVISION instead of %d\n",
- GetLastError());
-
- /* test ACE string type */
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
-
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(D;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
-
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "ERROR:(D;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
- "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
- GetLastError());
-
- /* test ACE string access rights */
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;GRGWGX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;RCSDWDWO;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;RPWPCCDCLCSWLODTCR;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;FAFRFWFX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;KAKRKWKX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "S:(AU;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
- LocalFree(pSD);
+ for (i = 0; i < sizeof(cssd)/sizeof(cssd[0]); i++)
+ {
+ DWORD GLE;
- /* test ACE string access right error case */
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(A;;ROB;;;WD)", SDDL_REVISION_1, &pSD, NULL);
- ok(!ret && GetLastError() == ERROR_INVALID_ACL,
- "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_ACL instead of %d\n",
- GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+ cssd[i].sidstring, cssd[i].revision, &pSD, NULL);
+ GLE = GetLastError();
+ ok(ret == cssd[i].ret, "(%02d) Expected %s (%d)\n", i, cssd[i].ret ? "success" : "failure", GLE);
+ if (!cssd[i].ret)
+ ok(GLE == cssd[i].GLE ||
+ (cssd[i].altGLE && GLE == cssd[i].altGLE),
+ "(%02d) Unexpected last error %d\n", i, GLE);
+ if (ret)
+ LocalFree(pSD);
+ }
/* test behaviour with NULL parameters */
SetLastError(0xdeadbeef);
GetLastError());
/* test behaviour with empty strings */
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
-
SetLastError(0xdeadbeef);
ret = pConvertStringSecurityDescriptorToSecurityDescriptorW(
Blank, SDDL_REVISION_1, &pSD, NULL);
ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
-
- /* test ACE string SID */
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(D;;GA;;;S-1-0-0)", SDDL_REVISION_1, &pSD, NULL);
- ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
LocalFree(pSD);
-
- SetLastError(0xdeadbeef);
- ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
- "D:(D;;GA;;;Nonexistent account)", SDDL_REVISION_1, &pSD, NULL);
- ok(!ret, "Expected failure, got %d\n", ret);
- ok(GetLastError() == ERROR_INVALID_ACL || GetLastError() == ERROR_INVALID_SID,
- "Expected ERROR_INVALID_ACL or ERROR_INVALID_SID, got %d\n", GetLastError());
}
static void test_ConvertSecurityDescriptorToString(void)
CHECK_ONE_OF_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", /* XP */
"O:SYG:S-1-5-21-93476-23408-4576D:NO_ACCESS_CONTROLS:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)" /* Vista */);
}
+
+ LocalFree(psid2);
+ LocalFree(psid);
}
static void test_SetSecurityDescriptorControl (PSECURITY_DESCRIPTOR sec)
ok(sd != NULL, "GetSecurityInfo\n");
ok(owner != NULL, "GetSecurityInfo\n");
ok(group != NULL, "GetSecurityInfo\n");
- ok(dacl != NULL, "GetSecurityInfo\n");
- ok(IsValidAcl(dacl), "GetSecurityInfo\n");
+ if (dacl != NULL)
+ ok(IsValidAcl(dacl), "GetSecurityInfo\n");
+ else
+ win_skip("No ACL information returned\n");
LocalFree(sd);
ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret);
ok(owner != NULL, "GetSecurityInfo\n");
ok(group != NULL, "GetSecurityInfo\n");
- ok(dacl != NULL, "GetSecurityInfo\n");
- ok(IsValidAcl(dacl), "GetSecurityInfo\n");
+ if (dacl != NULL)
+ ok(IsValidAcl(dacl), "GetSecurityInfo\n");
+ else
+ win_skip("No ACL information returned\n");
CloseHandle(obj);
}
ok(*pGetSidSubAuthority(psid,1) == 93476,"GetSidSubAuthority gave %d expected 93476\n",*pGetSidSubAuthority(psid,1));
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
SetLastError(0xbebecaca);
- todo_wine ok(*pGetSidSubAuthority(psid,4) == 0,"GetSidSubAuthority gave %d,expected 0\n",*pGetSidSubAuthority(psid,4));
+ ok(pGetSidSubAuthority(psid,4) != NULL,"Expected out of bounds GetSidSubAuthority to return a non-NULL pointer\n");
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
LocalFree(psid);
}
+static void test_CheckTokenMembership(void)
+{
+ PTOKEN_GROUPS token_groups;
+ DWORD size;
+ HANDLE process_token, token;
+ BOOL is_member;
+ BOOL ret;
+ DWORD i;
+
+ if (!pCheckTokenMembership)
+ {
+ win_skip("CheckTokenMembership is not available\n");
+ return;
+ }
+ ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &process_token);
+ ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
+
+ ret = DuplicateToken(process_token, SecurityImpersonation, &token);
+ ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
+
+ /* groups */
+ ret = GetTokenInformation(token, TokenGroups, NULL, 0, &size);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "GetTokenInformation(TokenGroups) %s with error %d\n",
+ ret ? "succeeded" : "failed", GetLastError());
+ token_groups = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetTokenInformation(token, TokenGroups, token_groups, size, &size);
+ ok(ret, "GetTokenInformation(TokenGroups) failed with error %d\n", GetLastError());
+
+ for (i = 0; i < token_groups->GroupCount; i++)
+ {
+ if (token_groups->Groups[i].Attributes & SE_GROUP_ENABLED)
+ break;
+ }
+
+ if (i == token_groups->GroupCount)
+ {
+ HeapFree(GetProcessHeap(), 0, token_groups);
+ CloseHandle(token);
+ skip("user not a member of any group\n");
+ return;
+ }
+
+ ret = pCheckTokenMembership(token, token_groups->Groups[i].Sid, &is_member);
+ ok(ret, "CheckTokenMembership failed with error %d\n", GetLastError());
+ ok(is_member, "CheckTokenMembership should have detected sid as member\n");
+
+ ret = pCheckTokenMembership(NULL, token_groups->Groups[i].Sid, &is_member);
+ ok(ret, "CheckTokenMembership failed with error %d\n", GetLastError());
+ ok(is_member, "CheckTokenMembership should have detected sid as member\n");
+
+ ret = pCheckTokenMembership(process_token, token_groups->Groups[i].Sid, &is_member);
+todo_wine {
+ ok(!ret && GetLastError() == ERROR_NO_IMPERSONATION_TOKEN,
+ "CheckTokenMembership with process token %s with error %d\n",
+ ret ? "succeeded" : "failed", GetLastError());
+ ok(!is_member, "CheckTokenMembership should have cleared is_member\n");
+}
+
+ HeapFree(GetProcessHeap(), 0, token_groups);
+ CloseHandle(token);
+ CloseHandle(process_token);
+}
+
+static void test_EqualSid(void)
+{
+ PSID sid1, sid2;
+ BOOL ret;
+ SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY };
+ SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY };
+
+ SetLastError(0xdeadbeef);
+ ret = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid1);
+ if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ win_skip("AllocateAndInitializeSid is not implemented\n");
+ return;
+ }
+ ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+ ok(GetLastError() == 0xdeadbeef,
+ "AllocateAndInitializeSid shouldn't have set last error to %d\n",
+ GetLastError());
+
+ ret = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0, &sid2);
+ ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = EqualSid(sid1, sid2);
+ ok(!ret, "World and domain admins sids shouldn't have been equal\n");
+ ok(GetLastError() == ERROR_SUCCESS ||
+ broken(GetLastError() == 0xdeadbeef), /* NT4 */
+ "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ sid2 = FreeSid(sid2);
+ ok(!sid2, "FreeSid should have returned NULL instead of %p\n", sid2);
+ ok(GetLastError() == 0xdeadbeef,
+ "FreeSid shouldn't have set last error to %d\n",
+ GetLastError());
+
+ ret = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid2);
+ ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = EqualSid(sid1, sid2);
+ ok(ret, "Same sids should have been equal\n");
+ ok(GetLastError() == ERROR_SUCCESS ||
+ broken(GetLastError() == 0xdeadbeef), /* NT4 */
+ "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n",
+ GetLastError());
+
+ ((SID *)sid2)->Revision = 2;
+ SetLastError(0xdeadbeef);
+ ret = EqualSid(sid1, sid2);
+ ok(!ret, "EqualSid with invalid sid should have returned FALSE\n");
+ ok(GetLastError() == ERROR_SUCCESS ||
+ broken(GetLastError() == 0xdeadbeef), /* NT4 */
+ "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n",
+ GetLastError());
+ ((SID *)sid2)->Revision = SID_REVISION;
+
+ FreeSid(sid1);
+ FreeSid(sid2);
+}
+
START_TEST(security)
{
init();
test_acls();
test_GetSecurityInfo();
test_GetSidSubAuthority();
+ test_CheckTokenMembership();
+ test_EqualSid();
}