[ADVAPI32_WINETEST] Sync with Wine Staging 2.9. CORE-13362
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:57:35 +0000 (14:57 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:57:35 +0000 (14:57 +0000)
svn path=/trunk/; revision=74911

rostests/winetests/advapi32/crypt.c
rostests/winetests/advapi32/eventlog.c
rostests/winetests/advapi32/lsa.c
rostests/winetests/advapi32/registry.c
rostests/winetests/advapi32/security.c
rostests/winetests/advapi32/service.c

index 84a54a1..13671eb 100644 (file)
@@ -255,6 +255,9 @@ static void test_incorrect_api_usage(void)
     ok (result, "%d\n", GetLastError());
     if (!result) return;
 
+    result = pCryptDestroyKey(hKey);
+    ok (result, "%d\n", GetLastError());
+
     result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
     ok (result, "%d\n", GetLastError());
     if (!result) return;
index 3ca59c3..838454e 100644 (file)
 
 #include <stdarg.h>
 
+#include "initguid.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "winnt.h"
 #include "winreg.h"
 #include "sddl.h"
+#include "wmistr.h"
+#include "evntrace.h"
 
 #include "wine/test.h"
 
@@ -909,6 +912,7 @@ static void test_readwrite(void)
 
     /* Read all events from our created eventlog, one by one */
     handle = OpenEventLogA(NULL, eventlogname);
+    ok(handle != NULL, "Failed to open Event Log, got %d\n", GetLastError());
     i = 0;
     for (;;)
     {
@@ -924,14 +928,13 @@ static void test_readwrite(void)
         SetLastError(0xdeadbeef);
         ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
                             0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
-        if (!ret && GetLastError() == ERROR_HANDLE_EOF)
+        ok(!ret, "Expected failure\n");
+        if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
         {
             HeapFree(GetProcessHeap(), 0, buf);
+            ok(GetLastError() == ERROR_HANDLE_EOF, "record %d, got %d\n", i, GetLastError());
             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,
@@ -1010,6 +1013,7 @@ static void test_readwrite(void)
 
     /* Test clearing a real eventlog */
     handle = OpenEventLogA(NULL, eventlogname);
+    ok(handle != NULL, "Failed to open Event Log, got %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     ret = ClearEventLogA(handle, NULL);
@@ -1142,6 +1146,98 @@ static void cleanup_eventlog(void)
     ok(bret, "Expected MoveFileEx to succeed: %d\n", GetLastError());
 }
 
+static void test_start_trace(void)
+{
+    const char sessionname[] = "wine";
+    const char filepath[] = "wine.etl";
+    const char filepath2[] = "eniw.etl";
+    EVENT_TRACE_PROPERTIES *properties;
+    TRACEHANDLE handle;
+    LONG buffersize;
+    LONG ret;
+
+    buffersize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(sessionname) + sizeof(filepath);
+    properties = (EVENT_TRACE_PROPERTIES *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize);
+    properties->Wnode.BufferSize = buffersize;
+    properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
+    properties->LogFileMode = EVENT_TRACE_FILE_MODE_NONE;
+    properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+    properties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(sessionname);
+    strcpy((char *)properties + properties->LogFileNameOffset, filepath);
+
+    properties->Wnode.BufferSize = 0;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_BAD_LENGTH ||
+       ret == ERROR_INVALID_PARAMETER, /* XP and 2k3 */
+       "Expected ERROR_BAD_LENGTH, got %d\n", ret);
+    properties->Wnode.BufferSize = buffersize;
+
+    ret = StartTraceA(&handle, "this name is too long", properties);
+    todo_wine
+    ok(ret == ERROR_BAD_LENGTH, "Expected ERROR_BAD_LENGTH, got %d\n", ret);
+
+    ret = StartTraceA(&handle, sessionname, NULL);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+
+    ret = StartTraceA(NULL, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+
+    properties->LogFileNameOffset = 1;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+    properties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(sessionname);
+
+    properties->LoggerNameOffset = 1;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+    properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+
+    properties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_FILE_MODE_CIRCULAR;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+    properties->LogFileMode = EVENT_TRACE_FILE_MODE_NONE;
+    /* XP creates a file we can't delete, so change the filepath to something else */
+    strcpy((char *)properties + properties->LogFileNameOffset, filepath2);
+
+    properties->Wnode.Guid = SystemTraceControlGuid;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+    properties->Wnode.Guid = (GUID){0};
+
+    properties->LogFileNameOffset = 0;
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_BAD_PATHNAME, "Expected ERROR_BAD_PATHNAME, got %d\n", ret);
+    properties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(sessionname);
+
+    ret = StartTraceA(&handle, sessionname, properties);
+    if (ret == ERROR_ACCESS_DENIED)
+    {
+        skip("need admin rights\n");
+        goto done;
+    }
+    ok(ret == ERROR_SUCCESS, "Expected success, got %d\n", ret);
+
+    ret = StartTraceA(&handle, sessionname, properties);
+    todo_wine
+    ok(ret == ERROR_ALREADY_EXISTS ||
+       ret == ERROR_SHARING_VIOLATION, /* 2k3 */
+       "Expected ERROR_ALREADY_EXISTS, got %d\n", ret);
+
+    /* clean up */
+    ControlTraceA(handle, sessionname, properties, EVENT_TRACE_CONTROL_STOP);
+done:
+    HeapFree(GetProcessHeap(), 0, properties);
+    DeleteFileA(filepath);
+}
+
 START_TEST(eventlog)
 {
     SetLastError(0xdeadbeef);
@@ -1171,4 +1267,7 @@ START_TEST(eventlog)
         test_autocreation();
         cleanup_eventlog();
     }
+
+    /* Trace tests */
+    test_start_trace();
 }
index 6449c18..58bccd1 100644 (file)
@@ -44,8 +44,10 @@ static NTSTATUS (WINAPI *pLsaFreeMemory)(PVOID);
 static NTSTATUS (WINAPI *pLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE);
 static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
 static BOOL     (WINAPI *pConvertSidToStringSidA)(PSID,LPSTR*);
+static BOOL     (WINAPI *pConvertStringSidToSidA)(LPCSTR,PSID*);
 static NTSTATUS (WINAPI *pLsaLookupNames2)(LSA_HANDLE,ULONG,ULONG,PLSA_UNICODE_STRING,PLSA_REFERENCED_DOMAIN_LIST*,PLSA_TRANSLATED_SID2*);
 static NTSTATUS (WINAPI *pLsaLookupSids)(LSA_HANDLE,ULONG,PSID*,LSA_REFERENCED_DOMAIN_LIST**,LSA_TRANSLATED_NAME**);
+static PVOID    (WINAPI *pFreeSid)(PSID);
 
 static BOOL init(void)
 {
@@ -57,10 +59,12 @@ static BOOL init(void)
     pLsaOpenPolicy = (void*)GetProcAddress(hadvapi32, "LsaOpenPolicy");
     pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy");
     pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
+    pConvertStringSidToSidA = (void*)GetProcAddress(hadvapi32, "ConvertStringSidToSidA");
     pLsaLookupNames2 = (void*)GetProcAddress(hadvapi32, "LsaLookupNames2");
     pLsaLookupSids = (void*)GetProcAddress(hadvapi32, "LsaLookupSids");
+    pFreeSid = (void*)GetProcAddress(hadvapi32, "FreeSid");
 
-    if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA)
+    if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA && pConvertStringSidToSidA && pFreeSid)
         return TRUE;
 
     return FALSE;
