static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx) { struct SMB4ACL_T *pacl = NULL; struct SMB4ACE_T *pace; SMB_ACE4PROP_T ace = { .flags = SMB_ACE4_ID_SPECIAL, .who = { .id = SMB_ACE4_WHO_EVERYONE, }, .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, .aceFlags = 0, .aceMask = SMB_ACE4_ALL_MASKS, }; DEBUG(10, ("Building default full access acl\n")); pacl = smb_create_smb4acl(mem_ctx); if (pacl == NULL) { DEBUG(0, ("talloc failed\n")); errno = ENOMEM; return NULL; } pace = smb_add_ace4(pacl, &ace); if (pace == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(pacl); errno = ENOMEM; return NULL; } return pacl; }
static bool aixjfs2_get_nfs4_acl(const char *name, SMB4ACL_T **ppacl, bool *pretryPosix) { int32_t i; AIXJFS2_ACL_T *pacl = NULL; nfs4_acl_int_t *jfs2_acl = NULL; nfs4_ace_int_t *jfs2_ace = NULL; acl_type_t type; DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", name)); memset(&type, 0, sizeof(acl_type_t)); type.u64 = ACL_NFS4; pacl = aixjfs2_getacl_alloc(name, &type); if (pacl == NULL) { DEBUG(9, ("aixjfs2_getacl_alloc failed for %s with %s\n", name, strerror(errno))); if (errno==ENOSYS) *pretryPosix = True; return False; } jfs2_acl = &pacl->jfs2_acl[0]; DEBUG(10, ("len: %d, version: %d, nace: %d, type: 0x%x\n", jfs2_acl->aclLength, jfs2_acl->aclVersion, jfs2_acl->aclEntryN, type.u64)); *ppacl = smb_create_smb4acl(); if (*ppacl==NULL) return False; jfs2_ace = &jfs2_acl->aclEntry[0]; for (i=0; i<jfs2_acl->aclEntryN; i++) { SMB_ACE4PROP_T aceprop; DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, " "who: %d, aclLen: %d\n", jfs2_ace->aceType, jfs2_ace->flags, jfs2_ace->aceFlags, jfs2_ace->aceMask, jfs2_ace->aceWho.id, jfs2_ace->entryLen)); aceprop.aceType = jfs2_ace->aceType; aceprop.aceFlags = jfs2_ace->aceFlags; aceprop.aceMask = jfs2_ace->aceMask; aceprop.flags = (jfs2_ace->flags&ACE4_ID_SPECIAL) ? SMB_ACE4_ID_SPECIAL : 0; /* don't care it's real content is only 16 or 32 bit */ aceprop.who.id = jfs2_ace->aceWho.id; if (smb_add_ace4(*ppacl, &aceprop)==NULL) return False; /* iterate to the next jfs2 ace */ jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2_ace) + jfs2_ace->entryLen); } DEBUG(10,("jfs2 get_nt_acl finished successfully\n")); return True; }
static SMB4ACL_T *smbacl4_win2nfs4( TALLOC_CTX *mem_ctx, const files_struct *fsp, const struct security_acl *dacl, smbacl4_vfs_params *pparams, uid_t ownerUID, gid_t ownerGID ) { SMB4ACL_T *theacl; uint32 i; const char *filename = fsp->fsp_name->base_name; DEBUG(10, ("smbacl4_win2nfs4 invoked\n")); theacl = smb_create_smb4acl(mem_ctx); if (theacl==NULL) return NULL; for(i=0; i<dacl->num_aces; i++) { SMB_ACE4PROP_T ace_v4; bool addNewACE = true; if (!smbacl4_fill_ace4(fsp->fsp_name, pparams, ownerUID, ownerGID, dacl->aces + i, &ace_v4)) { DEBUG(3, ("Could not fill ace for file %s, SID %s\n", filename, sid_string_dbg(&((dacl->aces+i)->trustee)))); continue; } if (pparams->acedup!=e_dontcare) { if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl, &ace_v4, &addNewACE, i)) return NULL; } if (addNewACE) smb_add_ace4(theacl, &ace_v4); } if (pparams->mode==e_simple) { smbacl4_substitute_simple(theacl, ownerUID, ownerGID); } if (pparams->mode==e_special) { smbacl4_substitute_special(theacl, ownerUID, ownerGID); } return theacl; }
static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct SMB4ACL_T **ppacl) { int i; struct nfs4acl *nfs4acl = NULL; struct SMB4ACL_T *pacl = NULL; TALLOC_CTX *frame = talloc_stackframe(); nfs4acl = nfs4acl_blob2acl(blob, frame); /* create SMB4ACL data */ if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } for(i=0; i<nfs4acl->a_count; i++) { SMB_ACE4PROP_T aceprop; aceprop.aceType = (uint32_t) nfs4acl->ace[i].e_type; aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags; aceprop.aceMask = (uint32_t) nfs4acl->ace[i].e_mask; aceprop.who.id = (uint32_t) nfs4acl->ace[i].e_id; if (!strcmp(nfs4acl->ace[i].e_who, NFS4ACL_XATTR_OWNER_WHO)) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_OWNER; } else if (!strcmp(nfs4acl->ace[i].e_who, NFS4ACL_XATTR_GROUP_WHO)) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_GROUP; } else if (!strcmp(nfs4acl->ace[i].e_who, NFS4ACL_XATTR_EVERYONE_WHO)) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE; } else { aceprop.flags = 0; } if(smb_add_ace4(pacl, &aceprop) == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } } *ppacl = pacl; TALLOC_FREE(frame); return NT_STATUS_OK; }
/* * Because there is no good way to guarantee that a new xattr will be * created on file creation there might be no acl xattr on a file when * trying to read the acl. In this case the acl xattr will get * constructed at that time from the parent acl. * If the parent ACL doesn't have an xattr either the call will * recurse to the next parent directory until the share root is * reached. If the share root doesn't contain an ACL xattr either a * default ACL will be used. * Also a default ACL will be set if a non inheriting ACL is encountered. * * Basic algorithm: * read acl xattr blob * if acl xattr blob doesn't exist * stat current directory to know if it's a file or directory * read acl xattr blob from parent dir * acl xattr blob to smb nfs4 acl * calculate inherited smb nfs4 acl * without inheritance use default smb nfs4 acl * smb nfs4 acl to acl xattr blob * set acl xattr blob * return smb nfs4 acl * else * acl xattr blob to smb nfs4 acl * * Todo: Really use mem_ctx after fixing interface of nfs4_acls */ static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle, const char *path, TALLOC_CTX *mem_ctx) { char *parent_dir = NULL; struct SMB4ACL_T *pparentacl = NULL; struct SMB4ACL_T *pchildacl = NULL; struct SMB4ACE_T *pace; SMB_ACE4PROP_T ace; bool isdir; struct smb_filename *smb_fname = NULL; NTSTATUS status; int ret; TALLOC_CTX *frame = talloc_stackframe(); DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n", path)); smb_fname = synthetic_smb_fname(frame, path, NULL, NULL); if (smb_fname == NULL) { TALLOC_FREE(frame); errno = ENOMEM; return NULL; } ret = SMB_VFS_STAT(handle->conn, smb_fname); if (ret == -1) { DEBUG(0,("nfs4acls_inheritacl: failed to stat " "directory %s. Error was %s\n", smb_fname_str_dbg(smb_fname), strerror(errno))); TALLOC_FREE(frame); return NULL; } isdir = S_ISDIR(smb_fname->st.st_ex_mode); if (!parent_dirname(talloc_tos(), path, &parent_dir, NULL)) { TALLOC_FREE(frame); errno = ENOMEM; return NULL; } status = nfs4_get_nfs4_acl(handle, frame, parent_dir, &pparentacl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) && strncmp(parent_dir, ".", 2) != 0) { pparentacl = nfs4acls_inheritacl(handle, parent_dir, frame); } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { pparentacl = nfs4acls_defaultacl(frame); } else if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return NULL; } pchildacl = smb_create_smb4acl(mem_ctx); if (pchildacl == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(frame); errno = ENOMEM; return NULL; } for (pace = smb_first_ace4(pparentacl); pace != NULL; pace = smb_next_ace4(pace)) { struct SMB4ACE_T *pchildace; ace = *smb_get_ace4(pace); if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) || (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) { DEBUG(10, ("non inheriting ace type: %d, iflags: %x, " "flags: %x, mask: %x, who: %d\n", ace.aceType, ace.flags, ace.aceFlags, ace.aceMask, ace.who.id)); continue; } DEBUG(10, ("inheriting ace type: %d, iflags: %x, " "flags: %x, mask: %x, who: %d\n", ace.aceType, ace.flags, ace.aceFlags, ace.aceMask, ace.who.id)); ace.aceFlags |= SMB_ACE4_INHERITED_ACE; if (ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) { ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE; } if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) { ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE; ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE; ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE; } pchildace = smb_add_ace4(pchildacl, &ace); if (pchildace == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(frame); errno = ENOMEM; return NULL; } } /* Set a default ACL if we didn't inherit anything. */ if (smb_first_ace4(pchildacl) == NULL) { TALLOC_FREE(pchildacl); pchildacl = nfs4acls_defaultacl(mem_ctx); } /* store the returned ACL to get it directly in the future and avoid dynamic inheritance behavior. */ nfs4acl_xattr_set_smb4acl(handle, path, pchildacl); TALLOC_FREE(frame); return pchildacl; }
/* zfs_get_nt_acl() * read the local file's acls and return it in NT form * using the NFSv4 format conversion */ static NTSTATUS zfs_get_nt_acl_common(const char *name, uint32 security_info, SMB4ACL_T **ppacl) { int naces, i; ace_t *acebuf; SMB4ACL_T *pacl; TALLOC_CTX *mem_ctx; /* read the number of file aces */ if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) { if(errno == ENOSYS) { DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not " "supported on the filesystem where the file " "reside", name)); } else { DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name, strerror(errno))); } return map_nt_error_from_unix(errno); } /* allocate the field of ZFS aces */ mem_ctx = talloc_tos(); acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces); if(acebuf == NULL) { return NT_STATUS_NO_MEMORY; } /* read the aces into the field */ if(acl(name, ACE_GETACL, naces, acebuf) < 0) { DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name, strerror(errno))); return map_nt_error_from_unix(errno); } /* create SMB4ACL data */ if((pacl = smb_create_smb4acl()) == NULL) { return NT_STATUS_NO_MEMORY; } for(i=0; i<naces; i++) { SMB_ACE4PROP_T aceprop; aceprop.aceType = (uint32) acebuf[i].a_type; aceprop.aceFlags = (uint32) acebuf[i].a_flags; aceprop.aceMask = (uint32) acebuf[i].a_access_mask; aceprop.who.id = (uint32) acebuf[i].a_who; if(aceprop.aceFlags & ACE_OWNER) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_OWNER; } else if(aceprop.aceFlags & ACE_GROUP) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_GROUP; } else if(aceprop.aceFlags & ACE_EVERYONE) { aceprop.flags = SMB_ACE4_ID_SPECIAL; aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE; } else { aceprop.flags = 0; } if(smb_add_ace4(pacl, &aceprop) == NULL) return NT_STATUS_NO_MEMORY; } *ppacl = pacl; return NT_STATUS_OK; }
/* Tries to get nfs4 acls and returns SMB ACL allocated. * On failure returns 1 if it got non-NFSv4 ACL to prompt * retry with POSIX ACL checks. * On failure returns -1 if there is system (GPFS) error, check errno. * Returns 0 on success */ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl) { int i; struct gpfs_acl *gacl = NULL; DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname)); /* First get the real acl length */ gacl = gpfs_getacl_alloc(fname, 0); if (gacl == NULL) { DEBUG(9, ("gpfs_getacl failed for %s with %s\n", fname, strerror(errno))); return -1; } if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) { DEBUG(10, ("Got non-nfsv4 acl\n")); /* Retry with POSIX ACLs check */ return 1; } *ppacl = smb_create_smb4acl(); DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n", gacl->acl_len, gacl->acl_level, gacl->acl_version, gacl->acl_nace)); for (i=0; i<gacl->acl_nace; i++) { struct gpfs_ace_v4 *gace = &gacl->ace_v4[i]; SMB_ACE4PROP_T smbace; DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, " "who: %d\n", gace->aceType, gace->aceIFlags, gace->aceFlags, gace->aceMask, gace->aceWho)); ZERO_STRUCT(smbace); if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) { smbace.flags |= SMB_ACE4_ID_SPECIAL; switch (gace->aceWho) { case ACE4_SPECIAL_OWNER: smbace.who.special_id = SMB_ACE4_WHO_OWNER; break; case ACE4_SPECIAL_GROUP: smbace.who.special_id = SMB_ACE4_WHO_GROUP; break; case ACE4_SPECIAL_EVERYONE: smbace.who.special_id = SMB_ACE4_WHO_EVERYONE; break; default: DEBUG(8, ("invalid special gpfs id %d " "ignored\n", gace->aceWho)); continue; /* don't add it */ } } else { if (gace->aceFlags & ACE4_FLAG_GROUP_ID) smbace.who.gid = gace->aceWho; else smbace.who.uid = gace->aceWho; } /* remove redundent deny entries */ if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) { struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1]; if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE && prev->aceFlags == gace->aceFlags && prev->aceIFlags == gace->aceIFlags && (gace->aceMask & prev->aceMask) == 0 && gace->aceWho == prev->aceWho) { /* its redundent - skip it */ continue; } } smbace.aceType = gace->aceType; smbace.aceFlags = gace->aceFlags; smbace.aceMask = gace->aceMask; smb_add_ace4(*ppacl, &smbace); } return 0; }