NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
struct smbsrv_request *req,
struct pvfs_filename *name, int fd,
+ uint32_t access_mask,
union smb_setfileinfo *info)
{
struct xattr_NTACL *acl;
uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
struct security_descriptor *new_sd, *sd;
NTSTATUS status;
+ uid_t uid = -1;
+ gid_t gid = -1;
acl = talloc_p(req, struct xattr_NTACL);
if (acl == NULL) {
new_sd = info->set_secdesc.in.sd;
+ uid = name->st.st_uid;
+ gid = name->st.st_gid;
+
/* only set the elements that have been specified */
- if (secinfo_flags & SECINFO_OWNER) {
+ if ((secinfo_flags & SECINFO_OWNER) &&
+ !dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) {
+ if (!(access_mask & SEC_STD_WRITE_OWNER)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
sd->owner_sid = new_sd->owner_sid;
+ status = sidmap_sid_to_unixuid(pvfs->sidmap, sd->owner_sid, &uid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
- if (secinfo_flags & SECINFO_GROUP) {
+ if ((secinfo_flags & SECINFO_GROUP) &&
+ !dom_sid_equal(sd->group_sid, new_sd->group_sid)) {
sd->group_sid = new_sd->group_sid;
+ status = sidmap_sid_to_unixgid(pvfs->sidmap, sd->owner_sid, &gid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
if (secinfo_flags & SECINFO_DACL) {
sd->dacl = new_sd->dacl;
}
if (secinfo_flags & SECINFO_SACL) {
sd->sacl = new_sd->sacl;
+ if (!(access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
pvfs_translate_generic_bits(sd->sacl);
}
+ if (uid != -1 || gid != -1) {
+ int ret;
+ if (fd == -1) {
+ ret = chown(name->full_name, uid, gid);
+ } else {
+ ret = fchown(fd, uid, gid);
+ }
+ if (ret == -1) {
+ return pvfs_map_errno(pvfs, errno);
+ }
+ }
+
status = pvfs_acl_save(pvfs, name, fd, acl);
return status;
set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
- status = pvfs_acl_set(pvfs, req, name, fd, &set);
+ status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
} else {
/* otherwise setup an inherited acl from the parent */
status = pvfs_acl_inherit(pvfs, req, name, fd);
}
if (access_mask & SEC_FLAG_MAXIMUM_ALLOWED) {
- access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
+ access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE |
+ SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL;
}
+ access_mask |= SEC_FILE_READ_ATTRIBUTE;
+
if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
flags = O_RDWR;
} else {
needed = 0;
break;
+ case RAW_FILEINFO_SEC_DESC:
+ needed = SEC_STD_READ_CONTROL;
+ break;
+
default:
needed = SEC_FILE_READ_ATTRIBUTE;
break;
/*
determine what access bits are needed for a call
*/
-static uint32_t pvfs_setfileinfo_access(enum smb_setfileinfo_level level)
+static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info)
{
uint32_t needed;
- switch (level) {
+ switch (info->generic.level) {
case RAW_SFILEINFO_EA_SET:
needed = SEC_FILE_WRITE_EA;
break;
needed = 0;
break;
+ case RAW_SFILEINFO_SEC_DESC:
+ needed = 0;
+ if (info->set_secdesc.in.secinfo_flags & (SECINFO_DACL|SECINFO_SACL)) {
+ needed |= SEC_STD_WRITE_DAC;
+ }
+ break;
+
default:
needed = SEC_FILE_WRITE_ATTRIBUTE;
break;
h = f->handle;
- access_needed = pvfs_setfileinfo_access(info->generic.level);
+ access_needed = pvfs_setfileinfo_access(info);
if ((f->access_mask & access_needed) != access_needed) {
return NT_STATUS_ACCESS_DENIED;
}
&info->rename_information.in);
case RAW_SFILEINFO_SEC_DESC:
- return pvfs_acl_set(pvfs, req, h->name, h->fd, info);
+ return pvfs_acl_set(pvfs, req, h->name, h->fd, f->access_mask, info);
default:
return NT_STATUS_INVALID_LEVEL;
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- access_needed = pvfs_setfileinfo_access(info->generic.level);
+ access_needed = pvfs_setfileinfo_access(info);
status = pvfs_access_check_simple(pvfs, req, name, access_needed);
if (!NT_STATUS_IS_OK(status)) {
return status;