- Sync to date wine AdvApi32 cross tests.
authorJames Tabor <james.tabor@reactos.org>
Tue, 9 Dec 2008 19:26:45 +0000 (19:26 +0000)
committerJames Tabor <james.tabor@reactos.org>
Tue, 9 Dec 2008 19:26:45 +0000 (19:26 +0000)
svn path=/trunk/; revision=37982

rostests/winetests/advapi32/cred.c
rostests/winetests/advapi32/crypt.c
rostests/winetests/advapi32/registry.c
rostests/winetests/advapi32/security.c
rostests/winetests/advapi32/service.c

index 1bb2545..df14439 100644 (file)
@@ -97,12 +97,19 @@ static void test_CredWriteA(void)
 
     SetLastError(0xdeadbeef);
     ret = pCredWriteA(&new_cred, 0);
-    ok(!ret, "CredWrite with username without domain should have failed\n");
-    ok(GetLastError() == ERROR_BAD_USERNAME ||
-       GetLastError() == ERROR_NO_SUCH_LOGON_SESSION || /* Vista */
-       broken(GetLastError() == ERROR_IO_PENDING),
-       "CredWrite with username without domain should return ERROR_BAD_USERNAME"
-       "or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError());
+    if (ret)
+    {
+        /* Vista */
+        ok(GetLastError() == ERROR_IO_PENDING,
+           "Expected ERROR_IO_PENDING, got %d\n", GetLastError());
+    }
+    else
+    {
+        ok(GetLastError() == ERROR_BAD_USERNAME ||
+           GetLastError() == ERROR_NO_SUCH_LOGON_SESSION, /* Vista */
+           "CredWrite with username without domain should return ERROR_BAD_USERNAME"
+           "or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError());
+    }
 
     new_cred.UserName = NULL;
     SetLastError(0xdeadbeef);
index 1d2cfa2..44d0896 100644 (file)
@@ -274,11 +274,11 @@ static void test_incorrect_api_usage(void)
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
-    result = pCryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen);
+    result = pCryptDecrypt(hKey, 0, TRUE, 0, &temp, &dwLen);
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
-    result = pCryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen, 1);
+    result = pCryptEncrypt(hKey, 0, TRUE, 0, &temp, &dwLen, 1);
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hKey2);
@@ -293,7 +293,7 @@ static void test_incorrect_api_usage(void)
 #endif
 
     dwLen = 1;
-    result = pCryptExportKey(hKey, (HCRYPTPROV)NULL, 0, 0, &temp, &dwLen);
+    result = pCryptExportKey(hKey, 0, 0, 0, &temp, &dwLen);
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
@@ -320,7 +320,7 @@ static void test_incorrect_api_usage(void)
     result = pCryptHashSessionKey(hHash, hKey, 0);
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
-    result = pCryptImportKey(hProv, &temp, 1, (HCRYPTKEY)NULL, 0, &hKey2);
+    result = pCryptImportKey(hProv, &temp, 1, 0, 0, &hKey2);
     ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     if (pCryptSignHashW)
@@ -560,59 +560,77 @@ static void test_enum_providers(void)
        LocalFree(provider);
 }
 
-static BOOL FindProvTypesRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszTypeName, 
+static BOOL FindProvTypesRegVals(DWORD *pdwIndex, DWORD *pdwProvType, LPSTR *pszTypeName,
                                 DWORD *pcbTypeName, DWORD *pdwTypeCount)
 {
        HKEY hKey;
        HKEY hSubKey;
        PSTR ch;
-       
+       LPSTR szName;
+       DWORD cbName;
+       BOOL ret = FALSE;
+
        if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types", &hKey))
                return FALSE;
-       
-       if (RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwTypeCount, pcbTypeName, NULL,
+
+       if (RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwTypeCount, &cbName, NULL,
                        NULL, NULL, NULL, NULL, NULL))
-           return FALSE;
-       (*pcbTypeName)++;
-       
-       if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName))))
-               return FALSE;
-       
-       if (RegEnumKeyEx(hKey, dwIndex, *pszTypeName, pcbTypeName, NULL, NULL, NULL, NULL))
-           return FALSE;
-       (*pcbTypeName)++;
-       ch = *pszTypeName + strlen(*pszTypeName);
-       /* Convert "Type 000" to 0, etc/ */
-       *pdwProvType = *(--ch) - '0';
-       *pdwProvType += (*(--ch) - '0') * 10;
-       *pdwProvType += (*(--ch) - '0') * 100;
-       
-       if (RegOpenKey(hKey, *pszTypeName, &hSubKey))
-           return FALSE;
-       
-       if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, NULL, pcbTypeName))
-            return FALSE;
+               goto cleanup;
+       cbName++;
 
-       if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName))))
-               return FALSE;
-       
-       if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, (LPBYTE)*pszTypeName, pcbTypeName))
-           return FALSE;
-       
+       if (!(szName = LocalAlloc(LMEM_ZEROINIT, cbName)))
+               goto cleanup;
+
+       while (!RegEnumKeyEx(hKey, *pdwIndex, szName, &cbName, NULL, NULL, NULL, NULL))
+       {
+               cbName++;
+               ch = szName + strlen(szName);
+               /* Convert "Type 000" to 0, etc/ */
+               *pdwProvType = *(--ch) - '0';
+               *pdwProvType += (*(--ch) - '0') * 10;
+               *pdwProvType += (*(--ch) - '0') * 100;
+
+               if (RegOpenKey(hKey, szName, &hSubKey))
+                       break;
+
+               if (!RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, NULL, pcbTypeName))
+               {
+                       if (!(*pszTypeName = LocalAlloc(LMEM_ZEROINIT, *pcbTypeName)))
+                               break;
+
+                       if (!RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, (LPBYTE)*pszTypeName, pcbTypeName))
+                       {
+                               ret = TRUE;
+                               break;
+                       }
+
+                       LocalFree(*pszTypeName);
+               }
+
+               RegCloseKey(hSubKey);
+
+               (*pdwIndex)++;
+       }
+
+       if (!ret)
+               LocalFree(*pszTypeName);
        RegCloseKey(hSubKey);
+       LocalFree(szName);
+
+cleanup:
        RegCloseKey(hKey);
