/* * PROJECT: ReactOS api tests * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Tests for RegCreateKeyExW. * COPYRIGHT: Copyright 2023 Doug Lyons */ /* * Idea based loosely on code from the following: * https://learn.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c-- */ #include #include #define WIN32_NO_STATUS #define _INC_WINDOWS #define COM_NO_WINDOWS_H #include #include START_TEST(RegCreateKeyEx) { HKEY hkey_main; DWORD dwRes, dwDisposition; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; PSID pEveryoneSID = NULL, pAdminSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = {SECURITY_WORLD_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY}; EXPLICIT_ACCESSW ea[2]; SECURITY_ATTRIBUTES sa = { 0 }; LONG lRes; BOOL bRes; LONG ErrorCode = 0; HKEY hkSub = NULL; // If any of the test keys already exist, delete them to ensure proper testing if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS) { RegCloseKey(hkey_main); ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey"); ok_dec(ErrorCode, ERROR_SUCCESS); if (ErrorCode != ERROR_SUCCESS) { skip("'HKCU\\mykey' cannot be deleted. Terminating test\n"); goto Cleanup; } } if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey1", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS) { RegCloseKey(hkey_main); ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey1"); ok_dec(ErrorCode, ERROR_SUCCESS); if (ErrorCode != ERROR_SUCCESS) { skip("'HKCU\\mykey1' cannot be deleted. Terminating test\n"); goto Cleanup; } } if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey2", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS) { RegCloseKey(hkey_main); ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey2"); ok_dec(ErrorCode, ERROR_SUCCESS); if (ErrorCode != ERROR_SUCCESS) { skip("'HKCU\\mykey2' cannot be deleted. Terminating test\n"); goto Cleanup; } } // Setup GetLastError to known value for tests SetLastError(0xdeadbeef); // Create a well-known SID for the Everyone group. bRes = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID); ok(bRes, "AllocateAndInitializeSid Error %ld\n", GetLastError()); if (!bRes) { skip("EveryoneSID not initialized. Terminating test\n"); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, sizeof(ea)); ea[0].grfAccessPermissions = KEY_READ; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance= NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = pEveryoneSID; // Create a SID for the BUILTIN\Administrators group. bRes = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID); ok(bRes, "AllocateAndInitializeSid Error %ld\n", GetLastError()); if (!bRes) { skip("AdminSID not initialized. Terminating test\n"); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to the key. ea[1].grfAccessPermissions = KEY_ALL_ACCESS; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance= NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = pAdminSID; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAclW(_countof(ea), ea, NULL, &pACL); ok(dwRes == ERROR_SUCCESS, "SetEntriesInAcl Error %ld\n", GetLastError()); if (dwRes != ERROR_SUCCESS) goto Cleanup; // Initialize a security descriptor. pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); ok(pSD != NULL, "LocalAlloc Error %ld\n", GetLastError()); if (pSD == NULL) goto Cleanup; bRes = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); ok(bRes, "InitializeSecurityDescriptor Error %ld\n", GetLastError()); if (!bRes) goto Cleanup; // Add the ACL to the security descriptor. bRes = SetSecurityDescriptorDacl(pSD, TRUE, // bDaclPresent flag pACL, FALSE); // not a default DACL ok(bRes, "SetSecurityDescriptorDacl Error %ld\n", GetLastError()); if (!bRes) goto Cleanup; // Initialize a security attributes structure. sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; // Use the security attributes to set the security descriptor // with an nlength that is 0. sa.nLength = 0; lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey", 0, L"", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes); ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n"); if (dwDisposition != REG_CREATED_NEW_KEY) goto Cleanup; // Test the -A function lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey", 0, "", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes); ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n"); if (dwDisposition != REG_OPENED_EXISTING_KEY) goto Cleanup; // Use the security attributes to set the security descriptor // with an nlength that is too short, but not 0. sa.nLength = sizeof(SECURITY_ATTRIBUTES) / 2; lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey1", 0, L"", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes); ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n"); if (dwDisposition != REG_CREATED_NEW_KEY) goto Cleanup; // Test the -A function lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey1", 0, "", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes); ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n"); if (dwDisposition != REG_OPENED_EXISTING_KEY) goto Cleanup; // Use the security attributes to set the security descriptor // with an nlength that is too long. sa.nLength = sizeof(SECURITY_ATTRIBUTES) + 10; lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey2", 0, L"", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes); ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n"); if (dwDisposition != REG_CREATED_NEW_KEY) goto Cleanup; // Test the -A function lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey2", 0, "", 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes); ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n"); if (dwDisposition != REG_OPENED_EXISTING_KEY) goto Cleanup; Cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAdminSID) FreeSid(pAdminSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); if (hkSub) RegCloseKey(hkSub); // Delete the subkeys created for testing ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey"); ok_dec(ErrorCode, ERROR_SUCCESS); ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey1"); ok_dec(ErrorCode, ERROR_SUCCESS); ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey2"); ok_dec(ErrorCode, ERROR_SUCCESS); }