summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/posix/pvfs_acl.c149
-rw-r--r--source4/ntvfs/posix/pvfs_open.c22
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c11
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c2
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;
}