void crsetcredgrp(cred_t *cr, credgrp_t *grps) { ASSERT(cr->cr_ref <= 2); if (cr->cr_grps != NULL) crgrprele(cr->cr_grps); cr->cr_grps = grps; }
/* * Release previous hold on a cred structure. Free it if refcnt == 0. * If cred uses label different from zone label, free it. */ void crfree(cred_t *cr) { if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) { ASSERT(cr != kcred); if (cr->cr_label) label_rele(cr->cr_label); if (cr->cr_klpd) crklpd_rele(cr->cr_klpd); if (cr->cr_zone) zone_cred_rele(cr->cr_zone); if (cr->cr_ksid) kcrsid_rele(cr->cr_ksid); if (cr->cr_grps) crgrprele(cr->cr_grps); kmem_cache_free(cred_cache, cr); } }
int crsetgroups(cred_t *cr, int n, gid_t *grp) { ASSERT(cr->cr_ref <= 2); if (n > ngroups_max || n < 0) return (-1); if (cr->cr_grps != NULL) crgrprele(cr->cr_grps); if (n > 0) { cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP); bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t)); cr->cr_grps->crg_ref = 1; cr->cr_grps->crg_ngroups = n; qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp); } else { cr->cr_grps = NULL; } return (0); }
int setgroups(int gidsetsize, gid_t *gidset) { proc_t *p; cred_t *cr, *newcr; int i; int n = gidsetsize; int error; int scnt = 0; ksidlist_t *ksl = NULL; zone_t *zone; struct credgrp *grps = NULL; /* Perform the cheapest tests before grabbing p_crlock */ if (n > ngroups_max || n < 0) return (set_errno(EINVAL)); zone = crgetzone(CRED()); if (n != 0) { const gid_t *groups; grps = crgrpcopyin(n, gidset); if (grps == NULL) return (set_errno(EFAULT)); groups = crgetggroups(grps); for (i = 0; i < n; i++) { if (!VALID_GID(groups[i], zone)) { crgrprele(grps); return (set_errno(EINVAL)); } if (groups[i] > MAXUID) scnt++; } if (scnt > 0) { ksl = kcrsid_gidstosids(zone, n, (gid_t *)groups); if (ksl == NULL) { crgrprele(grps); return (set_errno(EINVAL)); } } } /* * Need to pre-allocate the new cred structure before acquiring * the p_crlock mutex. */ newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); retry: cr = p->p_cred; crhold(cr); mutex_exit(&p->p_crlock); if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) != 0) { if (grps != NULL) crgrprele(grps); if (ksl != NULL) ksidlist_rele(ksl); crfree(newcr); crfree(cr); return (set_errno(error)); } mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry; crdup_to(cr, newcr); crsetsidlist(newcr, ksl); crsetcredgrp(newcr, grps); p->p_cred = newcr; crhold(newcr); /* hold for the current thread */ crfree(cr); /* free the old one */ mutex_exit(&p->p_crlock); /* * Broadcast new cred to process threads (including the current one). */ crset(p, newcr); return (0); }