From 3bafbe9d52d8189439b4969c091324d56c2462ed Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 17 Apr 2014 16:07:46 -0600
Subject: [PATCH] server: Unify the storage of security attributes for files
 and directories. (try 7)

---
 server/change.c | 45 ++++++---------------------------------------
 server/file.c   | 34 ++++++++++++++++++++++------------
 server/file.h   |  2 ++
 3 files changed, 30 insertions(+), 51 deletions(-)

diff --git a/server/change.c b/server/change.c
index 1c384310d59..1e27e266fc1 100644
--- a/server/change.c
+++ b/server/change.c
@@ -373,48 +373,15 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
                        unsigned int set_info )
 {
     struct dir *dir = (struct dir *)obj;
-    const SID *owner;
-    struct stat st;
-    mode_t mode;
-    int unix_fd;
+    struct fd *fd;
+    int ret;
 
     assert( obj->ops == &dir_ops );
 
-    unix_fd = get_dir_unix_fd( dir );
-
-    if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
-
-    if (set_info & OWNER_SECURITY_INFORMATION)
-    {
-        owner = sd_get_owner( sd );
-        if (!owner)
-        {
-            set_error( STATUS_INVALID_SECURITY_DESCR );
-            return 0;
-        }
-        if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) ))
-        {
-            /* FIXME: get Unix uid and call fchown */
-        }
-    }
-    else if (obj->sd)
-        owner = sd_get_owner( obj->sd );
-    else
-        owner = token_get_user( current->process->token );
-
-    if (set_info & DACL_SECURITY_INFORMATION)
-    {
-        /* keep the bits that we don't map to access rights in the ACL */
-        mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
-        mode |= sd_to_mode( sd, owner );
-
-        if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
-        {
-            file_set_error();
-            return 0;
-        }
-    }
-    return 1;
+    fd = dir_get_fd( obj );
+    ret = set_file_sd( obj, fd, &dir->mode, &dir->uid, sd, set_info );
+    release_object( fd );
+    return ret;
 }
 
 static struct change_record *get_first_change_record( struct dir *dir )
diff --git a/server/file.c b/server/file.c
index af080ffc5fb..34da2168643 100644
--- a/server/file.c
+++ b/server/file.c
@@ -562,18 +562,13 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
     return new_mode;
 }
 
-static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
-                        unsigned int set_info )
+int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid,
+                 const struct security_descriptor *sd, unsigned int set_info )
 {
-    struct file *file = (struct file *)obj;
+    int unix_fd = get_unix_fd( fd );
     const SID *owner;
     struct stat st;
-    mode_t mode;
-    int unix_fd;
-
-    assert( obj->ops == &file_ops );
-
-    unix_fd = get_file_unix_fd( file );
+    mode_t new_mode;
 
     if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
 
@@ -600,10 +595,10 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
     if (set_info & DACL_SECURITY_INFORMATION)
     {
         /* keep the bits that we don't map to access rights in the ACL */
-        mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
-        mode |= sd_to_mode( sd, owner );
+        new_mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
+        new_mode |= sd_to_mode( sd, owner );
 
-        if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
+        if (((st.st_mode ^ new_mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, new_mode ) == -1)
         {
             file_set_error();
             return 0;
@@ -645,6 +640,21 @@ static struct list *file_get_kernel_obj_list( struct object *obj )
     return &file->kernel_object;
 }
 
+static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
+                        unsigned int set_info )
+{
+    struct file *file = (struct file *)obj;
+    struct fd *fd;
+    int ret;
+
+    assert( obj->ops == &file_ops );
+
+    fd = file_get_fd( obj );
+    ret = set_file_sd( obj, fd, &file->mode, &file->uid, sd, set_info );
+    release_object( fd );
+    return ret;
+}
+
 static void file_destroy( struct object *obj )
 {
     struct file *file = (struct file *)obj;
diff --git a/server/file.h b/server/file.h
index 69b2b368aed..d241927ebbd 100644
--- a/server/file.h
+++ b/server/file.h
@@ -151,6 +151,8 @@ extern struct object_type *file_get_type( struct object *obj );
 extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group );
 extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
 extern int is_file_executable( const char *name );
+extern int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid,
+                        const struct security_descriptor *sd, unsigned int set_info );
 
 /* file mapping functions */
 
-- 
2.17.1

