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