/* * Decide whether it is okay to remove within a sticky directory. * * In sticky directories, write access is not sufficient; * you can remove entries from a directory only if: * * you own the directory, * you own the entry, * the entry is a plain file and you have write access, * or you are privileged (checked in secpolicy...). * * The function returns 0 if remove access is granted. */ int zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) { uid_t uid; uid_t downer; uid_t fowner; zfsvfs_t *zfsvfs = ZTOZSB(zdp); if (zfsvfs->z_replay) return (0); if ((zdp->z_mode & S_ISVTX) == 0) return (0); downer = zfs_fuid_map_id(zfsvfs, KUID_TO_SUID(ZTOI(zdp)->i_uid), cr, ZFS_OWNER); fowner = zfs_fuid_map_id(zfsvfs, KUID_TO_SUID(ZTOI(zp)->i_uid), cr, ZFS_OWNER); if ((uid = crgetuid(cr)) == downer || uid == fowner || (S_ISDIR(ZTOI(zp)->i_mode) && zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0)) return (0); else return (secpolicy_vnode_remove(cr)); }
/* * Load all permissions user based on cred belongs to. */ static void dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl, char checkflag, cred_t *cr) { const gid_t *gids; int ngids, i; uint64_t id; id = crgetuid(cr); (void) dsl_load_sets(mos, zapobj, ZFS_DELEG_USER_SETS, checkflag, &id, avl); id = crgetgid(cr); (void) dsl_load_sets(mos, zapobj, ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); (void) dsl_load_sets(mos, zapobj, ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl); ngids = crgetngroups(cr); gids = crgetgroups(cr); for (i = 0; i != ngids; i++) { id = gids[i]; (void) dsl_load_sets(mos, zapobj, ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); } }
/* * Validate that user is allowed to unallow specified permissions. They * must have the 'allow' permission, and even then can only unallow * perms for their uid. */ int dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr) { nvpair_t *whopair = NULL; int error; char idstr[32]; if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0) return (error); (void) snprintf(idstr, sizeof (idstr), "%lld", (longlong_t)crgetuid(cr)); while (whopair = nvlist_next_nvpair(nvp, whopair)) { zfs_deleg_who_type_t type = nvpair_name(whopair)[0]; if (type != ZFS_DELEG_USER && type != ZFS_DELEG_USER_SETS) return (EPERM); if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0) return (EPERM); } return (0); }
uid_t zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid, cred_t *cr, zfs_fuid_type_t type) { #ifdef HAVE_ZPL uint32_t index = FUID_INDEX(fuid); const char *domain; uid_t id; if (index == 0) return (fuid); domain = zfs_fuid_find_by_idx(zfsvfs, index); ASSERT(domain != NULL); if (type == ZFS_OWNER || type == ZFS_ACE_USER) { (void) kidmap_getuidbysid(crgetzone(cr), domain, FUID_RID(fuid), &id); } else { (void) kidmap_getgidbysid(crgetzone(cr), domain, FUID_RID(fuid), &id); } return (id); #endif if(type == ZFS_OWNER || type == ZFS_ACE_USER) return (crgetuid(cr)); else return (crgetgid(cr)); }
/* * Decide whether it is okay to remove within a sticky directory. * * In sticky directories, write access is not sufficient; * you can remove entries from a directory only if: * * you own the directory, * you own the entry, * the entry is a plain file and you have write access, * or you are privileged (checked in secpolicy...). * * The function returns 0 if remove access is granted. */ int zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) { #ifdef HAVE_ZPL uid_t uid; uid_t downer; uid_t fowner; zfsvfs_t *zfsvfs = zdp->z_zfsvfs; if (zdp->z_zfsvfs->z_replay) return (0); if ((zdp->z_mode & S_ISVTX) == 0) return (0); downer = zfs_fuid_map_id(zfsvfs, zdp->z_uid, cr, ZFS_OWNER); fowner = zfs_fuid_map_id(zfsvfs, zp->z_uid, cr, ZFS_OWNER); if ((uid = crgetuid(cr)) == downer || uid == fowner || (ZTOV(zp)->v_type == VREG && zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0)) return (0); else return (secpolicy_vnode_remove(cr)); #endif return 0; }
/* * XDR loopback unix auth parameters. * NOTE: this is an XDR_ENCODE only routine. */ bool_t xdr_authloopback(XDR *xdrs) { uid_t uid; gid_t gid; int len; caddr_t groups; char *name = uts_nodename(); struct cred *cr; time_t now; if (xdrs->x_op != XDR_ENCODE) return (FALSE); cr = CRED(); uid = crgetuid(cr); gid = crgetgid(cr); len = crgetngroups(cr); groups = (caddr_t)crgetgroups(cr); now = gethrestime_sec(); if (xdr_uint32(xdrs, (uint32_t *)&now) && xdr_string(xdrs, &name, MAX_MACHINE_NAME) && xdr_uid_t(xdrs, &uid) && xdr_gid_t(xdrs, &gid) && xdr_array(xdrs, &groups, (uint_t *)&len, NGRPS_LOOPBACK, sizeof (int), (xdrproc_t)xdr_int)) return (TRUE); return (FALSE); }
/* * Write out a history event. */ int spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what) { history_arg_t *ha; int err = 0; dmu_tx_t *tx; ASSERT(what != LOG_INTERNAL); tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir); err = dmu_tx_assign(tx, TXG_WAIT); if (err) { dmu_tx_abort(tx); return (err); } ha = kmem_alloc(sizeof (history_arg_t), KM_SLEEP); ha->ha_history_str = strdup(history_str); ha->ha_zone = strdup(spa_history_zone()); ha->ha_log_type = what; ha->ha_uid = crgetuid(CRED()); /* Kick this off asynchronously; errors are ignored. */ dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL, spa_history_log_sync, spa, ha, 0, tx); dmu_tx_commit(tx); /* spa_history_log_sync will free ha and strings */ return (err); }
static int VMBlockOpen(struct vnode **vpp, // IN: Vnode for file to open int flag, // IN: Open flags struct cred *cr // IN: Credentials of caller #if OS_VFS_VERSION >= 5 , caller_context_t *ctx // IN: Caller's context #endif ) { VMBlockMountInfo *mip; Bool isRoot = TRUE; Debug(VMBLOCK_ENTRY_LOGLEVEL, "VMBlockOpen: entry\n"); /* * The opened vnode is held for us, so we don't need to do anything here * except make sure only root opens the mount point. */ mip = VPTOMIP(*vpp); if (mip->root == *vpp) { isRoot = crgetuid(cr) == 0; } return isRoot ? 0 : EACCES; }
/* * 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)); }
static int splat_cred_test1(struct file *file, void *arg) { char str[GROUP_STR_SIZE]; uid_t uid, ruid, suid; gid_t gid, rgid, sgid, *groups; int ngroups, i, count = 0; uid = crgetuid(CRED()); ruid = crgetruid(CRED()); suid = crgetsuid(CRED()); gid = crgetgid(CRED()); rgid = crgetrgid(CRED()); sgid = crgetsgid(CRED()); crhold(CRED()); ngroups = crgetngroups(CRED()); groups = crgetgroups(CRED()); memset(str, 0, GROUP_STR_SIZE); for (i = 0; i < ngroups; i++) { count += sprintf(str + count, "%d ", groups[i]); if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) { splat_vprint(file, SPLAT_CRED_TEST1_NAME, "Failed too many group entries for temp " "buffer: %d, %s\n", ngroups, str); return -ENOSPC; } } crfree(CRED()); splat_vprint(file, SPLAT_CRED_TEST1_NAME, "uid: %d ruid: %d suid: %d " "gid: %d rgid: %d sgid: %d\n", uid, ruid, suid, gid, rgid, sgid); splat_vprint(file, SPLAT_CRED_TEST1_NAME, "ngroups: %d groups: %s\n", ngroups, str); if (uid || ruid || suid || gid || rgid || sgid) { splat_vprint(file, SPLAT_CRED_TEST1_NAME, "Failed expected all uids+gids to be %d\n", 0); return -EIDRM; } if (ngroups > NGROUPS_MAX) { splat_vprint(file, SPLAT_CRED_TEST1_NAME, "Failed ngroups must not exceed NGROUPS_MAX: " "%d > %d\n", ngroups, NGROUPS_MAX); return -EIDRM; } splat_vprint(file, SPLAT_CRED_TEST1_NAME, "Success sane CRED(): %d\n", 0); return 0; } /* splat_cred_test1() */
int zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; znode_t *xzp; dmu_tx_t *tx; int error; zfs_fuid_info_t *fuidp = NULL; *xvpp = NULL; /* * In FreeBSD, access checking for creating an EA is being done * in zfs_setextattr(), */ #ifndef __FreeBSD__ if (error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr)) return (error); #endif tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_bonus(tx, zp->z_id); dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); if (IS_EPHEMERAL(crgetuid(cr)) || IS_EPHEMERAL(crgetgid(cr))) { if (zfsvfs->z_fuid_obj == 0) { dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, FUID_SIZE_ESTIMATE(zfsvfs)); dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL); } else { dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj); dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0, FUID_SIZE_ESTIMATE(zfsvfs)); } } error = dmu_tx_assign(tx, zfsvfs->z_assign); if (error) { if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT) dmu_tx_wait(tx); dmu_tx_abort(tx); return (error); } zfs_mknode(zp, vap, tx, cr, IS_XATTR, &xzp, 0, NULL, &fuidp); ASSERT(xzp->z_phys->zp_parent == zp->z_id); dmu_buf_will_dirty(zp->z_dbuf, tx); zp->z_phys->zp_xattr = xzp->z_id; (void) zfs_log_create(zfsvfs->z_log, tx, TX_MKXATTR, zp, xzp, "", NULL, fuidp, vap); if (fuidp) zfs_fuid_info_free(fuidp); dmu_tx_commit(tx); *xvpp = ZTOV(xzp); return (0); }
static void smb_tree_set_execsub_info(smb_tree_t *tree, smb_execsub_info_t *subs) { subs->e_winname = tree->t_user->u_name; subs->e_userdom = tree->t_user->u_domain; subs->e_srv_ipaddr = tree->t_session->local_ipaddr; subs->e_cli_ipaddr = tree->t_session->ipaddr; subs->e_cli_netbiosname = tree->t_session->workstation; subs->e_uid = crgetuid(tree->t_user->u_cred); }
int /* ERRNO if error, 0 if successful. */ sam_access_ino( sam_node_t *ip, /* pointer to inode. */ int mode, /* mode of access to be verified */ boolean_t locked, /* is ip->inode_rwl held by caller? */ cred_t *credp) /* credentials pointer. */ { int shift = 0; ASSERT(!locked || RW_LOCK_HELD(&ip->inode_rwl)); /* * If requesting write access, and read only filesystem or WORM file * return error. */ if (mode & S_IWRITE) { if (ip->mp->mt.fi_mflag & MS_RDONLY) { return (EROFS); } if (ip->di.status.b.worm_rdonly && !S_ISDIR(ip->di.mode)) { return (EROFS); } } if (!locked) { RW_LOCK_OS(&ip->inode_rwl, RW_READER); } /* Use ACL, if present, to check access. */ if (ip->di.status.b.acl) { int error; error = sam_acl_access(ip, mode, credp); if (!locked) { RW_UNLOCK_OS(&ip->inode_rwl, RW_READER); } return (error); } if (!locked) { RW_UNLOCK_OS(&ip->inode_rwl, RW_READER); } if (crgetuid(credp) != ip->di.uid) { shift += 3; if (!groupmember((uid_t)ip->di.gid, credp)) { shift += 3; } } mode &= ~(ip->di.mode << shift); if (mode == 0) { return (0); } return (secpolicy_vnode_access(credp, SAM_ITOV(ip), ip->di.uid, mode)); }
int /* ERRNO if error, 0 if successful. */ sam_access_ino( sam_node_t *ip, /* pointer to inode. */ int mode, /* mode of access to be verified, */ /* owner position. */ boolean_t locked, /* is ip->inode_rwl held by caller? */ cred_t *credp) /* credentials pointer. */ { ASSERT(!locked); /* * If requesting write access, and read only filesystem or WORM file * return error. */ if (mode & S_IWRITE) { if (ip->mp->mt.fi_mflag & MS_RDONLY) { return (EROFS); } if (ip->di.status.b.worm_rdonly && !S_ISDIR(ip->di.mode)) { return (EROFS); } } if (crgetuid(credp) == 0) { return (0); /* all accesses allowed for root */ } if (crgetuid(credp) != ip->di.uid) { /* * caller not owner, check group */ mode >>= 3; if (!in_group_p(ip->di.gid)) { /* * caller not in group, check other */ mode >>= 3; }
/* * find_ids(packet, mp) * * attempt to discern the uid and projid of the originator of a packet by * looking at the dblks making up the packet - yeuch! * * We do it by skipping any fragments with a credp of NULL (originated in * kernel), taking the first value that isn't NULL to be the credp for the * whole packet. We also suck the projid from the same fragment. */ static void find_ids(ipgpc_packet_t *packet, mblk_t *mp) { cred_t *cr; cr = msg_getcred(mp, NULL); if (cr != NULL) { packet->uid = crgetuid(cr); packet->projid = crgetprojid(cr); } else { packet->uid = (uid_t)-1; packet->projid = -1; } }
int tmp_sticky_remove_access(struct tmpnode *dir, struct tmpnode *entry, struct cred *cr) { uid_t uid = crgetuid(cr); if ((dir->tn_mode & S_ISVTX) && uid != dir->tn_uid && uid != entry->tn_uid && (entry->tn_type != VREG || tmp_taccess(entry, VWRITE, cr) != 0)) return (secpolicy_vnode_remove(cr)); return (0); }
/*ARGSUSED*/ static int bootfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) { int shift = 0; bootfs_node_t *bpn = (bootfs_node_t *)vp->v_data; if (crgetuid(cr) != bpn->bvn_attr.va_uid) { shift += 3; if (groupmember(bpn->bvn_attr.va_gid, cr) == 0) shift += 3; } return (secpolicy_vnode_access2(cr, vp, bpn->bvn_attr.va_uid, bpn->bvn_attr.va_mode << shift, mode)); }
/* * Standard access() like check. Figure out which mode bits apply * to the caller then pass the missing mode bits to the secpolicy function. */ static int nm_access_unlocked(void *vnp, int mode, cred_t *crp) { struct namenode *nodep = vnp; int shift = 0; if (crgetuid(crp) != nodep->nm_vattr.va_uid) { shift += 3; if (!groupmember(nodep->nm_vattr.va_gid, crp)) shift += 3; } return (secpolicy_vnode_access2(crp, NMTOV(nodep), nodep->nm_vattr.va_uid, nodep->nm_vattr.va_mode << shift, mode)); }
int zfs_create_share_dir(zfs_sb_t *zsb, dmu_tx_t *tx) { #ifdef HAVE_SMB_SHARE zfs_acl_ids_t acl_ids; vattr_t vattr; znode_t *sharezp; vnode_t *vp; znode_t *zp; int error; vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; vattr.va_mode = S_IFDIR | 0555; vattr.va_uid = crgetuid(kcred); vattr.va_gid = crgetgid(kcred); sharezp = kmem_cache_alloc(znode_cache, KM_SLEEP); sharezp->z_moved = 0; sharezp->z_unlinked = 0; sharezp->z_atime_dirty = 0; sharezp->z_zfsvfs = zfsvfs; sharezp->z_is_sa = zfsvfs->z_use_sa; vp = ZTOV(sharezp); vn_reinit(vp); vp->v_type = VDIR; VERIFY(0 == zfs_acl_ids_create(sharezp, IS_ROOT_NODE, &vattr, kcred, NULL, &acl_ids)); zfs_mknode(sharezp, &vattr, tx, kcred, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, sharezp); ASSERT(!vn_in_dnlc(ZTOV(sharezp))); /* not valid to move */ POINTER_INVALIDATE(&sharezp->z_zfsvfs); error = zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, ZFS_SHARES_DIR, 8, 1, &sharezp->z_id, tx); zfsvfs->z_shares_dir = sharezp->z_id; zfs_acl_ids_free(&acl_ids); // ZTOV(sharezp)->v_count = 0; sa_handle_destroy(sharezp->z_sa_hdl); kmem_cache_free(znode_cache, sharezp); return (error); #else return (0); #endif /* HAVE_SMB_SHARE */ }
/* * Decide whether it is okay to remove within a sticky directory. * * In sticky directories, write access is not sufficient; * you can remove entries from a directory only if: * * you own the directory, * you own the entry, * the entry is a plain file and you have write access, * or you are privileged (checked in secpolicy...). * * The function returns 0 if remove access is granted. */ int zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) { uid_t uid; if (zdp->z_zfsvfs->z_assign >= TXG_INITIAL) /* ZIL replay */ return (0); if ((zdp->z_phys->zp_mode & S_ISVTX) == 0 || (uid = crgetuid(cr)) == zdp->z_phys->zp_uid || uid == zp->z_phys->zp_uid || (ZTOV(zp)->v_type == VREG && zfs_zaccess(zp, ACE_WRITE_DATA, cr) == 0)) return (0); else return (secpolicy_vnode_remove(cr)); }
/* * 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)); }
/* * check a specified user/group for a requested permission */ static int dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm, int checkflag, cred_t *cr) { //const gid_t *gids; // int ngids; //int i; uint64_t id; /* check for user */ id = crgetuid(cr); if (dsl_check_access(mos, zapobj, ZFS_DELEG_USER, checkflag, &id, perm) == 0) return (0); /* check for users primary group */ id = crgetgid(cr); if (dsl_check_access(mos, zapobj, ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) return (0); /* check for everyone entry */ id = -1; if (dsl_check_access(mos, zapobj, ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0) return (0); /* check each supplemental group user is a member of */ /*XXX NOEL: get kauth equivs for the below, crgetngroups, crgetgroups*/ #ifndef __APPLE__ ngids = crgetngroups(cr); gids = crgetgroups(cr); for (i = 0; i != ngids; i++) { id = gids[i]; if (dsl_check_access(mos, zapobj, ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) return (0); } return (EPERM); #endif return 0; }
/* ARGSUSED */ static int auto_access( vnode_t *vp, int mode, int flags, cred_t *cred, caller_context_t *ct) { fnnode_t *fnp = vntofn(vp); vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp)); if (error = auto_trigger_mount(vp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is mounted on. */ error = VOP_ACCESS(newvp, mode, 0, cred, ct); VN_RELE(newvp); } else { int shift = 0; /* * really interested in the autofs node, check the * access on it */ ASSERT(error == 0); if (crgetuid(cred) != fnp->fn_uid) { shift += 3; if (groupmember(fnp->fn_gid, cred) == 0) shift += 3; } error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid, fnp->fn_mode << shift, mode); } done: AUTOFS_DPRINT((5, "auto_access: error=%d\n", error)); return (error); }
/* * set all create time permission on new dataset. */ void dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr) { dsl_dir_t *dd; uint64_t uid = crgetuid(cr); if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) < SPA_VERSION_DELEGATED_PERMS) return; for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) { uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj; if (pzapobj == 0) continue; copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx); copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx); } }
/* * * Cachefs used to know too much about how creds looked; since it's * committed to persistent storage, we can't change the layout so * it now has a "dl_cred_t" which (unsurprisingly) looks exactly like * an old credential. * * The dst argument needs to point to: * struct dl_cred_t; * <buffer space> buffer for groups * * The source is a proper kernel cred_t. * */ static size_t copy_cred(cred_t *src, dl_cred_t *dst) { int n; const gid_t *sgrp = crgetgroups(src); n = MIN(NGROUPS_MAX_DEFAULT, crgetngroups(src)); /* copy the fixed fields */ dst->cr_uid = crgetuid(src); dst->cr_ruid = crgetruid(src); dst->cr_suid = crgetsuid(src); dst->cr_gid = crgetgid(src); dst->cr_rgid = crgetrgid(src); dst->cr_sgid = crgetsgid(src); dst->cr_groups[0] = sgrp[0]; dst->cr_ngroups = n; bcopy(sgrp, (void *)(dst + 1), (n - 1) * sizeof (gid_t)); return (sizeof (dl_cred_t) + (n - 1) * sizeof (gid_t)); }
/* * check a specified user/group for a requested permission */ static int dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm, int checkflag, cred_t *cr) { const gid_t *gids; int ngids; int i; uint64_t id; /* check for user */ id = crgetuid(cr); if (dsl_check_access(mos, zapobj, ZFS_DELEG_USER, checkflag, &id, perm) == 0) return (0); /* check for users primary group */ id = crgetgid(cr); if (dsl_check_access(mos, zapobj, ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) return (0); /* check for everyone entry */ id = -1; if (dsl_check_access(mos, zapobj, ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0) return (0); /* check each supplemental group user is a member of */ ngids = crgetngroups(cr); gids = crgetgroups(cr); for (i = 0; i != ngids; i++) { id = gids[i]; if (dsl_check_access(mos, zapobj, ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) return (0); } return (EPERM); }
/* * This function is used for secpolicy_setattr(). It must call an * access() like function while it is already holding the * dv_contents lock. We only care about this when dv_attr != NULL; * so the unlocked access call only concerns itself with that * particular branch of devfs_access(). */ static int devfs_unlocked_access(void *vdv, int mode, struct cred *cr) { struct dv_node *dv = vdv; int shift = 0; uid_t owner = dv->dv_attr->va_uid; /* Check access based on owner, group and public permissions. */ if (crgetuid(cr) != owner) { shift += 3; if (groupmember(dv->dv_attr->va_gid, cr) == 0) shift += 3; } /* compute missing mode bits */ mode &= ~(dv->dv_attr->va_mode << shift); if (mode == 0) return (0); return (secpolicy_vnode_access(cr, DVTOV(dv), owner, mode)); }
int tmp_taccess(void *vtp, int mode, struct cred *cred) { struct tmpnode *tp = vtp; int shift = 0; /* * Check access based on owner, group and * public permissions in tmpnode. */ if (crgetuid(cred) != tp->tn_uid) { shift += MODESHIFT; if (groupmember(tp->tn_gid, cred) == 0) shift += MODESHIFT; } /* compute missing mode bits */ mode &= ~(tp->tn_mode << shift); if (mode == 0) return (0); return (secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid, mode)); }
/* * Decide whether it is okay to remove within a sticky directory. * * In sticky directories, write access is not sufficient; * you can remove entries from a directory only if: * * you own the directory, * you own the entry, * the entry is a plain file and you have write access, * or you are privileged (checked in secpolicy...). * * The function returns 0 if remove access is granted. */ int zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) { uid_t uid; if (zdp->z_zfsvfs->z_assign >= TXG_INITIAL) /* ZIL replay */ return (0); if ((zdp->z_mode & S_ISVTX) == 0 || (uid = crgetuid(cr)) == zdp->z_uid || uid == zp->z_uid || ( #ifdef __APPLE__ vnode_isreg(ZTOV(zp)) && #else ZTOV(zp)->v_type == VREG && #endif zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0) ) return (0); else return (secpolicy_vnode_remove(cr)); }
static int xmem_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred) { struct xmemnode *parent; struct xmemnode *from; struct xmount *xm = (struct xmount *)VTOXM(dvp); int error; struct xmemnode *found = NULL; struct vnode *realvp; if (VOP_REALVP(srcvp, &realvp) == 0) srcvp = realvp; parent = (struct xmemnode *)VTOXN(dvp); from = (struct xmemnode *)VTOXN(srcvp); if ((srcvp->v_type == VDIR && secpolicy_fs_linkdir(cred, dvp->v_vfsp) != 0) || (from->xn_uid != crgetuid(cred) && secpolicy_basic_link(cred) != 0)) return (EPERM); error = xdirlookup(parent, tnm, &found, cred); if (error == 0) { ASSERT(found); xmemnode_rele(found); return (EEXIST); } if (error != ENOENT) return (error); rw_enter(&parent->xn_rwlock, RW_WRITER); error = xdirenter(xm, parent, tnm, DE_LINK, (struct xmemnode *)NULL, from, NULL, (struct xmemnode **)NULL, cred); rw_exit(&parent->xn_rwlock); return (error); }