int setgid(gid_t gid) { proc_t *p; int error; int do_nocd = 0; cred_t *cr, *newcr; ksid_t ksid, *ksp; zone_t *zone = crgetzone(CRED()); if (!VALID_GID(gid, zone)) return (set_errno(EINVAL)); if (gid > MAXUID) { if (ksid_lookupbygid(zone, gid, &ksid) != 0) return (set_errno(EINVAL)); ksp = &ksid; } else { ksp = NULL; } /* * Need to pre-allocate the new cred structure before grabbing * the p_crlock mutex. We cannot hold the mutex across the * secpolicy functions. */ newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); retry: cr = p->p_cred; crhold(cr); mutex_exit(&p->p_crlock); if ((gid == cr->cr_rgid || gid == cr->cr_sgid) && secpolicy_allow_setid(cr, -1, B_TRUE) != 0) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry; error = 0; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_gid = gid; crsetsid(newcr, ksp, KSID_GROUP); mutex_exit(&p->p_crlock); } else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry; /* * A privileged process that makes itself look like a * set-gid process must be marked to produce no core dump. */ if (cr->cr_gid != gid || cr->cr_rgid != gid || cr->cr_sgid != gid) do_nocd = 1; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_gid = gid; newcr->cr_rgid = gid; newcr->cr_sgid = gid; crsetsid(newcr, ksp, KSID_GROUP); mutex_exit(&p->p_crlock); } else { crfree(newcr); crfree(cr); if (ksp != NULL) ksid_rele(ksp); } if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } crset(p, newcr); /* broadcast to process threads */ return (0); } return (set_errno(error)); }
/* * Buy-back from SunOS 4.x * * Like setgid() and setegid() combined -except- that non-root users * can change cr_rgid to cr_gid, and the semantics of cr_sgid are * subtly different. */ int setregid(gid_t rgid, gid_t egid) { proc_t *p; int error = EPERM; int do_nocd = 0; cred_t *cr, *newcr; ksid_t ksid, *ksp; zone_t *zone = crgetzone(CRED()); if ((rgid != -1 && !VALID_GID(rgid, zone)) || (egid != -1 && !VALID_GID(egid, zone))) return (set_errno(EINVAL)); if (egid != -1 && egid > MAXUID) { if (ksid_lookupbygid(zone, egid, &ksid) != 0) return (set_errno(EINVAL)); ksp = &ksid; } else { ksp = NULL; } /* * Need to pre-allocate the new cred structure before grabbing * the p_crlock mutex. */ newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); cr = p->p_cred; if ((rgid == -1 || rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) && (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid || egid == cr->cr_sgid) || (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) { crhold(cr); crcopy_to(cr, newcr); p->p_cred = newcr; if (egid != -1) { newcr->cr_gid = egid; crsetsid(newcr, ksp, KSID_GROUP); } if (rgid != -1) newcr->cr_rgid = rgid; /* * "If the real gid is being changed, or the effective gid is * being changed to a value not equal to the real gid, the * saved gid is set to the new effective gid." */ if (rgid != -1 || (egid != -1 && newcr->cr_gid != newcr->cr_rgid)) newcr->cr_sgid = newcr->cr_gid; /* * A privileged process that makes itself look like a * set-gid process must be marked to produce no core dump. */ if ((cr->cr_gid != newcr->cr_gid || cr->cr_rgid != newcr->cr_rgid || cr->cr_sgid != newcr->cr_sgid) && error == 0) do_nocd = 1; error = 0; crfree(cr); } mutex_exit(&p->p_crlock); if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } crset(p, newcr); /* broadcast to process threads */ return (0); } crfree(newcr); if (ksp != NULL) ksid_rele(ksp); return (set_errno(error)); }
int setuid(uid_t uid) { proc_t *p; int error; int do_nocd = 0; int uidchge = 0; cred_t *cr, *newcr; uid_t oldruid = uid; zoneid_t zoneid = getzoneid(); ksid_t ksid, *ksp; zone_t *zone = crgetzone(CRED()); if (!VALID_UID(uid, zone)) return (set_errno(EINVAL)); if (uid > MAXUID) { if (ksid_lookupbyuid(zone, uid, &ksid) != 0) return (set_errno(EINVAL)); ksp = &ksid; } else { ksp = NULL; } /* * Need to pre-allocate the new cred structure before grabbing * the p_crlock mutex. We can't hold on to the p_crlock for most * if this though, now that we allow kernel upcalls from the * policy routines. */ newcr = cralloc_ksid(); p = ttoproc(curthread); retry: mutex_enter(&p->p_crlock); retry_locked: cr = p->p_cred; crhold(cr); mutex_exit(&p->p_crlock); if ((uid == cr->cr_ruid || uid == cr->cr_suid) && secpolicy_allow_setid(cr, uid, B_TRUE) != 0) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry_locked; error = 0; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); mutex_exit(&p->p_crlock); } else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry_locked; if (!uidchge && uid != cr->cr_ruid) { /* * The ruid of the process is going to change. In order * to avoid a race condition involving the * process-count associated with the newly given ruid, * we increment the count before assigning the * credential to the process. * To do that, we'll have to take pidlock, so we first * release p_crlock. */ mutex_exit(&p->p_crlock); uidchge = 1; mutex_enter(&pidlock); upcount_inc(uid, zoneid); mutex_exit(&pidlock); /* * As we released p_crlock we can't rely on the cr * we read. So retry the whole thing. */ goto retry; } /* * A privileged process that gives up its privilege * must be marked to produce no core dump. */ if (cr->cr_uid != uid || cr->cr_ruid != uid || cr->cr_suid != uid) do_nocd = 1; oldruid = cr->cr_ruid; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_ruid = uid; newcr->cr_suid = uid; newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); priv_reset_PA(newcr, B_TRUE); ASSERT(uid != oldruid ? uidchge : 1); mutex_exit(&p->p_crlock); } else { crfree(newcr); crfree(cr); if (ksp != NULL) ksid_rele(ksp); } /* * We decrement the number of processes associated with the oldruid * to match the increment above, even if the ruid of the process * did not change or an error occurred (oldruid == uid). */ if (uidchge) { mutex_enter(&pidlock); upcount_dec(oldruid, zoneid); mutex_exit(&pidlock); } if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } crset(p, newcr); /* broadcast to process threads */ return (0); } return (set_errno(error)); }
/* * Buy-back from SunOS 4.x * * Like setuid() and seteuid() combined -except- that non-root users * can change cr_ruid to cr_uid, and the semantics of cr_suid are * subtly different. */ int setreuid(uid_t ruid, uid_t euid) { proc_t *p; int error = 0; int do_nocd = 0; int uidchge = 0; uid_t oldruid = ruid; cred_t *cr, *newcr; zoneid_t zoneid = getzoneid(); ksid_t ksid, *ksp; zone_t *zone = crgetzone(CRED()); if ((ruid != -1 && !VALID_UID(ruid, zone)) || (euid != -1 && !VALID_UID(euid, zone))) return (set_errno(EINVAL)); if (euid != -1 && euid > MAXUID) { if (ksid_lookupbyuid(zone, euid, &ksid) != 0) return (set_errno(EINVAL)); ksp = &ksid; } else { ksp = NULL; } /* * Need to pre-allocate the new cred structure before grabbing * the p_crlock mutex. */ newcr = cralloc_ksid(); p = ttoproc(curthread); retry: mutex_enter(&p->p_crlock); retry_locked: crhold(cr = p->p_cred); mutex_exit(&p->p_crlock); if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid && secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry_locked; error = EPERM; } else if (euid != -1 && euid != cr->cr_ruid && euid != cr->cr_uid && euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry_locked; error = EPERM; } else { mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry_locked; if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) { /* * The ruid of the process is going to change. In order * to avoid a race condition involving the * process-count associated with the newly given ruid, * we increment the count before assigning the * credential to the process. * To do that, we'll have to take pidlock, so we first * release p_crlock. */ mutex_exit(&p->p_crlock); uidchge = 1; mutex_enter(&pidlock); upcount_inc(ruid, zoneid); mutex_exit(&pidlock); /* * As we released p_crlock we can't rely on the cr * we read. So retry the whole thing. */ goto retry; } crhold(cr); crcopy_to(cr, newcr); p->p_cred = newcr; if (euid != -1) { newcr->cr_uid = euid; crsetsid(newcr, ksp, KSID_USER); } if (ruid != -1) { oldruid = newcr->cr_ruid; newcr->cr_ruid = ruid; ASSERT(ruid != oldruid ? uidchge : 1); } /* * "If the real uid is being changed, or the effective uid is * being changed to a value not equal to the real uid, the * saved uid is set to the new effective uid." */ if (ruid != -1 || (euid != -1 && newcr->cr_uid != newcr->cr_ruid)) newcr->cr_suid = newcr->cr_uid; /* * A process that gives up its privilege * must be marked to produce no core dump. */ if ((cr->cr_uid != newcr->cr_uid || cr->cr_ruid != newcr->cr_ruid || cr->cr_suid != newcr->cr_suid)) do_nocd = 1; priv_reset_PA(newcr, ruid != -1 && euid != -1 && ruid == euid); crfree(cr); } mutex_exit(&p->p_crlock); /* * We decrement the number of processes associated with the oldruid * to match the increment above, even if the ruid of the process * did not change or an error occurred (oldruid == uid). */ if (uidchge) { ASSERT(oldruid != -1 && ruid != -1); mutex_enter(&pidlock); upcount_dec(oldruid, zoneid); mutex_exit(&pidlock); } if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } crset(p, newcr); /* broadcast to process threads */ return (0); } crfree(newcr); if (ksp != NULL) ksid_rele(ksp); return (set_errno(error)); }
int seteuid(uid_t uid) { proc_t *p; int error = EPERM; int do_nocd = 0; cred_t *cr, *newcr; ksid_t ksid, *ksp; zone_t *zone = crgetzone(CRED()); if (!VALID_UID(uid, zone)) return (set_errno(EINVAL)); if (uid > MAXUID) { if (ksid_lookupbyuid(zone, uid, &ksid) != 0) return (set_errno(EINVAL)); ksp = &ksid; } else { ksp = NULL; } /* * Need to pre-allocate the new cred structure before grabbing * the p_crlock mutex. */ newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); retry: crhold(cr = p->p_cred); mutex_exit(&p->p_crlock); if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid || (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { /* * A privileged process that makes itself look like a * set-uid process must be marked to produce no core dump, * if the effective uid did changed. */ mutex_enter(&p->p_crlock); crfree(cr); if (cr != p->p_cred) goto retry; if (cr->cr_uid != uid && error == 0) do_nocd = 1; error = 0; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); priv_reset_PA(newcr, B_FALSE); mutex_exit(&p->p_crlock); if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } crset(p, newcr); /* broadcast to process threads */ return (0); } crfree(newcr); crfree(cr); if (ksp != NULL) ksid_rele(ksp); return (set_errno(error)); }
/* * 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); }