#include <sys/param.h>
#include <sys/acct.h>
#include <sys/systm.h>
#include <sys/ucred.h>
#include <sys/proc.h>
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/malloc.h>
#include <bsm/audit_kernel.h>
#include <sys/mount.h>
#include <mach/message.h>
#include <mach/host_security.h>
#include <kern/host.h>
struct setprivexec_args {
int flag;
};
int
setprivexec(p, uap, retval)
struct proc *p;
register struct setprivexec_args *uap;
register_t *retval;
{
AUDIT_ARG(value, uap->flag);
*retval = p->p_debugger;
p->p_debugger = (uap->flag != 0);
return(0);
}
getpid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pid;
#if COMPAT_43
retval[1] = p->p_pptr->p_pid;
#endif
return (0);
}
getppid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pptr->p_pid;
return (0);
}
getpgrp(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pgrp->pg_id;
return (0);
}
struct getpgid_args {
pid_t pid;
};
int
getpgid(p, uap, retval)
struct proc *p;
struct getpgid_args *uap;
register_t *retval;
{
struct proc *pt;
pt = p;
if (uap->pid == 0)
goto found;
if ((pt = pfind(uap->pid)) == 0)
return (ESRCH);
found:
*retval = pt->p_pgrp->pg_id;
return (0);
}
struct getsid_args {
pid_t pid;
};
int
getsid(p, uap, retval)
struct proc *p;
struct getsid_args *uap;
register_t *retval;
{
struct proc *pt;
pt = p;
if (uap->pid == 0)
goto found;
if ((pt = pfind(uap->pid)) == 0)
return (ESRCH);
found:
*retval = pt->p_session->s_sid;
return (0);
}
getuid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_cred->p_ruid;
#if COMPAT_43
retval[1] = p->p_ucred->cr_uid;
#endif
return (0);
}
geteuid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_ucred->cr_uid;
return (0);
}
getgid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_cred->p_rgid;
#if COMPAT_43
retval[1] = p->p_ucred->cr_groups[0];
#endif
return (0);
}
getegid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_ucred->cr_groups[0];
return (0);
}
struct getgroups_args {
u_int gidsetsize;
gid_t *gidset;
};
getgroups(p, uap, retval)
struct proc *p;
register struct getgroups_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register u_int ngrp;
int error;
if ((ngrp = uap->gidsetsize) == 0) {
*retval = pc->pc_ucred->cr_ngroups;
return (0);
}
if (ngrp < pc->pc_ucred->cr_ngroups)
return (EINVAL);
pcred_readlock(p);
ngrp = pc->pc_ucred->cr_ngroups;
if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
(caddr_t)uap->gidset, ngrp * sizeof(gid_t))) {
pcred_unlock(p);
return (error);
}
pcred_unlock(p);
*retval = ngrp;
return (0);
}
setsid(p, uap, retval)
register struct proc *p;
void *uap;
register_t *retval;
{
if (p->p_pgid == p->p_pid || pgfind(p->p_pid) || p->p_flag & P_INVFORK) {
return (EPERM);
} else {
(void)enterpgrp(p, p->p_pid, 1);
*retval = p->p_pid;
return (0);
}
}
struct setpgid_args {
int pid;
int pgid;
};
setpgid(curp, uap, retval)
struct proc *curp;
register struct setpgid_args *uap;
register_t *retval;
{
register struct proc *targp;
register struct pgrp *pgrp;
if (uap->pid != 0 && uap->pid != curp->p_pid) {
if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
return (ESRCH);
if (targp->p_session != curp->p_session)
return (EPERM);
if (targp->p_flag & P_EXEC)
return (EACCES);
} else
targp = curp;
if (SESS_LEADER(targp))
return (EPERM);
if (uap->pgid == 0)
uap->pgid = targp->p_pid;
else if (uap->pgid != targp->p_pid)
if ((pgrp = pgfind(uap->pgid)) == 0 ||
pgrp->pg_session != curp->p_session)
return (EPERM);
return (enterpgrp(targp, uap->pgid, 0));
}
struct issetugid_args {
int dummy;
};
issetugid(p, uap, retval)
struct proc *p;
struct issetugid_args *uap;
register_t *retval;
{
*retval = (p->p_flag & P_SUGID) ? 1 : 0;
return (0);
}
struct setuid_args {
uid_t uid;
};
setuid(p, uap, retval)
struct proc *p;
struct setuid_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register uid_t uid;
int error;
uid = uap->uid;
AUDIT_ARG(uid, uid, 0, 0, 0);
if (uid != pc->p_ruid &&
(error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
prepare_profile_database(uap->uid);
pcred_writelock(p);
(void)chgproccnt(pc->p_ruid, -1);
(void)chgproccnt(uid, 1);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_uid = uid;
pc->p_ruid = uid;
pc->p_svuid = uid;
pcred_unlock(p);
set_security_token(p);
p->p_flag |= P_SUGID;
return (0);
}
struct seteuid_args {
uid_t euid;
};
seteuid(p, uap, retval)
struct proc *p;
struct seteuid_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register uid_t euid;
int error;
euid = uap->euid;
AUDIT_ARG(uid, 0, euid, 0, 0);
if (euid != pc->p_ruid && euid != pc->p_svuid &&
(error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
pcred_writelock(p);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_uid = euid;
pcred_unlock(p);
set_security_token(p);
p->p_flag |= P_SUGID;
return (0);
}
struct setgid_args {
gid_t gid;
};
setgid(p, uap, retval)
struct proc *p;
struct setgid_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register gid_t gid;
int error;
gid = uap->gid;
AUDIT_ARG(gid, gid, 0, 0, 0);
if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
pcred_writelock(p);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_groups[0] = gid;
pc->p_rgid = gid;
pc->p_svgid = gid;
pcred_unlock(p);
set_security_token(p);
p->p_flag |= P_SUGID;
return (0);
}
struct setegid_args {
gid_t egid;
};
setegid(p, uap, retval)
struct proc *p;
struct setegid_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register gid_t egid;
int error;
egid = uap->egid;
AUDIT_ARG(gid, 0, egid, 0, 0);
if (egid != pc->p_rgid && egid != pc->p_svgid &&
(error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
pcred_writelock(p);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_groups[0] = egid;
pcred_unlock(p);
set_security_token(p);
p->p_flag |= P_SUGID;
return (0);
}
struct setgroups_args{
u_int gidsetsize;
gid_t *gidset;
};
setgroups(p, uap, retval)
struct proc *p;
struct setgroups_args *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
struct ucred *new, *old;
register u_int ngrp;
int error;
if (error = suser(pc->pc_ucred, &p->p_acflag))
return (error);
ngrp = uap->gidsetsize;
if (ngrp > NGROUPS)
return (EINVAL);
new = crget();
if ( ngrp < 1 ) {
ngrp = 1;
}
else {
error = copyin((caddr_t)uap->gidset,
(caddr_t)new->cr_groups, ngrp * sizeof(gid_t));
if (error) {
crfree(new);
return (error);
}
}
new->cr_ngroups = ngrp;
AUDIT_ARG(groupset, new->cr_groups, ngrp);
pcred_writelock(p);
old = pc->pc_ucred;
new->cr_uid = old->cr_uid;
pc->pc_ucred = new;
pcred_unlock(p);
set_security_token(p);
p->p_flag |= P_SUGID;
if (old != NOCRED)
crfree(old);
return (0);
}
#if COMPAT_43
struct osetreuid_args{
int ruid;
int euid;
};
osetreuid(p, uap, retval)
register struct proc *p;
struct osetreuid_args *uap;
register_t *retval;
{
struct seteuid_args seuidargs;
struct setuid_args suidargs;
if (uap->ruid == (uid_t)-1) {
if (uap->euid == (uid_t)-1)
return (0);
seuidargs.euid = uap->euid;
return (seteuid(p, &seuidargs, retval));
}
if (uap->euid == (uid_t)-1) {
seuidargs.euid = uap->ruid;
return (seteuid(p, &seuidargs, retval));
}
suidargs.uid = uap->ruid;
return (setuid(p, &suidargs, retval));
}
struct osetregid_args {
int rgid;
int egid;
};
osetregid(p, uap, retval)
register struct proc *p;
struct osetregid_args *uap;
register_t *retval;
{
struct setegid_args segidargs;
struct setgid_args sgidargs;
if (uap->rgid == (gid_t)-1) {
if (uap->egid == (gid_t)-1)
return (0);
segidargs.egid = uap->egid;
return (setegid(p, &segidargs, retval));
}
if (uap->egid == (gid_t)-1) {
segidargs.egid = uap->rgid;
return (setegid(p, &segidargs, retval));
}
sgidargs.gid = uap->rgid;
return (setgid(p, &sgidargs, retval));
}
#endif
groupmember(gid, cred)
gid_t gid;
register struct ucred *cred;
{
register 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);
}
suser(cred, acflag)
struct ucred *cred;
u_short *acflag;
{
#if DIAGNOSTIC
if (cred == NOCRED || cred == FSCRED)
panic("suser");
#endif
if (cred->cr_uid == 0) {
if (acflag)
*acflag |= ASU;
return (0);
}
return (EPERM);
}
int
is_suser(void)
{
struct proc *p = current_proc();
if (!p)
return (0);
return (suser(p->p_ucred, &p->p_acflag) == 0);
}
int
is_suser1(void)
{
struct proc *p = current_proc();
if (!p)
return (0);
return (suser(p->p_ucred, &p->p_acflag) == 0 ||
p->p_cred->p_ruid == 0 || p->p_cred->p_svuid == 0);
}
struct ucred *
crget()
{
register struct ucred *cr;
MALLOC_ZONE(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
bzero((caddr_t)cr, sizeof(*cr));
cr->cr_ref = 1;
return (cr);
}
void
crfree(cr)
struct ucred *cr;
{
#if DIAGNOSTIC
if (cr == NOCRED || cr == FSCRED)
panic("crfree");
#endif
if (--cr->cr_ref == 0)
FREE_ZONE((caddr_t)cr, sizeof *cr, M_CRED);
}
struct ucred *
crcopy(cr)
struct ucred *cr;
{
struct ucred *newcr;
#if DIAGNOSTIC
if (cr == NOCRED || cr == FSCRED)
panic("crcopy");
#endif
if (cr->cr_ref == 1)
return (cr);
newcr = crget();
*newcr = *cr;
crfree(cr);
newcr->cr_ref = 1;
return (newcr);
}
struct ucred *
crdup(cr)
struct ucred *cr;
{
struct ucred *newcr;
#if DIAGNOSTIC
if (cr == NOCRED || cr == FSCRED)
panic("crdup");
#endif
newcr = crget();
*newcr = *cr;
newcr->cr_ref = 1;
return (newcr);
}
int
crcmp(cr1, cr2)
struct ucred *cr1;
struct ucred *cr2;
{
int i;
if (cr1 == cr2)
return 0;
if (cr1 == NOCRED || cr1 == FSCRED ||
cr2 == NOCRED || cr2 == FSCRED)
return 1;
if (cr1->cr_uid != cr2->cr_uid)
return 1;
if (cr1->cr_ngroups != cr2->cr_ngroups)
return 1;
for (i=0; i < cr1->cr_ngroups; i++)
if (cr1->cr_groups[i] != cr2->cr_groups[i])
return 1;
return (0);
}
struct getlogin_args {
char *namebuf;
u_int namelen;
};
getlogin(p, uap, retval)
struct proc *p;
struct getlogin_args *uap;
register_t *retval;
{
if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
(caddr_t)uap->namebuf, uap->namelen));
}
struct setlogin_args {
char *namebuf;
};
setlogin(p, uap, retval)
struct proc *p;
struct setlogin_args *uap;
register_t *retval;
{
int error;
int dummy=0;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
error = copyinstr((caddr_t) uap->namebuf,
(caddr_t) p->p_pgrp->pg_session->s_login,
sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
if(!error)
AUDIT_ARG(text, p->p_pgrp->pg_session->s_login);
else if (error == ENAMETOOLONG)
error = EINVAL;
return (error);
}
kern_return_t
set_security_token(struct proc * p)
{
security_token_t sec_token;
audit_token_t audit_token;
sec_token.val[0] = p->p_ucred->cr_uid;
sec_token.val[1] = p->p_ucred->cr_gid;
audit_token.val[0] = p->p_au->ai_auid;
audit_token.val[1] = p->p_ucred->cr_uid;
audit_token.val[2] = p->p_ucred->cr_gid;
audit_token.val[3] = p->p_cred->p_ruid;
audit_token.val[4] = p->p_cred->p_rgid;
audit_token.val[5] = p->p_pid;
audit_token.val[6] = p->p_au->ai_asid;
audit_token.val[7] = p->p_au->ai_termid.port;
return host_security_set_task_token(host_security_self(),
p->task,
sec_token,
audit_token,
(sec_token.val[0]) ?
HOST_PRIV_NULL :
host_priv_self());
}
__private_extern__
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(xcr->cr_groups));
}