From 116bf59039367e09f1409e5a4df5f64d9667749f Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 15 Oct 2014 10:02:27 +0200
Subject: kernel32: Implement passing security descriptors from CreateProcess
 to the wineserver. (try 2)

Based on a patch by Joris van der Wel.

Unfortunately we have to duplicate create_struct_sd from ntdll, but thats the easiest solution right now. In long term we should probably think about moving process creation logic to ntdll.
---
 dlls/advapi32/tests/security.c |   3 --
 dlls/kernel32/process.c        | 102 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index b44496a..b1b35aa 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -2696,7 +2696,6 @@ static void test_process_security_child(void)
     ret = DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(),
                            &handle1, PROCESS_ALL_ACCESS, TRUE, 0 );
     err = GetLastError();
-    todo_wine
     ok(!ret && err == ERROR_ACCESS_DENIED, "duplicating handle should have failed "
        "with STATUS_ACCESS_DENIED, instead of err:%d\n", err);
 
@@ -2704,10 +2703,8 @@ static void test_process_security_child(void)
 
     /* These two should fail - they are denied by ACL */
     handle = OpenProcess( PROCESS_VM_READ, FALSE, GetCurrentProcessId() );
-    todo_wine
     ok(handle == NULL, "OpenProcess(PROCESS_VM_READ) should have failed\n");
     handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
-    todo_wine
     ok(handle == NULL, "OpenProcess(PROCESS_ALL_ACCESS) should have failed\n");
 
     /* Documented privilege elevation */
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index 5de8b59..d1746a5 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -1916,6 +1916,70 @@ static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd,
     return pid;
 }
 
+/* creates a struct security_descriptor and contained information in one contiguous piece of memory */
+static NTSTATUS create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd,
+                                 data_size_t *server_sd_len)
+{
+    unsigned int len;
+    PSID owner, group;
+    ACL *dacl, *sacl;
+    BOOLEAN owner_present, group_present, dacl_present, sacl_present;
+    BOOLEAN defaulted;
+    NTSTATUS status;
+    unsigned char *ptr;
+
+    if (!nt_sd)
+    {
+        *server_sd = NULL;
+        *server_sd_len = 0;
+        return STATUS_SUCCESS;
+    }
+
+    len = sizeof(struct security_descriptor);
+
+    status = RtlGetOwnerSecurityDescriptor(nt_sd, &owner, &owner_present);
+    if (status != STATUS_SUCCESS) return status;
+    status = RtlGetGroupSecurityDescriptor(nt_sd, &group, &group_present);
+    if (status != STATUS_SUCCESS) return status;
+    status = RtlGetSaclSecurityDescriptor(nt_sd, &sacl_present, &sacl, &defaulted);
+    if (status != STATUS_SUCCESS) return status;
+    status = RtlGetDaclSecurityDescriptor(nt_sd, &dacl_present, &dacl, &defaulted);
+    if (status != STATUS_SUCCESS) return status;
+
+    if (owner_present)
+        len += RtlLengthSid(owner);
+    if (group_present)
+        len += RtlLengthSid(group);
+    if (sacl_present && sacl)
+        len += sacl->AclSize;
+    if (dacl_present && dacl)
+        len += dacl->AclSize;
+
+    /* fix alignment for the Unicode name that follows the structure */
+    len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
+    *server_sd = RtlAllocateHeap(GetProcessHeap(), 0, len);
+    if (!*server_sd) return STATUS_NO_MEMORY;
+
+    (*server_sd)->control = ((SECURITY_DESCRIPTOR *)nt_sd)->Control & ~SE_SELF_RELATIVE;
+    (*server_sd)->owner_len = owner_present ? RtlLengthSid(owner) : 0;
+    (*server_sd)->group_len = group_present ? RtlLengthSid(group) : 0;
+    (*server_sd)->sacl_len = (sacl_present && sacl) ? sacl->AclSize : 0;
+    (*server_sd)->dacl_len = (dacl_present && dacl) ? dacl->AclSize : 0;
+
+    ptr = (unsigned char *)(*server_sd + 1);
+    memcpy(ptr, owner, (*server_sd)->owner_len);
+    ptr += (*server_sd)->owner_len;
+    memcpy(ptr, group, (*server_sd)->group_len);
+    ptr += (*server_sd)->group_len;
+    memcpy(ptr, sacl, (*server_sd)->sacl_len);
+    ptr += (*server_sd)->sacl_len;
+    memcpy(ptr, dacl, (*server_sd)->dacl_len);
+
+    *server_sd_len = len;
+
+    return STATUS_SUCCESS;
+}
+
 /***********************************************************************
  *           create_process
  *
@@ -1939,6 +2003,8 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
     int socketfd[2], stdin_fd = -1, stdout_fd = -1;
     pid_t pid;
     int err, cpu;
+    struct security_descriptor *process_sd = NULL, *thread_sd = NULL;
+    data_size_t process_sd_size = 0, thread_sd_size = 0;
 
     if ((cpu = get_process_cpu( filename, binary_info )) == -1)
     {
@@ -1993,12 +2059,41 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
         return FALSE;
     }
 
+    if (psa && (psa->nLength >= sizeof(*psa)))
+    {
+        status = create_struct_sd( psa->lpSecurityDescriptor, &process_sd, &process_sd_size );
+        if (status != STATUS_SUCCESS)
+        {
+            close( socketfd[0] );
+            close( socketfd[1] );
+            WARN( "Invalid process security descriptor: Status %x\n", status );
+            SetLastError( RtlNtStatusToDosError(status) );
+            return FALSE;
+        }
+    }
+
+    if (tsa && (tsa->nLength >= sizeof(*tsa)))
+    {
+        status = create_struct_sd( tsa->lpSecurityDescriptor, &thread_sd, &thread_sd_size );
+        if (status != STATUS_SUCCESS)
+        {
+            RtlFreeHeap( GetProcessHeap(), 0, process_sd );
+            close( socketfd[0] );
+            close( socketfd[1] );
+            WARN( "Invalid thread security descriptor: Status %x\n", status );
+            SetLastError( RtlNtStatusToDosError(status) );
+            return FALSE;
+        }
+    }
+
     RtlAcquirePebLock();
 
     if (!(startup_info = create_startup_info( filename, cmd_line, cur_dir, env, flags, startup,
                                               &startup_info_size )))
     {
         RtlReleasePebLock();
+        RtlFreeHeap( GetProcessHeap(), 0, process_sd );
+        RtlFreeHeap( GetProcessHeap(), 0, thread_sd );
         close( socketfd[0] );
         close( socketfd[1] );
         return FALSE;
@@ -2036,10 +2131,12 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
         req->cpu            = cpu;
         req->info_size      = startup_info_size;
         req->env_size       = (env_end - env) * sizeof(WCHAR);
-        req->process_sd_size = 0;
+        req->process_sd_size = process_sd_size;
 
         wine_server_add_data( req, startup_info, startup_info_size );
         wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) );
+        wine_server_add_data( req, process_sd, process_sd_size );
+        wine_server_add_data( req, thread_sd, thread_sd_size );
         if (!(status = wine_server_call( req )))
         {
             info->dwProcessId = (DWORD)reply->pid;
@@ -2052,6 +2149,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
     SERVER_END_REQ;
 
     RtlReleasePebLock();
+    RtlFreeHeap( GetProcessHeap(), 0, process_sd );
+    RtlFreeHeap( GetProcessHeap(), 0, thread_sd );
+
     if (status)
     {
         switch (status)
-- 
2.1.2