@@ -68,6 +72,8 @@ static BOOL init(void)
 
 static void test_lsa(void)
 {
+    static WCHAR machineW[] = {'W','i','n','e','N','o','M','a','c','h','i','n','e',0};
+    LSA_UNICODE_STRING machine;
     NTSTATUS status;
     LSA_HANDLE handle;
     LSA_OBJECT_ATTRIBUTES object_attributes;
@@ -75,6 +81,14 @@ static void test_lsa(void)
     ZeroMemory(&object_attributes, sizeof(object_attributes));
     object_attributes.Length = sizeof(object_attributes);
 
+    machine.Buffer = machineW;
+    machine.Length = sizeof(machineW) - 2;
+    machine.MaximumLength = sizeof(machineW);
+
+    status = pLsaOpenPolicy( &machine, &object_attributes, POLICY_LOOKUP_NAMES, &handle);
+    ok(status == RPC_NT_SERVER_UNAVAILABLE,
+       "LsaOpenPolicy(POLICY_LOOKUP_NAMES) for invalid machine returned 0x%08x\n", status);
+
     status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
     ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
        "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
@@ -407,6 +421,48 @@ static void test_LsaLookupSids(void)
     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
 }
 
+static void test_LsaLookupSids_NullBuffers(void)
+{
+    LSA_REFERENCED_DOMAIN_LIST *list;
+    LSA_OBJECT_ATTRIBUTES attrs;
+    LSA_TRANSLATED_NAME *names;
+    LSA_HANDLE policy;
+    NTSTATUS status;
+    BOOL ret;
+    PSID sid;
+
+    memset(&attrs, 0, sizeof(attrs));
+    attrs.Length = sizeof(attrs);
+
+    status = pLsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &policy);
+    ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
+
+    ret = pConvertStringSidToSidA("S-1-1-0", &sid);
+    ok(ret == TRUE, "pConvertStringSidToSidA returned false\n");
+
+    status = pLsaLookupSids(policy, 1, &sid, &list, &names);
+    ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
+
+    ok(list->Entries > 0, "got %d\n", list->Entries);
+
+    if (list->Entries)
+    {
+       ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains);
+       ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid);
+       ok(list->Domains[0].Name.MaximumLength > list->Domains[0].Name.Length, "got %d, %d\n", list->Domains[0].Name.MaximumLength,
+           list->Domains[0].Name.Length);
+       ok(list->Domains[0].Name.Buffer != NULL, "domain[0] name buffer is null\n");
+    }
+
+    pLsaFreeMemory(names);
+    pLsaFreeMemory(list);
+
+    pFreeSid(sid);
+
+    status = pLsaClose(policy);
+    ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
+}
+
 START_TEST(lsa)
 {
     if (!init()) {
@@ -417,4 +473,5 @@ START_TEST(lsa)
     test_lsa();
     test_LsaLookupNames2();
     test_LsaLookupSids();
+    test_LsaLookupSids_NullBuffers();
 }
index 521902a..8af1ebf 100644 (file)
@@ -30,6 +30,7 @@
 #include "winbase.h"
 #include "wine/winternl.h"
 #include "winreg.h"
+#include "winperf.h"
 #include "winsvc.h"
 #include "winerror.h"
 #include "aclapi.h"
@@ -774,11 +775,10 @@ cleanup:
 
 static void test_query_value_ex(void)
 {
-    DWORD ret;
-    DWORD size;
-    DWORD type;
+    DWORD ret, size, type;
     BYTE buffer[10];
-    
+
+    size = sizeof(buffer);
     ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
     ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
     ok(size == strlen(sTestpath1) + 1, "(%d,%d)\n", (DWORD)strlen(sTestpath1) + 1, size);
@@ -1842,7 +1842,7 @@ static void test_reg_query_info(void)
     ok(classbufferW[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW[0]);
 
     /* empty key */
-    sdlen = 0;
+    sdlen = classlen =0;
     ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
@@ -1856,7 +1856,7 @@ static void test_reg_query_info(void)
     ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
     ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
 
-    sdlen = 0;
+    sdlen = classlen = 0;
     ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
@@ -1877,7 +1877,7 @@ static void test_reg_query_info(void)
     ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
 
     /* with subkey & default value */
-    sdlen = 0;
+    sdlen = classlen = 0;
     ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
@@ -1891,7 +1891,7 @@ static void test_reg_query_info(void)
     ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
     ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
 
-    sdlen = 0;
+    sdlen = classlen = 0;
     ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
@@ -1912,12 +1912,14 @@ static void test_reg_query_info(void)
     ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
 
     /* with named value */
+    classlen = 0;
     ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(values == 3, "values = %u\n", values);
     ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
     ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
 
+    classlen = 0;
     ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
     ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
     ok(values == 3, "values = %u\n", values);
@@ -3301,6 +3303,38 @@ static void test_classesroot_mask(void)
     RegCloseKey( hkey );
 }
 
+static void test_perflib_key(void)
+{
+    DWORD size;
+    LONG ret;
+    HKEY key;
+
+    ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009", &key);
+    ok(ret == ERROR_SUCCESS, "RegOpenKeyA failed with error %u\n", ret);
+
+    ret = RegQueryValueExA(key, "Counter", NULL, NULL, NULL, &size);
+    if (ret != ERROR_SUCCESS)
+    {
+        skip("Perflib\\009\\Counter does not exist, skipping perflib test\n");
+        goto done;
+    }
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed with error %u\n", ret);
+
+    /* Windows only compares the first few characters of the value name.
+     * On Windows XP / 2003, it is sufficient to use "Cou", newer versions
+     * require a longer substring. */
+
+    ret = RegQueryValueExA(key, "Counters", NULL, NULL, NULL, &size);
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed with error %u\n", ret);
+    ret = RegQueryValueExA(key, "Counter2", NULL, NULL, NULL, &size);
+    todo_wine ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed with error %u\n", ret);
+    ret = RegQueryValueExA(key, "CounterWine", NULL, NULL, NULL, &size);
+    todo_wine ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed with error %u\n", ret);
+
+done:
+    RegCloseKey(key);
+}
+
 static void test_deleted_key(void)
 {
     HKEY hkey, hkey2;
@@ -3489,6 +3523,54 @@ static void test_RegNotifyChangeKeyValue(void)
     CloseHandle(event);
 }
 
+static void test_RegQueryValueExPerformanceData(void)
+{
+    DWORD cbData, len;
+    BYTE *value;
+    DWORD dwret;
+    LONG limit = 6;
+    PERF_DATA_BLOCK *pdb;
+
+    /* Test with data == NULL */
+    dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, NULL, &cbData );
+    todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret );
+
+    /* Test ERROR_MORE_DATA, start with small buffer */
+    len = 10;
+    value = HeapAlloc(GetProcessHeap(), 0, len);
+    cbData = len;
+    dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, value, &cbData );
+    todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret );
+    while( dwret == ERROR_MORE_DATA && limit)
+    {
+        len = len * 10;
+        value = HeapReAlloc( GetProcessHeap(), 0, value, len );
+        cbData = len;
+        dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, value, &cbData );
+        limit--;
+    }
+    ok(limit > 0, "too many times ERROR_MORE_DATA returned\n");
+
+    todo_wine ok(dwret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", dwret);
+
+    /* Check returned data */
+    if (dwret == ERROR_SUCCESS)
+    {
+        todo_wine ok(len >= sizeof(PERF_DATA_BLOCK), "got size %d\n", len);
+        if (len >= sizeof(PERF_DATA_BLOCK)) {
+            pdb = (PERF_DATA_BLOCK*) value;
+            ok(pdb->Signature[0] == 'P', "expected Signature[0] = 'P', got 0x%x\n", pdb->Signature[0]);
+            ok(pdb->Signature[1] == 'E', "expected Signature[1] = 'E', got 0x%x\n", pdb->Signature[1]);
+            ok(pdb->Signature[2] == 'R', "expected Signature[2] = 'R', got 0x%x\n", pdb->Signature[2]);
+            ok(pdb->Signature[3] == 'F', "expected Signature[3] = 'F', got 0x%x\n", pdb->Signature[3]);
+            /* TODO: check other field */
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, value);
+}
+
+
 START_TEST(registry)
 {
     /* Load pointers for functions that are not available in all Windows versions */
@@ -3513,6 +3595,7 @@ START_TEST(registry)
     test_classesroot();
     test_classesroot_enum();
     test_classesroot_mask();
+    test_perflib_key();
     test_reg_save_key();
     test_reg_load_key();
     test_reg_unload_key();
@@ -3524,6 +3607,7 @@ START_TEST(registry)
     test_delete_key_value();
     test_RegOpenCurrentUser();
     test_RegNotifyChangeKeyValue();
+    test_RegQueryValueExPerformanceData();
 
     /* cleanup */
     delete_key( hkey_main );
index 663ce8f..d037969 100644 (file)
@@ -2,7 +2,7 @@
  * Unit tests for security functions
  *
  * Copyright (c) 2004 Mike McCormack
- * Copyright (c) 2011 Dmitry Timoshkov
+ * Copyright (c) 2011,2013,2014,2016 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -73,6 +73,7 @@
 static BOOL (WINAPI *pAddAccessAllowedAceEx)(PACL, DWORD, DWORD, DWORD, PSID);
 static BOOL (WINAPI *pAddAccessDeniedAceEx)(PACL, DWORD, DWORD, DWORD, PSID);
 static BOOL (WINAPI *pAddAuditAccessAceEx)(PACL, DWORD, DWORD, DWORD, PSID, BOOL, BOOL);
+static BOOL (WINAPI *pAddMandatoryAce)(PACL,DWORD,DWORD,DWORD,PSID);
 static VOID (WINAPI *pBuildTrusteeWithSidA)( PTRUSTEEA pTrustee, PSID pSid );
 static VOID (WINAPI *pBuildTrusteeWithNameA)( PTRUSTEEA pTrustee, LPSTR pName );
 static VOID (WINAPI *pBuildTrusteeWithObjectsAndNameA)( PTRUSTEEA pTrustee,
@@ -141,19 +142,12 @@ static BOOL     (WINAPI *pGetWindowsAccountDomainSid)(PSID,PSID,DWORD*);
 static void     (WINAPI *pRtlInitAnsiString)(PANSI_STRING,PCSZ);
 static NTSTATUS (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING);
 static PSID_IDENTIFIER_AUTHORITY (WINAPI *pGetSidIdentifierAuthority)(PSID);
+static DWORD    (WINAPI *pGetExplicitEntriesFromAclW)(PACL,PULONG,PEXPLICIT_ACCESSW*);
 
 static HMODULE hmod;
 static int     myARGC;
 static char**  myARGV;
 
-struct strsid_entry
-{
-    const char *str;
-    DWORD flags;
-};
-#define STRSID_OK     0
-#define STRSID_OPT    1
-
 #define SID_SLOTS 4
 static char debugsid_str[SID_SLOTS][256];
 static int debugsid_index = 0;
@@ -183,12 +177,6 @@ static const char* debugstr_sid(PSID sid)
     return res;
 }
 
-struct sidRef
-{
-    SID_IDENTIFIER_AUTHORITY auth;
-    const char *refStr;
-};
-
 static void init(void)
 {
     HMODULE hntdll;
@@ -207,6 +195,7 @@ static void init(void)
     pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx");
     pAddAccessDeniedAceEx = (void *)GetProcAddress(hmod, "AddAccessDeniedAceEx");
     pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx");
+    pAddMandatoryAce = (void *)GetProcAddress(hmod, "AddMandatoryAce");
     pCheckTokenMembership = (void *)GetProcAddress(hmod, "CheckTokenMembership");
     pConvertStringSecurityDescriptorToSecurityDescriptorA =
         (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" );
@@ -235,6 +224,8 @@ static void init(void)
     pGetAce = (void *)GetProcAddress(hmod, "GetAce");
     pGetWindowsAccountDomainSid = (void *)GetProcAddress(hmod, "GetWindowsAccountDomainSid");
     pGetSidIdentifierAuthority = (void *)GetProcAddress(hmod, "GetSidIdentifierAuthority");
+    pGetExplicitEntriesFromAclW = (void *)GetProcAddress(hmod, "GetExplicitEntriesFromAclW");
+    pDuplicateTokenEx = (void *)GetProcAddress(hmod, "DuplicateTokenEx");
 
     myARGC = winetest_get_mainargs( &myARGV );
 }
@@ -305,7 +296,11 @@ static void test_group_equal(HANDLE Handle, PSID expected, int line)
 
 static void test_sid(void)
 {
-    struct sidRef refs[] = {
+    static struct
+    {
+        SID_IDENTIFIER_AUTHORITY auth;
+        const char *refStr;
+    } refs[] = {
      { { {0x00,0x00,0x33,0x44,0x55,0x66} }, "S-1-860116326-1" },
      { { {0x00,0x00,0x01,0x02,0x03,0x04} }, "S-1-16909060-1"  },
      { { {0x00,0x00,0x00,0x01,0x02,0x03} }, "S-1-66051-1"     },
@@ -313,24 +308,60 @@ static void test_sid(void)
      { { {0x00,0x00,0x00,0x00,0x00,0x02} }, "S-1-2-1"         },
      { { {0x00,0x00,0x00,0x00,0x00,0x0c} }, "S-1-12-1"        },
     };
-    struct strsid_entry strsid_table[] = {
-        {"AO", STRSID_OK},  {"RU", STRSID_OK},  {"AN", STRSID_OK},  {"AU", STRSID_OK},
-        {"BA", STRSID_OK},  {"BG", STRSID_OK},  {"BO", STRSID_OK},  {"BU", STRSID_OK},
-        {"CA", STRSID_OPT}, {"CG", STRSID_OK},  {"CO", STRSID_OK},  {"DA", STRSID_OPT},
-        {"DC", STRSID_OPT}, {"DD", STRSID_OPT}, {"DG", STRSID_OPT}, {"DU", STRSID_OPT},
-        {"EA", STRSID_OPT}, {"ED", STRSID_OK},  {"WD", STRSID_OK},  {"PA", STRSID_OPT},
-        {"IU", STRSID_OK},  {"LA", STRSID_OK},  {"LG", STRSID_OK},  {"LS", STRSID_OK},
-        {"SY", STRSID_OK},  {"NU", STRSID_OK},  {"NO", STRSID_OK},  {"NS", STRSID_OK},
-        {"PO", STRSID_OK},  {"PS", STRSID_OK},  {"PU", STRSID_OK},  {"RS", STRSID_OPT},
-        {"RD", STRSID_OK},  {"RE", STRSID_OK},  {"RC", STRSID_OK},  {"SA", STRSID_OPT},
-        {"SO", STRSID_OK},  {"SU", STRSID_OK}};
-
+    static const struct
+    {
+        const char *str;
+        WELL_KNOWN_SID_TYPE sid_type;
+        BOOL optional;
+    } strsid_table[] = {
+        /* Please keep the list sorted. */
+        { "AC", WinBuiltinAnyPackageSid, TRUE },
+        { "AN", WinAnonymousSid },
+        { "AO", WinBuiltinAccountOperatorsSid },
+        { "AU", WinAuthenticatedUserSid },
+        { "BA", WinBuiltinAdministratorsSid },
+        { "BG", WinBuiltinGuestsSid },
+        { "BO", WinBuiltinBackupOperatorsSid },
+        { "BU", WinBuiltinUsersSid },
+        { "CA", WinAccountCertAdminsSid, TRUE},
+        { "CG", WinCreatorGroupSid },
+        { "CO", WinCreatorOwnerSid },
+        { "DA", WinAccountDomainAdminsSid, TRUE},
+        { "DC", WinAccountComputersSid, TRUE},
+        { "DD", WinAccountControllersSid, TRUE},
+        { "DG", WinAccountDomainGuestsSid, TRUE},
+        { "DU", WinAccountDomainUsersSid, TRUE},
+        { "EA", WinAccountEnterpriseAdminsSid, TRUE},
+        { "ED", WinEnterpriseControllersSid },
+        { "IU", WinInteractiveSid },
+        { "LA", WinAccountAdministratorSid },
+        { "LG", WinAccountGuestSid },
+        { "LS", WinLocalServiceSid },
+        { "NO", WinBuiltinNetworkConfigurationOperatorsSid },
+        { "NS", WinNetworkServiceSid },
+        { "NU", WinNetworkSid },
+        { "PA", WinAccountPolicyAdminsSid, TRUE},
+        { "PO", WinBuiltinPrintOperatorsSid },
+        { "PS", WinSelfSid },
+        { "PU", WinBuiltinPowerUsersSid },
+        { "RC", WinRestrictedCodeSid },
+        { "RD", WinBuiltinRemoteDesktopUsersSid },
+        { "RE", WinBuiltinReplicatorSid },
+        { "RS", WinAccountRasAndIasServersSid, TRUE },
+        { "RU", WinBuiltinPreWindows2000CompatibleAccessSid },
+        { "SA", WinAccountSchemaAdminsSid, TRUE },
+        { "SO", WinBuiltinSystemOperatorsSid },
+        { "SU", WinServiceSid },
+        { "SY", WinLocalSystemSid },
+        { "WD", WinWorldSid },
+    };
+    SID_IDENTIFIER_AUTHORITY domain_ident = { SECURITY_NT_AUTHORITY };
     const char noSubAuthStr[] = "S-1-5";
     unsigned int i;
-    PSID psid = NULL;
+    PSID psid, domain_sid;
     SID *pisid;
     BOOL r;
-    LPSTR str = NULL;
+    LPSTR str;
 
     if( !pConvertSidToStringSidA || !pConvertStringSidToSidA )
     {
@@ -410,7 +441,7 @@ static void test_sid(void)
     }
 
     /* string constant format not supported before XP */
-    r = pConvertStringSidToSidA(strsid_table[0].str, &psid);
+    r = pConvertStringSidToSidA("AN", &psid);
     if(!r)
     {
         win_skip("String constant format not supported\n");
@@ -418,25 +449,51 @@ static void test_sid(void)
     }
     LocalFree(psid);
 
+    AllocateAndInitializeSid(&domain_ident, 4, SECURITY_NT_NON_UNIQUE, 0, 0, 0, 0, 0, 0, 0, &domain_sid);
+
     for(i = 0; i < sizeof(strsid_table) / sizeof(strsid_table[0]); i++)
     {
-        char *temp;
-
         SetLastError(0xdeadbeef);
         r = pConvertStringSidToSidA(strsid_table[i].str, &psid);
 
-        if (!(strsid_table[i].flags & STRSID_OPT))
+        if (!(strsid_table[i].optional))
         {
             ok(r, "%s: got %u\n", strsid_table[i].str, GetLastError());
         }
 
         if (r)
         {
-            if ((winetest_debug > 1) && (pConvertSidToStringSidA(psid, &temp)))
+            char buf[SECURITY_MAX_SID_SIZE];
+            char *sid_string, *well_known_sid_string;
+            DWORD n, size;
+
+            /* zero out domain id before comparison to simplify things */
+            if (strsid_table[i].sid_type == WinAccountAdministratorSid ||
+                strsid_table[i].sid_type == WinAccountGuestSid)
             {
-                trace(" %s: %s\n", strsid_table[i].str, temp);
-                LocalFree(temp);
+                for (n = 1; n <= 3; n++)
+                    *GetSidSubAuthority(psid, n) = 0;
             }
+
+            r = pConvertSidToStringSidA(psid, &sid_string);
+            ok(r, "%s: ConvertSidToStringSid error %u\n", strsid_table[i].str, GetLastError());
+            if (winetest_debug > 1)
+                trace("%s => %s\n", strsid_table[i].str, sid_string);
+
+            size = sizeof(buf);
+            r = pCreateWellKnownSid(strsid_table[i].sid_type, domain_sid, buf, &size);
+            ok(r, "%u: CreateWellKnownSid(%u) error %u\n", i, strsid_table[i].sid_type, GetLastError());
+
+            r = pConvertSidToStringSidA(buf, &well_known_sid_string);
+            ok(r, "%u: ConvertSidToStringSi(%u) error %u\n", i, strsid_table[i].sid_type, GetLastError());
+            if (winetest_debug > 1)
+                trace("%u => %s\n", strsid_table[i].sid_type, well_known_sid_string);
+
+            ok(strcmp(sid_string, well_known_sid_string) == 0,
+               "%u: (%u) expected %s, got %s\n", i, strsid_table[i].sid_type, well_known_sid_string, sid_string);
+
+            LocalFree(well_known_sid_string);
+            LocalFree(sid_string);
             LocalFree(psid);
         }
         else
@@ -447,6 +504,8 @@ static void test_sid(void)
                 trace(" %s: couldn't be converted\n", strsid_table[i].str);
         }
     }
+
+    LocalFree(domain_sid);
 }
 
 static void test_trustee(void)
@@ -1384,6 +1443,12 @@ static void test_AccessCheck(void)
     ok(AccessStatus && (Access == KEY_READ),
         "AccessCheck failed to grant access with error %d\n",
         GetLastError());
+    ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    ok(AccessStatus && (Access == KEY_ALL_ACCESS),
+        "AccessCheck failed to grant access with error %d\n",
+        GetLastError());
 
     /* sd with blank dacl */
     ret = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, Acl, FALSE);
@@ -1911,6 +1976,30 @@ static void test_token_attr(void)
     CloseHandle(Token);
 }
 
+static void test_GetTokenInformation(void)
+{
+    DWORD is_app_container, size;
+    HANDLE token;
+    BOOL ret;
+
+    ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
+    ok(ret, "OpenProcessToken failed: %u\n", GetLastError());
+
+    size = 0;
+    is_app_container = 0xdeadbeef;
+    ret = GetTokenInformation(token, TokenIsAppContainer, &is_app_container,
+                              sizeof(is_app_container), &size);
+    ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER ||
+                     GetLastError() == ERROR_INVALID_FUNCTION), /* pre-win8 */
+       "GetTokenInformation failed: %u\n", GetLastError());
+    if(ret) {
+        ok(size == sizeof(is_app_container), "size = %u\n", size);
+        ok(!is_app_container, "is_app_container = %x\n", is_app_container);
+    }
+
+    CloseHandle(token);
+}
+
 typedef union _MAX_SID
 {
     SID sid;
@@ -2263,7 +2352,7 @@ static void test_LookupAccountSid(void)
     if (pCreateWellKnownSid && pConvertSidToStringSidA)
     {
         trace("Well Known SIDs:\n");
-        for (i = 0; i <= 60; i++)
+        for (i = 0; i <= 84; i++)
         {
             size = SECURITY_MAX_SID_SIZE;
             if (pCreateWellKnownSid(i, NULL, &max_sid.sid, &size))
@@ -3037,7 +3126,6 @@ static void test_impersonation_level(void)
     HKEY hkey;
     DWORD error;
 
-    pDuplicateTokenEx = (void *)GetProcAddress(hmod, "DuplicateTokenEx");
     if( !pDuplicateTokenEx ) {
         win_skip("DuplicateTokenEx is not available\n");
         return;
@@ -3730,6 +3818,7 @@ static void test_CreateDirectoryA(void)
     ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
     bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
     ok(bret, "GetAclInformation failed\n");
+    todo_wine
     ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
                                acl_size.AceCount);
     LocalFree(pSD);
@@ -3816,7 +3905,6 @@ static void test_CreateDirectoryA(void)
     ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
     bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
     ok(bret, "GetAclInformation failed\n");
-    todo_wine
     ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
                                acl_size.AceCount);
     LocalFree(pSD);
@@ -4200,10 +4288,14 @@ static void test_GetNamedSecurityInfoA(void)
         ok(bret, "Failed to get Builtin Users ACE.\n");
         flags = ((ACE_HEADER *)ace)->AceFlags;
         ok(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE)
-           || broken(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|INHERITED_ACE)) /* w2k8 */,
+           || broken(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|INHERITED_ACE)) /* w2k8 */
+           || broken(flags == (CONTAINER_INHERIT_ACE|INHERITED_ACE)) /* win 10 wow64 */
+           || broken(flags == CONTAINER_INHERIT_ACE), /* win 10 */
            "Builtin Users ACE has unexpected flags (0x%x != 0x%x)\n", flags,
            INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE);
