xref: /csrg-svn/sys/kern/kern_prot.c (revision 37579)
123372Smckusick /*
237578Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337578Smckusick  * All rights reserved.
423372Smckusick  *
537578Smckusick  * Redistribution and use in source and binary forms are permitted
637578Smckusick  * provided that the above copyright notice and this paragraph are
737578Smckusick  * duplicated in all such forms and that any documentation,
837578Smckusick  * advertising materials, and other materials related to such
937578Smckusick  * distribution and use acknowledge that the software was developed
1037578Smckusick  * by the University of California, Berkeley.  The name of the
1137578Smckusick  * University may not be used to endorse or promote products derived
1237578Smckusick  * from this software without specific prior written permission.
1337578Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437578Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537578Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637578Smckusick  *
17*37579Smckusick  *	@(#)kern_prot.c	7.6 (Berkeley) 05/01/89
1823372Smckusick  */
197420Sroot 
207420Sroot /*
217498Sroot  * System calls related to processes and protection
227420Sroot  */
237420Sroot 
2417092Sbloom #include "param.h"
2537578Smckusick #include "acct.h"
2617092Sbloom #include "systm.h"
2717092Sbloom #include "user.h"
2817092Sbloom #include "proc.h"
2917092Sbloom #include "timeb.h"
3017092Sbloom #include "times.h"
3117092Sbloom #include "reboot.h"
3237578Smckusick #include "mount.h"
3317092Sbloom #include "buf.h"
3437578Smckusick #include "../ufs/quota.h"
3537578Smckusick #include "malloc.h"
3637578Smckusick #define GRPSTART 0
377420Sroot 
38*37579Smckusick #include "machine/reg.h"
39*37579Smckusick 
407498Sroot getpid()
417498Sroot {
427498Sroot 
437498Sroot 	u.u_r.r_val1 = u.u_procp->p_pid;
447498Sroot 	u.u_r.r_val2 = u.u_procp->p_ppid;
457498Sroot }
467498Sroot 
477498Sroot getpgrp()
487498Sroot {
497498Sroot 	register struct a {
507498Sroot 		int	pid;
517498Sroot 	} *uap = (struct a *)u.u_ap;
527498Sroot 	register struct proc *p;
537498Sroot 
547498Sroot 	if (uap->pid == 0)
55*37579Smckusick 		p = u.u_procp;
56*37579Smckusick 	else if ((p = pfind(uap->pid)) == 0) {
577498Sroot 		u.u_error = ESRCH;
587498Sroot 		return;
597498Sroot 	}
60*37579Smckusick 	u.u_r.r_val1 = p->p_pgrp->pg_id;
617498Sroot }
627498Sroot 
637420Sroot getuid()
647420Sroot {
657420Sroot 
667420Sroot 	u.u_r.r_val1 = u.u_ruid;
677420Sroot 	u.u_r.r_val2 = u.u_uid;
687420Sroot }
697420Sroot 
707498Sroot getgid()
717498Sroot {
727498Sroot 
737498Sroot 	u.u_r.r_val1 = u.u_rgid;
747498Sroot 	u.u_r.r_val2 = u.u_gid;
757498Sroot }
767498Sroot 
777866Sroot getgroups()
787498Sroot {
797498Sroot 	register struct	a {
808624Sroot 		u_int	gidsetsize;
817498Sroot 		int	*gidset;
827498Sroot 	} *uap = (struct a *)u.u_ap;
8318362Skarels 	register gid_t *gp;
8418362Skarels 	register int *lp;
8518362Skarels 	int groups[NGROUPS];
867498Sroot 
8737578Smckusick 	if (uap->gidsetsize == 0) {
8837578Smckusick 		u.u_r.r_val1 = u.u_ngroups - GRPSTART;
8937578Smckusick 		return;
9037578Smckusick 	}
9137578Smckusick 	if (uap->gidsetsize < u.u_ngroups - GRPSTART) {
927866Sroot 		u.u_error = EINVAL;
937866Sroot 		return;
947866Sroot 	}
9537578Smckusick 	uap->gidsetsize = u.u_ngroups - GRPSTART;
9637578Smckusick 	gp = &u.u_groups[GRPSTART];
9737578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
9818362Skarels 		*lp++ = *gp++;
9918362Skarels 	u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
10018362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
1019997Ssam 	if (u.u_error)
1027498Sroot 		return;
1037866Sroot 	u.u_r.r_val1 = uap->gidsetsize;
1047498Sroot }
1057498Sroot 
106*37579Smckusick setsid()
107*37579Smckusick {
108*37579Smckusick 	register struct proc *p = u.u_procp;
109*37579Smckusick 
110*37579Smckusick 	if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid))
111*37579Smckusick 		u.u_error = EPERM;
112*37579Smckusick 	else {
113*37579Smckusick 		pgmv(p, p->p_pid, 1);
114*37579Smckusick 		u.u_r.r_val1 = p->p_pid;
115*37579Smckusick 	}
116*37579Smckusick 	return;
117*37579Smckusick }
118*37579Smckusick 
119*37579Smckusick /*
120*37579Smckusick  * set process group
121*37579Smckusick  *
122*37579Smckusick  * if target pid != caller's pid
123*37579Smckusick  *	pid must be an inferior
124*37579Smckusick  *	pid must be in same session
125*37579Smckusick  *	pid can't have done an exec
126*37579Smckusick  *	there must exist a pid with pgid in same session
127*37579Smckusick  * pid must not be session leader
128*37579Smckusick  */
1297498Sroot setpgrp()
1307498Sroot {
1317498Sroot 	register struct a {
1327498Sroot 		int	pid;
133*37579Smckusick 		int	pgid;
1347498Sroot 	} *uap = (struct a *)u.u_ap;
135*37579Smckusick 	register struct proc *p;
136*37579Smckusick 	register struct pgrp *pgrp;
1377498Sroot 
1387498Sroot 	if (uap->pid == 0)
139*37579Smckusick 		p = u.u_procp;
140*37579Smckusick 	else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) {
1417498Sroot 		u.u_error = ESRCH;
1427498Sroot 		return;
1437498Sroot 	}
144*37579Smckusick 	else if (p != u.u_procp) {
145*37579Smckusick 		if (p->p_session != u.u_procp->p_session) {
146*37579Smckusick 			u.u_error = EPERM;
147*37579Smckusick 			return;
148*37579Smckusick 		}
149*37579Smckusick 		if (p->p_flag&SEXEC) {
150*37579Smckusick 			u.u_error = EACCES;
151*37579Smckusick 			return;
152*37579Smckusick 		}
153*37579Smckusick 	}
154*37579Smckusick 	if (SESS_LEADER(p)) {
1557498Sroot 		u.u_error = EPERM;
1567498Sroot 		return;
1577498Sroot 	}
158*37579Smckusick 	if (uap->pgid == 0)
159*37579Smckusick 		uap->pgid = p->p_pid;
160*37579Smckusick 	else if ((uap->pgid != p->p_pid) &&
161*37579Smckusick 		(((pgrp = pgfind(uap->pgid)) == 0) ||
162*37579Smckusick 		   pgrp->pg_mem == NULL ||
163*37579Smckusick 	           pgrp->pg_session != u.u_procp->p_session)) {
164*37579Smckusick 		u.u_error = EPERM;
165*37579Smckusick 		return;
166*37579Smckusick 	}
167*37579Smckusick 	/*
168*37579Smckusick 	 * done checking, now doit
169*37579Smckusick 	 */
170*37579Smckusick 	pgmv(p, uap->pgid, 0);
1717498Sroot }
1727498Sroot 
1739160Ssam setreuid()
1747420Sroot {
1759160Ssam 	struct a {
1769160Ssam 		int	ruid;
1779160Ssam 		int	euid;
1789160Ssam 	} *uap;
1799160Ssam 	register int ruid, euid;
1809160Ssam 
1819160Ssam 	uap = (struct a *)u.u_ap;
1829160Ssam 	ruid = uap->ruid;
1839160Ssam 	if (ruid == -1)
1849160Ssam 		ruid = u.u_ruid;
18537553Smckusick 	if (u.u_ruid != ruid && u.u_uid != ruid &&
18637553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
1879160Ssam 		return;
1889160Ssam 	euid = uap->euid;
1899160Ssam 	if (euid == -1)
1909160Ssam 		euid = u.u_uid;
19137553Smckusick 	if (u.u_ruid != euid && u.u_uid != euid &&
19237553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
1939160Ssam 		return;
1949160Ssam 	/*
1959160Ssam 	 * Everything's okay, do it.
19637578Smckusick 	 * Copy credentials so other references do not
19737578Smckusick 	 * see our changes.
1989160Ssam 	 */
1999160Ssam #ifdef QUOTA
2009320Ssam 	if (u.u_quota->q_uid != ruid) {
2019320Ssam 		qclean();
20226354Skarels 		qstart(getquota((uid_t)ruid, 0, 0));
2039320Ssam 	}
2049160Ssam #endif
20537578Smckusick 	if (u.u_cred->cr_ref > 1)
20637578Smckusick 		u.u_cred = crcopy(u.u_cred);
20725627Skarels 	u.u_procp->p_uid = euid;
2089320Ssam 	u.u_ruid = ruid;
2099160Ssam 	u.u_uid = euid;
2109160Ssam }
2119160Ssam 
2129160Ssam setregid()
2137420Sroot {
2149160Ssam 	register struct a {
2159160Ssam 		int	rgid;
2169160Ssam 		int	egid;
2179160Ssam 	} *uap;
2189160Ssam 	register int rgid, egid;
2199160Ssam 
2209160Ssam 	uap = (struct a *)u.u_ap;
2219160Ssam 	rgid = uap->rgid;
2229160Ssam 	if (rgid == -1)
2239160Ssam 		rgid = u.u_rgid;
22437553Smckusick 	if (u.u_rgid != rgid && u.u_gid != rgid &&
22537553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
2269160Ssam 		return;
2279160Ssam 	egid = uap->egid;
2289160Ssam 	if (egid == -1)
2299160Ssam 		egid = u.u_gid;
23037553Smckusick 	if (u.u_rgid != egid && u.u_gid != egid &&
23137553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
2329160Ssam 		return;
23337578Smckusick 	if (u.u_cred->cr_ref > 1)
23437578Smckusick 		u.u_cred = crcopy(u.u_cred);
23537578Smckusick 	u.u_rgid = rgid;
23611164Ssam 	u.u_gid = egid;
2379160Ssam }
2389160Ssam 
2397866Sroot setgroups()
2407498Sroot {
2417498Sroot 	register struct	a {
2428624Sroot 		u_int	gidsetsize;
2437498Sroot 		int	*gidset;
2447498Sroot 	} *uap = (struct a *)u.u_ap;
24518362Skarels 	register gid_t *gp;
24618362Skarels 	register int *lp;
24737578Smckusick 	int ngrp, groups[NGROUPS];
2487498Sroot 
24937553Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
2507498Sroot 		return;
25137578Smckusick 	ngrp = uap->gidsetsize + GRPSTART;
25237578Smckusick 	if (ngrp > sizeof (u.u_groups) / sizeof (u.u_groups[0])) {
2537866Sroot 		u.u_error = EINVAL;
2547498Sroot 		return;
2557498Sroot 	}
25618362Skarels 	u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
25718362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
2589997Ssam 	if (u.u_error)
2597498Sroot 		return;
26037578Smckusick 	gp = &u.u_groups[GRPSTART];
26137578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
26218362Skarels 		*gp++ = *lp++;
26337578Smckusick 	u.u_ngroups = ngrp;
2647498Sroot }
2657498Sroot 
2667498Sroot /*
26737578Smckusick  * Check if gid is a member of the group set.
26811810Ssam  */
26937578Smckusick groupmember(gid, cred)
27026275Skarels 	gid_t gid;
27137578Smckusick 	register struct ucred *cred;
2727866Sroot {
27318362Skarels 	register gid_t *gp;
27437578Smckusick 	gid_t *egp;
2757866Sroot 
27637578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
27737578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
2787866Sroot 		if (*gp == gid)
27937578Smckusick 			return (1);
28037578Smckusick 	return (0);
2817866Sroot }
2827866Sroot 
28311810Ssam /*
28437578Smckusick  * Test if the current user is the super user.
28511810Ssam  */
28637578Smckusick suser(cred, acflag)
28737578Smckusick 	struct ucred *cred;
28837578Smckusick 	short *acflag;
2897866Sroot {
2907866Sroot 
29137578Smckusick 	if (cred->cr_uid == 0) {
29237578Smckusick 		if (acflag)
29337578Smckusick 			*acflag |= ASU;
29437578Smckusick 		return (0);
29518362Skarels 	}
29637578Smckusick 	return (EPERM);
2977866Sroot }
29811810Ssam 
29911810Ssam /*
30037578Smckusick  * Allocate a zeroed cred structure.
30111810Ssam  */
30237578Smckusick struct ucred *
30337578Smckusick crget()
30411810Ssam {
30537578Smckusick 	register struct ucred *cr;
30611810Ssam 
30737578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
30837578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
30937578Smckusick 	cr->cr_ref = 1;
31037578Smckusick 	return(cr);
31111810Ssam }
31237085Skfall 
31337085Skfall /*
31437578Smckusick  * Free a cred structure.
31537578Smckusick  * Throws away space when ref count gets to 0.
31637085Skfall  */
31737578Smckusick crfree(cr)
31837578Smckusick 	struct ucred *cr;
31937578Smckusick {
32037578Smckusick 	int	s = splimp();
32137085Skfall 
32237578Smckusick 	if (--cr->cr_ref != 0) {
32337578Smckusick 		(void) splx(s);
32437578Smckusick 		return;
32537578Smckusick 	}
32637578Smckusick 	FREE((caddr_t)cr, M_CRED);
32737578Smckusick 	(void) splx(s);
32837578Smckusick }
32937578Smckusick 
33037578Smckusick /*
33137578Smckusick  * Copy cred structure to a new one and free the old one.
33237578Smckusick  */
33337578Smckusick struct ucred *
33437578Smckusick crcopy(cr)
33537578Smckusick 	struct ucred *cr;
33637085Skfall {
33737578Smckusick 	struct ucred *newcr;
33837085Skfall 
33937578Smckusick 	newcr = crget();
34037578Smckusick 	*newcr = *cr;
34137578Smckusick 	crfree(cr);
34237578Smckusick 	newcr->cr_ref = 1;
34337578Smckusick 	return(newcr);
34437085Skfall }
34537085Skfall 
34637085Skfall /*
34737578Smckusick  * Dup cred struct to a new held one.
34837085Skfall  */
34937578Smckusick struct ucred *
35037578Smckusick crdup(cr)
35137578Smckusick 	struct ucred *cr;
35237085Skfall {
35337578Smckusick 	struct ucred *newcr;
35437085Skfall 
35537578Smckusick 	newcr = crget();
35637578Smckusick 	*newcr = *cr;
35737578Smckusick 	newcr->cr_ref = 1;
35837578Smckusick 	return(newcr);
35937085Skfall }
360*37579Smckusick 
361*37579Smckusick /*
362*37579Smckusick  * Get login name of process owner, if available
363*37579Smckusick  */
364*37579Smckusick 
365*37579Smckusick getlogname()
366*37579Smckusick {
367*37579Smckusick 	struct a {
368*37579Smckusick 		char	*namebuf;
369*37579Smckusick 		u_int	namelen;
370*37579Smckusick 	} *uap = (struct a *)u.u_ap;
371*37579Smckusick 
372*37579Smckusick 	if (uap->namelen > sizeof (u.u_logname))
373*37579Smckusick 		uap->namelen = sizeof (u.u_logname);
374*37579Smckusick 	u.u_error = copyout((caddr_t)u.u_logname, (caddr_t)uap->namebuf,
375*37579Smckusick 		uap->namelen);
376*37579Smckusick }
377*37579Smckusick 
378*37579Smckusick /*
379*37579Smckusick  * Set login name of process owner
380*37579Smckusick  */
381*37579Smckusick 
382*37579Smckusick setlogname()
383*37579Smckusick {
384*37579Smckusick 	struct a {
385*37579Smckusick 		char	*namebuf;
386*37579Smckusick 		u_int	namelen;
387*37579Smckusick 	} *uap = (struct a *)u.u_ap;
388*37579Smckusick 
389*37579Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
390*37579Smckusick 		return;
391*37579Smckusick 	if (uap->namelen > sizeof (u.u_logname) - 1)
392*37579Smckusick 		u.u_error = EINVAL;
393*37579Smckusick 	else
394*37579Smckusick 		u.u_error = copyin((caddr_t)uap->namebuf,
395*37579Smckusick 			(caddr_t)u.u_logname, uap->namelen);
396*37579Smckusick }
397