diff options
Diffstat (limited to '')
-rw-r--r-- | source4/ntvfs/posix/pvfs_acl_nfs4.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_acl_nfs4.c b/source4/ntvfs/posix/pvfs_acl_nfs4.c new file mode 100644 index 0000000..3ddc1b6 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_acl_nfs4.c @@ -0,0 +1,199 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - NT ACLs mapped to NFS4 ACLs, as per + http://www.suse.de/~agruen/nfs4acl/ + + Copyright (C) Andrew Tridgell 2006 + + 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 "vfs_posix.h" +#include "../lib/util/unix_privs.h" +#include "librpc/gen_ndr/ndr_nfs4acl.h" +#include "libcli/security/security.h" + +NTSTATUS pvfs_acl_nfs4_init(TALLOC_CTX *); + +#define ACE4_IDENTIFIER_GROUP 0x40 + +/* + load the current ACL from system.nfs4acl +*/ +static NTSTATUS pvfs_acl_load_nfs4(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, + TALLOC_CTX *mem_ctx, + struct security_descriptor **psd) +{ + NTSTATUS status; + struct nfs4acl *acl; + struct security_descriptor *sd; + int i, num_ids; + struct id_map *ids; + + acl = talloc_zero(mem_ctx, struct nfs4acl); + NT_STATUS_HAVE_NO_MEMORY(acl); + + status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, fd, + NFS4ACL_NDR_XATTR_NAME, + acl, (void *) ndr_pull_nfs4acl); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(acl); + return status; + } + + *psd = security_descriptor_initialise(mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(*psd); + + sd = *psd; + + sd->type |= acl->a_flags; + + /* the number of ids to map is the acl count plus uid and gid */ + num_ids = acl->a_count +2; + ids = talloc_array(sd, struct id_map, num_ids); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids[0].xid.id = name->st.st_uid; + ids[0].xid.type = ID_TYPE_UID; + ids[0].sid = NULL; + ids[0].status = ID_UNKNOWN; + + ids[1].xid.id = name->st.st_gid; + ids[1].xid.type = ID_TYPE_GID; + ids[1].sid = NULL; + ids[1].status = ID_UNKNOWN; + + for (i=0;i<acl->a_count;i++) { + struct nfs4ace *a = &acl->ace[i]; + ids[i+2].xid.id = a->e_id; + if (a->e_flags & ACE4_IDENTIFIER_GROUP) { + ids[i+2].xid.type = ID_TYPE_GID; + } else { + ids[i+2].xid.type = ID_TYPE_UID; + } + ids[i+2].sid = NULL; + ids[i+2].status = ID_UNKNOWN; + } + + /* Allocate memory for the sids from the security descriptor to be on + * the safe side. */ + status = wbc_xids_to_sids(ids, num_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); + + for (i=0;i<acl->a_count;i++) { + struct nfs4ace *a = &acl->ace[i]; + struct security_ace ace = {}; + ace.type = a->e_type; + ace.flags = a->e_flags; + ace.access_mask = a->e_mask; + ace.trustee = *ids[i+2].sid; + security_descriptor_dacl_add(sd, &ace); + } + + return NT_STATUS_OK; +} + +/* + save the acl for a file into system.nfs4acl +*/ +static NTSTATUS pvfs_acl_save_nfs4(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, + struct security_descriptor *sd) +{ + NTSTATUS status; + void *privs; + struct nfs4acl acl; + int i; + TALLOC_CTX *tmp_ctx; + struct id_map *ids; + + tmp_ctx = talloc_new(pvfs); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + acl.a_version = 0; + acl.a_flags = sd->type; + acl.a_count = sd->dacl?sd->dacl->num_aces:0; + acl.a_owner_mask = 0; + acl.a_group_mask = 0; + acl.a_other_mask = 0; + + acl.ace = talloc_array(tmp_ctx, struct nfs4ace, acl.a_count); + if (!acl.ace) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + ids = talloc_array(tmp_ctx, struct id_map, acl.a_count); + if (ids == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + for (i=0;i<acl.a_count;i++) { + struct security_ace *ace = &sd->dacl->aces[i]; + ZERO_STRUCT(ids[i].xid); + ids[i].sid = dom_sid_dup(ids, &ace->trustee); + if (ids[i].sid == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + ids[i].status = ID_UNKNOWN; + } + + status = wbc_sids_to_xids(ids, acl.a_count); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + + for (i=0;i<acl.a_count;i++) { + struct nfs4ace *a = &acl.ace[i]; + struct security_ace *ace = &sd->dacl->aces[i]; + a->e_type = ace->type; + a->e_flags = ace->flags; + a->e_mask = ace->access_mask; + if (ids[i].xid.type != ID_TYPE_UID) { + a->e_flags |= ACE4_IDENTIFIER_GROUP; + } + a->e_id = ids[i].xid.id; + a->e_who = ""; + } + + privs = root_privileges(); + status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, + NFS4ACL_NDR_XATTR_NAME, + &acl, (void *) ndr_push_nfs4acl); + talloc_free(privs); + + talloc_free(tmp_ctx); + return status; +} + + +/* + initialise pvfs acl NFS4 backend +*/ +NTSTATUS pvfs_acl_nfs4_init(TALLOC_CTX *ctx) +{ + struct pvfs_acl_ops ops = { + .name = "nfs4acl", + .acl_load = pvfs_acl_load_nfs4, + .acl_save = pvfs_acl_save_nfs4 + }; + return pvfs_acl_register(ctx, &ops); +} |