-       
-       return TRUE;
+
+       return ret;
 }
 
 static void test_enum_provider_types(void)
 {
        /* expected values */
-       DWORD dwProvType;
+       DWORD dwProvType = 0;
        LPSTR pszTypeName = NULL;
        DWORD cbTypeName;
        DWORD dwTypeCount;
-       
+
        /* actual values */
        DWORD index = 0;
        DWORD provType;
@@ -622,45 +640,47 @@ static void test_enum_provider_types(void)
        DWORD result;
        DWORD notNull = 5;
        DWORD notZeroFlags = 5;
-       
+
        if(!pCryptEnumProviderTypesA)
        {
-           skip("CryptEnumProviderTypesA is not available\n");
-           return;
+               skip("CryptEnumProviderTypesA is not available\n");
+               return;
        }
-       
-       if (!FindProvTypesRegVals(index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount))
+
+       if (!FindProvTypesRegVals(&index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount))
        {
-           skip("Could not find provider types in registry\n");
-           return;
+               skip("Could not find provider types in registry\n");
+               return;
        }
-       
+
        /* check pdwReserved for NULL */
        result = pCryptEnumProviderTypesA(index, &notNull, 0, &provType, typeName, &typeNameSize);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %d\n", 
-               ERROR_INVALID_PARAMETER, GetLastError());
-       
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n",
+               GetLastError());
+
        /* check dwFlags == zero */
        result = pCryptEnumProviderTypesA(index, NULL, notZeroFlags, &provType, typeName, &typeNameSize);
-       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %i, got %d\n",
-               ERROR_INVALID_PARAMETER, GetLastError());
-       
-       /* alloc provider type to half the size required
-        * cbTypeName holds the size required */
-       typeNameSize = cbTypeName / 2;
-       if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize))))
-               return;
+       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected ERROR_INVALID_PARAMETER, got %d\n",
+               GetLastError());
 
        /* This test fails under Win2k SP4:
-          result = TRUE, GetLastError() == 0xdeadbeef
-       SetLastError(0xdeadbeef);
-       result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize);
-       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected 0/ERROR_MORE_DATA, got %d/%08lx\n",
-               result, GetLastError());
-       */
-       
-       LocalFree(typeName);
-       
+        * result = TRUE, GetLastError() == 0xdeadbeef */
+       if (0)
+       {
+               /* alloc provider type to half the size required
+                * cbTypeName holds the size required */
+               typeNameSize = cbTypeName / 2;
+               if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize))))
+                       goto cleanup;
+
+               SetLastError(0xdeadbeef);
+               result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize);
+               ok(!result && GetLastError()==ERROR_MORE_DATA, "expected 0/ERROR_MORE_DATA, got %d/%d\n",
+                       result, GetLastError());
+
+               LocalFree(typeName);
+       }
+
        /* loop through the provider types to get the number of provider types 
         * after loop ends, count should be dwTypeCount + 1 so subtract 1
         * to get actual number of provider types */
@@ -669,30 +689,31 @@ static void test_enum_provider_types(void)
                ;
        typeCount--;
        ok(typeCount==dwTypeCount, "expected %d, got %d\n", dwTypeCount, typeCount);
-       
+
        /* loop past the actual number of provider types to get the error
         * ERROR_NO_MORE_ITEMS */
        for (typeCount = 0; typeCount < dwTypeCount + 1; typeCount++)
                result = pCryptEnumProviderTypesA(typeCount, NULL, 0, &provType, NULL, &typeNameSize);
-       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %d\n", 
-                       ERROR_NO_MORE_ITEMS, GetLastError());
-       
+       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n",
+               GetLastError());
 
        /* check expected versus actual values returned */
        result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, NULL, &typeNameSize);
        ok(result && typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize);
        if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize))))
-               return;
-               
+               goto cleanup;
+
        typeNameSize = 0xdeadbeef;
        result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize);
        ok(result, "expected TRUE, got %d\n", result);
        ok(provType==dwProvType, "expected %d, got %d\n", dwProvType, provType);
        if (pszTypeName)
-           ok(!strcmp(pszTypeName, typeName), "expected %s, got %s\n", pszTypeName, typeName);
+               ok(!strcmp(pszTypeName, typeName), "expected %s, got %s\n", pszTypeName, typeName);
        ok(typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize);
-       
+
        LocalFree(typeName);
+cleanup:
+       LocalFree(pszTypeName);
 }
 
 static BOOL FindDfltProvRegVals(DWORD dwProvType, DWORD dwFlags, LPSTR *pszProvName, DWORD *pcbProvName)
index 95608c6..6eb9d54 100644 (file)
@@ -199,13 +199,14 @@ static void setup_main_key(void)
     assert (!RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main ));
 }
 
-static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string,
+#define lok ok_(__FILE__, line)
+#define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len)
+static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
                                    DWORD full_byte_len)
 {
     DWORD ret, type, cbData;
     DWORD str_byte_len;
-    LPSTR value;
-    static const char nA[]={'N', 0};
+    BYTE* value;
 
     type=0xdeadbeef;
     cbData=0xdeadbeef;
@@ -215,43 +216,44 @@ static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string,
     SetLastError(0xdeadbeef);
     ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
     GLE = GetLastError();
-    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
+    lok(ret == ERROR_SUCCESS, "RegQueryValueExA/1 failed: %d, GLE=%d\n", ret, GLE);
     /* It is wrong for the Ansi version to not be implemented */
     ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE);
     if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
 
     str_byte_len = (string ? lstrlenA(string) : 0) + 1;
-    ok(type == REG_SZ, "RegQueryValueExA returned type %d\n", type);
-    ok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */,
+    lok(type == REG_SZ, "RegQueryValueExA/1 returned type %d\n", type);
+    lok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */,
         "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
 
-    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
-    strcpy(value, nA);
+    value = HeapAlloc(GetProcessHeap(), 0, cbData+1);
+    memset(value, 0xbd, cbData+1);
     type=0xdeadbeef;
