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 /** 93 * @brief 94 * Creates a default security descriptor that is going 95 * to be used by both the newly created process and thread 96 * by a call to CreateProcessAsUserA/W. This descriptor also 97 * serves for the newly duplicated token object that is going 98 * to be set for the token which acts as the main user. 99 * 100 * @param[in] TokenHandle 101 * A handle to a token. The function will use this token to 102 * query security details such as the owner and primary group 103 * associated with the security context of this token. The 104 * obtained information will then be assigned to the security 105 * descriptor. 106 * 107 * @param[out] Sd 108 * A pointer to an allocated security descriptor that is given 109 * to the caller. 110 * 111 * @return 112 * Return TRUE if the security descriptor has been successfully 113 * created, FALSE otherwise. 114 * 115 * @remarks 116 * When a process is created on behald of the user's security context 117 * this user will be the owner and responsible for that process. Whatever 118 * objects created or stuff done within the process space is at the 119 * discretion of the user, that is, further objects created are in 120 * charge by the user himself as is the owner of the process. 121 * 122 * !!!NOTE!!! -- On Windows the security descriptor is created by using 123 * CreatePrivateObjectSecurity(Ex) API call. Whilst the way the security 124 * descriptor is created in our end is not wrong per se, this function 125 * serves a placeholder until CreatePrivateObjectSecurity is implemented. 126 */ 127 static 128 BOOL 129 CreateDefaultProcessSecurityCommon( 130 _In_ HANDLE TokenHandle, 131 _Out_ PSECURITY_DESCRIPTOR *Sd) 132 { 133 NTSTATUS Status; 134 BOOL Success; 135 PACL Dacl; 136 PTOKEN_OWNER OwnerOfToken; 137 PTOKEN_PRIMARY_GROUP PrimaryGroupOfToken; 138 SECURITY_DESCRIPTOR AbsoluteSd; 139 ULONG DaclSize, TokenOwnerSize, PrimaryGroupSize, RelativeSDSize = 0; 140 PSID OwnerSid = NULL, SystemSid = NULL, PrimaryGroupSid = NULL; 141 PSECURITY_DESCRIPTOR RelativeSD = NULL; 142 static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; 143 144 /* 145 * Since we do not know how much space 146 * is needed to allocate the buffer to 147 * hold the token owner, first we must 148 * query the exact size. 149 */ 150 Status = NtQueryInformationToken(TokenHandle, 151 TokenOwner, 152 NULL, 153 0, 154 &TokenOwnerSize); 155 if (Status != STATUS_BUFFER_TOO_SMALL) 156 { 157 ERR("CreateDefaultProcessSecurityCommon(): Unexpected status code returned, must be STATUS_BUFFER_TOO_SMALL (Status 0x%08lx)\n", Status); 158 return FALSE; 159 } 160 161 /* We have the required space size, allocate the buffer now */ 162 OwnerOfToken = RtlAllocateHeap(RtlGetProcessHeap(), 163 HEAP_ZERO_MEMORY, 164 TokenOwnerSize); 165 if (OwnerOfToken == NULL) 166 { 167 ERR("CreateDefaultProcessSecurityCommon(): Failed to allocate buffer for token owner!\n"); 168 return FALSE; 169 } 170 171 /* Now query the token owner */ 172 Status = NtQueryInformationToken(TokenHandle, 173 TokenOwner, 174 OwnerOfToken, 175 TokenOwnerSize, 176 &TokenOwnerSize); 177 if (!NT_SUCCESS(Status)) 178 { 179 ERR("CreateDefaultProcessSecurityCommon(): Failed to query the token owner (Status 0x%08lx)\n", Status); 180 Success = FALSE; 181 goto Quit; 182 } 183 184 /* Do the same process but for the primary group now */ 185 Status = NtQueryInformationToken(TokenHandle, 186 TokenPrimaryGroup, 187 NULL, 188 0, 189 &PrimaryGroupSize); 190 if (Status != STATUS_BUFFER_TOO_SMALL) 191 { 192 ERR("CreateDefaultProcessSecurityCommon(): Unexpected status code returned, must be STATUS_BUFFER_TOO_SMALL (Status 0x%08lx)\n", Status); 193 Success = FALSE; 194 goto Quit; 195 } 196 197 /* Allocate the buffer */ 198 PrimaryGroupOfToken = RtlAllocateHeap(RtlGetProcessHeap(), 199 HEAP_ZERO_MEMORY, 200 PrimaryGroupSize); 201 if (PrimaryGroupOfToken == NULL) 202 { 203 ERR("CreateDefaultProcessSecurityCommon(): Failed to allocate buffer for primary group token!\n"); 204 Success = FALSE; 205 goto Quit; 206 } 207 208 /* Query the primary group now */ 209 Status = NtQueryInformationToken(TokenHandle, 210 TokenPrimaryGroup, 211 PrimaryGroupOfToken, 212 PrimaryGroupSize, 213 &PrimaryGroupSize); 214 if (!NT_SUCCESS(Status)) 215 { 216 ERR("CreateDefaultProcessSecurityCommon(): Failed to query the token owner (Status 0x%08lx)\n", Status); 217 Success = FALSE; 218 goto Quit; 219 } 220 221 /* Create the SYSTEM SID */ 222 if (!AllocateAndInitializeSid(&NtAuthority, 223 1, 224 SECURITY_LOCAL_SYSTEM_RID, 225 0, 0, 0, 0, 0, 0, 0, 226 &SystemSid)) 227 { 228 ERR("CreateDefaultProcessSecurityCommon(): Failed to create Local System SID (error code %d)\n", GetLastError()); 229 Success = FALSE; 230 goto Quit; 231 } 232 233 /* Cache the token owner and primary group SID */ 234 OwnerSid = OwnerOfToken->Owner; 235 PrimaryGroupSid = PrimaryGroupOfToken->PrimaryGroup; 236 237 /* Set up the DACL size */ 238 DaclSize = sizeof(ACL) + 239 sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(OwnerSid) + 240 sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(SystemSid); 241 242 /* Allocate buffer for the DACL */ 243 Dacl = RtlAllocateHeap(RtlGetProcessHeap(), 244 HEAP_ZERO_MEMORY, 245 DaclSize); 246 if (Dacl == NULL) 247 { 248 ERR("CreateDefaultProcessSecurityCommon(): Failed to allocate buffer for DACL!\n"); 249 Success = FALSE; 250 goto Quit; 251 } 252 253 /* Initialize the DACL */ 254 if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION)) 255 { 256 ERR("CreateDefaultProcessSecurityCommon(): Failed to initialize DACL (error code %d)\n", GetLastError()); 257 Success = FALSE; 258 goto Quit; 259 } 260 261 /* Give full powers to the owner */ 262 if (!AddAccessAllowedAce(Dacl, 263 ACL_REVISION, 264 GENERIC_ALL, 265 OwnerSid)) 266 { 267 ERR("CreateDefaultProcessSecurityCommon(): Failed to set up ACE for owner (error code %d)\n", GetLastError()); 268 Success = FALSE; 269 goto Quit; 270 } 271 272 /* Give full powers to SYSTEM as well */ 273 if (!AddAccessAllowedAce(Dacl, 274 ACL_REVISION, 275 GENERIC_ALL, 276 SystemSid)) 277 { 278 ERR("CreateDefaultProcessSecurityCommon(): Failed to set up ACE for SYSTEM (error code %d)\n", GetLastError()); 279 Success = FALSE; 280 goto Quit; 281 } 282 283 /* Initialize the descriptor in absolute format */ 284 if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION)) 285 { 286 ERR("CreateDefaultProcessSecurityCommon(): Failed to initialize absolute security descriptor (error code %d)\n", GetLastError()); 287 Success = FALSE; 288 goto Quit; 289 } 290 291 /* Set the DACL to the security descriptor */ 292 if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE)) 293 { 294 ERR("CreateDefaultProcessSecurityCommon(): Failed to set up DACL to absolute security descriptor (error code %d)\n", GetLastError()); 295 Success = FALSE; 296 goto Quit; 297 } 298 299 /* Set the owner for this descriptor */ 300 if (!SetSecurityDescriptorOwner(&AbsoluteSd, OwnerSid, FALSE)) 301 { 302 ERR("CreateDefaultProcessSecurityCommon(): Failed to set up owner to absolute security descriptor (error code %d)\n", GetLastError()); 303 Success = FALSE; 304 goto Quit; 305 } 306 307 /* Set the primary group for this descriptor */ 308 if (!SetSecurityDescriptorGroup(&AbsoluteSd, PrimaryGroupSid, FALSE)) 309 { 310 ERR("CreateDefaultProcessSecurityCommon(): Failed to set up group to absolute security descriptor (error code %d)\n", GetLastError()); 311 Success = FALSE; 312 goto Quit; 313 } 314 315 /* 316 * Determine the exact size space of the absolute 317 * descriptor so that we can allocate a buffer 318 * to hold the descriptor in a converted self 319 * relative format. 320 */ 321 if (!MakeSelfRelativeSD(&AbsoluteSd, NULL, &RelativeSDSize) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) 322 { 323 ERR("CreateDefaultProcessSecurityCommon(): Unexpected error code (error code %d -- must be ERROR_INSUFFICIENT_BUFFER)\n", GetLastError()); 324 Success = FALSE; 325 goto Quit; 326 } 327 328 /* Allocate the buffer */ 329 RelativeSD = RtlAllocateHeap(RtlGetProcessHeap(), 330 HEAP_ZERO_MEMORY, 331 RelativeSDSize); 332 if (RelativeSD == NULL) 333 { 334 ERR("CreateDefaultProcessSecurityCommon(): Failed to allocate buffer for self relative descriptor!\n"); 335 Success = FALSE; 336 goto Quit; 337 } 338 339 /* Convert to a self relative format now */ 340 if (!MakeSelfRelativeSD(&AbsoluteSd, RelativeSD, &RelativeSDSize)) 341 { 342 ERR("CreateDefaultProcessSecurityCommon(): Failed to allocate relative SD, buffer too smal (error code %d)\n", GetLastError()); 343 Success = FALSE; 344 goto Quit; 345 } 346 347 /* Success, give the descriptor to the caller */ 348 *Sd = RelativeSD; 349 Success = TRUE; 350 351 Quit: 352 /* Free all the stuff we have allocated */ 353 if (OwnerOfToken != NULL) 354 RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerOfToken); 355 356 if (PrimaryGroupOfToken != NULL) 357 RtlFreeHeap(RtlGetProcessHeap(), 0, PrimaryGroupOfToken); 358 359 if (SystemSid != NULL) 360 FreeSid(SystemSid); 361 362 if (Dacl != NULL) 363 RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl); 364 365 if (Success == FALSE) 366 { 367 if (RelativeSD != NULL) 368 { 369 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSD); 370 } 371 } 372 373 return Success; 374 } 375 376 377 /** 378 * @brief 379 * Changes the object security information of a process 380 * and thread that belongs to the process with new security 381 * data, basically by replacing the previous security descriptor 382 * with a new one. 383 * 384 * @param[in] ProcessHandle 385 * A handle to a valid process of which security information is 386 * to be changed by setting up a new security descriptor. 387 * 388 * @param[in] ThreadHandle 389 * A handle to a valid thread of which security information is 390 * to be changed by setting up a new security descriptor. 391 * 392 * @param[in] ProcessSecurity 393 * A pointer to a security descriptor that is for the process. 394 * 395 * @param[in] ThreadSecurity 396 * A pointer to a security descriptor that is for the thread. 397 * 398 * @return 399 * Return TRUE if new security information has been set, FALSE 400 * otherwise. 401 */ 402 static 403 BOOL 404 InsertProcessSecurityCommon( 405 _In_ HANDLE ProcessHandle, 406 _In_ HANDLE ThreadHandle, 407 _In_ PSECURITY_DESCRIPTOR ProcessSecurity, 408 _In_ PSECURITY_DESCRIPTOR ThreadSecurity) 409 { 410 /* Set new security data for the process */ 411 if (!SetKernelObjectSecurity(ProcessHandle, 412 DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, 413 ProcessSecurity)) 414 { 415 ERR("InsertProcessSecurityCommon(): Failed to set security for process (error code %d)\n", GetLastError()); 416 return FALSE; 417 } 418 419 /* Set new security data for the thread */ 420 if (!SetKernelObjectSecurity(ThreadHandle, 421 DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, 422 ThreadSecurity)) 423 { 424 ERR("InsertProcessSecurityCommon(): Failed to set security for thread (error code %d)\n", GetLastError()); 425 return FALSE; 426 } 427 428 return TRUE; 429 } 430 431 432 /** 433 * @brief 434 * Sets a primary token to the newly created process. 435 * The primary token that gets assigned to is a token 436 * whose security context is associated with the logged 437 * in user. For futher documentation information, see 438 * Remarks. 439 * 440 * @param[in] ImpersonateAsSelf 441 * If set to TRUE, the function will act on behalf of 442 * the calling process by impersonating its security context. 443 * Generally the caller will disable impersonation and attempt 444 * to act on behalf of the said main process as a first tentative 445 * to acquire the needed privilege in order to assign a token 446 * to the process. If set to FALSE, the function won't act on behalf 447 * of the calling process. 448 * 449 * @param[in] ProcessHandle 450 * A handle to the newly created process. The function will use it 451 * as a mean to assign the primary token to this process. 452 * 453 * @param[in] ThreadHandle 454 * A handle to the newly and primary created thread associated with 455 * the process. 456 * 457 * @param[in] DuplicatedTokenHandle 458 * A handle to a duplicated access token. This token represents as a primary 459 * one, initially duplicated in form as a primary type from an impersonation 460 * type. 461 * 462 * @return 463 * STATUS_SUCCESS is returned if token assignment to process succeeded, otherwise 464 * a failure NTSTATUS code is returned. A potential failure status code is 465 * STATUS_ACCESS_DENIED which means the caller doesn't have enough rights 466 * to grant access for primary token assignment to process. 467 * 468 * @remarks 469 * This function acts like an internal helper for CreateProcessAsUserCommon (and as 470 * such for CreateProcessAsUserW/A as well) as once a process is created, the 471 * function is tasked to assign the security context of the logged in user to 472 * that process. However, the rate of success of inserting the token into the 473 * process ultimately depends on the caller. 474 * 475 * The caller will either succeed or fail at acquiring SE_ASSIGNPRIMARYTOKEN_PRIVILEGE 476 * privilege depending on the security context of the user. If it's allowed, the caller 477 * would generally acquire such privilege immediately but if not, the caller will attempt 478 * to do a second try. 479 */ 480 static 481 NTSTATUS 482 InsertTokenToProcessCommon( 483 _In_ BOOL ImpersonateAsSelf, 484 _In_ HANDLE ProcessHandle, 485 _In_ HANDLE ThreadHandle, 486 _In_ HANDLE DuplicatedTokenHandle) 487 { 488 NTSTATUS Status; 489 PROCESS_ACCESS_TOKEN AccessToken; 490 BOOLEAN PrivilegeSet; 491 BOOLEAN HavePrivilege; 492 493 /* 494 * Assume the SE_ASSIGNPRIMARYTOKEN_PRIVILEGE 495 * privilege hasn't been set. 496 */ 497 PrivilegeSet = FALSE; 498 499 /* 500 * The caller asked that we must impersonate as 501 * ourselves, that is, we'll be going to impersonate 502 * the security context of the calling process. If 503 * self impersonation fails then the caller has 504 * to do a "rinse and repeat" approach. 505 */ 506 if (ImpersonateAsSelf) 507 { 508 Status = RtlImpersonateSelf(SecurityImpersonation); 509 if (!NT_SUCCESS(Status)) 510 { 511 ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status); 512 return Status; 513 } 514 } 515 516 /* 517 * Attempt to acquire the process primary token assignment privilege 518 * in case we actually need it. 519 * The call will either succeed or fail when the caller has (or has not) 520 * enough rights. 521 * The last situation may not be dramatic for us. Indeed it may happen 522 * that the user-provided token is a restricted version of the caller's 523 * primary token (aka. a "child" token), or both tokens inherit (i.e. are 524 * children, and are together "siblings") from a common parent token. 525 * In this case the NT kernel allows us to assign the token to the child 526 * process without the need for the assignment privilege, which is fine. 527 * On the contrary, if the user-provided token is completely arbitrary, 528 * then the NT kernel will enforce the presence of the assignment privilege: 529 * because we failed (by assumption) to assign the privilege, the process 530 * token assignment will fail as required. It is then the job of the 531 * caller to manually acquire the necessary privileges. 532 */ 533 Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 534 TRUE, TRUE, &PrivilegeSet); 535 HavePrivilege = NT_SUCCESS(Status); 536 if (!HavePrivilege) 537 { 538 ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, " 539 "attempting to continue without it...\n", Status); 540 } 541 542 /* 543 * Assign the duplicated token and thread 544 * handle to the structure so that we'll 545 * use it to assign the primary token 546 * to process. 547 */ 548 AccessToken.Token = DuplicatedTokenHandle; 549 AccessToken.Thread = ThreadHandle; 550 551 /* Set the new process token */ 552 Status = NtSetInformationProcess(ProcessHandle, 553 ProcessAccessToken, 554 (PVOID)&AccessToken, 555 sizeof(AccessToken)); 556 557 /* Restore the privilege */ 558 if (HavePrivilege) 559 { 560 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 561 PrivilegeSet, TRUE, &PrivilegeSet); 562 } 563 564 /* 565 * Check again if the caller wanted to impersonate 566 * as self. If that is the case we must revert this 567 * impersonation back. 568 */ 569 if (ImpersonateAsSelf) 570 { 571 RevertToSelf(); 572 } 573 574 /* 575 * Finally, check if we actually succeeded on assigning 576 * a primary token to the process. If we failed, oh well, 577 * asta la vista baby e arrivederci. The caller has to do 578 * a rinse and repeat approach. 579 */ 580 if (!NT_SUCCESS(Status)) 581 { 582 ERR("Failed to assign primary token to the process (Status 0x%08lx)\n", Status); 583 return Status; 584 } 585 586 return STATUS_SUCCESS; 587 } 588 589 /** 590 * @brief 591 * Internal function that serves as a helper for 592 * CreateProcessAsUserW/A routines on creating 593 * a process within the context of the logged in 594 * user. 595 * 596 * @param[in] hToken 597 * A handle to an access token that is associated 598 * with the logged in user. If the caller does not 599 * submit a token, the helper will immediately quit 600 * and return success, and the newly created process 601 * will be created upon using the default security 602 * context. 603 * 604 * @param[in] dwCreationFlags 605 * Bit masks containing the creation process flags. 606 * The function uses this parameter to determine 607 * if the process wasn't created in a suspended way 608 * and if not the function will resume the main thread. 609 * 610 * @param[in] lpProcessAttributes 611 * A pointer to process attributes. This function uses 612 * this parameter to gather the security descriptor, 613 * if ever present. If it is, this descriptor takes 614 * precedence over the default one when setting 615 * new security information to the process. 616 * 617 * @param[in] lpThreadAttributes 618 * A pointer to thread attributes. This function uses 619 * this parameter to gather the security descriptor, 620 * if ever present. If it is, this descriptor takes 621 * precedence over the default one when setting 622 * new security information to the thread. 623 * 624 * @param[in,out] lpProcessInformation 625 * A pointer to a structure that contains process creation 626 * information data. Such pointer contains the process 627 * and thread handles and whatnot. 628 * 629 * @return 630 * Returns TRUE if the helper has successfully assigned 631 * the newly created process the user's security context 632 * to that process, otherwise FALSE is returned. 633 * 634 * @remarks 635 * In order for the helper function to assign the primary 636 * token to the process, it has to do a "rinse and repeat" 637 * approach. That is, the helper will stop the impersonation 638 * and attempt to assign the token to process by acting 639 * on behalf of the main process' security context. If that 640 * fails, the function will do a second attempt by doing this 641 * but with impersonation enabled instead. 642 */ 643 static 644 BOOL 645 CreateProcessAsUserCommon( 646 _In_opt_ HANDLE hToken, 647 _In_ DWORD dwCreationFlags, 648 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 649 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 650 _Inout_ LPPROCESS_INFORMATION lpProcessInformation) 651 { 652 NTSTATUS Status = STATUS_SUCCESS, StatusOnExit; 653 BOOL Success; 654 TOKEN_TYPE Type; 655 ULONG ReturnLength; 656 OBJECT_ATTRIBUTES ObjectAttributes; 657 PSECURITY_DESCRIPTOR DefaultSd = NULL, ProcessSd, ThreadSd; 658 HANDLE hTokenDup = NULL; 659 HANDLE OriginalImpersonationToken = NULL; 660 HANDLE NullToken = NULL; 661 662 if (hToken != NULL) 663 { 664 /* Check whether the user-provided token is a primary token */ 665 // GetTokenInformation(); 666 Status = NtQueryInformationToken(hToken, 667 TokenType, 668 &Type, 669 sizeof(Type), 670 &ReturnLength); 671 if (!NT_SUCCESS(Status)) 672 { 673 ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status); 674 Success = FALSE; 675 goto Quit; 676 } 677 678 if (Type != TokenPrimary) 679 { 680 ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken, Type); 681 Status = STATUS_BAD_TOKEN_TYPE; 682 Success = FALSE; 683 goto Quit; 684 } 685 686 /* 687 * Open the original token of the calling thread 688 * and halt the impersonation for the moment 689 * being. The opened thread token will be cached 690 * so that we will restore it back when we're done. 691 */ 692 Status = NtOpenThreadToken(NtCurrentThread(), 693 TOKEN_QUERY | TOKEN_IMPERSONATE, 694 TRUE, 695 &OriginalImpersonationToken); 696 if (!NT_SUCCESS(Status)) 697 { 698 /* We failed? Does this thread have a token at least? */ 699 OriginalImpersonationToken = NULL; 700 if (Status != STATUS_NO_TOKEN) 701 { 702 /* 703 * OK so this thread has a token but we 704 * could not open it for whatever reason. 705 * Bail out then. 706 */ 707 ERR("Failed to open thread token with 0x%08lx\n", Status); 708 Success = FALSE; 709 goto Quit; 710 } 711 } 712 else 713 { 714 /* We succeeded, stop the impersonation for now */ 715 Status = NtSetInformationThread(NtCurrentThread(), 716 ThreadImpersonationToken, 717 &NullToken, 718 sizeof(NullToken)); 719 if (!NT_SUCCESS(Status)) 720 { 721 ERR("Failed to stop impersonation with 0x%08lx\n", Status); 722 Success = FALSE; 723 goto Quit; 724 } 725 } 726 727 /* 728 * Create a security descriptor that will be common for the 729 * newly created process on behalf of the context user. 730 */ 731 if (!CreateDefaultProcessSecurityCommon(hToken, &DefaultSd)) 732 { 733 ERR("Failed to create common security descriptor for the token for new process!\n"); 734 Success = FALSE; 735 goto Quit; 736 } 737 738 /* 739 * Duplicate the token for this new process. This token 740 * object will get a default security descriptor that we 741 * have created ourselves in ADVAPI32. 742 */ 743 InitializeObjectAttributes(&ObjectAttributes, 744 NULL, 745 0, 746 NULL, 747 DefaultSd); 748 Status = NtDuplicateToken(hToken, 749 0, 750 &ObjectAttributes, 751 FALSE, 752 TokenPrimary, 753 &hTokenDup); 754 if (!NT_SUCCESS(Status)) 755 { 756 ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status); 757 Success = FALSE; 758 goto Quit; 759 } 760 761 /* 762 * Now it's time to set the primary token into 763 * the process. On the first try, do it by 764 * impersonating the security context of the 765 * calling process (impersonate as self). 766 */ 767 Status = InsertTokenToProcessCommon(TRUE, 768 lpProcessInformation->hProcess, 769 lpProcessInformation->hThread, 770 hTokenDup); 771 if (!NT_SUCCESS(Status)) 772 { 773 /* 774 * OK, we failed. Our second (and last try) is to not 775 * impersonate as self but instead we will try by setting 776 * the original impersonation (thread) token and set the 777 * primary token to the process through this way. This is 778 * what we call -- the "rinse and repeat" approach. 779 */ 780 Status = NtSetInformationThread(NtCurrentThread(), 781 ThreadImpersonationToken, 782 &OriginalImpersonationToken, 783 sizeof(OriginalImpersonationToken)); 784 if (!NT_SUCCESS(Status)) 785 { 786 ERR("Failed to restore impersonation token for setting process token, Status 0x%08lx\n", Status); 787 NtClose(hTokenDup); 788 Success = FALSE; 789 goto Quit; 790 } 791 792 /* Retry again */ 793 Status = InsertTokenToProcessCommon(FALSE, 794 lpProcessInformation->hProcess, 795 lpProcessInformation->hThread, 796 hTokenDup); 797 if (!NT_SUCCESS(Status)) 798 { 799 /* Even the second try failed, bail out... */ 800 ERR("Failed to insert the primary token into process, Status 0x%08lx\n", Status); 801 NtClose(hTokenDup); 802 Success = FALSE; 803 goto Quit; 804 } 805 806 /* All good, now stop impersonation */ 807 Status = NtSetInformationThread(NtCurrentThread(), 808 ThreadImpersonationToken, 809 &NullToken, 810 sizeof(NullToken)); 811 if (!NT_SUCCESS(Status)) 812 { 813 ERR("Failed to unset impersonationg token after setting process token, Status 0x%08lx\n", Status); 814 NtClose(hTokenDup); 815 Success = FALSE; 816 goto Quit; 817 } 818 } 819 820 /* 821 * FIXME: As we have successfully set up a primary token to 822 * the newly created process, we must set up as well a definite 823 * limit of quota charges for this process on the context of 824 * this user. 825 */ 826 827 /* 828 * As we have successfully set the token into the process now 829 * it is time that we set up new security information for both 830 * the process and its thread as well, that is, these securable 831 * objects will grant a security descriptor. The security descriptors 832 * provided by the caller take precedence so we should use theirs 833 * if possible in this case. Otherwise both the process and thread 834 * will receive the default security descriptor that we have created 835 * ourselves. 836 * 837 * BEAR IN MIND!!! AT THE MOMENT when these securable objects get new 838 * security information, the process (and the thread) can't be opened 839 * by the creator anymore as the new owner will take in charge of 840 * the process and future objects that are going to be created within 841 * the process. For further information in regard of the documentation 842 * see https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw. 843 */ 844 if (lpProcessAttributes && lpProcessAttributes->lpSecurityDescriptor) 845 { 846 ProcessSd = lpProcessAttributes->lpSecurityDescriptor; 847 } 848 else 849 { 850 ProcessSd = DefaultSd; 851 } 852 853 if (lpThreadAttributes && lpThreadAttributes->lpSecurityDescriptor) 854 { 855 ThreadSd = lpThreadAttributes->lpSecurityDescriptor; 856 } 857 else 858 { 859 ThreadSd = DefaultSd; 860 } 861 862 /* Set new security info to the process and thread now */ 863 if (!InsertProcessSecurityCommon(lpProcessInformation->hProcess, 864 lpProcessInformation->hThread, 865 ProcessSd, 866 ThreadSd)) 867 { 868 ERR("Failed to set new security information for process and thread!\n"); 869 NtClose(hTokenDup); 870 Success = FALSE; 871 goto Quit; 872 } 873 874 /* Close the duplicated token */ 875 NtClose(hTokenDup); 876 Success = TRUE; 877 } 878 879 /* 880 * If the caller did not supply a token then just declare 881 * ourselves as job done. The newly created process will use 882 * the default security context at this point anyway. 883 */ 884 TRACE("No token supplied, the process will use default security context!\n"); 885 Success = TRUE; 886 887 Quit: 888 /* 889 * If we successfully opened the thread token before 890 * and stopped the impersonation then we have to assign 891 * its original token back and close that token we have 892 * referenced it. 893 */ 894 if (OriginalImpersonationToken != NULL) 895 { 896 StatusOnExit = NtSetInformationThread(NtCurrentThread(), 897 ThreadImpersonationToken, 898 &OriginalImpersonationToken, 899 sizeof(OriginalImpersonationToken)); 900 901 /* 902 * We really must assert ourselves that we successfully 903 * set the original token back, otherwise if we fail 904 * then something is seriously going wrong.... 905 * The status code is cached in a separate status 906 * variable because we would not want to tamper 907 * with the original status code that could have been 908 * returned by someone else above in this function code. 909 */ 910 ASSERT(NT_SUCCESS(StatusOnExit)); 911 912 /* De-reference it */ 913 NtClose(OriginalImpersonationToken); 914 } 915 916 /* Terminate the process and set the last error status */ 917 if (!NT_SUCCESS(Status)) 918 { 919 TerminateProcess(lpProcessInformation->hProcess, Status); 920 SetLastError(RtlNtStatusToDosError(Status)); 921 } 922 923 /* Resume the main thread */ 924 if (!(dwCreationFlags & CREATE_SUSPENDED)) 925 { 926 ResumeThread(lpProcessInformation->hThread); 927 } 928 929 /* Free the security descriptor from memory */ 930 if (DefaultSd != NULL) 931 { 932 RtlFreeHeap(RtlGetProcessHeap(), 0, DefaultSd); 933 } 934 935 return Success; 936 } 937 938 939 /* 940 * @implemented 941 */ 942 BOOL 943 WINAPI 944 DECLSPEC_HOTPATCH 945 CreateProcessAsUserA( 946 _In_opt_ HANDLE hToken, 947 _In_opt_ LPCSTR lpApplicationName, 948 _Inout_opt_ LPSTR lpCommandLine, 949 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 950 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 951 _In_ BOOL bInheritHandles, 952 _In_ DWORD dwCreationFlags, 953 _In_opt_ LPVOID lpEnvironment, 954 _In_opt_ LPCSTR lpCurrentDirectory, 955 _In_ LPSTARTUPINFOA lpStartupInfo, 956 _Out_ LPPROCESS_INFORMATION lpProcessInformation) 957 { 958 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_a(lpApplicationName), 959 debugstr_a(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles, 960 dwCreationFlags, lpEnvironment, debugstr_a(lpCurrentDirectory), lpStartupInfo, lpProcessInformation); 961 962 /* Create the process with a suspended main thread */ 963 if (!CreateProcessA(lpApplicationName, 964 lpCommandLine, 965 lpProcessAttributes, 966 lpThreadAttributes, 967 bInheritHandles, 968 dwCreationFlags | CREATE_SUSPENDED, 969 lpEnvironment, 970 lpCurrentDirectory, 971 lpStartupInfo, 972 lpProcessInformation)) 973 { 974 ERR("CreateProcessA failed, last error: %d\n", GetLastError()); 975 return FALSE; 976 } 977 978 /* Call the helper function */ 979 return CreateProcessAsUserCommon(hToken, 980 dwCreationFlags, 981 lpProcessAttributes, 982 lpThreadAttributes, 983 lpProcessInformation); 984 } 985 986 987 /* 988 * @implemented 989 */ 990 BOOL 991 WINAPI 992 DECLSPEC_HOTPATCH 993 CreateProcessAsUserW( 994 _In_opt_ HANDLE hToken, 995 _In_opt_ LPCWSTR lpApplicationName, 996 _Inout_opt_ LPWSTR lpCommandLine, 997 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 998 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 999 _In_ BOOL bInheritHandles, 1000 _In_ DWORD dwCreationFlags, 1001 _In_opt_ LPVOID lpEnvironment, 1002 _In_opt_ LPCWSTR lpCurrentDirectory, 1003 _In_ LPSTARTUPINFOW lpStartupInfo, 1004 _Out_ LPPROCESS_INFORMATION lpProcessInformation) 1005 { 1006 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_w(lpApplicationName), 1007 debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles, 1008 dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory), lpStartupInfo, lpProcessInformation); 1009 1010 /* Create the process with a suspended main thread */ 1011 if (!CreateProcessW(lpApplicationName, 1012 lpCommandLine, 1013 lpProcessAttributes, 1014 lpThreadAttributes, 1015 bInheritHandles, 1016 dwCreationFlags | CREATE_SUSPENDED, 1017 lpEnvironment, 1018 lpCurrentDirectory, 1019 lpStartupInfo, 1020 lpProcessInformation)) 1021 { 1022 ERR("CreateProcessW failed, last error: %d\n", GetLastError()); 1023 return FALSE; 1024 } 1025 1026 /* Call the helper function */ 1027 return CreateProcessAsUserCommon(hToken, 1028 dwCreationFlags, 1029 lpProcessAttributes, 1030 lpThreadAttributes, 1031 lpProcessInformation); 1032 } 1033 1034 1035 /* 1036 * @implemented 1037 */ 1038 BOOL 1039 WINAPI 1040 LogonUserA( 1041 _In_ LPSTR lpszUsername, 1042 _In_opt_ LPSTR lpszDomain, 1043 _In_opt_ LPSTR lpszPassword, 1044 _In_ DWORD dwLogonType, 1045 _In_ DWORD dwLogonProvider, 1046 _Out_opt_ PHANDLE phToken) 1047 { 1048 return LogonUserExA(lpszUsername, 1049 lpszDomain, 1050 lpszPassword, 1051 dwLogonType, 1052 dwLogonProvider, 1053 phToken, 1054 NULL, 1055 NULL, 1056 NULL, 1057 NULL); 1058 } 1059 1060 1061 /* 1062 * @implemented 1063 */ 1064 BOOL 1065 WINAPI 1066 LogonUserExA( 1067 _In_ LPSTR lpszUsername, 1068 _In_opt_ LPSTR lpszDomain, 1069 _In_opt_ LPSTR lpszPassword, 1070 _In_ DWORD dwLogonType, 1071 _In_ DWORD dwLogonProvider, 1072 _Out_opt_ PHANDLE phToken, 1073 _Out_opt_ PSID *ppLogonSid, 1074 _Out_opt_ PVOID *ppProfileBuffer, 1075 _Out_opt_ LPDWORD pdwProfileLength, 1076 _Out_opt_ PQUOTA_LIMITS pQuotaLimits) 1077 { 1078 UNICODE_STRING UserName; 1079 UNICODE_STRING Domain; 1080 UNICODE_STRING Password; 1081 BOOL ret = FALSE; 1082 1083 UserName.Buffer = NULL; 1084 Domain.Buffer = NULL; 1085 Password.Buffer = NULL; 1086 1087 if (!RtlCreateUnicodeStringFromAsciiz(&UserName, lpszUsername)) 1088 { 1089 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1090 goto UsernameDone; 1091 } 1092 1093 if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain)) 1094 { 1095 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1096 goto DomainDone; 1097 } 1098 1099 if (!RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword)) 1100 { 1101 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1102 goto PasswordDone; 1103 } 1104 1105 ret = LogonUserExW(UserName.Buffer, 1106 Domain.Buffer, 1107 Password.Buffer, 1108 dwLogonType, 1109 dwLogonProvider, 1110 phToken, 1111 ppLogonSid, 1112 ppProfileBuffer, 1113 pdwProfileLength, 1114 pQuotaLimits); 1115 1116 if (Password.Buffer != NULL) 1117 RtlFreeUnicodeString(&Password); 1118 1119 PasswordDone: 1120 if (Domain.Buffer != NULL) 1121 RtlFreeUnicodeString(&Domain); 1122 1123 DomainDone: 1124 if (UserName.Buffer != NULL) 1125 RtlFreeUnicodeString(&UserName); 1126 1127 UsernameDone: 1128 return ret; 1129 } 1130 1131 1132 /* 1133 * @implemented 1134 */ 1135 BOOL 1136 WINAPI 1137 LogonUserW( 1138 _In_ LPWSTR lpszUsername, 1139 _In_opt_ LPWSTR lpszDomain, 1140 _In_opt_ LPWSTR lpszPassword, 1141 _In_ DWORD dwLogonType, 1142 _In_ DWORD dwLogonProvider, 1143 _Out_opt_ PHANDLE phToken) 1144 { 1145 return LogonUserExW(lpszUsername, 1146 lpszDomain, 1147 lpszPassword, 1148 dwLogonType, 1149 dwLogonProvider, 1150 phToken, 1151 NULL, 1152 NULL, 1153 NULL, 1154 NULL); 1155 } 1156 1157 1158 /* 1159 * @implemented 1160 */ 1161 BOOL 1162 WINAPI 1163 LogonUserExW( 1164 _In_ LPWSTR lpszUsername, 1165 _In_opt_ LPWSTR lpszDomain, 1166 _In_opt_ LPWSTR lpszPassword, 1167 _In_ DWORD dwLogonType, 1168 _In_ DWORD dwLogonProvider, 1169 _Out_opt_ PHANDLE phToken, 1170 _Out_opt_ PSID *ppLogonSid, 1171 _Out_opt_ PVOID *ppProfileBuffer, 1172 _Out_opt_ LPDWORD pdwProfileLength, 1173 _Out_opt_ PQUOTA_LIMITS pQuotaLimits) 1174 { 1175 SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY}; 1176 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; 1177 PSID LogonSid = NULL; 1178 PSID LocalSid = NULL; 1179 LSA_STRING OriginName; 1180 UNICODE_STRING DomainName; 1181 UNICODE_STRING UserName; 1182 UNICODE_STRING Password; 1183 PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL; 1184 ULONG AuthInfoLength; 1185 ULONG_PTR Ptr; 1186 TOKEN_SOURCE TokenSource; 1187 PTOKEN_GROUPS TokenGroups = NULL; 1188 PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL; 1189 ULONG ProfileBufferLength = 0; 1190 LUID Luid = {0, 0}; 1191 LUID LogonId = {0, 0}; 1192 HANDLE TokenHandle = NULL; 1193 QUOTA_LIMITS QuotaLimits; 1194 SECURITY_LOGON_TYPE LogonType; 1195 NTSTATUS SubStatus = STATUS_SUCCESS; 1196 NTSTATUS Status; 1197 1198 if ((ppProfileBuffer != NULL && pdwProfileLength == NULL) || 1199 (ppProfileBuffer == NULL && pdwProfileLength != NULL)) 1200 { 1201 SetLastError(ERROR_INVALID_PARAMETER); 1202 return FALSE; 1203 } 1204 1205 if (ppProfileBuffer != NULL && pdwProfileLength != NULL) 1206 { 1207 *ppProfileBuffer = NULL; 1208 *pdwProfileLength = 0; 1209 } 1210 1211 if (phToken != NULL) 1212 *phToken = NULL; 1213 1214 switch (dwLogonType) 1215 { 1216 case LOGON32_LOGON_INTERACTIVE: 1217 LogonType = Interactive; 1218 break; 1219 1220 case LOGON32_LOGON_NETWORK: 1221 LogonType = Network; 1222 break; 1223 1224 case LOGON32_LOGON_BATCH: 1225 LogonType = Batch; 1226 break; 1227 1228 case LOGON32_LOGON_SERVICE: 1229 LogonType = Service; 1230 break; 1231 1232 default: 1233 ERR("Invalid logon type: %ul\n", dwLogonType); 1234 Status = STATUS_INVALID_PARAMETER; 1235 goto done; 1236 } 1237 1238 if (LsaHandle == NULL) 1239 { 1240 Status = OpenLogonLsaHandle(); 1241 if (!NT_SUCCESS(Status)) 1242 goto done; 1243 } 1244 1245 RtlInitAnsiString((PANSI_STRING)&OriginName, 1246 "Advapi32 Logon"); 1247 1248 RtlInitUnicodeString(&DomainName, 1249 lpszDomain); 1250 1251 RtlInitUnicodeString(&UserName, 1252 lpszUsername); 1253 1254 RtlInitUnicodeString(&Password, 1255 lpszPassword); 1256 1257 AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+ 1258 DomainName.MaximumLength + 1259 UserName.MaximumLength + 1260 Password.MaximumLength; 1261 1262 AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(), 1263 HEAP_ZERO_MEMORY, 1264 AuthInfoLength); 1265 if (AuthInfo == NULL) 1266 { 1267 Status = STATUS_INSUFFICIENT_RESOURCES; 1268 goto done; 1269 } 1270 1271 AuthInfo->MessageType = MsV1_0InteractiveLogon; 1272 1273 Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON); 1274 1275 AuthInfo->LogonDomainName.Length = DomainName.Length; 1276 AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength; 1277 AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr; 1278 if (DomainName.MaximumLength > 0) 1279 { 1280 RtlCopyMemory(AuthInfo->LogonDomainName.Buffer, 1281 DomainName.Buffer, 1282 DomainName.MaximumLength); 1283 1284 Ptr += DomainName.MaximumLength; 1285 } 1286 1287 AuthInfo->UserName.Length = UserName.Length; 1288 AuthInfo->UserName.MaximumLength = UserName.MaximumLength; 1289 AuthInfo->UserName.Buffer = (PWCHAR)Ptr; 1290 if (UserName.MaximumLength > 0) 1291 RtlCopyMemory(AuthInfo->UserName.Buffer, 1292 UserName.Buffer, 1293 UserName.MaximumLength); 1294 1295 Ptr += UserName.MaximumLength; 1296 1297 AuthInfo->Password.Length = Password.Length; 1298 AuthInfo->Password.MaximumLength = Password.MaximumLength; 1299 AuthInfo->Password.Buffer = (PWCHAR)Ptr; 1300 if (Password.MaximumLength > 0) 1301 RtlCopyMemory(AuthInfo->Password.Buffer, 1302 Password.Buffer, 1303 Password.MaximumLength); 1304 1305 /* Create the Logon SID */ 1306 AllocateLocallyUniqueId(&LogonId); 1307 Status = RtlAllocateAndInitializeSid(&SystemAuthority, 1308 SECURITY_LOGON_IDS_RID_COUNT, 1309 SECURITY_LOGON_IDS_RID, 1310 LogonId.HighPart, 1311 LogonId.LowPart, 1312 SECURITY_NULL_RID, 1313 SECURITY_NULL_RID, 1314 SECURITY_NULL_RID, 1315 SECURITY_NULL_RID, 1316 SECURITY_NULL_RID, 1317 &LogonSid); 1318 if (!NT_SUCCESS(Status)) 1319 goto done; 1320 1321 /* Create the Local SID */ 1322 Status = RtlAllocateAndInitializeSid(&LocalAuthority, 1323 1, 1324 SECURITY_LOCAL_RID, 1325 SECURITY_NULL_RID, 1326 SECURITY_NULL_RID, 1327 SECURITY_NULL_RID, 1328 SECURITY_NULL_RID, 1329 SECURITY_NULL_RID, 1330 SECURITY_NULL_RID, 1331 SECURITY_NULL_RID, 1332 &LocalSid); 1333 if (!NT_SUCCESS(Status)) 1334 goto done; 1335 1336 /* Allocate and set the token groups */ 1337 TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(), 1338 HEAP_ZERO_MEMORY, 1339 sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES))); 1340 if (TokenGroups == NULL) 1341 { 1342 Status = STATUS_INSUFFICIENT_RESOURCES; 1343 goto done; 1344 } 1345 1346 TokenGroups->GroupCount = 2; 1347 TokenGroups->Groups[0].Sid = LogonSid; 1348 TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | 1349 SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID; 1350 TokenGroups->Groups[1].Sid = LocalSid; 1351 TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | 1352 SE_GROUP_ENABLED_BY_DEFAULT; 1353 1354 /* Set the token source */ 1355 RtlCopyMemory(TokenSource.SourceName, 1356 AdvapiTokenSourceName, 1357 sizeof(TokenSource.SourceName)); 1358 AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); 1359 1360 Status = LsaLogonUser(LsaHandle, 1361 &OriginName, 1362 LogonType, 1363 AuthenticationPackage, 1364 (PVOID)AuthInfo, 1365 AuthInfoLength, 1366 TokenGroups, 1367 &TokenSource, 1368 (PVOID*)&ProfileBuffer, 1369 &ProfileBufferLength, 1370 &Luid, 1371 &TokenHandle, 1372 &QuotaLimits, 1373 &SubStatus); 1374 if (!NT_SUCCESS(Status)) 1375 { 1376 ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status); 1377 goto done; 1378 } 1379 1380 if (ProfileBuffer != NULL) 1381 { 1382 TRACE("ProfileBuffer: %p\n", ProfileBuffer); 1383 TRACE("MessageType: %u\n", ProfileBuffer->MessageType); 1384 1385 TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer); 1386 TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer); 1387 1388 TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer); 1389 TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer); 1390 } 1391 1392 TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart); 1393 1394 if (TokenHandle != NULL) 1395 { 1396 TRACE("TokenHandle: %p\n", TokenHandle); 1397 } 1398 1399 if (phToken != NULL) 1400 *phToken = TokenHandle; 1401 1402 /* FIXME: return ppLogonSid and pQuotaLimits */ 1403 1404 done: 1405 if (ProfileBuffer != NULL) 1406 LsaFreeReturnBuffer(ProfileBuffer); 1407 1408 if (!NT_SUCCESS(Status)) 1409 { 1410 if (TokenHandle != NULL) 1411 CloseHandle(TokenHandle); 1412 } 1413 1414 if (TokenGroups != NULL) 1415 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups); 1416 1417 if (LocalSid != NULL) 1418 RtlFreeSid(LocalSid); 1419 1420 if (LogonSid != NULL) 1421 RtlFreeSid(LogonSid); 1422 1423 if (AuthInfo != NULL) 1424 RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo); 1425 1426 if (!NT_SUCCESS(Status)) 1427 { 1428 SetLastError(RtlNtStatusToDosError(Status)); 1429 return FALSE; 1430 } 1431 1432 return TRUE; 1433 } 1434 1435 /* EOF */ 1436