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