-    ret = RegQueryValueExA(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
+    ret = RegQueryValueExA(hkey_main, name, NULL, &type, value, &cbData);
     GLE = GetLastError();
-    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
+    lok(ret == ERROR_SUCCESS, "RegQueryValueExA/2 failed: %d, GLE=%d\n", ret, GLE);
     if (!string)
     {
         /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
-        ok(strcmp(value, nA) == 0 || (cbData == 1 && *value == '\0') /* Win9x */,
-           "RegQueryValueExA failed: '%s' != '%s'\n", value, string);
+        lok(*value == 0xbd || (cbData == 1 && *value == '\0') /* Win9x */,
+           "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value);
     }
     else
     {
-        ok(memcmp(value, string, cbData) == 0, "RegQueryValueExA failed: %s/%d != %s/%d\n",
-           wine_debugstr_an(value, cbData), cbData,
+        lok(memcmp(value, string, cbData) == 0, "RegQueryValueExA/2 failed: %s/%d != %s/%d\n",
+           wine_debugstr_an((char*)value, cbData), cbData,
            wine_debugstr_an(string, full_byte_len), full_byte_len);
+        lok(*(value+cbData) == 0xbd, "RegQueryValueExA/2 overflowed at offset %u: %02x != bd\n", cbData, *(value+cbData));
     }
     HeapFree(GetProcessHeap(), 0, value);
 }
 
-static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string,
+#define test_hkey_main_Value_W(name, string, full_byte_len) _test_hkey_main_Value_W(__LINE__, name, string, full_byte_len)
+static void _test_hkey_main_Value_W(int line, LPCWSTR name, LPCWSTR string,
                                    DWORD full_byte_len)
 {
     DWORD ret, type, cbData;
-    LPWSTR value;
-    static const WCHAR nW[]={'N', 0};
+    BYTE* value;
 
     type=0xdeadbeef;
     cbData=0xdeadbeef;
@@ -261,31 +263,33 @@ static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string,
     SetLastError(0xdeadbeef);
     ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData);
     GLE = GetLastError();
-    ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE);
+    lok(ret == ERROR_SUCCESS, "RegQueryValueExW/1 failed: %d, GLE=%d\n", ret, GLE);
     if(GLE == ERROR_CALL_NOT_IMPLEMENTED)
     {
         win_skip("RegQueryValueExW() is not implemented\n");
         return;
     }
 
-    ok(type == REG_SZ, "RegQueryValueExW returned type %d\n", type);
-    ok(cbData == full_byte_len,
+    lok(type == REG_SZ, "RegQueryValueExW/1 returned type %d\n", type);
+    lok(cbData == full_byte_len,
         "cbData=%d instead of %d\n", cbData, full_byte_len);
 
-    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
-    lstrcpyW(value, nW);
+    /* Give enough space to overflow by one WCHAR */
+    value = HeapAlloc(GetProcessHeap(), 0, cbData+2);
+    memset(value, 0xbd, cbData+2);
     type=0xdeadbeef;
-    ret = RegQueryValueExW(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
+    ret = RegQueryValueExW(hkey_main, name, NULL, &type, value, &cbData);
     GLE = GetLastError();
-    ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE);
-    if (!string)
+    lok(ret == ERROR_SUCCESS, "RegQueryValueExW/2 failed: %d, GLE=%d\n", ret, GLE);
+    if (string)
     {
-        /* When cbData == 0, RegQueryValueExW() should not modify the buffer */
-        string=nW;
+        lok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
+           wine_debugstr_wn((WCHAR*)value, cbData / sizeof(WCHAR)), cbData,
+           wine_debugstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
     }
-    ok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
-       wine_debugstr_wn(value, cbData / sizeof(WCHAR)), cbData,
-       wine_debugstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
+    /* This implies that when cbData == 0, RegQueryValueExW() should not modify the buffer */
+    lok(*(value+cbData) == 0xbd, "RegQueryValueExW/2 overflowed at %u: %02x != bd\n", cbData, *(value+cbData));
+    lok(*(value+cbData+1) == 0xbd, "RegQueryValueExW/2 overflowed at %u+1: %02x != bd\n", cbData, *(value+cbData+1));
     HeapFree(GetProcessHeap(), 0, value);
 }
 
@@ -957,6 +961,14 @@ static void test_reg_open_key(void)
            ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */
            , "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
 
+    hkResult = NULL;
+    ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult);
+    ok(ret == ERROR_SUCCESS || /* 2k/XP */
+       ret == ERROR_BAD_PATHNAME || /* NT */
+       ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */
+       , "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
+    RegCloseKey(hkResult);
+
     /* WOW64 flags */
     hkResult = NULL;
     ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult);
@@ -1308,6 +1320,87 @@ cleanup:
     RegCloseKey(subkey);
 }
 
+static void test_string_termination(void)
+{
+    HKEY subkey;
+    LSTATUS ret;
+    static const char string[] = "FullString";
+    char name[11];
+    BYTE buffer[11];
+    DWORD insize, outsize, nsize;
+
+    ret = RegCreateKeyA(hkey_main, "string_termination", &subkey);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */
+    insize=sizeof(string)-1;
+    ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
+    outsize=insize;
+    ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
+    ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %d\n", ret);
+
+    /* Off-by-two RegSetValueExA -> no trailing '\0', except on Win9x */
+    insize=sizeof(string)-2;
+    ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
+    outsize=0;
+    ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize);
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
+    ok(outsize == insize || broken(outsize == sizeof(string)) /* Win9x */,
+       "wrong size %u != %u\n", outsize, insize);
+
+    if (outsize == insize)
+    {
+        /* RegQueryValueExA may return a string with no trailing '\0' */
+        outsize=insize;
+        memset(buffer, 0xbd, sizeof(buffer));
+        ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
+        ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
+        ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
+        ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
+           wine_debugstr_an((char*)buffer, outsize), outsize, string);
+        ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
+
+        /* RegQueryValueExA adds a trailing '\0' if there is room */
+        outsize=insize+1;
+        memset(buffer, 0xbd, sizeof(buffer));
+        ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
+        ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
+        ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
+        ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
+           wine_debugstr_an((char*)buffer, outsize), outsize, string);
+        ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
+
+        /* RegEnumValueA may return a string with no trailing '\0' */
+        outsize=insize;
+        memset(buffer, 0xbd, sizeof(buffer));
+        nsize=sizeof(name);
+        ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
+        ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
+        ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
+        ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
+        ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
+           wine_debugstr_an((char*)buffer, outsize), outsize, string);
+        ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
+
+        /* RegEnumValueA adds a trailing '\0' if there is room */
+        outsize=insize+1;
+        memset(buffer, 0xbd, sizeof(buffer));
+        nsize=sizeof(name);
+        ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
+        ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
+        ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
+        ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
+        ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
+           wine_debugstr_an((char*)buffer, outsize), outsize, string);
+        ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
+    }
+
+    RegDeleteKeyA(subkey, "");
+    RegCloseKey(subkey);
+}
+
 static void test_reg_delete_tree(void)
 {
     CHAR buffer[MAX_PATH];
@@ -1398,6 +1491,7 @@ START_TEST(registry)
     test_reg_close_key();
     test_reg_delete_key();
     test_reg_query_value();
+    test_string_termination();
 
     /* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */
     if (set_privileges(SE_BACKUP_NAME, TRUE) &&
index fbce2a6..bdcdb9e 100644 (file)
@@ -81,10 +81,14 @@ typedef BOOL (WINAPI *fnConvertSidToStringSidA)( PSID pSid, LPSTR *str );
 typedef BOOL (WINAPI *fnConvertStringSidToSidA)( LPCSTR str, PSID pSid );
 static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR, DWORD,
                                                                             PSECURITY_DESCRIPTOR*, PULONG );
+static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorW)(LPCWSTR, DWORD,
+                                                                            PSECURITY_DESCRIPTOR*, PULONG );
 static BOOL (WINAPI *pConvertSecurityDescriptorToStringSecurityDescriptorA)(PSECURITY_DESCRIPTOR, DWORD,
                                                                             SECURITY_INFORMATION, LPSTR *, PULONG );
 typedef BOOL (WINAPI *fnGetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
                                           PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+typedef BOOL (WINAPI *fnSetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
+                                          PSECURITY_DESCRIPTOR);
 static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION,
                                               PSID*, PSID*, PACL*, PACL*,
                                               PSECURITY_DESCRIPTOR*);
