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

This commit is contained in:
Paul Bryan Roberts 2008-11-03 22:37:17 +00:00 committed by Alexandre Julliard
parent d87af3dfb2
commit 6435a5ddab
2 changed files with 134 additions and 2 deletions

View file

@ -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);

View file

@ -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 );