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