@@ -117,6 +121,7 @@ fnMakeSelfRelativeSD pMakeSelfRelativeSD;
 fnConvertSidToStringSidA pConvertSidToStringSidA;
 fnConvertStringSidToSidA pConvertStringSidToSidA;
 fnGetFileSecurityA pGetFileSecurityA;
+fnSetFileSecurityA pSetFileSecurityA;
 fnRtlAdjustPrivilege pRtlAdjustPrivilege;
 fnCreateWellKnownSid pCreateWellKnownSid;
 fnDuplicateTokenEx pDuplicateTokenEx;
@@ -144,8 +149,12 @@ static void init(void)
     pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx");
     pConvertStringSecurityDescriptorToSecurityDescriptorA =
         (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" );
+    pConvertStringSecurityDescriptorToSecurityDescriptorW =
+        (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorW" );
     pConvertSecurityDescriptorToStringSecurityDescriptorA =
         (void *)GetProcAddress(hmod, "ConvertSecurityDescriptorToStringSecurityDescriptorA" );
+    pGetFileSecurityA = (fnGetFileSecurityA)GetProcAddress(hmod, "GetFileSecurityA" );
+    pSetFileSecurityA = (fnSetFileSecurityA)GetProcAddress(hmod, "SetFileSecurityA" );
     pCreateWellKnownSid = (fnCreateWellKnownSid)GetProcAddress( hmod, "CreateWellKnownSid" );
     pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA");
     pMakeSelfRelativeSD = (void *)GetProcAddress(hmod, "MakeSelfRelativeSD");
@@ -495,7 +504,7 @@ static void test_trustee(void)
 #define SE_DEBUG_PRIVILEGE               20L
 #define SE_AUDIT_PRIVILEGE               21L
 #define SE_SYSTEM_ENVIRONMENT_PRIVILEGE  22L
-#define SE_CHANGE_NOTIFY_PRIVILLEGE      23L
+#define SE_CHANGE_NOTIFY_PRIVILEGE       23L
 #define SE_REMOTE_SHUTDOWN_PRIVILEGE     24L
 #define SE_UNDOCK_PRIVILEGE              25L
 #define SE_SYNC_AGENT_PRIVILEGE          26L
@@ -570,7 +579,7 @@ static void test_lookupPrivilegeName(void)
      "SeCreateTokenPrivilege (got %d, expected %d)\n", cchName,
      (int)strlen("SeCreateTokenPrivilege"));
     /* check known values */
-    for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i < SE_MAX_WELL_KNOWN_PRIVILEGE; i++)
+    for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i <= SE_MAX_WELL_KNOWN_PRIVILEGE; i++)
     {
         luid.LowPart = i;
         cchName = sizeof(buf);
@@ -625,7 +634,7 @@ static void test_lookupPrivilegeValue(void)
      { "SeDebugPrivilege", SE_DEBUG_PRIVILEGE },
      { "SeAuditPrivilege", SE_AUDIT_PRIVILEGE },
      { "SeSystemEnvironmentPrivilege", SE_SYSTEM_ENVIRONMENT_PRIVILEGE },
-     { "SeChangeNotifyPrivilege", SE_CHANGE_NOTIFY_PRIVILLEGE },
+     { "SeChangeNotifyPrivilege", SE_CHANGE_NOTIFY_PRIVILEGE },
      { "SeRemoteShutdownPrivilege", SE_REMOTE_SHUTDOWN_PRIVILEGE },
      { "SeUndockPrivilege", SE_UNDOCK_PRIVILEGE },
      { "SeSyncAgentPrivilege", SE_SYNC_AGENT_PRIVILEGE },
@@ -690,31 +699,128 @@ static void test_luid(void)
 
 static void test_FileSecurity(void)
 {
-    char directory[MAX_PATH];
-    DWORD retval, outSize;
-    BOOL result;
-    BYTE buffer[0x40];
-
-    pGetFileSecurityA = (fnGetFileSecurityA)
-                    GetProcAddress( hmod, "GetFileSecurityA" );
-    if( !pGetFileSecurityA )
+    char wintmpdir [MAX_PATH];
+    char path [MAX_PATH];
+    char file [MAX_PATH];
+    BOOL rc;
+    HANDLE fh;
+    DWORD sdSize;
+    DWORD retSize;
+    BYTE *sd;
+    SECURITY_INFORMATION const request = OWNER_SECURITY_INFORMATION
+                                       | GROUP_SECURITY_INFORMATION
+                                       | DACL_SECURITY_INFORMATION;
+
+    if (!pGetFileSecurityA) {
+        win_skip ("GetFileSecurity is not available\n");
+        return;
+    }
+
+    if (!pSetFileSecurityA) {
+        win_skip ("SetFileSecurity is not available\n");
         return;
+    }
 
-    retval = GetTempPathA(sizeof(directory), directory);
-    if (!retval) {
-        trace("GetTempPathA failed\n");
+    if (!GetTempPathA (sizeof (wintmpdir), wintmpdir)) {
+        win_skip ("GetTempPathA failed\n");
         return;
     }
 
-    strcpy(directory, "\\Should not exist");
+    /* Create a temporary directory and in it a temporary file */
+    strcat (strcpy (path, wintmpdir), "rary");
+    SetLastError(0xdeadbeef);
+    rc = CreateDirectoryA (path, NULL);
+    ok (rc || GetLastError() == ERROR_ALREADY_EXISTS, "CreateDirectoryA "
+        "failed for '%s' with %d\n", path, GetLastError());
+
+    strcat (strcpy (file, path), "\\ess");
+    SetLastError(0xdeadbeef);
+    fh = CreateFileA (file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    ok (fh != INVALID_HANDLE_VALUE, "CreateFileA "
+        "failed for '%s' with %d\n", file, GetLastError());
+    CloseHandle (fh);
+
+    /* For the temporary file ... */
+
+    /* Get size needed */
+    retSize = 0;
+    SetLastError(0xdeadbeef);
+    rc = pGetFileSecurityA (file, request, NULL, 0, &retSize);
+    if (!rc && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) {
+        win_skip("GetFileSecurityA is not implemented\n");
+        goto cleanup;
+    }
+    ok (!rc, "GetFileSecurityA "
+        "was expected to fail for '%s'\n", file);
+    ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA "
+        "returned %d; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError());
+    ok (retSize > sizeof (SECURITY_DESCRIPTOR), "GetFileSecurityA returned size %d\n", retSize);
+
+    sdSize = retSize;
+    sd = HeapAlloc (GetProcessHeap (), 0, sdSize);
+
+    /* Get security descriptor for real */
+    retSize = -1;
+    SetLastError(0xdeadbeef);
+    rc = pGetFileSecurityA (file, request, sd, sdSize, &retSize);
+    ok (rc, "GetFileSecurityA "
+        "was not expected to fail '%s': %d\n", file, GetLastError());
+    ok (retSize == sdSize ||
+        broken(retSize == 0), /* NT4 */
+        "GetFileSecurityA returned size %d; expected %d\n", retSize, sdSize);
+
+    /* Use it to set security descriptor */
+    SetLastError(0xdeadbeef);
+    rc = pSetFileSecurityA (file, request, sd);
+    ok (rc, "SetFileSecurityA "
+        "was not expected to fail '%s': %d\n", file, GetLastError());
+
+    HeapFree (GetProcessHeap (), 0, sd);
+
+    /* Repeat for the temporary directory ... */
+
+    /* Get size needed */
+    retSize = 0;
+    SetLastError(0xdeadbeef);
+    rc = pGetFileSecurityA (path, request, NULL, 0, &retSize);
+    ok (!rc, "GetFileSecurityA "
+        "was expected to fail for '%s'\n", path);
+    ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA "
+        "returned %d; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError());
+    ok (retSize > sizeof (SECURITY_DESCRIPTOR), "GetFileSecurityA returned size %d\n", retSize);
+
+    sdSize = retSize;
+    sd = HeapAlloc (GetProcessHeap (), 0, sdSize);
+
+    /* Get security descriptor for real */
+    retSize = -1;
+    SetLastError(0xdeadbeef);
+    rc = pGetFileSecurityA (path, request, sd, sdSize, &retSize);
+    ok (rc, "GetFileSecurityA "
+        "was not expected to fail '%s': %d\n", path, GetLastError());
+    ok (retSize == sdSize ||
+        broken(retSize == 0), /* NT4 */
+        "GetFileSecurityA returned size %d; expected %d\n", retSize, sdSize);
+
+    /* Use it to set security descriptor */
+    SetLastError(0xdeadbeef);
+    rc = pSetFileSecurityA (path, request, sd);
+    ok (rc, "SetFileSecurityA "
+        "was not expected to fail '%s': %d\n", path, GetLastError());
+    HeapFree (GetProcessHeap (), 0, sd);
 
-    SetLastError(NO_ERROR);
-    result = pGetFileSecurityA( directory,OWNER_SECURITY_INFORMATION,buffer,0x40,&outSize);
-    ok(!result, "GetFileSecurityA should fail for not existing directories/files\n"); 
-    ok( (GetLastError() == ERROR_FILE_NOT_FOUND ) ||
-        (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) , 
-        "last error ERROR_FILE_NOT_FOUND / ERROR_CALL_NOT_IMPLEMENTED (98) "
-        "expected, got %d\n", GetLastError());
+    /* Old test */
+    strcpy (wintmpdir, "\\Should not exist");
+    SetLastError(0xdeadbeef);
+    rc = pGetFileSecurityA (wintmpdir, OWNER_SECURITY_INFORMATION, NULL, 0, &sdSize);
+    ok (!rc, "GetFileSecurityA should fail for not existing directories/files\n");
+    ok (GetLastError() == ERROR_FILE_NOT_FOUND,
+        "last error ERROR_FILE_NOT_FOUND expected, got %d\n", GetLastError());
+
+cleanup:
+    /* Remove temporary file and directory */
+    DeleteFileA(file);
+    RemoveDirectoryA(path);
 }
 
 static void test_AccessCheck(void)
@@ -1310,6 +1416,14 @@ static void test_LookupAccountSid(void)
     ret = LookupAccountSidW(NULL, pUsersSid, accountW, &real_acc_sizeW, domainW, &real_dom_sizeW, &use);
     ok(ret, "LookupAccountSidW() Expected TRUE, got FALSE\n");
 
+    /* try an invalid system name */
+    real_acc_sizeA = MAX_PATH;
+    real_dom_sizeA = MAX_PATH;
+    ret = LookupAccountSidA("deepthought", pUsersSid, accountA, &real_acc_sizeA, domainA, &real_dom_sizeA, &use);
+    ok(!ret, "LookupAccountSidA() Expected FALSE got TRUE\n");
+    ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* Vista */,
+       "LookupAccountSidA() Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %u\n", GetLastError());
+
     /* native windows crashes if domainW or accountW is NULL */
 
     /* try a small account buffer */
@@ -1550,10 +1664,10 @@ static void test_LookupAccountName(void)
     {
         ok(!lstrcmp(account, user_name), "Expected %s, got %s\n", user_name, account);
         ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain);
-        ok(domain_size == domain_save - 1, "Expected %d, got %d\n", domain_save - 1, domain_size);
-        ok(lstrlen(domain) == domain_size, "Expected %d\n", lstrlen(domain));
-        ok(sid_use == SidTypeUser, "Expected SidTypeUser, got %d\n", sid_use);
     }
+    ok(domain_size == domain_save - 1, "Expected %d, got %d\n", domain_save - 1, domain_size);
+    ok(lstrlen(domain) == domain_size, "Expected %d, got %d\n", lstrlen(domain), domain_size);
+    ok(sid_use == SidTypeUser, "Expected SidTypeUser (%d), got %d\n", SidTypeUser, sid_use);
     domain_size = domain_save;
     sid_size = sid_save;
 
@@ -1568,12 +1682,10 @@ static void test_LookupAccountName(void)
         ok(ret, "Failed to lookup account name\n");
         ok(sid_size != 0, "sid_size was zero\n");
         ok(!lstrcmp(account, "Everyone"), "Expected Everyone, got %s\n", account);
-        todo_wine
         ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain);
         ok(domain_size == 0, "Expected 0, got %d\n", domain_size);