-        ok(ace->Mask == GENERIC_READ, "Builtin Users ACE has unexpected mask (0x%x != 0x%x)\n",
+        ok(ace->Mask == GENERIC_READ
+           || broken(ace->Mask == KEY_READ), /* win 10 */
+           "Builtin Users ACE has unexpected mask (0x%x != 0x%x)\n",
                                       ace->Mask, GENERIC_READ);
     }
     ok(admins_ace_id != -1, "Bultin Admins ACE not found.\n");
@@ -4215,7 +4307,9 @@ static void test_GetNamedSecurityInfoA(void)
         ok(flags == 0x0
            || broken(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|INHERITED_ACE)) /* w2k8 */
            || broken(flags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)) /* win7 */
-           || broken(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE)), /* win8+ */
+           || broken(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE)) /* win8+ */
+           || broken(flags == (CONTAINER_INHERIT_ACE|INHERITED_ACE)) /* win 10 wow64 */
+           || broken(flags == CONTAINER_INHERIT_ACE), /* win 10 */
            "Builtin Admins ACE has unexpected flags (0x%x != 0x0)\n", flags);
         ok(ace->Mask == KEY_ALL_ACCESS || broken(ace->Mask == GENERIC_ALL) /* w2k8 */,
            "Builtin Admins ACE has unexpected mask (0x%x != 0x%x)\n", ace->Mask, KEY_ALL_ACCESS);
