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 
23 START_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 
207 Cleanup:
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 
231