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