@@ -6395,6 +6489,276 @@ static void test_AddAce(void)
     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError() = %d\n", GetLastError());
 }
 
+static void test_AddMandatoryAce(void)
+{
+    static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+                            {SECURITY_MANDATORY_LOW_RID}};
+    static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+                               {SECURITY_MANDATORY_MEDIUM_RID}};
+    static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+                             {SECURITY_MANDATORY_HIGH_RID}};
+    SYSTEM_MANDATORY_LABEL_ACE *ace;
+    char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+    SECURITY_DESCRIPTOR *sd2, *sd = (SECURITY_DESCRIPTOR *)&buffer_sd;
+    SECURITY_ATTRIBUTES sa;
+    char buffer_acl[256];
+    ACL *pAcl = (ACL *)&buffer_acl;
+    ACL *sAcl;
+    BOOL defaulted, present, ret, found, found2;
+    HANDLE handle;
+    DWORD index, size;
+
+    if (!pAddMandatoryAce)
+    {
+        win_skip("AddMandatoryAce not supported, skipping test\n");
+        return;
+    }
+
+    ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+    ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError());
+
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.lpSecurityDescriptor = sd;
+    sa.bInheritHandle       = FALSE;
+
+    handle = CreateEventA(&sa, TRUE, TRUE, "test_event");
+    ok(handle != NULL, "CreateEventA failed with error %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = TRUE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(!present, "sAcl is present\n");
+    ok(sAcl == (void *)0xdeadbeef, "sAcl is set\n");
+    todo_wine ok(!defaulted, "sAcl defaulted\n");
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+    CloseHandle(handle);
+
+    ret = InitializeAcl(pAcl, 256, ACL_REVISION);
+    ok(ret, "InitializeAcl failed with %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, 0x1234, &low_level);
+    ok(!ret, "AddMandatoryAce succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER,
+       "Expected ERROR_INVALID_PARAMETER got %u\n", GetLastError());
+
+    ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, &low_level);
+    ok(ret, "AddMandatoryAce failed with %u\n", GetLastError());
+
+    index = 0;
+    found = FALSE;
+    while (pGetAce( pAcl, index++, (void **)&ace ))
+    {
+        if (ace->Header.AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
+        ok(ace->Header.AceFlags == 0, "Expected flags 0, got %x\n", ace->Header.AceFlags);
+        ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
+           "Expected mask SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, got %x\n", ace->Mask);
+        ok(EqualSid(&ace->SidStart, &low_level), "Expected low integrity level\n");
+        found = TRUE;
+    }
+    ok(found, "Could not find mandatory label ace\n");
+
+    ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE);
+    ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+    handle = CreateEventA(&sa, TRUE, TRUE, "test_event");
+    ok(handle != NULL, "CreateEventA failed with error %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(present, "sAcl not present\n");
+    ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n");
+    ok(!defaulted, "sAcl defaulted\n");
+
+    index = 0;
+    found = FALSE;
+    while (pGetAce( sAcl, index++, (void **)&ace ))
+    {
+        if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
+        {
+            found = TRUE;
+            ok(ace->Header.AceFlags == 0, "Expected 0 as flags, got %x\n", ace->Header.AceFlags);
+            ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
+               "Expected SYSTEM_MANDATORY_LABEL_NO_WRITE_UP as flag, got %x\n", ace->Mask);
+            ok(EqualSid(&ace->SidStart, &low_level), "Expected low integrity level\n");
+        }
+    }
+    ok(found, "Could not find mandatory label\n");
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+
+    ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level);
+    ok(ret, "AddMandatoryAce failed with %u\n", GetLastError());
+
+    ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(present, "sAcl not present\n");
+    ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n");
+    ok(sAcl->AceCount == 2, "Expected 2 ACEs, got %d\n", sAcl->AceCount);
+    ok(!defaulted, "sAcl defaulted\n");
+
+    index = 0;
+    found = found2 = FALSE;
+    while (pGetAce( sAcl, index++, (void **)&ace ))
+    {
+        if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
+        {
+            if (EqualSid(&ace->SidStart, &low_level))
+            {
+                found = TRUE;
+                ok(ace->Header.AceFlags == 0, "Expected 0 as flags, got %x\n", ace->Header.AceFlags);
+                ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
+                   "Expected SYSTEM_MANDATORY_LABEL_NO_WRITE_UP as flag, got %x\n", ace->Mask);
+            }
+            if (EqualSid(&ace->SidStart, &medium_level))
+            {
+                found2 = TRUE;
+                ok(ace->Header.AceFlags == 0, "Expected 0 as flags, got %x\n", ace->Header.AceFlags);
+                ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
+                   "Expected SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP as flag, got %x\n", ace->Mask);
+            }
+        }
+    }
+    ok(found, "Could not find low mandatory label\n");
+    ok(found2, "Could not find medium mandatory label\n");
+
+    HeapFree( GetProcessHeap(), 0, sd2);
+
+    ret = SetSecurityDescriptorSacl(sd, FALSE, NULL, FALSE);
+    ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+    ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(present, "sAcl not present\n");
+    ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n");
+    ok(sAcl->AceCount == 0, "Expected 0 ACEs, got %d\n", sAcl->AceCount);
+    ok(!defaulted, "sAcl defaulted\n");
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+
+    ret = InitializeAcl(pAcl, 256, ACL_REVISION);
+    ok(ret, "InitializeAcl failed with %u\n", GetLastError());
+
+    ret = pAddMandatoryAce(pAcl, ACL_REVISION3, 0, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, &medium_level);
+    ok(ret, "AddMandatoryAce failed with %u\n", GetLastError());
+
+    ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE);
+    ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+    ret = SetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(present, "sAcl not present\n");
+    ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n");
+    ok(sAcl->AclRevision == ACL_REVISION3, "Expected revision 3, got %d\n", sAcl->AclRevision);
+    ok(!defaulted, "sAcl defaulted\n");
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+    CloseHandle(handle);
+
+    ret = OpenProcessToken(GetCurrentProcess(), READ_CONTROL, &handle);
+    ok(ret, "got %d with %d (expected TRUE)\n", ret, GetLastError());
+
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(handle, LABEL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    sAcl = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd2, &present, &sAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+    ok(present, "sAcl not present\n");
+    ok(sAcl != (void *)0xdeadbeef, "sAcl not set\n");
+    ok(sAcl->AceCount == 1, "Expected 1 ACEs, got %d\n", sAcl->AceCount);
+    ok(!defaulted, "sAcl defaulted\n");
+
+    index = 0;
+    found = FALSE;
+    while (pGetAce( sAcl, index++, (void **)&ace ))
+    {
+        if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE &&
+            (EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level)))
+        {
+            found = TRUE;
+            ok(ace->Header.AceFlags == 0, "Expected 0 as flags, got %x\n", ace->Header.AceFlags);
+            ok(ace->Mask == SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
+               "Expected SYSTEM_MANDATORY_LABEL_NO_WRITE_UP as flag, got %x\n", ace->Mask);
+        }
+    }
+    ok(found, "Could not find medium/high mandatory label\n");
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+    CloseHandle(handle);
+}
+
 static void test_system_security_access(void)
 {
     static const WCHAR testkeyW[] =
@@ -6653,6 +7017,524 @@ static void test_pseudo_tokens(void)
                  "Expected ERROR_NO_TOKEN, got %u\n", GetLastError());
 }
 
