From d294da0642e0fafe103120915f835d529840d233 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 30 Mar 2015 12:32:34 +0200
Subject: server: Add a helper function set_sd_from_token_internal to merge two
 security descriptors.

---
 server/object.c | 59 ++++++++++++++++++++++++++++++++++++---------------------
 server/object.h |  3 +++
 2 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/server/object.c b/server/object.c
index 4455718aac..522035bcb8 100644
--- a/server/object.c
+++ b/server/object.c
@@ -535,8 +535,9 @@ struct security_descriptor *default_get_sd( struct object *obj )
     return obj->sd;
 }
 
-int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
-                                unsigned int set_info, struct token *token )
+struct security_descriptor *set_sd_from_token_internal( const struct security_descriptor *sd,
+                                                        const struct security_descriptor *old_sd,
+                                                        unsigned int set_info, struct token *token )
 {
     struct security_descriptor new_sd, *new_sd_ptr;
     int present;
@@ -545,8 +546,6 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
     ACL *replaced_sacl = NULL;
     char *ptr;
 
-    if (!set_info) return 1;
-
     new_sd.control = sd->control & ~SE_SELF_RELATIVE;
 
     if (set_info & OWNER_SECURITY_INFORMATION && sd->owner_len)
@@ -554,10 +553,10 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
         owner = sd_get_owner( sd );
         new_sd.owner_len = sd->owner_len;
     }
-    else if (obj->sd && obj->sd->owner_len)
+    else if (old_sd && old_sd->owner_len)
     {
-        owner = sd_get_owner( obj->sd );
-        new_sd.owner_len = obj->sd->owner_len;
+        owner = sd_get_owner( old_sd );
+        new_sd.owner_len = old_sd->owner_len;
     }
     else if (token)
     {
@@ -571,10 +570,10 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
         group = sd_get_group( sd );
         new_sd.group_len = sd->group_len;
     }
-    else if (obj->sd && obj->sd->group_len)
+    else if (old_sd && old_sd->group_len)
     {
-        group = sd_get_group( obj->sd );
-        new_sd.group_len = obj->sd->group_len;
+        group = sd_get_group( old_sd );
+        new_sd.group_len = old_sd->group_len;
     }
     else if (token)
     {
@@ -592,20 +591,20 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
     else if (set_info & LABEL_SECURITY_INFORMATION && present)
     {
         const ACL *old_sacl = NULL;
-        if (obj->sd && obj->sd->control & SE_SACL_PRESENT) old_sacl = sd_get_sacl( obj->sd, &present );
-        if (!(replaced_sacl = replace_security_labels( old_sacl, sacl ))) return 0;
+        if (old_sd && old_sd->control & SE_SACL_PRESENT) old_sacl = sd_get_sacl( old_sd, &present );
+        if (!(replaced_sacl = replace_security_labels( old_sacl, sacl ))) return NULL;
         new_sd.control |= SE_SACL_PRESENT;
         new_sd.sacl_len = replaced_sacl->AclSize;
         sacl = replaced_sacl;
     }
     else
     {
-        if (obj->sd) sacl = sd_get_sacl( obj->sd, &present );
+        if (old_sd) sacl = sd_get_sacl( old_sd, &present );
 
-        if (obj->sd && present)
+        if (old_sd && present)
         {
             new_sd.control |= SE_SACL_PRESENT;
-            new_sd.sacl_len = obj->sd->sacl_len;
+            new_sd.sacl_len = old_sd->sacl_len;
         }
         else
             new_sd.sacl_len = 0;
@@ -619,12 +618,12 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
     }
     else
     {
-        if (obj->sd) dacl = sd_get_dacl( obj->sd, &present );
+        if (old_sd) dacl = sd_get_dacl( old_sd, &present );
 
-        if (obj->sd && present)
+        if (old_sd && present)
         {
             new_sd.control |= SE_DACL_PRESENT;
-            new_sd.dacl_len = obj->sd->dacl_len;
+            new_sd.dacl_len = old_sd->dacl_len;
         }
         else if (token)
         {
@@ -640,7 +639,7 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
     if (!ptr)
     {
         free( replaced_sacl );
-        return 0;
+        return NULL;
     }
     new_sd_ptr = (struct security_descriptor*)ptr;
 
@@ -655,9 +654,25 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri
     memcpy( ptr, dacl, new_sd.dacl_len );
 
     free( replaced_sacl );
-    free( obj->sd );
-    obj->sd = new_sd_ptr;
-    return 1;
+    return new_sd_ptr;
+}
+
+int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
+                                unsigned int set_info, struct token *token )
+{
+    struct security_descriptor *new_sd;
+
+    if (!set_info) return 1;
+
+    new_sd = set_sd_from_token_internal( sd, obj->sd, set_info, token );
+    if (new_sd)
+    {
+        free( obj->sd );
+        obj->sd = new_sd;
+        return 1;
+    }
+
+    return 0;
 }
 
 /** Set the security descriptor using the current primary token for defaults. */
diff --git a/server/object.h b/server/object.h
index b5c50e1cee..cfbd5e06bc 100644
--- a/server/object.h
+++ b/server/object.h
@@ -156,6 +156,9 @@ extern struct fd *no_get_fd( struct object *obj );
 extern unsigned int no_map_access( struct object *obj, unsigned int access );
 extern struct security_descriptor *default_get_sd( struct object *obj );
 extern int default_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info );
+extern struct security_descriptor *set_sd_from_token_internal( const struct security_descriptor *sd,
+                                                               const struct security_descriptor *old_sd,
+                                                               unsigned int set_info, struct token *token );
 extern int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
                                        unsigned int set_info, struct token *token );
 extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attributes );
-- 
2.13.1

