mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
Added patch with basic implementation for token integrity levels and UAC handling.
This commit is contained in:
parent
8f9cc5e01c
commit
5559653869
@ -0,0 +1,456 @@
|
||||
From ba50fc98ee4690e62899d48efc856c2bc910536c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 01:25:02 +0200
|
||||
Subject: advapi32/tests: Extend security label / token integrity tests.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/Makefile.in | 2 +-
|
||||
dlls/advapi32/tests/security.c | 389 +++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 387 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/Makefile.in b/dlls/advapi32/tests/Makefile.in
|
||||
index 36ce031ef62..4437e6e5de7 100644
|
||||
--- a/dlls/advapi32/tests/Makefile.in
|
||||
+++ b/dlls/advapi32/tests/Makefile.in
|
||||
@@ -1,5 +1,5 @@
|
||||
TESTDLL = advapi32.dll
|
||||
-IMPORTS = ole32 advapi32
|
||||
+IMPORTS = ole32 user32 advapi32
|
||||
|
||||
C_SRCS = \
|
||||
cred.c \
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 0fd41fe82fa..4a03db27e69 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -7191,13 +7191,19 @@ static void test_token_security_descriptor(void)
|
||||
{
|
||||
static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
{SECURITY_MANDATORY_LOW_RID}};
|
||||
+ static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
+ {SECURITY_MANDATORY_MEDIUM_RID}};
|
||||
+ static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
+ {SECURITY_MANDATORY_HIGH_RID}};
|
||||
char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
||||
- SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2;
|
||||
+ SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2, *sd3;
|
||||
char buffer_acl[256], buffer[MAX_PATH];
|
||||
- ACL *acl = (ACL *)&buffer_acl, *acl2, *acl_child;
|
||||
+ ACL *acl = (ACL *)&buffer_acl, *acl2, *acl_child, *sacl;
|
||||
BOOL defaulted, present, ret, found;
|
||||
- HANDLE token, token2, token3;
|
||||
+ HANDLE token, token2, token3, token4, token5, token6;
|
||||
EXPLICIT_ACCESSW exp_access;
|
||||
+ TOKEN_MANDATORY_LABEL *tml;
|
||||
+ BYTE buffer_integrity[64];
|
||||
PROCESS_INFORMATION info;
|
||||
DWORD size, index, retd;
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
@@ -7347,6 +7353,185 @@ static void test_token_security_descriptor(void)
|
||||
/* The security label is also not inherited */
|
||||
if (pAddMandatoryAce)
|
||||
{
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
|
||||
+ "Expected medium or high integrity level\n");
|
||||
+
|
||||
+ if (EqualSid(tml->Label.Sid, &high_level))
|
||||
+ {
|
||||
+ DWORD process_id;
|
||||
+ HANDLE process;
|
||||
+ HWND shell;
|
||||
+
|
||||
+ /* This test tries to get a medium token and then impersonates this token. The
|
||||
+ * idea is to check whether the sd label of a newly created token depends on the
|
||||
+ * current active token or the integrity level of the newly created token. */
|
||||
+
|
||||
+ /* Steal process token of the explorer.exe process */
|
||||
+ shell = GetShellWindow();
|
||||
+ todo_wine ok(shell != NULL, "Failed to get shell window\n");
|
||||
+ if (!shell) shell = GetDesktopWindow(); /* FIXME: Workaround for Wine */
|
||||
+ ok(GetWindowThreadProcessId(shell, &process_id),
|
||||
+ "Failed to get process id of shell window: %u\n", GetLastError());
|
||||
+ process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);
|
||||
+ ok(process != NULL, "Failed to open process: %u\n", GetLastError());
|
||||
+ ok(OpenProcessToken(process, TOKEN_ALL_ACCESS, &token4),
|
||||
+ "Failed to open process token: %u\n", GetLastError());
|
||||
+ CloseHandle(process);
|
||||
+
|
||||
+ /* Check TokenIntegrityLevel and LABEL_SECURITY_INFORMATION of explorer.exe token */
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
+
|
||||
+ size = 0;
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ sacl = NULL;
|
||||
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ ok(present, "No SACL in the security descriptor\n");
|
||||
+ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+
|
||||
+ if (sacl)
|
||||
+ {
|
||||
+ ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
+ todo_wine ok(EqualSid(&ace->SidStart, &medium_level),
|
||||
+ "Expected medium integrity level\n");
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd3);
|
||||
+
|
||||
+ /* Start child process with the explorer.exe token */
|
||||
+ memset(&startup, 0, sizeof(startup));
|
||||
+ startup.cb = sizeof(startup);
|
||||
+ startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
+ startup.wShowWindow = SW_SHOWNORMAL;
|
||||
+
|
||||
+ sprintf(buffer, "%s tests/security.c test_token_sd_medium", myARGV[0]);
|
||||
+ ret = CreateProcessAsUserA(token4, NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
|
||||
+ ok(ret || GetLastError() == ERROR_PRIVILEGE_NOT_HELD,
|
||||
+ "CreateProcess failed with error %u\n", GetLastError());
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ winetest_wait_child_process(info.hProcess);
|
||||
+ CloseHandle(info.hProcess);
|
||||
+ CloseHandle(info.hThread);
|
||||
+ }
|
||||
+ else
|
||||
+ win_skip("Skipping test for creating process with medium level token\n");
|
||||
+
|
||||
+ ret = DuplicateTokenEx(token4, 0, NULL, SecurityImpersonation, TokenImpersonation, &token5);
|
||||
+ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
|
||||
+ ret = SetThreadToken(NULL, token5);
|
||||
+ todo_wine ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
|
||||
+ CloseHandle(token4);
|
||||
+
|
||||
+ /* Restrict current process token while impersonating a medium integrity token */
|
||||
+ ret = CreateRestrictedToken(token, 0, 0, NULL, 0, NULL, 0, NULL, &token6);
|
||||
+ ok(ret, "CreateRestrictedToken failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token6, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &high_level), "Expected high integrity level\n");
|
||||
+
|
||||
+ size = 0;
|
||||
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ sacl = NULL;
|
||||
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+
|
||||
+ if (sacl)
|
||||
+ {
|
||||
+ ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
+ ok(EqualSid(&ace->SidStart, &medium_level),
|
||||
+ "Expected medium integrity level\n");
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd3);
|
||||
+ RevertToSelf();
|
||||
+ CloseHandle(token5);
|
||||
+
|
||||
+ /* Start child process with the restricted token */
|
||||
+ sprintf(buffer, "%s tests/security.c test_token_sd_restricted", myARGV[0]);
|
||||
+ ret = CreateProcessAsUserA(token6, NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
|
||||
+ ok(ret, "CreateProcess failed with error %u\n", GetLastError());
|
||||
+ winetest_wait_child_process(info.hProcess);
|
||||
+ CloseHandle(info.hProcess);
|
||||
+ CloseHandle(info.hThread);
|
||||
+ CloseHandle(token6);
|
||||
+
|
||||
+ /* DuplicateTokenEx should assign security label even when SA points to empty SD */
|
||||
+ memset(sd, 0, sizeof(buffer_sd));
|
||||
+ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
+ ok(ret, "InitializeSecurityDescriptor failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
+ sa.lpSecurityDescriptor = sd;
|
||||
+ sa.bInheritHandle = FALSE;
|
||||
+
|
||||
+ ret = DuplicateTokenEx(token, 0, &sa, 0, TokenPrimary, &token6);
|
||||
+ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ size = 0;
|
||||
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
+ todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ sacl = NULL;
|
||||
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
+ todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+
|
||||
+ if (sacl)
|
||||
+ {
|
||||
+ ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
+ ok(EqualSid(&ace->SidStart, &high_level),
|
||||
+ "Expected high integrity level\n");
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd3);
|
||||
+ CloseHandle(token6);
|
||||
+ }
|
||||
+ else
|
||||
+ skip("Skipping test, running without admin rights\n");
|
||||
+
|
||||
ret = InitializeAcl(acl, 256, ACL_REVISION);
|
||||
ok(ret, "InitializeAcl failed with error %u\n", GetLastError());
|
||||
|
||||
@@ -7362,6 +7547,90 @@ static void test_token_security_descriptor(void)
|
||||
|
||||
ret = SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd);
|
||||
ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ /* changing the label of the security descriptor does not change the integrity level of the token itself */
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
|
||||
+ "Expected medium or high integrity level\n");
|
||||
+
|
||||
+ /* restricting / duplicating a token resets the mandatory sd label */
|
||||
+ ret = CreateRestrictedToken(token, 0, 0, NULL, 0, NULL, 0, NULL, &token4);
|
||||
+ ok(ret, "CreateRestrictedToken failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
|
||||
+ "Expected medium or high integrity level\n");
|
||||
+
|
||||
+ size = 0;
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+
|
||||
+ if (sacl)
|
||||
+ {
|
||||
+ ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
+ ok(EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level),
|
||||
+ "Low integrity level should not have been inherited\n");
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd3);
|
||||
+ CloseHandle(token4);
|
||||
+
|
||||
+ ret = DuplicateTokenEx(token, 0, NULL, 0, TokenPrimary, &token4);
|
||||
+ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL*) buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
|
||||
+ "Expected medium or high integrity level\n");
|
||||
+
|
||||
+ size = 0;
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
+ todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ sacl = NULL;
|
||||
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
+ todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+
|
||||
+ if (sacl)
|
||||
+ {
|
||||
+ ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
+ ok(EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level),
|
||||
+ "Low integrity level should not have been inherited\n");
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd3);
|
||||
+ CloseHandle(token4);
|
||||
}
|
||||
else
|
||||
win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
|
||||
@@ -7467,6 +7736,116 @@ static void test_child_token_sd(void)
|
||||
HeapFree(GetProcessHeap(), 0, sd);
|
||||
}
|
||||
|
||||
+static void test_child_token_sd_restricted(void)
|
||||
+{
|
||||
+ static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
+ {SECURITY_MANDATORY_HIGH_RID}};
|
||||
+ SYSTEM_MANDATORY_LABEL_ACE *ace_label;
|
||||
+ BOOL ret, present, defaulted;
|
||||
+ TOKEN_MANDATORY_LABEL *tml;
|
||||
+ BYTE buffer_integrity[64];
|
||||
+ SECURITY_DESCRIPTOR *sd;
|
||||
+ HANDLE token;
|
||||
+ DWORD size;
|
||||
+ ACL *acl;
|
||||
+
|
||||
+ if (!pAddMandatoryAce)
|
||||
+ {
|
||||
+ win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
|
||||
+ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size);
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ acl = NULL;
|
||||
+ present = FALSE;
|
||||
+ defaulted = TRUE;
|
||||
+ ret = GetSecurityDescriptorSacl(sd, &present, &acl, &defaulted);
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ ok(present, "SACL not present\n");
|
||||
+ ok(acl && acl != (void *)0xdeadbeef, "Got invalid SACL\n");
|
||||
+ ok(!defaulted, "SACL defaulted\n");
|
||||
+ ok(acl->AceCount == 1, "Expected exactly one ACE\n");
|
||||
+ ret = pGetAce(acl, 0, (void **)&ace_label);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace_label->Header.AceType);
|
||||
+ ok(EqualSid(&ace_label->SidStart, &high_level),
|
||||
+ "Expected high integrity level\n");
|
||||
+
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ ok(EqualSid(tml->Label.Sid, &high_level), "Expected high integrity level\n");
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd);
|
||||
+}
|
||||
+
|
||||
+static void test_child_token_sd_medium(void)
|
||||
+{
|
||||
+ static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
+ {SECURITY_MANDATORY_MEDIUM_RID}};
|
||||
+ SYSTEM_MANDATORY_LABEL_ACE *ace_label;
|
||||
+ BOOL ret, present, defaulted;
|
||||
+ TOKEN_MANDATORY_LABEL *tml;
|
||||
+ BYTE buffer_integrity[64];
|
||||
+ SECURITY_DESCRIPTOR *sd;
|
||||
+ HANDLE token;
|
||||
+ DWORD size;
|
||||
+ ACL *acl;
|
||||
+
|
||||
+ if (!pAddMandatoryAce)
|
||||
+ {
|
||||
+ win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
|
||||
+ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
|
||||
+
|
||||
+ sd = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size);
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+
|
||||
+ acl = NULL;
|
||||
+ present = FALSE;
|
||||
+ defaulted = TRUE;
|
||||
+ ret = GetSecurityDescriptorSacl(sd, &present, &acl, &defaulted);
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ ok(present, "SACL not present\n");
|
||||
+ ok(acl && acl != (void *)0xdeadbeef, "Got invalid SACL\n");
|
||||
+ ok(!defaulted, "SACL defaulted\n");
|
||||
+ ok(acl->AceCount == 1, "Expected exactly one ACE\n");
|
||||
+ ret = pGetAce(acl, 0, (void **)&ace_label);
|
||||
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
+ ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
+ "Unexpected ACE type %#x\n", ace_label->Header.AceType);
|
||||
+ todo_wine ok(EqualSid(&ace_label->SidStart, &medium_level),
|
||||
+ "Expected medium integrity level\n");
|
||||
+
|
||||
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
+ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
+ todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, sd);
|
||||
+}
|
||||
+
|
||||
static void test_GetExplicitEntriesFromAclW(void)
|
||||
{
|
||||
static const WCHAR wszCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'};
|
||||
@@ -7653,6 +8032,10 @@ START_TEST(security)
|
||||
{
|
||||
if (!strcmp(myARGV[2], "test_token_sd"))
|
||||
test_child_token_sd();
|
||||
+ else if (!strcmp(myARGV[2], "test_token_sd_restricted"))
|
||||
+ test_child_token_sd_restricted();
|
||||
+ else if (!strcmp(myARGV[2], "test_token_sd_medium"))
|
||||
+ test_child_token_sd_medium();
|
||||
else
|
||||
test_process_security_child();
|
||||
return;
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,136 @@
|
||||
From 4b428e09733605affb987d369f56ec09d2525858 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 00:26:03 +0200
|
||||
Subject: server: Implement token elevation information.
|
||||
|
||||
---
|
||||
dlls/ntdll/nt.c | 16 ++++++++++++----
|
||||
server/protocol.def | 8 ++++++++
|
||||
server/token.c | 22 +++++++++++++++++++---
|
||||
3 files changed, 39 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
|
||||
index 5822dec9b15..dda6cabe1cf 100644
|
||||
--- a/dlls/ntdll/nt.c
|
||||
+++ b/dlls/ntdll/nt.c
|
||||
@@ -597,18 +597,26 @@ NTSTATUS WINAPI NtQueryInformationToken(
|
||||
SERVER_END_REQ;
|
||||
break;
|
||||
case TokenElevationType:
|
||||
+ SERVER_START_REQ( get_token_elevation_type )
|
||||
{
|
||||
TOKEN_ELEVATION_TYPE *elevation_type = tokeninfo;
|
||||
- FIXME("QueryInformationToken( ..., TokenElevationType, ...) semi-stub\n");
|
||||
- *elevation_type = TokenElevationTypeFull;
|
||||
+ req->handle = wine_server_obj_handle( token );
|
||||
+ status = wine_server_call( req );
|
||||
+ if (status == STATUS_SUCCESS)
|
||||
+ *elevation_type = reply->elevation;
|
||||
}
|
||||
+ SERVER_END_REQ;
|
||||
break;
|
||||
case TokenElevation:
|
||||
+ SERVER_START_REQ( get_token_elevation_type )
|
||||
{
|
||||
TOKEN_ELEVATION *elevation = tokeninfo;
|
||||
- FIXME("QueryInformationToken( ..., TokenElevation, ...) semi-stub\n");
|
||||
- elevation->TokenIsElevated = TRUE;
|
||||
+ req->handle = wine_server_obj_handle( token );
|
||||
+ status = wine_server_call( req );
|
||||
+ if (status == STATUS_SUCCESS)
|
||||
+ elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull);
|
||||
}
|
||||
+ SERVER_END_REQ;
|
||||
break;
|
||||
case TokenSessionId:
|
||||
{
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index b3dce66eb9c..33f1d5f0ab8 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3673,6 +3673,14 @@ struct handle_info
|
||||
@END
|
||||
|
||||
|
||||
+/* Get elevation level of token */
|
||||
+@REQ(get_token_elevation_type)
|
||||
+ obj_handle_t handle; /* handle to the object */
|
||||
+@REPLY
|
||||
+ unsigned int elevation; /* elevation level */
|
||||
+@END
|
||||
+
|
||||
+
|
||||
/* Create I/O completion port */
|
||||
@REQ(create_completion)
|
||||
unsigned int access; /* desired access to a port */
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index 7ab0f634c05..6a1085bae12 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -126,6 +126,7 @@ struct token
|
||||
ACL *default_dacl; /* the default DACL to assign to objects created by this user */
|
||||
TOKEN_SOURCE source; /* source of the token */
|
||||
int impersonation_level; /* impersonation level this token is capable of if non-primary token */
|
||||
+ TOKEN_ELEVATION_TYPE elevation; /* elevation level */
|
||||
};
|
||||
|
||||
struct privilege
|
||||
@@ -566,7 +567,7 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
|
||||
const ACL *default_dacl, TOKEN_SOURCE source,
|
||||
const luid_t *modified_id,
|
||||
- int impersonation_level )
|
||||
+ int impersonation_level, TOKEN_ELEVATION_TYPE elevation )
|
||||
{
|
||||
struct token *token = alloc_object( &token_ops );
|
||||
if (token)
|
||||
@@ -588,6 +589,7 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
token->impersonation_level = impersonation_level;
|
||||
token->default_dacl = NULL;
|
||||
token->primary_group = NULL;
|
||||
+ token->elevation = elevation;
|
||||
|
||||
/* copy user */
|
||||
token->user = memdup( user, security_sid_len( user ));
|
||||
@@ -700,7 +702,8 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
token = create_token( primary, src_token->user, NULL, 0,
|
||||
NULL, 0, src_token->default_dacl,
|
||||
src_token->source, modified_id,
|
||||
- impersonation_level );
|
||||
+ impersonation_level,
|
||||
+ src_token->elevation );
|
||||
if (!token) return token;
|
||||
|
||||
/* copy groups */
|
||||
@@ -904,7 +907,7 @@ struct token *token_create_admin( void )
|
||||
static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
|
||||
token = create_token( TRUE, user_sid, admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
|
||||
admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]), default_dacl,
|
||||
- admin_source, NULL, -1 );
|
||||
+ admin_source, NULL, -1, TokenElevationTypeFull );
|
||||
/* we really need a primary group */
|
||||
assert( token->primary_group );
|
||||
}
|
||||
@@ -1652,6 +1655,19 @@ DECL_HANDLER(get_token_statistics)
|
||||
}
|
||||
}
|
||||
|
||||
+DECL_HANDLER(get_token_elevation_type)
|
||||
+{
|
||||
+ struct token *token;
|
||||
+
|
||||
+ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
|
||||
+ TOKEN_QUERY,
|
||||
+ &token_ops )))
|
||||
+ {
|
||||
+ reply->elevation = token->elevation;
|
||||
+ release_object( token );
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
DECL_HANDLER(get_token_default_dacl)
|
||||
{
|
||||
struct token *token;
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,81 @@
|
||||
From 7e73f449d158f0d6a6b6b421d073dbaf1741e1c7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 02:22:11 +0200
|
||||
Subject: server: Correctly treat zero access mask in duplicate_token
|
||||
wineserver call.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 14 +++++++-------
|
||||
server/token.c | 3 ++-
|
||||
2 files changed, 9 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 4a03db27e69..f1a64e29dea 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -7438,7 +7438,7 @@ static void test_token_security_descriptor(void)
|
||||
ret = DuplicateTokenEx(token4, 0, NULL, SecurityImpersonation, TokenImpersonation, &token5);
|
||||
ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
|
||||
ret = SetThreadToken(NULL, token5);
|
||||
- todo_wine ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
|
||||
+ ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
|
||||
CloseHandle(token4);
|
||||
|
||||
/* Restrict current process token while impersonating a medium integrity token */
|
||||
@@ -7503,16 +7503,16 @@ static void test_token_security_descriptor(void)
|
||||
|
||||
size = 0;
|
||||
ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
- todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
"Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
|
||||
sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
- todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
|
||||
sacl = NULL;
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
- todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
@@ -7606,16 +7606,16 @@ static void test_token_security_descriptor(void)
|
||||
|
||||
size = 0;
|
||||
ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
- todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
"Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
|
||||
|
||||
sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
|
||||
- todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
+ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
|
||||
|
||||
sacl = NULL;
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
- todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index 6a1085bae12..292e1df80fd 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -1376,7 +1376,8 @@ DECL_HANDLER(duplicate_token)
|
||||
struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
|
||||
if (token)
|
||||
{
|
||||
- reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes );
|
||||
+ unsigned int access = req->access ? req->access : get_handle_access( current->process, req->handle );
|
||||
+ reply->new_handle = alloc_handle_no_access_check( current->process, token, access, objattr->attributes );
|
||||
release_object( token );
|
||||
}
|
||||
release_object( src_token );
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,153 @@
|
||||
From 3092c9de3ac89e77a139db97a33b8b15f9a12eac Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 02:28:35 +0200
|
||||
Subject: server: Implement token integrity level.
|
||||
|
||||
---
|
||||
dlls/ntdll/nt.c | 23 ++++++++++++++---------
|
||||
server/protocol.def | 7 +++++++
|
||||
server/token.c | 30 +++++++++++++++++++++++++++---
|
||||
3 files changed, 48 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
|
||||
index dda6cabe1cf..6f2b24e6ba4 100644
|
||||
--- a/dlls/ntdll/nt.c
|
||||
+++ b/dlls/ntdll/nt.c
|
||||
@@ -372,7 +372,7 @@ NTSTATUS WINAPI NtQueryInformationToken(
|
||||
0, /* TokenAccessInformation */
|
||||
0, /* TokenVirtualizationAllowed */
|
||||
0, /* TokenVirtualizationEnabled */
|
||||
- sizeof(TOKEN_MANDATORY_LABEL) + sizeof(SID), /* TokenIntegrityLevel [sizeof(SID) includes one SubAuthority] */
|
||||
+ 0, /* TokenIntegrityLevel */
|
||||
0, /* TokenUIAccess */
|
||||
0, /* TokenMandatoryPolicy */
|
||||
sizeof(TOKEN_GROUPS) + sizeof(logon_sid), /* TokenLogonSid */
|
||||
@@ -625,18 +625,23 @@ NTSTATUS WINAPI NtQueryInformationToken(
|
||||
}
|
||||
break;
|
||||
case TokenIntegrityLevel:
|
||||
+ SERVER_START_REQ( get_token_integrity )
|
||||
{
|
||||
- /* report always "S-1-16-12288" (high mandatory level) for now */
|
||||
- static const SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
|
||||
- {SECURITY_MANDATORY_HIGH_RID}};
|
||||
-
|
||||
TOKEN_MANDATORY_LABEL *tml = tokeninfo;
|
||||
- PSID psid = tml + 1;
|
||||
+ PSID sid = tml + 1;
|
||||
+ DWORD sid_len = tokeninfolength < sizeof(*tml) ? 0 : tokeninfolength - sizeof(*tml);
|
||||
|
||||
- tml->Label.Sid = psid;
|
||||
- tml->Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
|
||||
- memcpy(psid, &high_level, sizeof(SID));
|
||||
+ req->handle = wine_server_obj_handle( token );
|
||||
+ wine_server_set_reply( req, sid, sid_len );
|
||||
+ status = wine_server_call( req );
|
||||
+ if (retlen) *retlen = reply->sid_len + sizeof(*tml);
|
||||
+ if (status == STATUS_SUCCESS)
|
||||
+ {
|
||||
+ tml->Label.Sid = sid;
|
||||
+ tml->Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
|
||||
+ }
|
||||
}
|
||||
+ SERVER_END_REQ;
|
||||
break;
|
||||
case TokenAppContainerSid:
|
||||
{
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index 33f1d5f0ab8..ac2e2242511 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3424,6 +3424,13 @@ enum caret_state
|
||||
VARARG(sid,SID); /* the sid specified by which_sid from the token */
|
||||
@END
|
||||
|
||||
+@REQ(get_token_integrity)
|
||||
+ obj_handle_t handle; /* handle to the token */
|
||||
+@REPLY
|
||||
+ data_size_t sid_len; /* length needed to store sid */
|
||||
+ VARARG(sid,SID); /* the integrity sid */
|
||||
+@END
|
||||
+
|
||||
@REQ(get_token_groups)
|
||||
obj_handle_t handle; /* handle to the token */
|
||||
@REPLY
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index 292e1df80fd..8d2de6ab58e 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -127,6 +127,7 @@ struct token
|
||||
TOKEN_SOURCE source; /* source of the token */
|
||||
int impersonation_level; /* impersonation level this token is capable of if non-primary token */
|
||||
TOKEN_ELEVATION_TYPE elevation; /* elevation level */
|
||||
+ const SID *integrity; /* token integrity */
|
||||
};
|
||||
|
||||
struct privilege
|
||||
@@ -567,7 +568,8 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
|
||||
const ACL *default_dacl, TOKEN_SOURCE source,
|
||||
const luid_t *modified_id,
|
||||
- int impersonation_level, TOKEN_ELEVATION_TYPE elevation )
|
||||
+ int impersonation_level, TOKEN_ELEVATION_TYPE elevation,
|
||||
+ const SID *integrity )
|
||||
{
|
||||
struct token *token = alloc_object( &token_ops );
|
||||
if (token)
|
||||
@@ -648,6 +650,7 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
}
|
||||
|
||||
token->source = source;
|
||||
+ token->integrity = integrity;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
@@ -703,7 +706,8 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
NULL, 0, src_token->default_dacl,
|
||||
src_token->source, modified_id,
|
||||
impersonation_level,
|
||||
- src_token->elevation );
|
||||
+ src_token->elevation,
|
||||
+ src_token->integrity );
|
||||
if (!token) return token;
|
||||
|
||||
/* copy groups */
|
||||
@@ -907,7 +911,7 @@ struct token *token_create_admin( void )
|
||||
static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
|
||||
token = create_token( TRUE, user_sid, admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
|
||||
admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]), default_dacl,
|
||||
- admin_source, NULL, -1, TokenElevationTypeFull );
|
||||
+ admin_source, NULL, -1, TokenElevationTypeFull, &high_label_sid );
|
||||
/* we really need a primary group */
|
||||
assert( token->primary_group );
|
||||
}
|
||||
@@ -1550,6 +1554,26 @@ DECL_HANDLER(get_token_sid)
|
||||
}
|
||||
}
|
||||
|
||||
+/* retrieves the integrity sid */
|
||||
+DECL_HANDLER(get_token_integrity)
|
||||
+{
|
||||
+ struct token *token;
|
||||
+
|
||||
+ reply->sid_len = 0;
|
||||
+
|
||||
+ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
|
||||
+ TOKEN_QUERY,
|
||||
+ &token_ops )))
|
||||
+ {
|
||||
+ reply->sid_len = security_sid_len( token->integrity );
|
||||
+ if (reply->sid_len <= get_reply_max_size())
|
||||
+ set_reply_data( token->integrity, reply->sid_len );
|
||||
+ else
|
||||
+ set_error( STATUS_BUFFER_TOO_SMALL );
|
||||
+ release_object( token );
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* retrieves the groups that the user represented by the token belongs to */
|
||||
DECL_HANDLER(get_token_groups)
|
||||
{
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,46 @@
|
||||
From 77c9e6c6f408a2b59a79f3773a379a43b6994f2c Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 6 Aug 2017 15:16:33 +0200
|
||||
Subject: server: Use all group attributes in create_token.
|
||||
|
||||
---
|
||||
server/token.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index 8d2de6ab58e..e61fe97bfa0 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -613,13 +613,13 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
return NULL;
|
||||
}
|
||||
memcpy( &group->sid, groups[i].Sid, security_sid_len( groups[i].Sid ));
|
||||
- group->enabled = TRUE;
|
||||
- group->def = TRUE;
|
||||
- group->logon = (groups[i].Attributes & SE_GROUP_LOGON_ID) != 0;
|
||||
group->mandatory = (groups[i].Attributes & SE_GROUP_MANDATORY) != 0;
|
||||
- group->owner = (groups[i].Attributes & SE_GROUP_OWNER) != 0;
|
||||
- group->resource = FALSE;
|
||||
- group->deny_only = FALSE;
|
||||
+ group->def = (groups[i].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) != 0;
|
||||
+ group->enabled = (groups[i].Attributes & SE_GROUP_ENABLED) != 0;
|
||||
+ group->owner = (groups[i].Attributes & SE_GROUP_OWNER) != 0;
|
||||
+ group->deny_only = (groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) != 0;
|
||||
+ group->logon = (groups[i].Attributes & SE_GROUP_LOGON_ID) != 0;
|
||||
+ group->resource = (groups[i].Attributes & SE_GROUP_RESOURCE) != 0;
|
||||
list_add_tail( &token->groups, &group->entry );
|
||||
/* Use first owner capable group as an owner */
|
||||
if (!token->primary_group && group->owner)
|
||||
@@ -1628,8 +1628,8 @@ DECL_HANDLER(get_token_groups)
|
||||
if (group->enabled) *attr_ptr |= SE_GROUP_ENABLED;
|
||||
if (group->owner) *attr_ptr |= SE_GROUP_OWNER;
|
||||
if (group->deny_only) *attr_ptr |= SE_GROUP_USE_FOR_DENY_ONLY;
|
||||
- if (group->resource) *attr_ptr |= SE_GROUP_RESOURCE;
|
||||
if (group->logon) *attr_ptr |= SE_GROUP_LOGON_ID;
|
||||
+ if (group->resource) *attr_ptr |= SE_GROUP_RESOURCE;
|
||||
|
||||
memcpy(sid_ptr, &group->sid, security_sid_len( &group->sid ));
|
||||
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,218 @@
|
||||
From fcceb1b0f1aee4ca4fe7362a4e87c4c94456f2ec Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 01:45:29 +0200
|
||||
Subject: ntdll: Add function to create new tokens for elevation purposes.
|
||||
|
||||
---
|
||||
dlls/ntdll/ntdll.spec | 3 ++
|
||||
dlls/ntdll/ntdll_misc.h | 3 ++
|
||||
dlls/ntdll/process.c | 18 +++++++++++
|
||||
server/protocol.def | 8 +++++
|
||||
server/security.h | 1 +
|
||||
server/token.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
6 files changed, 117 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
||||
index 275fda57970..8f5357b944c 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -1487,6 +1487,9 @@
|
||||
@ cdecl wine_server_send_fd(long)
|
||||
@ cdecl __wine_make_process_system()
|
||||
|
||||
+# Token
|
||||
+@ cdecl __wine_create_default_token(long)
|
||||
+
|
||||
# Version
|
||||
@ cdecl wine_get_version() NTDLL_wine_get_version
|
||||
@ cdecl wine_get_patches() NTDLL_wine_get_patches
|
||||
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
|
||||
index c6c60090d10..e64cb9e75a3 100644
|
||||
--- a/dlls/ntdll/ntdll_misc.h
|
||||
+++ b/dlls/ntdll/ntdll_misc.h
|
||||
@@ -82,6 +82,9 @@ extern void fill_cpu_info(void) DECLSPEC_HIDDEN;
|
||||
extern void *grow_virtual_heap( HANDLE handle, SIZE_T *size ) DECLSPEC_HIDDEN;
|
||||
extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN;
|
||||
|
||||
+/* token */
|
||||
+extern HANDLE CDECL __wine_create_default_token(BOOL admin);
|
||||
+
|
||||
/* server support */
|
||||
extern timeout_t server_start_time DECLSPEC_HIDDEN;
|
||||
extern unsigned int server_cpus DECLSPEC_HIDDEN;
|
||||
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
|
||||
index f2eb09c142f..ba4613e87b3 100644
|
||||
--- a/dlls/ntdll/process.c
|
||||
+++ b/dlls/ntdll/process.c
|
||||
@@ -99,6 +99,24 @@ HANDLE CDECL __wine_make_process_system(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/***********************************************************************
|
||||
+ * __wine_create_default_token (NTDLL.@)
|
||||
+ *
|
||||
+ * Creates a default limited or admin token.
|
||||
+ */
|
||||
+HANDLE CDECL __wine_create_default_token( BOOL admin )
|
||||
+{
|
||||
+ HANDLE ret = NULL;
|
||||
+ SERVER_START_REQ( create_token )
|
||||
+ {
|
||||
+ req->admin = admin;
|
||||
+ if (!wine_server_call( req ))
|
||||
+ ret = wine_server_ptr_handle( reply->token );
|
||||
+ }
|
||||
+ SERVER_END_REQ;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static UINT process_error_mode;
|
||||
|
||||
#define UNIMPLEMENTED_INFO_CLASS(c) \
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index ac2e2242511..300f23fb9b6 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3688,6 +3688,14 @@ struct handle_info
|
||||
@END
|
||||
|
||||
|
||||
+/* Create a new token */
|
||||
+@REQ(create_token)
|
||||
+ unsigned int admin; /* admin or limited token */
|
||||
+@REPLY
|
||||
+ obj_handle_t token; /* handle for new token */
|
||||
+@END
|
||||
+
|
||||
+
|
||||
/* Create I/O completion port */
|
||||
@REQ(create_completion)
|
||||
unsigned int access; /* desired access to a port */
|
||||
diff --git a/server/security.h b/server/security.h
|
||||
index 6c337143c3d..21e90ccf23f 100644
|
||||
--- a/server/security.h
|
||||
+++ b/server/security.h
|
||||
@@ -49,6 +49,7 @@ extern const PSID security_builtin_users_sid;
|
||||
extern const PSID security_builtin_admins_sid;
|
||||
extern const PSID security_domain_users_sid;
|
||||
extern const PSID security_high_label_sid;
|
||||
+extern const PSID security_medium_label_sid;
|
||||
|
||||
|
||||
/* token functions */
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index e61fe97bfa0..c9d36a5b4f3 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -71,6 +71,7 @@ static const SID anonymous_logon_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORIT
|
||||
static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } };
|
||||
static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } };
|
||||
static const SID high_label_sid = { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY }, { SECURITY_MANDATORY_HIGH_RID } };
|
||||
+static const SID medium_label_sid = { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY }, { SECURITY_MANDATORY_MEDIUM_RID } };
|
||||
static const struct /* same fields as struct SID */
|
||||
{
|
||||
BYTE Revision;
|
||||
@@ -110,6 +111,7 @@ const PSID security_builtin_admins_sid = (PSID)&builtin_admins_sid;
|
||||
const PSID security_builtin_users_sid = (PSID)&builtin_users_sid;
|
||||
const PSID security_domain_users_sid = (PSID)&domain_users_sid;
|
||||
const PSID security_high_label_sid = (PSID)&high_label_sid;
|
||||
+const PSID security_medium_label_sid = (PSID)&medium_label_sid;
|
||||
|
||||
static luid_t prev_luid_value = { 1000, 0 };
|
||||
|
||||
@@ -924,6 +926,64 @@ struct token *token_create_admin( void )
|
||||
return token;
|
||||
}
|
||||
|
||||
+static struct token *token_create_limited( void )
|
||||
+{
|
||||
+ struct token *token = NULL;
|
||||
+ static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY };
|
||||
+ static const unsigned int alias_admins_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS };
|
||||
+ static const unsigned int alias_users_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS };
|
||||
+ /* on Windows, this value changes every time the user logs on */
|
||||
+ static const unsigned int logon_subauth[] = { SECURITY_LOGON_IDS_RID, 0, 1 /* FIXME: should be randomly generated when tokens are inherited by new processes */ };
|
||||
+ PSID alias_admins_sid;
|
||||
+ PSID alias_users_sid;
|
||||
+ PSID logon_sid;
|
||||
+ const SID *user_sid = security_unix_uid_to_sid( getuid() );
|
||||
+ ACL *default_dacl = create_default_dacl( user_sid );
|
||||
+
|
||||
+ alias_admins_sid = security_sid_alloc( &nt_authority, sizeof(alias_admins_subauth)/sizeof(alias_admins_subauth[0]),
|
||||
+ alias_admins_subauth );
|
||||
+ alias_users_sid = security_sid_alloc( &nt_authority, sizeof(alias_users_subauth)/sizeof(alias_users_subauth[0]),
|
||||
+ alias_users_subauth );
|
||||
+ logon_sid = security_sid_alloc( &nt_authority, sizeof(logon_subauth)/sizeof(logon_subauth[0]),
|
||||
+ logon_subauth );
|
||||
+
|
||||
+ if (alias_admins_sid && alias_users_sid && logon_sid && default_dacl)
|
||||
+ {
|
||||
+ const LUID_AND_ATTRIBUTES user_privs[] =
|
||||
+ {
|
||||
+ { SeChangeNotifyPrivilege , SE_PRIVILEGE_ENABLED },
|
||||
+ { SeShutdownPrivilege , 0 },
|
||||
+ { SeUndockPrivilege , 0 },
|
||||
+ };
|
||||
+ /* note: we don't include non-builtin groups here for the user -
|
||||
+ * telling us these is the job of a client-side program */
|
||||
+ const SID_AND_ATTRIBUTES user_groups[] =
|
||||
+ {
|
||||
+ { security_world_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
|
||||
+ { security_local_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
|
||||
+ { security_interactive_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
|
||||
+ { security_authenticated_user_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
|
||||
+ { security_domain_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_OWNER },
|
||||
+ { alias_admins_sid, SE_GROUP_USE_FOR_DENY_ONLY },
|
||||
+ { alias_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
|
||||
+ { logon_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_LOGON_ID },
|
||||
+ };
|
||||
+ static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
|
||||
+ token = create_token( TRUE, user_sid, user_groups, sizeof(user_groups)/sizeof(user_groups[0]),
|
||||
+ user_privs, sizeof(user_privs)/sizeof(user_privs[0]), default_dacl,
|
||||
+ admin_source, NULL, -1, TokenElevationTypeLimited, &medium_label_sid );
|
||||
+ /* we really need a primary group */
|
||||
+ assert( token->primary_group );
|
||||
+ }
|
||||
+
|
||||
+ free( logon_sid );
|
||||
+ free( alias_admins_sid );
|
||||
+ free( alias_users_sid );
|
||||
+ free( default_dacl );
|
||||
+
|
||||
+ return token;
|
||||
+}
|
||||
+
|
||||
static struct privilege *token_find_privilege( struct token *token, const LUID *luid, int enabled_only )
|
||||
{
|
||||
struct privilege *privilege;
|
||||
@@ -1738,3 +1798,27 @@ DECL_HANDLER(set_token_default_dacl)
|
||||
release_object( token );
|
||||
}
|
||||
}
|
||||
+
|
||||
+DECL_HANDLER(create_token)
|
||||
+{
|
||||
+ struct token *token;
|
||||
+ PSID label;
|
||||
+
|
||||
+ if (req->admin)
|
||||
+ {
|
||||
+ token = token_create_admin();
|
||||
+ label = security_high_label_sid;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ token = token_create_limited();
|
||||
+ label = security_medium_label_sid;
|
||||
+ }
|
||||
+
|
||||
+ if (token)
|
||||
+ {
|
||||
+ if (token_assign_label( token, label ))
|
||||
+ reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
|
||||
+ release_object( token );
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,66 @@
|
||||
From cf24ca0854a5b0dca2055f0991fd9a932125c65e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 02:03:20 +0200
|
||||
Subject: shell32: Implement process elevation using runas verb.
|
||||
|
||||
---
|
||||
dlls/shell32/shlexec.c | 22 ++++++++++++++++++++--
|
||||
1 file changed, 20 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c
|
||||
index 0cf112b6373..af50078dbca 100644
|
||||
--- a/dlls/shell32/shlexec.c
|
||||
+++ b/dlls/shell32/shlexec.c
|
||||
@@ -50,6 +50,8 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(exec);
|
||||
|
||||
+extern HANDLE CDECL __wine_create_default_token(BOOL admin);
|
||||
+
|
||||
static const WCHAR wszOpen[] = {'o','p','e','n',0};
|
||||
static const WCHAR wszExe[] = {'.','e','x','e',0};
|
||||
static const WCHAR wszILPtr[] = {':','%','p',0};
|
||||
@@ -312,6 +314,8 @@ static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR psz
|
||||
static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
|
||||
const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
|
||||
{
|
||||
+ static WCHAR runasW[] = {'r','u','n','a','s',0};
|
||||
+ HANDLE token = NULL;
|
||||
STARTUPINFOW startup;
|
||||
PROCESS_INFORMATION info;
|
||||
UINT_PTR retval = SE_ERR_NOASSOC;
|
||||
@@ -344,8 +348,20 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
|
||||
dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
|
||||
if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
|
||||
dwCreationFlags |= CREATE_NEW_CONSOLE;
|
||||
- if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
|
||||
- lpDirectory, &startup, &info))
|
||||
+
|
||||
+ /* Spawning a process with runas verb means that the process should be
|
||||
+ * executed with admin rights. This function ignores the manifest data,
|
||||
+ * and allows programs to elevate rights on-demand. On Windows a complex
|
||||
+ * RPC menchanism is used, using CreateProcessAsUser would fail because
|
||||
+ * it can only be used to drop rights. */
|
||||
+ if (psei->lpVerb && !strcmpiW(psei->lpVerb, runasW))
|
||||
+ {
|
||||
+ if (!(token = __wine_create_default_token(TRUE)))
|
||||
+ ERR("Failed to create admin token\n");
|
||||
+ }
|
||||
+
|
||||
+ if (CreateProcessAsUserW(token, NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE,
|
||||
+ dwCreationFlags, env, lpDirectory, &startup, &info))
|
||||
{
|
||||
/* Give 30 seconds to the app to come up, if desired. Probably only needed
|
||||
when starting app immediately before making a DDE connection. */
|
||||
@@ -365,6 +381,8 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
|
||||
retval = ERROR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
+ if (token) CloseHandle(token);
|
||||
+
|
||||
TRACE("returning %lu\n", retval);
|
||||
|
||||
psei_out->hInstApp = (HINSTANCE)retval;
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,149 @@
|
||||
From 7b7147df179554c5701f5d759a7b161d79ef90f3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 03:39:55 +0200
|
||||
Subject: ntdll: Implement process token elevation through manifests.
|
||||
|
||||
---
|
||||
dlls/ntdll/loader.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
server/process.c | 8 ++++++++
|
||||
server/process.h | 1 +
|
||||
server/protocol.def | 7 +++++++
|
||||
server/token.c | 14 ++++++++++++++
|
||||
5 files changed, 67 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
|
||||
index a09eca9db75..2f6bcbde8fe 100644
|
||||
--- a/dlls/ntdll/loader.c
|
||||
+++ b/dlls/ntdll/loader.c
|
||||
@@ -3632,6 +3632,32 @@ static void load_global_options(void)
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
+ * elevate_process
|
||||
+ */
|
||||
+static void elevate_process( void )
|
||||
+{
|
||||
+ NTSTATUS status;
|
||||
+ HANDLE token;
|
||||
+
|
||||
+ if (!(token = __wine_create_default_token( TRUE )))
|
||||
+ {
|
||||
+ ERR( "Failed to create admin token\n" );
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ SERVER_START_REQ( replace_process_token )
|
||||
+ {
|
||||
+ req->token = wine_server_obj_handle( token );
|
||||
+ if ((status = wine_server_call( req )))
|
||||
+ ERR( "Failed to replace process token: %08x\n", status );
|
||||
+ }
|
||||
+ SERVER_END_REQ;
|
||||
+
|
||||
+ NtClose( token );
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/***********************************************************************
|
||||
* start_process
|
||||
*/
|
||||
static void start_process( void *arg )
|
||||
@@ -3679,6 +3705,7 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
|
||||
ULONG_PTR unknown3, ULONG_PTR unknown4 )
|
||||
{
|
||||
static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
|
||||
+ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION runlevel;
|
||||
LARGE_INTEGER timeout;
|
||||
NTSTATUS status;
|
||||
WINE_MODREF *wm;
|
||||
@@ -3725,6 +3752,16 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
|
||||
if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
|
||||
heap_set_debug_flags( GetProcessHeap() );
|
||||
|
||||
+ /* elevate process if necessary */
|
||||
+ status = RtlQueryInformationActivationContext( 0, NULL, 0, RunlevelInformationInActivationContext,
|
||||
+ &runlevel, sizeof(runlevel), NULL );
|
||||
+ if (!status && (runlevel.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE ||
|
||||
+ runlevel.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN))
|
||||
+ {
|
||||
+ TRACE( "Application requested admin rights (run level %d)\n", runlevel.RunLevel );
|
||||
+ elevate_process(); /* FIXME: the process exists with a wrong token for a short time */
|
||||
+ }
|
||||
+
|
||||
/* Store original entrypoint (in case it gets corrupted) */
|
||||
start_params.kernel_start = kernel_start;
|
||||
start_params.entry = wm->ldr.EntryPoint;
|
||||
diff --git a/server/process.c b/server/process.c
|
||||
index f0f60edcd3f..74675d343b4 100644
|
||||
--- a/server/process.c
|
||||
+++ b/server/process.c
|
||||
@@ -1146,6 +1146,14 @@ struct process_snapshot *process_snap( int *count )
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
+/* replace the token of a process */
|
||||
+void replace_process_token( struct process *process, struct token *new_token )
|
||||
+{
|
||||
+ release_object(current->process->token);
|
||||
+ current->process->token = new_token;
|
||||
+ grab_object(new_token);
|
||||
+}
|
||||
+
|
||||
/* create a new process */
|
||||
DECL_HANDLER(new_process)
|
||||
{
|
||||
diff --git a/server/process.h b/server/process.h
|
||||
index 548796f9c22..262eb59627b 100644
|
||||
--- a/server/process.h
|
||||
+++ b/server/process.h
|
||||
@@ -137,6 +137,7 @@ extern void break_process( struct process *process );
|
||||
extern void detach_debugged_processes( struct thread *debugger );
|
||||
extern struct process_snapshot *process_snap( int *count );
|
||||
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
|
||||
+extern void replace_process_token( struct process *process, struct token *token );
|
||||
|
||||
/* console functions */
|
||||
extern void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin);
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index 300f23fb9b6..e5b598259f7 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3696,6 +3696,13 @@ struct handle_info
|
||||
@END
|
||||
|
||||
|
||||
+/* Create a new token */
|
||||
+@REQ(replace_process_token)
|
||||
+ obj_handle_t token; /* new process token */
|
||||
+@REPLY
|
||||
+@END
|
||||
+
|
||||
+
|
||||
/* Create I/O completion port */
|
||||
@REQ(create_completion)
|
||||
unsigned int access; /* desired access to a port */
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index c9d36a5b4f3..385ea3bbfda 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -1822,3 +1822,17 @@ DECL_HANDLER(create_token)
|
||||
release_object( token );
|
||||
}
|
||||
}
|
||||
+
|
||||
+/* Replaces the token of the current process */
|
||||
+DECL_HANDLER(replace_process_token)
|
||||
+{
|
||||
+ struct token *token;
|
||||
+
|
||||
+ if ((token = (struct token *)get_handle_obj( current->process, req->token,
|
||||
+ TOKEN_ASSIGN_PRIMARY,
|
||||
+ &token_ops )))
|
||||
+ {
|
||||
+ replace_process_token( current->process, token );
|
||||
+ release_object( token );
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,95 @@
|
||||
From 75dfd37e14223b28a023f098a90926ab40d078fc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 04:02:16 +0200
|
||||
Subject: kernel32: Implement CreateProcessInternalW.
|
||||
|
||||
---
|
||||
dlls/kernel32/kernel32.spec | 2 +-
|
||||
dlls/kernel32/process.c | 24 ++++++++++++++----------
|
||||
include/winbase.h | 1 +
|
||||
3 files changed, 16 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
|
||||
index 608a89da3bd..0b2879ddd33 100644
|
||||
--- a/dlls/kernel32/kernel32.spec
|
||||
+++ b/dlls/kernel32/kernel32.spec
|
||||
@@ -315,7 +315,7 @@
|
||||
@ stdcall CreateProcessA(str str ptr ptr long long ptr str ptr ptr)
|
||||
# @ stub CreateProcessAsUserW
|
||||
# @ stub CreateProcessInternalA
|
||||
-# @ stub CreateProcessInternalW
|
||||
+@ stdcall CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr)
|
||||
# @ stub CreateProcessInternalWSecure
|
||||
@ stdcall CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr)
|
||||
@ stdcall CreateRemoteThread(long ptr long ptr long long ptr)
|
||||
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
|
||||
index 00b93348855..cacdcb3b621 100644
|
||||
--- a/dlls/kernel32/process.c
|
||||
+++ b/dlls/kernel32/process.c
|
||||
@@ -2463,12 +2463,13 @@ static LPWSTR get_file_name( LPCWSTR appname, LPWSTR cmdline, LPWSTR buffer,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-
|
||||
-/* Steam hotpatches CreateProcessA and W, so to prevent it from crashing use an internal function */
|
||||
-static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
|
||||
- LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
|
||||
- LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
|
||||
- LPPROCESS_INFORMATION info )
|
||||
+/**********************************************************************
|
||||
+ * CreateProcessInternalW (KERNEL32.@)
|
||||
+ */
|
||||
+BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
|
||||
+ LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
|
||||
+ LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
|
||||
+ LPPROCESS_INFORMATION info, HANDLE *new_token )
|
||||
{
|
||||
BOOL retv = FALSE;
|
||||
HANDLE hFile = 0;
|
||||
@@ -2481,6 +2482,9 @@ static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_A
|
||||
|
||||
TRACE("app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
|
||||
|
||||
+ if (token) FIXME("Creating a process with a token is not yet implemented\n");
|
||||
+ if (new_token) FIXME("No support for returning created process token\n");
|
||||
+
|
||||
if (!(tidy_cmdline = get_file_name( app_name, cmd_line, name, sizeof(name)/sizeof(WCHAR),
|
||||
&hFile, &binary_info )))
|
||||
return FALSE;
|
||||
@@ -2632,8 +2636,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( LPCSTR app_name, LPSTR cmd_line, L
|
||||
FIXME("StartupInfo.lpReserved is used, please report (%s)\n",
|
||||
debugstr_a(startup_info->lpReserved));
|
||||
|
||||
- ret = create_process_impl( app_nameW, cmd_lineW, process_attr, thread_attr,
|
||||
- inherit, flags, env, cur_dirW, &infoW, info );
|
||||
+ ret = CreateProcessInternalW( NULL, app_nameW, cmd_lineW, process_attr, thread_attr,
|
||||
+ inherit, flags, env, cur_dirW, &infoW, info, NULL );
|
||||
done:
|
||||
HeapFree( GetProcessHeap(), 0, app_nameW );
|
||||
HeapFree( GetProcessHeap(), 0, cmd_lineW );
|
||||
@@ -2652,8 +2656,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line,
|
||||
LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
|
||||
LPPROCESS_INFORMATION info )
|
||||
{
|
||||
- return create_process_impl( app_name, cmd_line, process_attr, thread_attr,
|
||||
- inherit, flags, env, cur_dir, startup_info, info);
|
||||
+ return CreateProcessInternalW( NULL, app_name, cmd_line, process_attr, thread_attr,
|
||||
+ inherit, flags, env, cur_dir, startup_info, info, NULL);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/include/winbase.h b/include/winbase.h
|
||||
index 24efbd865ab..7982fa4a070 100644
|
||||
--- a/include/winbase.h
|
||||
+++ b/include/winbase.h
|
||||
@@ -1847,6 +1847,7 @@ WINBASEAPI BOOL WINAPI CreateProcessW(LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTE
|
||||
WINADVAPI BOOL WINAPI CreateProcessAsUserA(HANDLE,LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION);
|
||||
WINADVAPI BOOL WINAPI CreateProcessAsUserW(HANDLE,LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
|
||||
#define CreateProcessAsUser WINELIB_NAME_AW(CreateProcessAsUser)
|
||||
+WINBASEAPI BOOL WINAPI CreateProcessInternalW(HANDLE,LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION,HANDLE*);
|
||||
WINADVAPI BOOL WINAPI CreateProcessWithLogonW(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPCWSTR,LPWSTR,DWORD,LPVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
|
||||
WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE,LPSECURITY_ATTRIBUTES,SIZE_T,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD);
|
||||
WINBASEAPI HANDLE WINAPI CreateRemoteThreadEx(HANDLE,LPSECURITY_ATTRIBUTES,SIZE_T,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPPROC_THREAD_ATTRIBUTE_LIST,LPDWORD);
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,318 @@
|
||||
From 9709db4e722195a70c5950b78b445c71eac495af Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sun, 6 Aug 2017 02:08:05 +0200
|
||||
Subject: server: Implement support for creating processes using a token.
|
||||
|
||||
---
|
||||
dlls/kernel32/process.c | 33 ++++++++++++++++++---------------
|
||||
server/process.c | 29 +++++++++++++++++++++++++----
|
||||
server/process.h | 2 +-
|
||||
server/protocol.def | 1 +
|
||||
server/request.c | 2 +-
|
||||
server/security.h | 2 ++
|
||||
server/token.c | 11 +++++++++++
|
||||
7 files changed, 59 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
|
||||
index cacdcb3b621..3ae9d175a79 100644
|
||||
--- a/dlls/kernel32/process.c
|
||||
+++ b/dlls/kernel32/process.c
|
||||
@@ -2064,7 +2064,7 @@ static NTSTATUS create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_des
|
||||
* Create a new process. If hFile is a valid handle we have an exe
|
||||
* file, otherwise it is a Winelib app.
|
||||
*/
|
||||
-static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPWSTR env,
|
||||
+static BOOL create_process( HANDLE token, HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPWSTR env,
|
||||
LPCWSTR cur_dir, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
||||
BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
|
||||
LPPROCESS_INFORMATION info, LPCSTR unixdir,
|
||||
@@ -2210,6 +2210,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
|
||||
req->info_size = startup_info_size;
|
||||
req->env_size = (env_end - env) * sizeof(WCHAR);
|
||||
req->process_sd_size = process_sd_size;
|
||||
+ req->token = wine_server_obj_handle( token );
|
||||
|
||||
wine_server_add_data( req, startup_info, startup_info_size );
|
||||
wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) );
|
||||
@@ -2310,7 +2311,7 @@ error:
|
||||
*
|
||||
* Create a new VDM process for a 16-bit or DOS application.
|
||||
*/
|
||||
-static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, LPCWSTR cur_dir,
|
||||
+static BOOL create_vdm_process( HANDLE token, LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, LPCWSTR cur_dir,
|
||||
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
||||
BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
|
||||
LPPROCESS_INFORMATION info, LPCSTR unixdir,
|
||||
@@ -2334,7 +2335,7 @@ static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, L
|
||||
return FALSE;
|
||||
}
|
||||
sprintfW(new_cmd_line, argsW, winevdmW, buffer, cmd_line);
|
||||
- ret = create_process( 0, winevdmW, new_cmd_line, env, cur_dir, psa, tsa, inherit,
|
||||
+ ret = create_process( token, 0, winevdmW, new_cmd_line, env, cur_dir, psa, tsa, inherit,
|
||||
flags, startup, info, unixdir, binary_info, exec_only );
|
||||
HeapFree( GetProcessHeap(), 0, new_cmd_line );
|
||||
return ret;
|
||||
@@ -2346,7 +2347,7 @@ static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, L
|
||||
*
|
||||
* Create a new cmd shell process for a .BAT file.
|
||||
*/
|
||||
-static BOOL create_cmd_process( LPCWSTR filename, LPWSTR cmd_line, LPVOID env, LPCWSTR cur_dir,
|
||||
+static BOOL create_cmd_process( HANDLE token, LPCWSTR filename, LPWSTR cmd_line, LPVOID env, LPCWSTR cur_dir,
|
||||
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
||||
BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
|
||||
LPPROCESS_INFORMATION info )
|
||||
@@ -2371,8 +2372,8 @@ static BOOL create_cmd_process( LPCWSTR filename, LPWSTR cmd_line, LPVOID env, L
|
||||
strcpyW( newcmdline, comspec );
|
||||
strcatW( newcmdline, slashcW );
|
||||
strcatW( newcmdline, cmd_line );
|
||||
- ret = CreateProcessW( comspec, newcmdline, psa, tsa, inherit,
|
||||
- flags, env, cur_dir, startup, info );
|
||||
+ ret = CreateProcessInternalW( token, comspec, newcmdline, psa, tsa, inherit,
|
||||
+ flags, env, cur_dir, startup, info, NULL );
|
||||
HeapFree( GetProcessHeap(), 0, newcmdline );
|
||||
return ret;
|
||||
}
|
||||
@@ -2482,7 +2483,9 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||
|
||||
TRACE("app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
|
||||
|
||||
- if (token) FIXME("Creating a process with a token is not yet implemented\n");
|
||||
+ /* FIXME: Starting a process which requires admin rights should fail
|
||||
+ * with ERROR_ELEVATION_REQUIRED when no token is passed. */
|
||||
+
|
||||
if (new_token) FIXME("No support for returning created process token\n");
|
||||
|
||||
if (!(tidy_cmdline = get_file_name( app_name, cmd_line, name, sizeof(name)/sizeof(WCHAR),
|
||||
@@ -2540,20 +2543,20 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||
debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32,
|
||||
binary_info.res_start, binary_info.res_end, binary_info.arch,
|
||||
(binary_info.flags & BINARY_FLAG_FAKEDLL) ? ", fakedll" : "" );
|
||||
- retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
+ retv = create_process( token, hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
|
||||
break;
|
||||
case BINARY_OS216:
|
||||
case BINARY_WIN16:
|
||||
case BINARY_DOS:
|
||||
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
||||
- retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
+ retv = create_vdm_process( token, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
|
||||
break;
|
||||
case BINARY_UNIX_LIB:
|
||||
TRACE( "starting %s as %d-bit Winelib app\n",
|
||||
debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32 );
|
||||
- retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
+ retv = create_process( token, hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
|
||||
break;
|
||||
case BINARY_UNKNOWN:
|
||||
@@ -2565,7 +2568,7 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||
TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
|
||||
binary_info.type = BINARY_DOS;
|
||||
binary_info.arch = IMAGE_FILE_MACHINE_I386;
|
||||
- retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
+ retv = create_vdm_process( token, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
inherit, flags, startup_info, info, unixdir,
|
||||
&binary_info, FALSE );
|
||||
break;
|
||||
@@ -2573,7 +2576,7 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||
if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ) )
|
||||
{
|
||||
TRACE( "starting %s as batch binary\n", debugstr_w(name) );
|
||||
- retv = create_cmd_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
+ retv = create_cmd_process( token, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
|
||||
inherit, flags, startup_info, info );
|
||||
break;
|
||||
}
|
||||
@@ -2692,12 +2695,12 @@ static void exec_process( LPCWSTR name )
|
||||
TRACE( "starting %s as Win%d binary (%p-%p, arch %04x)\n",
|
||||
debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32,
|
||||
binary_info.res_start, binary_info.res_end, binary_info.arch );
|
||||
- create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
+ create_process( NULL, hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
|
||||
break;
|
||||
case BINARY_UNIX_LIB:
|
||||
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
|
||||
- create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
+ create_process( NULL, hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
|
||||
break;
|
||||
case BINARY_UNKNOWN:
|
||||
@@ -2711,7 +2714,7 @@ static void exec_process( LPCWSTR name )
|
||||
case BINARY_WIN16:
|
||||
case BINARY_DOS:
|
||||
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
||||
- create_vdm_process( name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
+ create_vdm_process( NULL, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
|
||||
FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
|
||||
break;
|
||||
default:
|
||||
diff --git a/server/process.c b/server/process.c
|
||||
index 74675d343b4..ef2452fb8fb 100644
|
||||
--- a/server/process.c
|
||||
+++ b/server/process.c
|
||||
@@ -501,7 +501,7 @@ static void start_sigkill_timer( struct process *process )
|
||||
|
||||
/* create a new process and its main thread */
|
||||
/* if the function fails the fd is closed */
|
||||
-struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all )
|
||||
+struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all, struct token *token )
|
||||
{
|
||||
struct process *process;
|
||||
struct thread *thread = NULL;
|
||||
@@ -571,7 +571,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
|
||||
: alloc_handle_table( process, 0 );
|
||||
/* Note: for security reasons, starting a new process does not attempt
|
||||
* to use the current impersonation token for the new process */
|
||||
- process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
|
||||
+ process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
|
||||
process->affinity = parent->affinity;
|
||||
}
|
||||
if (!process->handles || !process->token) goto error;
|
||||
@@ -1160,6 +1160,7 @@ DECL_HANDLER(new_process)
|
||||
struct startup_info *info;
|
||||
struct thread *thread;
|
||||
struct process *process;
|
||||
+ struct token *token = NULL;
|
||||
struct process *parent = current->process;
|
||||
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
|
||||
const struct security_descriptor *process_sd = NULL, *thread_sd = NULL;
|
||||
@@ -1195,9 +1196,27 @@ DECL_HANDLER(new_process)
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (req->token)
|
||||
+ {
|
||||
+ token = get_token_from_handle( req->token, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY );
|
||||
+ if (!token)
|
||||
+ {
|
||||
+ close( socket_fd );
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!token_is_primary( token ))
|
||||
+ {
|
||||
+ set_error( STATUS_BAD_TOKEN_TYPE );
|
||||
+ release_object( token );
|
||||
+ close( socket_fd );
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!req->info_size) /* create an orphaned process */
|
||||
{
|
||||
- create_process( socket_fd, NULL, 0 );
|
||||
+ create_process( socket_fd, NULL, 0, token );
|
||||
+ if (token) release_object( token );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1205,6 +1224,7 @@ DECL_HANDLER(new_process)
|
||||
if (!(info = alloc_object( &startup_info_ops )))
|
||||
{
|
||||
close( socket_fd );
|
||||
+ if (token) release_object( token );
|
||||
return;
|
||||
}
|
||||
info->exe_file = NULL;
|
||||
@@ -1287,7 +1307,7 @@ DECL_HANDLER(new_process)
|
||||
}
|
||||
}
|
||||
|
||||
- if (!(thread = create_process( socket_fd, current, req->inherit_all ))) goto done;
|
||||
+ if (!(thread = create_process( socket_fd, current, req->inherit_all, token ))) goto done;
|
||||
process = thread->process;
|
||||
process->startup_info = (struct startup_info *)grab_object( info );
|
||||
|
||||
@@ -1369,6 +1389,7 @@ DECL_HANDLER(new_process)
|
||||
}
|
||||
|
||||
done:
|
||||
+ if (token) release_object( token );
|
||||
release_object( info );
|
||||
}
|
||||
|
||||
diff --git a/server/process.h b/server/process.h
|
||||
index 262eb59627b..fcb45d8d676 100644
|
||||
--- a/server/process.h
|
||||
+++ b/server/process.h
|
||||
@@ -115,7 +115,7 @@ struct process_snapshot
|
||||
extern unsigned int alloc_ptid( void *ptr );
|
||||
extern void free_ptid( unsigned int id );
|
||||
extern void *get_ptid_entry( unsigned int id );
|
||||
-extern struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all );
|
||||
+extern struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all, struct token *token );
|
||||
extern data_size_t init_process( struct thread *thread );
|
||||
extern struct thread *get_process_first_thread( struct process *process );
|
||||
extern struct process *get_process_from_id( process_id_t id );
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index e5b598259f7..7106cdb6f04 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -767,6 +767,7 @@ struct rawinput_device
|
||||
data_size_t info_size; /* size of startup info */
|
||||
data_size_t env_size; /* size of the environment */
|
||||
data_size_t process_sd_size;/* size of the process security descriptor */
|
||||
+ obj_handle_t token; /* token for the new process */
|
||||
VARARG(info,startup_info,info_size); /* startup information */
|
||||
VARARG(env,unicode_str,env_size); /* environment for new process */
|
||||
VARARG(process_sd,security_descriptor,process_sd_size); /* security descriptor to set on the process */
|
||||
diff --git a/server/request.c b/server/request.c
|
||||
index 83e608917f8..23760cdeb98 100644
|
||||
--- a/server/request.c
|
||||
+++ b/server/request.c
|
||||
@@ -571,7 +571,7 @@ static void master_socket_poll_event( struct fd *fd, int event )
|
||||
int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
|
||||
if (client == -1) return;
|
||||
fcntl( client, F_SETFL, O_NONBLOCK );
|
||||
- create_process( client, NULL, 0 );
|
||||
+ create_process( client, NULL, 0, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/server/security.h b/server/security.h
|
||||
index 21e90ccf23f..32dfe5f8db9 100644
|
||||
--- a/server/security.h
|
||||
+++ b/server/security.h
|
||||
@@ -67,6 +67,8 @@ extern const ACL *token_get_default_dacl( struct token *token );
|
||||
extern const SID *token_get_user( struct token *token );
|
||||
extern const SID *token_get_primary_group( struct token *token );
|
||||
extern int token_sid_present( struct token *token, const SID *sid, int deny);
|
||||
+extern struct token *get_token_from_handle( obj_handle_t handle, unsigned int access );
|
||||
+extern int token_is_primary( struct token *token );
|
||||
|
||||
static inline const ACE_HEADER *ace_next( const ACE_HEADER *ace )
|
||||
{
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index 385ea3bbfda..c507294b49d 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -851,6 +851,12 @@ int token_assign_label( struct token *token, PSID label )
|
||||
return ret;
|
||||
}
|
||||
|
||||
+struct token *get_token_from_handle( obj_handle_t handle, unsigned int access )
|
||||
+{
|
||||
+ return (struct token *)get_handle_obj( current->process, handle,
|
||||
+ access, &token_ops );
|
||||
+}
|
||||
+
|
||||
struct token *token_create_admin( void )
|
||||
{
|
||||
struct token *token = NULL;
|
||||
@@ -1278,6 +1284,11 @@ const SID *token_get_primary_group( struct token *token )
|
||||
return token->primary_group;
|
||||
}
|
||||
|
||||
+int token_is_primary( struct token *token )
|
||||
+{
|
||||
+ return token->primary;
|
||||
+}
|
||||
+
|
||||
int check_object_access(struct object *obj, unsigned int *access)
|
||||
{
|
||||
GENERIC_MAPPING mapping;
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,62 @@
|
||||
From bddfc5e460ca5d5751bf7d9069379e0e0462ae94 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sun, 6 Aug 2017 02:11:15 +0200
|
||||
Subject: advapi32: Use token in CreateProcessAsUserW and
|
||||
CreateProcessWithTokenW.
|
||||
|
||||
---
|
||||
dlls/advapi32/security.c | 14 ++++++++------
|
||||
1 file changed, 8 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c
|
||||
index c531e45c9a0..4fc27ef82f9 100644
|
||||
--- a/dlls/advapi32/security.c
|
||||
+++ b/dlls/advapi32/security.c
|
||||
@@ -5700,13 +5700,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW(
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation )
|
||||
{
|
||||
- FIXME("%p %s %s %p %p %d 0x%08x %p %s %p %p - semi-stub\n", hToken,
|
||||
+ 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);
|
||||
|
||||
/* We should create the process with a suspended main thread */
|
||||
- if (!CreateProcessW (lpApplicationName,
|
||||
+ if (!CreateProcessInternalW(hToken,
|
||||
+ lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
@@ -5715,7 +5716,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW(
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
- lpProcessInformation))
|
||||
+ lpProcessInformation,
|
||||
+ NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -5742,14 +5744,14 @@ BOOL WINAPI CreateProcessWithTokenW(HANDLE token, DWORD logon_flags, LPCWSTR app
|
||||
DWORD creation_flags, void *environment, LPCWSTR current_directory, STARTUPINFOW *startup_info,
|
||||
PROCESS_INFORMATION *process_information )
|
||||
{
|
||||
- FIXME("%p 0x%08x %s %s 0x%08x %p %s %p %p - semi-stub\n", token,
|
||||
+ TRACE("%p 0x%08x %s %s 0x%08x %p %s %p %p\n", token,
|
||||
logon_flags, debugstr_w(application_name), debugstr_w(command_line),
|
||||
creation_flags, environment, debugstr_w(current_directory),
|
||||
startup_info, process_information);
|
||||
|
||||
/* FIXME: check if handles should be inherited */
|
||||
- return CreateProcessW( application_name, command_line, NULL, NULL, FALSE, creation_flags, environment,
|
||||
- current_directory, startup_info, process_information );
|
||||
+ return CreateProcessInternalW( token, application_name, command_line, NULL, NULL, FALSE, creation_flags, environment,
|
||||
+ current_directory, startup_info, process_information, NULL );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,80 @@
|
||||
From 31a5f689a12c1db6edcc86dcd8e81f38a5f19fc5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 02:53:06 +0200
|
||||
Subject: user32: Start explorer.exe using limited rights.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 4 ++--
|
||||
dlls/user32/win.c | 12 ++++++++++--
|
||||
2 files changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index f1a64e29dea..52524ee6fe2 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -7387,7 +7387,7 @@ static void test_token_security_descriptor(void)
|
||||
ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
- todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
|
||||
size = 0;
|
||||
ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
|
||||
@@ -7841,7 +7841,7 @@ static void test_child_token_sd_medium(void)
|
||||
ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
|
||||
ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
|
||||
tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
|
||||
- todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
+ ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, sd);
|
||||
}
|
||||
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
|
||||
index cbf22374374..ea116b9d139 100644
|
||||
--- a/dlls/user32/win.c
|
||||
+++ b/dlls/user32/win.c
|
||||
@@ -43,6 +43,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win);
|
||||
#define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
|
||||
#define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
|
||||
|
||||
+extern HANDLE CDECL __wine_create_default_token(BOOL admin);
|
||||
+
|
||||
static DWORD process_layout = ~0u;
|
||||
|
||||
static struct list window_surfaces = LIST_INIT( window_surfaces );
|
||||
@@ -2067,6 +2069,7 @@ HWND WINAPI GetDesktopWindow(void)
|
||||
WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
|
||||
WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
|
||||
WCHAR desktop[MAX_PATH];
|
||||
+ HANDLE token;
|
||||
void *redir;
|
||||
|
||||
SERVER_START_REQ( set_user_object_info )
|
||||
@@ -2099,9 +2102,12 @@ HWND WINAPI GetDesktopWindow(void)
|
||||
strcpyW( cmdline, app );
|
||||
strcatW( cmdline, args );
|
||||
|
||||
+ if (!(token = __wine_create_default_token( FALSE )))
|
||||
+ ERR( "Failed to create limited token\n" );
|
||||
+
|
||||
Wow64DisableWow64FsRedirection( &redir );
|
||||
- if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
|
||||
- NULL, windir, &si, &pi ))
|
||||
+ if (CreateProcessAsUserW( token, app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
|
||||
+ NULL, windir, &si, &pi ))
|
||||
{
|
||||
TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
|
||||
WaitForInputIdle( pi.hProcess, 10000 );
|
||||
@@ -2111,6 +2117,8 @@ HWND WINAPI GetDesktopWindow(void)
|
||||
else WARN( "failed to start explorer, err %d\n", GetLastError() );
|
||||
Wow64RevertWow64FsRedirection( redir );
|
||||
|
||||
+ if (token) CloseHandle( token );
|
||||
+
|
||||
SERVER_START_REQ( get_desktop_window )
|
||||
{
|
||||
req->force = 1;
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,222 @@
|
||||
From 71366dad7ac934b2e24cfcf19104b4589b91652a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 03:33:26 +0200
|
||||
Subject: server: Correctly assign security labels for tokens.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 21 ++++++++++-----------
|
||||
server/process.c | 8 +-------
|
||||
server/security.h | 2 +-
|
||||
server/token.c | 41 ++++++++++++++++++++++++-----------------
|
||||
4 files changed, 36 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 52524ee6fe2..a35baab0e25 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -7289,7 +7289,6 @@ static void test_token_security_descriptor(void)
|
||||
defaulted = TRUE;
|
||||
ret = GetSecurityDescriptorDacl(sd2, &present, &acl2, &defaulted);
|
||||
ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
|
||||
- todo_wine
|
||||
ok(present, "DACL not present\n");
|
||||
|
||||
if (present)
|
||||
@@ -7410,7 +7409,7 @@ static void test_token_security_descriptor(void)
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
"Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
- todo_wine ok(EqualSid(&ace->SidStart, &medium_level),
|
||||
+ ok(EqualSid(&ace->SidStart, &medium_level),
|
||||
"Expected medium integrity level\n");
|
||||
}
|
||||
|
||||
@@ -7463,8 +7462,8 @@ static void test_token_security_descriptor(void)
|
||||
sacl = NULL;
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
- todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+ ok(present, "No SACL in the security descriptor\n");
|
||||
+ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
if (sacl)
|
||||
{
|
||||
@@ -7513,8 +7512,8 @@ static void test_token_security_descriptor(void)
|
||||
sacl = NULL;
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
- todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+ ok(present, "No SACL in the security descriptor\n");
|
||||
+ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
if (sacl)
|
||||
{
|
||||
@@ -7578,8 +7577,8 @@ static void test_token_security_descriptor(void)
|
||||
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
- todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+ ok(present, "No SACL in the security descriptor\n");
|
||||
+ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
if (sacl)
|
||||
{
|
||||
@@ -7616,8 +7615,8 @@ static void test_token_security_descriptor(void)
|
||||
sacl = NULL;
|
||||
ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
|
||||
ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
|
||||
- todo_wine ok(present, "No SACL in the security descriptor\n");
|
||||
- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
+ ok(present, "No SACL in the security descriptor\n");
|
||||
+ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
|
||||
|
||||
if (sacl)
|
||||
{
|
||||
@@ -7834,7 +7833,7 @@ static void test_child_token_sd_medium(void)
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
"Unexpected ACE type %#x\n", ace_label->Header.AceType);
|
||||
- todo_wine ok(EqualSid(&ace_label->SidStart, &medium_level),
|
||||
+ ok(EqualSid(&ace_label->SidStart, &medium_level),
|
||||
"Expected medium integrity level\n");
|
||||
|
||||
memset(buffer_integrity, 0, sizeof(buffer_integrity));
|
||||
diff --git a/server/process.c b/server/process.c
|
||||
index ef2452fb8fb..ae998ab80b9 100644
|
||||
--- a/server/process.c
|
||||
+++ b/server/process.c
|
||||
@@ -571,17 +571,11 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
|
||||
: alloc_handle_table( process, 0 );
|
||||
/* Note: for security reasons, starting a new process does not attempt
|
||||
* to use the current impersonation token for the new process */
|
||||
- process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
|
||||
+ process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0, NULL );
|
||||
process->affinity = parent->affinity;
|
||||
}
|
||||
if (!process->handles || !process->token) goto error;
|
||||
|
||||
- /* Assign a high security label to the token. The default would be medium
|
||||
- * but Wine provides admin access to all applications right now so high
|
||||
- * makes more sense for the time being. */
|
||||
- if (!token_assign_label( process->token, security_high_label_sid ))
|
||||
- goto error;
|
||||
-
|
||||
/* create the main thread */
|
||||
if (pipe( request_pipe ) == -1)
|
||||
{
|
||||
diff --git a/server/security.h b/server/security.h
|
||||
index 32dfe5f8db9..87377ccd673 100644
|
||||
--- a/server/security.h
|
||||
+++ b/server/security.h
|
||||
@@ -59,7 +59,7 @@ extern int token_assign_label( struct token *token, PSID label );
|
||||
extern struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
int impersonation_level, const struct security_descriptor *sd,
|
||||
const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
|
||||
- const SID *filter_groups, unsigned int group_count );
|
||||
+ const SID *filter_groups, unsigned int group_count, struct token *impersonation );
|
||||
extern int token_check_privileges( struct token *token, int all_required,
|
||||
const LUID_AND_ATTRIBUTES *reqprivs,
|
||||
unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index c507294b49d..c6b0f0d39d3 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -686,7 +686,7 @@ static int filter_privilege( struct privilege *privilege, const LUID_AND_ATTRIBU
|
||||
struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
int impersonation_level, const struct security_descriptor *sd,
|
||||
const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
|
||||
- const SID *filter_groups, unsigned int group_count)
|
||||
+ const SID *filter_groups, unsigned int group_count, struct token *impersonation)
|
||||
{
|
||||
const luid_t *modified_id =
|
||||
primary || (impersonation_level == src_token->impersonation_level) ?
|
||||
@@ -750,6 +750,12 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
|
||||
|
||||
+ if (!token_assign_label( token, impersonation ? (PSID)impersonation->integrity : (PSID)token->integrity ))
|
||||
+ {
|
||||
+ release_object( token );
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -922,6 +928,12 @@ struct token *token_create_admin( void )
|
||||
admin_source, NULL, -1, TokenElevationTypeFull, &high_label_sid );
|
||||
/* we really need a primary group */
|
||||
assert( token->primary_group );
|
||||
+
|
||||
+ if (!token_assign_label( token, (PSID)token->integrity ))
|
||||
+ {
|
||||
+ release_object( token );
|
||||
+ token = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
free( logon_sid );
|
||||
@@ -980,6 +992,12 @@ static struct token *token_create_limited( void )
|
||||
admin_source, NULL, -1, TokenElevationTypeLimited, &medium_label_sid );
|
||||
/* we really need a primary group */
|
||||
assert( token->primary_group );
|
||||
+
|
||||
+ if (!token_assign_label( token, (PSID)token->integrity ))
|
||||
+ {
|
||||
+ release_object( token );
|
||||
+ token = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
free( logon_sid );
|
||||
@@ -1448,7 +1466,8 @@ DECL_HANDLER(duplicate_token)
|
||||
TOKEN_DUPLICATE,
|
||||
&token_ops )))
|
||||
{
|
||||
- struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
|
||||
+ struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0,
|
||||
+ NULL, 0, thread_get_impersonation_token( current ) );
|
||||
if (token)
|
||||
{
|
||||
unsigned int access = req->access ? req->access : get_handle_access( current->process, req->handle );
|
||||
@@ -1478,7 +1497,7 @@ DECL_HANDLER(filter_token)
|
||||
group_count = get_sid_count( filter_groups, get_req_data_size() - priv_count * sizeof(LUID_AND_ATTRIBUTES) );
|
||||
|
||||
token = token_duplicate( src_token, src_token->primary, src_token->impersonation_level, NULL,
|
||||
- filter_privileges, priv_count, filter_groups, group_count );
|
||||
+ filter_privileges, priv_count, filter_groups, group_count, thread_get_impersonation_token( current ) );
|
||||
if (token)
|
||||
{
|
||||
unsigned int access = get_handle_access( current->process, req->handle );
|
||||
@@ -1813,23 +1832,11 @@ DECL_HANDLER(set_token_default_dacl)
|
||||
DECL_HANDLER(create_token)
|
||||
{
|
||||
struct token *token;
|
||||
- PSID label;
|
||||
-
|
||||
- if (req->admin)
|
||||
- {
|
||||
- token = token_create_admin();
|
||||
- label = security_high_label_sid;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- token = token_create_limited();
|
||||
- label = security_medium_label_sid;
|
||||
- }
|
||||
|
||||
+ token = req->admin ? token_create_admin() : token_create_limited();
|
||||
if (token)
|
||||
{
|
||||
- if (token_assign_label( token, label ))
|
||||
- reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
|
||||
+ reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
|
||||
release_object( token );
|
||||
}
|
||||
}
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,344 @@
|
||||
From 3c523f6408b12cbf2f70ae857df3a386e8b18cb4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sun, 6 Aug 2017 03:15:34 +0200
|
||||
Subject: programs/runas: Basic implementation for starting processes with a
|
||||
different trustlevel.
|
||||
|
||||
---
|
||||
configure.ac | 1 +
|
||||
programs/runas/Makefile.in | 8 ++
|
||||
programs/runas/runas.c | 214 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
programs/runas/runas.h | 26 ++++++
|
||||
programs/runas/runas.rc | 39 +++++++++
|
||||
5 files changed, 288 insertions(+)
|
||||
create mode 100644 programs/runas/Makefile.in
|
||||
create mode 100644 programs/runas/runas.c
|
||||
create mode 100644 programs/runas/runas.h
|
||||
create mode 100644 programs/runas/runas.rc
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index edc100f4637..b9c648bce43 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -3861,6 +3861,7 @@ WINE_CONFIG_TEST(programs/regedit/tests)
|
||||
WINE_CONFIG_PROGRAM(regsvcs,,[install])
|
||||
WINE_CONFIG_PROGRAM(regsvr32,,[clean,install,installbin,manpage])
|
||||
WINE_CONFIG_PROGRAM(rpcss,,[clean,install])
|
||||
+WINE_CONFIG_PROGRAM(runas,,[install])
|
||||
WINE_CONFIG_PROGRAM(rundll.exe16,enable_win16,[install])
|
||||
WINE_CONFIG_PROGRAM(rundll32,,[install])
|
||||
WINE_CONFIG_PROGRAM(sc,,[install])
|
||||
diff --git a/programs/runas/Makefile.in b/programs/runas/Makefile.in
|
||||
new file mode 100644
|
||||
index 00000000000..be9434b214a
|
||||
--- /dev/null
|
||||
+++ b/programs/runas/Makefile.in
|
||||
@@ -0,0 +1,8 @@
|
||||
+MODULE = runas.exe
|
||||
+APPMODE = -mconsole -municode
|
||||
+IMPORTS = advapi32 user32
|
||||
+
|
||||
+C_SRCS = \
|
||||
+ runas.c
|
||||
+
|
||||
+RC_SRCS = runas.rc
|
||||
diff --git a/programs/runas/runas.c b/programs/runas/runas.c
|
||||
new file mode 100644
|
||||
index 00000000000..cfd1c73ac56
|
||||
--- /dev/null
|
||||
+++ b/programs/runas/runas.c
|
||||
@@ -0,0 +1,214 @@
|
||||
+/*
|
||||
+ * runas.exe implementation
|
||||
+ *
|
||||
+ * Copyright 2017 Michael Müller
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#include <windows.h>
|
||||
+#include <wine/unicode.h>
|
||||
+#include <wine/debug.h>
|
||||
+
|
||||
+#include "runas.h"
|
||||
+
|
||||
+WINE_DEFAULT_DEBUG_CHANNEL(runas);
|
||||
+
|
||||
+extern HANDLE CDECL __wine_create_default_token(BOOL admin);
|
||||
+
|
||||
+struct cmdinfo
|
||||
+{
|
||||
+ WCHAR *program;
|
||||
+ DWORD trustlevel;
|
||||
+};
|
||||
+
|
||||
+static void output_writeconsole(const WCHAR *str, DWORD wlen)
|
||||
+{
|
||||
+ DWORD count, ret;
|
||||
+
|
||||
+ ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
|
||||
+ if (!ret)
|
||||
+ {
|
||||
+ DWORD len;
|
||||
+ char *msgA;
|
||||
+
|
||||
+ /* On Windows WriteConsoleW() fails if the output is redirected. So fall
|
||||
+ * back to WriteFile(), assuming the console encoding is still the right
|
||||
+ * one in that case.
|
||||
+ */
|
||||
+ len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
|
||||
+ msgA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
|
||||
+ if (!msgA) return;
|
||||
+
|
||||
+ WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
|
||||
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
|
||||
+ HeapFree(GetProcessHeap(), 0, msgA);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args)
|
||||
+{
|
||||
+ WCHAR *str;
|
||||
+ DWORD len;
|
||||
+
|
||||
+ SetLastError(NO_ERROR);
|
||||
+ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
+ fmt, 0, 0, (WCHAR *)&str, 0, &va_args);
|
||||
+ if (len == 0 && GetLastError() != NO_ERROR)
|
||||
+ {
|
||||
+ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
|
||||
+ return;
|
||||
+ }
|
||||
+ output_writeconsole(str, len);
|
||||
+ LocalFree(str);
|
||||
+}
|
||||
+
|
||||
+static void __cdecl output_message(unsigned int id, ...)
|
||||
+{
|
||||
+ WCHAR fmt[1024];
|
||||
+ __ms_va_list va_args;
|
||||
+
|
||||
+ if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, sizeof(fmt)/sizeof(WCHAR)))
|
||||
+ {
|
||||
+ WINE_FIXME("LoadString failed with %d\n", GetLastError());
|
||||
+ return;
|
||||
+ }
|
||||
+ __ms_va_start(va_args, id);
|
||||
+ output_formatstring(fmt, va_args);
|
||||
+ __ms_va_end(va_args);
|
||||
+}
|
||||
+
|
||||
+static void show_usage(void)
|
||||
+{
|
||||
+ output_message(STRING_USAGE);
|
||||
+}
|
||||
+
|
||||
+static void show_trustlevels(void)
|
||||
+{
|
||||
+ output_message(STRING_TRUSTLEVELS);
|
||||
+ ExitProcess(0);
|
||||
+}
|
||||
+
|
||||
+static WCHAR *starts_with(WCHAR *str, const WCHAR *start)
|
||||
+{
|
||||
+ DWORD start_len = strlenW(start);
|
||||
+ if (strlenW(str) < start_len)
|
||||
+ return NULL;
|
||||
+ if (strncmpW(str, start, start_len))
|
||||
+ return NULL;
|
||||
+ return str + start_len;
|
||||
+}
|
||||
+
|
||||
+static BOOL parse_command_line(int argc, WCHAR *argv[], struct cmdinfo *cmd)
|
||||
+{
|
||||
+ static const WCHAR showtrustlevelsW[] = {'/','s','h','o','w','t','r','u','s','t','l','e','v','e','l','s',0};
|
||||
+ static const WCHAR trustlevelW[] = {'/','t','r','u','s','t','l','e','v','e','l',':',0};
|
||||
+ int i;
|
||||
+
|
||||
+ memset(cmd, 0, sizeof(*cmd));
|
||||
+
|
||||
+ for (i = 1; i < argc; i++)
|
||||
+ {
|
||||
+ if (argv[i][0] == '/')
|
||||
+ {
|
||||
+ WCHAR *arg;
|
||||
+
|
||||
+ if ((arg = starts_with(argv[i], trustlevelW)))
|
||||
+ cmd->trustlevel = strtoulW(arg, NULL, 0);
|
||||
+ else if (!strcmpW(argv[i], showtrustlevelsW))
|
||||
+ show_trustlevels();
|
||||
+ else
|
||||
+ WINE_FIXME("Ignoring parameter %s\n", wine_dbgstr_w(argv[i]));
|
||||
+ }
|
||||
+ else if (argv[i][0])
|
||||
+ {
|
||||
+ if (cmd->program) return FALSE;
|
||||
+ cmd->program = argv[i];
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BOOL start_process(struct cmdinfo *cmd)
|
||||
+{
|
||||
+ PROCESS_INFORMATION info;
|
||||
+ STARTUPINFOW startup;
|
||||
+ HANDLE token = NULL;
|
||||
+ BOOL ret;
|
||||
+
|
||||
+ if (cmd->trustlevel == 0x20000)
|
||||
+ {
|
||||
+ if (!(token = __wine_create_default_token(FALSE)))
|
||||
+ ERR("Failed to create limited token\n");
|
||||
+ }
|
||||
+
|
||||
+ memset(&startup, 0, sizeof(startup));
|
||||
+ startup.cb = sizeof(startup);
|
||||
+ ret = CreateProcessAsUserW(token, NULL, cmd->program, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ CloseHandle(info.hProcess);
|
||||
+ CloseHandle(info.hThread);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ DWORD error = GetLastError();
|
||||
+ WCHAR *str;
|
||||
+
|
||||
+ if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (WCHAR *)&str, 0, NULL))
|
||||
+ {
|
||||
+ output_message(STRING_START_ERROR, cmd->program, error, str);
|
||||
+ LocalFree(str);
|
||||
+ }
|
||||
+ else
|
||||
+ WINE_FIXME("Failed to format error: %u\n", error);
|
||||
+ }
|
||||
+
|
||||
+ if (token) CloseHandle(token);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int wmain(int argc, WCHAR *argv[])
|
||||
+{
|
||||
+ struct cmdinfo cmd;
|
||||
+
|
||||
+ if (argc <= 1)
|
||||
+ {
|
||||
+ show_usage();
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!parse_command_line(argc, argv, &cmd))
|
||||
+ {
|
||||
+ show_usage();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (!cmd.program)
|
||||
+ {
|
||||
+ show_usage();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (cmd.trustlevel && cmd.trustlevel != 0x20000)
|
||||
+ {
|
||||
+ output_message(STRING_UNHANDLED_TRUSTLEVEL, cmd.trustlevel);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return start_process(&cmd);
|
||||
+}
|
||||
diff --git a/programs/runas/runas.h b/programs/runas/runas.h
|
||||
new file mode 100644
|
||||
index 00000000000..40599a3b33b
|
||||
--- /dev/null
|
||||
+++ b/programs/runas/runas.h
|
||||
@@ -0,0 +1,26 @@
|
||||
+/*
|
||||
+ * runas.exe implementation
|
||||
+ *
|
||||
+ * Copyright 2017 Michael Müller
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#include <windef.h>
|
||||
+
|
||||
+#define STRING_USAGE 101
|
||||
+#define STRING_UNHANDLED_TRUSTLEVEL 102
|
||||
+#define STRING_TRUSTLEVELS 103
|
||||
+#define STRING_START_ERROR 104
|
||||
diff --git a/programs/runas/runas.rc b/programs/runas/runas.rc
|
||||
new file mode 100644
|
||||
index 00000000000..f9297a44794
|
||||
--- /dev/null
|
||||
+++ b/programs/runas/runas.rc
|
||||
@@ -0,0 +1,39 @@
|
||||
+/*
|
||||
+ * runas.exe implementation
|
||||
+ *
|
||||
+ * Copyright 2017 Michael Müller
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#include "runas.h"
|
||||
+
|
||||
+#pragma makedep po
|
||||
+
|
||||
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||
+
|
||||
+STRINGTABLE
|
||||
+{
|
||||
+ STRING_USAGE, "Usage of RUNAS:\n\n\
|
||||
+\RUNAS /trustlevel:<trustlevel> program\n\n\
|
||||
+\ /showtrustlevels Show possible trustlevels\n\
|
||||
+\ /trustlevel <trustlevel> should be listed in /showtrustlevels\n\
|
||||
+\ program Program to start\n\n"
|
||||
+ STRING_UNHANDLED_TRUSTLEVEL, "runas: Unhandled trustlevel 0x%1!x!\n"
|
||||
+ STRING_TRUSTLEVELS, "The following trustlevels are supported:\n\
|
||||
+0x20000 (standard user)\n"
|
||||
+ STRING_START_ERROR, "RUNAS-Error: %1 could not be started\n\
|
||||
+ %2!u!: %3\n"
|
||||
+}
|
||||
--
|
||||
2.13.1
|
||||
|
@ -0,0 +1,58 @@
|
||||
From 6d4621ddba8139747345c05f6251bae9b3c68e39 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Mon, 7 Aug 2017 15:28:33 +0200
|
||||
Subject: ntdll: Add semi-stub for TokenLinkedToken info class.
|
||||
|
||||
---
|
||||
dlls/ntdll/nt.c | 28 +++++++++++++++++++++++++++-
|
||||
1 file changed, 27 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
|
||||
index 6f2b24e6ba4..99dba58b426 100644
|
||||
--- a/dlls/ntdll/nt.c
|
||||
+++ b/dlls/ntdll/nt.c
|
||||
@@ -366,7 +366,7 @@ NTSTATUS WINAPI NtQueryInformationToken(
|
||||
0, /* TokenAuditPolicy */
|
||||
0, /* TokenOrigin */
|
||||
sizeof(TOKEN_ELEVATION_TYPE), /* TokenElevationType */
|
||||
- 0, /* TokenLinkedToken */
|
||||
+ sizeof(TOKEN_LINKED_TOKEN), /* TokenLinkedToken */
|
||||
sizeof(TOKEN_ELEVATION), /* TokenElevation */
|
||||
0, /* TokenHasRestrictions */
|
||||
0, /* TokenAccessInformation */
|
||||
@@ -607,6 +607,32 @@ NTSTATUS WINAPI NtQueryInformationToken(
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
break;
|
||||
+ case TokenLinkedToken:
|
||||
+ SERVER_START_REQ( get_token_elevation_type )
|
||||
+ {
|
||||
+ TOKEN_LINKED_TOKEN *linked_token = tokeninfo;
|
||||
+ req->handle = wine_server_obj_handle( token );
|
||||
+ status = wine_server_call( req );
|
||||
+ if (status == STATUS_SUCCESS)
|
||||
+ {
|
||||
+ HANDLE token;
|
||||
+ /* FIXME: On Wine we do not have real linked tokens yet. Typically, a
|
||||
+ * program running with admin privileges is linked to a limited token,
|
||||
+ * and vice versa. We just create a new token instead of storing links
|
||||
+ * on the wineserver side. Using TokenLinkedToken twice should return
|
||||
+ * back the original token. */
|
||||
+ if ((reply->elevation == TokenElevationTypeFull || reply->elevation == TokenElevationTypeLimited) &&
|
||||
+ (token = __wine_create_default_token( reply->elevation != TokenElevationTypeFull )))
|
||||
+ {
|
||||
+ status = NtDuplicateToken( token, 0, NULL, SecurityIdentification, TokenImpersonation, &linked_token->LinkedToken );
|
||||
+ NtClose( token );
|
||||
+ }
|
||||
+ else
|
||||
+ status = STATUS_NO_TOKEN;
|
||||
+ }
|
||||
+ }
|
||||
+ SERVER_END_REQ;
|
||||
+ break;
|
||||
case TokenElevation:
|
||||
SERVER_START_REQ( get_token_elevation_type )
|
||||
{
|
||||
--
|
||||
2.13.1
|
||||
|
12
patches/advapi32-Token_Integrity_Level/definition
Normal file
12
patches/advapi32-Token_Integrity_Level/definition
Normal file
@ -0,0 +1,12 @@
|
||||
Fixes: [40613] Basic implementation for token integrity levels and UAC handling
|
||||
Depends: advapi32-CreateRestrictedToken
|
||||
Depends: advapi32-GetExplicitEntriesFromAclW
|
||||
Depends: kernel32-COMSPEC
|
||||
Depends: kernel32-UmsStubs
|
||||
Depends: ntdll-APC_Start_Process
|
||||
Depends: ntdll-Grow_Virtual_Heap
|
||||
Depends: ntdll-TokenLogonSid
|
||||
Depends: ntdll-RunlevelInformationInActivationContext
|
||||
Depends: server-CreateProcess_ACLs
|
||||
Depends: server-Misc_ACL
|
||||
Depends: Staging
|
@ -93,6 +93,7 @@ patch_enable_all ()
|
||||
enable_advapi32_LsaLookupSids="$1"
|
||||
enable_advapi32_Performance_Counters="$1"
|
||||
enable_advapi32_SetSecurityInfo="$1"
|
||||
enable_advapi32_Token_Integrity_Level="$1"
|
||||
enable_advapi32_WinBuiltinAnyPackageSid="$1"
|
||||
enable_api_ms_win_Stub_DLLs="$1"
|
||||
enable_avifil32_AVIFile_Proxies="$1"
|
||||
@ -549,6 +550,9 @@ patch_enable ()
|
||||
advapi32-SetSecurityInfo)
|
||||
enable_advapi32_SetSecurityInfo="$2"
|
||||
;;
|
||||
advapi32-Token_Integrity_Level)
|
||||
enable_advapi32_Token_Integrity_Level="$2"
|
||||
;;
|
||||
advapi32-WinBuiltinAnyPackageSid)
|
||||
enable_advapi32_WinBuiltinAnyPackageSid="$2"
|
||||
;;
|
||||
@ -2825,6 +2829,53 @@ if test "$enable_api_ms_win_Stub_DLLs" -eq 1; then
|
||||
enable_kernel32_UmsStubs=1
|
||||
fi
|
||||
|
||||
if test "$enable_advapi32_Token_Integrity_Level" -eq 1; then
|
||||
if test "$enable_Staging" -gt 1; then
|
||||
abort "Patchset Staging disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_advapi32_CreateRestrictedToken" -gt 1; then
|
||||
abort "Patchset advapi32-CreateRestrictedToken disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_advapi32_GetExplicitEntriesFromAclW" -gt 1; then
|
||||
abort "Patchset advapi32-GetExplicitEntriesFromAclW disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_kernel32_COMSPEC" -gt 1; then
|
||||
abort "Patchset kernel32-COMSPEC disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_kernel32_UmsStubs" -gt 1; then
|
||||
abort "Patchset kernel32-UmsStubs disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_ntdll_APC_Start_Process" -gt 1; then
|
||||
abort "Patchset ntdll-APC_Start_Process disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_ntdll_Grow_Virtual_Heap" -gt 1; then
|
||||
abort "Patchset ntdll-Grow_Virtual_Heap disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_ntdll_RunlevelInformationInActivationContext" -gt 1; then
|
||||
abort "Patchset ntdll-RunlevelInformationInActivationContext disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_ntdll_TokenLogonSid" -gt 1; then
|
||||
abort "Patchset ntdll-TokenLogonSid disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_server_CreateProcess_ACLs" -gt 1; then
|
||||
abort "Patchset server-CreateProcess_ACLs disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
if test "$enable_server_Misc_ACL" -gt 1; then
|
||||
abort "Patchset server-Misc_ACL disabled, but advapi32-Token_Integrity_Level depends on that."
|
||||
fi
|
||||
enable_Staging=1
|
||||
enable_advapi32_CreateRestrictedToken=1
|
||||
enable_advapi32_GetExplicitEntriesFromAclW=1
|
||||
enable_kernel32_COMSPEC=1
|
||||
enable_kernel32_UmsStubs=1
|
||||
enable_ntdll_APC_Start_Process=1
|
||||
enable_ntdll_Grow_Virtual_Heap=1
|
||||
enable_ntdll_RunlevelInformationInActivationContext=1
|
||||
enable_ntdll_TokenLogonSid=1
|
||||
enable_server_CreateProcess_ACLs=1
|
||||
enable_server_Misc_ACL=1
|
||||
fi
|
||||
|
||||
if test "$enable_advapi32_LsaLookupSids" -eq 1; then
|
||||
if test "$enable_server_CreateProcess_ACLs" -gt 1; then
|
||||
abort "Patchset server-CreateProcess_ACLs disabled, but advapi32-LsaLookupSids depends on that."
|
||||
@ -3151,6 +3202,143 @@ if test "$enable_advapi32_SetSecurityInfo" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset kernel32-COMSPEC
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/kernel32/process.c, programs/cmd/wcmdmain.c
|
||||
# |
|
||||
if test "$enable_kernel32_COMSPEC" -eq 1; then
|
||||
patch_apply kernel32-COMSPEC/0001-kernel32-Fallback-to-default-comspec-when-COMSPEC-is.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Qian Hong", "kernel32: Fallback to default comspec when %COMSPEC% is not set.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset kernel32-UmsStubs
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#43351] Add semi-stub implementation for CreateRemoteThreadEx
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/api-ms-win-core-processthreads-l1-1-0/api-ms-win-core-processthreads-l1-1-0.spec, dlls/api-ms-win-core-
|
||||
# | processthreads-l1-1-1/api-ms-win-core-processthreads-l1-1-1.spec, dlls/api-ms-win-core-processthreads-l1-1-2/api-ms-win-
|
||||
# | core-processthreads-l1-1-2.spec, dlls/kernel32/kernel32.spec, dlls/kernel32/sync.c, dlls/kernel32/thread.c,
|
||||
# | dlls/kernelbase/kernelbase.spec, include/winbase.h, include/winnt.h
|
||||
# |
|
||||
if test "$enable_kernel32_UmsStubs" -eq 1; then
|
||||
patch_apply kernel32-UmsStubs/0001-kernel32-Add-a-bunch-of-kernel32-stubs.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Dmitry Timoshkov", "kernel32: Add a bunch of kernel32 stubs.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-APC_Start_Process
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/loader.c
|
||||
# |
|
||||
if test "$enable_ntdll_APC_Start_Process" -eq 1; then
|
||||
patch_apply ntdll-APC_Start_Process/0001-ntdll-Process-APC-calls-before-starting-process.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Process APC calls before starting process.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-Grow_Virtual_Heap
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#39885] Remove memory limitation to 32GB on 64-bit by growing heap dynamically
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/heap.c, dlls/ntdll/ntdll_misc.h, dlls/ntdll/virtual.c
|
||||
# |
|
||||
if test "$enable_ntdll_Grow_Virtual_Heap" -eq 1; then
|
||||
patch_apply ntdll-Grow_Virtual_Heap/0001-ntdll-Remove-memory-limitation-to-32GB-on-64-bit-by-.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Remove memory limitation to 32GB on 64-bit by growing heap dynamically.", 2 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-RunlevelInformationInActivationContext
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/kernel32/tests/actctx.c, dlls/ntdll/actctx.c, include/winnt.h
|
||||
# |
|
||||
if test "$enable_ntdll_RunlevelInformationInActivationContext" -eq 1; then
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0001-include-Add-run-level-information-enum-and-structure.patch
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0002-ntdll-Parse-execution-level-information-in-manifest-.patch
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0003-ntdll-Implement-RunlevelInformationInActivationConte.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Michael Müller", "include: Add run level information enum and structure to winnt.h.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Parse execution level information in manifest data.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Implement RunlevelInformationInActivationContext in RtlQueryInformationActivationContext.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-TokenLogonSid
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/nt.c
|
||||
# |
|
||||
if test "$enable_ntdll_TokenLogonSid" -eq 1; then
|
||||
patch_apply ntdll-TokenLogonSid/0001-ntdll-TokenLogonSid-stub-in-NtQueryInformationToken.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Andrew Wesie", "ntdll: TokenLogonSid stub in NtQueryInformationToken.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset advapi32-Token_Integrity_Level
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
# | * Staging, advapi32-CreateRestrictedToken, advapi32-GetExplicitEntriesFromAclW, kernel32-COMSPEC, kernel32-UmsStubs,
|
||||
# | ntdll-APC_Start_Process, ntdll-Grow_Virtual_Heap, ntdll-RunlevelInformationInActivationContext, ntdll-TokenLogonSid,
|
||||
# | server-CreateProcess_ACLs, server-Misc_ACL
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#40613] Basic implementation for token integrity levels and UAC handling
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * configure.ac, dlls/advapi32/security.c, dlls/advapi32/tests/Makefile.in, dlls/advapi32/tests/security.c,
|
||||
# | dlls/kernel32/kernel32.spec, dlls/kernel32/process.c, dlls/ntdll/loader.c, dlls/ntdll/nt.c, dlls/ntdll/ntdll.spec,
|
||||
# | dlls/ntdll/ntdll_misc.h, dlls/ntdll/process.c, dlls/shell32/shlexec.c, dlls/user32/win.c, include/winbase.h,
|
||||
# | programs/runas/Makefile.in, programs/runas/runas.c, programs/runas/runas.h, programs/runas/runas.rc, server/process.c,
|
||||
# | server/process.h, server/protocol.def, server/request.c, server/security.h, server/token.c
|
||||
# |
|
||||
if test "$enable_advapi32_Token_Integrity_Level" -eq 1; then
|
||||
patch_apply advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0009-kernel32-Implement-CreateProcessInternalW.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0011-advapi32-Use-token-in-CreateProcessAsUserW-and-Creat.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch
|
||||
patch_apply advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Michael Müller", "advapi32/tests: Extend security label / token integrity tests.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "server: Implement token elevation information.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "server: Correctly treat zero access mask in duplicate_token wineserver call.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "server: Implement token integrity level.", 1 },';
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "server: Use all group attributes in create_token.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Add function to create new tokens for elevation purposes.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "shell32: Implement process elevation using runas verb.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Implement process token elevation through manifests.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "kernel32: Implement CreateProcessInternalW.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "server: Implement support for creating processes using a token.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "advapi32: Use token in CreateProcessAsUserW and CreateProcessWithTokenW.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "user32: Start explorer.exe using limited rights.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "server: Correctly assign security labels for tokens.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "programs/runas: Basic implementation for starting processes with a different trustlevel.", 1 },';
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Add semi-stub for TokenLinkedToken info class.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset advapi32-WinBuiltinAnyPackageSid
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
@ -3200,24 +3388,6 @@ if test "$enable_combase_RoApi" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset kernel32-UmsStubs
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#43351] Add semi-stub implementation for CreateRemoteThreadEx
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/api-ms-win-core-processthreads-l1-1-0/api-ms-win-core-processthreads-l1-1-0.spec, dlls/api-ms-win-core-
|
||||
# | processthreads-l1-1-1/api-ms-win-core-processthreads-l1-1-1.spec, dlls/api-ms-win-core-processthreads-l1-1-2/api-ms-win-
|
||||
# | core-processthreads-l1-1-2.spec, dlls/kernel32/kernel32.spec, dlls/kernel32/sync.c, dlls/kernel32/thread.c,
|
||||
# | dlls/kernelbase/kernelbase.spec, include/winbase.h, include/winnt.h
|
||||
# |
|
||||
if test "$enable_kernel32_UmsStubs" -eq 1; then
|
||||
patch_apply kernel32-UmsStubs/0001-kernel32-Add-a-bunch-of-kernel32-stubs.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Dmitry Timoshkov", "kernel32: Add a bunch of kernel32 stubs.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset api-ms-win-Stub_DLLs
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
@ -4942,18 +5112,6 @@ if test "$enable_iphlpapi_TCP_Table" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset kernel32-COMSPEC
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/kernel32/process.c, programs/cmd/wcmdmain.c
|
||||
# |
|
||||
if test "$enable_kernel32_COMSPEC" -eq 1; then
|
||||
patch_apply kernel32-COMSPEC/0001-kernel32-Fallback-to-default-comspec-when-COMSPEC-is.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Qian Hong", "kernel32: Fallback to default comspec when %COMSPEC% is not set.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset server-File_Permissions
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
@ -5786,18 +5944,6 @@ if test "$enable_ntdll_APC_Performance" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-APC_Start_Process
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/loader.c
|
||||
# |
|
||||
if test "$enable_ntdll_APC_Start_Process" -eq 1; then
|
||||
patch_apply ntdll-APC_Start_Process/0001-ntdll-Process-APC-calls-before-starting-process.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Process APC calls before starting process.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-Activation_Context
|
||||
# |
|
||||
# | Modified files:
|
||||
@ -6148,21 +6294,6 @@ if test "$enable_ntdll_Fix_Alignment" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-Grow_Virtual_Heap
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#39885] Remove memory limitation to 32GB on 64-bit by growing heap dynamically
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/heap.c, dlls/ntdll/ntdll_misc.h, dlls/ntdll/virtual.c
|
||||
# |
|
||||
if test "$enable_ntdll_Grow_Virtual_Heap" -eq 1; then
|
||||
patch_apply ntdll-Grow_Virtual_Heap/0001-ntdll-Remove-memory-limitation-to-32GB-on-64-bit-by-.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Remove memory limitation to 32GB on 64-bit by growing heap dynamically.", 2 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-LDR_MODULE
|
||||
# |
|
||||
# | Modified files:
|
||||
@ -6612,22 +6743,6 @@ if test "$enable_ntdll_RtlIpStringToAddress_Tests" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-RunlevelInformationInActivationContext
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/kernel32/tests/actctx.c, dlls/ntdll/actctx.c, include/winnt.h
|
||||
# |
|
||||
if test "$enable_ntdll_RunlevelInformationInActivationContext" -eq 1; then
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0001-include-Add-run-level-information-enum-and-structure.patch
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0002-ntdll-Parse-execution-level-information-in-manifest-.patch
|
||||
patch_apply ntdll-RunlevelInformationInActivationContext/0003-ntdll-Implement-RunlevelInformationInActivationConte.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Michael Müller", "include: Add run level information enum and structure to winnt.h.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Parse execution level information in manifest data.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "ntdll: Implement RunlevelInformationInActivationContext in RtlQueryInformationActivationContext.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-Serial_Port_Detection
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
@ -6733,18 +6848,6 @@ if test "$enable_ntdll_Threading" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-TokenLogonSid
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/nt.c
|
||||
# |
|
||||
if test "$enable_ntdll_TokenLogonSid" -eq 1; then
|
||||
patch_apply ntdll-TokenLogonSid/0001-ntdll-TokenLogonSid-stub-in-NtQueryInformationToken.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Andrew Wesie", "ntdll: TokenLogonSid stub in NtQueryInformationToken.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ws2_32-WriteWatches
|
||||
# |
|
||||
# | Modified files:
|
||||
|
Loading…
x
Reference in New Issue
Block a user