+static void test_maximum_allowed(void)
+{
+    HANDLE (WINAPI *pCreateEventExA)(SECURITY_ATTRIBUTES *, LPCSTR, DWORD, DWORD);
+    char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH], buffer_acl[256];
+    SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd;
+    SECURITY_ATTRIBUTES sa;
+    ACL *acl = (ACL *)&buffer_acl;
+    HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
+    ACCESS_MASK mask;
+    HANDLE handle;
+    BOOL ret;
+
+    pCreateEventExA = (void *)GetProcAddress(hkernel32, "CreateEventExA");
+    if (!pCreateEventExA)
+    {
+        win_skip("CreateEventExA is not available\n");
+        return;
+    }
+
+    ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+    ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError());
+    ret = InitializeAcl(acl, 256, ACL_REVISION);
+    ok(ret, "InitializeAcl failed with %u\n", GetLastError());
+    ret = SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with %u\n", GetLastError());
+
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.lpSecurityDescriptor = sd;
+    sa.bInheritHandle       = FALSE;
+
+    handle = pCreateEventExA(&sa, NULL, 0, MAXIMUM_ALLOWED | 0x4);
+    ok(handle != NULL, "CreateEventExA failed with error %u\n", GetLastError());
+    mask = get_obj_access(handle);
+    ok(mask == EVENT_ALL_ACCESS, "Expected %x, got %x\n", EVENT_ALL_ACCESS, mask);
+    CloseHandle(handle);
+}
+
+static void test_GetExplicitEntriesFromAclW(void)
+{
+    static const WCHAR wszCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'};
+    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY };
+    SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY };
+    PSID everyone_sid = NULL, users_sid = NULL;
+    EXPLICIT_ACCESSW access;
+    EXPLICIT_ACCESSW *access2;
+    PACL new_acl, old_acl = NULL;
+    ULONG count;
+    DWORD res;
+
+    if (!pGetExplicitEntriesFromAclW)
+    {
+        win_skip("GetExplicitEntriesFromAclW is not available\n");
+        return;
+    }
+
+    if (!pSetEntriesInAclW)
+    {
+        win_skip("SetEntriesInAclW is not available\n");
+        return;
+    }
+
+    old_acl = HeapAlloc(GetProcessHeap(), 0, 256);
+    res = InitializeAcl(old_acl, 256, ACL_REVISION);
+    if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("ACLs not implemented - skipping tests\n");
+        HeapFree(GetProcessHeap(), 0, old_acl);
+        return;
+    }
+    ok(res, "InitializeAcl failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+                                   DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &users_sid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AddAccessAllowedAce(old_acl, ACL_REVISION, KEY_READ, users_sid);
+    ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError());
+
+    access2 = NULL;
+    res = pGetExplicitEntriesFromAclW(old_acl, &count, &access2);
+    ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError());
+    ok(count == 1, "Expected count == 1, got %d\n", count);
+    ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode);
+    ok(access2[0].grfAccessPermissions == KEY_READ, "Expected KEY_READ, got %d\n", access2[0].grfAccessPermissions);
+    ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm);
+    ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance);
+    ok(EqualSid(access2[0].Trustee.ptstrName, users_sid), "Expected equal SIDs\n");
+    LocalFree(access2);
+
+    access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+    access.Trustee.pMultipleTrustee = NULL;
+
+    access.grfAccessPermissions = KEY_WRITE;
+    access.grfAccessMode = GRANT_ACCESS;
+    access.grfInheritance = NO_INHERITANCE;
+    access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+    access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    access.Trustee.ptstrName = everyone_sid;
+    res = pSetEntriesInAclW(1, &access, old_acl, &new_acl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(new_acl != NULL, "returned acl was NULL\n");
+
+    access2 = NULL;
+    res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2);
+    ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError());
+    ok(count == 2, "Expected count == 2, got %d\n", count);
+    ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode);
+    ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions);
+    ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN,
+       "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType);
+    ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm);
+    ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance);
+    ok(EqualSid(access2[0].Trustee.ptstrName, everyone_sid), "Expected equal SIDs\n");
+    LocalFree(access2);
+    LocalFree(new_acl);
+
+    access.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+    res = pSetEntriesInAclW(1, &access, old_acl, &new_acl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(new_acl != NULL, "returned acl was NULL\n");
+
+    access2 = NULL;
+    res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2);
+    ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError());
+    ok(count == 2, "Expected count == 2, got %d\n", count);
+    ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode);
+    ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions);
+    ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN,
+       "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType);
+    ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm);
+    ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance);
+    ok(EqualSid(access2[0].Trustee.ptstrName, everyone_sid), "Expected equal SIDs\n");
+    LocalFree(access2);
+    LocalFree(new_acl);
+
+    access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+    access.Trustee.ptstrName = (LPWSTR)wszCurrentUser;
+    res = pSetEntriesInAclW(1, &access, old_acl, &new_acl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(new_acl != NULL, "returned acl was NULL\n");
+
+    access2 = NULL;
+    res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2);
+    ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError());
+    ok(count == 2, "Expected count == 2, got %d\n", count);
+    ok(access2[0].grfAccessMode == GRANT_ACCESS, "Expected GRANT_ACCESS, got %d\n", access2[0].grfAccessMode);
+    ok(access2[0].grfAccessPermissions == KEY_WRITE, "Expected KEY_WRITE, got %d\n", access2[0].grfAccessPermissions);
+    ok(access2[0].Trustee.TrusteeType == TRUSTEE_IS_UNKNOWN,
+       "Expected TRUSTEE_IS_UNKNOWN trustee type, got %d\n", access2[0].Trustee.TrusteeType);
+    ok(access2[0].Trustee.TrusteeForm == TRUSTEE_IS_SID, "Expected SID trustee, got %d\n", access2[0].Trustee.TrusteeForm);
+    ok(access2[0].grfInheritance == NO_INHERITANCE, "Expected NO_INHERITANCE, got %x\n", access2[0].grfInheritance);
+    LocalFree(access2);
+    LocalFree(new_acl);
+
+    access.grfAccessMode = REVOKE_ACCESS;
+    access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    access.Trustee.ptstrName = users_sid;
+    res = pSetEntriesInAclW(1, &access, old_acl, &new_acl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(new_acl != NULL, "returned acl was NULL\n");
+
+    access2 = (void *)0xdeadbeef;
+    res = pGetExplicitEntriesFromAclW(new_acl, &count, &access2);
+    ok(res == ERROR_SUCCESS, "GetExplicitEntriesFromAclW failed with error %d\n", GetLastError());
+    ok(count == 0, "Expected count == 0, got %d\n", count);
+    ok(access2 == NULL, "access2 was not NULL\n");
+    LocalFree(new_acl);
+
+    FreeSid(users_sid);
+    FreeSid(everyone_sid);
+    HeapFree(GetProcessHeap(), 0, old_acl);
+}
+
+static void test_token_security_descriptor(void)
+{
+    static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+                                             {SECURITY_MANDATORY_LOW_RID}};
+    ACCESS_ALLOWED_ACE *ace;
+    char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+    SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2;
+    char buffer_acl[256], buffer[MAX_PATH];
+    ACL *pAcl = (ACL *)&buffer_acl, *pAcl2, *pAclChild;
+    BOOL defaulted, present, ret, found;
+    HANDLE token, token2, token3;
+    EXPLICIT_ACCESSW exp_access;
+    PROCESS_INFORMATION info;
+    SECURITY_ATTRIBUTES sa;
+    DWORD size, index, retd;
+    STARTUPINFOA startup;
+    PSID psid;
+
+    if (!pDuplicateTokenEx || !pConvertStringSidToSidA || !pAddAccessAllowedAceEx || !pGetAce || !pSetEntriesInAclW)
+    {
+        win_skip("Some functions not available\n");
+        return;
+    }
+
+    /* Test whether we can create tokens with security descriptors */
+    ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
+    ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
+
+    ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+    ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError());
+
+    ret = InitializeAcl(pAcl, 256, ACL_REVISION);
+    ok(ret, "InitializeAcl failed with %u\n", GetLastError());
+
+    ret = pConvertStringSidToSidA("S-1-5-6", &psid);
+    ok(ret, "ConvertStringSidToSidA failed with %u\n", GetLastError());
+
+    ret = pAddAccessAllowedAceEx(pAcl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, GENERIC_ALL, psid);
+    ok(ret, "AddAccessAllowedAceEx failed with %u\n", GetLastError());
+
+    ret = SetSecurityDescriptorDacl(sd, TRUE, pAcl, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with %u\n", GetLastError());
+
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.lpSecurityDescriptor = sd;
+    sa.bInheritHandle       = FALSE;
+
+    ret = pDuplicateTokenEx(token, MAXIMUM_ALLOWED, &sa, SecurityImpersonation, TokenImpersonation, &token2);
+    ok(ret, "DuplicateTokenEx failed with %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(token2, DACL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(token2, DACL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    pAcl2 = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted);
+    ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError());
+    ok(present, "pAcl2 not present\n");
+    ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n");
+    ok(pAcl2->AceCount == 1, "Expected 1 ACEs, got %d\n", pAcl2->AceCount);
+    ok(!defaulted, "pAcl2 defaulted\n");
+
+    index = 0;
+    found = FALSE;
+    while (pGetAce( pAcl2, index++, (void **)&ace ))
+    {
+        if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid))
+        {
+            found = TRUE;
+            ok(ace->Header.AceFlags == NO_PROPAGATE_INHERIT_ACE,
+               "Expected NO_PROPAGATE_INHERIT_ACE as flags, got %x\n", ace->Header.AceFlags);
+        }
+    }
+    ok(found, "Could not find access allowed ace\n");
+
+    HeapFree( GetProcessHeap(), 0, sd2);
+
+    /* Duplicate token without security attributes.
+     * Tokens do not inherit the security descriptor when calling DuplicateToken,
+     * see https://blogs.msdn.microsoft.com/oldnewthing/20160512-00/?p=93447
+     */
+    ret = pDuplicateTokenEx(token2, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenImpersonation, &token3);
+    ok(ret, "DuplicateTokenEx failed with %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(token3, DACL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(token3, DACL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    pAcl2 = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted);
+    ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError());
+    todo_wine
+    ok(present, "pAcl2 not present\n");
+    ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n");
+    ok(!defaulted, "pAcl2 defaulted\n");
+
+    if (pAcl2)
+    {
+        index = 0;
+        found = FALSE;
+        while (pGetAce( pAcl2, index++, (void **)&ace ))
+        {
+            if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid))
+                found = TRUE;
+        }
+        ok(!found, "Access allowed ace got inherited!\n");
+    }
+
+    HeapFree(GetProcessHeap(), 0, sd2);
+
+    /* When creating a child process, the process does only inherit the
+     * Token of the parent, but not the DACL of the token.
+     */
+    ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd2 = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd2, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    pAcl2 = (void *)0xdeadbeef;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorDacl(sd2, &present, &pAcl2, &defaulted);
+    ok(ret, "GetSecurityDescriptorDacl failed with %u\n", GetLastError());
+    ok(present, "pAcl2 not present\n");
+    ok(pAcl2 != (void *)0xdeadbeef, "pAcl2 not set\n");
+    ok(!defaulted, "pAcl2 defaulted\n");
+
+    /* check that the ace we add for testing does not already exist! */
+    if (pAcl2)
+    {
+        index = 0;
+        found = FALSE;
+        while (pGetAce( pAcl2, index++, (void **)&ace ))
+        {
+            if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid))
+                found = TRUE;
+        }
+        ok(!found, "Test ace does already exist!\n");
+    }
+
+    exp_access.grfAccessPermissions = GENERIC_ALL;
+    exp_access.grfAccessMode = GRANT_ACCESS;
+    exp_access.grfInheritance = NO_PROPAGATE_INHERIT_ACE;
+    exp_access.Trustee.pMultipleTrustee = NULL;
+    exp_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    exp_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+    exp_access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+    exp_access.Trustee.ptstrName = (void*)psid;
+
+    retd = pSetEntriesInAclW(1, &exp_access, pAcl2, &pAclChild);
+    ok(retd == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", retd);
+
+    memset(sd, 0, sizeof(buffer_sd));
+    ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+    ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError());
+
+    ret = SetSecurityDescriptorDacl(sd, TRUE, pAclChild, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with %u\n", GetLastError());
+
+    ret = SetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd);
+    ok(ret, "SetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    /* The security label is also not inherited */
+    if (pAddMandatoryAce)
+    {
+        ret = InitializeAcl(pAcl, 256, ACL_REVISION);
+        ok(ret, "InitializeAcl failed with %u\n", GetLastError());
+
+        ret = pAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, &low_level);
+        ok(ret, "AddMandatoryAce failed with %u\n", GetLastError());
+
+        memset(sd, 0, sizeof(buffer_sd));
+        ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
+        ok(ret, "InitializeSecurityDescriptor failed with %u\n", GetLastError());
+
+        ret = SetSecurityDescriptorSacl(sd, TRUE, pAcl, FALSE);
+        ok(ret, "SetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+        ret = SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd);
+        ok(ret, "SetKernelObjectSecurity failed with %u\n", GetLastError());
+    }
+    else
+        win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
+
+    /* start child process with our modified token */
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = SW_SHOWNORMAL;
+
+    sprintf(buffer, "%s tests/security.c test_token_sd", myARGV[0]);
+    ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
+    ok(ret, "CreateProcess failed with error %u\n", GetLastError());
+    winetest_wait_child_process(info.hProcess);
+    CloseHandle(info.hProcess);
+    CloseHandle(info.hThread);
+
+    LocalFree(pAclChild);
+    LocalFree(psid);
+
+    CloseHandle(token3);
+    CloseHandle(token2);
+    CloseHandle(token);
+}
+
+static void test_child_token_sd(void)
+{
+    static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+                                             {SECURITY_MANDATORY_LOW_RID}};
+    SYSTEM_MANDATORY_LABEL_ACE *ace_label;
+    BOOL ret, present, defaulted, found;
+    ACCESS_ALLOWED_ACE *ace_acc;
+    SECURITY_DESCRIPTOR *sd;
+    DWORD size, index;
+    HANDLE token;
+    ACL *pAcl;
+    PSID psid;
+
+    ret = pConvertStringSidToSidA("S-1-5-6", &psid);
+    ok(ret, "ConvertStringSidToSidA failed with %u\n", GetLastError());
+
+    ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
+    ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
+
+    ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(token, DACL_SECURITY_INFORMATION, sd, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    pAcl = NULL;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorDacl(sd, &present, &pAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+    index = 0;
+    found = FALSE;
+    if (present && pAcl)
+    {
+        ok(pAcl->AceCount > 0, "Expected at least one ACE\n");
+        while (pGetAce( pAcl, index++, (void **)&ace_acc ))
+        {
+            if (ace_acc->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace_acc->SidStart, psid))
+                found = TRUE;
+        }
+    }
+    ok(!found, "The ACE should not haven been inherited from the parent\n");
+
+    LocalFree(psid);
+    HeapFree(GetProcessHeap(), 0, sd);
+
+    if (!pAddMandatoryAce)
+    {
+        win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
+        return;
+    }
+
+    ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "GetKernelObjectSecurity failed with %u\n", GetLastError());
+
+    sd = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size);
+    ok(ret, "GetKernelObjectSecurity failed %u\n", GetLastError());
+
+    pAcl = NULL;
+    present = FALSE;
+    defaulted = TRUE;
+    ret = GetSecurityDescriptorSacl(sd, &present, &pAcl, &defaulted);
+    ok(ret, "GetSecurityDescriptorSacl failed with %u\n", GetLastError());
+
+    index = 0;
+    found = FALSE;
+    if (present && pAcl)
+    {
+        while (pGetAce( pAcl, index++, (void **)&ace_label ))
+        {
+            if (ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE && EqualSid(&ace_label->SidStart, &low_level))
+                found = TRUE;
+        }
+    }
+    ok(!found, "Low integrity level should not have been inherited\n");
+
+    HeapFree(GetProcessHeap(), 0, sd);
+}
+
+static void test_BuildSecurityDescriptorW(void)
+{
+    SECURITY_DESCRIPTOR old_sd, *new_sd, *rel_sd;
+    ULONG new_sd_size;
+    DWORD buf_size;
+    char buf[1024];
+    BOOL success;
+    DWORD ret;
+
+    InitializeSecurityDescriptor(&old_sd, SECURITY_DESCRIPTOR_REVISION);
+
+    buf_size = sizeof(buf);
+    rel_sd = (SECURITY_DESCRIPTOR *)buf;
+    success = MakeSelfRelativeSD(&old_sd, rel_sd, &buf_size);
+    ok(success, "MakeSelfRelativeSD failed with %u\n", GetLastError());
+
+    new_sd = NULL;
+    new_sd_size = 0;
+    ret = BuildSecurityDescriptorW(NULL, NULL, 0, NULL, 0, NULL, NULL, &new_sd_size, (void **)&new_sd);
+    ok(ret == ERROR_SUCCESS, "BuildSecurityDescriptor failed with %u\n", ret);
+    ok(new_sd != NULL, "expected new_sd != NULL\n");
+    ok(new_sd_size == sizeof(old_sd), "expected new_sd_size == sizeof(old_sd), got %u\n", new_sd_size);
+    LocalFree(new_sd);
+
+    new_sd = (void *)0xdeadbeef;
+    ret = BuildSecurityDescriptorW(NULL, NULL, 0, NULL, 0, NULL, &old_sd, &new_sd_size, (void **)&new_sd);
+    ok(ret == ERROR_INVALID_SECURITY_DESCR, "expected ERROR_INVALID_SECURITY_DESCR, got %u\n", ret);
+    ok(new_sd == (void *)0xdeadbeef, "expected new_sd == 0xdeadbeef, got %p\n", new_sd);
+
+    new_sd = NULL;
+    new_sd_size = 0;
+    ret = BuildSecurityDescriptorW(NULL, NULL, 0, NULL, 0, NULL, rel_sd, &new_sd_size, (void **)&new_sd);
+    ok(ret == ERROR_SUCCESS, "BuildSecurityDescriptor failed with %u\n", ret);
+    ok(new_sd != NULL, "expected new_sd != NULL\n");
+    ok(new_sd_size == sizeof(old_sd), "expected new_sd_size == sizeof(old_sd), got %u\n", new_sd_size);
+    LocalFree(new_sd);
+}
+
 START_TEST(security)
 {
     init();
@@ -6660,7 +7542,10 @@ START_TEST(security)
 
     if (myARGC >= 3)
     {
-        test_process_security_child();
+        if (!strcmp(myARGV[2], "test_token_sd"))
+            test_child_token_sd();
+        else
+            test_process_security_child();
         return;
     }
     test_kernel_objects_security();
@@ -6671,6 +7556,7 @@ START_TEST(security)
     test_FileSecurity();
     test_AccessCheck();
     test_token_attr();
+    test_GetTokenInformation();
     test_LookupAccountSid();
     test_LookupAccountName();
     test_security_descriptor();
@@ -6696,7 +7582,14 @@ START_TEST(security)
     test_default_dacl_owner_sid();
     test_AdjustTokenPrivileges();
     test_AddAce();
+    test_AddMandatoryAce();
     test_system_security_access();
     test_GetSidIdentifierAuthority();
     test_pseudo_tokens();
+    test_maximum_allowed();
+    test_GetExplicitEntriesFromAclW();
+    test_BuildSecurityDescriptorW();
+
+    /* must be the last test, modifies process token */
+    test_token_security_descriptor();
 }
