From e913a48ded85e7baf91a355fff46fe270afed936 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 30 Dec 2004 05:50:23 +0000 Subject: r4408: added the remaining access check hooks into pvfs. All calls should now have acl checking, and obey the various inheritance rules. (This used to be commit 5fe51807d6b97e68b65f152c0f405e5c5a025d21) --- source4/ntvfs/posix/pvfs_acl.c | 21 ++++++++++++++ source4/ntvfs/posix/pvfs_mkdir.c | 16 +++++++++++ source4/ntvfs/posix/pvfs_open.c | 18 +++++++++--- source4/ntvfs/posix/pvfs_qfileinfo.c | 37 ++++++++++++++++++++++++ source4/ntvfs/posix/pvfs_rename.c | 22 ++++++++++++++ source4/ntvfs/posix/pvfs_setfileinfo.c | 52 ++++++++++++++++++++++++++++++++-- 6 files changed, 159 insertions(+), 7 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index c2309b92ea..a5cd9ebd79 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -371,9 +371,30 @@ NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs, struct pvfs_filename *name, uint32_t access_needed) { + if (access_needed == 0) { + return NT_STATUS_OK; + } return pvfs_access_check(pvfs, req, name, &access_needed); } +/* + access check for creating a new file/directory +*/ +NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_filename *name) +{ + struct pvfs_filename *parent; + NTSTATUS status; + + status = pvfs_resolve_parent(pvfs, req, name, &parent); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return pvfs_access_check_simple(pvfs, req, name, SEC_DIR_ADD_FILE); +} + /* determine if an ACE is inheritable diff --git a/source4/ntvfs/posix/pvfs_mkdir.c b/source4/ntvfs/posix/pvfs_mkdir.c index 14fffb6a2e..d2d431ae79 100644 --- a/source4/ntvfs/posix/pvfs_mkdir.c +++ b/source4/ntvfs/posix/pvfs_mkdir.c @@ -22,6 +22,7 @@ #include "includes.h" #include "vfs_posix.h" +#include "librpc/gen_ndr/ndr_security.h" /* create a directory with EAs @@ -43,6 +44,11 @@ static NTSTATUS pvfs_t2mkdir(struct pvfs_state *pvfs, return NT_STATUS_OBJECT_NAME_COLLISION; } + status = pvfs_access_check_create(pvfs, req, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + mode = pvfs_fileperms(pvfs, FILE_ATTRIBUTE_DIRECTORY); if (mkdir(name->full_name, mode) == -1) { @@ -108,6 +114,11 @@ NTSTATUS pvfs_mkdir(struct ntvfs_module_context *ntvfs, return NT_STATUS_OBJECT_NAME_COLLISION; } + status = pvfs_access_check_create(pvfs, req, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + mode = pvfs_fileperms(pvfs, FILE_ATTRIBUTE_DIRECTORY); if (mkdir(name->full_name, mode) == -1) { @@ -146,6 +157,11 @@ NTSTATUS pvfs_rmdir(struct ntvfs_module_context *ntvfs, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = pvfs_xattr_unlink_hook(pvfs, name->full_name); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 1695d8e1d9..3941414cd8 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -198,10 +198,12 @@ 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); - if (!NT_STATUS_IS_OK(status)) { - idr_remove(pvfs->idtree_fnum, fnum); - return status; - } + } else { + status = pvfs_access_check_create(pvfs, req, name); + } + if (!NT_STATUS_IS_OK(status)) { + idr_remove(pvfs->idtree_fnum, fnum); + return status; } f->fnum = fnum; @@ -450,6 +452,11 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, mode_t mode; uint32_t attrib; + status = pvfs_access_check_create(pvfs, req, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { return NT_STATUS_CANNOT_DELETE; @@ -1065,6 +1072,9 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, /* if this was a stream create then create the stream as well */ if (!name->stream_exists) { + if (!(access_mask & SEC_FILE_WRITE_ATTRIBUTE)) { + return NT_STATUS_ACCESS_DENIED; + } status = pvfs_stream_create(pvfs, f->handle->name, fd); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 75a9909492..dae9ca649c 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -24,6 +24,31 @@ #include "vfs_posix.h" #include "librpc/gen_ndr/ndr_xattr.h" + +/* + determine what access bits are needed for a call +*/ +static uint32_t pvfs_fileinfo_access(enum smb_fileinfo_level level) +{ + uint32_t needed; + + switch (level) { + case RAW_FILEINFO_EA_LIST: + case RAW_FILEINFO_ALL_EAS: + needed = SEC_FILE_READ_EA; + break; + + case RAW_FILEINFO_IS_NAME_VALID: + needed = 0; + break; + + default: + needed = SEC_FILE_READ_ATTRIBUTE; + break; + } + return needed; +} + /* reply to a RAW_FILEINFO_EA_LIST call */ @@ -269,6 +294,12 @@ NTSTATUS pvfs_qpathinfo(struct ntvfs_module_context *ntvfs, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + status = pvfs_access_check_simple(pvfs, req, name, + pvfs_fileinfo_access(info->generic.level)); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = pvfs_map_fileinfo(pvfs, req, name, info, -1); return status; @@ -284,6 +315,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, struct pvfs_file *f; struct pvfs_file_handle *h; NTSTATUS status; + uint32_t access_needed; f = pvfs_find_fd(pvfs, req, info->generic.in.fnum); if (!f) { @@ -291,6 +323,11 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, } h = f->handle; + access_needed = pvfs_fileinfo_access(info->generic.level); + if (!(f->access_mask & access_needed)) { + return NT_STATUS_ACCESS_DENIED; + } + /* update the file information */ status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index 0ca05bbc17..9fe92c9173 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -169,6 +169,11 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, } } + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2); if (fname2 == NULL) { return NT_STATUS_NO_MEMORY; @@ -283,6 +288,11 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs, return status; } + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = pvfs_can_rename(pvfs, name1); if (!NT_STATUS_IS_OK(status)) { return status; @@ -357,18 +367,30 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, switch (ren->ntrename.in.flags) { case RENAME_FLAG_RENAME: + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (rename(name1->full_name, name2->full_name) == -1) { return pvfs_map_errno(pvfs, errno); } break; case RENAME_FLAG_HARD_LINK: + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (link(name1->full_name, name2->full_name) == -1) { return pvfs_map_errno(pvfs, errno); } break; case RENAME_FLAG_COPY: + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } return pvfs_copy_file(pvfs, name1, name2); case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 31db6ce630..10eb082183 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -26,6 +26,38 @@ #include "librpc/gen_ndr/ndr_xattr.h" +/* + determine what access bits are needed for a call +*/ +static uint32_t pvfs_setfileinfo_access(enum smb_setfileinfo_level level) +{ + uint32_t needed; + + switch (level) { + case RAW_SFILEINFO_EA_SET: + needed = SEC_FILE_WRITE_EA; + break; + + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + needed = SEC_STD_DELETE; + break; + + case RAW_SFILEINFO_END_OF_FILE_INFO: + needed = SEC_FILE_WRITE_DATA; + break; + + case RAW_SFILEINFO_POSITION_INFORMATION: + needed = 0; + break; + + default: + needed = SEC_FILE_WRITE_ATTRIBUTE; + break; + } + return needed; +} + /* rename_information level */ @@ -100,6 +132,11 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, } } + status = pvfs_access_check_create(pvfs, req, name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (rename(name->full_name, name2->full_name) == -1) { return pvfs_map_errno(pvfs, errno); } @@ -202,6 +239,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, uint32_t create_options; struct pvfs_filename newstats; NTSTATUS status; + uint32_t access_needed; f = pvfs_find_fd(pvfs, req, info->generic.file.fnum); if (!f) { @@ -210,6 +248,11 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, h = f->handle; + access_needed = pvfs_setfileinfo_access(info->generic.level); + if (!(f->access_mask & access_needed)) { + return NT_STATUS_ACCESS_DENIED; + } + /* update the file information */ status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); if (!NT_STATUS_IS_OK(status)) { @@ -272,9 +315,6 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFORMATION: - if (!(f->access_mask & SEC_STD_DELETE)) { - return NT_STATUS_ACCESS_DENIED; - } create_options = h->create_options; if (info->disposition_info.in.delete_on_close) { create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; @@ -389,6 +429,7 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, struct pvfs_filename newstats; NTSTATUS status; struct utimbuf unix_times; + uint32_t access_needed; /* resolve the cifs name to a posix name */ status = pvfs_resolve_name(pvfs, req, info->generic.file.fname, @@ -401,6 +442,11 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + access_needed = pvfs_setfileinfo_access(info->generic.level); + status = pvfs_access_check_simple(pvfs, req, name, access_needed); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* we take a copy of the current file stats, then update newstats in each of the elements below. At the end we -- cgit