static int gpfsacl_emu_chmod(const char *path, mode_t mode) { SMB4ACL_T *pacl = NULL; int result; bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False}; int i; files_struct fake_fsp; /* TODO: rationalize parametrization */ SMB4ACE_T *smbace; DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode)); result = gpfs_get_nfs4_acl(path, &pacl); if (result) return result; if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) { DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path)); } for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *ace = smb_get_ace4(smbace); uint32_t specid = ace->who.special_id; if (ace->flags&SMB_ACE4_ID_SPECIAL && ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE && specid <= SMB_ACE4_WHO_EVERYONE) { uint32_t newMask; if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) haveAllowEntry[specid] = True; /* mode >> 6 for @owner, mode >> 3 for @group, * mode >> 0 for @everyone */ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask, mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3)); if (ace->aceMask!=newMask) { DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n", path, ace->aceMask, newMask, specid)); } ace->aceMask = newMask; } }
static bool aixjfs2_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) { SMB4ACE_T *smbace; TALLOC_CTX *mem_ctx; nfs4_acl_int_t *jfs2acl; int32_t entryLen; uint32 aclLen, naces; int rc; acl_type_t acltype; DEBUG(10, ("jfs2_process_smbacl invoked on %s\n", fsp_str_dbg(fsp))); /* no need to be freed which is alloced with mem_ctx */ mem_ctx = talloc_tos(); entryLen = sizeof(nfs4_ace_int_t); if (entryLen & 0x03) entryLen = entryLen + 4 - (entryLen%4); naces = smb_get_naces(smbacl); aclLen = ACL_V4_SIZ + naces * entryLen; jfs2acl = (nfs4_acl_int_t *)TALLOC_SIZE(mem_ctx, aclLen); if (jfs2acl==NULL) { DEBUG(0, ("TALLOC_SIZE failed\n")); errno = ENOMEM; return False; } jfs2acl->aclLength = ACL_V4_SIZ; jfs2acl->aclVersion = NFS4_ACL_INT_STRUCT_VERSION; jfs2acl->aclEntryN = 0; for(smbace = smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); nfs4_ace_int_t *jfs2_ace = (nfs4_ace_int_t *)(((char *)jfs2acl) + jfs2acl->aclLength); memset(jfs2_ace, 0, entryLen); jfs2_ace->entryLen = entryLen; /* won't store textual "who" */ jfs2_ace->aceType = aceprop->aceType; /* only ACCES|DENY supported by jfs2 */ jfs2_ace->aceFlags = aceprop->aceFlags; jfs2_ace->aceMask = aceprop->aceMask; jfs2_ace->flags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_ID_SPECIAL : 0; /* don't care it's real content is only 16 or 32 bit */ jfs2_ace->aceWho.id = aceprop->who.id; /* iterate to the next jfs2 ace */ jfs2acl->aclLength += jfs2_ace->entryLen; jfs2acl->aclEntryN++; } SMB_ASSERT(jfs2acl->aclEntryN==naces); /* Don't query it (again) */ memset(&acltype, 0, sizeof(acl_type_t)); acltype.u64 = ACL_NFS4; /* won't set S_ISUID - the only one JFS2/NFS4 accepts */ rc = aclx_put( fsp->fsp_name->base_name, SET_ACL, /* set only the ACL, not mode bits */ acltype, /* not a pointer !!! */ jfs2acl, jfs2acl->aclLength, 0 /* don't set here mode bits */ ); if (rc) { DEBUG(8, ("aclx_put failed with %s\n", strerror(errno))); return False; } DEBUG(10, ("jfs2_process_smbacl succeeded.\n")); return True; }
/* * 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; }
static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx, struct SMB4ACL_T *smbacl, struct nfs4acl **pnfs4acl, bool denymissingspecial) { struct nfs4acl *nfs4acl; struct SMB4ACE_T *smbace; bool have_special_id = false; int i; /* allocate the field of NFS4 aces */ nfs4acl = talloc_zero(mem_ctx, struct nfs4acl); if(nfs4acl == NULL) { errno = ENOMEM; return false; } nfs4acl->a_count = smb_get_naces(smbacl); nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace, nfs4acl->a_count); if(nfs4acl->ace == NULL) { TALLOC_FREE(nfs4acl); errno = ENOMEM; return false; } /* handle all aces */ for(smbace = smb_first_ace4(smbacl), i = 0; smbace!=NULL; smbace = smb_next_ace4(smbace), i++) { SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); nfs4acl->ace[i].e_type = aceprop->aceType; nfs4acl->ace[i].e_flags = aceprop->aceFlags; nfs4acl->ace[i].e_mask = aceprop->aceMask; nfs4acl->ace[i].e_id = aceprop->who.id; if(aceprop->flags & SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) { case SMB_ACE4_WHO_EVERYONE: nfs4acl->ace[i].e_who = NFS4ACL_XATTR_EVERYONE_WHO; break; case SMB_ACE4_WHO_OWNER: nfs4acl->ace[i].e_who = NFS4ACL_XATTR_OWNER_WHO; break; case SMB_ACE4_WHO_GROUP: nfs4acl->ace[i].e_who = NFS4ACL_XATTR_GROUP_WHO; break; default: DEBUG(8, ("unsupported special_id %d\n", \ aceprop->who.special_id)); continue; /* don't add it !!! */ } have_special_id = true; } else { nfs4acl->ace[i].e_who = ""; } } if (!have_special_id && denymissingspecial) { TALLOC_FREE(nfs4acl); errno = EACCES; return false; } SMB_ASSERT(i == nfs4acl->a_count); *pnfs4acl = nfs4acl; return true; }
/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */ static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) { int naces = smb_get_naces(smbacl), i; ace_t *acebuf; SMB4ACE_T *smbace; TALLOC_CTX *mem_ctx; bool have_special_id = false; /* allocate the field of ZFS aces */ mem_ctx = talloc_tos(); acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces); if(acebuf == NULL) { errno = ENOMEM; return False; } /* handle all aces */ for(smbace = smb_first_ace4(smbacl), i = 0; smbace!=NULL; smbace = smb_next_ace4(smbace), i++) { SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); acebuf[i].a_type = aceprop->aceType; acebuf[i].a_flags = aceprop->aceFlags; acebuf[i].a_access_mask = aceprop->aceMask; acebuf[i].a_who = aceprop->who.id; if(aceprop->flags & SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) { case SMB_ACE4_WHO_EVERYONE: acebuf[i].a_flags |= ACE_EVERYONE; break; case SMB_ACE4_WHO_OWNER: acebuf[i].a_flags |= ACE_OWNER; break; case SMB_ACE4_WHO_GROUP: acebuf[i].a_flags |= ACE_GROUP; break; default: DEBUG(8, ("unsupported special_id %d\n", \ aceprop->who.special_id)); continue; /* don't add it !!! */ } have_special_id = true; } } if (!have_special_id && lp_parm_bool(fsp->conn->params->service, "zfsacl", "denymissingspecial", false)) { errno = EACCES; return false; } SMB_ASSERT(i == naces); /* store acl */ if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) { if(errno == ENOSYS) { DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not " "supported on the filesystem where the file " "reside", fsp_str_dbg(fsp))); } else { DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp), strerror(errno))); } return 0; } return True; }
static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) { int ret; gpfs_aclLen_t gacl_len; SMB4ACE_T *smbace; struct gpfs_acl *gacl; TALLOC_CTX *mem_ctx = talloc_tos(); gacl_len = sizeof(struct gpfs_acl) + (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t); gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len); if (gacl == NULL) { DEBUG(0, ("talloc failed\n")); errno = ENOMEM; return False; } gacl->acl_len = gacl_len; gacl->acl_level = 0; gacl->acl_version = GPFS_ACL_VERSION_NFS4; gacl->acl_type = GPFS_ACL_TYPE_NFS4; gacl->acl_nace = 0; /* change later... */ for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace]; SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; /* * GPFS can't distinguish between WRITE and APPEND on * files, so one being set without the other is an * error. Sorry for the many ()'s :-) */ if (!fsp->is_directory && ((((gace->aceMask & ACE4_MASK_WRITE) == 0) && ((gace->aceMask & ACE4_MASK_APPEND) != 0)) || (((gace->aceMask & ACE4_MASK_WRITE) != 0) && ((gace->aceMask & ACE4_MASK_APPEND) == 0))) && lp_parm_bool(fsp->conn->params->service, "gpfs", "merge_writeappend", True)) { DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains " "WRITE^APPEND, setting WRITE|APPEND\n", fsp->fsp_name)); gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; } gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; if (aceprop->flags&SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) { case SMB_ACE4_WHO_EVERYONE: gace->aceWho = ACE4_SPECIAL_EVERYONE; break; case SMB_ACE4_WHO_OWNER: gace->aceWho = ACE4_SPECIAL_OWNER; break; case SMB_ACE4_WHO_GROUP: gace->aceWho = ACE4_SPECIAL_GROUP; break; default: DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id)); continue; /* don't add it !!! */ } } else { /* just only for the type safety... */ if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP) gace->aceWho = aceprop->who.gid; else gace->aceWho = aceprop->who.uid; } gacl->acl_nace++; } ret = smbd_gpfs_putacl(fsp->fsp_name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl); if (ret != 0) { DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno))); gpfs_dumpacl(8, gacl); return False; } DEBUG(10, ("gpfs_putacl succeeded\n")); return True; }