1 /*
2  * Copyright 2014 Akihiro Sagawa
3  * Copyright 2016-2018, 2021 Hugh McMaster
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "reg_test.h"
21 
22 static void test_command_syntax(void)
23 {
24     DWORD r;
25 
26     delete_tree(HKEY_CURRENT_USER, KEY_BASE, 0);
27 
28     run_reg_exe("reg delete", &r);
29     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
30 
31     run_reg_exe("reg delete /?", &r);
32     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
33 
34     run_reg_exe("reg delete /h", &r);
35     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
36 
37     run_reg_exe("reg delete -H", &r);
38     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
39 
40     /* Multiple /v* switches */
41     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v Wine /ve", &r);
42     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
43 
44     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v Wine /va", &r);
45     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
46 
47     run_reg_exe("reg delete HKCU\\" KEY_BASE " /ve /ve", &r);
48     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
49 
50     run_reg_exe("reg delete HKCU\\" KEY_BASE " /ve /va", &r);
51     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
52 
53     run_reg_exe("reg delete HKCU\\" KEY_BASE " /va /va", &r);
54     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
55 
56     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v Test /ve /va", &r);
57     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
58 
59     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v Wine /v Test /f", &r);
60     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
61 
62     /* No /v argument */
63     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v", &r);
64     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
65 
66     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f /v", &r);
67     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
68 
69     /* Test registry view */
70     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f /reg:32 /reg:32", &r);
71     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
72 
73     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f /reg:32 /reg:64", &r);
74     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
75 
76     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f /reg:64 /reg:64", &r);
77     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
78 }
79 
80 static void test_delete(void)
81 {
82     HKEY hkey;
83     DWORD r;
84     const DWORD deadbeef = 0xdeadbeef;
85 
86     delete_tree(HKEY_CURRENT_USER, KEY_BASE, 0);
87 
88     /* Create a test key */
89     add_key(HKEY_CURRENT_USER, KEY_BASE, 0, &hkey);
90     add_value(hkey, "foo", REG_DWORD, &deadbeef, sizeof(deadbeef));
91     add_value(hkey, "bar", REG_DWORD, &deadbeef, sizeof(deadbeef));
92     add_value(hkey, NULL, REG_DWORD, &deadbeef, sizeof(deadbeef));
93 
94     add_key(hkey, "subkey", 0, NULL);
95 
96     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v bar /f", &r);
97     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
98     verify_reg_nonexist(hkey, "bar");
99 
100     run_reg_exe("reg delete HKCU\\" KEY_BASE " /ve /f", &r);
101     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
102     verify_reg_nonexist(hkey, "");
103 
104     run_reg_exe("reg delete HKCU\\" KEY_BASE " /va /f", &r);
105     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
106     verify_reg_nonexist(hkey, "foo");
107     verify_key(hkey, "subkey", 0);
108 
109     /* Test forward and back slashes */
110     add_key(hkey, "https://winehq.org", 0, NULL);
111     add_value(hkey, "count/up", REG_SZ, "one/two/three", 14);
112     add_value(hkey, "\\foo\\bar", REG_SZ, "", 1);
113 
114     run_reg_exe("reg delete HKCU\\" KEY_BASE "\\https://winehq.org /f", &r);
115     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
116     verify_key_nonexist(hkey, "https://winehq.org", 0);
117 
118     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v count/up /f", &r);
119     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
120     verify_reg_nonexist(hkey, "count/up");
121 
122     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v \\foo\\bar /f", &r);
123     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
124     verify_reg_nonexist(hkey, "\\foo\\bar");
125 
126     add_value(hkey, "string\\01", REG_SZ, "Value", 6);
127     add_value(hkey, "string2", REG_SZ, "foo\\0bar", 9);
128     add_value(hkey, "\\0", REG_SZ, "Value", 6);
129 
130     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v string\\01 /f", &r);
131     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
132     verify_reg_nonexist(hkey, "string\\01");
133 
134     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v string2 /f", &r);
135     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
136     verify_reg_nonexist(hkey, "string2");
137 
138     run_reg_exe("reg delete HKCU\\" KEY_BASE " /v \\0 /f", &r);
139     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
140     verify_reg_nonexist(hkey, "\\0");
141 
142     close_key(hkey);
143 
144     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f", &r);
145     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
146     verify_key_nonexist(HKEY_CURRENT_USER, KEY_BASE, 0);
147 
148     run_reg_exe("reg delete HKCU\\" KEY_BASE " /f", &r);
149     ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
150 }
151 
152 #if 0
153 static void create_test_key(REGSAM sam)
154 {
155     HKEY hkey, subkey;
156     DWORD dword;
157 
158     add_key(HKEY_LOCAL_MACHINE, KEY_BASE, sam, &hkey);
159 
160     dword = 0x100;
161     add_value(hkey, "DWORD", REG_DWORD, &dword, sizeof(dword));
162     add_value(hkey, "String", REG_SZ, "Your text here...", 18);
163     add_value(hkey, NULL, REG_SZ, "Default value name", 19);
164     add_value(hkey, "Multiple Strings", REG_MULTI_SZ, "Line1\0Line2\0Line3\0", 19);
165 
166     add_key(hkey, "Subkey", sam, &subkey);
167     add_value(subkey, "Binary", REG_BINARY, "\x11\x22\x33\x44", 4);
168     add_value(subkey, "Undefined hex", 0x100, "%PATH%", 7);
169     close_key(subkey);
170 
171     close_key(hkey);
172 }
173 
174 static void test_registry_view_win32(void)
175 {
176     HKEY hkey;
177     DWORD r;
178     BOOL is_wow64, is_win32;
179 
180     IsWow64Process(GetCurrentProcess(), &is_wow64);
181     is_win32 = !is_wow64 && (sizeof(void *) == sizeof(int));
182 
183     if (!is_win32) return;
184 
185     delete_tree(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
186 
187     /* Test deletion from the 32-bit registry view (32-bit Windows) */
188     create_test_key(KEY_WOW64_32KEY);
189 
190     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY, &hkey);
191 
192     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:32", &r);
193     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
194     verify_reg_nonexist(hkey, "DWORD");
195 
196     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:32", &r);
197     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
198     verify_reg_nonexist(hkey, NULL);
199 
200     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:32", &r);
201     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
202     verify_reg_nonexist(hkey, "String");
203     verify_reg_nonexist(hkey, "Multiple Strings");
204     verify_key(hkey, "Subkey", KEY_WOW64_32KEY);
205 
206     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:32", &r);
207     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
208     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_32KEY);
209 
210     close_key(hkey);
211 
212     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:32", &r);
213     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
214     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
215 
216     /* Test deletion from the 64-bit registry view, which doesn't exist on 32-bit Windows */
217     create_test_key(KEY_WOW64_64KEY);
218 
219     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY, &hkey);
220 
221     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:64", &r);
222     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
223     verify_reg_nonexist(hkey, "DWORD");
224 
225     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:64", &r);
226     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
227     verify_reg_nonexist(hkey, NULL);
228 
229     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:64", &r);
230     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
231     verify_reg_nonexist(hkey, "String");
232     verify_reg_nonexist(hkey, "Multiple Strings");
233     verify_key(hkey, "Subkey", KEY_WOW64_64KEY);
234 
235     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:64", &r);
236     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
237     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_64KEY);
238 
239     close_key(hkey);
240 
241     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:64", &r);
242     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
243     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
244 }
245 
246 static void test_registry_view_win64(void)
247 {
248     HKEY hkey;
249     DWORD r;
250     BOOL is_wow64, is_win64;
251 
252     IsWow64Process(GetCurrentProcess(), &is_wow64);
253     is_win64 = !is_wow64 && (sizeof(void *) > sizeof(int));
254 
255     if (!is_win64) return;
256 
257     delete_tree(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
258     delete_tree(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
259 
260     /* Test deletion from the 32-bit registry view (64-bit Windows) */
261     create_test_key(KEY_WOW64_32KEY);
262 
263     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
264 
265     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY, &hkey);
266 
267     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:32", &r);
268     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
269     verify_reg_nonexist(hkey, "DWORD");
270 
271     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:32", &r);
272     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
273     verify_reg_nonexist(hkey, NULL);
274 
275     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:32", &r);
276     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
277     verify_reg_nonexist(hkey, "String");
278     verify_reg_nonexist(hkey, "Multiple Strings");
279     verify_key(hkey, "Subkey", KEY_WOW64_32KEY);
280 
281     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:32", &r);
282     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
283     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_32KEY);
284 
285     close_key(hkey);
286 
287     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:32", &r);
288     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
289     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
290 
291     /* Test deletion from the 64-bit registry view (64-bit Windows) */
292     create_test_key(KEY_WOW64_64KEY);
293 
294     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
295 
296     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY, &hkey);
297 
298     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:64", &r);
299     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
300     verify_reg_nonexist(hkey, "DWORD");
301 
302     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:64", &r);
303     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
304     verify_reg_nonexist(hkey, NULL);
305 
306     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:64", &r);
307     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
308     verify_reg_nonexist(hkey, "String");
309     verify_reg_nonexist(hkey, "Multiple Strings");
310     verify_key(hkey, "Subkey", KEY_WOW64_64KEY);
311 
312     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:64", &r);
313     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
314     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_64KEY);
315 
316     close_key(hkey);
317 
318     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:64", &r);
319     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
320     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
321 }
322 
323 static void test_registry_view_wow64(void)
324 {
325     HKEY hkey;
326     DWORD r;
327     BOOL is_wow64;
328 
329     IsWow64Process(GetCurrentProcess(), &is_wow64);
330 
331     if (!is_wow64) return;
332 
333     delete_tree(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
334     delete_tree(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
335 
336     /* Test deletion from the 32-bit registry view (WOW64) */
337     create_test_key(KEY_WOW64_32KEY);
338 
339     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
340 
341     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY, &hkey);
342 
343     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:32", &r);
344     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
345     verify_reg_nonexist(hkey, "DWORD");
346 
347     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:32", &r);
348     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
349     verify_reg_nonexist(hkey, NULL);
350 
351     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:32", &r);
352     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
353     verify_reg_nonexist(hkey, "String");
354     verify_reg_nonexist(hkey, "Multiple Strings");
355     verify_key(hkey, "Subkey", KEY_WOW64_32KEY);
356 
357     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:32", &r);
358     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
359     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_32KEY);
360 
361     close_key(hkey);
362 
363     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:32", &r);
364     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
365     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
366 
367     /* Test deletion from the 64-bit registry view (WOW64) */
368     create_test_key(KEY_WOW64_64KEY);
369 
370     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_32KEY);
371 
372     open_key(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY, &hkey);
373 
374     run_reg_exe("reg delete HKLM\\" KEY_BASE " /v DWORD /f /reg:64", &r);
375     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
376     verify_reg_nonexist(hkey, "DWORD");
377 
378     run_reg_exe("reg delete HKLM\\" KEY_BASE " /ve /f /reg:64", &r);
379     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
380     verify_reg_nonexist(hkey, NULL);
381 
382     run_reg_exe("reg delete HKLM\\" KEY_BASE " /va /f /reg:64", &r);
383     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
384     verify_reg_nonexist(hkey, "String");
385     verify_reg_nonexist(hkey, "Multiple Strings");
386     verify_key(hkey, "Subkey", KEY_WOW64_64KEY);
387 
388     run_reg_exe("reg delete HKLM\\" KEY_BASE "\\Subkey /f /reg:64", &r);
389     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
390     verify_key_nonexist(hkey, "Subkey", KEY_WOW64_64KEY);
391 
392     close_key(hkey);
393 
394     run_reg_exe("reg delete HKLM\\" KEY_BASE " /f /reg:64", &r);
395     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
396     verify_key_nonexist(HKEY_LOCAL_MACHINE, KEY_BASE, KEY_WOW64_64KEY);
397 }
398 #endif
399 
400 START_TEST(delete)
401 {
402     DWORD r;
403 
404     if (!run_reg_exe("reg.exe /?", &r)) {
405         win_skip("reg.exe not available, skipping 'delete' tests\n");
406         return;
407     }
408 
409     test_command_syntax();
410     test_delete();
411 
412     /* Check if reg.exe is running with elevated privileges */
413     if (!is_elevated_process())
414     {
415         win_skip("reg.exe is not running with elevated privileges; "
416                  "skipping registry view tests\n");
417         return;
418     }
419 
420 #if 0
421     test_registry_view_win32();
422     test_registry_view_win64();
423     test_registry_view_wow64();
424 #endif
425 
426 }
427