#include <sys/param.h>
#include <sys/acct.h>
#include <sys/systm.h>
#include <sys/sysmsg.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/caps.h>
#include <sys/malloc.h>
#include <sys/pioctl.h>
#include <sys/resourcevar.h>
#include <sys/jail.h>
#include <sys/lockf.h>
#include <sys/spinlock.h>
#include <sys/spinlock2.h>
static MALLOC_DEFINE(M_CRED, "cred", "credentials");
int
sys_getpid(struct sysmsg *sysmsg, const struct getpid_args *uap)
{
struct proc *p = curproc;
sysmsg->sysmsg_fds[0] = p->p_pid;
return (0);
}
int
sys_getppid(struct sysmsg *sysmsg, const struct getppid_args *uap)
{
struct proc *p = curproc;
sysmsg->sysmsg_result = p->p_ppid;
return (0);
}
int
sys_lwp_gettid(struct sysmsg *sysmsg, const struct lwp_gettid_args *uap)
{
struct lwp *lp = curthread->td_lwp;
sysmsg->sysmsg_result = lp->lwp_tid;
return (0);
}
int
sys_getpgrp(struct sysmsg *sysmsg, const struct getpgrp_args *uap)
{
struct proc *p = curproc;
lwkt_gettoken_shared(&p->p_token);
sysmsg->sysmsg_result = p->p_pgrp->pg_id;
lwkt_reltoken(&p->p_token);
return (0);
}
int
sys_getpgid(struct sysmsg *sysmsg, const struct getpgid_args *uap)
{
struct proc *p = curproc;
struct proc *pt;
int error;
error = 0;
if (uap->pid == 0) {
pt = p;
PHOLD(pt);
} else {
pt = pfind(uap->pid);
if (pt == NULL)
error = ESRCH;
}
if (error == 0) {
lwkt_gettoken_shared(&pt->p_token);
sysmsg->sysmsg_result = pt->p_pgrp->pg_id;
lwkt_reltoken(&pt->p_token);
}
if (pt)
PRELE(pt);
return (error);
}
int
sys_getsid(struct sysmsg *sysmsg, const struct getsid_args *uap)
{
struct proc *p = curproc;
struct proc *pt;
int error;
error = 0;
if (uap->pid == 0) {
pt = p;
PHOLD(pt);
} else {
pt = pfind(uap->pid);
if (pt == NULL)
error = ESRCH;
}
if (error == 0)
sysmsg->sysmsg_result = pt->p_session->s_sid;
if (pt)
PRELE(pt);
return (error);
}
int
sys_getuid(struct sysmsg *sysmsg, const struct getuid_args *uap)
{
struct ucred *cred = curthread->td_ucred;
sysmsg->sysmsg_fds[0] = cred->cr_ruid;
return (0);
}
int
sys_geteuid(struct sysmsg *sysmsg, const struct geteuid_args *uap)
{
struct ucred *cred = curthread->td_ucred;
sysmsg->sysmsg_result = cred->cr_uid;
return (0);
}
int
sys_getgid(struct sysmsg *sysmsg, const struct getgid_args *uap)
{
struct ucred *cred = curthread->td_ucred;
sysmsg->sysmsg_fds[0] = cred->cr_rgid;
return (0);
}
int
sys_getegid(struct sysmsg *sysmsg, const struct getegid_args *uap)
{
struct ucred *cred = curthread->td_ucred;
sysmsg->sysmsg_result = cred->cr_groups[0];
return (0);
}
int
sys_getgroups(struct sysmsg *sysmsg, const struct getgroups_args *uap)
{
struct ucred *cr;
u_int ngrp;
int error;
cr = curthread->td_ucred;
if ((ngrp = uap->gidsetsize) == 0) {
sysmsg->sysmsg_result = cr->cr_ngroups;
return (0);
}
if (ngrp < cr->cr_ngroups)
return (EINVAL);
ngrp = cr->cr_ngroups;
error = copyout((caddr_t)cr->cr_groups,
(caddr_t)uap->gidset, ngrp * sizeof(gid_t));
if (error == 0)
sysmsg->sysmsg_result = ngrp;
return (error);
}
int
sys_lwp_setname(struct sysmsg *sysmsg, const struct lwp_setname_args *uap)
{
struct proc *p = curproc;
struct lwp *lp;
char buf[LPMAP_MAXTHREADTITLE];
int error;
size_t len;
if (uap->name != NULL) {
error = copyinstr(uap->name, buf, sizeof(buf), &len);
if (error) {
if (error != ENAMETOOLONG)
return error;
buf[sizeof(buf)-1] = 0;
len = sizeof(buf) - 1;
}
} else {
buf[0] = 0;
len = 1;
}
lwkt_gettoken(&p->p_token);
lp = lwpfind(p, uap->tid);
if (lp) {
lwkt_gettoken(&lp->lwp_token);
if (lp->lwp_lpmap == NULL)
lwp_usermap(lp, -1);
if (lp->lwp_lpmap)
bcopy(buf, lp->lwp_lpmap->thread_title, len);
lwkt_reltoken(&lp->lwp_token);
LWPRELE(lp);
error = 0;
} else {
error = ESRCH;
}
lwkt_reltoken(&p->p_token);
return error;
}
int
sys_lwp_getname(struct sysmsg *sysmsg, const struct lwp_getname_args *uap)
{
struct proc *p = curproc;
struct lwp *lp;
char buf[LPMAP_MAXTHREADTITLE];
int error;
size_t len;
char c;
len = 0;
lwkt_gettoken(&p->p_token);
lp = lwpfind(p, uap->tid);
if (lp) {
lwkt_gettoken(&lp->lwp_token);
if (lp->lwp_lpmap == NULL)
lwp_usermap(lp, -1);
if (lp->lwp_lpmap) {
for (len = 0; len < LPMAP_MAXTHREADTITLE - 1 &&
len < uap->len - 1; ++len) {
c = lp->lwp_lpmap->thread_title[len];
if (c == 0)
break;
buf[len] = c;
}
}
lwkt_reltoken(&lp->lwp_token);
LWPRELE(lp);
error = 0;
} else {
error = ESRCH;
}
buf[len++] = 0;
lwkt_reltoken(&p->p_token);
if (uap->len)
error = copyout(buf, uap->name, len);
return error;
}
int
sys_setsid(struct sysmsg *sysmsg, const struct setsid_args *uap)
{
struct proc *p = curproc;
struct pgrp *pg = NULL;
int error;
lwkt_gettoken(&p->p_token);
if (p->p_pgid == p->p_pid || (pg = pgfind(p->p_pid)) != NULL) {
error = EPERM;
if (pg)
pgrel(pg);
} else {
enterpgrp(p, p->p_pid, 1);
sysmsg->sysmsg_result = p->p_pid;
error = 0;
}
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setpgid(struct sysmsg *sysmsg, const struct setpgid_args *uap)
{
struct proc *curp = curproc;
struct proc *targp;
struct pgrp *pgrp = NULL;
int error;
int pgid = uap->pgid;
if (pgid < 0)
return (EINVAL);
if (uap->pid != 0 && uap->pid != curp->p_pid) {
if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
if (targp)
PRELE(targp);
error = ESRCH;
targp = NULL;
goto done;
}
lwkt_gettoken(&targp->p_token);
if (targp->p_pgrp == NULL ||
targp->p_session != curp->p_session) {
error = EPERM;
goto done;
}
if (targp->p_flags & P_EXEC) {
error = EACCES;
goto done;
}
} else {
targp = curp;
PHOLD(targp);
lwkt_gettoken(&targp->p_token);
}
if (SESS_LEADER(targp)) {
error = EPERM;
goto done;
}
if (pgid == 0) {
pgid = targp->p_pid;
} else if (pgid != targp->p_pid) {
if ((pgrp = pgfind(pgid)) == NULL ||
pgrp->pg_session != curp->p_session) {
error = EPERM;
goto done;
}
}
error = enterpgrp(targp, pgid, 0);
done:
if (pgrp)
pgrel(pgrp);
if (targp) {
lwkt_reltoken(&targp->p_token);
PRELE(targp);
}
return (error);
}
#define POSIX_APPENDIX_B_4_2_2
int
sys_setuid(struct sysmsg *sysmsg, const struct setuid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
uid_t uid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
uid = uap->uid;
if (uid != cr->cr_ruid &&
#ifdef _POSIX_SAVED_IDS
uid != crc->cr_svuid &&
#endif
#ifdef POSIX_APPENDIX_B_4_2_2
uid != cr->cr_uid &&
#endif
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETUID)))
goto done;
#ifdef _POSIX_SAVED_IDS
if (
#ifdef POSIX_APPENDIX_B_4_2_2
uid == cr->cr_uid ||
#endif
caps_priv_check(cr, SYSCAP_NOCRED_SETUID, 0) == 0)
#endif
{
if (uid != cr->cr_ruid) {
cr = change_ruid(uid);
setsugid();
}
if (cr->cr_svuid != uid) {
cr = cratom_proc(p);
cr->cr_svuid = uid;
setsugid();
}
}
if (cr->cr_uid != uid) {
change_euid(uid);
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_seteuid(struct sysmsg *sysmsg, const struct seteuid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
uid_t euid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
euid = uap->euid;
if (euid != cr->cr_ruid &&
euid != cr->cr_svuid &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETEUID)))
{
lwkt_reltoken(&p->p_token);
return (error);
}
if (cr->cr_uid != euid) {
change_euid(euid);
setsugid();
}
lwkt_reltoken(&p->p_token);
return (0);
}
int
sys_setgid(struct sysmsg *sysmsg, const struct setgid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
gid_t gid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
gid = uap->gid;
if (gid != cr->cr_rgid &&
#ifdef _POSIX_SAVED_IDS
gid != cr->cr_svgid &&
#endif
#ifdef POSIX_APPENDIX_B_4_2_2
gid != cr->cr_groups[0] &&
#endif
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETGID)))
{
goto done;
}
#ifdef _POSIX_SAVED_IDS
if (
#ifdef POSIX_APPENDIX_B_4_2_2
gid == cr->cr_groups[0] ||
#endif
cpas_priv_check(cr, SYSCAP_NOCRED_SETGID) == 0)
#endif
{
if (cr->cr_rgid != gid) {
cr = cratom_proc(p);
cr->cr_rgid = gid;
setsugid();
}
if (cr->cr_svgid != gid) {
cr = cratom_proc(p);
cr->cr_svgid = gid;
setsugid();
}
}
if (cr->cr_groups[0] != gid) {
cr = cratom_proc(p);
cr->cr_groups[0] = gid;
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setegid(struct sysmsg *sysmsg, const struct setegid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
gid_t egid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
egid = uap->egid;
if (egid != cr->cr_rgid &&
egid != cr->cr_svgid &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETEGID)))
{
goto done;
}
if (cr->cr_groups[0] != egid) {
cr = cratom_proc(p);
cr->cr_groups[0] = egid;
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setgroups(struct sysmsg *sysmsg, const struct setgroups_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
u_int ngrp;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
if ((error = caps_priv_check(cr, SYSCAP_NOCRED_SETGROUPS)))
goto done;
ngrp = uap->gidsetsize;
if (ngrp > NGROUPS) {
error = EINVAL;
goto done;
}
cr = cratom_proc(p);
if (ngrp < 1) {
cr->cr_ngroups = 1;
} else {
error = copyin(uap->gidset, cr->cr_groups,
ngrp * sizeof(gid_t));
if (error)
goto done;
cr->cr_ngroups = ngrp;
}
setsugid();
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setreuid(struct sysmsg *sysmsg, const struct setreuid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
uid_t ruid, euid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
ruid = uap->ruid;
euid = uap->euid;
if (((ruid != (uid_t)-1 && ruid != cr->cr_ruid &&
ruid != cr->cr_svuid) ||
(euid != (uid_t)-1 && euid != cr->cr_uid &&
euid != cr->cr_ruid && euid != cr->cr_svuid)) &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETREUID)) != 0)
{
goto done;
}
if (euid != (uid_t)-1 && cr->cr_uid != euid) {
cr = change_euid(euid);
setsugid();
}
if (ruid != (uid_t)-1 && cr->cr_ruid != ruid) {
cr = change_ruid(ruid);
setsugid();
}
if ((ruid != (uid_t)-1 || cr->cr_uid != cr->cr_ruid) &&
cr->cr_svuid != cr->cr_uid) {
cr = cratom_proc(p);
cr->cr_svuid = cr->cr_uid;
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setregid(struct sysmsg *sysmsg, const struct setregid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
gid_t rgid, egid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
rgid = uap->rgid;
egid = uap->egid;
if (((rgid != (gid_t)-1 && rgid != cr->cr_rgid &&
rgid != cr->cr_svgid) ||
(egid != (gid_t)-1 && egid != cr->cr_groups[0] &&
egid != cr->cr_rgid && egid != cr->cr_svgid)) &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETREGID)) != 0)
{
goto done;
}
if (egid != (gid_t)-1 && cr->cr_groups[0] != egid) {
cr = cratom_proc(p);
cr->cr_groups[0] = egid;
setsugid();
}
if (rgid != (gid_t)-1 && cr->cr_rgid != rgid) {
cr = cratom_proc(p);
cr->cr_rgid = rgid;
setsugid();
}
if ((rgid != (gid_t)-1 || cr->cr_groups[0] != cr->cr_rgid) &&
cr->cr_svgid != cr->cr_groups[0]) {
cr = cratom_proc(p);
cr->cr_svgid = cr->cr_groups[0];
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setresuid(struct sysmsg *sysmsg, const struct setresuid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
uid_t ruid, euid, suid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
ruid = uap->ruid;
euid = uap->euid;
suid = uap->suid;
if (((ruid != (uid_t)-1 && ruid != cr->cr_ruid &&
ruid != cr->cr_svuid && ruid != cr->cr_uid) ||
(euid != (uid_t)-1 && euid != cr->cr_ruid &&
euid != cr->cr_svuid && euid != cr->cr_uid) ||
(suid != (uid_t)-1 && suid != cr->cr_ruid &&
suid != cr->cr_svuid && suid != cr->cr_uid)) &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETRESUID)) != 0)
{
goto done;
}
if (euid != (uid_t)-1 && cr->cr_uid != euid) {
cr = change_euid(euid);
setsugid();
}
if (ruid != (uid_t)-1 && cr->cr_ruid != ruid) {
cr = change_ruid(ruid);
setsugid();
}
if (suid != (uid_t)-1 && cr->cr_svuid != suid) {
cr = cratom_proc(p);
cr->cr_svuid = suid;
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_setresgid(struct sysmsg *sysmsg, const struct setresgid_args *uap)
{
struct proc *p = curproc;
struct ucred *cr;
gid_t rgid, egid, sgid;
int error;
lwkt_gettoken(&p->p_token);
cr = p->p_ucred;
rgid = uap->rgid;
egid = uap->egid;
sgid = uap->sgid;
if (((rgid != (gid_t)-1 && rgid != cr->cr_rgid &&
rgid != cr->cr_svgid && rgid != cr->cr_groups[0]) ||
(egid != (gid_t)-1 && egid != cr->cr_rgid &&
egid != cr->cr_svgid && egid != cr->cr_groups[0]) ||
(sgid != (gid_t)-1 && sgid != cr->cr_rgid &&
sgid != cr->cr_svgid && sgid != cr->cr_groups[0])) &&
(error = caps_priv_check(cr, SYSCAP_NOCRED_SETRESGID)) != 0)
{
goto done;
}
if (egid != (gid_t)-1 && cr->cr_groups[0] != egid) {
cr = cratom_proc(p);
cr->cr_groups[0] = egid;
setsugid();
}
if (rgid != (gid_t)-1 && cr->cr_rgid != rgid) {
cr = cratom_proc(p);
cr->cr_rgid = rgid;
setsugid();
}
if (sgid != (gid_t)-1 && cr->cr_svgid != sgid) {
cr = cratom_proc(p);
cr->cr_svgid = sgid;
setsugid();
}
error = 0;
done:
lwkt_reltoken(&p->p_token);
return (error);
}
int
sys_getresuid(struct sysmsg *sysmsg, const struct getresuid_args *uap)
{
struct ucred *cr;
int error1 = 0, error2 = 0, error3 = 0;
cr = curthread->td_ucred;
if (uap->ruid)
error1 = copyout((caddr_t)&cr->cr_ruid,
(caddr_t)uap->ruid, sizeof(cr->cr_ruid));
if (uap->euid)
error2 = copyout((caddr_t)&cr->cr_uid,
(caddr_t)uap->euid, sizeof(cr->cr_uid));
if (uap->suid)
error3 = copyout((caddr_t)&cr->cr_svuid,
(caddr_t)uap->suid, sizeof(cr->cr_svuid));
return error1 ? error1 : (error2 ? error2 : error3);
}
int
sys_getresgid(struct sysmsg *sysmsg, const struct getresgid_args *uap)
{
struct ucred *cr;
int error1 = 0, error2 = 0, error3 = 0;
cr = curthread->td_ucred;
if (uap->rgid)
error1 = copyout(&cr->cr_rgid, uap->rgid,
sizeof(cr->cr_rgid));
if (uap->egid)
error2 = copyout(&cr->cr_groups[0], uap->egid,
sizeof(cr->cr_groups[0]));
if (uap->sgid)
error3 = copyout(&cr->cr_svgid, uap->sgid,
sizeof(cr->cr_svgid));
return error1 ? error1 : (error2 ? error2 : error3);
}
int
sys_issetugid(struct sysmsg *sysmsg, const struct issetugid_args *uap)
{
sysmsg->sysmsg_result = (curproc->p_flags & P_SUGID) ? 1 : 0;
return (0);
}
int
groupmember(gid_t gid, struct ucred *cred)
{
gid_t *gp;
gid_t *egp;
egp = &(cred->cr_groups[cred->cr_ngroups]);
for (gp = cred->cr_groups; gp < egp; gp++) {
if (*gp == gid)
return (1);
}
return (0);
}
#if 0
int
priv_check(struct thread *td, int priv)
{
if (td->td_lwp != NULL)
return priv_check_cred(td->td_ucred, priv, 0);
return (0);
}
int
priv_check_cred(struct ucred *cred, int priv, int flags)
{
int error;
KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege"));
KASSERT(cred != NULL || (flags & NULL_CRED_OKAY),
("priv_check_cred: NULL cred!"));
if (cred == NULL) {
if (flags & NULL_CRED_OKAY)
return (0);
else
return (EPERM);
}
if (cred->cr_uid != 0)
return (EPERM);
error = prison_priv_check(cred, priv);
if (error)
return (error);
error = caps_priv_check(cred, priv);
if (error)
return (error);
return (0);
}
#endif
int
p_trespass(struct ucred *cr1, struct ucred *cr2)
{
if (cr1 == cr2)
return (0);
if (!PRISON_CHECK(cr1, cr2))
return (ESRCH);
if ((caps_get(cr1, SYSCAP_RESTRICTEDROOT) & __SYSCAP_SELF) &&
(caps_get(cr2, SYSCAP_RESTRICTEDROOT) & __SYSCAP_SELF) == 0)
{
return (ESRCH);
}
if (cr1->cr_ruid == cr2->cr_ruid)
return (0);
if (cr1->cr_uid == cr2->cr_ruid)
return (0);
if (cr1->cr_ruid == cr2->cr_uid)
return (0);
if (cr1->cr_uid == cr2->cr_uid)
return (0);
if (caps_priv_check(cr1, SYSCAP_NOPROC_TRESPASS) == 0)
return (0);
if (cr1->cr_uid == 0)
return (0);
return (EPERM);
}
struct ucred *
crget(void)
{
struct ucred *cr;
cr = kmalloc(sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
cr->cr_ref = 1;
return (cr);
}
struct ucred *
crhold(struct ucred *cr)
{
if (cr != NOCRED && cr != FSCRED)
atomic_add_long(&cr->cr_ref, 1);
return(cr);
}
void
crfree(struct ucred *cr)
{
if (cr->cr_ref <= 0)
panic("Freeing already free credential! %p", cr);
if (atomic_fetchadd_long(&cr->cr_ref, -1) == 1) {
if (cr->cr_uidinfo != NULL) {
uidrop(cr->cr_uidinfo);
cr->cr_uidinfo = NULL;
}
if (cr->cr_ruidinfo != NULL) {
uidrop(cr->cr_ruidinfo);
cr->cr_ruidinfo = NULL;
}
if (jailed(cr))
prison_free(cr->cr_prison);
cr->cr_prison = NULL;
kfree((caddr_t)cr, M_CRED);
}
}
struct ucred *
cratom(struct ucred **pcr)
{
struct ucred *oldcr;
struct ucred *newcr;
oldcr = *pcr;
if (oldcr->cr_ref == 1)
return (oldcr);
newcr = crget();
oldcr = *pcr;
*newcr = *oldcr;
uihold(newcr->cr_uidinfo);
uihold(newcr->cr_ruidinfo);
if (jailed(newcr))
prison_hold(newcr->cr_prison);
newcr->cr_ref = 1;
crfree(oldcr);
*pcr = newcr;
return (newcr);
}
struct ucred *
cratom_proc(struct proc *p)
{
struct ucred *oldcr;
struct ucred *newcr;
oldcr = p->p_ucred;
if (oldcr->cr_ref == 1)
return(oldcr);
newcr = crget();
oldcr = p->p_ucred;
*newcr = *oldcr;
uihold(newcr->cr_uidinfo);
uihold(newcr->cr_ruidinfo);
if (jailed(newcr))
prison_hold(newcr->cr_prison);
newcr->cr_ref = 1;
spin_lock(&p->p_spin);
p->p_ucred = newcr;
spin_unlock(&p->p_spin);
crfree(oldcr);
return newcr;
}
struct ucred *
crdup(struct ucred *cr)
{
struct ucred *newcr;
newcr = crget();
*newcr = *cr;
uihold(newcr->cr_uidinfo);
uihold(newcr->cr_ruidinfo);
if (jailed(newcr))
prison_hold(newcr->cr_prison);
newcr->cr_ref = 1;
return (newcr);
}
struct ucred *
crdup_nocaps(struct ucred *cr)
{
struct ucred *newcr;
newcr = crget();
*newcr = *cr;
uihold(newcr->cr_uidinfo);
uihold(newcr->cr_ruidinfo);
newcr->cr_prison = NULL;
bzero(&newcr->cr_caps, sizeof(newcr->cr_caps));
newcr->cr_ref = 1;
return (newcr);
}
void
cru2x(struct ucred *cr, struct xucred *xcr)
{
bzero(xcr, sizeof(*xcr));
xcr->cr_version = XUCRED_VERSION;
xcr->cr_uid = cr->cr_uid;
xcr->cr_ngroups = cr->cr_ngroups;
bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
}
int
sys_getlogin(struct sysmsg *sysmsg, const struct getlogin_args *uap)
{
struct proc *p = curproc;
char buf[MAXLOGNAME];
int error;
size_t namelen;
namelen = uap->namelen;
if (namelen > MAXLOGNAME)
namelen = MAXLOGNAME;
bzero(buf, sizeof(buf));
lwkt_gettoken_shared(&p->p_token);
bcopy(p->p_pgrp->pg_session->s_login, buf, namelen);
lwkt_reltoken(&p->p_token);
error = copyout(buf, uap->namebuf, namelen);
return (error);
}
int
sys_setlogin(struct sysmsg *sysmsg, const struct setlogin_args *uap)
{
struct thread *td = curthread;
struct proc *p;
struct ucred *cred;
char buf[MAXLOGNAME];
int error;
cred = td->td_ucred;
p = td->td_proc;
if ((error = caps_priv_check(cred, SYSCAP_NOPROC_SETLOGIN)))
return (error);
bzero(buf, sizeof(buf));
error = copyinstr(uap->namebuf, buf, sizeof(buf), NULL);
if (error == ENAMETOOLONG)
error = EINVAL;
if (error == 0) {
lwkt_gettoken_shared(&p->p_token);
memcpy(p->p_pgrp->pg_session->s_login, buf, sizeof(buf));
lwkt_reltoken(&p->p_token);
}
return (error);
}
void
setsugid(void)
{
struct proc *p = curproc;
KKASSERT(p != NULL);
lwkt_gettoken(&p->p_token);
p->p_flags |= P_SUGID;
if (!(p->p_pfsflags & PF_ISUGID))
p->p_stops = 0;
lwkt_reltoken(&p->p_token);
}
struct ucred *
change_euid(uid_t euid)
{
struct proc *p = curproc;
struct ucred *cr;
KKASSERT(p != NULL);
lf_count_adjust(p, 0);
cr = cratom_proc(p);
cr->cr_uid = euid;
uireplace(&cr->cr_uidinfo, uifind(euid));
lf_count_adjust(p, 1);
return (cr);
}
struct ucred *
change_ruid(uid_t ruid)
{
struct proc *p = curproc;
struct ucred *cr;
KKASSERT(p != NULL);
cr = cratom_proc(p);
chgproccnt(cr->cr_ruidinfo, -1, 0);
cr->cr_ruid = ruid;
uireplace(&cr->cr_ruidinfo, uifind(ruid));
chgproccnt(cr->cr_ruidinfo, 1, 0);
return (cr);
}