📄 pvfs_acl.c
字号:
/* 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 3 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, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "auth/auth.h"#include "vfs_posix.h"#include "librpc/gen_ndr/xattr.h"#include "libcli/security/security.h"/* the list of currently registered ACL backends */static struct pvfs_acl_backend { const struct pvfs_acl_ops *ops;} *backends = NULL;static int num_backends;/* register a pvfs acl backend. The 'name' can be later used by other backends to find the operations structure for this backend. */NTSTATUS pvfs_acl_register(const struct pvfs_acl_ops *ops){ struct pvfs_acl_ops *new_ops; if (pvfs_acl_backend_byname(ops->name) != NULL) { DEBUG(0,("pvfs acl backend '%s' already registered\n", ops->name)); return NT_STATUS_OBJECT_NAME_COLLISION; } backends = talloc_realloc(talloc_autofree_context(), backends, struct pvfs_acl_backend, num_backends+1); NT_STATUS_HAVE_NO_MEMORY(backends); new_ops = talloc_memdup(backends, ops, sizeof(*ops)); new_ops->name = talloc_strdup(new_ops, ops->name); backends[num_backends].ops = new_ops; num_backends++; DEBUG(3,("NTVFS backend '%s' registered\n", ops->name)); return NT_STATUS_OK;}/* return the operations structure for a named backend*/const struct pvfs_acl_ops *pvfs_acl_backend_byname(const char *name){ int i; for (i=0;i<num_backends;i++) { if (strcmp(backends[i].ops->name, name) == 0) { return backends[i].ops; } } return NULL;}/* map a single access_mask from generic to specific bits for files/dirs*/static uint32_t pvfs_translate_mask(uint32_t access_mask){ if (access_mask & SEC_MASK_GENERIC) { if (access_mask & SEC_GENERIC_READ) access_mask |= SEC_RIGHTS_FILE_READ; if (access_mask & SEC_GENERIC_WRITE) access_mask |= SEC_RIGHTS_FILE_WRITE; if (access_mask & SEC_GENERIC_EXECUTE) access_mask |= SEC_RIGHTS_FILE_EXECUTE; if (access_mask & SEC_GENERIC_ALL) access_mask |= SEC_RIGHTS_FILE_ALL; access_mask &= ~SEC_MASK_GENERIC; } return access_mask;}/* map any generic access bits in the given acl this relies on the fact that the mappings for files and directories are the same*/static void pvfs_translate_generic_bits(struct security_acl *acl){ unsigned i; if (!acl) return; for (i=0;i<acl->num_aces;i++) { struct security_ace *ace = &acl->aces[i]; ace->access_mask = pvfs_translate_mask(ace->access_mask); }}/* setup a default ACL for a file*/static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd, struct security_descriptor **psd){ struct security_descriptor *sd; NTSTATUS status; struct security_ace ace; mode_t mode; struct id_mapping *ids; struct composite_context *ctx; *psd = security_descriptor_initialise(req); if (*psd == NULL) { return NT_STATUS_NO_MEMORY; } sd = *psd; ids = talloc_zero_array(sd, struct id_mapping, 2); NT_STATUS_HAVE_NO_MEMORY(ids); ids[0].unixid = talloc(ids, struct unixid); NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); ids[0].unixid->id = name->st.st_uid; ids[0].unixid->type = ID_TYPE_UID; ids[0].sid = NULL; ids[1].unixid = talloc(ids, struct unixid); NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); ids[1].unixid->id = name->st.st_gid; ids[1].unixid->type = ID_TYPE_GID; ids[1].sid = NULL; ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids); NT_STATUS_HAVE_NO_MEMORY(ctx); status = wbc_xids_to_sids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); sd->owner_sid = talloc_steal(sd, ids[0].sid); sd->group_sid = talloc_steal(sd, ids[1].sid); talloc_free(ids); sd->type |= SEC_DESC_DACL_PRESENT; mode = name->st.st_mode; /* we provide up to 4 ACEs - Owner - Group - Everyone - Administrator */ /* setup owner ACE */ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.trustee = *sd->owner_sid; ace.access_mask = 0; if (mode & S_IRUSR) { if (mode & S_IWUSR) { ace.access_mask |= SEC_RIGHTS_FILE_ALL; } else { ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE; } } if (mode & S_IWUSR) { ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE; } if (ace.access_mask) { security_descriptor_dacl_add(sd, &ace); } /* setup group ACE */ ace.trustee = *sd->group_sid; ace.access_mask = 0; if (mode & S_IRGRP) { ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE; } if (mode & S_IWGRP) { /* note that delete is not granted - this matches posix behaviour */ ace.access_mask |= SEC_RIGHTS_FILE_WRITE; } if (ace.access_mask) { security_descriptor_dacl_add(sd, &ace); } /* setup other ACE */ ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD); ace.access_mask = 0; if (mode & S_IROTH) { ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE; } if (mode & S_IWOTH) { ace.access_mask |= SEC_RIGHTS_FILE_WRITE; } if (ace.access_mask) { security_descriptor_dacl_add(sd, &ace); } /* setup system ACE */ ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM); ace.access_mask = SEC_RIGHTS_FILE_ALL; security_descriptor_dacl_add(sd, &ace); 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 & SECINFO_OWNER)) { sd->owner_sid = NULL; } if (!(secinfo_flags & SECINFO_GROUP)) { sd->group_sid = NULL; } if (!(secinfo_flags & SECINFO_DACL)) { sd->dacl = NULL; } if (!(secinfo_flags & SECINFO_SACL)) { sd->sacl = NULL; }}/* answer a setfileinfo for an ACL*/NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd, uint32_t access_mask, union smb_setfileinfo *info){ uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags; struct security_descriptor *new_sd, *sd, orig_sd; NTSTATUS status = NT_STATUS_NOT_FOUND; uid_t old_uid = -1; gid_t old_gid = -1; uid_t new_uid = -1; gid_t new_gid = -1; struct id_mapping *ids; struct composite_context *ctx; if (pvfs->acl_ops != NULL) { status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd); } if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { status = pvfs_default_acl(pvfs, req, name, fd, &sd); } if (!NT_STATUS_IS_OK(status)) { return status; } ids = talloc(req, struct id_mapping); NT_STATUS_HAVE_NO_MEMORY(ids); ids->unixid = NULL; ids->sid = NULL; ids->status = NT_STATUS_NONE_MAPPED; new_sd = info->set_secdesc.in.sd; orig_sd = *sd; old_uid = name->st.st_uid; old_gid = name->st.st_gid; /* only set the elements that have been specified */ if (secinfo_flags & SECINFO_OWNER) { if (!(access_mask & SEC_STD_WRITE_OWNER)) { return NT_STATUS_ACCESS_DENIED; } if (!dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) { ids->sid = new_sd->owner_sid; ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids); NT_STATUS_HAVE_NO_MEMORY(ctx); status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); if (ids->unixid->type == ID_TYPE_BOTH || ids->unixid->type == ID_TYPE_UID) { new_uid = ids->unixid->id; } } sd->owner_sid = new_sd->owner_sid; } if (secinfo_flags & SECINFO_GROUP) { if (!(access_mask & SEC_STD_WRITE_OWNER)) { return NT_STATUS_ACCESS_DENIED; } if (!dom_sid_equal(sd->group_sid, new_sd->group_sid)) { ids->sid = new_sd->group_sid; ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids); NT_STATUS_HAVE_NO_MEMORY(ctx); status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); if (ids->unixid->type == ID_TYPE_BOTH || ids->unixid->type == ID_TYPE_GID) { new_gid = ids->unixid->id; } } sd->group_sid = new_sd->group_sid; } if (secinfo_flags & SECINFO_DACL) { if (!(access_mask & SEC_STD_WRITE_DAC)) { return NT_STATUS_ACCESS_DENIED; } sd->dacl = new_sd->dacl; pvfs_translate_generic_bits(sd->dacl); } if (secinfo_flags & SECINFO_SACL) { if (!(access_mask & SEC_FLAG_SYSTEM_SECURITY)) { return NT_STATUS_ACCESS_DENIED; } sd->sacl = new_sd->sacl; pvfs_translate_generic_bits(sd->sacl); } if (new_uid == old_uid) { new_uid = -1; } if (new_gid == old_gid) { new_gid = -1; } /* if there's something to change try it */ if (new_uid != -1 || new_gid != -1) { int ret; if (fd == -1) { ret = chown(name->full_name, new_uid, new_gid); } else { ret = fchown(fd, new_uid, new_gid); } if (ret == -1) { return pvfs_map_errno(pvfs, errno); } } /* we avoid saving if the sd is the same. This means when clients copy files and end up copying the default sd that we don't needlessly use xattrs */ if (!security_descriptor_equal(sd, &orig_sd) && pvfs->acl_ops) { status = pvfs->acl_ops->acl_save(pvfs, name, fd, sd); } return status;}/* answer a fileinfo query for the ACL*/NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd, union smb_fileinfo *info){ NTSTATUS status = NT_STATUS_NOT_FOUND; struct security_descriptor *sd; if (pvfs->acl_ops) { status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd); } if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { status = pvfs_default_acl(pvfs, req, name, fd, &sd); } if (!NT_STATUS_IS_OK(status)) { return status; } normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags); info->query_secdesc.out.sd = sd; return NT_STATUS_OK;}/* check the read only bit against any of the write access bits*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -