diff options
Diffstat (limited to 'source4/ntvfs')
-rw-r--r-- | source4/ntvfs/posix/config.mk | 1 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_acl.c | 193 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 10 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_setfileinfo.c | 3 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_xattr.c | 43 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 3 | ||||
-rw-r--r-- | source4/ntvfs/unixuid/vfs_unixuid.c | 4 |
7 files changed, 254 insertions, 3 deletions
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 1d33d8b381..7999a32741 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -28,6 +28,7 @@ ADD_OBJ_FILES = \ ntvfs/posix/pvfs_ioctl.o \ ntvfs/posix/pvfs_xattr.o \ ntvfs/posix/pvfs_streams.o \ + ntvfs/posix/pvfs_acl.o \ ntvfs/common/opendb.o \ ntvfs/common/brlock.o # End MODULE ntvfs_posix diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c new file mode 100644 index 0000000000..2885604311 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -0,0 +1,193 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - ACL support + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "system/filesys.h" +#include "vfs_posix.h" +#include "librpc/gen_ndr/ndr_xattr.h" + + +/* + setup a default ACL for a file +*/ +static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_filename *name, int fd, + struct xattr_DosAcl *acl) +{ + struct security_descriptor *sd; + struct nt_user_token *token = req->session->session_info->nt_user_token; + int i; + + sd = security_descriptor_initialise(req); + if (sd == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* nasty hack to get a reasonable sec desc - should be based on posix uid/gid + and perms */ + if (token->num_sids > 0) { + sd->owner_sid = token->user_sids[0]; + } + if (token->num_sids > 1) { + sd->group_sid = token->user_sids[1]; + } + + for (i=0;i<token->num_sids;i++) { + struct security_ace ace; + NTSTATUS status; + + ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; + ace.flags = 0; + ace.access_mask = SEC_RIGHTS_FULL_CTRL | STD_RIGHT_ALL_ACCESS; + ace.trustee = *token->user_sids[i]; + + status = security_descriptor_dacl_add(sd, &ace); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + acl->version = 1; + acl->info.sd = sd; + + return NT_STATUS_OK; +} + + +/* + omit any security_descriptor elements not specified in the given + secinfo flags +*/ +static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags) +{ + if (!(secinfo_flags & OWNER_SECURITY_INFORMATION)) { + sd->owner_sid = NULL; + } + if (!(secinfo_flags & GROUP_SECURITY_INFORMATION)) { + sd->group_sid = NULL; + } + if (!(secinfo_flags & DACL_SECURITY_INFORMATION)) { + sd->dacl = NULL; + } + if (!(secinfo_flags & SACL_SECURITY_INFORMATION)) { + sd->sacl = NULL; + } +} + +/* + answer a setfileinfo for an ACL +*/ +NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_filename *name, int fd, + union smb_setfileinfo *info) +{ + struct xattr_DosAcl *acl; + uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags; + struct security_descriptor *new_sd, *sd; + NTSTATUS status; + + acl = talloc_p(req, struct xattr_DosAcl); + if (acl == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = pvfs_acl_load(pvfs, name, fd, acl); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = pvfs_default_acl(pvfs, req, name, fd, acl); + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (acl->version) { + case 1: + sd = acl->info.sd; + break; + default: + return NT_STATUS_INVALID_LEVEL; + } + + new_sd = info->set_secdesc.in.sd; + + /* only set the elements that have been specified */ + if (secinfo_flags & OWNER_SECURITY_INFORMATION) { + sd->owner_sid = new_sd->owner_sid; + } + if (secinfo_flags & GROUP_SECURITY_INFORMATION) { + sd->group_sid = new_sd->group_sid; + } + if (secinfo_flags & DACL_SECURITY_INFORMATION) { + sd->dacl = new_sd->dacl; + } + if (secinfo_flags & SACL_SECURITY_INFORMATION) { + sd->sacl = new_sd->sacl; + } + + status = pvfs_acl_save(pvfs, name, fd, acl); + + return status; +} + + +/* + answer a fileinfo query for the ACL +*/ +NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_filename *name, int fd, + union smb_fileinfo *info) +{ + struct xattr_DosAcl *acl; + NTSTATUS status; + struct security_descriptor *sd; + + acl = talloc_p(req, struct xattr_DosAcl); + if (acl == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = pvfs_acl_load(pvfs, name, fd, acl); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = pvfs_default_acl(pvfs, req, name, fd, acl); + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (acl->version) { + case 1: + sd = acl->info.sd; + break; + default: + return NT_STATUS_INVALID_LEVEL; + } + + normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags); + + info->query_secdesc.out.sd = sd; + + return NT_STATUS_OK; +} + diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index f6e1288b1d..fe53b0a415 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -56,7 +56,8 @@ static NTSTATUS pvfs_query_all_eas(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, /* approximately map a struct pvfs_filename to a generic fileinfo struct */ -static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, +static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, + struct smbsrv_request *req, struct pvfs_filename *name, union smb_fileinfo *info, int fd) { @@ -91,7 +92,7 @@ static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; case RAW_FILEINFO_ALL_EAS: - return pvfs_query_all_eas(pvfs, mem_ctx, name, fd, &info->all_eas.out); + return pvfs_query_all_eas(pvfs, req, name, fd, &info->all_eas.out); case RAW_FILEINFO_IS_NAME_VALID: return NT_STATUS_OK; @@ -149,7 +150,7 @@ static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, case RAW_FILEINFO_STREAM_INFO: case RAW_FILEINFO_STREAM_INFORMATION: - return pvfs_stream_information(pvfs, mem_ctx, name, fd, &info->stream_info.out); + return pvfs_stream_information(pvfs, req, name, fd, &info->stream_info.out); case RAW_FILEINFO_COMPRESSION_INFO: case RAW_FILEINFO_COMPRESSION_INFORMATION: @@ -194,6 +195,9 @@ static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, info->attribute_tag_information.out.attrib = name->dos.attrib; info->attribute_tag_information.out.reparse_tag = 0; return NT_STATUS_OK; + + case RAW_FILEINFO_SEC_DESC: + return pvfs_acl_query(pvfs, req, name, fd, info); } return NT_STATUS_INVALID_LEVEL; diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index d31bcac337..cc1b69b8ea 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -301,6 +301,9 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, return pvfs_setfileinfo_rename(pvfs, req, h->name, &info->rename_information.in); + case RAW_SFILEINFO_SEC_DESC: + return pvfs_acl_set(pvfs, req, h->name, h->fd, info); + default: return NT_STATUS_INVALID_LEVEL; } diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c index 6984c2d284..a50348ef04 100644 --- a/source4/ntvfs/posix/pvfs_xattr.c +++ b/source4/ntvfs/posix/pvfs_xattr.c @@ -348,6 +348,49 @@ NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams); } + +/* + load the current ACL from extended attributes +*/ +NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, + struct xattr_DosAcl *acl) +{ + NTSTATUS status; + ZERO_STRUCTP(acl); + if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { + return NT_STATUS_OK; + } + status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd, + XATTR_DOSACL_NAME, + acl, + (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAcl); + return status; +} + +/* + save the acl for a file into filesystem xattr +*/ +NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, + struct xattr_DosAcl *acl) +{ + NTSTATUS status; + void *privs; + + if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { + return NT_STATUS_OK; + } + + /* this xattr is in the "system" namespace, so we need + admin privileges to set it */ + privs = root_privileges(); + status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, + XATTR_DOSACL_NAME, + acl, + (ndr_push_flags_fn_t)ndr_push_xattr_DosAcl); + talloc_free(privs); + return status; +} + /* create a zero length xattr with the given name */ diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index e02bd7aa32..e19b0739c7 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -65,6 +65,9 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS; } + if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { + pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS; + } } diff --git a/source4/ntvfs/unixuid/vfs_unixuid.c b/source4/ntvfs/unixuid/vfs_unixuid.c index 4520df59fc..674ce3e5cf 100644 --- a/source4/ntvfs/unixuid/vfs_unixuid.c +++ b/source4/ntvfs/unixuid/vfs_unixuid.c @@ -294,6 +294,10 @@ static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs, struct unix_sec_ctx *newsec; NTSTATUS status; + if (req->session == NULL) { + return NT_STATUS_ACCESS_DENIED; + } + *sec = save_unix_security(req); if (*sec == NULL) { return NT_STATUS_NO_MEMORY; |