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
OpenLogonLsaHandle(VOID)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
CloseLogonLsaHandle(VOID)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
CreateDefaultProcessSecurityCommon(_In_ HANDLE TokenHandle,_Out_ PSECURITY_DESCRIPTOR * Sd)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
InsertProcessSecurityCommon(_In_ HANDLE ProcessHandle,_In_ HANDLE ThreadHandle,_In_ PSECURITY_DESCRIPTOR ProcessSecurity,_In_ PSECURITY_DESCRIPTOR ThreadSecurity)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
InsertTokenToProcessCommon(_In_ BOOL ImpersonateAsSelf,_In_ HANDLE ProcessHandle,_In_ HANDLE ThreadHandle,_In_ HANDLE DuplicatedTokenHandle)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
CreateProcessAsUserCommon(_In_opt_ HANDLE hToken,_In_ DWORD dwCreationFlags,_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_Inout_ LPPROCESS_INFORMATION lpProcessInformation)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
CreateProcessAsUserA(_In_opt_ HANDLE hToken,_In_opt_ LPCSTR lpApplicationName,_Inout_opt_ LPSTR lpCommandLine,_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_ BOOL bInheritHandles,_In_ DWORD dwCreationFlags,_In_opt_ LPVOID lpEnvironment,_In_opt_ LPCSTR lpCurrentDirectory,_In_ LPSTARTUPINFOA lpStartupInfo,_Out_ LPPROCESS_INFORMATION lpProcessInformation)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
CreateProcessAsUserW(_In_opt_ HANDLE hToken,_In_opt_ LPCWSTR lpApplicationName,_Inout_opt_ LPWSTR lpCommandLine,_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_ BOOL bInheritHandles,_In_ DWORD dwCreationFlags,_In_opt_ LPVOID lpEnvironment,_In_opt_ LPCWSTR lpCurrentDirectory,_In_ LPSTARTUPINFOW lpStartupInfo,_Out_ LPPROCESS_INFORMATION lpProcessInformation)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
LogonUserA(_In_ LPSTR lpszUsername,_In_opt_ LPSTR lpszDomain,_In_opt_ LPSTR lpszPassword,_In_ DWORD dwLogonType,_In_ DWORD dwLogonProvider,_Out_opt_ PHANDLE phToken)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
LogonUserExA(_In_ LPSTR lpszUsername,_In_opt_ LPSTR lpszDomain,_In_opt_ LPSTR lpszPassword,_In_ DWORD dwLogonType,_In_ DWORD dwLogonProvider,_Out_opt_ PHANDLE phToken,_Out_opt_ PSID * ppLogonSid,_Out_opt_ PVOID * ppProfileBuffer,_Out_opt_ LPDWORD pdwProfileLength,_Out_opt_ PQUOTA_LIMITS pQuotaLimits)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
LogonUserW(_In_ LPWSTR lpszUsername,_In_opt_ LPWSTR lpszDomain,_In_opt_ LPWSTR lpszPassword,_In_ DWORD dwLogonType,_In_ DWORD dwLogonProvider,_Out_opt_ PHANDLE phToken)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
LogonUserExW(_In_ LPWSTR lpszUsername,_In_opt_ LPWSTR lpszDomain,_In_opt_ LPWSTR lpszPassword,_In_ DWORD dwLogonType,_In_ DWORD dwLogonProvider,_Out_opt_ PHANDLE phToken,_Out_opt_ PSID * ppLogonSid,_Out_opt_ PVOID * ppProfileBuffer,_Out_opt_ LPDWORD pdwProfileLength,_Out_opt_ PQUOTA_LIMITS pQuotaLimits)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