mirror of
https://github.com/reactos/reactos.git
synced 2024-07-04 11:44:33 +00:00
[ADVAPI32] Improve a bit CreateProcessAsUser().
- Check whether the user-provided token is a primary token. - Do not fail when the RtlAdjustPrivilege() call fails (see the code comment for an explanation). TL;DR is: that call may indeed fail but the privilege may also not be necessary because the user-provided token is a restricted version of the caller's primary token. And this is situation is perfectly fine. This fixes Java 7 installation, CORE-14874.
This commit is contained in:
parent
89c5191d3f
commit
c446ce0d62
|
@ -145,9 +145,30 @@ CreateProcessAsUserCommon(
|
||||||
|
|
||||||
if (hToken != NULL)
|
if (hToken != NULL)
|
||||||
{
|
{
|
||||||
|
TOKEN_TYPE Type;
|
||||||
|
ULONG ReturnLength;
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
HANDLE hTokenDup;
|
HANDLE hTokenDup;
|
||||||
BOOLEAN PrivilegeSet = FALSE;
|
BOOLEAN PrivilegeSet = FALSE, HavePrivilege;
|
||||||
|
|
||||||
|
/* Check whether the user-provided token is a primary token */
|
||||||
|
// GetTokenInformation();
|
||||||
|
Status = NtQueryInformationToken(hToken,
|
||||||
|
TokenType,
|
||||||
|
&Type,
|
||||||
|
sizeof(Type),
|
||||||
|
&ReturnLength);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status);
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
if (Type != TokenPrimary)
|
||||||
|
{
|
||||||
|
ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken, Type);
|
||||||
|
Status = STATUS_BAD_TOKEN_TYPE;
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
/* Duplicate the token for this new process */
|
/* Duplicate the token for this new process */
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
@ -163,32 +184,43 @@ CreateProcessAsUserCommon(
|
||||||
&hTokenDup);
|
&hTokenDup);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ERR("NtDuplicateToken failed, Status 0x%08x\n", Status);
|
ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status);
|
||||||
TerminateProcess(lpProcessInformation->hProcess, Status);
|
goto Quit;
|
||||||
SetLastError(RtlNtStatusToDosError(Status));
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Do we always need SecurityImpersonation?
|
// FIXME: Do we always need SecurityImpersonation?
|
||||||
if (!ImpersonateSelf(SecurityImpersonation))
|
Status = RtlImpersonateSelf(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))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx\n", Status);
|
ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status);
|
||||||
RevertToSelf();
|
|
||||||
NtClose(hTokenDup);
|
NtClose(hTokenDup);
|
||||||
TerminateProcess(lpProcessInformation->hProcess, Status);
|
goto Quit;
|
||||||
SetLastError(RtlNtStatusToDosError(Status));
|
}
|
||||||
return FALSE;
|
|
||||||
|
/*
|
||||||
|
* Attempt to acquire the process primary token assignment privilege
|
||||||
|
* in case we actually need it.
|
||||||
|
* The call will either succeed or fail when the caller has (or has not)
|
||||||
|
* enough rights.
|
||||||
|
* The last situation may not be dramatic for us. Indeed it may happen
|
||||||
|
* that the user-provided token is a restricted version of the caller's
|
||||||
|
* primary token (aka. a "child" token), or both tokens inherit (i.e. are
|
||||||
|
* children, and are together "siblings") from a common parent token.
|
||||||
|
* In this case the NT kernel allows us to assign the token to the child
|
||||||
|
* process without the need for the assignment privilege, which is fine.
|
||||||
|
* On the contrary, if the user-provided token is completely arbitrary,
|
||||||
|
* then the NT kernel will enforce the presence of the assignment privilege:
|
||||||
|
* because we failed (by assumption) to assign the privilege, the process
|
||||||
|
* token assignment will fail as required. It is then the job of the
|
||||||
|
* caller to manually acquire the necessary privileges.
|
||||||
|
*/
|
||||||
|
Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
|
||||||
|
TRUE, TRUE, &PrivilegeSet);
|
||||||
|
HavePrivilege = NT_SUCCESS(Status);
|
||||||
|
if (!HavePrivilege)
|
||||||
|
{
|
||||||
|
ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, "
|
||||||
|
"attempting to continue without it...\n", Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessToken.Token = hTokenDup;
|
AccessToken.Token = hTokenDup;
|
||||||
|
@ -200,8 +232,12 @@ CreateProcessAsUserCommon(
|
||||||
(PVOID)&AccessToken,
|
(PVOID)&AccessToken,
|
||||||
sizeof(AccessToken));
|
sizeof(AccessToken));
|
||||||
|
|
||||||
/* Restore the privileges */
|
/* Restore the privilege */
|
||||||
RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, PrivilegeSet, TRUE, &PrivilegeSet);
|
if (HavePrivilege)
|
||||||
|
{
|
||||||
|
RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
|
||||||
|
PrivilegeSet, TRUE, &PrivilegeSet);
|
||||||
|
}
|
||||||
|
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
|
|
||||||
|
@ -211,7 +247,13 @@ CreateProcessAsUserCommon(
|
||||||
/* Check whether NtSetInformationProcess() failed */
|
/* Check whether NtSetInformationProcess() failed */
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ERR("NtSetInformationProcess failed, Status 0x%08x\n", Status);
|
ERR("NtSetInformationProcess() failed, Status 0x%08x\n", Status);
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Quit:
|
||||||
TerminateProcess(lpProcessInformation->hProcess, Status);
|
TerminateProcess(lpProcessInformation->hProcess, Status);
|
||||||
SetLastError(RtlNtStatusToDosError(Status));
|
SetLastError(RtlNtStatusToDosError(Status));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
Loading…
Reference in a new issue