1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/advapi32/misc/logon.c 5 * PURPOSE: Logon functions 6 * PROGRAMMER: Eric Kohl 7 */ 8 9 #include <advapi32.h> 10 WINE_DEFAULT_DEBUG_CHANNEL(advapi); 11 12 /* GLOBALS *****************************************************************/ 13 14 static const CHAR AdvapiTokenSourceName[] = "Advapi "; 15 C_ASSERT(sizeof(AdvapiTokenSourceName) == RTL_FIELD_SIZE(TOKEN_SOURCE, SourceName) + 1); 16 17 HANDLE LsaHandle = NULL; 18 ULONG AuthenticationPackage = 0; 19 20 /* FUNCTIONS ***************************************************************/ 21 22 static 23 NTSTATUS 24 OpenLogonLsaHandle(VOID) 25 { 26 LSA_STRING LogonProcessName; 27 LSA_STRING PackageName; 28 LSA_OPERATIONAL_MODE SecurityMode = 0; 29 NTSTATUS Status; 30 31 RtlInitAnsiString((PANSI_STRING)&LogonProcessName, 32 "User32LogonProcess"); 33 34 Status = LsaRegisterLogonProcess(&LogonProcessName, 35 &LsaHandle, 36 &SecurityMode); 37 if (!NT_SUCCESS(Status)) 38 { 39 TRACE("LsaRegisterLogonProcess failed (Status 0x%08lx)\n", Status); 40 goto done; 41 } 42 43 RtlInitAnsiString((PANSI_STRING)&PackageName, 44 MSV1_0_PACKAGE_NAME); 45 46 Status = LsaLookupAuthenticationPackage(LsaHandle, 47 &PackageName, 48 &AuthenticationPackage); 49 if (!NT_SUCCESS(Status)) 50 { 51 TRACE("LsaLookupAuthenticationPackage failed (Status 0x%08lx)\n", Status); 52 goto done; 53 } 54 55 TRACE("AuthenticationPackage: 0x%08lx\n", AuthenticationPackage); 56 57 done: 58 if (!NT_SUCCESS(Status)) 59 { 60 if (LsaHandle != NULL) 61 { 62 Status = LsaDeregisterLogonProcess(LsaHandle); 63 if (!NT_SUCCESS(Status)) 64 { 65 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status); 66 } 67 } 68 } 69 70 return Status; 71 } 72 73 74 NTSTATUS 75 CloseLogonLsaHandle(VOID) 76 { 77 NTSTATUS Status = STATUS_SUCCESS; 78 79 if (LsaHandle != NULL) 80 { 81 Status = LsaDeregisterLogonProcess(LsaHandle); 82 if (!NT_SUCCESS(Status)) 83 { 84 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status); 85 } 86 } 87 88 return Status; 89 } 90 91 92 static 93 BOOL 94 CreateProcessAsUserCommon( 95 _In_opt_ HANDLE hToken, 96 _In_ DWORD dwCreationFlags, 97 _Out_ LPPROCESS_INFORMATION lpProcessInformation) 98 { 99 NTSTATUS Status; 100 PROCESS_ACCESS_TOKEN AccessToken; 101 102 if (hToken != NULL) 103 { 104 TOKEN_TYPE Type; 105 ULONG ReturnLength; 106 OBJECT_ATTRIBUTES ObjectAttributes; 107 HANDLE hTokenDup; 108 BOOLEAN PrivilegeSet = FALSE, HavePrivilege; 109 110 /* Check whether the user-provided token is a primary token */ 111 // GetTokenInformation(); 112 Status = NtQueryInformationToken(hToken, 113 TokenType, 114 &Type, 115 sizeof(Type), 116 &ReturnLength); 117 if (!NT_SUCCESS(Status)) 118 { 119 ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status); 120 goto Quit; 121 } 122 if (Type != TokenPrimary) 123 { 124 ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken, Type); 125 Status = STATUS_BAD_TOKEN_TYPE; 126 goto Quit; 127 } 128 129 /* Duplicate the token for this new process */ 130 InitializeObjectAttributes(&ObjectAttributes, 131 NULL, 132 0, 133 NULL, 134 NULL); // FIXME: Use a valid SecurityDescriptor! 135 Status = NtDuplicateToken(hToken, 136 0, 137 &ObjectAttributes, 138 FALSE, 139 TokenPrimary, 140 &hTokenDup); 141 if (!NT_SUCCESS(Status)) 142 { 143 ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status); 144 goto Quit; 145 } 146 147 // FIXME: Do we always need SecurityImpersonation? 148 Status = RtlImpersonateSelf(SecurityImpersonation); 149 if (!NT_SUCCESS(Status)) 150 { 151 ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status); 152 NtClose(hTokenDup); 153 goto Quit; 154 } 155 156 /* 157 * Attempt to acquire the process primary token assignment privilege 158 * in case we actually need it. 159 * The call will either succeed or fail when the caller has (or has not) 160 * enough rights. 161 * The last situation may not be dramatic for us. Indeed it may happen 162 * that the user-provided token is a restricted version of the caller's 163 * primary token (aka. a "child" token), or both tokens inherit (i.e. are 164 * children, and are together "siblings") from a common parent token. 165 * In this case the NT kernel allows us to assign the token to the child 166 * process without the need for the assignment privilege, which is fine. 167 * On the contrary, if the user-provided token is completely arbitrary, 168 * then the NT kernel will enforce the presence of the assignment privilege: 169 * because we failed (by assumption) to assign the privilege, the process 170 * token assignment will fail as required. It is then the job of the 171 * caller to manually acquire the necessary privileges. 172 */ 173 Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 174 TRUE, TRUE, &PrivilegeSet); 175 HavePrivilege = NT_SUCCESS(Status); 176 if (!HavePrivilege) 177 { 178 ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, " 179 "attempting to continue without it...\n", Status); 180 } 181 182 AccessToken.Token = hTokenDup; 183 AccessToken.Thread = lpProcessInformation->hThread; 184 185 /* Set the new process token */ 186 Status = NtSetInformationProcess(lpProcessInformation->hProcess, 187 ProcessAccessToken, 188 (PVOID)&AccessToken, 189 sizeof(AccessToken)); 190 191 /* Restore the privilege */ 192 if (HavePrivilege) 193 { 194 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 195 PrivilegeSet, TRUE, &PrivilegeSet); 196 } 197 198 RevertToSelf(); 199 200 /* Close the duplicated token */ 201 NtClose(hTokenDup); 202 203 /* Check whether NtSetInformationProcess() failed */ 204 if (!NT_SUCCESS(Status)) 205 { 206 ERR("NtSetInformationProcess() failed, Status 0x%08x\n", Status); 207 goto Quit; 208 } 209 210 if (!NT_SUCCESS(Status)) 211 { 212 Quit: 213 TerminateProcess(lpProcessInformation->hProcess, Status); 214 SetLastError(RtlNtStatusToDosError(Status)); 215 return FALSE; 216 } 217 } 218 219 /* Resume the main thread */ 220 if (!(dwCreationFlags & CREATE_SUSPENDED)) 221 { 222 ResumeThread(lpProcessInformation->hThread); 223 } 224 225 return TRUE; 226 } 227 228 229 /* 230 * @implemented 231 */ 232 BOOL 233 WINAPI 234 DECLSPEC_HOTPATCH 235 CreateProcessAsUserA( 236 _In_opt_ HANDLE hToken, 237 _In_opt_ LPCSTR lpApplicationName, 238 _Inout_opt_ LPSTR lpCommandLine, 239 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 240 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 241 _In_ BOOL bInheritHandles, 242 _In_ DWORD dwCreationFlags, 243 _In_opt_ LPVOID lpEnvironment, 244 _In_opt_ LPCSTR lpCurrentDirectory, 245 _In_ LPSTARTUPINFOA lpStartupInfo, 246 _Out_ LPPROCESS_INFORMATION lpProcessInformation) 247 { 248 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_a(lpApplicationName), 249 debugstr_a(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles, 250 dwCreationFlags, lpEnvironment, debugstr_a(lpCurrentDirectory), lpStartupInfo, lpProcessInformation); 251 252 /* Create the process with a suspended main thread */ 253 if (!CreateProcessA(lpApplicationName, 254 lpCommandLine, 255 lpProcessAttributes, 256 lpThreadAttributes, 257 bInheritHandles, 258 dwCreationFlags | CREATE_SUSPENDED, 259 lpEnvironment, 260 lpCurrentDirectory, 261 lpStartupInfo, 262 lpProcessInformation)) 263 { 264 ERR("CreateProcessA failed, last error: %d\n", GetLastError()); 265 return FALSE; 266 } 267 268 /* Call the helper function */ 269 return CreateProcessAsUserCommon(hToken, 270 dwCreationFlags, 271 lpProcessInformation); 272 } 273 274 275 /* 276 * @implemented 277 */ 278 BOOL 279 WINAPI 280 DECLSPEC_HOTPATCH 281 CreateProcessAsUserW( 282 _In_opt_ HANDLE hToken, 283 _In_opt_ LPCWSTR lpApplicationName, 284 _Inout_opt_ LPWSTR lpCommandLine, 285 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 286 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 287 _In_ BOOL bInheritHandles, 288 _In_ DWORD dwCreationFlags, 289 _In_opt_ LPVOID lpEnvironment, 290 _In_opt_ LPCWSTR lpCurrentDirectory, 291 _In_ LPSTARTUPINFOW lpStartupInfo, 292 _Out_ LPPROCESS_INFORMATION lpProcessInformation) 293 { 294 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_w(lpApplicationName), 295 debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles, 296 dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory), lpStartupInfo, lpProcessInformation); 297 298 /* Create the process with a suspended main thread */ 299 if (!CreateProcessW(lpApplicationName, 300 lpCommandLine, 301 lpProcessAttributes, 302 lpThreadAttributes, 303 bInheritHandles, 304 dwCreationFlags | CREATE_SUSPENDED, 305 lpEnvironment, 306 lpCurrentDirectory, 307 lpStartupInfo, 308 lpProcessInformation)) 309 { 310 ERR("CreateProcessW failed, last error: %d\n", GetLastError()); 311 return FALSE; 312 } 313 314 /* Call the helper function */ 315 return CreateProcessAsUserCommon(hToken, 316 dwCreationFlags, 317 lpProcessInformation); 318 } 319 320 321 /* 322 * @implemented 323 */ 324 BOOL 325 WINAPI 326 LogonUserA( 327 _In_ LPSTR lpszUsername, 328 _In_opt_ LPSTR lpszDomain, 329 _In_opt_ LPSTR lpszPassword, 330 _In_ DWORD dwLogonType, 331 _In_ DWORD dwLogonProvider, 332 _Out_opt_ PHANDLE phToken) 333 { 334 return LogonUserExA(lpszUsername, 335 lpszDomain, 336 lpszPassword, 337 dwLogonType, 338 dwLogonProvider, 339 phToken, 340 NULL, 341 NULL, 342 NULL, 343 NULL); 344 } 345 346 347 /* 348 * @implemented 349 */ 350 BOOL 351 WINAPI 352 LogonUserExA( 353 _In_ LPSTR lpszUsername, 354 _In_opt_ LPSTR lpszDomain, 355 _In_opt_ LPSTR lpszPassword, 356 _In_ DWORD dwLogonType, 357 _In_ DWORD dwLogonProvider, 358 _Out_opt_ PHANDLE phToken, 359 _Out_opt_ PSID *ppLogonSid, 360 _Out_opt_ PVOID *ppProfileBuffer, 361 _Out_opt_ LPDWORD pdwProfileLength, 362 _Out_opt_ PQUOTA_LIMITS pQuotaLimits) 363 { 364 UNICODE_STRING UserName; 365 UNICODE_STRING Domain; 366 UNICODE_STRING Password; 367 BOOL ret = FALSE; 368 369 UserName.Buffer = NULL; 370 Domain.Buffer = NULL; 371 Password.Buffer = NULL; 372 373 if (!RtlCreateUnicodeStringFromAsciiz(&UserName, lpszUsername)) 374 { 375 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 376 goto UsernameDone; 377 } 378 379 if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain)) 380 { 381 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 382 goto DomainDone; 383 } 384 385 if (!RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword)) 386 { 387 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 388 goto PasswordDone; 389 } 390 391 ret = LogonUserExW(UserName.Buffer, 392 Domain.Buffer, 393 Password.Buffer, 394 dwLogonType, 395 dwLogonProvider, 396 phToken, 397 ppLogonSid, 398 ppProfileBuffer, 399 pdwProfileLength, 400 pQuotaLimits); 401 402 if (Password.Buffer != NULL) 403 RtlFreeUnicodeString(&Password); 404 405 PasswordDone: 406 if (Domain.Buffer != NULL) 407 RtlFreeUnicodeString(&Domain); 408 409 DomainDone: 410 if (UserName.Buffer != NULL) 411 RtlFreeUnicodeString(&UserName); 412 413 UsernameDone: 414 return ret; 415 } 416 417 418 /* 419 * @implemented 420 */ 421 BOOL 422 WINAPI 423 LogonUserW( 424 _In_ LPWSTR lpszUsername, 425 _In_opt_ LPWSTR lpszDomain, 426 _In_opt_ LPWSTR lpszPassword, 427 _In_ DWORD dwLogonType, 428 _In_ DWORD dwLogonProvider, 429 _Out_opt_ PHANDLE phToken) 430 { 431 return LogonUserExW(lpszUsername, 432 lpszDomain, 433 lpszPassword, 434 dwLogonType, 435 dwLogonProvider, 436 phToken, 437 NULL, 438 NULL, 439 NULL, 440 NULL); 441 } 442 443 444 /* 445 * @implemented 446 */ 447 BOOL 448 WINAPI 449 LogonUserExW( 450 _In_ LPWSTR lpszUsername, 451 _In_opt_ LPWSTR lpszDomain, 452 _In_opt_ LPWSTR lpszPassword, 453 _In_ DWORD dwLogonType, 454 _In_ DWORD dwLogonProvider, 455 _Out_opt_ PHANDLE phToken, 456 _Out_opt_ PSID *ppLogonSid, 457 _Out_opt_ PVOID *ppProfileBuffer, 458 _Out_opt_ LPDWORD pdwProfileLength, 459 _Out_opt_ PQUOTA_LIMITS pQuotaLimits) 460 { 461 SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY}; 462 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; 463 PSID LogonSid = NULL; 464 PSID LocalSid = NULL; 465 LSA_STRING OriginName; 466 UNICODE_STRING DomainName; 467 UNICODE_STRING UserName; 468 UNICODE_STRING Password; 469 PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL; 470 ULONG AuthInfoLength; 471 ULONG_PTR Ptr; 472 TOKEN_SOURCE TokenSource; 473 PTOKEN_GROUPS TokenGroups = NULL; 474 PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL; 475 ULONG ProfileBufferLength = 0; 476 LUID Luid = {0, 0}; 477 LUID LogonId = {0, 0}; 478 HANDLE TokenHandle = NULL; 479 QUOTA_LIMITS QuotaLimits; 480 SECURITY_LOGON_TYPE LogonType; 481 NTSTATUS SubStatus = STATUS_SUCCESS; 482 NTSTATUS Status; 483 484 if ((ppProfileBuffer != NULL && pdwProfileLength == NULL) || 485 (ppProfileBuffer == NULL && pdwProfileLength != NULL)) 486 { 487 SetLastError(ERROR_INVALID_PARAMETER); 488 return FALSE; 489 } 490 491 if (ppProfileBuffer != NULL && pdwProfileLength != NULL) 492 { 493 *ppProfileBuffer = NULL; 494 *pdwProfileLength = 0; 495 } 496 497 if (phToken != NULL) 498 *phToken = NULL; 499 500 switch (dwLogonType) 501 { 502 case LOGON32_LOGON_INTERACTIVE: 503 LogonType = Interactive; 504 break; 505 506 case LOGON32_LOGON_NETWORK: 507 LogonType = Network; 508 break; 509 510 case LOGON32_LOGON_BATCH: 511 LogonType = Batch; 512 break; 513 514 case LOGON32_LOGON_SERVICE: 515 LogonType = Service; 516 break; 517 518 default: 519 ERR("Invalid logon type: %ul\n", dwLogonType); 520 Status = STATUS_INVALID_PARAMETER; 521 goto done; 522 } 523 524 if (LsaHandle == NULL) 525 { 526 Status = OpenLogonLsaHandle(); 527 if (!NT_SUCCESS(Status)) 528 goto done; 529 } 530 531 RtlInitAnsiString((PANSI_STRING)&OriginName, 532 "Advapi32 Logon"); 533 534 RtlInitUnicodeString(&DomainName, 535 lpszDomain); 536 537 RtlInitUnicodeString(&UserName, 538 lpszUsername); 539 540 RtlInitUnicodeString(&Password, 541 lpszPassword); 542 543 AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+ 544 DomainName.MaximumLength + 545 UserName.MaximumLength + 546 Password.MaximumLength; 547 548 AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(), 549 HEAP_ZERO_MEMORY, 550 AuthInfoLength); 551 if (AuthInfo == NULL) 552 { 553 Status = STATUS_INSUFFICIENT_RESOURCES; 554 goto done; 555 } 556 557 AuthInfo->MessageType = MsV1_0InteractiveLogon; 558 559 Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON); 560 561 AuthInfo->LogonDomainName.Length = DomainName.Length; 562 AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength; 563 AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr; 564 if (DomainName.MaximumLength > 0) 565 { 566 RtlCopyMemory(AuthInfo->LogonDomainName.Buffer, 567 DomainName.Buffer, 568 DomainName.MaximumLength); 569 570 Ptr += DomainName.MaximumLength; 571 } 572 573 AuthInfo->UserName.Length = UserName.Length; 574 AuthInfo->UserName.MaximumLength = UserName.MaximumLength; 575 AuthInfo->UserName.Buffer = (PWCHAR)Ptr; 576 if (UserName.MaximumLength > 0) 577 RtlCopyMemory(AuthInfo->UserName.Buffer, 578 UserName.Buffer, 579 UserName.MaximumLength); 580 581 Ptr += UserName.MaximumLength; 582 583 AuthInfo->Password.Length = Password.Length; 584 AuthInfo->Password.MaximumLength = Password.MaximumLength; 585 AuthInfo->Password.Buffer = (PWCHAR)Ptr; 586 if (Password.MaximumLength > 0) 587 RtlCopyMemory(AuthInfo->Password.Buffer, 588 Password.Buffer, 589 Password.MaximumLength); 590 591 /* Create the Logon SID */ 592 AllocateLocallyUniqueId(&LogonId); 593 Status = RtlAllocateAndInitializeSid(&SystemAuthority, 594 SECURITY_LOGON_IDS_RID_COUNT, 595 SECURITY_LOGON_IDS_RID, 596 LogonId.HighPart, 597 LogonId.LowPart, 598 SECURITY_NULL_RID, 599 SECURITY_NULL_RID, 600 SECURITY_NULL_RID, 601 SECURITY_NULL_RID, 602 SECURITY_NULL_RID, 603 &LogonSid); 604 if (!NT_SUCCESS(Status)) 605 goto done; 606 607 /* Create the Local SID */ 608 Status = RtlAllocateAndInitializeSid(&LocalAuthority, 609 1, 610 SECURITY_LOCAL_RID, 611 SECURITY_NULL_RID, 612 SECURITY_NULL_RID, 613 SECURITY_NULL_RID, 614 SECURITY_NULL_RID, 615 SECURITY_NULL_RID, 616 SECURITY_NULL_RID, 617 SECURITY_NULL_RID, 618 &LocalSid); 619 if (!NT_SUCCESS(Status)) 620 goto done; 621 622 /* Allocate and set the token groups */ 623 TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(), 624 HEAP_ZERO_MEMORY, 625 sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES))); 626 if (TokenGroups == NULL) 627 { 628 Status = STATUS_INSUFFICIENT_RESOURCES; 629 goto done; 630 } 631 632 TokenGroups->GroupCount = 2; 633 TokenGroups->Groups[0].Sid = LogonSid; 634 TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | 635 SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID; 636 TokenGroups->Groups[1].Sid = LocalSid; 637 TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | 638 SE_GROUP_ENABLED_BY_DEFAULT; 639 640 /* Set the token source */ 641 RtlCopyMemory(TokenSource.SourceName, 642 AdvapiTokenSourceName, 643 sizeof(TokenSource.SourceName)); 644 AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); 645 646 Status = LsaLogonUser(LsaHandle, 647 &OriginName, 648 LogonType, 649 AuthenticationPackage, 650 (PVOID)AuthInfo, 651 AuthInfoLength, 652 TokenGroups, 653 &TokenSource, 654 (PVOID*)&ProfileBuffer, 655 &ProfileBufferLength, 656 &Luid, 657 &TokenHandle, 658 &QuotaLimits, 659 &SubStatus); 660 if (!NT_SUCCESS(Status)) 661 { 662 ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status); 663 goto done; 664 } 665 666 if (ProfileBuffer != NULL) 667 { 668 TRACE("ProfileBuffer: %p\n", ProfileBuffer); 669 TRACE("MessageType: %u\n", ProfileBuffer->MessageType); 670 671 TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer); 672 TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer); 673 674 TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer); 675 TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer); 676 } 677 678 TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart); 679 680 if (TokenHandle != NULL) 681 { 682 TRACE("TokenHandle: %p\n", TokenHandle); 683 } 684 685 if (phToken != NULL) 686 *phToken = TokenHandle; 687 688 /* FIXME: return ppLogonSid and pQuotaLimits */ 689 690 done: 691 if (ProfileBuffer != NULL) 692 LsaFreeReturnBuffer(ProfileBuffer); 693 694 if (!NT_SUCCESS(Status)) 695 { 696 if (TokenHandle != NULL) 697 CloseHandle(TokenHandle); 698 } 699 700 if (TokenGroups != NULL) 701 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups); 702 703 if (LocalSid != NULL) 704 RtlFreeSid(LocalSid); 705 706 if (LogonSid != NULL) 707 RtlFreeSid(LogonSid); 708 709 if (AuthInfo != NULL) 710 RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo); 711 712 if (!NT_SUCCESS(Status)) 713 { 714 SetLastError(RtlNtStatusToDosError(Status)); 715 return FALSE; 716 } 717 718 return TRUE; 719 } 720 721 /* EOF */ 722