xref: /freebsd/sys/kern/kern_prot.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
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 #ifndef _SYS_SYSPROTO_H_
720 struct issetugid_args {
721 	int dummy;
722 };
723 #endif
724 /* ARGSUSED */
725 int
726 issetugid(p, uap)
727 	register struct proc *p;
728 	struct issetugid_args *uap;
729 {
730 	/*
731 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
732 	 * we use P_SUGID because we consider changing the owners as
733 	 * "tainting" as well.
734 	 * This is significant for procs that start as root and "become"
735 	 * a user without an exec - programs cannot know *everything*
736 	 * that libc *might* have put in their data segment.
737 	 */
738 	if (p->p_flag & P_SUGID)
739 		return (1);
740 	return (0);
741 }
742 
743 /*
744  * Check if gid is a member of the group set.
745  */
746 int
747 groupmember(gid, cred)
748 	gid_t gid;
749 	register struct ucred *cred;
750 {
751 	register gid_t *gp;
752 	gid_t *egp;
753 
754 	egp = &(cred->cr_groups[cred->cr_ngroups]);
755 	for (gp = cred->cr_groups; gp < egp; gp++)
756 		if (*gp == gid)
757 			return (1);
758 	return (0);
759 }
760 
761 /*
762  * Test whether the specified credentials imply "super-user"
763  * privilege; if so, and we have accounting info, set the flag
764  * indicating use of super-powers.
765  * Returns 0 or error.
766  */
767 int
768 suser(p)
769 	struct proc *p;
770 {
771 	return suser_xxx(0, p, 0);
772 }
773 
774 int
775 suser_xxx(cred, proc, flag)
776 	struct ucred *cred;
777 	struct proc *proc;
778 	int flag;
779 {
780 	if (!cred && !proc) {
781 		printf("suser_xxx(): THINK!\n");
782 		return (EPERM);
783 	}
784 	if (!cred)
785 		cred = proc->p_ucred;
786 	if (cred->cr_uid != 0)
787 		return (EPERM);
788 	if (proc && proc->p_prison && !(flag & PRISON_ROOT))
789 		return (EPERM);
790 	if (proc)
791 		proc->p_acflag |= ASU;
792 	return (0);
793 }
794 
795 /*
796  * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise.
797  */
798 
799 int
800 p_trespass(struct proc *p1, struct proc *p2)
801 {
802 
803 	if (p1 == p2)
804 		return (0);
805 	if (!PRISON_CHECK(p1, p2))
806 		return (ESRCH);
807 	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
808 		return (0);
809 	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
810 		return (0);
811 	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
812 		return (0);
813 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
814 		return (0);
815 	if (!suser_xxx(0, p1, PRISON_ROOT))
816 		return (0);
817 	return (EPERM);
818 }
819 
820 /*
821  * Allocate a zeroed cred structure.
822  */
823 struct ucred *
824 crget()
825 {
826 	register struct ucred *cr;
827 
828 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
829 	bzero((caddr_t)cr, sizeof(*cr));
830 	cr->cr_ref = 1;
831 	return (cr);
832 }
833 
834 /*
835  * Free a cred structure.
836  * Throws away space when ref count gets to 0.
837  */
838 void
839 crfree(cr)
840 	struct ucred *cr;
841 {
842 	if (--cr->cr_ref == 0)
843 		FREE((caddr_t)cr, M_CRED);
844 }
845 
846 /*
847  * Copy cred structure to a new one and free the old one.
848  */
849 struct ucred *
850 crcopy(cr)
851 	struct ucred *cr;
852 {
853 	struct ucred *newcr;
854 
855 	if (cr->cr_ref == 1)
856 		return (cr);
857 	newcr = crget();
858 	*newcr = *cr;
859 	crfree(cr);
860 	newcr->cr_ref = 1;
861 	return (newcr);
862 }
863 
864 /*
865  * Dup cred struct to a new held one.
866  */
867 struct ucred *
868 crdup(cr)
869 	struct ucred *cr;
870 {
871 	struct ucred *newcr;
872 
873 	newcr = crget();
874 	*newcr = *cr;
875 	newcr->cr_ref = 1;
876 	return (newcr);
877 }
878 
879 /*
880  * Get login name, if available.
881  */
882 #ifndef _SYS_SYSPROTO_H_
883 struct getlogin_args {
884 	char	*namebuf;
885 	u_int	namelen;
886 };
887 #endif
888 /* ARGSUSED */
889 int
890 getlogin(p, uap)
891 	struct proc *p;
892 	struct getlogin_args *uap;
893 {
894 
895 	if (uap->namelen > MAXLOGNAME)
896 		uap->namelen = MAXLOGNAME;
897 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
898 	    (caddr_t) uap->namebuf, uap->namelen));
899 }
900 
901 /*
902  * Set login name.
903  */
904 #ifndef _SYS_SYSPROTO_H_
905 struct setlogin_args {
906 	char	*namebuf;
907 };
908 #endif
909 /* ARGSUSED */
910 int
911 setlogin(p, uap)
912 	struct proc *p;
913 	struct setlogin_args *uap;
914 {
915 	int error;
916 	char logintmp[MAXLOGNAME];
917 
918 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
919 		return (error);
920 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
921 	    sizeof(logintmp), (size_t *)0);
922 	if (error == ENAMETOOLONG)
923 		error = EINVAL;
924 	else if (!error)
925 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
926 		    sizeof(logintmp));
927 	return (error);
928 }
929 
930 void
931 setsugid(p)
932      struct proc *p;
933 {
934 	p->p_flag |= P_SUGID;
935 	if (!(p->p_pfsflags & PF_ISUGID))
936 		p->p_stops = 0;
937 }
938