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