-        todo_wine
         ok(lstrlen(domain) == domain_size, "Expected %d, got %d\n", lstrlen(domain), domain_size);
-        ok(sid_use == SidTypeWellKnownGroup, "Expected SidTypeUser, got %d\n", sid_use);
+        ok(sid_use == SidTypeWellKnownGroup, "Expected SidTypeWellKnownGroup (%d), got %d\n", SidTypeWellKnownGroup, sid_use);
         domain_size = domain_save;
     }
 
@@ -1616,28 +1728,33 @@ static void test_LookupAccountName(void)
     sid_use = 0xcafebabe;
     SetLastError(0xdeadbeef);
     ret = LookupAccountNameA(NULL, NULL, NULL, &sid_size, NULL, &domain_size, &sid_use);
-    ok(!ret, "Expected 0, got %d\n", ret);
-    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
-       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
-    ok(sid_size != 0, "Expected non-zero sid size\n");
-    ok(domain_size != 0, "Expected non-zero domain size\n");
-    ok(sid_use == 0xcafebabe, "Expected 0xcafebabe, got %d\n", sid_use);
-
-    psid = HeapAlloc(GetProcessHeap(), 0, sid_size);
-    domain = HeapAlloc(GetProcessHeap(), 0, domain_size);
-
-    /* try NULL account name */
-    ret = LookupAccountNameA(NULL, NULL, psid, &sid_size, domain, &domain_size, &sid_use);
-    get_sid_info(psid, &account, &sid_dom);
-    ok(ret, "Failed to lookup account name\n");
-    todo_wine
+    if (!ret && GetLastError() != ERROR_NONE_MAPPED)
     {
+        ok(!ret, "Expected 0, got %d\n", ret);
+        ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+           "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+        ok(sid_size != 0, "Expected non-zero sid size\n");
+        ok(domain_size != 0, "Expected non-zero domain size\n");
+        ok(sid_use == 0xcafebabe, "Expected 0xcafebabe, got %d\n", sid_use);
+
+        psid = HeapAlloc(GetProcessHeap(), 0, sid_size);
+        domain = HeapAlloc(GetProcessHeap(), 0, domain_size);
+
+        /* try NULL account name */
+        ret = LookupAccountNameA(NULL, NULL, psid, &sid_size, domain, &domain_size, &sid_use);
+        get_sid_info(psid, &account, &sid_dom);
+        ok(ret, "Failed to lookup account name\n");
         /* Using a fixed string will not work on different locales */
         ok(!lstrcmp(account, domain),
            "Got %s for account and %s for domain, these should be the same\n",
            account, domain);
-        ok(sid_use == SidTypeDomain, "Expected SidTypeDomain, got %d\n", SidTypeDomain);
+        ok(sid_use == SidTypeDomain, "Expected SidTypeDomain (%d), got %d\n", SidTypeDomain, sid_use);
+
+        HeapFree(GetProcessHeap(), 0, psid);
+        HeapFree(GetProcessHeap(), 0, domain);
     }
