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