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
10 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
12 /* GLOBALS *****************************************************************/
14 static const CHAR AdvapiTokenSourceName
[] = "Advapi ";
15 C_ASSERT(sizeof(AdvapiTokenSourceName
) == RTL_FIELD_SIZE(TOKEN_SOURCE
, SourceName
) + 1);
17 HANDLE LsaHandle
= NULL
;
18 ULONG AuthenticationPackage
= 0;
20 /* FUNCTIONS ***************************************************************/
24 OpenLogonLsaHandle(VOID
)
26 LSA_STRING LogonProcessName
;
27 LSA_STRING PackageName
;
28 LSA_OPERATIONAL_MODE SecurityMode
= 0;
31 RtlInitAnsiString((PANSI_STRING
)&LogonProcessName
,
32 "User32LogonProcess");
34 Status
= LsaRegisterLogonProcess(&LogonProcessName
,
37 if (!NT_SUCCESS(Status
))
39 TRACE("LsaRegisterLogonProcess failed (Status 0x%08lx)\n", Status
);
43 RtlInitAnsiString((PANSI_STRING
)&PackageName
,
46 Status
= LsaLookupAuthenticationPackage(LsaHandle
,
48 &AuthenticationPackage
);
49 if (!NT_SUCCESS(Status
))
51 TRACE("LsaLookupAuthenticationPackage failed (Status 0x%08lx)\n", Status
);
55 TRACE("AuthenticationPackage: 0x%08lx\n", AuthenticationPackage
);
58 if (!NT_SUCCESS(Status
))
60 if (LsaHandle
!= NULL
)
62 Status
= LsaDeregisterLogonProcess(LsaHandle
);
63 if (!NT_SUCCESS(Status
))
65 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status
);
75 CloseLogonLsaHandle(VOID
)
77 NTSTATUS Status
= STATUS_SUCCESS
;
79 if (LsaHandle
!= NULL
)
81 Status
= LsaDeregisterLogonProcess(LsaHandle
);
82 if (!NT_SUCCESS(Status
))
84 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status
);
94 CreateProcessAsUserCommon(
95 _In_opt_ HANDLE hToken
,
96 _In_ DWORD dwCreationFlags
,
97 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
100 PROCESS_ACCESS_TOKEN AccessToken
;
106 OBJECT_ATTRIBUTES ObjectAttributes
;
108 BOOLEAN PrivilegeSet
= FALSE
, HavePrivilege
;
110 /* Check whether the user-provided token is a primary token */
111 // GetTokenInformation();
112 Status
= NtQueryInformationToken(hToken
,
117 if (!NT_SUCCESS(Status
))
119 ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status
);
122 if (Type
!= TokenPrimary
)
124 ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken
, Type
);
125 Status
= STATUS_BAD_TOKEN_TYPE
;
129 /* Duplicate the token for this new process */
130 InitializeObjectAttributes(&ObjectAttributes
,
134 NULL
); // FIXME: Use a valid SecurityDescriptor!
135 Status
= NtDuplicateToken(hToken
,
141 if (!NT_SUCCESS(Status
))
143 ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status
);
147 // FIXME: Do we always need SecurityImpersonation?
148 Status
= RtlImpersonateSelf(SecurityImpersonation
);
149 if (!NT_SUCCESS(Status
))
151 ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status
);
157 * Attempt to acquire the process primary token assignment privilege
158 * in case we actually need it.
159 * The call will either succeed or fail when the caller has (or has not)
161 * The last situation may not be dramatic for us. Indeed it may happen
162 * that the user-provided token is a restricted version of the caller's
163 * primary token (aka. a "child" token), or both tokens inherit (i.e. are
164 * children, and are together "siblings") from a common parent token.
165 * In this case the NT kernel allows us to assign the token to the child
166 * process without the need for the assignment privilege, which is fine.
167 * On the contrary, if the user-provided token is completely arbitrary,
168 * then the NT kernel will enforce the presence of the assignment privilege:
169 * because we failed (by assumption) to assign the privilege, the process
170 * token assignment will fail as required. It is then the job of the
171 * caller to manually acquire the necessary privileges.
173 Status
= RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
,
174 TRUE
, TRUE
, &PrivilegeSet
);
175 HavePrivilege
= NT_SUCCESS(Status
);
178 ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, "
179 "attempting to continue without it...\n", Status
);
182 AccessToken
.Token
= hTokenDup
;
183 AccessToken
.Thread
= lpProcessInformation
->hThread
;
185 /* Set the new process token */
186 Status
= NtSetInformationProcess(lpProcessInformation
->hProcess
,
189 sizeof(AccessToken
));
191 /* Restore the privilege */
194 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
,
195 PrivilegeSet
, TRUE
, &PrivilegeSet
);
200 /* Close the duplicated token */
203 /* Check whether NtSetInformationProcess() failed */
204 if (!NT_SUCCESS(Status
))
206 ERR("NtSetInformationProcess() failed, Status 0x%08x\n", Status
);
210 if (!NT_SUCCESS(Status
))
213 TerminateProcess(lpProcessInformation
->hProcess
, Status
);
214 SetLastError(RtlNtStatusToDosError(Status
));
219 /* Resume the main thread */
220 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
222 ResumeThread(lpProcessInformation
->hThread
);
235 CreateProcessAsUserA(
236 _In_opt_ HANDLE hToken
,
237 _In_opt_ LPCSTR lpApplicationName
,
238 _Inout_opt_ LPSTR lpCommandLine
,
239 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes
,
240 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes
,
241 _In_ BOOL bInheritHandles
,
242 _In_ DWORD dwCreationFlags
,
243 _In_opt_ LPVOID lpEnvironment
,
244 _In_opt_ LPCSTR lpCurrentDirectory
,
245 _In_ LPSTARTUPINFOA lpStartupInfo
,
246 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
248 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken
, debugstr_a(lpApplicationName
),
249 debugstr_a(lpCommandLine
), lpProcessAttributes
, lpThreadAttributes
, bInheritHandles
,
250 dwCreationFlags
, lpEnvironment
, debugstr_a(lpCurrentDirectory
), lpStartupInfo
, lpProcessInformation
);
252 /* Create the process with a suspended main thread */
253 if (!CreateProcessA(lpApplicationName
,
258 dwCreationFlags
| CREATE_SUSPENDED
,
262 lpProcessInformation
))
264 ERR("CreateProcessA failed, last error: %d\n", GetLastError());
268 /* Call the helper function */
269 return CreateProcessAsUserCommon(hToken
,
271 lpProcessInformation
);
281 CreateProcessAsUserW(
282 _In_opt_ HANDLE hToken
,
283 _In_opt_ LPCWSTR lpApplicationName
,
284 _Inout_opt_ LPWSTR lpCommandLine
,
285 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes
,
286 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes
,
287 _In_ BOOL bInheritHandles
,
288 _In_ DWORD dwCreationFlags
,
289 _In_opt_ LPVOID lpEnvironment
,
290 _In_opt_ LPCWSTR lpCurrentDirectory
,
291 _In_ LPSTARTUPINFOW lpStartupInfo
,
292 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
294 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken
, debugstr_w(lpApplicationName
),
295 debugstr_w(lpCommandLine
), lpProcessAttributes
, lpThreadAttributes
, bInheritHandles
,
296 dwCreationFlags
, lpEnvironment
, debugstr_w(lpCurrentDirectory
), lpStartupInfo
, lpProcessInformation
);
298 /* Create the process with a suspended main thread */
299 if (!CreateProcessW(lpApplicationName
,
304 dwCreationFlags
| CREATE_SUSPENDED
,
308 lpProcessInformation
))
310 ERR("CreateProcessW failed, last error: %d\n", GetLastError());
314 /* Call the helper function */
315 return CreateProcessAsUserCommon(hToken
,
317 lpProcessInformation
);
327 _In_ LPSTR lpszUsername
,
328 _In_opt_ LPSTR lpszDomain
,
329 _In_opt_ LPSTR lpszPassword
,
330 _In_ DWORD dwLogonType
,
331 _In_ DWORD dwLogonProvider
,
332 _Out_opt_ PHANDLE phToken
)
334 return LogonUserExA(lpszUsername
,
353 _In_ LPSTR lpszUsername
,
354 _In_opt_ LPSTR lpszDomain
,
355 _In_opt_ LPSTR lpszPassword
,
356 _In_ DWORD dwLogonType
,
357 _In_ DWORD dwLogonProvider
,
358 _Out_opt_ PHANDLE phToken
,
359 _Out_opt_ PSID
*ppLogonSid
,
360 _Out_opt_ PVOID
*ppProfileBuffer
,
361 _Out_opt_ LPDWORD pdwProfileLength
,
362 _Out_opt_ PQUOTA_LIMITS pQuotaLimits
)
364 UNICODE_STRING UserName
;
365 UNICODE_STRING Domain
;
366 UNICODE_STRING Password
;
369 UserName
.Buffer
= NULL
;
370 Domain
.Buffer
= NULL
;
371 Password
.Buffer
= NULL
;
373 if (!RtlCreateUnicodeStringFromAsciiz(&UserName
, lpszUsername
))
375 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
379 if (!RtlCreateUnicodeStringFromAsciiz(&Domain
, lpszDomain
))
381 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
385 if (!RtlCreateUnicodeStringFromAsciiz(&Password
, lpszPassword
))
387 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
391 ret
= LogonUserExW(UserName
.Buffer
,
402 if (Password
.Buffer
!= NULL
)
403 RtlFreeUnicodeString(&Password
);
406 if (Domain
.Buffer
!= NULL
)
407 RtlFreeUnicodeString(&Domain
);
410 if (UserName
.Buffer
!= NULL
)
411 RtlFreeUnicodeString(&UserName
);
424 _In_ LPWSTR lpszUsername
,
425 _In_opt_ LPWSTR lpszDomain
,
426 _In_opt_ LPWSTR lpszPassword
,
427 _In_ DWORD dwLogonType
,
428 _In_ DWORD dwLogonProvider
,
429 _Out_opt_ PHANDLE phToken
)
431 return LogonUserExW(lpszUsername
,
450 _In_ LPWSTR lpszUsername
,
451 _In_opt_ LPWSTR lpszDomain
,
452 _In_opt_ LPWSTR lpszPassword
,
453 _In_ DWORD dwLogonType
,
454 _In_ DWORD dwLogonProvider
,
455 _Out_opt_ PHANDLE phToken
,
456 _Out_opt_ PSID
*ppLogonSid
,
457 _Out_opt_ PVOID
*ppProfileBuffer
,
458 _Out_opt_ LPDWORD pdwProfileLength
,
459 _Out_opt_ PQUOTA_LIMITS pQuotaLimits
)
461 SID_IDENTIFIER_AUTHORITY LocalAuthority
= {SECURITY_LOCAL_SID_AUTHORITY
};
462 SID_IDENTIFIER_AUTHORITY SystemAuthority
= {SECURITY_NT_AUTHORITY
};
463 PSID LogonSid
= NULL
;
464 PSID LocalSid
= NULL
;
465 LSA_STRING OriginName
;
466 UNICODE_STRING DomainName
;
467 UNICODE_STRING UserName
;
468 UNICODE_STRING Password
;
469 PMSV1_0_INTERACTIVE_LOGON AuthInfo
= NULL
;
470 ULONG AuthInfoLength
;
472 TOKEN_SOURCE TokenSource
;
473 PTOKEN_GROUPS TokenGroups
= NULL
;
474 PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer
= NULL
;
475 ULONG ProfileBufferLength
= 0;
477 LUID LogonId
= {0, 0};
478 HANDLE TokenHandle
= NULL
;
479 QUOTA_LIMITS QuotaLimits
;
480 SECURITY_LOGON_TYPE LogonType
;
481 NTSTATUS SubStatus
= STATUS_SUCCESS
;
484 if ((ppProfileBuffer
!= NULL
&& pdwProfileLength
== NULL
) ||
485 (ppProfileBuffer
== NULL
&& pdwProfileLength
!= NULL
))
487 SetLastError(ERROR_INVALID_PARAMETER
);
491 if (ppProfileBuffer
!= NULL
&& pdwProfileLength
!= NULL
)
493 *ppProfileBuffer
= NULL
;
494 *pdwProfileLength
= 0;
502 case LOGON32_LOGON_INTERACTIVE
:
503 LogonType
= Interactive
;
506 case LOGON32_LOGON_NETWORK
:
510 case LOGON32_LOGON_BATCH
:
514 case LOGON32_LOGON_SERVICE
:
519 ERR("Invalid logon type: %ul\n", dwLogonType
);
520 Status
= STATUS_INVALID_PARAMETER
;
524 if (LsaHandle
== NULL
)
526 Status
= OpenLogonLsaHandle();
527 if (!NT_SUCCESS(Status
))
531 RtlInitAnsiString((PANSI_STRING
)&OriginName
,
534 RtlInitUnicodeString(&DomainName
,
537 RtlInitUnicodeString(&UserName
,
540 RtlInitUnicodeString(&Password
,
543 AuthInfoLength
= sizeof(MSV1_0_INTERACTIVE_LOGON
)+
544 DomainName
.MaximumLength
+
545 UserName
.MaximumLength
+
546 Password
.MaximumLength
;
548 AuthInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
551 if (AuthInfo
== NULL
)
553 Status
= STATUS_INSUFFICIENT_RESOURCES
;
557 AuthInfo
->MessageType
= MsV1_0InteractiveLogon
;
559 Ptr
= (ULONG_PTR
)AuthInfo
+ sizeof(MSV1_0_INTERACTIVE_LOGON
);
561 AuthInfo
->LogonDomainName
.Length
= DomainName
.Length
;
562 AuthInfo
->LogonDomainName
.MaximumLength
= DomainName
.MaximumLength
;
563 AuthInfo
->LogonDomainName
.Buffer
= (DomainName
.Buffer
== NULL
) ? NULL
: (PWCHAR
)Ptr
;
564 if (DomainName
.MaximumLength
> 0)
566 RtlCopyMemory(AuthInfo
->LogonDomainName
.Buffer
,
568 DomainName
.MaximumLength
);
570 Ptr
+= DomainName
.MaximumLength
;
573 AuthInfo
->UserName
.Length
= UserName
.Length
;
574 AuthInfo
->UserName
.MaximumLength
= UserName
.MaximumLength
;
575 AuthInfo
->UserName
.Buffer
= (PWCHAR
)Ptr
;
576 if (UserName
.MaximumLength
> 0)
577 RtlCopyMemory(AuthInfo
->UserName
.Buffer
,
579 UserName
.MaximumLength
);
581 Ptr
+= UserName
.MaximumLength
;
583 AuthInfo
->Password
.Length
= Password
.Length
;
584 AuthInfo
->Password
.MaximumLength
= Password
.MaximumLength
;
585 AuthInfo
->Password
.Buffer
= (PWCHAR
)Ptr
;
586 if (Password
.MaximumLength
> 0)
587 RtlCopyMemory(AuthInfo
->Password
.Buffer
,
589 Password
.MaximumLength
);
591 /* Create the Logon SID */
592 AllocateLocallyUniqueId(&LogonId
);
593 Status
= RtlAllocateAndInitializeSid(&SystemAuthority
,
594 SECURITY_LOGON_IDS_RID_COUNT
,
595 SECURITY_LOGON_IDS_RID
,
604 if (!NT_SUCCESS(Status
))
607 /* Create the Local SID */
608 Status
= RtlAllocateAndInitializeSid(&LocalAuthority
,
619 if (!NT_SUCCESS(Status
))
622 /* Allocate and set the token groups */
623 TokenGroups
= RtlAllocateHeap(RtlGetProcessHeap(),
625 sizeof(TOKEN_GROUPS
) + ((2 - ANYSIZE_ARRAY
) * sizeof(SID_AND_ATTRIBUTES
)));
626 if (TokenGroups
== NULL
)
628 Status
= STATUS_INSUFFICIENT_RESOURCES
;
632 TokenGroups
->GroupCount
= 2;
633 TokenGroups
->Groups
[0].Sid
= LogonSid
;
634 TokenGroups
->Groups
[0].Attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED
|
635 SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_LOGON_ID
;
636 TokenGroups
->Groups
[1].Sid
= LocalSid
;
637 TokenGroups
->Groups
[1].Attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED
|
638 SE_GROUP_ENABLED_BY_DEFAULT
;
640 /* Set the token source */
641 RtlCopyMemory(TokenSource
.SourceName
,
642 AdvapiTokenSourceName
,
643 sizeof(TokenSource
.SourceName
));
644 AllocateLocallyUniqueId(&TokenSource
.SourceIdentifier
);
646 Status
= LsaLogonUser(LsaHandle
,
649 AuthenticationPackage
,
654 (PVOID
*)&ProfileBuffer
,
655 &ProfileBufferLength
,
660 if (!NT_SUCCESS(Status
))
662 ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status
);
666 if (ProfileBuffer
!= NULL
)
668 TRACE("ProfileBuffer: %p\n", ProfileBuffer
);
669 TRACE("MessageType: %u\n", ProfileBuffer
->MessageType
);
671 TRACE("FullName: %p\n", ProfileBuffer
->FullName
.Buffer
);
672 TRACE("FullName: %S\n", ProfileBuffer
->FullName
.Buffer
);
674 TRACE("LogonServer: %p\n", ProfileBuffer
->LogonServer
.Buffer
);
675 TRACE("LogonServer: %S\n", ProfileBuffer
->LogonServer
.Buffer
);
678 TRACE("Luid: 0x%08lx%08lx\n", Luid
.HighPart
, Luid
.LowPart
);
680 if (TokenHandle
!= NULL
)
682 TRACE("TokenHandle: %p\n", TokenHandle
);
686 *phToken
= TokenHandle
;
688 /* FIXME: return ppLogonSid and pQuotaLimits */
691 if (ProfileBuffer
!= NULL
)
692 LsaFreeReturnBuffer(ProfileBuffer
);
694 if (!NT_SUCCESS(Status
))
696 if (TokenHandle
!= NULL
)
697 CloseHandle(TokenHandle
);
700 if (TokenGroups
!= NULL
)
701 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups
);
703 if (LocalSid
!= NULL
)
704 RtlFreeSid(LocalSid
);
706 if (LogonSid
!= NULL
)
707 RtlFreeSid(LogonSid
);
709 if (AuthInfo
!= NULL
)
710 RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo
);
712 if (!NT_SUCCESS(Status
))
714 SetLastError(RtlNtStatusToDosError(Status
));