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 HANDLE LsaHandle
= NULL
;
15 ULONG AuthenticationPackage
= 0;
17 /* FUNCTIONS ***************************************************************/
21 OpenLogonLsaHandle(VOID
)
23 LSA_STRING LogonProcessName
;
24 LSA_STRING PackageName
;
25 LSA_OPERATIONAL_MODE SecurityMode
= 0;
28 RtlInitAnsiString((PANSI_STRING
)&LogonProcessName
,
29 "User32LogonProcess");
31 Status
= LsaRegisterLogonProcess(&LogonProcessName
,
34 if (!NT_SUCCESS(Status
))
36 TRACE("LsaRegisterLogonProcess failed (Status 0x%08lx)\n", Status
);
40 RtlInitAnsiString((PANSI_STRING
)&PackageName
,
43 Status
= LsaLookupAuthenticationPackage(LsaHandle
,
45 &AuthenticationPackage
);
46 if (!NT_SUCCESS(Status
))
48 TRACE("LsaLookupAuthenticationPackage failed (Status 0x%08lx)\n", Status
);
52 TRACE("AuthenticationPackage: 0x%08lx\n", AuthenticationPackage
);
55 if (!NT_SUCCESS(Status
))
57 if (LsaHandle
!= NULL
)
59 Status
= LsaDeregisterLogonProcess(LsaHandle
);
60 if (!NT_SUCCESS(Status
))
62 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status
);
72 CloseLogonLsaHandle(VOID
)
74 NTSTATUS Status
= STATUS_SUCCESS
;
76 if (LsaHandle
!= NULL
)
78 Status
= LsaDeregisterLogonProcess(LsaHandle
);
79 if (!NT_SUCCESS(Status
))
81 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status
);
91 CreateProcessAsUserCommon(
92 _In_opt_ HANDLE hToken
,
93 _In_ DWORD dwCreationFlags
,
94 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
97 PROCESS_ACCESS_TOKEN AccessToken
;
103 OBJECT_ATTRIBUTES ObjectAttributes
;
105 BOOLEAN PrivilegeSet
= FALSE
, HavePrivilege
;
107 /* Check whether the user-provided token is a primary token */
108 // GetTokenInformation();
109 Status
= NtQueryInformationToken(hToken
,
114 if (!NT_SUCCESS(Status
))
116 ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status
);
119 if (Type
!= TokenPrimary
)
121 ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken
, Type
);
122 Status
= STATUS_BAD_TOKEN_TYPE
;
126 /* Duplicate the token for this new process */
127 InitializeObjectAttributes(&ObjectAttributes
,
131 NULL
); // FIXME: Use a valid SecurityDescriptor!
132 Status
= NtDuplicateToken(hToken
,
138 if (!NT_SUCCESS(Status
))
140 ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status
);
144 // FIXME: Do we always need SecurityImpersonation?
145 Status
= RtlImpersonateSelf(SecurityImpersonation
);
146 if (!NT_SUCCESS(Status
))
148 ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status
);
154 * Attempt to acquire the process primary token assignment privilege
155 * in case we actually need it.
156 * The call will either succeed or fail when the caller has (or has not)
158 * The last situation may not be dramatic for us. Indeed it may happen
159 * that the user-provided token is a restricted version of the caller's
160 * primary token (aka. a "child" token), or both tokens inherit (i.e. are
161 * children, and are together "siblings") from a common parent token.
162 * In this case the NT kernel allows us to assign the token to the child
163 * process without the need for the assignment privilege, which is fine.
164 * On the contrary, if the user-provided token is completely arbitrary,
165 * then the NT kernel will enforce the presence of the assignment privilege:
166 * because we failed (by assumption) to assign the privilege, the process
167 * token assignment will fail as required. It is then the job of the
168 * caller to manually acquire the necessary privileges.
170 Status
= RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
,
171 TRUE
, TRUE
, &PrivilegeSet
);
172 HavePrivilege
= NT_SUCCESS(Status
);
175 ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, "
176 "attempting to continue without it...\n", Status
);
179 AccessToken
.Token
= hTokenDup
;
180 AccessToken
.Thread
= lpProcessInformation
->hThread
;
182 /* Set the new process token */
183 Status
= NtSetInformationProcess(lpProcessInformation
->hProcess
,
186 sizeof(AccessToken
));
188 /* Restore the privilege */
191 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
,
192 PrivilegeSet
, TRUE
, &PrivilegeSet
);
197 /* Close the duplicated token */
200 /* Check whether NtSetInformationProcess() failed */
201 if (!NT_SUCCESS(Status
))
203 ERR("NtSetInformationProcess() failed, Status 0x%08x\n", Status
);
207 if (!NT_SUCCESS(Status
))
210 TerminateProcess(lpProcessInformation
->hProcess
, Status
);
211 SetLastError(RtlNtStatusToDosError(Status
));
216 /* Resume the main thread */
217 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
219 ResumeThread(lpProcessInformation
->hThread
);
232 CreateProcessAsUserA(
233 _In_opt_ HANDLE hToken
,
234 _In_opt_ LPCSTR lpApplicationName
,
235 _Inout_opt_ LPSTR lpCommandLine
,
236 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes
,
237 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes
,
238 _In_ BOOL bInheritHandles
,
239 _In_ DWORD dwCreationFlags
,
240 _In_opt_ LPVOID lpEnvironment
,
241 _In_opt_ LPCSTR lpCurrentDirectory
,
242 _In_ LPSTARTUPINFOA lpStartupInfo
,
243 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
245 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken
, debugstr_a(lpApplicationName
),
246 debugstr_a(lpCommandLine
), lpProcessAttributes
, lpThreadAttributes
, bInheritHandles
,
247 dwCreationFlags
, lpEnvironment
, debugstr_a(lpCurrentDirectory
), lpStartupInfo
, lpProcessInformation
);
249 /* Create the process with a suspended main thread */
250 if (!CreateProcessA(lpApplicationName
,
255 dwCreationFlags
| CREATE_SUSPENDED
,
259 lpProcessInformation
))
261 ERR("CreateProcessA failed, last error: %d\n", GetLastError());
265 /* Call the helper function */
266 return CreateProcessAsUserCommon(hToken
,
268 lpProcessInformation
);
278 CreateProcessAsUserW(
279 _In_opt_ HANDLE hToken
,
280 _In_opt_ LPCWSTR lpApplicationName
,
281 _Inout_opt_ LPWSTR lpCommandLine
,
282 _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes
,
283 _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes
,
284 _In_ BOOL bInheritHandles
,
285 _In_ DWORD dwCreationFlags
,
286 _In_opt_ LPVOID lpEnvironment
,
287 _In_opt_ LPCWSTR lpCurrentDirectory
,
288 _In_ LPSTARTUPINFOW lpStartupInfo
,
289 _Out_ LPPROCESS_INFORMATION lpProcessInformation
)
291 TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken
, debugstr_w(lpApplicationName
),
292 debugstr_w(lpCommandLine
), lpProcessAttributes
, lpThreadAttributes
, bInheritHandles
,
293 dwCreationFlags
, lpEnvironment
, debugstr_w(lpCurrentDirectory
), lpStartupInfo
, lpProcessInformation
);
295 /* Create the process with a suspended main thread */
296 if (!CreateProcessW(lpApplicationName
,
301 dwCreationFlags
| CREATE_SUSPENDED
,
305 lpProcessInformation
))
307 ERR("CreateProcessW failed, last error: %d\n", GetLastError());
311 /* Call the helper function */
312 return CreateProcessAsUserCommon(hToken
,
314 lpProcessInformation
);
324 _In_ LPSTR lpszUsername
,
325 _In_opt_ LPSTR lpszDomain
,
326 _In_opt_ LPSTR lpszPassword
,
327 _In_ DWORD dwLogonType
,
328 _In_ DWORD dwLogonProvider
,
329 _Out_opt_ PHANDLE phToken
)
331 return LogonUserExA(lpszUsername
,
350 _In_ LPSTR lpszUsername
,
351 _In_opt_ LPSTR lpszDomain
,
352 _In_opt_ LPSTR lpszPassword
,
353 _In_ DWORD dwLogonType
,
354 _In_ DWORD dwLogonProvider
,
355 _Out_opt_ PHANDLE phToken
,
356 _Out_opt_ PSID
*ppLogonSid
,
357 _Out_opt_ PVOID
*ppProfileBuffer
,
358 _Out_opt_ LPDWORD pdwProfileLength
,
359 _Out_opt_ PQUOTA_LIMITS pQuotaLimits
)
361 UNICODE_STRING UserName
;
362 UNICODE_STRING Domain
;
363 UNICODE_STRING Password
;
366 UserName
.Buffer
= NULL
;
367 Domain
.Buffer
= NULL
;
368 Password
.Buffer
= NULL
;
370 if (!RtlCreateUnicodeStringFromAsciiz(&UserName
, lpszUsername
))
372 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
376 if (!RtlCreateUnicodeStringFromAsciiz(&Domain
, lpszDomain
))
378 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
382 if (!RtlCreateUnicodeStringFromAsciiz(&Password
, lpszPassword
))
384 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
388 ret
= LogonUserExW(UserName
.Buffer
,
399 if (Password
.Buffer
!= NULL
)
400 RtlFreeUnicodeString(&Password
);
403 if (Domain
.Buffer
!= NULL
)
404 RtlFreeUnicodeString(&Domain
);
407 if (UserName
.Buffer
!= NULL
)
408 RtlFreeUnicodeString(&UserName
);
421 _In_ LPWSTR lpszUsername
,
422 _In_opt_ LPWSTR lpszDomain
,
423 _In_opt_ LPWSTR lpszPassword
,
424 _In_ DWORD dwLogonType
,
425 _In_ DWORD dwLogonProvider
,
426 _Out_opt_ PHANDLE phToken
)
428 return LogonUserExW(lpszUsername
,
447 _In_ LPWSTR lpszUsername
,
448 _In_opt_ LPWSTR lpszDomain
,
449 _In_opt_ LPWSTR lpszPassword
,
450 _In_ DWORD dwLogonType
,
451 _In_ DWORD dwLogonProvider
,
452 _Out_opt_ PHANDLE phToken
,
453 _Out_opt_ PSID
*ppLogonSid
,
454 _Out_opt_ PVOID
*ppProfileBuffer
,
455 _Out_opt_ LPDWORD pdwProfileLength
,
456 _Out_opt_ PQUOTA_LIMITS pQuotaLimits
)
458 SID_IDENTIFIER_AUTHORITY LocalAuthority
= {SECURITY_LOCAL_SID_AUTHORITY
};
459 SID_IDENTIFIER_AUTHORITY SystemAuthority
= {SECURITY_NT_AUTHORITY
};
460 PSID LogonSid
= NULL
;
461 PSID LocalSid
= NULL
;
462 LSA_STRING OriginName
;
463 UNICODE_STRING DomainName
;
464 UNICODE_STRING UserName
;
465 UNICODE_STRING Password
;
466 PMSV1_0_INTERACTIVE_LOGON AuthInfo
= NULL
;
467 ULONG AuthInfoLength
;
469 TOKEN_SOURCE TokenSource
;
470 PTOKEN_GROUPS TokenGroups
= NULL
;
471 PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer
= NULL
;
472 ULONG ProfileBufferLength
= 0;
474 LUID LogonId
= {0, 0};
475 HANDLE TokenHandle
= NULL
;
476 QUOTA_LIMITS QuotaLimits
;
477 SECURITY_LOGON_TYPE LogonType
;
478 NTSTATUS SubStatus
= STATUS_SUCCESS
;
481 if ((ppProfileBuffer
!= NULL
&& pdwProfileLength
== NULL
) ||
482 (ppProfileBuffer
== NULL
&& pdwProfileLength
!= NULL
))
484 SetLastError(ERROR_INVALID_PARAMETER
);
488 if (ppProfileBuffer
!= NULL
&& pdwProfileLength
!= NULL
)
490 *ppProfileBuffer
= NULL
;
491 *pdwProfileLength
= 0;
499 case LOGON32_LOGON_INTERACTIVE
:
500 LogonType
= Interactive
;
503 case LOGON32_LOGON_NETWORK
:
507 case LOGON32_LOGON_BATCH
:
511 case LOGON32_LOGON_SERVICE
:
516 ERR("Invalid logon type: %ul\n", dwLogonType
);
517 Status
= STATUS_INVALID_PARAMETER
;
521 if (LsaHandle
== NULL
)
523 Status
= OpenLogonLsaHandle();
524 if (!NT_SUCCESS(Status
))
528 RtlInitAnsiString((PANSI_STRING
)&OriginName
,
531 RtlInitUnicodeString(&DomainName
,
534 RtlInitUnicodeString(&UserName
,
537 RtlInitUnicodeString(&Password
,
540 AuthInfoLength
= sizeof(MSV1_0_INTERACTIVE_LOGON
)+
541 DomainName
.MaximumLength
+
542 UserName
.MaximumLength
+
543 Password
.MaximumLength
;
545 AuthInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
548 if (AuthInfo
== NULL
)
550 Status
= STATUS_INSUFFICIENT_RESOURCES
;
554 AuthInfo
->MessageType
= MsV1_0InteractiveLogon
;
556 Ptr
= (ULONG_PTR
)AuthInfo
+ sizeof(MSV1_0_INTERACTIVE_LOGON
);
558 AuthInfo
->LogonDomainName
.Length
= DomainName
.Length
;
559 AuthInfo
->LogonDomainName
.MaximumLength
= DomainName
.MaximumLength
;
560 AuthInfo
->LogonDomainName
.Buffer
= (DomainName
.Buffer
== NULL
) ? NULL
: (PWCHAR
)Ptr
;
561 if (DomainName
.MaximumLength
> 0)
563 RtlCopyMemory(AuthInfo
->LogonDomainName
.Buffer
,
565 DomainName
.MaximumLength
);
567 Ptr
+= DomainName
.MaximumLength
;
570 AuthInfo
->UserName
.Length
= UserName
.Length
;
571 AuthInfo
->UserName
.MaximumLength
= UserName
.MaximumLength
;
572 AuthInfo
->UserName
.Buffer
= (PWCHAR
)Ptr
;
573 if (UserName
.MaximumLength
> 0)
574 RtlCopyMemory(AuthInfo
->UserName
.Buffer
,
576 UserName
.MaximumLength
);
578 Ptr
+= UserName
.MaximumLength
;
580 AuthInfo
->Password
.Length
= Password
.Length
;
581 AuthInfo
->Password
.MaximumLength
= Password
.MaximumLength
;
582 AuthInfo
->Password
.Buffer
= (PWCHAR
)Ptr
;
583 if (Password
.MaximumLength
> 0)
584 RtlCopyMemory(AuthInfo
->Password
.Buffer
,
586 Password
.MaximumLength
);
588 /* Create the Logon SID */
589 AllocateLocallyUniqueId(&LogonId
);
590 Status
= RtlAllocateAndInitializeSid(&SystemAuthority
,
591 SECURITY_LOGON_IDS_RID_COUNT
,
592 SECURITY_LOGON_IDS_RID
,
601 if (!NT_SUCCESS(Status
))
604 /* Create the Local SID */
605 Status
= RtlAllocateAndInitializeSid(&LocalAuthority
,
616 if (!NT_SUCCESS(Status
))
619 /* Allocate and set the token groups */
620 TokenGroups
= RtlAllocateHeap(RtlGetProcessHeap(),
622 sizeof(TOKEN_GROUPS
) + ((2 - ANYSIZE_ARRAY
) * sizeof(SID_AND_ATTRIBUTES
)));
623 if (TokenGroups
== NULL
)
625 Status
= STATUS_INSUFFICIENT_RESOURCES
;
629 TokenGroups
->GroupCount
= 2;
630 TokenGroups
->Groups
[0].Sid
= LogonSid
;
631 TokenGroups
->Groups
[0].Attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED
|
632 SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_LOGON_ID
;
633 TokenGroups
->Groups
[1].Sid
= LocalSid
;
634 TokenGroups
->Groups
[1].Attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED
|
635 SE_GROUP_ENABLED_BY_DEFAULT
;
637 /* Set the token source */
638 strncpy(TokenSource
.SourceName
, "Advapi ", sizeof(TokenSource
.SourceName
));
639 AllocateLocallyUniqueId(&TokenSource
.SourceIdentifier
);
641 Status
= LsaLogonUser(LsaHandle
,
644 AuthenticationPackage
,
649 (PVOID
*)&ProfileBuffer
,
650 &ProfileBufferLength
,
655 if (!NT_SUCCESS(Status
))
657 ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status
);
661 if (ProfileBuffer
!= NULL
)
663 TRACE("ProfileBuffer: %p\n", ProfileBuffer
);
664 TRACE("MessageType: %u\n", ProfileBuffer
->MessageType
);
666 TRACE("FullName: %p\n", ProfileBuffer
->FullName
.Buffer
);
667 TRACE("FullName: %S\n", ProfileBuffer
->FullName
.Buffer
);
669 TRACE("LogonServer: %p\n", ProfileBuffer
->LogonServer
.Buffer
);
670 TRACE("LogonServer: %S\n", ProfileBuffer
->LogonServer
.Buffer
);
673 TRACE("Luid: 0x%08lx%08lx\n", Luid
.HighPart
, Luid
.LowPart
);
675 if (TokenHandle
!= NULL
)
677 TRACE("TokenHandle: %p\n", TokenHandle
);
681 *phToken
= TokenHandle
;
683 /* FIXME: return ppLogonSid and pQuotaLimits */
686 if (ProfileBuffer
!= NULL
)
687 LsaFreeReturnBuffer(ProfileBuffer
);
689 if (!NT_SUCCESS(Status
))
691 if (TokenHandle
!= NULL
)
692 CloseHandle(TokenHandle
);
695 if (TokenGroups
!= NULL
)
696 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups
);
698 if (LocalSid
!= NULL
)
699 RtlFreeSid(LocalSid
);
701 if (LogonSid
!= NULL
)
702 RtlFreeSid(LogonSid
);
704 if (AuthInfo
!= NULL
)
705 RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo
);
707 if (!NT_SUCCESS(Status
))
709 SetLastError(RtlNtStatusToDosError(Status
));