1 /*
2  * Unit tests for lsa functions
3  *
4  * Copyright (c) 2006 Robert Reif
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #ifndef __REACTOS__
30 #include "ntsecapi.h"
31 #endif
32 #include "sddl.h"
33 #include "winnls.h"
34 #include "objbase.h"
35 #include "initguid.h"
36 #include "wine/test.h"
37 #include "winternl.h"
38 #ifdef __REACTOS__
39 #include <ntsecapi.h>
40 #endif
41 #include "ntlsa.h"
42 
43 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
44 
45 static void test_lsa(void)
46 {
47     static WCHAR machineW[] = {'W','i','n','e','N','o','M','a','c','h','i','n','e',0};
48     LSA_UNICODE_STRING machine;
49     NTSTATUS status;
50     LSA_HANDLE handle;
51     LSA_OBJECT_ATTRIBUTES object_attributes;
52 
53     ZeroMemory(&object_attributes, sizeof(object_attributes));
54     object_attributes.Length = sizeof(object_attributes);
55 
56     machine.Buffer = machineW;
57     machine.Length = sizeof(machineW) - 2;
58     machine.MaximumLength = sizeof(machineW);
59 
60     status = LsaOpenPolicy( &machine, &object_attributes, POLICY_LOOKUP_NAMES, &handle);
61     ok(status == RPC_NT_SERVER_UNAVAILABLE,
62        "LsaOpenPolicy(POLICY_LOOKUP_NAMES) for invalid machine returned 0x%08x\n", status);
63 
64     status = LsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
65     ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
66        "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
67 
68     /* try a more restricted access mask if necessary */
69     if (status == STATUS_ACCESS_DENIED) {
70         trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES\n");
71         status = LsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES, &handle);
72         ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES) returned 0x%08x\n", status);
73     }
74 
75     if (status == STATUS_SUCCESS) {
76         PPOLICY_AUDIT_EVENTS_INFO audit_events_info;
77         PPOLICY_PRIMARY_DOMAIN_INFO primary_domain_info;
78         PPOLICY_ACCOUNT_DOMAIN_INFO account_domain_info;
79         PPOLICY_DNS_DOMAIN_INFO dns_domain_info;
80         HANDLE token;
81         BOOL ret;
82 
83         status = LsaQueryInformationPolicy(handle, PolicyAuditEventsInformation, (void **)&audit_events_info);
84         if (status == STATUS_ACCESS_DENIED)
85             skip("Not enough rights to retrieve PolicyAuditEventsInformation\n");
86         else
87             ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyAuditEventsInformation) failed, returned 0x%08x\n", status);
88         if (status == STATUS_SUCCESS)
89             LsaFreeMemory(audit_events_info);
90 
91         status = LsaQueryInformationPolicy(handle, PolicyPrimaryDomainInformation, (void **)&primary_domain_info);
92         ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyPrimaryDomainInformation) failed, returned 0x%08x\n", status);
93         if (status == STATUS_SUCCESS) {
94             if (primary_domain_info->Sid) {
95                 LPSTR strsid;
96                 if (ConvertSidToStringSidA(primary_domain_info->Sid, &strsid))
97                 {
98                     if (primary_domain_info->Name.Buffer) {
99                         LPSTR name = NULL;
100                         UINT len;
101                         len = WideCharToMultiByte( CP_ACP, 0, primary_domain_info->Name.Buffer, -1, NULL, 0, NULL, NULL );
102                         name = LocalAlloc( 0, len );
103                         WideCharToMultiByte( CP_ACP, 0, primary_domain_info->Name.Buffer, -1, name, len, NULL, NULL );
104                         trace("  name: %s sid: %s\n", name, strsid);
105                         LocalFree( name );
106                     } else
107                         trace("  name: NULL sid: %s\n", strsid);
108                     LocalFree( strsid );
109                 }
110                 else
111                     trace("invalid sid\n");
112             }
113             else
114                 trace("Running on a standalone system.\n");
115             LsaFreeMemory(primary_domain_info);
116         }
117 
118         status = LsaQueryInformationPolicy(handle, PolicyAccountDomainInformation, (void **)&account_domain_info);
119         ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyAccountDomainInformation) failed, returned 0x%08x\n", status);
120         if (status == STATUS_SUCCESS)
121             LsaFreeMemory(account_domain_info);
122 
123         /* This isn't supported in NT4 */
124         status = LsaQueryInformationPolicy(handle, PolicyDnsDomainInformation, (void **)&dns_domain_info);
125         ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER,
126            "LsaQueryInformationPolicy(PolicyDnsDomainInformation) failed, returned 0x%08x\n", status);
127         if (status == STATUS_SUCCESS) {
128             if (dns_domain_info->Sid || !IsEqualGUID(&dns_domain_info->DomainGuid, &GUID_NULL)) {
129                 LPSTR strsid = NULL;
130                 LPSTR name = NULL;
131                 LPSTR domain = NULL;
132                 LPSTR forest = NULL;
133                 LPSTR guidstr = NULL;
134                 WCHAR guidstrW[64];
135                 UINT len;
136                 guidstrW[0] = '\0';
137                 ConvertSidToStringSidA(dns_domain_info->Sid, &strsid);
138                 StringFromGUID2(&dns_domain_info->DomainGuid, guidstrW, sizeof(guidstrW)/sizeof(WCHAR));
139                 len = WideCharToMultiByte( CP_ACP, 0, guidstrW, -1, NULL, 0, NULL, NULL );
140                 guidstr = LocalAlloc( 0, len );
141                 WideCharToMultiByte( CP_ACP, 0, guidstrW, -1, guidstr, len, NULL, NULL );
142                 if (dns_domain_info->Name.Buffer) {
143                     len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->Name.Buffer, -1, NULL, 0, NULL, NULL );
144                     name = LocalAlloc( 0, len );
145                     WideCharToMultiByte( CP_ACP, 0, dns_domain_info->Name.Buffer, -1, name, len, NULL, NULL );
146                 }
147                 if (dns_domain_info->DnsDomainName.Buffer) {
148                     len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsDomainName.Buffer, -1, NULL, 0, NULL, NULL );
149                     domain = LocalAlloc( 0, len );
150                     WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsDomainName.Buffer, -1, domain, len, NULL, NULL );
151                 }
152                 if (dns_domain_info->DnsForestName.Buffer) {
153                     len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsForestName.Buffer, -1, NULL, 0, NULL, NULL );
154                     forest = LocalAlloc( 0, len );
155                     WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsForestName.Buffer, -1, forest, len, NULL, NULL );
156                 }
157                 trace("  name: %s domain: %s forest: %s guid: %s sid: %s\n",
158                       name ? name : "NULL", domain ? domain : "NULL",
159                       forest ? forest : "NULL", guidstr, strsid ? strsid : "NULL");
160                 LocalFree( name );
161                 LocalFree( forest );
162                 LocalFree( domain );
163                 LocalFree( guidstr );
164                 LocalFree( strsid );
165             }
166             else
167                 trace("Running on a standalone system.\n");
168             LsaFreeMemory(dns_domain_info);
169         }
170 
171         /* We need a valid SID to pass to LsaEnumerateAccountRights */
172         ret = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token );
173         ok(ret, "Unable to obtain process token, error %u\n", GetLastError( ));
174         if (ret) {
175             char buffer[64];
176             DWORD len;
177             TOKEN_USER *token_user = (TOKEN_USER *) buffer;
178             ret = GetTokenInformation( token, TokenUser, (LPVOID) token_user, sizeof(buffer), &len );
179             ok(ret || GetLastError( ) == ERROR_INSUFFICIENT_BUFFER, "Unable to obtain token information, error %u\n", GetLastError( ));
180             if (! ret && GetLastError( ) == ERROR_INSUFFICIENT_BUFFER) {
181                 trace("Resizing buffer to %u.\n", len);
182                 token_user = LocalAlloc( 0, len );
183                 if (token_user != NULL)
184                     ret = GetTokenInformation( token, TokenUser, (LPVOID) token_user, len, &len );
185             }
186 
187             if (ret) {
188                 PLSA_UNICODE_STRING rights;
189                 ULONG rights_count;
190                 rights = (PLSA_UNICODE_STRING) 0xdeadbeaf;
191                 rights_count = 0xcafecafe;
192                 status = LsaEnumerateAccountRights(handle, token_user->User.Sid, &rights, &rights_count);
193                 ok(status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, "Unexpected status 0x%x\n", status);
194                 if (status == STATUS_SUCCESS)
195                     LsaFreeMemory( rights );
196                 else
197                     ok(rights == NULL && rights_count == 0, "Expected rights and rights_count to be set to 0 on failure\n");
198             }
199             if (token_user != NULL && token_user != (TOKEN_USER *) buffer)
200                 LocalFree( token_user );
201             CloseHandle( token );
202         }
203 
204         status = LsaClose(handle);
205         ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
206     }
207 }
208 
209 static void get_sid_info(PSID psid, LPSTR *user, LPSTR *dom)
210 {
211     static char account[257], domain[257];
212     DWORD user_size, dom_size;
213     SID_NAME_USE use;
214     BOOL ret;
215 
216     *user = account;
217     *dom = domain;
218 
219     user_size = dom_size = 257;
220     account[0] = domain[0] = 0;
221     ret = LookupAccountSidA(NULL, psid, account, &user_size, domain, &dom_size, &use);
222     ok(ret, "LookupAccountSidA failed %u\n", GetLastError());
223 }
224 
225 static void test_LsaLookupNames2(void)
226 {
227     static const WCHAR n1[] = {'L','O','C','A','L',' ','S','E','R','V','I','C','E'};
228     static const WCHAR n2[] = {'N','T',' ','A','U','T','H','O','R','I','T','Y','\\','L','o','c','a','l','S','e','r','v','i','c','e'};
229 
230     NTSTATUS status;
231     LSA_HANDLE handle;
232     LSA_OBJECT_ATTRIBUTES attrs;
233     PLSA_REFERENCED_DOMAIN_LIST domains;
234     PLSA_TRANSLATED_SID2 sids;
235     LSA_UNICODE_STRING name[3];
236     LPSTR account, sid_dom;
237 
238     if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
239         (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
240     {
241         skip("Non-English locale (skipping LsaLookupNames2 tests)\n");
242         return;
243     }
244 
245     memset(&attrs, 0, sizeof(attrs));
246     attrs.Length = sizeof(attrs);
247 
248     status = LsaOpenPolicy(NULL, &attrs, POLICY_ALL_ACCESS, &handle);
249     ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
250        "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
251 
252     /* try a more restricted access mask if necessary */
253     if (status == STATUS_ACCESS_DENIED)
254     {
255         trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n");
256         status = LsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &handle);
257         ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status);
258     }
259     if (status != STATUS_SUCCESS)
260     {
261         skip("Cannot acquire policy handle\n");
262         return;
263     }
264 
265     name[0].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n1));
266     name[0].Length = name[0].MaximumLength = sizeof(n1);
267     memcpy(name[0].Buffer, n1, sizeof(n1));
268 
269     name[1].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n1));
270     name[1].Length = name[1].MaximumLength = sizeof(n1) - sizeof(WCHAR);
271     memcpy(name[1].Buffer, n1, sizeof(n1) - sizeof(WCHAR));
272 
273     name[2].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n2));
274     name[2].Length = name[2].MaximumLength = sizeof(n2);
275     memcpy(name[2].Buffer, n2, sizeof(n2));
276 
277     /* account name only */
278     sids = NULL;
279     domains = NULL;
280     status = LsaLookupNames2(handle, 0, 1, &name[0], &domains, &sids);
281     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x)\n", status);
282     ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use);
283     ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags);
284     ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries);
285     get_sid_info(sids[0].Sid, &account, &sid_dom);
286     ok(!strcmp(account, "LOCAL SERVICE"), "expected \"LOCAL SERVICE\", got \"%s\"\n", account);
287     ok(!strcmp(sid_dom, "NT AUTHORITY"), "expected \"NT AUTHORITY\", got \"%s\"\n", sid_dom);
288     LsaFreeMemory(sids);
289     LsaFreeMemory(domains);
290 
291     /* unknown account name */
292     sids = NULL;
293     domains = NULL;
294     status = LsaLookupNames2(handle, 0, 1, &name[1], &domains, &sids);
295     ok(status == STATUS_NONE_MAPPED, "expected STATUS_NONE_MAPPED, got %x)\n", status);
296     ok(sids[0].Use == SidTypeUnknown, "expected SidTypeUnknown, got %u\n", sids[0].Use);
297     ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags);
298     ok(domains->Entries == 0, "expected 0, got %u\n", domains->Entries);
299     LsaFreeMemory(sids);
300     LsaFreeMemory(domains);
301 
302     /* account + domain */
303     sids = NULL;
304     domains = NULL;
305     status = LsaLookupNames2(handle, 0, 1, &name[2], &domains, &sids);
306     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x)\n", status);
307     ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use);
308     ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags);
309     ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries);
310     get_sid_info(sids[0].Sid, &account, &sid_dom);
311     ok(!strcmp(account, "LOCAL SERVICE"), "expected \"LOCAL SERVICE\", got \"%s\"\n", account);
312     ok(!strcmp(sid_dom, "NT AUTHORITY"), "expected \"NT AUTHORITY\", got \"%s\"\n", sid_dom);
313     LsaFreeMemory(sids);
314     LsaFreeMemory(domains);
315 
316     /* all three */
317     sids = NULL;
318     domains = NULL;
319     status = LsaLookupNames2(handle, 0, 3, name, &domains, &sids);
320     ok(status == STATUS_SOME_NOT_MAPPED, "expected STATUS_SOME_NOT_MAPPED, got %x)\n", status);
321     ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use);
322     ok(sids[1].Use == SidTypeUnknown, "expected SidTypeUnknown, got %u\n", sids[1].Use);
323     ok(sids[2].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[2].Use);
324     ok(sids[0].DomainIndex == 0, "expected 0, got %u\n", sids[0].DomainIndex);
325     ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries);
326     LsaFreeMemory(sids);
327     LsaFreeMemory(domains);
328 
329     HeapFree(GetProcessHeap(), 0, name[0].Buffer);
330     HeapFree(GetProcessHeap(), 0, name[1].Buffer);
331     HeapFree(GetProcessHeap(), 0, name[2].Buffer);
332 
333     status = LsaClose(handle);
334     ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
335 }
336 
337 static void test_LsaLookupSids(void)
338 {
339     LSA_REFERENCED_DOMAIN_LIST *list;
340     LSA_OBJECT_ATTRIBUTES attrs;
341     LSA_TRANSLATED_NAME *names;
342     LSA_HANDLE policy;
343     TOKEN_USER *user;
344     NTSTATUS status;
345     HANDLE token;
346     DWORD size;
347     BOOL ret;
348     PSID sid;
349 
350     memset(&attrs, 0, sizeof(attrs));
351     attrs.Length = sizeof(attrs);
352 
353     status = LsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &policy);
354     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
355 
356     ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
357     ok(ret, "got %d\n", ret);
358 
359     ret = GetTokenInformation(token, TokenUser, NULL, 0, &size);
360     ok(!ret, "got %d\n", ret);
361 
362     user = HeapAlloc(GetProcessHeap(), 0, size);
363     ret = GetTokenInformation(token, TokenUser, user, size, &size);
364     ok(ret, "got %d\n", ret);
365 
366     status = LsaLookupSids(policy, 1, &user->User.Sid, &list, &names);
367     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
368 
369     ok(list->Entries > 0, "got %d\n", list->Entries);
370     if (list->Entries)
371     {
372        ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains);
373        ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid);
374        ok(list->Domains[0].Name.MaximumLength > list->Domains[0].Name.Length, "got %d, %d\n", list->Domains[0].Name.MaximumLength,
375            list->Domains[0].Name.Length);
376     }
377 
378     LsaFreeMemory(names);
379     LsaFreeMemory(list);
380 
381     HeapFree(GetProcessHeap(), 0, user);
382 
383     CloseHandle(token);
384 
385     ret = ConvertStringSidToSidA("S-1-1-0", &sid);
386     ok(ret == TRUE, "ConvertStringSidToSidA returned false\n");
387 
388     status = LsaLookupSids(policy, 1, &sid, &list, &names);
389     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
390 
391     ok(list->Entries > 0, "got %d\n", list->Entries);
392 
393     if (list->Entries)
394     {
395        ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains);
396        ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid);
397        ok(list->Domains[0].Name.MaximumLength > list->Domains[0].Name.Length, "got %d, %d\n", list->Domains[0].Name.MaximumLength,
398            list->Domains[0].Name.Length);
399        ok(list->Domains[0].Name.Buffer != NULL, "domain[0] name buffer is null\n");
400     }
401 
402     LsaFreeMemory(names);
403     LsaFreeMemory(list);
404 
405     FreeSid(sid);
406 
407     status = LsaClose(policy);
408     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
409 }
410 
411 static void test_LsaLookupPrivilegeName(void)
412 {
413     LSA_OBJECT_ATTRIBUTES attrs;
414     LSA_UNICODE_STRING *name;
415     LSA_HANDLE policy;
416     NTSTATUS status;
417     LUID luid;
418 
419     memset(&attrs, 0, sizeof(attrs));
420     attrs.Length = sizeof(attrs);
421 
422     status = LsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &policy);
423     ok(status == STATUS_SUCCESS, "Failed to open policy, %#x.\n", status);
424 
425     name = (void *)0xdeadbeef;
426     status = LsaLookupPrivilegeName(policy, NULL, &name);
427     ok(status != STATUS_SUCCESS, "Unexpected status %#x.\n", status);
428     ok(name == (void *)0xdeadbeef, "Unexpected name pointer.\n");
429 
430     name = (void *)0xdeadbeef;
431     luid.HighPart = 1;
432     luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
433     status = LsaLookupPrivilegeName(policy, &luid, &name);
434     ok(status == STATUS_NO_SUCH_PRIVILEGE, "Unexpected status %#x.\n", status);
435     ok(name == NULL, "Unexpected name pointer.\n");
436 
437     luid.HighPart = 0;
438     luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
439     status = LsaLookupPrivilegeName(policy, &luid, &name);
440     ok(status == 0, "got %#x.\n", status);
441     LsaFreeMemory(name);
442 }
443 
444 START_TEST(lsa)
445 {
446     test_lsa();
447     test_LsaLookupNames2();
448     test_LsaLookupSids();
449     test_LsaLookupPrivilegeName();
450 }
451