+    else
+        win_skip("NULL account name doesn't work on NT4\n");
 
     /* try an invalid account name */
     SetLastError(0xdeadbeef);
@@ -1645,17 +1762,22 @@ static void test_LookupAccountName(void)
     domain_size = 0;
     ret = LookupAccountNameA(NULL, "oogabooga", NULL, &sid_size, NULL, &domain_size, &sid_use);
     ok(!ret, "Expected 0, got %d\n", ret);
-    todo_wine
-    {
-        ok(GetLastError() == ERROR_NONE_MAPPED ||
-           broken(GetLastError() == ERROR_TRUSTED_RELATIONSHIP_FAILURE),
-           "Expected ERROR_NONE_MAPPED, got %d\n", GetLastError());
-        ok(sid_size == 0, "Expected 0, got %d\n", sid_size);
-        ok(domain_size == 0, "Expected 0, got %d\n", domain_size);
-    }
+    ok(GetLastError() == ERROR_NONE_MAPPED ||
+       broken(GetLastError() == ERROR_TRUSTED_RELATIONSHIP_FAILURE),
+       "Expected ERROR_NONE_MAPPED, got %d\n", GetLastError());
+    ok(sid_size == 0, "Expected 0, got %d\n", sid_size);
+    ok(domain_size == 0, "Expected 0, got %d\n", domain_size);
 
-    HeapFree(GetProcessHeap(), 0, psid);
-    HeapFree(GetProcessHeap(), 0, domain);
+    /* try an invalid system name */
+    SetLastError(0xdeadbeef);
+    sid_size = 0;
+    domain_size = 0;
+    ret = LookupAccountNameA("deepthought", NULL, NULL, &sid_size, NULL, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* Vista */,
+       "Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %d\n", GetLastError());
+    ok(sid_size == 0, "Expected 0, got %d\n", sid_size);
+    ok(domain_size == 0, "Expected 0, got %d\n", domain_size);
 }
 
 static void test_security_descriptor(void)
@@ -1962,7 +2084,7 @@ static void test_impersonation_level(void)
     ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
     error = GetLastError();
     ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenUser) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error);
-    User = (TOKEN_USER *)HeapAlloc(GetProcessHeap(), 0, Size);
+    User = HeapAlloc(GetProcessHeap(), 0, Size);
     ret = GetTokenInformation(Token, TokenUser, User, Size, &Size);
     ok(ret, "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
     HeapFree(GetProcessHeap(), 0, User);
@@ -1971,11 +2093,11 @@ static void test_impersonation_level(void)
     ret = GetTokenInformation(Token, TokenPrivileges, NULL, 0, &Size);
     error = GetLastError();
     ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error);
-    Privileges = (TOKEN_PRIVILEGES *)HeapAlloc(GetProcessHeap(), 0, Size);
+    Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
     ret = GetTokenInformation(Token, TokenPrivileges, Privileges, Size, &Size);
     ok(ret, "GetTokenInformation(TokenPrivileges) failed with error %d\n", GetLastError());
 
-    PrivilegeSet = (PRIVILEGE_SET *)HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PRIVILEGE_SET, Privilege[Privileges->PrivilegeCount]));
+    PrivilegeSet = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PRIVILEGE_SET, Privilege[Privileges->PrivilegeCount]));
     PrivilegeSet->PrivilegeCount = Privileges->PrivilegeCount;
     memcpy(PrivilegeSet->Privilege, Privileges->Privileges, PrivilegeSet->PrivilegeCount * sizeof(PrivilegeSet->Privilege[0]));
     PrivilegeSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
@@ -2031,7 +2153,7 @@ static void test_SetEntriesInAcl(void)
 
     if (!pSetEntriesInAclW)
     {
-        skip("SetEntriesInAclW is not available\n");
+        win_skip("SetEntriesInAclW is not available\n");
         return;
     }
 
@@ -2039,17 +2161,20 @@ static void test_SetEntriesInAcl(void)
     res = pSetEntriesInAclW(0, NULL, NULL, &NewAcl);
     if(res == ERROR_CALL_NOT_IMPLEMENTED)
     {
-        skip("SetEntriesInAclW is not implemented\n");
+        win_skip("SetEntriesInAclW is not implemented\n");
         return;
     }
     ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
