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