diff options
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r-- | source4/ntvfs/posix/pvfs_acl.c | 149 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 22 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 11 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_setfileinfo.c | 2 |
4 files changed, 124 insertions, 60 deletions
diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index 26515cfe1a..842aced6f2 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -485,6 +485,8 @@ static bool pvfs_group_member(struct pvfs_state *pvfs, gid_t gid) doing this saves on building a full security descriptor for the common case of access check on files with no specific NT ACL + + If name is NULL then treat as a new file creation */ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, struct ntvfs_request *req, @@ -499,13 +501,14 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, return NT_STATUS_ACCESS_DENIED; } - if (uid == name->st.st_uid) { + if (name == NULL || uid == name->st.st_uid) { max_bits |= SEC_STD_ALL; } else if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) { max_bits |= SEC_STD_DELETE; } - if ((name->st.st_mode & S_IWOTH) || + if (name == NULL || + (name->st.st_mode & S_IWOTH) || ((name->st.st_mode & S_IWGRP) && pvfs_group_member(pvfs, name->st.st_gid))) { max_bits |= SEC_STD_ALL; @@ -540,7 +543,7 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, if (*access_mask & ~max_bits) { DEBUG(0,(__location__ " denied access to '%s' - wanted 0x%08x but got 0x%08x (missing 0x%08x)\n", - name->full_name, *access_mask, max_bits, *access_mask & ~max_bits)); + name?name->full_name:"(new file)", *access_mask, max_bits, *access_mask & ~max_bits)); return NT_STATUS_ACCESS_DENIED; } @@ -643,26 +646,47 @@ NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs, NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, - uint32_t *access_mask) + uint32_t *access_mask, + bool container, + struct security_descriptor **sd) { struct pvfs_filename *parent; NTSTATUS status; + struct security_token *token = req->session_info->security_token; + + if (pvfs_read_only(pvfs, *access_mask)) { + return NT_STATUS_ACCESS_DENIED; + } 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); + status = pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE); 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); + if (*sd == NULL) { + status = pvfs_acl_inherited_sd(pvfs, req, req, parent, container, sd); } - return status; + talloc_free(parent); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* expand the generic access bits to file specific bits */ + *access_mask = pvfs_translate_mask(*access_mask); + if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { + *access_mask &= ~SEC_FILE_READ_ATTRIBUTE; + } + + if (*sd == NULL) { + return pvfs_access_check_unix(pvfs, req, NULL, access_mask); + } + return sec_access_check(*sd, token, *access_mask, access_mask); } /* @@ -790,47 +814,42 @@ static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs, /* - setup an ACL on a new file/directory based on the inherited ACL from - the parent. If there is no inherited ACL then we don't set anything, - as the default ACL applies anyway + calculate the ACL on a new file/directory based on the inherited ACL + from the parent. If there is no inherited ACL then return a NULL + ACL, which means the default ACL should be used */ -NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, - struct ntvfs_request *req, - struct pvfs_filename *name, - int fd) +NTSTATUS pvfs_acl_inherited_sd(struct pvfs_state *pvfs, + TALLOC_CTX *mem_ctx, + struct ntvfs_request *req, + struct pvfs_filename *parent, + bool container, + struct security_descriptor **ret_sd) { struct xattr_NTACL *acl; NTSTATUS status; - struct pvfs_filename *parent; struct security_descriptor *parent_sd, *sd; - bool container; struct id_mapping *ids; struct composite_context *ctx; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - /* form the parents path */ - status = pvfs_resolve_parent(pvfs, req, name, &parent); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + *ret_sd = NULL; acl = talloc(req, struct xattr_NTACL); - if (acl == NULL) { - return NT_STATUS_NO_MEMORY; - } + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(acl, tmp_ctx); status = pvfs_acl_load(pvfs, parent, -1, acl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + talloc_free(tmp_ctx); return NT_STATUS_OK; } - if (!NT_STATUS_IS_OK(status)) { - return status; - } + NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx); switch (acl->version) { case 1: parent_sd = acl->info.sd; break; default: + talloc_free(tmp_ctx); return NT_STATUS_INVALID_ACL; } @@ -838,61 +857,99 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, parent_sd->dacl == NULL || parent_sd->dacl->num_aces == 0) { /* go with the default ACL */ + talloc_free(tmp_ctx); return NT_STATUS_OK; } /* create the new sd */ sd = security_descriptor_initialise(req); - if (sd == NULL) { - return NT_STATUS_NO_MEMORY; - } + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sd, tmp_ctx); ids = talloc_array(sd, struct id_mapping, 2); - NT_STATUS_HAVE_NO_MEMORY(ids); + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids, tmp_ctx); ids[0].unixid = talloc(ids, struct unixid); - NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); - ids[0].unixid->id = name->st.st_uid; + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids[0].unixid, tmp_ctx); + ids[0].unixid->id = geteuid(); ids[0].unixid->type = ID_TYPE_UID; ids[0].sid = NULL; ids[0].status = NT_STATUS_NONE_MAPPED; ids[1].unixid = talloc(ids, struct unixid); - NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); - ids[1].unixid->id = name->st.st_gid; + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids[1].unixid, tmp_ctx); + ids[1].unixid->id = getegid(); ids[1].unixid->type = ID_TYPE_GID; ids[1].sid = NULL; ids[1].status = NT_STATUS_NONE_MAPPED; ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids); - NT_STATUS_HAVE_NO_MEMORY(ctx); + NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ctx, tmp_ctx); status = wbc_xids_to_sids_recv(ctx, &ids); - NT_STATUS_NOT_OK_RETURN(status); + NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx); sd->owner_sid = talloc_steal(sd, ids[0].sid); sd->group_sid = talloc_steal(sd, ids[1].sid); sd->type |= SEC_DESC_DACL_PRESENT; - container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false; - /* fill in the aces from the parent */ status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx); /* if there is nothing to inherit then we fallback to the default acl */ if (sd->dacl == NULL || sd->dacl->num_aces == 0) { + talloc_free(tmp_ctx); return NT_STATUS_OK; } - acl->info.sd = sd; + *ret_sd = talloc_steal(mem_ctx, sd); + + talloc_free(tmp_ctx); + return NT_STATUS_OK; +} + + +/* + setup an ACL on a new file/directory based on the inherited ACL from + the parent. If there is no inherited ACL then we don't set anything, + as the default ACL applies anyway +*/ +NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, + struct ntvfs_request *req, + struct pvfs_filename *name, + int fd) +{ + struct xattr_NTACL acl; + NTSTATUS status; + struct security_descriptor *sd; + struct pvfs_filename *parent; + bool container; + + /* form the parents path */ + status = pvfs_resolve_parent(pvfs, req, name, &parent); + NT_STATUS_NOT_OK_RETURN(status); + + container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false; + + status = pvfs_acl_inherited_sd(pvfs, req, req, parent, container, &sd); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(parent); + return status; + } + + if (sd == NULL) { + return NT_STATUS_OK; + } + + acl.version = 1; + acl.info.sd = sd; + + status = pvfs_acl_save(pvfs, name, fd, &acl); + talloc_free(sd); + talloc_free(parent); - status = pvfs_acl_save(pvfs, name, fd, acl); - return status; } diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index e8f1c0c4c8..59bd67b08d 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -103,10 +103,10 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd, struct pvfs_file *f, - union smb_open *io) + union smb_open *io, + struct security_descriptor *sd) { NTSTATUS status; - struct security_descriptor *sd; /* setup any EAs that were asked for */ if (io->ntcreatex.in.ea_list) { @@ -118,7 +118,6 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs, } } - sd = io->ntcreatex.in.sec_desc; /* setup an initial sec_desc if requested */ if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) { union smb_setfileinfo set; @@ -134,9 +133,6 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs, set.set_secdesc.in.sd = sd; 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); } return status; @@ -185,6 +181,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, uint32_t create_options; uint32_t share_access; bool forced; + struct security_descriptor *sd = NULL; create_options = io->generic.in.create_options; share_access = io->generic.in.share_access; @@ -251,8 +248,9 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, if (name->exists) { /* check the security descriptor */ status = pvfs_access_check(pvfs, req, name, &access_mask); - } else { - status = pvfs_access_check_create(pvfs, req, name, &access_mask); + } else { + sd = io->ntcreatex.in.sec_desc; + status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd); } NT_STATUS_NOT_OK_RETURN(status); @@ -352,7 +350,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, goto cleanup_delete; } - status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io); + status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } @@ -616,6 +614,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, struct pvfs_filename *parent; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; bool allow_level_II_oplock = false; + struct security_descriptor *sd = NULL; if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) { return NT_STATUS_INVALID_PARAMETER; @@ -630,7 +629,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, return NT_STATUS_CANNOT_DELETE; } - status = pvfs_access_check_create(pvfs, req, name, &access_mask); + sd = io->ntcreatex.in.sec_desc; + status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd); NT_STATUS_NOT_OK_RETURN(status); /* check that the parent isn't opened with delete on close set */ @@ -698,7 +698,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, } - status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io); + status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index 8e8da72e1f..8c5806d93f 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -498,13 +498,14 @@ static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, TODO: ../ collapsing, and outside share checking */ -NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, +NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, + struct ntvfs_request *req, const char *cifs_name, uint_t flags, struct pvfs_filename **name) { NTSTATUS status; - *name = talloc(mem_ctx, struct pvfs_filename); + *name = talloc(req, struct pvfs_filename); if (*name == NULL) { return NT_STATUS_NO_MEMORY; } @@ -516,6 +517,12 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, flags &= ~PVFS_RESOLVE_STREAMS; } + /* SMB2 doesn't allow a leading slash */ + if (req->ctx->protocol == PROTOCOL_SMB2 && + *cifs_name == '\\') { + return NT_STATUS_INVALID_PARAMETER; + } + /* do the basic conversion to a unix formatted path, also checking for allowable characters */ status = pvfs_unix_path(pvfs, cifs_name, flags, *name); diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 9fe02a8e17..244548382c 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -168,7 +168,7 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, } /* resolve the new name */ - status = pvfs_resolve_name(pvfs, name, new_name, 0, &name2); + status = pvfs_resolve_name(pvfs, req, new_name, 0, &name2); if (!NT_STATUS_IS_OK(status)) { return status; } |