-    ok(NewAcl == NULL, "NewAcl=%p, expected NULL\n", NewAcl);
+    ok(NewAcl == NULL ||
+        broken(NewAcl != NULL), /* NT4 */
+        "NewAcl=%p, expected NULL\n", NewAcl);
+    LocalFree(NewAcl);
 
     OldAcl = HeapAlloc(GetProcessHeap(), 0, 256);
     res = InitializeAcl(OldAcl, 256, ACL_REVISION);
     if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     {
-        skip("ACLs not implemented - skipping tests\n");
+        win_skip("ACLs not implemented - skipping tests\n");
         HeapFree(GetProcessHeap(), 0, OldAcl);
         return;
     }
@@ -2093,16 +2218,22 @@ static void test_SetEntriesInAcl(void)
 
         ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_BAD_FORM;
         res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
-        ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res);
-        ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl);
-        LocalFree(NewAcl);
+        ok(res == ERROR_INVALID_PARAMETER ||
+            broken(res == ERROR_NOT_SUPPORTED), /* NT4 */
+            "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl == NULL ||
+            broken(NewAcl != NULL), /* NT4 */
+            "returned acl wasn't NULL: %p\n", NewAcl);
 
         ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_USER;
         ExplicitAccess.Trustee.MultipleTrusteeOperation = TRUSTEE_IS_IMPERSONATE;
         res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
-        ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res);
-        ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl);
-        LocalFree(NewAcl);
+        ok(res == ERROR_INVALID_PARAMETER ||
+            broken(res == ERROR_NOT_SUPPORTED), /* NT4 */
+            "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl == NULL ||
+            broken(NewAcl != NULL), /* NT4 */
+            "returned acl wasn't NULL: %p\n", NewAcl);
 
         ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
         ExplicitAccess.grfAccessMode = SET_ACCESS;
@@ -2175,6 +2306,7 @@ static void test_ConvertStringSecurityDescriptor(void)
 {
     BOOL ret;
     PSECURITY_DESCRIPTOR pSD;
+    static const WCHAR Blank[] = { 0 };
 
     if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
     {
@@ -2255,11 +2387,51 @@ static void test_ConvertStringSecurityDescriptor(void)
     SetLastError(0xdeadbeef);
     ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
         "D:(A;;ROB;;;WD)", SDDL_REVISION_1, &pSD, NULL);
-    todo_wine
     ok(!ret && GetLastError() == ERROR_INVALID_ACL,
         "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_ACL instead of %d\n",
         GetLastError());
 
+    /* test behaviour with NULL parameters */
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        NULL, 0xdeadbeef, &pSD, NULL);
+    todo_wine
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorW(
+        NULL, 0xdeadbeef, &pSD, NULL);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;ROB;;;WD)", 0xdeadbeef, NULL, NULL);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;ROB;;;WD)", SDDL_REVISION_1, NULL, NULL);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        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(
@@ -2386,11 +2558,100 @@ static void test_ConvertSecurityDescriptorToString()
     }
 }
 
+static void test_SetSecurityDescriptorControl (PSECURITY_DESCRIPTOR sec)
+{
+    SECURITY_DESCRIPTOR_CONTROL ref;
+    SECURITY_DESCRIPTOR_CONTROL test;
+
+    SECURITY_DESCRIPTOR_CONTROL const mutable
+        = SE_DACL_AUTO_INHERIT_REQ | SE_SACL_AUTO_INHERIT_REQ
+        | SE_DACL_AUTO_INHERITED   | SE_SACL_AUTO_INHERITED
+        | SE_DACL_PROTECTED        | SE_SACL_PROTECTED
+        | 0x00000040               | 0x00000080        /* not defined in winnt.h */
+        ;
+    SECURITY_DESCRIPTOR_CONTROL const immutable
+        = SE_OWNER_DEFAULTED       | SE_GROUP_DEFAULTED
+        | SE_DACL_PRESENT          | SE_DACL_DEFAULTED
+        | SE_SACL_PRESENT          | SE_SACL_DEFAULTED
+        | SE_RM_CONTROL_VALID      | SE_SELF_RELATIVE
+        ;
+
+    int     bit;
+    DWORD   dwRevision;
+    LPCSTR  fmt = "Expected error %s, got %u\n";
+
+    GetSecurityDescriptorControl (sec, &ref, &dwRevision);
+
+    /* The mutable bits are mutable regardless of the truth of
+       SE_DACL_PRESENT and/or SE_SACL_PRESENT */
+
+    /* Check call barfs if any bit-of-interest is immutable */
+    for (bit = 0; bit < 16; ++bit)
+    {
+        SECURITY_DESCRIPTOR_CONTROL const bitOfInterest = 1 << bit;
+        SECURITY_DESCRIPTOR_CONTROL setOrClear = ref & bitOfInterest;
+
+        SECURITY_DESCRIPTOR_CONTROL ctrl;
+
+        DWORD   dwExpect  = (bitOfInterest & immutable)
+                          ?  ERROR_INVALID_PARAMETER  :  0xbebecaca;
+        LPCSTR  strExpect = (bitOfInterest & immutable)
+                          ? "ERROR_INVALID_PARAMETER" : "0xbebecaca";
+
+        ctrl = (bitOfInterest & mutable) ? ref + bitOfInterest : ref;
+        setOrClear ^= bitOfInterest;
+        SetLastError (0xbebecaca);
+        pSetSecurityDescriptorControl (sec, bitOfInterest, setOrClear);
+        ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ());
+        GetSecurityDescriptorControl(sec, &test, &dwRevision);
+        expect_eq(test, ctrl, int, "%x");
+
+        ctrl = ref;
+        setOrClear ^= bitOfInterest;
+        SetLastError (0xbebecaca);
+        pSetSecurityDescriptorControl (sec, bitOfInterest, setOrClear);
+        ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ());
+        GetSecurityDescriptorControl (sec, &test, &dwRevision);
+        expect_eq(test, ref, int, "%x");
+    }
+
+    /* Check call barfs if any bit-to-set is immutable
+       even when not a bit-of-interest */
+    for (bit = 0; bit < 16; ++bit)
+    {
+        SECURITY_DESCRIPTOR_CONTROL const bitsOfInterest = mutable;
+        SECURITY_DESCRIPTOR_CONTROL setOrClear = ref & bitsOfInterest;
+
+        SECURITY_DESCRIPTOR_CONTROL ctrl;
+
+        DWORD   dwExpect  = ((1 << bit) & immutable)
+                          ?  ERROR_INVALID_PARAMETER  :  0xbebecaca;
+        LPCSTR  strExpect = ((1 << bit) & immutable)
+                          ? "ERROR_INVALID_PARAMETER" : "0xbebecaca";
+
+        ctrl = ((1 << bit) & immutable) ? test : ref | mutable;
+        setOrClear ^= bitsOfInterest;
+        SetLastError (0xbebecaca);
+        pSetSecurityDescriptorControl (sec, bitsOfInterest, setOrClear | (1 << bit));
+        ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ());
+        GetSecurityDescriptorControl(sec, &test, &dwRevision);
+        expect_eq(test, ctrl, int, "%x");
+
+        ctrl = ((1 << bit) & immutable) ? test : ref | (1 << bit);
+        setOrClear ^= bitsOfInterest;
+        SetLastError (0xbebecaca);
+        pSetSecurityDescriptorControl (sec, bitsOfInterest, setOrClear | (1 << bit));
+        ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ());
+        GetSecurityDescriptorControl(sec, &test, &dwRevision);
+        expect_eq(test, ctrl, int, "%x");
+    }
+}
+
 static void test_PrivateObjectSecurity(void)
 {
     SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
     SECURITY_DESCRIPTOR_CONTROL ctrl;
-    PSECURITY_DESCRIPTOR sec = NULL;
+    PSECURITY_DESCRIPTOR sec;
     DWORD dwDescSize;
     DWORD dwRevision;
     DWORD retSize;
@@ -2404,16 +2665,36 @@ static void test_PrivateObjectSecurity(void)
         return;
     }
 
