You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-04-13 14:42:51 -07:00
Compare commits
90 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
22cdd720aa | ||
|
f818f80da7 | ||
|
2c4722a130 | ||
|
f4c1df296d | ||
|
1cdf74a117 | ||
|
0727cad0c9 | ||
|
63a8a664c9 | ||
|
c66ae9f084 | ||
|
ae2d23d9f4 | ||
|
b35d9813d2 | ||
|
54b732863c | ||
|
7b016ffde8 | ||
|
7a557fe8fd | ||
|
ce01adb3ed | ||
|
d7385d6c01 | ||
|
f85692946e | ||
|
36f5d4da6c | ||
|
1767361878 | ||
|
2a9948a07f | ||
|
97015ebf4e | ||
|
729ce1f6f3 | ||
|
279eca11f1 | ||
|
7709f6b37c | ||
|
34f5330124 | ||
|
578128d012 | ||
|
51cc8cbe36 | ||
|
f1b1baf057 | ||
|
467fed6501 | ||
|
83f27c90a6 | ||
|
7710cdb8c0 | ||
|
141768861c | ||
|
a8eca598ce | ||
|
ce7d9b6d08 | ||
|
a7f42dd60a | ||
|
83e5c37f16 | ||
|
7ad83e6e14 | ||
|
a7cf8014bb | ||
|
c50463197f | ||
|
f98abfe0dc | ||
|
5a79bf01f2 | ||
|
330f1cc410 | ||
|
d076d04ebc | ||
|
7b687557c3 | ||
|
00540ae7b9 | ||
|
41562729cd | ||
|
6b9d11ac58 | ||
|
e53b4e2702 | ||
|
eb4587492e | ||
|
b6bab9758e | ||
|
bab383452b | ||
|
9fbebe7a46 | ||
|
14cfabe8ab | ||
|
5adb9710aa | ||
|
f09e1db3cc | ||
|
ea6cb58103 | ||
|
62f94a1ed2 | ||
|
41cf5ea976 | ||
|
be0aab1653 | ||
|
0e27dc7034 | ||
|
f6565eb6af | ||
|
2d92c18c9e | ||
|
96dd810f82 | ||
|
8ca3547a36 | ||
|
4938755f5f | ||
|
adb8deeaf2 | ||
|
716ea2cef3 | ||
|
6edf4d136c | ||
|
51d419bbeb | ||
|
6b40eb077f | ||
|
ae3f3b8bb7 | ||
|
ed87feaf71 | ||
|
081fbc2ef1 | ||
|
4455721443 | ||
|
5559653869 | ||
|
8f9cc5e01c | ||
|
d364296484 | ||
|
0892d6d89e | ||
|
aa23179c36 | ||
|
e28edf1951 | ||
|
5f7efc6b30 | ||
|
71f0cf0aef | ||
|
ea9d4a0fa1 | ||
|
3aabb941ae | ||
|
f64dc8457e | ||
|
ebc9ba4921 | ||
|
77a90f1dd0 | ||
|
c0a61524e1 | ||
|
9f5d2cab05 | ||
|
2e99d9e465 | ||
|
2c12e538dd |
@@ -1,25 +0,0 @@
|
||||
From 33717bde9e702520e23ae014c398bd7076902d43 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 12:56:47 +0200
|
||||
Subject: shell32: Fix length parameter for ZeroMemory.
|
||||
|
||||
---
|
||||
dlls/shell32/shfldr_fs.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/shell32/shfldr_fs.c b/dlls/shell32/shfldr_fs.c
|
||||
index c7259276d1d..10653f92b52 100644
|
||||
--- a/dlls/shell32/shfldr_fs.c
|
||||
+++ b/dlls/shell32/shfldr_fs.c
|
||||
@@ -1315,7 +1315,7 @@ ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
|
||||
|
||||
if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
|
||||
SHGetPathFromIDListW (pidl, wszSrcPathRoot);
|
||||
- ZeroMemory(wszDstPath, MAX_PATH+1);
|
||||
+ ZeroMemory(wszDstPath, sizeof(wszDstPath));
|
||||
if (This->sPathTarget)
|
||||
lstrcpynW(wszDstPath, This->sPathTarget, MAX_PATH);
|
||||
PathAddBackslashW(wszSrcPathRoot);
|
||||
--
|
||||
2.13.0
|
||||
|
@@ -1,25 +0,0 @@
|
||||
From 2b5e9f330770221eee2eda2aab251eba8d370a60 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 13:17:54 +0200
|
||||
Subject: fusion: Fix length parameter for ZeroMemory.
|
||||
|
||||
---
|
||||
dlls/fusion/tests/asmname.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/fusion/tests/asmname.c b/dlls/fusion/tests/asmname.c
|
||||
index 5fb14a48291..21cd4874edc 100644
|
||||
--- a/dlls/fusion/tests/asmname.c
|
||||
+++ b/dlls/fusion/tests/asmname.c
|
||||
@@ -358,7 +358,7 @@ static void test_assembly_name_props_line(IAssemblyName *name,
|
||||
to_widechar(expect, vals[i].val);
|
||||
|
||||
size = MAX_PATH;
|
||||
- ZeroMemory(str, MAX_PATH);
|
||||
+ ZeroMemory(str, sizeof(str));
|
||||
hr = IAssemblyName_GetProperty(name, i, str, &size);
|
||||
to_multibyte(val, str);
|
||||
|
||||
--
|
||||
2.13.0
|
||||
|
@@ -1,34 +0,0 @@
|
||||
From 3e59710a3091a4a61b7cce00606ed23b7b66dfda Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 12:55:31 +0200
|
||||
Subject: fusion/tests: Avoid compiler warnings with GCC 7.
|
||||
|
||||
---
|
||||
dlls/fusion/tests/asmenum.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/fusion/tests/asmenum.c b/dlls/fusion/tests/asmenum.c
|
||||
index 1dc34a286e5..8b95f2a6bd5 100644
|
||||
--- a/dlls/fusion/tests/asmenum.c
|
||||
+++ b/dlls/fusion/tests/asmenum.c
|
||||
@@ -223,7 +223,7 @@ typedef struct _tagASMNAME
|
||||
static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path)
|
||||
{
|
||||
WIN32_FIND_DATAA ffd;
|
||||
- CHAR buf[MAX_PATH];
|
||||
+ CHAR buf[MAX_PATH + 37];
|
||||
CHAR disp[MAX_PATH];
|
||||
ASMNAME *name;
|
||||
HANDLE hfind;
|
||||
@@ -248,7 +248,7 @@ static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path)
|
||||
else if (depth == 1)
|
||||
{
|
||||
char culture[MAX_PATH];
|
||||
- char dll[MAX_PATH], exe[MAX_PATH];
|
||||
+ char dll[MAX_PATH + 6], exe[MAX_PATH + 6];
|
||||
|
||||
/* Directories with no dll or exe will not be enumerated */
|
||||
sprintf(dll, "%s\\%s\\%s.dll", path, ffd.cFileName, parent);
|
||||
--
|
||||
2.13.0
|
||||
|
@@ -1,34 +0,0 @@
|
||||
From d1eafd34d4c0619f956afd365ddbde79680a18dc Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 12:56:10 +0200
|
||||
Subject: kernel32/tests: Avoid compiler warnings with GCC 7.
|
||||
|
||||
---
|
||||
dlls/kernel32/tests/heap.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c
|
||||
index 0acf109dff0..70ba674bc91 100644
|
||||
--- a/dlls/kernel32/tests/heap.c
|
||||
+++ b/dlls/kernel32/tests/heap.c
|
||||
@@ -109,6 +109,9 @@ static void test_heap(void)
|
||||
}
|
||||
|
||||
/* test some border cases of HeapAlloc and HeapReAlloc */
|
||||
+#pragma GCC diagnostic push
|
||||
+#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
+#pragma GCC diagnostic ignored "-Walloc-size-larger-than="
|
||||
mem = HeapAlloc(GetProcessHeap(), 0, 0);
|
||||
ok(mem != NULL, "memory not allocated for size 0\n");
|
||||
msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0 - 7);
|
||||
@@ -125,6 +128,7 @@ static void test_heap(void)
|
||||
ok(size == 0 || broken(size == 1) /* some vista and win7 */,
|
||||
"HeapSize should have returned 0 instead of %lu\n", size);
|
||||
HeapFree(GetProcessHeap(), 0, msecond);
|
||||
+#pragma GCC diagnostic pop
|
||||
|
||||
/* large blocks must be 16-byte aligned */
|
||||
mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024);
|
||||
--
|
||||
2.13.1
|
||||
|
@@ -1,25 +0,0 @@
|
||||
From 61ceddca38f26c2df2acc6361c35ced52fe9b098 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 12:58:31 +0200
|
||||
Subject: rsaenh/tests: Avoid compiler warnings with GCC 7.
|
||||
|
||||
---
|
||||
dlls/rsaenh/rsaenh.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c
|
||||
index 9af770dfc6e..6978c860278 100644
|
||||
--- a/dlls/rsaenh/rsaenh.c
|
||||
+++ b/dlls/rsaenh/rsaenh.c
|
||||
@@ -1097,7 +1097,7 @@ static void store_key_permissions(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpe
|
||||
*/
|
||||
static BOOL create_container_key(KEYCONTAINER *pKeyContainer, REGSAM sam, HKEY *phKey)
|
||||
{
|
||||
- CHAR szRSABase[MAX_PATH];
|
||||
+ CHAR szRSABase[MAX_PATH + 25];
|
||||
HKEY hRootKey;
|
||||
|
||||
sprintf(szRSABase, RSAENH_REGKEY, pKeyContainer->szName);
|
||||
--
|
||||
2.13.0
|
||||
|
@@ -1,46 +0,0 @@
|
||||
From 67ed53ca67214d7dbdea7f342b9f2ff0356a220b Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 4 Jun 2017 12:59:10 +0200
|
||||
Subject: kernel32: Avoid compiler warnings with GCC 7.
|
||||
|
||||
---
|
||||
dlls/kernel32/oldconfig.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/oldconfig.c b/dlls/kernel32/oldconfig.c
|
||||
index 6c80dc614f0..3e628757283 100644
|
||||
--- a/dlls/kernel32/oldconfig.c
|
||||
+++ b/dlls/kernel32/oldconfig.c
|
||||
@@ -290,7 +290,8 @@ static void create_hardware_branch(void)
|
||||
{
|
||||
if (strncmp(dent->d_name, "hd", 2) == 0)
|
||||
{
|
||||
- sprintf(cStr, procname_ide_media, dent->d_name);
|
||||
+ result = snprintf(cStr, sizeof(cStr), procname_ide_media, dent->d_name);
|
||||
+ if (result < 0 || result >= sizeof(cStr)) continue;
|
||||
procfile = fopen(cStr, "r");
|
||||
if (!procfile)
|
||||
{
|
||||
@@ -306,7 +307,8 @@ static void create_hardware_branch(void)
|
||||
if (nType == DRIVE_UNKNOWN) continue;
|
||||
}
|
||||
|
||||
- sprintf(cStr, procname_ide_model, dent->d_name);
|
||||
+ result = snprintf(cStr, sizeof(cStr), procname_ide_model, dent->d_name);
|
||||
+ if (result < 0 || result >= sizeof(cStr)) continue;
|
||||
procfile = fopen(cStr, "r");
|
||||
if (!procfile)
|
||||
{
|
||||
@@ -322,7 +324,8 @@ static void create_hardware_branch(void)
|
||||
cDevModel[strlen(cDevModel) - 1] = 0;
|
||||
}
|
||||
|
||||
- sprintf(cUnixDeviceName, "/dev/%s", dent->d_name);
|
||||
+ result = snprintf(cUnixDeviceName, sizeof(cUnixDeviceName), "/dev/%s", dent->d_name);
|
||||
+ if (result < 0 || result >= sizeof(cUnixDeviceName)) continue;
|
||||
scsi_addr.PortNumber = (dent->d_name[2] - 'a') / 2;
|
||||
scsi_addr.PathId = 0;
|
||||
scsi_addr.TargetId = (dent->d_name[2] - 'a') % 2;
|
||||
--
|
||||
2.13.0
|
||||
|
@@ -0,0 +1,315 @@
|
||||
From 3f314cc8251f62f592013abe7b1c3b977de0699a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 4 Aug 2017 02:33:14 +0200
|
||||
Subject: ntdll: Implement NtFilterToken.
|
||||
|
||||
---
|
||||
dlls/ntdll/nt.c | 59 ++++++++++++++++++++++++++++++++++++
|
||||
dlls/ntdll/ntdll.spec | 2 +-
|
||||
include/winnt.h | 5 +++
|
||||
include/winternl.h | 1 +
|
||||
server/process.c | 2 +-
|
||||
server/protocol.def | 10 ++++++
|
||||
server/security.h | 4 ++-
|
||||
server/token.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
8 files changed, 162 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
|
||||
index 93554e929be..5822dec9b15 100644
|
||||
--- a/dlls/ntdll/nt.c
|
||||
+++ b/dlls/ntdll/nt.c
|
||||
@@ -136,6 +136,65 @@ NTSTATUS WINAPI NtDuplicateToken(
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
+ * NtFilterToken [NTDLL.@]
|
||||
+ * ZwFilterToken [NTDLL.@]
|
||||
+ */
|
||||
+NTSTATUS WINAPI NtFilterToken( HANDLE token, ULONG flags, TOKEN_GROUPS *disable_sids,
|
||||
+ TOKEN_PRIVILEGES *privileges, TOKEN_GROUPS *restrict_sids,
|
||||
+ HANDLE *new_token )
|
||||
+{
|
||||
+ data_size_t privileges_len = 0;
|
||||
+ data_size_t sids_len = 0;
|
||||
+ SID *sids = NULL;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ TRACE( "(%p, 0x%08x, %p, %p, %p, %p)\n", token, flags, disable_sids, privileges,
|
||||
+ restrict_sids, new_token );
|
||||
+
|
||||
+ if (flags)
|
||||
+ FIXME( "flags %x unsupported\n", flags );
|
||||
+
|
||||
+ if (restrict_sids)
|
||||
+ FIXME( "support for restricting sids not yet implemented\n" );
|
||||
+
|
||||
+ if (privileges)
|
||||
+ privileges_len = privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
|
||||
+
|
||||
+ if (disable_sids)
|
||||
+ {
|
||||
+ DWORD len, i;
|
||||
+ BYTE *tmp;
|
||||
+
|
||||
+ for (i = 0; i < disable_sids->GroupCount; i++)
|
||||
+ sids_len += RtlLengthSid( disable_sids->Groups[i].Sid );
|
||||
+
|
||||
+ sids = RtlAllocateHeap( GetProcessHeap(), 0, sids_len );
|
||||
+ if (!sids) return STATUS_NO_MEMORY;
|
||||
+
|
||||
+ for (i = 0, tmp = (BYTE *)sids; i < disable_sids->GroupCount; i++, tmp += len)
|
||||
+ {
|
||||
+ len = RtlLengthSid( disable_sids->Groups[i].Sid );
|
||||
+ memcpy( tmp, disable_sids->Groups[i].Sid, len );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ SERVER_START_REQ( filter_token )
|
||||
+ {
|
||||
+ req->handle = wine_server_obj_handle( token );
|
||||
+ req->flags = flags;
|
||||
+ req->privileges_size = privileges_len;
|
||||
+ wine_server_add_data( req, privileges->Privileges, privileges_len );
|
||||
+ wine_server_add_data( req, sids, sids_len );
|
||||
+ status = wine_server_call( req );
|
||||
+ if (!status) *new_token = wine_server_ptr_handle( reply->new_handle );
|
||||
+ }
|
||||
+ SERVER_END_REQ;
|
||||
+
|
||||
+ RtlFreeHeap( GetProcessHeap(), 0, sids );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+/******************************************************************************
|
||||
* NtOpenProcessToken [NTDLL.@]
|
||||
* ZwOpenProcessToken [NTDLL.@]
|
||||
*/
|
||||
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
||||
index 4f7ee496437..275fda57970 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -179,7 +179,7 @@
|
||||
# @ stub NtEnumerateSystemEnvironmentValuesEx
|
||||
@ stdcall NtEnumerateValueKey(long long long ptr long ptr)
|
||||
@ stub NtExtendSection
|
||||
-# @ stub NtFilterToken
|
||||
+@ stdcall NtFilterToken(long long ptr ptr ptr ptr)
|
||||
@ stdcall NtFindAtom(ptr long ptr)
|
||||
@ stdcall NtFlushBuffersFile(long ptr)
|
||||
@ stdcall NtFlushInstructionCache(long ptr long)
|
||||
diff --git a/include/winnt.h b/include/winnt.h
|
||||
index f91f81eb559..891c9b6d4bb 100644
|
||||
--- a/include/winnt.h
|
||||
+++ b/include/winnt.h
|
||||
@@ -3844,6 +3844,11 @@ typedef enum _TOKEN_INFORMATION_CLASS {
|
||||
TOKEN_ADJUST_SESSIONID | \
|
||||
TOKEN_ADJUST_DEFAULT )
|
||||
|
||||
+#define DISABLE_MAX_PRIVILEGE 0x1
|
||||
+#define SANDBOX_INERT 0x2
|
||||
+#define LUA_TOKEN 0x4
|
||||
+#define WRITE_RESTRICTED 0x8
|
||||
+
|
||||
#ifndef _SECURITY_DEFINED
|
||||
#define _SECURITY_DEFINED
|
||||
|
||||
diff --git a/include/winternl.h b/include/winternl.h
|
||||
index 140669b0105..899e8324d67 100644
|
||||
--- a/include/winternl.h
|
||||
+++ b/include/winternl.h
|
||||
@@ -2348,6 +2348,7 @@ NTSYSAPI NTSTATUS WINAPI NtDuplicateToken(HANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES
|
||||
NTSYSAPI NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *);
|
||||
NTSYSAPI NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
|
||||
NTSYSAPI NTSTATUS WINAPI NtExtendSection(HANDLE,PLARGE_INTEGER);
|
||||
+NTSYSAPI NTSTATUS WINAPI NtFilterToken(HANDLE,ULONG,TOKEN_GROUPS*,TOKEN_PRIVILEGES*,TOKEN_GROUPS*,HANDLE*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtFindAtom(const WCHAR*,ULONG,RTL_ATOM*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);
|
||||
diff --git a/server/process.c b/server/process.c
|
||||
index cbe726afe81..f0f60edcd3f 100644
|
||||
--- a/server/process.c
|
||||
+++ b/server/process.c
|
||||
@@ -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 );
|
||||
+ process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
|
||||
process->affinity = parent->affinity;
|
||||
}
|
||||
if (!process->handles || !process->token) goto error;
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index fc6e343af52..b3dce66eb9c 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3391,6 +3391,16 @@ enum caret_state
|
||||
obj_handle_t new_handle; /* duplicated handle */
|
||||
@END
|
||||
|
||||
+@REQ(filter_token)
|
||||
+ obj_handle_t handle; /* handle to the token to duplicate */
|
||||
+ unsigned int flags; /* flags */
|
||||
+ data_size_t privileges_size; /* size of privileges */
|
||||
+ VARARG(privileges,LUID_AND_ATTRIBUTES,privileges_size); /* privileges to remove from new token */
|
||||
+ VARARG(disable_sids,SID); /* array of groups to remove from new token */
|
||||
+@REPLY
|
||||
+ obj_handle_t new_handle; /* filtered handle */
|
||||
+@END
|
||||
+
|
||||
@REQ(access_check)
|
||||
obj_handle_t handle; /* handle to the token */
|
||||
unsigned int desired_access; /* desired access to the object */
|
||||
diff --git a/server/security.h b/server/security.h
|
||||
index 606dbb2ab2c..6c337143c3d 100644
|
||||
--- a/server/security.h
|
||||
+++ b/server/security.h
|
||||
@@ -56,7 +56,9 @@ extern const PSID security_high_label_sid;
|
||||
extern struct token *token_create_admin(void);
|
||||
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 );
|
||||
+ 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 );
|
||||
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 74db66e1e24..acd7a4dedb5 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -299,6 +299,19 @@ static int acl_is_valid( const ACL *acl, data_size_t size )
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+static unsigned int get_sid_count( const SID *sid, data_size_t size )
|
||||
+{
|
||||
+ unsigned int count;
|
||||
+
|
||||
+ for (count = 0; size >= sizeof(SID) && security_sid_len( sid ) <= size; count++)
|
||||
+ {
|
||||
+ size -= security_sid_len( sid );
|
||||
+ sid = (const SID *)((char *)sid + security_sid_len( sid ));
|
||||
+ }
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
/* checks whether all members of a security descriptor fit inside the size
|
||||
* of memory specified */
|
||||
int sd_is_valid( const struct security_descriptor *sd, data_size_t size )
|
||||
@@ -639,8 +652,36 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||
return token;
|
||||
}
|
||||
|
||||
+static int filter_group( struct group *group, const SID *filter, unsigned int count )
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < count; i++)
|
||||
+ {
|
||||
+ if (security_equal_sid( &group->sid, filter )) return 1;
|
||||
+ filter = (const SID *)((char *)filter + security_sid_len( filter ));
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int filter_privilege( struct privilege *privilege, const LUID_AND_ATTRIBUTES *filter, unsigned int count )
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < count; i++)
|
||||
+ {
|
||||
+ if (!memcmp( &privilege->luid, &filter[i].Luid, sizeof(LUID) ))
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
- int impersonation_level, const struct security_descriptor *sd )
|
||||
+ 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 luid_t *modified_id =
|
||||
primary || (impersonation_level == src_token->impersonation_level) ?
|
||||
@@ -676,6 +717,12 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
return NULL;
|
||||
}
|
||||
memcpy( newgroup, group, size );
|
||||
+ if (filter_group( group, filter_groups, group_count ))
|
||||
+ {
|
||||
+ newgroup->enabled = 0;
|
||||
+ newgroup->def = 0;
|
||||
+ newgroup->deny_only = 1;
|
||||
+ }
|
||||
list_add_tail( &token->groups, &newgroup->entry );
|
||||
if (src_token->primary_group == &group->sid)
|
||||
token->primary_group = &newgroup->sid;
|
||||
@@ -684,11 +731,14 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
||||
|
||||
/* copy privileges */
|
||||
LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
|
||||
+ {
|
||||
+ if (filter_privilege( privilege, filter_privileges, priv_count )) continue;
|
||||
if (!privilege_add( token, &privilege->luid, privilege->enabled ))
|
||||
{
|
||||
release_object( token );
|
||||
return NULL;
|
||||
}
|
||||
+ }
|
||||
|
||||
if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
|
||||
@@ -1322,7 +1372,7 @@ DECL_HANDLER(duplicate_token)
|
||||
TOKEN_DUPLICATE,
|
||||
&token_ops )))
|
||||
{
|
||||
- struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd );
|
||||
+ 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 );
|
||||
@@ -1332,6 +1382,36 @@ DECL_HANDLER(duplicate_token)
|
||||
}
|
||||
}
|
||||
|
||||
+/* creates a restricted version of a token */
|
||||
+DECL_HANDLER(filter_token)
|
||||
+{
|
||||
+ struct token *src_token;
|
||||
+
|
||||
+ if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
|
||||
+ TOKEN_DUPLICATE,
|
||||
+ &token_ops )))
|
||||
+ {
|
||||
+ const LUID_AND_ATTRIBUTES *filter_privileges = get_req_data();
|
||||
+ unsigned int priv_count, group_count;
|
||||
+ const SID *filter_groups;
|
||||
+ struct token *token;
|
||||
+
|
||||
+ priv_count = min( req->privileges_size, get_req_data_size() ) / sizeof(LUID_AND_ATTRIBUTES);
|
||||
+ filter_groups = (const SID *)((char *)filter_privileges + priv_count * sizeof(LUID_AND_ATTRIBUTES));
|
||||
+ 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 );
|
||||
+ if (token)
|
||||
+ {
|
||||
+ unsigned int access = get_handle_access( current->process, req->handle );
|
||||
+ reply->new_handle = alloc_handle_no_access_check( current->process, token, access, 0 );
|
||||
+ release_object( token );
|
||||
+ }
|
||||
+ release_object( src_token );
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* checks the specified privileges are held by the token */
|
||||
DECL_HANDLER(check_token_privileges)
|
||||
{
|
||||
--
|
||||
2.13.1
|
||||
|
@@ -0,0 +1,271 @@
|
||||
From 2a1064c5f90beac2bd709ab5d1c454c90a16189b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 4 Aug 2017 02:51:57 +0200
|
||||
Subject: advapi32: Implement CreateRestrictedToken.
|
||||
|
||||
---
|
||||
dlls/advapi32/security.c | 88 +++++++++++++++++++++++++++++++++++-------
|
||||
dlls/advapi32/tests/security.c | 88 +++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 157 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c
|
||||
index 82bb6689d43..c531e45c9a0 100644
|
||||
--- a/dlls/advapi32/security.c
|
||||
+++ b/dlls/advapi32/security.c
|
||||
@@ -840,6 +840,60 @@ BOOL WINAPI SetThreadToken(PHANDLE thread, HANDLE token)
|
||||
ThreadImpersonationToken, &token, sizeof token ));
|
||||
}
|
||||
|
||||
+static BOOL allocate_groups(TOKEN_GROUPS **groups_ret, SID_AND_ATTRIBUTES *sids, DWORD count)
|
||||
+{
|
||||
+ TOKEN_GROUPS *groups;
|
||||
+ DWORD i;
|
||||
+
|
||||
+ if (!count)
|
||||
+ {
|
||||
+ *groups_ret = NULL;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ groups = (TOKEN_GROUPS *)heap_alloc(FIELD_OFFSET(TOKEN_GROUPS, Groups) +
|
||||
+ count * sizeof(SID_AND_ATTRIBUTES));
|
||||
+ if (!groups)
|
||||
+ {
|
||||
+ SetLastError(ERROR_OUTOFMEMORY);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ groups->GroupCount = count;
|
||||
+ for (i = 0; i < count; i++)
|
||||
+ groups->Groups[i] = sids[i];
|
||||
+
|
||||
+ *groups_ret = groups;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BOOL allocate_privileges(TOKEN_PRIVILEGES **privileges_ret, LUID_AND_ATTRIBUTES *privs, DWORD count)
|
||||
+{
|
||||
+ TOKEN_PRIVILEGES *privileges;
|
||||
+ DWORD i;
|
||||
+
|
||||
+ if (!count)
|
||||
+ {
|
||||
+ *privileges_ret = NULL;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ privileges = (TOKEN_PRIVILEGES *)heap_alloc(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) +
|
||||
+ count * sizeof(LUID_AND_ATTRIBUTES));
|
||||
+ if (!privileges)
|
||||
+ {
|
||||
+ SetLastError(ERROR_OUTOFMEMORY);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ privileges->PrivilegeCount = count;
|
||||
+ for (i = 0; i < count; i++)
|
||||
+ privileges->Privileges[i] = privs[i];
|
||||
+
|
||||
+ *privileges_ret = privileges;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
/*************************************************************************
|
||||
* CreateRestrictedToken [ADVAPI32.@]
|
||||
*
|
||||
@@ -871,25 +925,33 @@ BOOL WINAPI CreateRestrictedToken(
|
||||
PSID_AND_ATTRIBUTES restrictSids,
|
||||
PHANDLE newToken)
|
||||
{
|
||||
- TOKEN_TYPE type;
|
||||
- SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous;
|
||||
- DWORD size;
|
||||
+ TOKEN_PRIVILEGES *delete_privs = NULL;
|
||||
+ TOKEN_GROUPS *disable_groups = NULL;
|
||||
+ TOKEN_GROUPS *restrict_sids = NULL;
|
||||
+ BOOL ret = FALSE;
|
||||
|
||||
- FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\n",
|
||||
+ TRACE("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p)\n",
|
||||
baseToken, flags, nDisableSids, disableSids,
|
||||
nDeletePrivs, deletePrivs,
|
||||
nRestrictSids, restrictSids,
|
||||
newToken);
|
||||
|
||||
- size = sizeof(type);
|
||||
- if (!GetTokenInformation( baseToken, TokenType, &type, size, &size )) return FALSE;
|
||||
- if (type == TokenImpersonation)
|
||||
- {
|
||||
- size = sizeof(level);
|
||||
- if (!GetTokenInformation( baseToken, TokenImpersonationLevel, &level, size, &size ))
|
||||
- return FALSE;
|
||||
- }
|
||||
- return DuplicateTokenEx( baseToken, MAXIMUM_ALLOWED, NULL, level, type, newToken );
|
||||
+ if (!allocate_groups(&disable_groups, disableSids, nDisableSids))
|
||||
+ goto done;
|
||||
+
|
||||
+ if (!allocate_privileges(&delete_privs, deletePrivs, nDeletePrivs))
|
||||
+ goto done;
|
||||
+
|
||||
+ if (!allocate_groups(&restrict_sids, restrictSids, nRestrictSids))
|
||||
+ goto done;
|
||||
+
|
||||
+ ret = set_ntstatus(NtFilterToken(baseToken, flags, disable_groups, delete_privs, restrict_sids, newToken));
|
||||
+
|
||||
+done:
|
||||
+ heap_free(disable_groups);
|
||||
+ heap_free(delete_privs);
|
||||
+ heap_free(restrict_sids);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/* ##############################
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index a1ecc409b73..0fd41fe82fa 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -5292,10 +5292,13 @@ static void test_GetUserNameW(void)
|
||||
|
||||
static void test_CreateRestrictedToken(void)
|
||||
{
|
||||
+ TOKEN_PRIMARY_GROUP *primary_group, *primary_group2;
|
||||
HANDLE process_token, token, r_token;
|
||||
PTOKEN_GROUPS token_groups, groups2;
|
||||
SID_AND_ATTRIBUTES sattr;
|
||||
SECURITY_IMPERSONATION_LEVEL level;
|
||||
+ TOKEN_PRIVILEGES *privs;
|
||||
+ PRIVILEGE_SET privset;
|
||||
TOKEN_TYPE type;
|
||||
BOOL is_member;
|
||||
DWORD size;
|
||||
@@ -5311,7 +5314,7 @@ static void test_CreateRestrictedToken(void)
|
||||
ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &process_token);
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
|
||||
- ret = DuplicateTokenEx(process_token, TOKEN_DUPLICATE|TOKEN_ADJUST_GROUPS|TOKEN_QUERY,
|
||||
+ ret = DuplicateTokenEx(process_token, TOKEN_DUPLICATE|TOKEN_ADJUST_GROUPS|TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
|
||||
NULL, SecurityImpersonation, TokenImpersonation, &token);
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
|
||||
@@ -5342,11 +5345,21 @@ static void test_CreateRestrictedToken(void)
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
ok(is_member, "not a member\n");
|
||||
|
||||
- /* disable a SID in new token */
|
||||
+ privset.PrivilegeCount = 1;
|
||||
+ privset.Control = PRIVILEGE_SET_ALL_NECESSARY;
|
||||
+ ret = LookupPrivilegeValueA(NULL, "SeChangeNotifyPrivilege", &privset.Privilege[0].Luid);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+
|
||||
+ is_member = FALSE;
|
||||
+ ret = PrivilegeCheck(token, &privset, &is_member);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+ ok(is_member, "Expected SeChangeNotifyPrivilege to be enabled\n");
|
||||
+
|
||||
+ /* disable a SID and a privilege in new token */
|
||||
sattr.Sid = token_groups->Groups[i].Sid;
|
||||
sattr.Attributes = 0;
|
||||
r_token = NULL;
|
||||
- ret = pCreateRestrictedToken(token, 0, 1, &sattr, 0, NULL, 0, NULL, &r_token);
|
||||
+ ret = pCreateRestrictedToken(token, 0, 1, &sattr, 1, &privset.Privilege[0], 0, NULL, &r_token);
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
|
||||
if (ret)
|
||||
@@ -5355,7 +5368,7 @@ static void test_CreateRestrictedToken(void)
|
||||
is_member = TRUE;
|
||||
ret = pCheckTokenMembership(r_token, token_groups->Groups[i].Sid, &is_member);
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
- todo_wine ok(!is_member, "not a member\n");
|
||||
+ ok(!is_member, "not a member\n");
|
||||
|
||||
ret = GetTokenInformation(r_token, TokenGroups, NULL, 0, &size);
|
||||
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n",
|
||||
@@ -5370,9 +5383,9 @@ static void test_CreateRestrictedToken(void)
|
||||
break;
|
||||
}
|
||||
|
||||
- todo_wine ok(groups2->Groups[j].Attributes & SE_GROUP_USE_FOR_DENY_ONLY,
|
||||
+ ok(groups2->Groups[j].Attributes & SE_GROUP_USE_FOR_DENY_ONLY,
|
||||
"got wrong attributes\n");
|
||||
- todo_wine ok((groups2->Groups[j].Attributes & SE_GROUP_ENABLED) == 0,
|
||||
+ ok((groups2->Groups[j].Attributes & SE_GROUP_ENABLED) == 0,
|
||||
"got wrong attributes\n");
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, groups2);
|
||||
@@ -5386,10 +5399,73 @@ static void test_CreateRestrictedToken(void)
|
||||
ret = GetTokenInformation(r_token, TokenImpersonationLevel, &level, size, &size);
|
||||
ok(ret, "got error %d\n", GetLastError());
|
||||
ok(level == SecurityImpersonation, "got level %u\n", type);
|
||||
+
|
||||
+ is_member = TRUE;
|
||||
+ ret = PrivilegeCheck(r_token, &privset, &is_member);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+ ok(!is_member, "Expected SeChangeNotifyPrivilege not to be enabled\n");
|
||||
+
|
||||
+ ret = GetTokenInformation(r_token, TokenPrivileges, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n",
|
||||
+ ret, GetLastError());
|
||||
+ privs = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ ret = GetTokenInformation(r_token, TokenPrivileges, privs, size, &size);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+
|
||||
+ is_member = FALSE;
|
||||
+ for (j = 0; j < privs->PrivilegeCount; j++)
|
||||
+ {
|
||||
+ if (RtlEqualLuid(&privs->Privileges[j].Luid, &privset.Privilege[0].Luid))
|
||||
+ {
|
||||
+ is_member = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ok(!is_member, "Expected not to find privilege\n");
|
||||
+ HeapFree(GetProcessHeap(), 0, privs);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, token_groups);
|
||||
CloseHandle(r_token);
|
||||
+
|
||||
+ ret = GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n",
|
||||
+ ret, GetLastError());
|
||||
+ primary_group = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ ret = GetTokenInformation(token, TokenPrimaryGroup, primary_group, size, &size);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+
|
||||
+ /* disable primary group */
|
||||
+ sattr.Sid = primary_group->PrimaryGroup;
|
||||
+ sattr.Attributes = 0;
|
||||
+ r_token = NULL;
|
||||
+ ret = pCreateRestrictedToken(token, 0, 1, &sattr, 0, NULL, 0, NULL, &r_token);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ is_member = TRUE;
|
||||
+ ret = pCheckTokenMembership(r_token, primary_group->PrimaryGroup, &is_member);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+ ok(!is_member, "not a member\n");
|
||||
+
|
||||
+ ret = GetTokenInformation(r_token, TokenPrimaryGroup, NULL, 0, &size);
|
||||
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n",
|
||||
+ ret, GetLastError());
|
||||
+ primary_group2 = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ ret = GetTokenInformation(r_token, TokenPrimaryGroup, primary_group2, size, &size);
|
||||
+ ok(ret, "got error %d\n", GetLastError());
|
||||
+
|
||||
+ ok(EqualSid(primary_group2->PrimaryGroup, primary_group->PrimaryGroup),
|
||||
+ "Expected same primary group\n");
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, primary_group2);
|
||||
+ }
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, primary_group);
|
||||
+ CloseHandle(r_token);
|
||||
+
|
||||
CloseHandle(token);
|
||||
CloseHandle(process_token);
|
||||
}
|
||||
--
|
||||
2.13.1
|
||||
|
@@ -0,0 +1,36 @@
|
||||
From 22a49dfa50cda9b1f5a5c64eabed2d17b0033896 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 4 Aug 2017 02:52:50 +0200
|
||||
Subject: server: Correctly validate SID length in sd_is_valid.
|
||||
|
||||
---
|
||||
server/token.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/server/token.c b/server/token.c
|
||||
index acd7a4dedb5..7ab0f634c05 100644
|
||||
--- a/server/token.c
|
||||
+++ b/server/token.c
|
||||
@@ -332,8 +332,7 @@ int sd_is_valid( const struct security_descriptor *sd, data_size_t size )
|
||||
owner = sd_get_owner( sd );
|
||||
if (owner)
|
||||
{
|
||||
- size_t needed_size = security_sid_len( owner );
|
||||
- if ((sd->owner_len < sizeof(SID)) || (needed_size > sd->owner_len))
|
||||
+ if ((sd->owner_len < sizeof(SID)) || (security_sid_len( owner ) > sd->owner_len))
|
||||
return FALSE;
|
||||
}
|
||||
offset += sd->owner_len;
|
||||
@@ -344,8 +343,7 @@ int sd_is_valid( const struct security_descriptor *sd, data_size_t size )
|
||||
group = sd_get_group( sd );
|
||||
if (group)
|
||||
{
|
||||
- size_t needed_size = security_sid_len( group );
|
||||
- if ((sd->group_len < sizeof(SID)) || (needed_size > sd->group_len))
|
||||
+ if ((sd->group_len < sizeof(SID)) || (security_sid_len( group ) > sd->group_len))
|
||||
return FALSE;
|
||||
}
|
||||
offset += sd->group_len;
|
||||
--
|
||||
2.13.1
|
||||
|
1
patches/advapi32-CreateRestrictedToken/definition
Normal file
1
patches/advapi32-CreateRestrictedToken/definition
Normal file
@@ -0,0 +1 @@
|
||||
Fixes: Implement advapi32.CreateRestrictedToken
|
@@ -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 0d98f9a1ea69511f6bb2901e71c72ac715bffd27 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 30dfa60b1a0..69bfe923234 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -1480,6 +1480,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 c97b1e1f73f..030704e1727 100644
|
||||
--- a/dlls/ntdll/ntdll_misc.h
|
||||
+++ b/dlls/ntdll/ntdll_misc.h
|
||||
@@ -77,6 +77,9 @@ extern void virtual_init_threading(void) DECLSPEC_HIDDEN;
|
||||
extern void fill_cpu_info(void) 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 f615ce2fea7..77048003ace 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 b5b2650c8ed..9140feee717 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3615,6 +3615,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 3301283ee25..7abd92386ea 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 };
|
||||
|
||||
@@ -915,6 +917,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;
|
||||
@@ -1729,3 +1789,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.14.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,109 @@
|
||||
From 1546d28f3e52363ad805a1c1df1a3163d65afbed 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 ++++++++++++++----------
|
||||
dlls/kernelbase/kernelbase.spec | 2 +-
|
||||
include/winbase.h | 1 +
|
||||
4 files changed, 17 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
|
||||
index c60c5d6e532..7b5397a126e 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 46449c9bf34..6cae911fdfb 100644
|
||||
--- a/dlls/kernel32/process.c
|
||||
+++ b/dlls/kernel32/process.c
|
||||
@@ -2441,12 +2441,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;
|
||||
@@ -2459,6 +2460,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;
|
||||
@@ -2610,8 +2614,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 );
|
||||
@@ -2630,8 +2634,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/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
|
||||
index bf254155aab..7b8c8c44161 100644
|
||||
--- a/dlls/kernelbase/kernelbase.spec
|
||||
+++ b/dlls/kernelbase/kernelbase.spec
|
||||
@@ -209,7 +209,7 @@
|
||||
@ stdcall CreateProcessAsUserA(long str str ptr ptr long long ptr str ptr ptr) advapi32.CreateProcessAsUserA
|
||||
@ stdcall CreateProcessAsUserW(long wstr wstr ptr ptr long long ptr wstr ptr ptr) advapi32.CreateProcessAsUserW
|
||||
# @ stub CreateProcessInternalA
|
||||
-# @ stub CreateProcessInternalW
|
||||
+@ stdcall CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr) kernel32.CreateProcessInternalW
|
||||
@ stdcall CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr) kernel32.CreateProcessW
|
||||
@ stdcall CreateRemoteThread(long ptr long ptr long long ptr) kernel32.CreateRemoteThread
|
||||
@ stdcall CreateRemoteThreadEx(long ptr long ptr long long ptr ptr) kernel32.CreateRemoteThreadEx
|
||||
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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user