Reactos
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tests for RegCreateKeyExW.
5 * COPYRIGHT: Copyright 2023 Doug Lyons <douglyons@douglyons.com>
6 */
7
8/*
9 * Idea based loosely on code from the following:
10 * https://learn.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c--
11 */
12
13#include <apitest.h>
14#include <stdio.h>
15
16#define WIN32_NO_STATUS
17#define _INC_WINDOWS
18#define COM_NO_WINDOWS_H
19#include <windef.h>
20#include <aclapi.h>
21
22
23START_TEST(RegCreateKeyEx)
24{
25 HKEY hkey_main;
26 DWORD dwRes, dwDisposition;
27 PACL pACL = NULL;
28 PSECURITY_DESCRIPTOR pSD = NULL;
29 PSID pEveryoneSID = NULL, pAdminSID = NULL;
30 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = {SECURITY_WORLD_SID_AUTHORITY};
31 SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY};
32 EXPLICIT_ACCESSW ea[2];
33 SECURITY_ATTRIBUTES sa = { 0 };
34 LONG lRes;
35 BOOL bRes;
36 LONG ErrorCode = 0;
37 HKEY hkSub = NULL;
38
39 // If any of the test keys already exist, delete them to ensure proper testing
40 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS)
41 {
42 RegCloseKey(hkey_main);
43 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey");
44 ok_dec(ErrorCode, ERROR_SUCCESS);
45 if (ErrorCode != ERROR_SUCCESS)
46 {
47 skip("'HKCU\\mykey' cannot be deleted. Terminating test\n");
48 goto Cleanup;
49 }
50 }
51
52 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey1", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS)
53 {
54 RegCloseKey(hkey_main);
55 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey1");
56 ok_dec(ErrorCode, ERROR_SUCCESS);
57 if (ErrorCode != ERROR_SUCCESS)
58 {
59 skip("'HKCU\\mykey1' cannot be deleted. Terminating test\n");
60 goto Cleanup;
61 }
62 }
63
64 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"mykey2", 0, KEY_ALL_ACCESS, &hkey_main) == ERROR_SUCCESS)
65 {
66 RegCloseKey(hkey_main);
67 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey2");
68 ok_dec(ErrorCode, ERROR_SUCCESS);
69 if (ErrorCode != ERROR_SUCCESS)
70 {
71 skip("'HKCU\\mykey2' cannot be deleted. Terminating test\n");
72 goto Cleanup;
73 }
74 }
75
76 // Setup GetLastError to known value for tests
77 SetLastError(0xdeadbeef);
78
79 // Create a well-known SID for the Everyone group.
80 bRes = AllocateAndInitializeSid(&SIDAuthWorld, 1,
81 SECURITY_WORLD_RID,
82 0, 0, 0, 0, 0, 0, 0,
83 &pEveryoneSID);
84 ok(bRes, "AllocateAndInitializeSid Error %ld\n", GetLastError());
85 if (!bRes)
86 {
87 skip("EveryoneSID not initialized. Terminating test\n");
88 goto Cleanup;
89 }
90
91 // Initialize an EXPLICIT_ACCESS structure for an ACE.
92 // The ACE will allow Everyone read access to the key.
93 ZeroMemory(&ea, sizeof(ea));
94 ea[0].grfAccessPermissions = KEY_READ;
95 ea[0].grfAccessMode = SET_ACCESS;
96 ea[0].grfInheritance= NO_INHERITANCE;
97 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
98 ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
99 ea[0].Trustee.ptstrName = pEveryoneSID;
100
101 // Create a SID for the BUILTIN\Administrators group.
102 bRes = AllocateAndInitializeSid(&SIDAuthNT, 2,
103 SECURITY_BUILTIN_DOMAIN_RID,
104 DOMAIN_ALIAS_RID_ADMINS,
105 0, 0, 0, 0, 0, 0,
106 &pAdminSID);
107 ok(bRes, "AllocateAndInitializeSid Error %ld\n", GetLastError());
108 if (!bRes)
109 {
110 skip("AdminSID not initialized. Terminating test\n");
111 goto Cleanup;
112 }
113
114 // Initialize an EXPLICIT_ACCESS structure for an ACE.
115 // The ACE will allow the Administrators group full access to the key.
116 ea[1].grfAccessPermissions = KEY_ALL_ACCESS;
117 ea[1].grfAccessMode = SET_ACCESS;
118 ea[1].grfInheritance= NO_INHERITANCE;
119 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
120 ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
121 ea[1].Trustee.ptstrName = pAdminSID;
122
123 // Create a new ACL that contains the new ACEs.
124 dwRes = SetEntriesInAclW(_countof(ea), ea, NULL, &pACL);
125 ok(dwRes == ERROR_SUCCESS, "SetEntriesInAcl Error %ld\n", GetLastError());
126 if (dwRes != ERROR_SUCCESS)
127 goto Cleanup;
128
129 // Initialize a security descriptor.
130 pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
131 ok(pSD != NULL, "LocalAlloc Error %ld\n", GetLastError());
132 if (pSD == NULL)
133 goto Cleanup;
134
135 bRes = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
136 ok(bRes, "InitializeSecurityDescriptor Error %ld\n", GetLastError());
137 if (!bRes)
138 goto Cleanup;
139
140 // Add the ACL to the security descriptor.
141 bRes = SetSecurityDescriptorDacl(pSD,
142 TRUE, // bDaclPresent flag
143 pACL,
144 FALSE); // not a default DACL
145 ok(bRes, "SetSecurityDescriptorDacl Error %ld\n", GetLastError());
146 if (!bRes)
147 goto Cleanup;
148
149 // Initialize a security attributes structure.
150 sa.lpSecurityDescriptor = pSD;
151 sa.bInheritHandle = FALSE;
152
153 // Use the security attributes to set the security descriptor
154 // with an nlength that is 0.
155 sa.nLength = 0;
156 lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey", 0, L"", 0,
157 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
158 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes);
159 ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n");
160 if (dwDisposition != REG_CREATED_NEW_KEY)
161 goto Cleanup;
162
163 // Test the -A function
164 lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey", 0, "", 0,
165 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
166 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes);
167 ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n");
168 if (dwDisposition != REG_OPENED_EXISTING_KEY)
169 goto Cleanup;
170
171 // Use the security attributes to set the security descriptor
172 // with an nlength that is too short, but not 0.
173 sa.nLength = sizeof(SECURITY_ATTRIBUTES) / 2;
174 lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey1", 0, L"", 0,
175 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
176 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes);
177 ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n");
178 if (dwDisposition != REG_CREATED_NEW_KEY)
179 goto Cleanup;
180
181 // Test the -A function
182 lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey1", 0, "", 0,
183 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
184 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes);
185 ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n");
186 if (dwDisposition != REG_OPENED_EXISTING_KEY)
187 goto Cleanup;
188
189 // Use the security attributes to set the security descriptor
190 // with an nlength that is too long.
191 sa.nLength = sizeof(SECURITY_ATTRIBUTES) + 10;
192 lRes = RegCreateKeyExW(HKEY_CURRENT_USER, L"mykey2", 0, L"", 0,
193 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
194 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExW returned '%ld', expected 0", lRes);
195 ok(dwDisposition == REG_CREATED_NEW_KEY, "Should have created NEW key\n");
196 if (dwDisposition != REG_CREATED_NEW_KEY)
197 goto Cleanup;
198
199 // Test the -A function
200 lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "mykey2", 0, "", 0,
201 KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition);
202 ok(lRes == ERROR_SUCCESS, "RegCreateKeyExA returned '%ld', expected 0", lRes);
203 ok(dwDisposition == REG_OPENED_EXISTING_KEY, "Should have opened EXISTING key\n");
204 if (dwDisposition != REG_OPENED_EXISTING_KEY)
205 goto Cleanup;
206
207Cleanup:
208
209 if (pEveryoneSID)
210 FreeSid(pEveryoneSID);
211 if (pAdminSID)
212 FreeSid(pAdminSID);
213 if (pACL)
214 LocalFree(pACL);
215 if (pSD)
216 LocalFree(pSD);
217 if (hkSub)
218 RegCloseKey(hkSub);
219
220 // Delete the subkeys created for testing
221 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey");
222 ok_dec(ErrorCode, ERROR_SUCCESS);
223
224 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey1");
225 ok_dec(ErrorCode, ERROR_SUCCESS);
226
227 ErrorCode = RegDeleteKeyW(HKEY_CURRENT_USER, L"mykey2");
228 ok_dec(ErrorCode, ERROR_SUCCESS);
229}
230