+    ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "O:SY"
+        "G:S-1-5-21-93476-23408-4576"
+        "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)"
+          "(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"
+        "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)",
+        SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n");
+
+    test_SetSecurityDescriptorControl(sec);
+
+    LocalFree(sec);
+
+    ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "O:SY"
+        "G:S-1-5-21-93476-23408-4576",
+        SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n");
+
+    test_SetSecurityDescriptorControl(sec);
+
+    LocalFree(sec);
+
     ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
         "O:SY"
         "G:S-1-5-21-93476-23408-4576"
         "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"
         "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n");
     buf = HeapAlloc(GetProcessHeap(), 0, dwDescSize);
-    DbgPrint("Received %p\n", sec);
     pSetSecurityDescriptorControl(sec, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
     GetSecurityDescriptorControl(sec, &ctrl, &dwRevision);
-    todo_wine expect_eq(ctrl, 0x9014, int, "%x");
+    expect_eq(ctrl, 0x9014, int, "%x");
 
     ok(GetPrivateObjectSecurity(sec, GROUP_SECURITY_INFORMATION, buf, dwDescSize, &retSize),
         "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError());
@@ -2488,11 +2769,17 @@ static void test_acls(void)
     ret = IsValidAcl(pAcl);
     ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
 
+    SetLastError(0xdeadbeef);
     ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION4);
-    ok(ret, "InitializeAcl(ACL_REVISION4) failed with error %d\n", GetLastError());
+    if (GetLastError() != ERROR_INVALID_PARAMETER)
+    {
+        ok(ret, "InitializeAcl(ACL_REVISION4) failed with error %d\n", GetLastError());
 
-    ret = IsValidAcl(pAcl);
-    ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
+        ret = IsValidAcl(pAcl);
+        ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
+    }
+    else
+        win_skip("ACL_REVISION4 is not implemented on NT4\n");
 
     SetLastError(0xdeadbeef);
     ret = InitializeAcl(pAcl, sizeof(buffer), -1);
@@ -2540,6 +2827,13 @@ static void test_GetSecurityInfo(void)
 
     LocalFree(sd);
 
+    if (!pCreateWellKnownSid)
+    {
+        win_skip("NULL parameter test would crash on NT4\n");
+        CloseHandle(obj);
+        return;
+    }
+
     /* If we don't ask for the security descriptor, Windows will still give us
        the other stuff, leaving us no way to free it.  */
     ret = pGetSecurityInfo(obj, SE_FILE_OBJECT,
index da62b0b..d6d321c 100644 (file)
@@ -564,7 +564,7 @@ static void test_get_displayname(void)
     displaysize = tempsizeW / 2;
     ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
     ok(!ret, "Expected failure\n");
-    ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
+    ok(displaysize == tempsizeW, "Expected the needed buffersize\n");
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
        "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
 
@@ -573,7 +573,7 @@ static void test_get_displayname(void)
     displaysize = tempsizeW;
     ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
     ok(!ret, "Expected failure\n");
-    ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
+    ok(displaysize == tempsizeW, "Expected the needed buffersize\n");
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
        "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
 
@@ -649,7 +649,7 @@ static void test_get_displayname(void)
 
     /* Delete the service */
     ret = DeleteService(svc_handle);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
 
     CloseServiceHandle(svc_handle);
     CloseServiceHandle(scm_handle);
@@ -882,7 +882,7 @@ static void test_query_svc(void)
     /* Only info level is correct. It looks like the buffer/size is checked second */
     SetLastError(0xdeadbeef);
     ret = pQueryServiceStatusEx(NULL, 0, NULL, 0, &needed);
-    /* NT4 checks the handle first */
+    /* NT4 and Wine check the handle first */
     if (GetLastError() != ERROR_INVALID_HANDLE)
     {
         ok(!ret, "Expected failure\n");
@@ -893,7 +893,7 @@ static void test_query_svc(void)
     }
 
     /* Pass a correct buffer and buffersize but a NULL handle */
-    statusproc = HeapAlloc(GetProcessHeap(), 0, needed);
+    statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS));
     bufsize = needed;
     SetLastError(0xdeadbeef);
     ret = pQueryServiceStatusEx(NULL, 0, (BYTE*)statusproc, bufsize, &needed);
@@ -1985,7 +1985,7 @@ static void test_refcount(void)
 
     /* Check if we can close the handle to the Service Control Manager */
     ret = CloseServiceHandle(scm_handle);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
 
     /* Get a new handle to the Service Control Manager */
     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
@@ -1997,7 +1997,7 @@ static void test_refcount(void)
 
     /* Delete the service */
     ret = DeleteService(svc_handle4);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
 
     /* We cannot create the same service again as it's still marked as 'being deleted'.
      * The reason is that we still have 4 open handles to this service even though we
@@ -2023,13 +2023,13 @@ static void test_refcount(void)
 
     /* Close all the handles to the service and try again */
     ret = CloseServiceHandle(svc_handle4);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
     ret = CloseServiceHandle(svc_handle3);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
     ret = CloseServiceHandle(svc_handle2);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
     ret = CloseServiceHandle(svc_handle1);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
 
     /* Wait a while. Doing a CreateService too soon will result again
      * in an ERROR_SERVICE_MARKED_FOR_DELETE error.
@@ -2044,7 +2044,7 @@ static void test_refcount(void)
 
     /* Delete the service */
     ret = DeleteService(svc_handle5);
-    ok(ret, "Expected success\n");
+    ok(ret, "Expected success (err=%d)\n", GetLastError());
 
     /* Wait a while. Just in case one of the following tests does a CreateService again */
     Sleep(1000);