/* * Create a file system FUID, based on information in the users cred */ uint64_t zfs_fuid_create_cred(zfsvfs_t *zfsvfs, zfs_fuid_type_t type, dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp) { uint64_t idx; ksid_t *ksid; uint32_t rid; char *kdomain; const char *domain; uid_t id; VERIFY(type == ZFS_OWNER || type == ZFS_GROUP); if (type == ZFS_OWNER) id = crgetuid(cr); else id = crgetgid(cr); if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id)) return ((uint64_t)id); ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP); VERIFY(ksid != NULL); rid = ksid_getrid(ksid); domain = ksid_getdomain(ksid); idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx); zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type); return (FUID_ENCODE(idx, rid)); }
/* * Check to see if id is a groupmember. If cred * has ksid info then sidlist is checked first * and if still not found then POSIX groups are checked * * Will use a straight FUID compare when possible. */ boolean_t zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr) { ksid_t *ksid = crgetsid(cr, KSID_GROUP); uid_t gid; if (ksid) { int i; ksid_t *ksid_groups; ksidlist_t *ksidlist = crgetsidlist(cr); uint32_t idx = FUID_INDEX(id); uint32_t rid = FUID_RID(id); ASSERT(ksidlist); ksid_groups = ksidlist->ksl_sids; for (i = 0; i != ksidlist->ksl_nsid; i++) { if (idx == 0) { if (id != IDMAP_WK_CREATOR_GROUP_GID && id == ksid_groups[i].ks_id) { return (B_TRUE); } } else { char *domain; domain = zfs_fuid_find_by_idx(zfsvfs, idx); ASSERT(domain != NULL); if (strcmp(domain, IDMAP_WK_CREATOR_SID_AUTHORITY) == 0) return (B_FALSE); if ((strcmp(domain, ksid_groups[i].ks_domain->kd_name) == 0) && rid == ksid_groups[i].ks_rid) return (B_TRUE); } } } /* * Not found in ksidlist, check posix groups */ gid = zfs_fuid_map_id(zfsvfs, id, cr, ZFS_GROUP); #ifdef __APPLE__ return (groupmember(gid, (kauth_cred_t)cr)); #else return (groupmember(gid, cr)); #endif }
/* * Create a file system FUID, based on information in the users cred * * If cred contains KSID_OWNER then it should be used to determine * the uid otherwise cred's uid will be used. By default cred's gid * is used unless it's an ephemeral ID in which case KSID_GROUP will * be used if it exists. */ uint64_t zfs_fuid_create_cred(zfsvfs_t *zfsvfs, zfs_fuid_type_t type, cred_t *cr, zfs_fuid_info_t **fuidp) { uint64_t idx; ksid_t *ksid; uint32_t rid; char *kdomain; const char *domain; uid_t id; VERIFY(type == ZFS_OWNER || type == ZFS_GROUP); ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP); if (!zfsvfs->z_use_fuids || (ksid == NULL)) { id = (type == ZFS_OWNER) ? crgetuid(cr) : crgetgid(cr); if (IS_EPHEMERAL(id)) return ((type == ZFS_OWNER) ? UID_NOBODY : GID_NOBODY); return ((uint64_t)id); } /* * ksid is present and FUID is supported */ id = (type == ZFS_OWNER) ? ksid_getid(ksid) : crgetgid(cr); if (!IS_EPHEMERAL(id)) return ((uint64_t)id); if (type == ZFS_GROUP) id = ksid_getid(ksid); rid = ksid_getrid(ksid); domain = ksid_getdomain(ksid); idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, B_TRUE); zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type); return (FUID_ENCODE(idx, rid)); }
/* * smb_fsacl_inherit * * Manufacture the inherited ACL from the given ACL considering * the new object type (file/dir) specified by 'is_dir'. The * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions. * This function implements Windows inheritance rules explained above. * * Note that the in/out ACLs are ZFS ACLs not Windows ACLs */ acl_t * smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, cred_t *cr) { boolean_t use_default = B_FALSE; int num_inheritable = 0; int numaces; ace_t *dir_zace; acl_t *new_zacl; ace_t *new_zace; ksid_t *owner_sid; ksid_t *group_sid; uid_t uid; gid_t gid; owner_sid = crgetsid(cr, KSID_OWNER); group_sid = crgetsid(cr, KSID_GROUP); ASSERT(owner_sid); ASSERT(group_sid); uid = owner_sid->ks_id; gid = group_sid->ks_id; num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir); if (num_inheritable == 0) { if (which_acl == SMB_DACL_SECINFO) { /* No inheritable access ACEs -> default DACL */ num_inheritable = DEFAULT_DACL_ACENUM; use_default = B_TRUE; } else { return (NULL); } } new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT); new_zace = new_zacl->acl_aclp; if (use_default) { bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl)); new_zace->a_who = uid; return (new_zacl); } for (numaces = 0, dir_zace = dir_zacl->acl_aclp; numaces < dir_zacl->acl_cnt; dir_zace++, numaces++) { switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) { case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE): /* * Files inherit an effective ACE. * * Dirs inherit an effective ACE. * The inherited ACE is inheritable unless the * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set */ smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid); new_zace++; if (is_dir && ZACE_IS_CREATOR(dir_zace) && (ZACE_IS_PROPAGATE(dir_zace))) { *new_zace = *dir_zace; new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | ACE_INHERITED_ACE); new_zace++; } break; case ACE_FILE_INHERIT_ACE: /* * Files inherit as an effective ACE. * * Dirs inherit an inherit-only ACE * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit * flag is also set. */ if (is_dir == 0) { smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid); new_zace++; } else if (ZACE_IS_PROPAGATE(dir_zace)) { *new_zace = *dir_zace; new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | ACE_INHERITED_ACE); new_zace++; } break; case ACE_DIRECTORY_INHERIT_ACE: /* * No effect on files * * Dirs inherit an effective ACE. * The inherited ACE is inheritable unless the * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set. */ if (is_dir == 0) break; smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid); new_zace++; if (ZACE_IS_CREATOR(dir_zace) && (ZACE_IS_PROPAGATE(dir_zace))) { *new_zace = *dir_zace; new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | ACE_INHERITED_ACE); new_zace++; } break; default: break; } } return (new_zacl); }