/* * 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); }
/* * 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); } }
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)); }
/* * 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); }
/* * 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)); }
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 */ }
/* * 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; }
/* * * 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); }
/* * Callup to the mountd to get access information in the kernel. */ static bool_t nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, struct netbuf *addr, int *access, cred_t *clnt_cred, uid_t *srv_uid, gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids) { varg_t varg = {0}; nfsauth_res_t res = {0}; XDR xdrs; size_t absz; caddr_t abuf; int last = 0; door_arg_t da; door_info_t di; door_handle_t dh; uint_t ntries = 0; /* * No entry in the cache for this client/flavor * so we need to call the nfsauth service in the * mount daemon. */ varg.vers = V_PROTO; varg.arg_u.arg.cmd = NFSAUTH_ACCESS; varg.arg_u.arg.areq.req_client.n_len = addr->len; varg.arg_u.arg.areq.req_client.n_bytes = addr->buf; varg.arg_u.arg.areq.req_netid = req_netid; varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; varg.arg_u.arg.areq.req_flavor = flavor; varg.arg_u.arg.areq.req_clnt_uid = crgetuid(clnt_cred); varg.arg_u.arg.areq.req_clnt_gid = crgetgid(clnt_cred); varg.arg_u.arg.areq.req_clnt_gids.len = crgetngroups(clnt_cred); varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)crgetgroups(clnt_cred); DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); /* * Setup the XDR stream for encoding the arguments. Notice that * in addition to the args having variable fields (req_netid and * req_path), the argument data structure is itself versioned, * so we need to make sure we can size the arguments buffer * appropriately to encode all the args. If we can't get sizing * info _or_ properly encode the arguments, there's really no * point in continuting, so we fail the request. */ if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) { *access = NFSAUTH_DENIED; return (FALSE); } abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE); if (!xdr_varg(&xdrs, &varg)) { XDR_DESTROY(&xdrs); goto fail; } XDR_DESTROY(&xdrs); /* * Prepare the door arguments * * We don't know the size of the message the daemon * will pass back to us. By setting rbuf to NULL, * we force the door code to allocate a buf of the * appropriate size. We must set rsize > 0, however, * else the door code acts as if no response was * expected and doesn't pass the data to us. */ da.data_ptr = (char *)abuf; da.data_size = absz; da.desc_ptr = NULL; da.desc_num = 0; da.rbuf = NULL; da.rsize = 1; retry: mutex_enter(&mountd_lock); dh = mountd_dh; if (dh != NULL) door_ki_hold(dh); mutex_exit(&mountd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet! * This could mean that either mountd(1m) has not yet * been started or that _this_ routine nuked the door * handle after receiving an EINTR for a REVOKED door. * * Returning NFSAUTH_DROP will cause the NFS client * to retransmit the request, so let's try to be more * rescillient and attempt for ntries before we bail. */ if (++ntries % NFSAUTH_DR_TRYCNT) { delay(hz); goto retry; } kmem_free(abuf, absz); sys_log("nfsauth: mountd has not established door"); *access = NFSAUTH_DROP; return (FALSE); } ntries = 0; /* * Now that we've got what we need, place the call. */ switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { case 0: /* Success */ door_ki_rele(dh); if (da.data_ptr == NULL && da.data_size == 0) { /* * The door_return that contained the data * failed! We're here because of the 2nd * door_return (w/o data) such that we can * get control of the thread (and exit * gracefully). */ DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, door_arg_t *, &da); goto fail; } break; case EAGAIN: /* * Server out of resources; back off for a bit */ door_ki_rele(dh); delay(hz); goto retry; /* NOTREACHED */ case EINTR: if (!door_ki_info(dh, &di)) { door_ki_rele(dh); if (di.di_attributes & DOOR_REVOKED) { /* * The server barfed and revoked * the (existing) door on us; we * want to wait to give smf(5) a * chance to restart mountd(1m) * and establish a new door handle. */ mutex_enter(&mountd_lock); if (dh == mountd_dh) { door_ki_rele(mountd_dh); mountd_dh = NULL; } mutex_exit(&mountd_lock); delay(hz); goto retry; } /* * If the door was _not_ revoked on us, * then more than likely we took an INTR, * so we need to fail the operation. */ goto fail; } /* * The only failure that can occur from getting * the door info is EINVAL, so we let the code * below handle it. */ /* FALLTHROUGH */ case EBADF: case EINVAL: default: /* * If we have a stale door handle, give smf a last * chance to start it by sleeping for a little bit. * If we're still hosed, we'll fail the call. * * Since we're going to reacquire the door handle * upon the retry, we opt to sleep for a bit and * _not_ to clear mountd_dh. If mountd restarted * and was able to set mountd_dh, we should see * the new instance; if not, we won't get caught * up in the retry/DELAY loop. */ door_ki_rele(dh); if (!last) { delay(hz); last++; goto retry; } sys_log("nfsauth: stale mountd door handle"); goto fail; }
id_t getmyid(idtype_t idtype) { proc_t *pp; uid_t uid; gid_t gid; pid_t sid; pp = ttoproc(curthread); switch (idtype) { case P_LWPID: return (curthread->t_tid); case P_PID: return (pp->p_pid); case P_PPID: return (pp->p_ppid); case P_PGID: return (pp->p_pgrp); case P_SID: mutex_enter(&pp->p_splock); sid = pp->p_sessp->s_sid; mutex_exit(&pp->p_splock); return (sid); case P_TASKID: return (pp->p_task->tk_tkid); case P_CID: return (curthread->t_cid); case P_UID: mutex_enter(&pp->p_crlock); uid = crgetuid(pp->p_cred); mutex_exit(&pp->p_crlock); return (uid); case P_GID: mutex_enter(&pp->p_crlock); gid = crgetgid(pp->p_cred); mutex_exit(&pp->p_crlock); return (gid); case P_PROJID: return (pp->p_task->tk_proj->kpj_id); case P_POOLID: return (pp->p_pool->pool_id); case P_ZONEID: return (pp->p_zone->zone_id); case P_CTID: return (PRCTID(pp)); case P_ALL: /* * The value doesn't matter for P_ALL. */ return (0); default: return (-1); } }
/* * lwpinset returns 1 if the thread pointed to * by tp is in the process set specified by psp and is not in * the sys scheduling class - otherwise 0 is returned. * * This function expects to be called with a valid procset_t. * The set should be checked using checkprocset() before calling * this function. */ int lwpinset(proc_t *pp, procset_t *psp, kthread_t *tp, int *done) { int loperand = 0; int roperand = 0; int lwplinset = 0; int lwprinset = 0; ASSERT(ttoproc(tp) == pp); /* * If process is in the sys class return (0). */ if (proctot(pp)->t_cid == 0) { return (0); } switch (psp->p_lidtype) { case P_LWPID: if (tp->t_tid == psp->p_lid) lwplinset ++; break; case P_PID: if (pp->p_pid == psp->p_lid) loperand++; break; case P_PPID: if (pp->p_ppid == psp->p_lid) loperand++; break; case P_PGID: if (pp->p_pgrp == psp->p_lid) loperand++; break; case P_SID: mutex_enter(&pp->p_splock); if (pp->p_sessp->s_sid == psp->p_lid) loperand++; mutex_exit(&pp->p_splock); break; case P_TASKID: if (pp->p_task->tk_tkid == psp->p_lid) loperand++; break; case P_CID: if (tp->t_cid == psp->p_lid) loperand++; break; case P_UID: mutex_enter(&pp->p_crlock); if (crgetuid(pp->p_cred) == psp->p_lid) loperand++; mutex_exit(&pp->p_crlock); break; case P_GID: mutex_enter(&pp->p_crlock); if (crgetgid(pp->p_cred) == psp->p_lid) loperand++; mutex_exit(&pp->p_crlock); break; case P_PROJID: if (pp->p_task->tk_proj->kpj_id == psp->p_lid) loperand++; break; case P_POOLID: if (pp->p_pool->pool_id == psp->p_lid) loperand++; break; case P_ZONEID: if (pp->p_zone->zone_id == psp->p_lid) loperand++; break; case P_CTID: if (PRCTID(pp) == psp->p_lid) loperand++; break; case P_ALL: loperand++; break; default: #ifdef DEBUG cmn_err(CE_WARN, "lwpinset called with bad set"); return (0); #else return (0); #endif } switch (psp->p_ridtype) { case P_LWPID: if (tp->t_tid == psp->p_rid) lwprinset ++; break; case P_PID: if (pp->p_pid == psp->p_rid) roperand++; break; case P_PPID: if (pp->p_ppid == psp->p_rid) roperand++; break; case P_PGID: if (pp->p_pgrp == psp->p_rid) roperand++; break; case P_SID: mutex_enter(&pp->p_splock); if (pp->p_sessp->s_sid == psp->p_rid) roperand++; mutex_exit(&pp->p_splock); break; case P_TASKID: if (pp->p_task->tk_tkid == psp->p_rid) roperand++; break; case P_CID: if (tp->t_cid == psp->p_rid) roperand++; break; case P_UID: mutex_enter(&pp->p_crlock); if (crgetuid(pp->p_cred) == psp->p_rid) roperand++; mutex_exit(&pp->p_crlock); break; case P_GID: mutex_enter(&pp->p_crlock); if (crgetgid(pp->p_cred) == psp->p_rid) roperand++; mutex_exit(&pp->p_crlock); break; case P_PROJID: if (pp->p_task->tk_proj->kpj_id == psp->p_rid) roperand++; break; case P_POOLID: if (pp->p_pool->pool_id == psp->p_rid) roperand++; break; case P_ZONEID: if (pp->p_zone->zone_id == psp->p_rid) roperand++; break; case P_CTID: if (PRCTID(pp) == psp->p_rid) roperand++; break; case P_ALL: roperand++; break; default: #ifdef DEBUG cmn_err(CE_WARN, "lwpinset called with bad set"); return (0); #else return (0); #endif } if (lwplinset && lwprinset) *done = 1; switch (psp->p_op) { case POP_DIFF: if ((loperand || lwplinset) && !(lwprinset || roperand)) return (1); else return (0); case POP_AND: if ((loperand || lwplinset) && (roperand || lwprinset)) return (1); else return (0); case POP_OR: if (loperand || roperand || lwplinset || lwprinset) return (1); else return (0); case POP_XOR: if (((loperand || lwplinset) && !(lwprinset || roperand)) || ((roperand || lwprinset) && !(lwplinset || loperand))) return (1); else return (0); default: #ifdef DEBUG cmn_err(CE_WARN, "lwpinset called with bad set"); return (0); #else return (0); #endif } /* NOTREACHED */ }
/* * procinset returns 1 if the process pointed to by pp is in the process * set specified by psp, otherwise 0 is returned. If either process set operand * has type P_CID and pp refers to a process that is exiting, by which we mean * that its p_tlist is NULL, then procinset will return 0. pp's p_lock must be * held across the call to this function. The caller should ensure that the * process does not belong to the SYS scheduling class. * * This function expects to be called with a valid procset_t. * The set should be checked using checkprocset() before calling * this function. */ int procinset(proc_t *pp, procset_t *psp) { int loperand = 0; int roperand = 0; int lwplinproc = 0; int lwprinproc = 0; kthread_t *tp; ASSERT(MUTEX_HELD(&pp->p_lock)); switch (psp->p_lidtype) { case P_LWPID: if (pp == ttoproc(curthread)) if (getlwpptr(psp->p_lid) != NULL) lwplinproc++; break; case P_PID: if (pp->p_pid == psp->p_lid) loperand++; break; case P_PPID: if (pp->p_ppid == psp->p_lid) loperand++; break; case P_PGID: if (pp->p_pgrp == psp->p_lid) loperand++; break; case P_SID: mutex_enter(&pp->p_splock); if (pp->p_sessp->s_sid == psp->p_lid) loperand++; mutex_exit(&pp->p_splock); break; case P_CID: tp = proctot(pp); if (tp == NULL) return (0); if (tp->t_cid == psp->p_lid) loperand++; break; case P_TASKID: if (pp->p_task->tk_tkid == psp->p_lid) loperand++; break; case P_UID: mutex_enter(&pp->p_crlock); if (crgetuid(pp->p_cred) == psp->p_lid) loperand++; mutex_exit(&pp->p_crlock); break; case P_GID: mutex_enter(&pp->p_crlock); if (crgetgid(pp->p_cred) == psp->p_lid) loperand++; mutex_exit(&pp->p_crlock); break; case P_PROJID: if (pp->p_task->tk_proj->kpj_id == psp->p_lid) loperand++; break; case P_POOLID: if (pp->p_pool->pool_id == psp->p_lid) loperand++; break; case P_ZONEID: if (pp->p_zone->zone_id == psp->p_lid) loperand++; break; case P_CTID: if (PRCTID(pp) == psp->p_lid) loperand++; break; case P_ALL: loperand++; break; default: #ifdef DEBUG cmn_err(CE_WARN, "procinset called with bad set"); return (0); #else return (0); #endif } switch (psp->p_ridtype) { case P_LWPID: if (pp == ttoproc(curthread)) if (getlwpptr(psp->p_rid) != NULL) lwprinproc++; break; case P_PID: if (pp->p_pid == psp->p_rid) roperand++; break; case P_PPID: if (pp->p_ppid == psp->p_rid) roperand++; break; case P_PGID: if (pp->p_pgrp == psp->p_rid) roperand++; break; case P_SID: mutex_enter(&pp->p_splock); if (pp->p_sessp->s_sid == psp->p_rid) roperand++; mutex_exit(&pp->p_splock); break; case P_TASKID: if (pp->p_task->tk_tkid == psp->p_rid) roperand++; break; case P_CID: tp = proctot(pp); if (tp == NULL) return (0); if (tp->t_cid == psp->p_rid) roperand++; break; case P_UID: mutex_enter(&pp->p_crlock); if (crgetuid(pp->p_cred) == psp->p_rid) roperand++; mutex_exit(&pp->p_crlock); break; case P_GID: mutex_enter(&pp->p_crlock); if (crgetgid(pp->p_cred) == psp->p_rid) roperand++; mutex_exit(&pp->p_crlock); break; case P_PROJID: if (pp->p_task->tk_proj->kpj_id == psp->p_rid) roperand++; break; case P_POOLID: if (pp->p_pool->pool_id == psp->p_rid) roperand++; break; case P_ZONEID: if (pp->p_zone->zone_id == psp->p_rid) roperand++; break; case P_CTID: if (PRCTID(pp) == psp->p_rid) roperand++; break; case P_ALL: roperand++; break; default: #ifdef DEBUG cmn_err(CE_WARN, "procinset called with bad set"); return (0); #else return (0); #endif } switch (psp->p_op) { case POP_DIFF: if (loperand && !lwprinproc && !roperand) return (1); else return (0); case POP_AND: if (loperand && roperand) return (1); else return (0); case POP_OR: if (loperand || roperand) return (1); else return (0); case POP_XOR: if ((loperand && !lwprinproc && !roperand) || (roperand && !lwplinproc && !loperand)) return (1); else return (0); default: #ifdef DEBUG cmn_err(CE_WARN, "procinset called with bad set"); return (0); #else return (0); #endif } /* NOTREACHED */ }
/* * Create a file system FUID for an ACL ace * or a chown/chgrp of the file. * This is similar to zfs_fuid_create_cred, except that * we can't find the domain + rid information in the * cred. Instead we have to query Winchester for the * domain and rid. * * During replay operations the domain+rid information is * found in the zfs_fuid_info_t that the replay code has * attached to the zfsvfs of the file system. */ uint64_t zfs_fuid_create(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr, zfs_fuid_type_t type, zfs_fuid_info_t **fuidpp) { #ifdef HAVE_ZPL const char *domain; char *kdomain; uint32_t fuid_idx = FUID_INDEX(id); uint32_t rid; idmap_stat status; uint64_t idx; zfs_fuid_t *zfuid = NULL; zfs_fuid_info_t *fuidp; /* * If POSIX ID, or entry is already a FUID then * just return the id * * We may also be handed an already FUID'ized id via * chmod. */ if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id) || fuid_idx != 0) return (id); if (zfsvfs->z_replay) { fuidp = zfsvfs->z_fuid_replay; /* * If we are passed an ephemeral id, but no * fuid_info was logged then return NOBODY. * This is most likely a result of idmap service * not being available. */ if (fuidp == NULL) return (UID_NOBODY); switch (type) { case ZFS_ACE_USER: case ZFS_ACE_GROUP: zfuid = list_head(&fuidp->z_fuids); rid = FUID_RID(zfuid->z_logfuid); idx = FUID_INDEX(zfuid->z_logfuid); break; case ZFS_OWNER: rid = FUID_RID(fuidp->z_fuid_owner); idx = FUID_INDEX(fuidp->z_fuid_owner); break; case ZFS_GROUP: rid = FUID_RID(fuidp->z_fuid_group); idx = FUID_INDEX(fuidp->z_fuid_group); break; }; domain = fuidp->z_domain_table[idx -1]; } else { if (type == ZFS_OWNER || type == ZFS_ACE_USER) status = kidmap_getsidbyuid(crgetzone(cr), id, &domain, &rid); else status = kidmap_getsidbygid(crgetzone(cr), id, &domain, &rid); if (status != 0) { /* * When returning nobody we will need to * make a dummy fuid table entry for logging * purposes. */ rid = UID_NOBODY; domain = nulldomain; } } idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, B_TRUE); if (!zfsvfs->z_replay) zfs_fuid_node_add(fuidpp, kdomain, rid, idx, id, type); else if (zfuid != NULL) { list_remove(&fuidp->z_fuids, zfuid); kmem_free(zfuid, sizeof (zfs_fuid_t)); } return (FUID_ENCODE(idx, rid)); #endif /* return cred uid which is set to acls uid */ if (type == ZFS_OWNER) return crgetuid(cr); else return crgetgid(cr); }
static bool_t authkern_marshal(AUTH *auth, XDR *xdrs, struct cred *cr) { char *sercred; XDR xdrm; struct opaque_auth *cred; bool_t ret = FALSE; const gid_t *gp, *gpend; int gidlen, credsize, namelen, rounded_namelen; int32_t *ptr; char *nodename = uts_nodename(); /* * First we try a fast path to get through * this very common operation. */ gp = crgetgroups(cr); gidlen = crgetngroups(cr); if (gidlen > NGRPS) gidlen = NGRPS; gpend = &gp[gidlen-1]; namelen = (int)strlen(nodename); rounded_namelen = RNDUP(namelen); credsize = 4 + 4 + rounded_namelen + 4 + 4 + 4 + gidlen * 4; ptr = XDR_INLINE(xdrs, 4 + 4 + credsize + 4 + 4); if (ptr) { /* * We can do the fast path. */ IXDR_PUT_INT32(ptr, AUTH_UNIX); /* cred flavor */ IXDR_PUT_INT32(ptr, credsize); /* cred len */ IXDR_PUT_INT32(ptr, gethrestime_sec()); IXDR_PUT_INT32(ptr, namelen); bcopy(nodename, (caddr_t)ptr, namelen); if (rounded_namelen - namelen) bzero(((caddr_t)ptr) + namelen, rounded_namelen - namelen); ptr += rounded_namelen / BYTES_PER_XDR_UNIT; IXDR_PUT_INT32(ptr, crgetuid(cr)); IXDR_PUT_INT32(ptr, crgetgid(cr)); IXDR_PUT_INT32(ptr, gidlen); while (gp <= gpend) { IXDR_PUT_INT32(ptr, *gp++); } IXDR_PUT_INT32(ptr, AUTH_NULL); /* verf flavor */ IXDR_PUT_INT32(ptr, 0); /* verf len */ return (TRUE); } sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP); /* * serialize u struct stuff into sercred */ xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE); if (!xdr_authkern(&xdrm)) { printf("authkern_marshal: xdr_authkern failed\n"); ret = FALSE; goto done; } /* * Make opaque auth credentials that point at serialized u struct */ cred = &(auth->ah_cred); cred->oa_length = XDR_GETPOS(&xdrm); cred->oa_base = sercred; /* * serialize credentials and verifiers (null) */ if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) && (xdr_opaque_auth(xdrs, &(auth->ah_verf)))) ret = TRUE; else ret = FALSE; done: kmem_free(sercred, MAX_AUTH_BYTES); return (ret); }
static int xdirmakexnode( struct xmemnode *dir, struct xmount *xm, struct vattr *va, enum de_op op, struct xmemnode **newnode, struct cred *cred) { struct xmemnode *xp; enum vtype type; ASSERT(va != NULL); ASSERT(op == DE_CREATE || op == DE_MKDIR); if (((va->va_mask & AT_ATIME) && TIMESPEC_OVERFLOW(&va->va_atime)) || ((va->va_mask & AT_MTIME) && TIMESPEC_OVERFLOW(&va->va_mtime))) return (EOVERFLOW); type = va->va_type; xp = xmem_memalloc(sizeof (struct xmemnode), 1); xp->xn_vnode = vn_alloc(KM_SLEEP); xmemnode_init(xm, xp, va, cred); if (type == VBLK || type == VCHR) { xp->xn_vnode->v_rdev = xp->xn_rdev = va->va_rdev; } else { xp->xn_vnode->v_rdev = xp->xn_rdev = NODEV; } xp->xn_vnode->v_type = type; xp->xn_uid = crgetuid(cred); /* * To determine the group-id of the created file: * 1) If the gid is set in the attribute list (non-Sun & pre-4.0 * clients are not likely to set the gid), then use it if * the process is privileged, belongs to the target group, * or the group is the same as the parent directory. * 2) If the filesystem was not mounted with the Old-BSD-compatible * GRPID option, and the directory's set-gid bit is clear, * then use the process's gid. * 3) Otherwise, set the group-id to the gid of the parent directory. */ if ((va->va_mask & AT_GID) && ((va->va_gid == dir->xn_gid) || groupmember(va->va_gid, cred) || secpolicy_vnode_create_gid(cred) == 0)) { xp->xn_gid = va->va_gid; } else { if (dir->xn_mode & VSGID) xp->xn_gid = dir->xn_gid; else xp->xn_gid = crgetgid(cred); } /* * If we're creating a directory, and the parent directory has the * set-GID bit set, set it on the new directory. * Otherwise, if the user is neither privileged nor a member of the * file's new group, clear the file's set-GID bit. */ if (dir->xn_mode & VSGID && type == VDIR) xp->xn_mode |= VSGID; else if ((xp->xn_mode & VSGID) && secpolicy_vnode_setids_setgids(cred, xp->xn_gid) != 0) xp->xn_mode &= ~VSGID; if (va->va_mask & AT_ATIME) xp->xn_atime = va->va_atime; if (va->va_mask & AT_MTIME) xp->xn_mtime = va->va_mtime; if (op == DE_MKDIR) xdirinit(dir, xp); *newnode = xp; return (0); }
void zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) { struct super_block *sb; zfs_sb_t *zsb; uint64_t moid, obj, sa_obj, version; uint64_t sense = ZFS_CASE_SENSITIVE; uint64_t norm = 0; nvpair_t *elem; int error; int i; znode_t *rootzp = NULL; vattr_t vattr; znode_t *zp; zfs_acl_ids_t acl_ids; /* * First attempt to create master node. */ /* * In an empty objset, there are no blocks to read and thus * there can be no i/o errors (which we assert below). */ moid = MASTER_NODE_OBJ; error = zap_create_claim(os, moid, DMU_OT_MASTER_NODE, DMU_OT_NONE, 0, tx); ASSERT(error == 0); /* * Set starting attributes. */ version = zfs_zpl_version_map(spa_version(dmu_objset_spa(os))); elem = NULL; while ((elem = nvlist_next_nvpair(zplprops, elem)) != NULL) { /* For the moment we expect all zpl props to be uint64_ts */ uint64_t val; char *name; ASSERT(nvpair_type(elem) == DATA_TYPE_UINT64); VERIFY(nvpair_value_uint64(elem, &val) == 0); name = nvpair_name(elem); if (strcmp(name, zfs_prop_to_name(ZFS_PROP_VERSION)) == 0) { if (val < version) version = val; } else { error = zap_update(os, moid, name, 8, 1, &val, tx); } ASSERT(error == 0); if (strcmp(name, zfs_prop_to_name(ZFS_PROP_NORMALIZE)) == 0) norm = val; else if (strcmp(name, zfs_prop_to_name(ZFS_PROP_CASE)) == 0) sense = val; } ASSERT(version != 0); error = zap_update(os, moid, ZPL_VERSION_STR, 8, 1, &version, tx); /* * Create zap object used for SA attribute registration */ if (version >= ZPL_VERSION_SA) { sa_obj = zap_create(os, DMU_OT_SA_MASTER_NODE, DMU_OT_NONE, 0, tx); error = zap_add(os, moid, ZFS_SA_ATTRS, 8, 1, &sa_obj, tx); ASSERT(error == 0); } else { sa_obj = 0; } /* * Create a delete queue. */ obj = zap_create(os, DMU_OT_UNLINKED_SET, DMU_OT_NONE, 0, tx); error = zap_add(os, moid, ZFS_UNLINKED_SET, 8, 1, &obj, tx); ASSERT(error == 0); /* * Create root znode. Create minimal znode/inode/zsb/sb * to allow zfs_mknode to work. */ vattr.va_mask = ATTR_MODE|ATTR_UID|ATTR_GID; vattr.va_mode = S_IFDIR|0755; vattr.va_uid = crgetuid(cr); vattr.va_gid = crgetgid(cr); rootzp = kmem_cache_alloc(znode_cache, KM_PUSHPAGE); rootzp->z_moved = 0; rootzp->z_unlinked = 0; rootzp->z_atime_dirty = 0; rootzp->z_is_sa = USE_SA(version, os); zsb = kmem_zalloc(sizeof (zfs_sb_t), KM_PUSHPAGE | KM_NODEBUG); zsb->z_os = os; zsb->z_parent = zsb; zsb->z_version = version; zsb->z_use_fuids = USE_FUIDS(version, os); zsb->z_use_sa = USE_SA(version, os); zsb->z_norm = norm; sb = kmem_zalloc(sizeof (struct super_block), KM_PUSHPAGE); sb->s_fs_info = zsb; ZTOI(rootzp)->i_sb = sb; error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END, &zsb->z_attr_table); ASSERT(error == 0); /* * Fold case on file systems that are always or sometimes case * insensitive. */ if (sense == ZFS_CASE_INSENSITIVE || sense == ZFS_CASE_MIXED) zsb->z_norm |= U8_TEXTPREP_TOUPPER; mutex_init(&zsb->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL); list_create(&zsb->z_all_znodes, sizeof (znode_t), offsetof(znode_t, z_link_node)); for (i = 0; i != ZFS_OBJ_MTX_SZ; i++) mutex_init(&zsb->z_hold_mtx[i], NULL, MUTEX_DEFAULT, NULL); VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr, cr, NULL, &acl_ids)); zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, rootzp); error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx); ASSERT(error == 0); zfs_acl_ids_free(&acl_ids); atomic_set(&ZTOI(rootzp)->i_count, 0); sa_handle_destroy(rootzp->z_sa_hdl); kmem_cache_free(znode_cache, rootzp); /* * Create shares directory */ error = zfs_create_share_dir(zsb, tx); ASSERT(error == 0); for (i = 0; i != ZFS_OBJ_MTX_SZ; i++) mutex_destroy(&zsb->z_hold_mtx[i]); kmem_free(sb, sizeof (struct super_block)); kmem_free(zsb, sizeof (zfs_sb_t)); }