reactos/dll/win32/advapi32/misc/logon.c
Hermès Bélusca-Maïto d4b4da5385
[ADVAPI32] Additions for CreateProcessAsUserA/W().
- Use a common helper function used by both the ANSI and UNICODE functions
  so that the large code block that deals with setting the new process token
  becomes automatically common to both these functions, while the ANSI vs.
  UNICODE conversions are handled directly via the CreateProcessA/W() calls.

- Duplicate the token and acquire the process primary token assignment
  privilege before calling NtSetInformationProcess().
2018-06-27 23:40:07 +02:00

693 lines
21 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/advapi32/misc/logon.c
* PURPOSE: Logon functions
* PROGRAMMER: Eric Kohl
*/
#include <advapi32.h>
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
/* GLOBALS *****************************************************************/
HANDLE LsaHandle = NULL;
ULONG AuthenticationPackage = 0;
/* FUNCTIONS ***************************************************************/
static
NTSTATUS
OpenLogonLsaHandle(VOID)
{
LSA_STRING LogonProcessName;
LSA_STRING PackageName;
LSA_OPERATIONAL_MODE SecurityMode = 0;
NTSTATUS Status;
RtlInitAnsiString((PANSI_STRING)&LogonProcessName,
"User32LogonProcess");
Status = LsaRegisterLogonProcess(&LogonProcessName,
&LsaHandle,
&SecurityMode);
if (!NT_SUCCESS(Status))
{
TRACE("LsaRegisterLogonProcess failed (Status 0x%08lx)\n", Status);
goto done;
}
RtlInitAnsiString((PANSI_STRING)&PackageName,
MSV1_0_PACKAGE_NAME);
Status = LsaLookupAuthenticationPackage(LsaHandle,
&PackageName,
&AuthenticationPackage);
if (!NT_SUCCESS(Status))
{
TRACE("LsaLookupAuthenticationPackage failed (Status 0x%08lx)\n", Status);
goto done;
}
TRACE("AuthenticationPackage: 0x%08lx\n", AuthenticationPackage);
done:
if (!NT_SUCCESS(Status))
{
if (LsaHandle != NULL)
{
Status = LsaDeregisterLogonProcess(LsaHandle);
if (!NT_SUCCESS(Status))
{
TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
}
}
}
return Status;
}
NTSTATUS
CloseLogonLsaHandle(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
if (LsaHandle != NULL)
{
Status = LsaDeregisterLogonProcess(LsaHandle);
if (!NT_SUCCESS(Status))
{
TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
}
}
return Status;
}
static
BOOL
CreateProcessAsUserCommon(
_In_ BOOL bUnicode,
_In_opt_ HANDLE hToken,
_In_opt_ LPCVOID lpApplicationName,
_Inout_opt_ LPVOID lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCVOID lpCurrentDirectory,
_In_ LPVOID lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation)
{
NTSTATUS Status;
PROCESS_ACCESS_TOKEN AccessToken;
/* Create the process with a suspended main thread */
if (bUnicode)
{
/* Call the UNICODE version */
if (!CreateProcessW((LPCWSTR)lpApplicationName,
(LPWSTR)lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags | CREATE_SUSPENDED,
lpEnvironment,
(LPCWSTR)lpCurrentDirectory,
(LPSTARTUPINFOW)lpStartupInfo,
lpProcessInformation))
{
ERR("CreateProcessW failed, last error: %d\n", GetLastError());
return FALSE;
}
}
else
{
/* Call the ANSI version */
if (!CreateProcessA((LPCSTR)lpApplicationName,
(LPSTR)lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags | CREATE_SUSPENDED,
lpEnvironment,
(LPCSTR)lpCurrentDirectory,
(LPSTARTUPINFOA)lpStartupInfo,
lpProcessInformation))
{
ERR("CreateProcessA failed, last error: %d\n", GetLastError());
return FALSE;
}
}
if (hToken != NULL)
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hTokenDup;
BOOLEAN PrivilegeSet = FALSE;
/* Duplicate the token for this new process */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL); // FIXME: Use a valid SecurityDescriptor!
Status = NtDuplicateToken(hToken,
0,
&ObjectAttributes,
FALSE,
TokenPrimary,
&hTokenDup);
if (!NT_SUCCESS(Status))
{
ERR("NtDuplicateToken failed, Status 0x%08x\n", Status);
TerminateProcess(lpProcessInformation->hProcess, Status);
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
// FIXME: Do we always need SecurityImpersonation?
if (!ImpersonateSelf(SecurityImpersonation))
{
ERR("ImpersonateSelf(SecurityImpersonation) failed, last error: %d\n", GetLastError());
NtClose(hTokenDup);
TerminateProcess(lpProcessInformation->hProcess, RtlGetLastNtStatus());
// SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
/* Acquire the process primary token assignment privilege */
Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, TRUE, &PrivilegeSet);
if (!NT_SUCCESS(Status))
{
ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx\n", Status);
RevertToSelf();
NtClose(hTokenDup);
TerminateProcess(lpProcessInformation->hProcess, Status);
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
AccessToken.Token = hTokenDup;
AccessToken.Thread = lpProcessInformation->hThread;
/* Set the new process token */
Status = NtSetInformationProcess(lpProcessInformation->hProcess,
ProcessAccessToken,
(PVOID)&AccessToken,
sizeof(AccessToken));
/* Restore the privileges */
RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, PrivilegeSet, TRUE, &PrivilegeSet);
RevertToSelf();
/* Close the duplicated token */
NtClose(hTokenDup);
/* Check whether NtSetInformationProcess() failed */
if (!NT_SUCCESS(Status))
{
ERR("NtSetInformationProcess failed, Status 0x%08x\n", Status);
TerminateProcess(lpProcessInformation->hProcess, Status);
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
}
/* Resume the main thread */
if (!(dwCreationFlags & CREATE_SUSPENDED))
{
ResumeThread(lpProcessInformation->hThread);
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
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)
{
TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_a(lpApplicationName),
debugstr_a(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles,
dwCreationFlags, lpEnvironment, debugstr_a(lpCurrentDirectory), lpStartupInfo, lpProcessInformation);
/* Call the helper function */
return CreateProcessAsUserCommon(FALSE,
hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
}
/*
* @implemented
*/
BOOL
WINAPI
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)
{
TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_w(lpApplicationName),
debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles,
dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory), lpStartupInfo, lpProcessInformation);
/* Call the helper function */
return CreateProcessAsUserCommon(TRUE,
hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
}
/*
* @implemented
*/
BOOL
WINAPI
LogonUserA(
_In_ LPSTR lpszUsername,
_In_opt_ LPSTR lpszDomain,
_In_opt_ LPSTR lpszPassword,
_In_ DWORD dwLogonType,
_In_ DWORD dwLogonProvider,
_Out_opt_ PHANDLE phToken)
{
return LogonUserExA(lpszUsername,
lpszDomain,
lpszPassword,
dwLogonType,
dwLogonProvider,
phToken,
NULL,
NULL,
NULL,
NULL);
}
/*
* @implemented
*/
BOOL
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)
{
UNICODE_STRING UserName;
UNICODE_STRING Domain;
UNICODE_STRING Password;
BOOL ret = FALSE;
UserName.Buffer = NULL;
Domain.Buffer = NULL;
Password.Buffer = NULL;
if (!RtlCreateUnicodeStringFromAsciiz(&UserName, lpszUsername))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto UsernameDone;
}
if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto DomainDone;
}
if (!RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto PasswordDone;
}
ret = LogonUserExW(UserName.Buffer,
Domain.Buffer,
Password.Buffer,
dwLogonType,
dwLogonProvider,
phToken,
ppLogonSid,
ppProfileBuffer,
pdwProfileLength,
pQuotaLimits);
if (Password.Buffer != NULL)
RtlFreeUnicodeString(&Password);
PasswordDone:
if (Domain.Buffer != NULL)
RtlFreeUnicodeString(&Domain);
DomainDone:
if (UserName.Buffer != NULL)
RtlFreeUnicodeString(&UserName);
UsernameDone:
return ret;
}
/*
* @implemented
*/
BOOL
WINAPI
LogonUserW(
_In_ LPWSTR lpszUsername,
_In_opt_ LPWSTR lpszDomain,
_In_opt_ LPWSTR lpszPassword,
_In_ DWORD dwLogonType,
_In_ DWORD dwLogonProvider,
_Out_opt_ PHANDLE phToken)
{
return LogonUserExW(lpszUsername,
lpszDomain,
lpszPassword,
dwLogonType,
dwLogonProvider,
phToken,
NULL,
NULL,
NULL,
NULL);
}
/*
* @implemented
*/
BOOL
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)
{
SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
PSID LogonSid = NULL;
PSID LocalSid = NULL;
LSA_STRING OriginName;
UNICODE_STRING DomainName;
UNICODE_STRING UserName;
UNICODE_STRING Password;
PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL;
ULONG AuthInfoLength;
ULONG_PTR Ptr;
TOKEN_SOURCE TokenSource;
PTOKEN_GROUPS TokenGroups = NULL;
PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL;
ULONG ProfileBufferLength = 0;
LUID Luid = {0, 0};
LUID LogonId = {0, 0};
HANDLE TokenHandle = NULL;
QUOTA_LIMITS QuotaLimits;
SECURITY_LOGON_TYPE LogonType;
NTSTATUS SubStatus = STATUS_SUCCESS;
NTSTATUS Status;
*phToken = NULL;
switch (dwLogonType)
{
case LOGON32_LOGON_INTERACTIVE:
LogonType = Interactive;
break;
case LOGON32_LOGON_NETWORK:
LogonType = Network;
break;
case LOGON32_LOGON_BATCH:
LogonType = Batch;
break;
case LOGON32_LOGON_SERVICE:
LogonType = Service;
break;
default:
ERR("Invalid logon type: %ul\n", dwLogonType);
Status = STATUS_INVALID_PARAMETER;
goto done;
}
if (LsaHandle == NULL)
{
Status = OpenLogonLsaHandle();
if (!NT_SUCCESS(Status))
goto done;
}
RtlInitAnsiString((PANSI_STRING)&OriginName,
"Advapi32 Logon");
RtlInitUnicodeString(&DomainName,
lpszDomain);
RtlInitUnicodeString(&UserName,
lpszUsername);
RtlInitUnicodeString(&Password,
lpszPassword);
AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+
DomainName.MaximumLength +
UserName.MaximumLength +
Password.MaximumLength;
AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
AuthInfoLength);
if (AuthInfo == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
AuthInfo->MessageType = MsV1_0InteractiveLogon;
Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON);
AuthInfo->LogonDomainName.Length = DomainName.Length;
AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength;
AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr;
if (DomainName.MaximumLength > 0)
{
RtlCopyMemory(AuthInfo->LogonDomainName.Buffer,
DomainName.Buffer,
DomainName.MaximumLength);
Ptr += DomainName.MaximumLength;
}
AuthInfo->UserName.Length = UserName.Length;
AuthInfo->UserName.MaximumLength = UserName.MaximumLength;
AuthInfo->UserName.Buffer = (PWCHAR)Ptr;
if (UserName.MaximumLength > 0)
RtlCopyMemory(AuthInfo->UserName.Buffer,
UserName.Buffer,
UserName.MaximumLength);
Ptr += UserName.MaximumLength;
AuthInfo->Password.Length = Password.Length;
AuthInfo->Password.MaximumLength = Password.MaximumLength;
AuthInfo->Password.Buffer = (PWCHAR)Ptr;
if (Password.MaximumLength > 0)
RtlCopyMemory(AuthInfo->Password.Buffer,
Password.Buffer,
Password.MaximumLength);
/* Create the Logon SID */
AllocateLocallyUniqueId(&LogonId);
Status = RtlAllocateAndInitializeSid(&SystemAuthority,
SECURITY_LOGON_IDS_RID_COUNT,
SECURITY_LOGON_IDS_RID,
LogonId.HighPart,
LogonId.LowPart,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
&LogonSid);
if (!NT_SUCCESS(Status))
goto done;
/* Create the Local SID */
Status = RtlAllocateAndInitializeSid(&LocalAuthority,
1,
SECURITY_LOCAL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
&LocalSid);
if (!NT_SUCCESS(Status))
goto done;
/* Allocate and set the token groups */
TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES)));
if (TokenGroups == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
TokenGroups->GroupCount = 2;
TokenGroups->Groups[0].Sid = LogonSid;
TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
TokenGroups->Groups[1].Sid = LocalSid;
TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
/* Set the token source */
strncpy(TokenSource.SourceName, "Advapi ", sizeof(TokenSource.SourceName));
AllocateLocallyUniqueId(&TokenSource.SourceIdentifier);
Status = LsaLogonUser(LsaHandle,
&OriginName,
LogonType,
AuthenticationPackage,
(PVOID)AuthInfo,
AuthInfoLength,
TokenGroups,
&TokenSource,
(PVOID*)&ProfileBuffer,
&ProfileBufferLength,
&Luid,
&TokenHandle,
&QuotaLimits,
&SubStatus);
if (!NT_SUCCESS(Status))
{
ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status);
goto done;
}
if (ProfileBuffer != NULL)
{
TRACE("ProfileBuffer: %p\n", ProfileBuffer);
TRACE("MessageType: %u\n", ProfileBuffer->MessageType);
TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer);
TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer);
TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer);
TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer);
}
TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart);
if (TokenHandle != NULL)
{
TRACE("TokenHandle: %p\n", TokenHandle);
}
*phToken = TokenHandle;
/* FIXME: return ppLogonSid, ppProfileBuffer, pdwProfileLength and pQuotaLimits */
done:
if (ProfileBuffer != NULL)
LsaFreeReturnBuffer(ProfileBuffer);
if (!NT_SUCCESS(Status))
{
if (TokenHandle != NULL)
CloseHandle(TokenHandle);
}
if (TokenGroups != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups);
if (LocalSid != NULL)
RtlFreeSid(LocalSid);
if (LogonSid != NULL)
RtlFreeSid(LogonSid);
if (AuthInfo != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo);
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
return TRUE;
}
/* EOF */