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