xref: /freebsd/sys/kern/kern_prot.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
39  * $FreeBSD$
40  */
41 
42 /*
43  * System calls related to processes and protection
44  */
45 
46 #include "opt_compat.h"
47 
48 #include <sys/param.h>
49 #include <sys/acct.h>
50 #include <sys/systm.h>
51 #include <sys/sysproto.h>
52 #include <sys/kernel.h>
53 #include <sys/proc.h>
54 #include <sys/malloc.h>
55 #include <sys/pioctl.h>
56 #include <sys/sysctl.h>
57 
58 static MALLOC_DEFINE(M_CRED, "cred", "credentials");
59 
60 #ifndef _SYS_SYSPROTO_H_
61 struct getpid_args {
62 	int	dummy;
63 };
64 #endif
65 
66 /*
67  * NOT MP SAFE due to p_pptr access
68  */
69 /* ARGSUSED */
70 int
71 getpid(p, uap)
72 	struct proc *p;
73 	struct getpid_args *uap;
74 {
75 
76 	p->p_retval[0] = p->p_pid;
77 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
78 	p->p_retval[1] = p->p_pptr->p_pid;
79 #endif
80 	return (0);
81 }
82 
83 #ifndef _SYS_SYSPROTO_H_
84 struct getppid_args {
85         int     dummy;
86 };
87 #endif
88 /* ARGSUSED */
89 int
90 getppid(p, uap)
91 	struct proc *p;
92 	struct getppid_args *uap;
93 {
94 
95 	p->p_retval[0] = p->p_pptr->p_pid;
96 	return (0);
97 }
98 
99 /*
100  * Get process group ID; note that POSIX getpgrp takes no parameter
101  *
102  * MP SAFE
103  */
104 #ifndef _SYS_SYSPROTO_H_
105 struct getpgrp_args {
106         int     dummy;
107 };
108 #endif
109 
110 int
111 getpgrp(p, uap)
112 	struct proc *p;
113 	struct getpgrp_args *uap;
114 {
115 
116 	p->p_retval[0] = p->p_pgrp->pg_id;
117 	return (0);
118 }
119 
120 /* Get an arbitary pid's process group id */
121 #ifndef _SYS_SYSPROTO_H_
122 struct getpgid_args {
123 	pid_t	pid;
124 };
125 #endif
126 
127 int
128 getpgid(p, uap)
129 	struct proc *p;
130 	struct getpgid_args *uap;
131 {
132 	struct proc *pt;
133 
134 	pt = p;
135 	if (uap->pid == 0)
136 		goto found;
137 
138 	if ((pt = pfind(uap->pid)) == 0)
139 		return ESRCH;
140 found:
141 	p->p_retval[0] = pt->p_pgrp->pg_id;
142 	return 0;
143 }
144 
145 /*
146  * Get an arbitary pid's session id.
147  */
148 #ifndef _SYS_SYSPROTO_H_
149 struct getsid_args {
150 	pid_t	pid;
151 };
152 #endif
153 
154 int
155 getsid(p, uap)
156 	struct proc *p;
157 	struct getsid_args *uap;
158 {
159 	struct proc *pt;
160 
161 	pt = p;
162 	if (uap->pid == 0)
163 		goto found;
164 
165 	if ((pt == pfind(uap->pid)) == 0)
166 		return ESRCH;
167 found:
168 	p->p_retval[0] = pt->p_session->s_sid;
169 	return 0;
170 }
171 
172 
173 /*
174  * getuid() - MP SAFE
175  */
176 #ifndef _SYS_SYSPROTO_H_
177 struct getuid_args {
178         int     dummy;
179 };
180 #endif
181 
182 /* ARGSUSED */
183 int
184 getuid(p, uap)
185 	struct proc *p;
186 	struct getuid_args *uap;
187 {
188 
189 	p->p_retval[0] = p->p_cred->p_ruid;
190 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
191 	p->p_retval[1] = p->p_ucred->cr_uid;
192 #endif
193 	return (0);
194 }
195 
196 /*
197  * geteuid() - MP SAFE
198  */
199 #ifndef _SYS_SYSPROTO_H_
200 struct geteuid_args {
201         int     dummy;
202 };
203 #endif
204 
205 /* ARGSUSED */
206 int
207 geteuid(p, uap)
208 	struct proc *p;
209 	struct geteuid_args *uap;
210 {
211 
212 	p->p_retval[0] = p->p_ucred->cr_uid;
213 	return (0);
214 }
215 
216 /*
217  * getgid() - MP SAFE
218  */
219 #ifndef _SYS_SYSPROTO_H_
220 struct getgid_args {
221         int     dummy;
222 };
223 #endif
224 
225 /* ARGSUSED */
226 int
227 getgid(p, uap)
228 	struct proc *p;
229 	struct getgid_args *uap;
230 {
231 
232 	p->p_retval[0] = p->p_cred->p_rgid;
233 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
234 	p->p_retval[1] = p->p_ucred->cr_groups[0];
235 #endif
236 	return (0);
237 }
238 
239 /*
240  * Get effective group ID.  The "egid" is groups[0], and could be obtained
241  * via getgroups.  This syscall exists because it is somewhat painful to do
242  * correctly in a library function.
243  */
244 #ifndef _SYS_SYSPROTO_H_
245 struct getegid_args {
246         int     dummy;
247 };
248 #endif
249 
250 /* ARGSUSED */
251 int
252 getegid(p, uap)
253 	struct proc *p;
254 	struct getegid_args *uap;
255 {
256 
257 	p->p_retval[0] = p->p_ucred->cr_groups[0];
258 	return (0);
259 }
260 
261 #ifndef _SYS_SYSPROTO_H_
262 struct getgroups_args {
263 	u_int	gidsetsize;
264 	gid_t	*gidset;
265 };
266 #endif
267 int
268 getgroups(p, uap)
269 	struct proc *p;
270 	register struct	getgroups_args *uap;
271 {
272 	register struct pcred *pc = p->p_cred;
273 	register u_int ngrp;
274 	int error;
275 
276 	if ((ngrp = uap->gidsetsize) == 0) {
277 		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
278 		return (0);
279 	}
280 	if (ngrp < pc->pc_ucred->cr_ngroups)
281 		return (EINVAL);
282 	ngrp = pc->pc_ucred->cr_ngroups;
283 	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
284 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
285 		return (error);
286 	p->p_retval[0] = ngrp;
287 	return (0);
288 }
289 
290 #ifndef _SYS_SYSPROTO_H_
291 struct setsid_args {
292         int     dummy;
293 };
294 #endif
295 
296 /* ARGSUSED */
297 int
298 setsid(p, uap)
299 	register struct proc *p;
300 	struct setsid_args *uap;
301 {
302 
303 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
304 		return (EPERM);
305 	} else {
306 		(void)enterpgrp(p, p->p_pid, 1);
307 		p->p_retval[0] = p->p_pid;
308 		return (0);
309 	}
310 }
311 
312 /*
313  * set process group (setpgid/old setpgrp)
314  *
315  * caller does setpgid(targpid, targpgid)
316  *
317  * pid must be caller or child of caller (ESRCH)
318  * if a child
319  *	pid must be in same session (EPERM)
320  *	pid can't have done an exec (EACCES)
321  * if pgid != pid
322  * 	there must exist some pid in same session having pgid (EPERM)
323  * pid must not be session leader (EPERM)
324  */
325 #ifndef _SYS_SYSPROTO_H_
326 struct setpgid_args {
327 	int	pid;	/* target process id */
328 	int	pgid;	/* target pgrp id */
329 };
330 #endif
331 /* ARGSUSED */
332 int
333 setpgid(curp, uap)
334 	struct proc *curp;
335 	register struct setpgid_args *uap;
336 {
337 	register struct proc *targp;		/* target process */
338 	register struct pgrp *pgrp;		/* target pgrp */
339 
340 	if (uap->pgid < 0)
341 		return (EINVAL);
342 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
343 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
344 			return (ESRCH);
345 		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
346 			return (EPERM);
347 		if (targp->p_flag & P_EXEC)
348 			return (EACCES);
349 	} else
350 		targp = curp;
351 	if (SESS_LEADER(targp))
352 		return (EPERM);
353 	if (uap->pgid == 0)
354 		uap->pgid = targp->p_pid;
355 	else if (uap->pgid != targp->p_pid)
356 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
357 	            pgrp->pg_session != curp->p_session)
358 			return (EPERM);
359 	return (enterpgrp(targp, uap->pgid, 0));
360 }
361 
362 /*
363  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
364  * compatable.  It says that setting the uid/gid to euid/egid is a special
365  * case of "appropriate privilege".  Once the rules are expanded out, this
366  * basically means that setuid(nnn) sets all three id's, in all permitted
367  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
368  * does not set the saved id - this is dangerous for traditional BSD
369  * programs.  For this reason, we *really* do not want to set
370  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
371  */
372 #define POSIX_APPENDIX_B_4_2_2
373 
374 #ifndef _SYS_SYSPROTO_H_
375 struct setuid_args {
376 	uid_t	uid;
377 };
378 #endif
379 /* ARGSUSED */
380 int
381 setuid(p, uap)
382 	struct proc *p;
383 	struct setuid_args *uap;
384 {
385 	register struct pcred *pc = p->p_cred;
386 	register uid_t uid;
387 	int error;
388 
389 	/*
390 	 * See if we have "permission" by POSIX 1003.1 rules.
391 	 *
392 	 * Note that setuid(geteuid()) is a special case of
393 	 * "appropriate privileges" in appendix B.4.2.2.  We need
394 	 * to use this clause to be compatable with traditional BSD
395 	 * semantics.  Basically, it means that "setuid(xx)" sets all
396 	 * three id's (assuming you have privs).
397 	 *
398 	 * Notes on the logic.  We do things in three steps.
399 	 * 1: We determine if the euid is going to change, and do EPERM
400 	 *    right away.  We unconditionally change the euid later if this
401 	 *    test is satisfied, simplifying that part of the logic.
402 	 * 2: We determine if the real and/or saved uid's are going to
403 	 *    change.  Determined by compile options.
404 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
405 	 */
406 	uid = uap->uid;
407 	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
408 #ifdef _POSIX_SAVED_IDS
409 	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
410 #endif
411 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
412 	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
413 #endif
414 	    (error = suser_xxx(0, p, PRISON_ROOT)))
415 		return (error);
416 
417 #ifdef _POSIX_SAVED_IDS
418 	/*
419 	 * Do we have "appropriate privileges" (are we root or uid == euid)
420 	 * If so, we are changing the real uid and/or saved uid.
421 	 */
422 	if (
423 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
424 	    uid == pc->pc_ucred->cr_uid ||
425 #endif
426 	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
427 #endif
428 	{
429 		/*
430 		 * Transfer proc count to new user.
431 		 */
432 		if (uid != pc->p_ruid) {
433 			(void)chgproccnt(pc->p_ruid, -1, 0);
434 			(void)chgproccnt(uid, 1, 0);
435 		}
436 		/*
437 		 * Set real uid
438 		 */
439 		if (uid != pc->p_ruid) {
440 			pc->p_ruid = uid;
441 			setsugid(p);
442 		}
443 		/*
444 		 * Set saved uid
445 		 *
446 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
447 		 * the security of seteuid() depends on it.  B.4.2.2 says it
448 		 * is important that we should do this.
449 		 */
450 		if (pc->p_svuid != uid) {
451 			pc->p_svuid = uid;
452 			setsugid(p);
453 		}
454 	}
455 
456 	/*
457 	 * In all permitted cases, we are changing the euid.
458 	 * Copy credentials so other references do not see our changes.
459 	 */
460 	if (pc->pc_ucred->cr_uid != uid) {
461 		pc->pc_ucred = crcopy(pc->pc_ucred);
462 		pc->pc_ucred->cr_uid = uid;
463 		setsugid(p);
464 	}
465 	return (0);
466 }
467 
468 #ifndef _SYS_SYSPROTO_H_
469 struct seteuid_args {
470 	uid_t	euid;
471 };
472 #endif
473 /* ARGSUSED */
474 int
475 seteuid(p, uap)
476 	struct proc *p;
477 	struct seteuid_args *uap;
478 {
479 	register struct pcred *pc = p->p_cred;
480 	register uid_t euid;
481 	int error;
482 
483 	euid = uap->euid;
484 	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
485 	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
486 	    (error = suser_xxx(0, p, PRISON_ROOT)))
487 		return (error);
488 	/*
489 	 * Everything's okay, do it.  Copy credentials so other references do
490 	 * not see our changes.
491 	 */
492 	if (pc->pc_ucred->cr_uid != euid) {
493 		pc->pc_ucred = crcopy(pc->pc_ucred);
494 		pc->pc_ucred->cr_uid = euid;
495 		setsugid(p);
496 	}
497 	return (0);
498 }
499 
500 #ifndef _SYS_SYSPROTO_H_
501 struct setgid_args {
502 	gid_t	gid;
503 };
504 #endif
505 /* ARGSUSED */
506 int
507 setgid(p, uap)
508 	struct proc *p;
509 	struct setgid_args *uap;
510 {
511 	register struct pcred *pc = p->p_cred;
512 	register gid_t gid;
513 	int error;
514 
515 	/*
516 	 * See if we have "permission" by POSIX 1003.1 rules.
517 	 *
518 	 * Note that setgid(getegid()) is a special case of
519 	 * "appropriate privileges" in appendix B.4.2.2.  We need
520 	 * to use this clause to be compatable with traditional BSD
521 	 * semantics.  Basically, it means that "setgid(xx)" sets all
522 	 * three id's (assuming you have privs).
523 	 *
524 	 * For notes on the logic here, see setuid() above.
525 	 */
526 	gid = uap->gid;
527 	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
528 #ifdef _POSIX_SAVED_IDS
529 	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
530 #endif
531 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
532 	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
533 #endif
534 	    (error = suser_xxx(0, p, PRISON_ROOT)))
535 		return (error);
536 
537 #ifdef _POSIX_SAVED_IDS
538 	/*
539 	 * Do we have "appropriate privileges" (are we root or gid == egid)
540 	 * If so, we are changing the real uid and saved gid.
541 	 */
542 	if (
543 #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
544 	    gid == pc->pc_ucred->cr_groups[0] ||
545 #endif
546 	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
547 #endif
548 	{
549 		/*
550 		 * Set real gid
551 		 */
552 		if (pc->p_rgid != gid) {
553 			pc->p_rgid = gid;
554 			setsugid(p);
555 		}
556 		/*
557 		 * Set saved gid
558 		 *
559 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
560 		 * the security of setegid() depends on it.  B.4.2.2 says it
561 		 * is important that we should do this.
562 		 */
563 		if (pc->p_svgid != gid) {
564 			pc->p_svgid = gid;
565 			setsugid(p);
566 		}
567 	}
568 	/*
569 	 * In all cases permitted cases, we are changing the egid.
570 	 * Copy credentials so other references do not see our changes.
571 	 */
572 	if (pc->pc_ucred->cr_groups[0] != gid) {
573 		pc->pc_ucred = crcopy(pc->pc_ucred);
574 		pc->pc_ucred->cr_groups[0] = gid;
575 		setsugid(p);
576 	}
577 	return (0);
578 }
579 
580 #ifndef _SYS_SYSPROTO_H_
581 struct setegid_args {
582 	gid_t	egid;
583 };
584 #endif
585 /* ARGSUSED */
586 int
587 setegid(p, uap)
588 	struct proc *p;
589 	struct setegid_args *uap;
590 {
591 	register struct pcred *pc = p->p_cred;
592 	register gid_t egid;
593 	int error;
594 
595 	egid = uap->egid;
596 	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
597 	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
598 	    (error = suser_xxx(0, p, PRISON_ROOT)))
599 		return (error);
600 	if (pc->pc_ucred->cr_groups[0] != egid) {
601 		pc->pc_ucred = crcopy(pc->pc_ucred);
602 		pc->pc_ucred->cr_groups[0] = egid;
603 		setsugid(p);
604 	}
605 	return (0);
606 }
607 
608 #ifndef _SYS_SYSPROTO_H_
609 struct setgroups_args {
610 	u_int	gidsetsize;
611 	gid_t	*gidset;
612 };
613 #endif
614 /* ARGSUSED */
615 int
616 setgroups(p, uap)
617 	struct proc *p;
618 	struct setgroups_args *uap;
619 {
620 	register struct pcred *pc = p->p_cred;
621 	register u_int ngrp;
622 	int error;
623 
624 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
625 		return (error);
626 	ngrp = uap->gidsetsize;
627 	if (ngrp > NGROUPS)
628 		return (EINVAL);
629 	/*
630 	 * XXX A little bit lazy here.  We could test if anything has
631 	 * changed before crcopy() and setting P_SUGID.
632 	 */
633 	pc->pc_ucred = crcopy(pc->pc_ucred);
634 	if (ngrp < 1) {
635 		/*
636 		 * setgroups(0, NULL) is a legitimate way of clearing the
637 		 * groups vector on non-BSD systems (which generally do not
638 		 * have the egid in the groups[0]).  We risk security holes
639 		 * when running non-BSD software if we do not do the same.
640 		 */
641 		pc->pc_ucred->cr_ngroups = 1;
642 	} else {
643 		if ((error = copyin((caddr_t)uap->gidset,
644 		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
645 			return (error);
646 		pc->pc_ucred->cr_ngroups = ngrp;
647 	}
648 	setsugid(p);
649 	return (0);
650 }
651 
652 #ifndef _SYS_SYSPROTO_H_
653 struct setreuid_args {
654 	uid_t	ruid;
655 	uid_t	euid;
656 };
657 #endif
658 /* ARGSUSED */
659 int
660 setreuid(p, uap)
661 	register struct proc *p;
662 	struct setreuid_args *uap;
663 {
664 	register struct pcred *pc = p->p_cred;
665 	register uid_t ruid, euid;
666 	int error;
667 
668 	ruid = uap->ruid;
669 	euid = uap->euid;
670 	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
671 	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
672 	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
673 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
674 		return (error);
675 
676 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
677 		pc->pc_ucred = crcopy(pc->pc_ucred);
678 		pc->pc_ucred->cr_uid = euid;
679 		setsugid(p);
680 	}
681 	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
682 		(void)chgproccnt(pc->p_ruid, -1, 0);
683 		(void)chgproccnt(ruid, 1, 0);
684 		pc->p_ruid = ruid;
685 		setsugid(p);
686 	}
687 	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
688 	    pc->p_svuid != pc->pc_ucred->cr_uid) {
689 		pc->p_svuid = pc->pc_ucred->cr_uid;
690 		setsugid(p);
691 	}
692 	return (0);
693 }
694 
695 #ifndef _SYS_SYSPROTO_H_
696 struct setregid_args {
697 	gid_t	rgid;
698 	gid_t	egid;
699 };
700 #endif
701 /* ARGSUSED */
702 int
703 setregid(p, uap)
704 	register struct proc *p;
705 	struct setregid_args *uap;
706 {
707 	register struct pcred *pc = p->p_cred;
708 	register gid_t rgid, egid;
709 	int error;
710 
711 	rgid = uap->rgid;
712 	egid = uap->egid;
713 	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
714 	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
715 	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
716 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
717 		return (error);
718 
719 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
720 		pc->pc_ucred = crcopy(pc->pc_ucred);
721 		pc->pc_ucred->cr_groups[0] = egid;
722 		setsugid(p);
723 	}
724 	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
725 		pc->p_rgid = rgid;
726 		setsugid(p);
727 	}
728 	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
729 	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
730 		pc->p_svgid = pc->pc_ucred->cr_groups[0];
731 		setsugid(p);
732 	}
733 	return (0);
734 }
735 
736 /*
737  * setresuid(ruid, euid, suid) is like setreuid except control over the
738  * saved uid is explicit.
739  */
740 
741 #ifndef _SYS_SYSPROTO_H_
742 struct setresuid_args {
743 	uid_t	ruid;
744 	uid_t	euid;
745 	uid_t	suid;
746 };
747 #endif
748 /* ARGSUSED */
749 int
750 setresuid(p, uap)
751 	register struct proc *p;
752 	struct setresuid_args *uap;
753 {
754 	register struct pcred *pc = p->p_cred;
755 	register uid_t ruid, euid, suid;
756 	int error;
757 
758 	ruid = uap->ruid;
759 	euid = uap->euid;
760 	suid = uap->suid;
761 	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
762 	      ruid != pc->pc_ucred->cr_uid) ||
763 	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
764 	      euid != pc->pc_ucred->cr_uid) ||
765 	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
766 	      suid != pc->pc_ucred->cr_uid)) &&
767 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
768 		return (error);
769 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
770 		pc->pc_ucred = crcopy(pc->pc_ucred);
771 		pc->pc_ucred->cr_uid = euid;
772 		setsugid(p);
773 	}
774 	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
775 		(void)chgproccnt(pc->p_ruid, -1, 0);
776 		(void)chgproccnt(ruid, 1, 0);
777 		pc->p_ruid = ruid;
778 		setsugid(p);
779 	}
780 	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
781 		pc->p_svuid = suid;
782 		setsugid(p);
783 	}
784 	return (0);
785 }
786 
787 /*
788  * setresgid(rgid, egid, sgid) is like setregid except control over the
789  * saved gid is explicit.
790  */
791 
792 #ifndef _SYS_SYSPROTO_H_
793 struct setresgid_args {
794 	gid_t	rgid;
795 	gid_t	egid;
796 	gid_t	sgid;
797 };
798 #endif
799 /* ARGSUSED */
800 int
801 setresgid(p, uap)
802 	register struct proc *p;
803 	struct setresgid_args *uap;
804 {
805 	register struct pcred *pc = p->p_cred;
806 	register gid_t rgid, egid, sgid;
807 	int error;
808 
809 	rgid = uap->rgid;
810 	egid = uap->egid;
811 	sgid = uap->sgid;
812 	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
813 	      rgid != pc->pc_ucred->cr_groups[0]) ||
814 	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
815 	      egid != pc->pc_ucred->cr_groups[0]) ||
816 	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
817 	      sgid != pc->pc_ucred->cr_groups[0])) &&
818 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
819 		return (error);
820 
821 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
822 		pc->pc_ucred = crcopy(pc->pc_ucred);
823 		pc->pc_ucred->cr_groups[0] = egid;
824 		setsugid(p);
825 	}
826 	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
827 		pc->p_rgid = rgid;
828 		setsugid(p);
829 	}
830 	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
831 		pc->p_svgid = sgid;
832 		setsugid(p);
833 	}
834 	return (0);
835 }
836 
837 #ifndef _SYS_SYSPROTO_H_
838 struct getresuid_args {
839 	uid_t	*ruid;
840 	uid_t	*euid;
841 	uid_t	*suid;
842 };
843 #endif
844 /* ARGSUSED */
845 int
846 getresuid(p, uap)
847 	register struct proc *p;
848 	struct getresuid_args *uap;
849 {
850 	struct pcred *pc = p->p_cred;
851 	int error1 = 0, error2 = 0, error3 = 0;
852 
853 	if (uap->ruid)
854 		error1 = copyout((caddr_t)&pc->p_ruid,
855 		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
856 	if (uap->euid)
857 		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
858 		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
859 	if (uap->suid)
860 		error3 = copyout((caddr_t)&pc->p_svuid,
861 		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
862 	return error1 ? error1 : (error2 ? error2 : error3);
863 }
864 
865 #ifndef _SYS_SYSPROTO_H_
866 struct getresgid_args {
867 	gid_t	*rgid;
868 	gid_t	*egid;
869 	gid_t	*sgid;
870 };
871 #endif
872 /* ARGSUSED */
873 int
874 getresgid(p, uap)
875 	register struct proc *p;
876 	struct getresgid_args *uap;
877 {
878 	struct pcred *pc = p->p_cred;
879 	int error1 = 0, error2 = 0, error3 = 0;
880 
881 	if (uap->rgid)
882 		error1 = copyout((caddr_t)&pc->p_rgid,
883 		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
884 	if (uap->egid)
885 		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
886 		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
887 	if (uap->sgid)
888 		error3 = copyout((caddr_t)&pc->p_svgid,
889 		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
890 	return error1 ? error1 : (error2 ? error2 : error3);
891 }
892 
893 
894 #ifndef _SYS_SYSPROTO_H_
895 struct issetugid_args {
896 	int dummy;
897 };
898 #endif
899 /* ARGSUSED */
900 int
901 issetugid(p, uap)
902 	register struct proc *p;
903 	struct issetugid_args *uap;
904 {
905 	/*
906 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
907 	 * we use P_SUGID because we consider changing the owners as
908 	 * "tainting" as well.
909 	 * This is significant for procs that start as root and "become"
910 	 * a user without an exec - programs cannot know *everything*
911 	 * that libc *might* have put in their data segment.
912 	 */
913 	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
914 	return (0);
915 }
916 
917 /*
918  * Check if gid is a member of the group set.
919  */
920 int
921 groupmember(gid, cred)
922 	gid_t gid;
923 	register struct ucred *cred;
924 {
925 	register gid_t *gp;
926 	gid_t *egp;
927 
928 	egp = &(cred->cr_groups[cred->cr_ngroups]);
929 	for (gp = cred->cr_groups; gp < egp; gp++)
930 		if (*gp == gid)
931 			return (1);
932 	return (0);
933 }
934 
935 static int suser_permitted = 1;
936 
937 SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
938     "processes with uid 0 have privilege");
939 
940 /*
941  * Test whether the specified credentials imply "super-user"
942  * privilege; if so, and we have accounting info, set the flag
943  * indicating use of super-powers.
944  * Returns 0 or error.
945  */
946 int
947 suser(p)
948 	struct proc *p;
949 {
950 	return suser_xxx(0, p, 0);
951 }
952 
953 int
954 suser_xxx(cred, proc, flag)
955 	struct ucred *cred;
956 	struct proc *proc;
957 	int flag;
958 {
959 	if (!suser_permitted)
960 		return (EPERM);
961 	if (!cred && !proc) {
962 		printf("suser_xxx(): THINK!\n");
963 		return (EPERM);
964 	}
965 	if (!cred)
966 		cred = proc->p_ucred;
967 	if (cred->cr_uid != 0)
968 		return (EPERM);
969 	if (proc && proc->p_prison && !(flag & PRISON_ROOT))
970 		return (EPERM);
971 	if (proc)
972 		proc->p_acflag |= ASU;
973 	return (0);
974 }
975 
976 /*
977  * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise.
978  */
979 
980 int
981 p_trespass(struct proc *p1, struct proc *p2)
982 {
983 
984 	if (p1 == p2)
985 		return (0);
986 	if (!PRISON_CHECK(p1, p2))
987 		return (ESRCH);
988 	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
989 		return (0);
990 	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
991 		return (0);
992 	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
993 		return (0);
994 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
995 		return (0);
996 	if (!suser_xxx(0, p1, PRISON_ROOT))
997 		return (0);
998 	return (EPERM);
999 }
1000 
1001 /*
1002  * Allocate a zeroed cred structure.
1003  */
1004 struct ucred *
1005 crget()
1006 {
1007 	register struct ucred *cr;
1008 
1009 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
1010 	bzero((caddr_t)cr, sizeof(*cr));
1011 	cr->cr_ref = 1;
1012 	return (cr);
1013 }
1014 
1015 /*
1016  * Free a cred structure.
1017  * Throws away space when ref count gets to 0.
1018  */
1019 void
1020 crfree(cr)
1021 	struct ucred *cr;
1022 {
1023 	if (--cr->cr_ref == 0)
1024 		FREE((caddr_t)cr, M_CRED);
1025 }
1026 
1027 /*
1028  * Copy cred structure to a new one and free the old one.
1029  */
1030 struct ucred *
1031 crcopy(cr)
1032 	struct ucred *cr;
1033 {
1034 	struct ucred *newcr;
1035 
1036 	if (cr->cr_ref == 1)
1037 		return (cr);
1038 	newcr = crget();
1039 	*newcr = *cr;
1040 	crfree(cr);
1041 	newcr->cr_ref = 1;
1042 	return (newcr);
1043 }
1044 
1045 /*
1046  * Dup cred struct to a new held one.
1047  */
1048 struct ucred *
1049 crdup(cr)
1050 	struct ucred *cr;
1051 {
1052 	struct ucred *newcr;
1053 
1054 	newcr = crget();
1055 	*newcr = *cr;
1056 	newcr->cr_ref = 1;
1057 	return (newcr);
1058 }
1059 
1060 /*
1061  * Get login name, if available.
1062  */
1063 #ifndef _SYS_SYSPROTO_H_
1064 struct getlogin_args {
1065 	char	*namebuf;
1066 	u_int	namelen;
1067 };
1068 #endif
1069 /* ARGSUSED */
1070 int
1071 getlogin(p, uap)
1072 	struct proc *p;
1073 	struct getlogin_args *uap;
1074 {
1075 
1076 	if (uap->namelen > MAXLOGNAME)
1077 		uap->namelen = MAXLOGNAME;
1078 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
1079 	    (caddr_t) uap->namebuf, uap->namelen));
1080 }
1081 
1082 /*
1083  * Set login name.
1084  */
1085 #ifndef _SYS_SYSPROTO_H_
1086 struct setlogin_args {
1087 	char	*namebuf;
1088 };
1089 #endif
1090 /* ARGSUSED */
1091 int
1092 setlogin(p, uap)
1093 	struct proc *p;
1094 	struct setlogin_args *uap;
1095 {
1096 	int error;
1097 	char logintmp[MAXLOGNAME];
1098 
1099 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
1100 		return (error);
1101 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
1102 	    sizeof(logintmp), (size_t *)0);
1103 	if (error == ENAMETOOLONG)
1104 		error = EINVAL;
1105 	else if (!error)
1106 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
1107 		    sizeof(logintmp));
1108 	return (error);
1109 }
1110 
1111 void
1112 setsugid(p)
1113 	struct proc *p;
1114 {
1115 	p->p_flag |= P_SUGID;
1116 	if (!(p->p_pfsflags & PF_ISUGID))
1117 		p->p_stops = 0;
1118 }
1119