diff options
-rw-r--r-- | source4/dsdb/common/sidmap.c | 41 | ||||
-rw-r--r-- | source4/librpc/config.mk | 9 | ||||
-rw-r--r-- | source4/librpc/idl/nfs4acl.idl | 41 | ||||
-rw-r--r-- | source4/ntvfs/posix/config.mk | 12 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_acl_nfs4.c | 163 |
5 files changed, 264 insertions, 2 deletions
diff --git a/source4/dsdb/common/sidmap.c b/source4/dsdb/common/sidmap.c index 73bfde2794..67649c1218 100644 --- a/source4/dsdb/common/sidmap.c +++ b/source4/dsdb/common/sidmap.c @@ -216,6 +216,47 @@ allocated_sid: /* + see if a sid is a group - very inefficient! +*/ +_PUBLIC_ BOOL sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid) +{ + const char *attrs[] = { "sAMAccountType", NULL }; + int ret; + TALLOC_CTX *tmp_ctx; + struct ldb_message **res; + NTSTATUS status; + struct dom_sid *domain_sid; + BOOL is_group; + + tmp_ctx = talloc_new(sidmap); + + ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, + "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid)); + if (ret == 1) { + is_group = is_group_account(res[0]); + talloc_free(tmp_ctx); + return is_group; + } + + status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return False; + } + + if (dom_sid_in_domain(domain_sid, sid)) { + uint32_t rid = sid->sub_auths[sid->num_auths-1]; + if (rid >= SIDMAP_LOCAL_GROUP_BASE) { + talloc_free(tmp_ctx); + return True; + } + } + + talloc_free(tmp_ctx); + return False; +} + +/* map a sid to a unix gid */ _PUBLIC_ NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap, diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index b1c45e47da..cf58e40c26 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -144,6 +144,13 @@ OBJ_FILES = gen_ndr/ndr_samr.o PUBLIC_HEADERS = gen_ndr/samr.h PUBLIC_DEPENDENCIES = LIBNDR NDR_MISC NDR_LSA NDR_SECURITY +[LIBRARY::NDR_NFS4ACL] +VERSION = 0.0.1 +SO_VERSION = 0 +OBJ_FILES = gen_ndr/ndr_nfs4acl.o +PUBLIC_HEADERS = gen_ndr/nfs4acl.h +PUBLIC_DEPENDENCIES = LIBNDR NDR_MISC NDR_SECURITY + [LIBRARY::NDR_SPOOLSS] VERSION = 0.0.1 SO_VERSION = 0 @@ -370,7 +377,7 @@ PUBLIC_DEPENDENCIES = \ NDR_NETLOGON NDR_TRKWKS NDR_KEYSVC NDR_KRB5PAC NDR_XATTR NDR_SCHANNEL \ NDR_ROT NDR_DRSBLOBS NDR_SVCCTL NDR_NBT NDR_WINSREPL NDR_SECURITY \ NDR_INITSHUTDOWN NDR_DNSSERVER NDR_WINSTATION NDR_IRPC NDR_DCOM NDR_OPENDB \ - NDR_SASL_HELPERS NDR_NOTIFY NDR_WINBIND NDR_FRSRPC NDR_FRSAPI + NDR_SASL_HELPERS NDR_NOTIFY NDR_WINBIND NDR_FRSRPC NDR_FRSAPI NDR_NFS4ACL [LIBRARY::RPC_NDR_ROT] VERSION = 0.0.1 diff --git a/source4/librpc/idl/nfs4acl.idl b/source4/librpc/idl/nfs4acl.idl new file mode 100644 index 0000000000..dc136150f4 --- /dev/null +++ b/source4/librpc/idl/nfs4acl.idl @@ -0,0 +1,41 @@ +#include "idl_types.h" + +/* + NFS4 ACL format on disk + see http://www.suse.de/~agruen/nfs4acl/ +*/ + +[ uuid("18763978-8625-abc3-54ca-9892bacdf321"), + version(1.0), + pointer_default(unique), + depends(misc,security) +] +interface nfs4acl +{ + const char *NFS4ACL_XATTR_NAME = "system.nfs4acl"; + + /* these structures use the same bit values and other constants as + in security.idl */ + typedef [flag(NDR_BIG_ENDIAN)] struct { + uint16 e_type; + uint16 e_flags; + uint32 e_mask; + uint32 e_id; + utf8string e_who; + [flag(NDR_ALIGN4)] DATA_BLOB _pad; + } nfs4ace; + + typedef [public,flag(NDR_BIG_ENDIAN)] struct { + uint8 a_version; + uint8 a_flags; + uint16 a_count; + uint32 a_owner_mask; + uint32 a_group_mask; + uint32 a_other_mask; + nfs4ace ace[a_count]; + } nfs4acl; + + NTSTATUS nfs4acl_test( + [in] nfs4acl acl + ); +} diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 57ee5b4090..ed182d9a98 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -9,6 +9,16 @@ OBJ_FILES = \ ################################################ ################################################ +# Start MODULE pvfs_acl_nfs4 +[MODULE::pvfs_acl_nfs4] +INIT_FUNCTION = pvfs_acl_nfs4_init +SUBSYSTEM = ntvfs +OBJ_FILES = \ + pvfs_acl_nfs4.o +# End MODULE pvfs_acl_nfs4 +################################################ + +################################################ # Start MODULE ntvfs_posix [MODULE::ntvfs_posix] SUBSYSTEM = ntvfs @@ -42,7 +52,7 @@ OBJ_FILES = \ pvfs_notify.o \ xattr_system.o \ xattr_tdb.o -PRIVATE_DEPENDENCIES = pvfs_acl_xattr +PRIVATE_DEPENDENCIES = pvfs_acl_xattr pvfs_acl_nfs4 PUBLIC_DEPENDENCIES = NDR_XATTR WRAP_XATTR BLKID ntvfs_common MESSAGING # End MODULE ntvfs_posix ################################################ diff --git a/source4/ntvfs/posix/pvfs_acl_nfs4.c b/source4/ntvfs/posix/pvfs_acl_nfs4.c new file mode 100644 index 0000000000..b0a329c639 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_acl_nfs4.c @@ -0,0 +1,163 @@ +/* + 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 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 "vfs_posix.h" +#include "lib/util/unix_privs.h" +#include "librpc/gen_ndr/ndr_nfs4acl.h" +#include "libcli/security/security.h" + +#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; + + 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_XATTR_NAME, + acl, 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; + status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid); + NT_STATUS_NOT_OK_RETURN(status); + status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid); + NT_STATUS_NOT_OK_RETURN(status); + + for (i=0;i<acl->a_count;i++) { + struct nfs4ace *a = &acl->ace[i]; + struct security_ace ace; + struct dom_sid *sid; + ace.type = a->e_type; + ace.flags = a->e_flags; + ace.access_mask = a->e_mask; + if (a->e_flags & ACE4_IDENTIFIER_GROUP) { + status = sidmap_gid_to_sid(pvfs->sidmap, sd, a->e_id, &sid); + } else { + status = sidmap_uid_to_sid(pvfs->sidmap, sd, a->e_id, &sid); + } + NT_STATUS_NOT_OK_RETURN(status); + ace.trustee = *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; + + 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; + } + + 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 (sidmap_sid_is_group(pvfs->sidmap, &ace->trustee)) { + gid_t gid; + a->e_flags |= ACE4_IDENTIFIER_GROUP; + status = sidmap_sid_to_unixgid(pvfs->sidmap, &ace->trustee, &gid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + a->e_id = gid; + } else { + uid_t uid; + status = sidmap_sid_to_unixuid(pvfs->sidmap, &ace->trustee, &uid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + a->e_id = uid; + } + a->e_who = ""; + } + + privs = root_privileges(); + status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, + NFS4ACL_XATTR_NAME, + &acl, ndr_push_nfs4acl); + talloc_free(privs); + + talloc_free(tmp_ctx); + return status; +} + + +/* + initialise pvfs acl NFS4 backend +*/ +NTSTATUS pvfs_acl_nfs4_init(void) +{ + struct pvfs_acl_ops ops = { + .name = "nfs4acl", + .acl_load = pvfs_acl_load_nfs4, + .acl_save = pvfs_acl_save_nfs4 + }; + return pvfs_acl_register(&ops); +} |