Paul Bryan Roberts : server: Clone file_get_sd() and file_set_fd() for directories.

Alexandre Julliard julliard at winehq.org
Fri Nov 7 07:24:07 CST 2008


Module: wine
Branch: master
Commit: 6435a5ddabda596d1c60d94a8f99ce19be95ac6d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6435a5ddabda596d1c60d94a8f99ce19be95ac6d

Author: Paul Bryan Roberts <pbronline-wine at yahoo.co.uk>
Date:   Mon Nov  3 22:37:17 2008 +0000

server: Clone file_get_sd() and file_set_fd() for directories.

---

 dlls/advapi32/tests/security.c |   37 +++++++++++++++
 server/change.c                |   99 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index d3efa0b..7e2e3f2 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -777,6 +777,43 @@ static void test_FileSecurity(void)
 
     HeapFree (GetProcessHeap (), 0, sd);
 
+    /* Repeat for the temporary directory ... */
+
+    /* Get size needed */
+    retSize = 0;
+    SetLastError (NO_ERROR);
+    rc = pGetFileSecurityA (path, request, NULL, 0, &retSize);
+    ok (!rc, "GetFileSecurityA "
+        "was expected to fail for '%s'\n", path);
+    ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA "
+        "returned %d; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError());
+    ok (retSize > sizeof (SECURITY_DESCRIPTOR), "GetFileSecurityA "
+        "returned size %d; expected > %d\n", retSize, sizeof (SECURITY_DESCRIPTOR));
+
+    sdSize = retSize;
+    sd = HeapAlloc (GetProcessHeap (), 0, sdSize);
+
+    /* Get security descriptor for real */
+    retSize = 0;
+    SetLastError (NO_ERROR);
+    rc = pGetFileSecurityA (path, request, sd, sdSize, &retSize);
+    ok (rc, "GetFileSecurityA "
+        "was not expected to fail '%s'\n", path);
+    ok (GetLastError () == NO_ERROR, "GetFileSecurityA "
+        "returned %d; expected NO_ERROR\n", GetLastError ());
+    ok (retSize == sdSize, "GetFileSecurityA "
+        "returned size %d; expected %d\n", retSize, sdSize);
+
+    /* Use it to set security descriptor */
+    SetLastError (NO_ERROR);
+    rc = pSetFileSecurityA (path, request, sd);
+    ok (rc, "SetFileSecurityA "
+        "was not expected to fail '%s'\n", path);
+    ok (GetLastError () == NO_ERROR, "SetFileSecurityA "
+        "returned %d; expected NO_ERROR\n", GetLastError ());
+
+    HeapFree (GetProcessHeap (), 0, sd);
+
     /* Remove temporary file and directory */
     DeleteFileA (file);
     RemoveDirectoryA (path);
diff --git a/server/change.c b/server/change.c
index 2c690e0..aded849 100644
--- a/server/change.c
+++ b/server/change.c
@@ -44,6 +44,8 @@
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
+#include "process.h"
+#include "security.h"
 #include "winternl.h"
 
 /* dnotify support */
@@ -146,6 +148,8 @@ struct dir
 {
     struct object  obj;      /* object header */
     struct fd     *fd;       /* file descriptor to the directory */
+    mode_t         mode;     /* file stat.st_mode */
+    uid_t          uid;      /* file stat.st_uid */
     struct list    entry;    /* entry in global change notifications list */
     unsigned int   filter;   /* notification filter */
     int            notified; /* SIGIO counter */
@@ -157,6 +161,9 @@ struct dir
 };
 
 static struct fd *dir_get_fd( struct object *obj );
+static struct security_descriptor *dir_get_sd( struct object *obj );
+static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
+                       unsigned int set_info );
 static void dir_dump( struct object *obj, int verbose );
 static void dir_destroy( struct object *obj );
 
@@ -172,8 +179,8 @@ static const struct object_ops dir_ops =
     no_signal,                /* signal */
     dir_get_fd,               /* get_fd */
     default_fd_map_access,    /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
+    dir_get_sd,               /* get_sd */
+    dir_set_sd,               /* set_sd */
     no_lookup_name,           /* lookup_name */
     no_open_file,             /* open_file */
     fd_close_handle,          /* close_handle */
@@ -291,6 +298,94 @@ static struct fd *dir_get_fd( struct object *obj )
     return (struct fd *)grab_object( dir->fd );
 }
 
+static int get_dir_unix_fd( struct dir *dir )
+{
+    return get_unix_fd( dir->fd );
+}
+
+static struct security_descriptor *dir_get_sd( struct object *obj )
+{
+    struct dir *dir = (struct dir *)obj;
+    int unix_fd;
+    struct stat st;
+    struct security_descriptor *sd;
+    assert( obj->ops == &dir_ops );
+
+    unix_fd = get_dir_unix_fd( dir );
+
+    if (unix_fd == -1 || fstat( unix_fd, &st ) == -1)
+        return obj->sd;
+
+    /* mode and uid the same? if so, no need to re-generate security descriptor */
+    if (obj->sd &&
+        (st.st_mode & (S_IRWXU|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXO)) &&
+        (st.st_uid == dir->uid))
+        return obj->sd;
+
+    sd = mode_to_sd( st.st_mode,
+                     security_unix_uid_to_sid( st.st_uid ),
+                     token_get_primary_group( current->process->token ));
+    if (!sd) return obj->sd;
+
+    dir->mode = st.st_mode;
+    dir->uid = st.st_uid;
+    free( obj->sd );
+    obj->sd = sd;
+    return sd;
+}
+
+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;
+    mode_t mode;
+    int unix_fd;
+
+    assert( obj->ops == &dir_ops );
+
+    unix_fd = get_dir_unix_fd( dir );
+
+    if (unix_fd == -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 = dir->mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXG);
+        mode |= sd_to_mode( sd, owner );
+
+        if (dir->mode != mode)
+        {
+            if (fchmod( unix_fd, mode ) == -1)
+            {
+                file_set_error();
+                return 0;
+            }
+
+            dir->mode = mode;
+        }
+    }
+    return 1;
+}
+
 static struct change_record *get_first_change_record( struct dir *dir )
 {
     struct list *ptr = list_head( &dir->change_records );




More information about the wine-cvs mailing list