xref: /csrg-svn/sys/kern/kern_prot.c (revision 40667)
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*40667Skarels  *	@(#)kern_prot.c	7.8 (Berkeley) 03/31/90
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"
367420Sroot 
3737579Smckusick #include "machine/reg.h"
3837579Smckusick 
397498Sroot getpid()
407498Sroot {
417498Sroot 
427498Sroot 	u.u_r.r_val1 = u.u_procp->p_pid;
437498Sroot 	u.u_r.r_val2 = u.u_procp->p_ppid;
447498Sroot }
457498Sroot 
467498Sroot getpgrp()
477498Sroot {
487498Sroot 	register struct a {
497498Sroot 		int	pid;
507498Sroot 	} *uap = (struct a *)u.u_ap;
517498Sroot 	register struct proc *p;
527498Sroot 
537498Sroot 	if (uap->pid == 0)
5437579Smckusick 		p = u.u_procp;
5537579Smckusick 	else if ((p = pfind(uap->pid)) == 0) {
567498Sroot 		u.u_error = ESRCH;
577498Sroot 		return;
587498Sroot 	}
5937579Smckusick 	u.u_r.r_val1 = p->p_pgrp->pg_id;
607498Sroot }
617498Sroot 
627420Sroot getuid()
637420Sroot {
647420Sroot 
65*40667Skarels 	u.u_r.r_val1 = u.u_procp->p_ruid;
66*40667Skarels 	u.u_r.r_val2 = u.u_cred->cr_uid;
677420Sroot }
687420Sroot 
697498Sroot getgid()
707498Sroot {
717498Sroot 
72*40667Skarels 	u.u_r.r_val1 = u.u_procp->p_rgid;
73*40667Skarels 	u.u_r.r_val2 = u.u_cred->cr_groups[0];
747498Sroot }
757498Sroot 
767866Sroot getgroups()
777498Sroot {
787498Sroot 	register struct	a {
798624Sroot 		u_int	gidsetsize;
807498Sroot 		int	*gidset;
817498Sroot 	} *uap = (struct a *)u.u_ap;
8218362Skarels 	register gid_t *gp;
8318362Skarels 	register int *lp;
8418362Skarels 	int groups[NGROUPS];
857498Sroot 
8637578Smckusick 	if (uap->gidsetsize == 0) {
87*40667Skarels 		u.u_r.r_val1 = u.u_cred->cr_ngroups;
8837578Smckusick 		return;
8937578Smckusick 	}
90*40667Skarels 	if (uap->gidsetsize < u.u_cred->cr_ngroups) {
917866Sroot 		u.u_error = EINVAL;
927866Sroot 		return;
937866Sroot 	}
94*40667Skarels 	uap->gidsetsize = u.u_cred->cr_ngroups;
95*40667Skarels 	gp = u.u_cred->cr_groups;
9637578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
9718362Skarels 		*lp++ = *gp++;
9818362Skarels 	u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
9918362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
1009997Ssam 	if (u.u_error)
1017498Sroot 		return;
1027866Sroot 	u.u_r.r_val1 = uap->gidsetsize;
1037498Sroot }
1047498Sroot 
10537579Smckusick setsid()
10637579Smckusick {
10737579Smckusick 	register struct proc *p = u.u_procp;
10837579Smckusick 
10937579Smckusick 	if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid))
11037579Smckusick 		u.u_error = EPERM;
11137579Smckusick 	else {
11237579Smckusick 		pgmv(p, p->p_pid, 1);
11337579Smckusick 		u.u_r.r_val1 = p->p_pid;
11437579Smckusick 	}
11537579Smckusick 	return;
11637579Smckusick }
11737579Smckusick 
11837579Smckusick /*
11937579Smckusick  * set process group
12037579Smckusick  *
121*40667Skarels  * caller does setpgrp(pid, pgid)
122*40667Skarels  *
123*40667Skarels  * pid must be caller or child of caller (ESRCH)
124*40667Skarels  * if a child
125*40667Skarels  *	pid must be in same session (EPERM)
126*40667Skarels  *	pid can't have done an exec (EACCES)
127*40667Skarels  * if pgid != pid
128*40667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
129*40667Skarels  * pid must not be session leader (EPERM)
13037579Smckusick  */
1317498Sroot setpgrp()
1327498Sroot {
1337498Sroot 	register struct a {
1347498Sroot 		int	pid;
13537579Smckusick 		int	pgid;
1367498Sroot 	} *uap = (struct a *)u.u_ap;
13737579Smckusick 	register struct proc *p;
13837579Smckusick 	register struct pgrp *pgrp;
1397498Sroot 
1407498Sroot 	if (uap->pid == 0)
14137579Smckusick 		p = u.u_procp;
14237579Smckusick 	else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) {
1437498Sroot 		u.u_error = ESRCH;
1447498Sroot 		return;
1457498Sroot 	}
14637579Smckusick 	else if (p != u.u_procp) {
14737579Smckusick 		if (p->p_session != u.u_procp->p_session) {
14837579Smckusick 			u.u_error = EPERM;
14937579Smckusick 			return;
15037579Smckusick 		}
15137579Smckusick 		if (p->p_flag&SEXEC) {
15237579Smckusick 			u.u_error = EACCES;
15337579Smckusick 			return;
15437579Smckusick 		}
15537579Smckusick 	}
15637579Smckusick 	if (SESS_LEADER(p)) {
1577498Sroot 		u.u_error = EPERM;
1587498Sroot 		return;
1597498Sroot 	}
16037579Smckusick 	if (uap->pgid == 0)
16137579Smckusick 		uap->pgid = p->p_pid;
16237579Smckusick 	else if ((uap->pgid != p->p_pid) &&
16337579Smckusick 		(((pgrp = pgfind(uap->pgid)) == 0) ||
16437579Smckusick 		   pgrp->pg_mem == NULL ||
16537579Smckusick 	           pgrp->pg_session != u.u_procp->p_session)) {
16637579Smckusick 		u.u_error = EPERM;
16737579Smckusick 		return;
16837579Smckusick 	}
16937579Smckusick 	/*
17037579Smckusick 	 * done checking, now doit
17137579Smckusick 	 */
17237579Smckusick 	pgmv(p, uap->pgid, 0);
1737498Sroot }
1747498Sroot 
1759160Ssam setreuid()
1767420Sroot {
1779160Ssam 	struct a {
1789160Ssam 		int	ruid;
1799160Ssam 		int	euid;
1809160Ssam 	} *uap;
181*40667Skarels 	register struct proc *p = u.u_procp;
1829160Ssam 	register int ruid, euid;
1839160Ssam 
1849160Ssam 	uap = (struct a *)u.u_ap;
1859160Ssam 	ruid = uap->ruid;
1869160Ssam 	if (ruid == -1)
187*40667Skarels 		ruid = p->p_ruid;
188*40667Skarels #ifdef COMPAT_43
189*40667Skarels 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
19037553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
191*40667Skarels #else
192*40667Skarels 	if (ruid != p->p_ruid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
193*40667Skarels #endif
1949160Ssam 		return;
1959160Ssam 	euid = uap->euid;
1969160Ssam 	if (euid == -1)
197*40667Skarels 		euid = u.u_cred->cr_uid;
198*40667Skarels 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
199*40667Skarels 	    euid != p->p_svuid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
2009160Ssam 		return;
2019160Ssam 	/*
2029160Ssam 	 * Everything's okay, do it.
20337578Smckusick 	 * Copy credentials so other references do not
20437578Smckusick 	 * see our changes.
2059160Ssam 	 */
2069160Ssam #ifdef QUOTA
2079320Ssam 	if (u.u_quota->q_uid != ruid) {
2089320Ssam 		qclean();
20926354Skarels 		qstart(getquota((uid_t)ruid, 0, 0));
2109320Ssam 	}
2119160Ssam #endif
21237578Smckusick 	if (u.u_cred->cr_ref > 1)
21337578Smckusick 		u.u_cred = crcopy(u.u_cred);
214*40667Skarels 	u.u_cred->cr_uid = euid;
215*40667Skarels 	p->p_uid = euid;
216*40667Skarels 	p->p_ruid = ruid;
2179160Ssam }
2189160Ssam 
2199160Ssam setregid()
2207420Sroot {
2219160Ssam 	register struct a {
2229160Ssam 		int	rgid;
2239160Ssam 		int	egid;
2249160Ssam 	} *uap;
2259160Ssam 	register int rgid, egid;
226*40667Skarels 	register struct proc *p = u.u_procp;
2279160Ssam 
2289160Ssam 	uap = (struct a *)u.u_ap;
2299160Ssam 	rgid = uap->rgid;
2309160Ssam 	if (rgid == -1)
231*40667Skarels 		rgid = p->p_rgid;
232*40667Skarels #ifdef COMPAT_43_XXX
233*40667Skarels 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
23437553Smckusick 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
235*40667Skarels #else
236*40667Skarels 	if (rgid != p->p_rgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
237*40667Skarels #endif
2389160Ssam 		return;
2399160Ssam 	egid = uap->egid;
2409160Ssam 	if (egid == -1)
241*40667Skarels 		egid = u.u_cred->cr_groups[0];
242*40667Skarels 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
243*40667Skarels 	    egid != p->p_svgid && (u.u_error = suser(u.u_cred, &u.u_acflag)))
2449160Ssam 		return;
24537578Smckusick 	if (u.u_cred->cr_ref > 1)
24637578Smckusick 		u.u_cred = crcopy(u.u_cred);
247*40667Skarels 	p->p_rgid = rgid;
248*40667Skarels 	u.u_cred->cr_groups[0] = egid;
2499160Ssam }
2509160Ssam 
2517866Sroot setgroups()
2527498Sroot {
2537498Sroot 	register struct	a {
2548624Sroot 		u_int	gidsetsize;
2557498Sroot 		int	*gidset;
2567498Sroot 	} *uap = (struct a *)u.u_ap;
25718362Skarels 	register gid_t *gp;
25818362Skarels 	register int *lp;
25937578Smckusick 	int ngrp, groups[NGROUPS];
2607498Sroot 
26137553Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
2627498Sroot 		return;
263*40667Skarels 	ngrp = uap->gidsetsize;
264*40667Skarels 	if (ngrp > NGROUPS) {
2657866Sroot 		u.u_error = EINVAL;
2667498Sroot 		return;
2677498Sroot 	}
26818362Skarels 	u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
26918362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
2709997Ssam 	if (u.u_error)
2717498Sroot 		return;
272*40667Skarels 	gp = u.u_cred->cr_groups;
27337578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
27418362Skarels 		*gp++ = *lp++;
275*40667Skarels 	u.u_cred->cr_ngroups = ngrp;
2767498Sroot }
2777498Sroot 
2787498Sroot /*
27937578Smckusick  * Check if gid is a member of the group set.
28011810Ssam  */
28137578Smckusick groupmember(gid, cred)
28226275Skarels 	gid_t gid;
28337578Smckusick 	register struct ucred *cred;
2847866Sroot {
28518362Skarels 	register gid_t *gp;
28637578Smckusick 	gid_t *egp;
2877866Sroot 
28837578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
28937578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
2907866Sroot 		if (*gp == gid)
29137578Smckusick 			return (1);
29237578Smckusick 	return (0);
2937866Sroot }
2947866Sroot 
29511810Ssam /*
29637578Smckusick  * Test if the current user is the super user.
29711810Ssam  */
29837578Smckusick suser(cred, acflag)
29937578Smckusick 	struct ucred *cred;
30037578Smckusick 	short *acflag;
3017866Sroot {
3027866Sroot 
30337578Smckusick 	if (cred->cr_uid == 0) {
30437578Smckusick 		if (acflag)
30537578Smckusick 			*acflag |= ASU;
30637578Smckusick 		return (0);
30718362Skarels 	}
30837578Smckusick 	return (EPERM);
3097866Sroot }
31011810Ssam 
31111810Ssam /*
31237578Smckusick  * Allocate a zeroed cred structure.
31311810Ssam  */
31437578Smckusick struct ucred *
31537578Smckusick crget()
31611810Ssam {
31737578Smckusick 	register struct ucred *cr;
31811810Ssam 
31937578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
32037578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
32137578Smckusick 	cr->cr_ref = 1;
32237578Smckusick 	return(cr);
32311810Ssam }
32437085Skfall 
32537085Skfall /*
32637578Smckusick  * Free a cred structure.
32737578Smckusick  * Throws away space when ref count gets to 0.
32837085Skfall  */
32937578Smckusick crfree(cr)
33037578Smckusick 	struct ucred *cr;
33137578Smckusick {
33237578Smckusick 	int	s = splimp();
33337085Skfall 
33437578Smckusick 	if (--cr->cr_ref != 0) {
33537578Smckusick 		(void) splx(s);
33637578Smckusick 		return;
33737578Smckusick 	}
33837578Smckusick 	FREE((caddr_t)cr, M_CRED);
33937578Smckusick 	(void) splx(s);
34037578Smckusick }
34137578Smckusick 
34237578Smckusick /*
34337578Smckusick  * Copy cred structure to a new one and free the old one.
34437578Smckusick  */
34537578Smckusick struct ucred *
34637578Smckusick crcopy(cr)
34737578Smckusick 	struct ucred *cr;
34837085Skfall {
34937578Smckusick 	struct ucred *newcr;
35037085Skfall 
35137578Smckusick 	newcr = crget();
35237578Smckusick 	*newcr = *cr;
35337578Smckusick 	crfree(cr);
35437578Smckusick 	newcr->cr_ref = 1;
35537578Smckusick 	return(newcr);
35637085Skfall }
35737085Skfall 
35837085Skfall /*
35937578Smckusick  * Dup cred struct to a new held one.
36037085Skfall  */
36137578Smckusick struct ucred *
36237578Smckusick crdup(cr)
36337578Smckusick 	struct ucred *cr;
36437085Skfall {
36537578Smckusick 	struct ucred *newcr;
36637085Skfall 
36737578Smckusick 	newcr = crget();
36837578Smckusick 	*newcr = *cr;
36937578Smckusick 	newcr->cr_ref = 1;
37037578Smckusick 	return(newcr);
37137085Skfall }
37237579Smckusick 
37337579Smckusick /*
374*40667Skarels  * Get login name, if available.
37537579Smckusick  */
376*40667Skarels getlogin()
37737579Smckusick {
37837579Smckusick 	struct a {
37937579Smckusick 		char	*namebuf;
38037579Smckusick 		u_int	namelen;
38137579Smckusick 	} *uap = (struct a *)u.u_ap;
38237579Smckusick 
383*40667Skarels 	if (uap->namelen > sizeof (u.u_procp->p_logname))
384*40667Skarels 		uap->namelen = sizeof (u.u_procp->p_logname);
385*40667Skarels 	u.u_error = copyout((caddr_t)u.u_procp->p_logname,
386*40667Skarels 			     (caddr_t)uap->namebuf, uap->namelen);
38737579Smckusick }
38837579Smckusick 
38937579Smckusick /*
390*40667Skarels  * Set login name.
39137579Smckusick  */
392*40667Skarels setlogin()
39337579Smckusick {
39437579Smckusick 	struct a {
39537579Smckusick 		char	*namebuf;
39637579Smckusick 	} *uap = (struct a *)u.u_ap;
397*40667Skarels 	int error;
39837579Smckusick 
39937579Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
40037579Smckusick 		return;
401*40667Skarels 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)u.u_procp->p_logname,
402*40667Skarels 	    sizeof (u.u_procp->p_logname) - 1, (int *) 0);
403*40667Skarels 	if (error == ENOENT)		/* name too long */
404*40667Skarels 		error = EINVAL;
405*40667Skarels 	u.u_error = error;
40637579Smckusick }
407