index 2b533ed..3a85b1c 100644 (file)
@@ -382,7 +382,7 @@ static void test_create_delete_svc(void)
         {
             svc_handle1 = CreateServiceA(scm_handle, servicename, display, 0, SERVICE_WIN32_OWN_PROCESS,
                                          SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
-            ok(!svc_handle1, "Expected failure\n");
+            ok(!svc_handle1, "Expected failure for display name '%s'\n", display);
             ok(GetLastError() == ERROR_DUPLICATE_SERVICE_NAME,
                "Expected ERROR_DUPLICATE_SERVICE_NAME, got %d\n", GetLastError());
         }
@@ -1404,7 +1404,7 @@ static void test_enum_svc(void)
 
         /* lpServiceName and lpDisplayName should always be filled */
         ok(services[i].lpServiceName[0], "Expected a service name\n");
-        ok(services[i].lpDisplayName[0], "Expected a display name\n");
+        ok(services[i].lpDisplayName && services[i].lpDisplayName[0], "Expected a display name\n");
 
         /* Decrement the counters to see if the functions calls return the same
          * numbers as the contents of these structures.
@@ -1707,7 +1707,7 @@ static void test_enum_svc(void)
 
         /* lpServiceName and lpDisplayName should always be filled */
         ok(exservices[i].lpServiceName[0], "Expected a service name\n");
-        ok(exservices[i].lpDisplayName[0], "Expected a display name\n");
+        ok(exservices[i].lpDisplayName && exservices[i].lpDisplayName[0], "Expected a display name\n");
 
         /* Decrement the counters to see if the functions calls return the
          * same numbers as the contents of these structures.