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;
+ struct security_descriptor *new_sd, *sd, orig_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;
+ orig_sd = *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);
}
- status = pvfs_acl_save(pvfs, name, fd, acl);
+ 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);
+ }
+ }
+
+ /* we avoid saving if the sd is the same. This means when clients
+ copy files and end up copying the default sd that we don't
+ needlessly use xattrs */
+ if (!security_descriptor_equal(sd, &orig_sd)) {
+ status = pvfs_acl_save(pvfs, name, fd, acl);
+ }
return status;
}
return NT_STATUS_ACCESS_DENIED;
}
+ *access_mask |= SEC_FILE_READ_ATTRIBUTE;
+
return NT_STATUS_OK;
}
/* expand the generic access bits to file specific bits */
*access_mask = pvfs_translate_mask(*access_mask);
+ *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
+
/* check the acl against the required access mask */
status = sec_access_check(sd, token, *access_mask, access_mask);
*/
NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
struct smbsrv_request *req,
- struct pvfs_filename *name)
+ struct pvfs_filename *name,
+ uint32_t *access_mask)
+{
+ struct pvfs_filename *parent;
+ NTSTATUS status;
+
+ status = pvfs_resolve_parent(pvfs, req, name, &parent);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = pvfs_access_check(pvfs, req, parent, access_mask);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
+ return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
+ }
+
+ return status;
+}
+
+/*
+ access check for creating a new file/directory - no access mask supplied
+*/
+NTSTATUS pvfs_access_check_create_nomask(struct pvfs_state *pvfs,
+ struct smbsrv_request *req,
+ struct pvfs_filename *name)
{
struct pvfs_filename *parent;
NTSTATUS status;
for (i=0;i<parent_sd->dacl->num_aces;i++) {
struct security_ace ace = parent_sd->dacl->aces[i];
NTSTATUS status;
+ const struct dom_sid *creator = NULL, *new_id = NULL;
+ uint32_t orig_flags;
if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
continue;
}
+ orig_flags = ace.flags;
+
/* see the RAW-ACLS inheritance test for details on these rules */
if (!container) {
ace.flags = 0;
}
}
- status = security_descriptor_dacl_add(sd, &ace);
+ /* the CREATOR sids are special when inherited */
+ if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) {
+ creator = pvfs->sid_cache.creator_owner;
+ new_id = sd->owner_sid;
+ } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) {
+ creator = pvfs->sid_cache.creator_group;
+ new_id = sd->group_sid;
+ } else {
+ new_id = &ace.trustee;
+ }
+
+ if (creator && container &&
+ (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ uint32_t flags = ace.flags;
+
+ ace.trustee = *new_id;
+ ace.flags = 0;
+ status = security_descriptor_dacl_add(sd, &ace);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ace.trustee = *creator;
+ ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY;
+ status = security_descriptor_dacl_add(sd, &ace);
+ } else if (container &&
+ !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ status = security_descriptor_dacl_add(sd, &ace);
+ } else {
+ ace.trustee = *new_id;
+ status = security_descriptor_dacl_add(sd, &ace);
+ }
+
if (!NT_STATUS_IS_OK(status)) {
return status;
}