server: Pass the security descriptor into create_file, if one is specified, and set the initial mode for the file appropriately.
This commit is contained in:
parent
f98556c119
commit
5f5df83281
|
@ -191,6 +191,22 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB
|
||||||
|
|
||||||
if (io->u.Status == STATUS_SUCCESS)
|
if (io->u.Status == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
|
struct security_descriptor *sd = NULL;
|
||||||
|
struct object_attributes objattr;
|
||||||
|
|
||||||
|
objattr.rootdir = 0;
|
||||||
|
objattr.sd_len = 0;
|
||||||
|
objattr.name_len = 0;
|
||||||
|
if (attr)
|
||||||
|
{
|
||||||
|
io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
|
||||||
|
if (io->u.Status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
RtlFreeAnsiString( &unix_name );
|
||||||
|
return io->u.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SERVER_START_REQ( create_file )
|
SERVER_START_REQ( create_file )
|
||||||
{
|
{
|
||||||
req->access = access;
|
req->access = access;
|
||||||
|
@ -199,11 +215,14 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB
|
||||||
req->create = disposition;
|
req->create = disposition;
|
||||||
req->options = options;
|
req->options = options;
|
||||||
req->attrs = attributes;
|
req->attrs = attributes;
|
||||||
|
wine_server_add_data( req, &objattr, sizeof(objattr) );
|
||||||
|
if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
|
||||||
wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
|
wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
|
||||||
io->u.Status = wine_server_call( req );
|
io->u.Status = wine_server_call( req );
|
||||||
*handle = reply->handle;
|
*handle = reply->handle;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
NTDLL_free_struct_sd( sd );
|
||||||
RtlFreeAnsiString( &unix_name );
|
RtlFreeAnsiString( &unix_name );
|
||||||
}
|
}
|
||||||
else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
|
else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
|
||||||
|
|
142
server/file.c
142
server/file.c
|
@ -75,6 +75,7 @@ static void file_destroy( struct object *obj );
|
||||||
static int file_get_poll_events( struct fd *fd );
|
static int file_get_poll_events( struct fd *fd );
|
||||||
static void file_flush( struct fd *fd, struct event **event );
|
static void file_flush( struct fd *fd, struct event **event );
|
||||||
static enum server_fd_type file_get_fd_type( struct fd *fd );
|
static enum server_fd_type file_get_fd_type( struct fd *fd );
|
||||||
|
static mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
|
||||||
|
|
||||||
static const struct object_ops file_ops =
|
static const struct object_ops file_ops =
|
||||||
{
|
{
|
||||||
|
@ -154,7 +155,7 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
|
||||||
|
|
||||||
static struct object *create_file( const char *nameptr, data_size_t len, unsigned int access,
|
static struct object *create_file( const char *nameptr, data_size_t len, unsigned int access,
|
||||||
unsigned int sharing, int create, unsigned int options,
|
unsigned int sharing, int create, unsigned int options,
|
||||||
unsigned int attrs )
|
unsigned int attrs, const struct security_descriptor *sd )
|
||||||
{
|
{
|
||||||
struct object *obj = NULL;
|
struct object *obj = NULL;
|
||||||
struct fd *fd;
|
struct fd *fd;
|
||||||
|
@ -177,11 +178,26 @@ static struct object *create_file( const char *nameptr, data_size_t len, unsigne
|
||||||
default: set_error( STATUS_INVALID_PARAMETER ); goto done;
|
default: set_error( STATUS_INVALID_PARAMETER ); goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sd)
|
||||||
|
{
|
||||||
|
const SID *owner = sd_get_owner( sd );
|
||||||
|
if (!owner)
|
||||||
|
owner = token_get_user( current->process->token );
|
||||||
|
mode = sd_to_mode( sd, owner );
|
||||||
|
}
|
||||||
|
else
|
||||||
mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
|
mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
|
||||||
|
|
||||||
if (len >= 4 &&
|
if (len >= 4 &&
|
||||||
(!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" )))
|
(!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" )))
|
||||||
mode |= 0111;
|
{
|
||||||
|
if (mode & S_IRUSR)
|
||||||
|
mode |= S_IXUSR;
|
||||||
|
if (mode & S_IRGRP)
|
||||||
|
mode |= S_IXGRP;
|
||||||
|
if (mode & S_IROTH)
|
||||||
|
mode |= S_IXOTH;
|
||||||
|
}
|
||||||
|
|
||||||
access = generic_file_map_access( access );
|
access = generic_file_map_access( access );
|
||||||
|
|
||||||
|
@ -395,57 +411,24 @@ static struct security_descriptor *file_get_sd( struct object *obj )
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
|
static mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner )
|
||||||
unsigned int set_info )
|
|
||||||
{
|
{
|
||||||
struct file *file = (struct file *)obj;
|
mode_t new_mode = 0;
|
||||||
mode_t new_mode;
|
|
||||||
mode_t denied_mode = 0;
|
mode_t denied_mode = 0;
|
||||||
const SID *owner;
|
|
||||||
int unix_fd;
|
|
||||||
|
|
||||||
assert( obj->ops == &file_ops );
|
|
||||||
|
|
||||||
unix_fd = get_file_unix_fd( file );
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
/* group and sacl not supported */
|
|
||||||
|
|
||||||
/* keep the bits that we don't map to access rights in the ACL */
|
|
||||||
new_mode = file->mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXG);
|
|
||||||
|
|
||||||
if (set_info & DACL_SECURITY_INFORMATION)
|
|
||||||
{
|
|
||||||
int present;
|
int present;
|
||||||
const ACL *dacl = sd_get_dacl( sd, &present );
|
const ACL *dacl = sd_get_dacl( sd, &present );
|
||||||
if (present && dacl)
|
if (present && dacl)
|
||||||
{
|
{
|
||||||
const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1);
|
const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1);
|
||||||
ULONG i;
|
ULONG i;
|
||||||
for (i = 0; i < dacl->AceCount; i++)
|
for (i = 0; i < dacl->AceCount; i++, ace_next( ace ))
|
||||||
{
|
{
|
||||||
const ACCESS_ALLOWED_ACE *aa_ace;
|
const ACCESS_ALLOWED_ACE *aa_ace;
|
||||||
const ACCESS_DENIED_ACE *ad_ace;
|
const ACCESS_DENIED_ACE *ad_ace;
|
||||||
const SID *sid;
|
const SID *sid;
|
||||||
|
|
||||||
|
if (ace->AceFlags & INHERIT_ONLY_ACE) continue;
|
||||||
|
|
||||||
switch (ace->AceType)
|
switch (ace->AceType)
|
||||||
{
|
{
|
||||||
case ACCESS_DENIED_ACE_TYPE:
|
case ACCESS_DENIED_ACE_TYPE:
|
||||||
|
@ -497,22 +480,64 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ace = ace_next( ace );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* no ACL means full access rights to anyone */
|
/* no ACL means full access rights to anyone */
|
||||||
new_mode |= S_IRWXU | S_IRWXO;
|
new_mode = S_IRWXU | S_IRWXO;
|
||||||
|
|
||||||
if (file->mode != (new_mode & ~denied_mode))
|
return new_mode & ~denied_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_set_sd( struct object *obj, const struct security_descriptor *sd,
|
||||||
|
unsigned int set_info )
|
||||||
{
|
{
|
||||||
if (fchmod( unix_fd, new_mode & ~denied_mode ) == -1)
|
struct file *file = (struct file *)obj;
|
||||||
|
const SID *owner;
|
||||||
|
mode_t mode;
|
||||||
|
int unix_fd;
|
||||||
|
|
||||||
|
assert( obj->ops == &file_ops );
|
||||||
|
|
||||||
|
unix_fd = get_file_unix_fd( file );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
/* group and sacl not supported */
|
||||||
|
|
||||||
|
if (set_info & DACL_SECURITY_INFORMATION)
|
||||||
|
{
|
||||||
|
/* keep the bits that we don't map to access rights in the ACL */
|
||||||
|
mode = file->mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXG);
|
||||||
|
mode |= sd_to_mode( sd, owner );
|
||||||
|
|
||||||
|
if (file->mode != mode)
|
||||||
|
{
|
||||||
|
if (fchmod( unix_fd, mode ) == -1)
|
||||||
{
|
{
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->mode = new_mode & ~denied_mode;
|
file->mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -625,10 +650,31 @@ int grow_file( struct file *file, file_pos_t size )
|
||||||
DECL_HANDLER(create_file)
|
DECL_HANDLER(create_file)
|
||||||
{
|
{
|
||||||
struct object *file;
|
struct object *file;
|
||||||
|
const struct object_attributes *objattr = get_req_data();
|
||||||
|
const struct security_descriptor *sd;
|
||||||
|
const char *name;
|
||||||
|
data_size_t name_len;
|
||||||
|
|
||||||
reply->handle = 0;
|
reply->handle = 0;
|
||||||
if ((file = create_file( get_req_data(), get_req_data_size(), req->access,
|
|
||||||
req->sharing, req->create, req->options, req->attrs )))
|
if (!objattr_is_valid( objattr, get_req_data_size() ))
|
||||||
|
return;
|
||||||
|
/* name is transferred in the unix codepage outside of the objattr structure */
|
||||||
|
if (objattr->name_len)
|
||||||
|
{
|
||||||
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL;
|
||||||
|
|
||||||
|
name = (const char *)get_req_data() + sizeof(*objattr) + objattr->sd_len;
|
||||||
|
name_len = get_req_data_size() - sizeof(*objattr) - objattr->sd_len;
|
||||||
|
|
||||||
|
reply->handle = 0;
|
||||||
|
if ((file = create_file( name, name_len, req->access,
|
||||||
|
req->sharing, req->create, req->options,
|
||||||
|
req->attrs, sd )))
|
||||||
{
|
{
|
||||||
reply->handle = alloc_handle( current->process, file, req->access, req->attributes );
|
reply->handle = alloc_handle( current->process, file, req->access, req->attributes );
|
||||||
release_object( file );
|
release_object( file );
|
||||||
|
|
|
@ -848,6 +848,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
||||||
int create; /* file create action */
|
int create; /* file create action */
|
||||||
unsigned int options; /* file options */
|
unsigned int options; /* file options */
|
||||||
unsigned int attrs; /* file attributes for creation */
|
unsigned int attrs; /* file attributes for creation */
|
||||||
|
VARARG(objattr,object_attributes); /* object attributes */
|
||||||
VARARG(filename,string); /* file name */
|
VARARG(filename,string); /* file name */
|
||||||
@REPLY
|
@REPLY
|
||||||
obj_handle_t handle; /* handle to the file */
|
obj_handle_t handle; /* handle to the file */
|
||||||
|
|
Loading…
Reference in New Issue