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); }
/* * Allocate a Solaris cred and initialize it based on the access token. * * If the user can be mapped to a non-ephemeral ID, the cred gid is set * to the Solaris user's primary group. * * If the mapped UID is ephemeral, or the primary group could not be * obtained, the cred gid is set to whatever Solaris group is mapped * to the token's primary group. */ cred_t * smb_cred_create(smb_token_t *token) { ksid_t ksid; ksidlist_t *ksidlist = NULL; smb_posix_grps_t *posix_grps; cred_t *cr; gid_t gid; ASSERT(token); ASSERT(token->tkn_posix_grps); posix_grps = token->tkn_posix_grps; cr = crget(); ASSERT(cr != NULL); if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) && (posix_grps->pg_ngrps != 0)) { gid = posix_grps->pg_grps[0]; } else { gid = token->tkn_primary_grp.i_id; } if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) { crfree(cr); return (NULL); } if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) { crfree(cr); return (NULL); } smb_cred_set_sid(&token->tkn_user, &ksid); crsetsid(cr, &ksid, KSID_USER); smb_cred_set_sid(&token->tkn_primary_grp, &ksid); crsetsid(cr, &ksid, KSID_GROUP); smb_cred_set_sid(&token->tkn_owner, &ksid); crsetsid(cr, &ksid, KSID_OWNER); ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); crsetsidlist(cr, ksidlist); /* * In the AD world, "take ownership privilege" is very much * like having Unix "root" privileges. It's normally given * to members of the "Administrators" group, which normally * includes the the local Administrator (like root) and when * joined to a domain, "Domain Admins". */ if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) { (void) crsetpriv(cr, PRIV_FILE_CHOWN, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, NULL); } return (cr); }