summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/modules/vfs_acl_common.c109
-rw-r--r--source3/modules/vfs_acl_tdb.c1
-rw-r--r--source3/modules/vfs_acl_xattr.c1
3 files changed, 104 insertions, 7 deletions
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 0bb0bca2db..0919dcc8be 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -186,6 +186,20 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ /* Pull the ACL from the underlying system. */
+ if (fsp) {
+ status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
+ fsp,
+ security_info,
+ ppdesc);
+ } else {
+ status = SMB_VFS_NEXT_GET_NT_ACL(handle,
+ name,
+ security_info,
+ ppdesc);
+ }
+ }
return status;
}
@@ -478,6 +492,51 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
}
}
+static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
+ const char *path,
+ uint32_t access_mask)
+{
+ char *parent_name = NULL;
+ struct security_descriptor *parent_desc = NULL;
+ uint32_t access_granted = 0;
+ NTSTATUS status;
+
+ if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = SMB_VFS_GET_NT_ACL(handle->conn,
+ parent_name,
+ (OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION),
+ &parent_desc);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("check_parent_acl_common: SMB_VFS_GET_NT_ACL "
+ "on directory %s for "
+ "path %s returned %s\n",
+ parent_name,
+ path,
+ nt_errstr(status) ));
+ return status;
+ }
+ status = smb1_file_se_access_check(parent_desc,
+ handle->conn->server_info->ptok,
+ access_mask,
+ &access_granted);
+ if(!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("check_parent_acl_common: access check "
+ "on directory %s for "
+ "path %s for mask 0x%x returned %s\n",
+ parent_name,
+ path,
+ access_mask,
+ nt_errstr(status) ));
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
/*********************************************************************
Check ACL on open. For new files inherit from parent directory.
*********************************************************************/
@@ -504,8 +563,7 @@ static int open_acl_common(vfs_handle_struct *handle,
status = get_full_smb_filename(talloc_tos(), smb_fname,
&fname);
if (!NT_STATUS_IS_OK(status)) {
- errno = map_errno_from_nt_status(status);
- return -1;
+ goto err;
}
status = get_nt_acl_internal(handle,
@@ -526,11 +584,21 @@ static int open_acl_common(vfs_handle_struct *handle,
"refused with error %s\n",
smb_fname_str_dbg(smb_fname),
nt_errstr(status) ));
- errno = map_errno_from_nt_status(status);
- return -1;
+ goto err;
}
} else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
file_existed = false;
+ /*
+ * If O_CREAT is true then we're trying to create a file.
+ * Check the parent directory ACL will allow this.
+ */
+ if (flags & O_CREAT) {
+ status = check_parent_acl_common(handle, fname,
+ SEC_DIR_ADD_FILE);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err;
+ }
+ }
}
DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
@@ -544,21 +612,38 @@ static int open_acl_common(vfs_handle_struct *handle,
/* File was created. Inherit from parent directory. */
status = fsp_set_smb_fname(fsp, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
- errno = map_errno_from_nt_status(status);
- return -1;
+ goto err;
}
inherit_new_acl(handle, smb_fname, fsp, false);
}
return fsp->fh->fd;
+
+ err:
+
+ errno = map_errno_from_nt_status(status);
+ return -1;
}
static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
{
struct smb_filename *smb_fname = NULL;
- int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
+ int ret;
NTSTATUS status;
+ SMB_STRUCT_STAT sbuf;
+ ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
+ if (ret == -1 && errno == ENOENT) {
+ /* We're creating a new directory. */
+ status = check_parent_acl_common(handle, path,
+ SEC_DIR_ADD_SUBDIR);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
+ return -1;
+ }
+ }
+
+ ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
if (ret == -1) {
return ret;
}
@@ -691,3 +776,13 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
return NT_STATUS_OK;
}
+
+static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr)
+{
+ NTSTATUS status = check_parent_acl_common(handle, fname, SEC_DIR_LIST);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ }
+ return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+}
diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c
index e9d0f9027a..f9e766d001 100644
--- a/source3/modules/vfs_acl_tdb.c
+++ b/source3/modules/vfs_acl_tdb.c
@@ -461,6 +461,7 @@ static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
static struct vfs_fn_pointers vfs_acl_tdb_fns = {
.connect_fn = connect_acl_tdb,
+ .opendir = opendir_acl_common,
.mkdir = mkdir_acl_common,
.open = open_acl_common,
.unlink = unlink_acl_tdb,
diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c
index 5e51a68875..c1812b9278 100644
--- a/source3/modules/vfs_acl_xattr.c
+++ b/source3/modules/vfs_acl_xattr.c
@@ -232,6 +232,7 @@ static int connect_acl_xattr(struct vfs_handle_struct *handle,
static struct vfs_fn_pointers vfs_acl_xattr_fns = {
.connect_fn = connect_acl_xattr,
+ .opendir = opendir_acl_common,
.mkdir = mkdir_acl_common,
.open = open_acl_common,
.fget_nt_acl = fget_nt_acl_common,