xref: /openbsd-src/sys/kern/kern_prot.c (revision 47911bd667ac77dc523b8a13ef40b012dbffa741)
1 /*	$OpenBSD: kern_prot.c,v 1.22 2002/10/30 20:02:58 millert Exp $	*/
2 /*	$NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the University of
24  *	California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
42  */
43 
44 /*
45  * System calls related to processes and protection
46  */
47 
48 #include <sys/param.h>
49 #include <sys/acct.h>
50 #include <sys/systm.h>
51 #include <sys/ucred.h>
52 #include <sys/proc.h>
53 #include <sys/timeb.h>
54 #include <sys/times.h>
55 #include <sys/malloc.h>
56 #include <sys/filedesc.h>
57 #include <sys/pool.h>
58 
59 #include <sys/mount.h>
60 #include <sys/syscallargs.h>
61 
62 /* ARGSUSED */
63 int
64 sys_getpid(p, v, retval)
65 	struct proc *p;
66 	void *v;
67 	register_t *retval;
68 {
69 
70 	*retval = p->p_pid;
71 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
72     defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
73 	retval[1] = p->p_pptr->p_pid;
74 #endif
75 	return (0);
76 }
77 
78 /* ARGSUSED */
79 int
80 sys_getppid(p, v, retval)
81 	struct proc *p;
82 	void *v;
83 	register_t *retval;
84 {
85 
86 	*retval = p->p_pptr->p_pid;
87 	return (0);
88 }
89 
90 /* Get process group ID; note that POSIX getpgrp takes no parameter */
91 int
92 sys_getpgrp(p, v, retval)
93 	struct proc *p;
94 	void *v;
95 	register_t *retval;
96 {
97 
98 	*retval = p->p_pgrp->pg_id;
99 	return (0);
100 }
101 
102 /*
103  * SysVR.4 compatible getpgid()
104  */
105 pid_t
106 sys_getpgid(curp, v, retval)
107 	struct proc *curp;
108 	void *v;
109 	register_t *retval;
110 {
111 	struct sys_getpgid_args /* {
112 		syscallarg(pid_t) pid;
113 	} */ *uap = v;
114 	struct proc *targp = curp;
115 
116 	if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
117 		goto found;
118 	if ((targp = pfind(SCARG(uap, pid))) == NULL)
119 		return (ESRCH);
120 	if (targp->p_session != curp->p_session)
121 		return (EPERM);
122 found:
123 	*retval = targp->p_pgid;
124 	return (0);
125 }
126 
127 pid_t
128 sys_getsid(curp, v, retval)
129 	struct proc *curp;
130 	void *v;
131 	register_t *retval;
132 {
133 	struct sys_getsid_args /* {
134 		syscallarg(pid_t) pid;
135 	} */ *uap = v;
136 	struct proc *targp = curp;
137 
138 	if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
139 		goto found;
140 	if ((targp = pfind(SCARG(uap, pid))) == NULL)
141 		return (ESRCH);
142 	if (targp->p_session != curp->p_session)
143 		return (EPERM);
144 found:
145 	/* Skip exiting processes */
146 	if (targp->p_pgrp->pg_session->s_leader == NULL)
147 		return (ESRCH);
148 	*retval = targp->p_pgrp->pg_session->s_leader->p_pid;
149 	return (0);
150 }
151 
152 /* ARGSUSED */
153 int
154 sys_getuid(p, v, retval)
155 	struct proc *p;
156 	void *v;
157 	register_t *retval;
158 {
159 
160 	*retval = p->p_cred->p_ruid;
161 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
162     defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
163 	retval[1] = p->p_ucred->cr_uid;
164 #endif
165 	return (0);
166 }
167 
168 /* ARGSUSED */
169 int
170 sys_geteuid(p, v, retval)
171 	struct proc *p;
172 	void *v;
173 	register_t *retval;
174 {
175 
176 	*retval = p->p_ucred->cr_uid;
177 	return (0);
178 }
179 
180 /* ARGSUSED */
181 int
182 sys_issetugid(p, v, retval)
183 	struct proc *p;
184 	void *v;
185 	register_t *retval;
186 {
187 	if (p->p_flag & P_SUGIDEXEC)
188 		*retval = 1;
189 	else
190 		*retval = 0;
191 	return (0);
192 }
193 
194 /* ARGSUSED */
195 int
196 sys_getgid(p, v, retval)
197 	struct proc *p;
198 	void *v;
199 	register_t *retval;
200 {
201 
202 	*retval = p->p_cred->p_rgid;
203 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
204 	retval[1] = p->p_ucred->cr_gid;
205 #endif
206 	return (0);
207 }
208 
209 /*
210  * Get effective group ID.  The "egid" is groups[0], and could be obtained
211  * via getgroups.  This syscall exists because it is somewhat painful to do
212  * correctly in a library function.
213  */
214 /* ARGSUSED */
215 int
216 sys_getegid(p, v, retval)
217 	struct proc *p;
218 	void *v;
219 	register_t *retval;
220 {
221 
222 	*retval = p->p_ucred->cr_gid;
223 	return (0);
224 }
225 
226 int
227 sys_getgroups(p, v, retval)
228 	struct proc *p;
229 	void *v;
230 	register_t *retval;
231 {
232 	struct sys_getgroups_args /* {
233 		syscallarg(int) gidsetsize;
234 		syscallarg(gid_t *) gidset;
235 	} */ *uap = v;
236 	struct pcred *pc = p->p_cred;
237 	u_int ngrp;
238 	int error;
239 
240 	if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
241 		*retval = pc->pc_ucred->cr_ngroups;
242 		return (0);
243 	}
244 	if (ngrp < pc->pc_ucred->cr_ngroups)
245 		return (EINVAL);
246 	ngrp = pc->pc_ucred->cr_ngroups;
247 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
248 	    (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
249 	if (error)
250 		return (error);
251 	*retval = ngrp;
252 	return (0);
253 }
254 
255 /* ARGSUSED */
256 int
257 sys_setsid(p, v, retval)
258 	struct proc *p;
259 	void *v;
260 	register_t *retval;
261 {
262 
263 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
264 		return (EPERM);
265 	} else {
266 		(void)enterpgrp(p, p->p_pid, 1);
267 		*retval = p->p_pid;
268 		return (0);
269 	}
270 }
271 
272 /*
273  * set process group (setpgid/old setpgrp)
274  *
275  * caller does setpgid(targpid, targpgid)
276  *
277  * pid must be caller or child of caller (ESRCH)
278  * if a child
279  *	pid must be in same session (EPERM)
280  *	pid can't have done an exec (EACCES)
281  * if pgid != pid
282  * 	there must exist some pid in same session having pgid (EPERM)
283  * pid must not be session leader (EPERM)
284  */
285 /* ARGSUSED */
286 int
287 sys_setpgid(curp, v, retval)
288 	struct proc *curp;
289 	void *v;
290 	register_t *retval;
291 {
292 	struct sys_setpgid_args /* {
293 		syscallarg(pid_t) pid;
294 		syscallarg(int) pgid;
295 	} */ *uap = v;
296 	struct proc *targp;		/* target process */
297 	struct pgrp *pgrp;		/* target pgrp */
298 	pid_t pid;
299 	int pgid;
300 
301 	pid = SCARG(uap, pid);
302 	pgid = SCARG(uap, pgid);
303 
304 	if (pgid < 0)
305 		return (EINVAL);
306 
307 	if (pid != 0 && pid != curp->p_pid) {
308 		if ((targp = pfind(pid)) == 0 || !inferior(targp))
309 			return (ESRCH);
310 		if (targp->p_session != curp->p_session)
311 			return (EPERM);
312 		if (targp->p_flag & P_EXEC)
313 			return (EACCES);
314 	} else
315 		targp = curp;
316 	if (SESS_LEADER(targp))
317 		return (EPERM);
318 	if (pgid == 0)
319 		pgid = targp->p_pid;
320 	else if (pgid != targp->p_pid)
321 		if ((pgrp = pgfind(pgid)) == 0 ||
322 		    pgrp->pg_session != curp->p_session)
323 			return (EPERM);
324 	return (enterpgrp(targp, pgid, 0));
325 }
326 
327 /* ARGSUSED */
328 int
329 sys_getresuid(p, v, retval)
330 	struct proc *p;
331 	void *v;
332 	register_t *retval;
333 {
334 	struct sys_getresuid_args /* {
335 		syscallarg(uid_t *) ruid;
336 		syscallarg(uid_t *) euid;
337 		syscallarg(uid_t *) suid;
338 	} */ *uap = v;
339 	struct pcred *pc = p->p_cred;
340 	uid_t *ruid, *euid, *suid;
341 	int error1 = 0, error2 = 0, error3 = 0;
342 
343 	ruid = SCARG(uap, ruid);
344 	euid = SCARG(uap, euid);
345 	suid = SCARG(uap, suid);
346 
347 	if (ruid != NULL)
348 		error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid));
349 	if (euid != NULL)
350 		error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid));
351 	if (suid != NULL)
352 		error3 = copyout(&pc->p_svuid, suid, sizeof(*suid));
353 
354 	return (error1 ? error1 : error2 ? error2 : error3);
355 }
356 
357 /* ARGSUSED */
358 int
359 sys_setresuid(p, v, retval)
360 	struct proc *p;
361 	void *v;
362 	register_t *retval;
363 {
364 	struct sys_setresuid_args /* {
365 		syscallarg(uid_t) ruid;
366 		syscallarg(uid_t) euid;
367 		syscallarg(uid_t) suid;
368 	} */ *uap = v;
369 	struct pcred *pc = p->p_cred;
370 	uid_t ruid, euid, suid;
371 	int error;
372 
373 	ruid = SCARG(uap, ruid);
374 	euid = SCARG(uap, euid);
375 	suid = SCARG(uap, suid);
376 
377 	if ((ruid == -1 || ruid == pc->p_ruid) &&
378 	    (euid == -1 || euid == pc->pc_ucred->cr_uid) &&
379 	    (suid == -1 || suid == pc->p_svuid))
380 		return (0);			/* no change */
381 
382 	/*
383 	 * Any of the real, effective, and saved uids may be changed
384 	 * to the current value of one of the three (root is not limited).
385 	 */
386 	if (ruid != (uid_t)-1 &&
387 	    ruid != pc->p_ruid &&
388 	    ruid != pc->pc_ucred->cr_uid &&
389 	    ruid != pc->p_svuid &&
390 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
391 		return (error);
392 
393 	if (euid != (uid_t)-1 &&
394 	    euid != pc->p_ruid &&
395 	    euid != pc->pc_ucred->cr_uid &&
396 	    euid != pc->p_svuid &&
397 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
398 		return (error);
399 
400 	if (suid != (uid_t)-1 &&
401 	    suid != pc->p_ruid &&
402 	    suid != pc->pc_ucred->cr_uid &&
403 	    suid != pc->p_svuid &&
404 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
405 		return (error);
406 
407 	/*
408 	 * Note that unlike the other set*uid() calls, each
409 	 * uid type is set independently of the others.
410 	 */
411 	if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
412 		/*
413 		 * Transfer proc count to new user.
414 		 */
415 		(void)chgproccnt(pc->p_ruid, -1);
416 		(void)chgproccnt(ruid, 1);
417 		pc->p_ruid = ruid;
418 	}
419 	if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
420 		/*
421 		 * Copy credentials so other references do not see our changes.
422 		 */
423 		pc->pc_ucred = crcopy(pc->pc_ucred);
424 		pc->pc_ucred->cr_uid = euid;
425 	}
426 	if (suid != (uid_t)-1 && suid != pc->p_svuid)
427 		pc->p_svuid = suid;
428 
429 	p->p_flag |= P_SUGID;
430 	return (0);
431 }
432 
433 /* ARGSUSED */
434 int
435 sys_getresgid(p, v, retval)
436 	struct proc *p;
437 	void *v;
438 	register_t *retval;
439 {
440 	struct sys_getresgid_args /* {
441 		syscallarg(gid_t *) rgid;
442 		syscallarg(gid_t *) egid;
443 		syscallarg(gid_t *) sgid;
444 	} */ *uap = v;
445 	struct pcred *pc = p->p_cred;
446 	gid_t *rgid, *egid, *sgid;
447 	int error1 = 0, error2 = 0, error3 = 0;
448 
449 	rgid = SCARG(uap, rgid);
450 	egid = SCARG(uap, egid);
451 	sgid = SCARG(uap, sgid);
452 
453 	if (rgid != NULL)
454 		error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid));
455 	if (egid != NULL)
456 		error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid));
457 	if (sgid != NULL)
458 		error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid));
459 
460 	return (error1 ? error1 : error2 ? error2 : error3);
461 }
462 
463 /* ARGSUSED */
464 int
465 sys_setresgid(p, v, retval)
466 	struct proc *p;
467 	void *v;
468 	register_t *retval;
469 {
470 	struct sys_setresgid_args /* {
471 		syscallarg(gid_t) rgid;
472 		syscallarg(gid_t) egid;
473 		syscallarg(gid_t) sgid;
474 	} */ *uap = v;
475 	struct pcred *pc = p->p_cred;
476 	gid_t rgid, egid, sgid;
477 	int error;
478 
479 	rgid = SCARG(uap, rgid);
480 	egid = SCARG(uap, egid);
481 	sgid = SCARG(uap, sgid);
482 
483 	if ((rgid == -1 || rgid == pc->p_rgid) &&
484 	    (egid == -1 || egid == pc->pc_ucred->cr_gid) &&
485 	    (sgid == -1 || sgid == pc->p_svgid))
486 		return (0);			/* no change */
487 
488 	/*
489 	 * Any of the real, effective, and saved gids may be changed
490 	 * to the current value of one of the three (root is not limited).
491 	 */
492 	if (rgid != (gid_t)-1 &&
493 	    rgid != pc->p_rgid &&
494 	    rgid != pc->pc_ucred->cr_gid &&
495 	    rgid != pc->p_svgid &&
496 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
497 		return (error);
498 
499 	if (egid != (gid_t)-1 &&
500 	    egid != pc->p_rgid &&
501 	    egid != pc->pc_ucred->cr_gid &&
502 	    egid != pc->p_svgid &&
503 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
504 		return (error);
505 
506 	if (sgid != (gid_t)-1 &&
507 	    sgid != pc->p_rgid &&
508 	    sgid != pc->pc_ucred->cr_gid &&
509 	    sgid != pc->p_svgid &&
510 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
511 		return (error);
512 
513 	/*
514 	 * Note that unlike the other set*gid() calls, each
515 	 * gid type is set independently of the others.
516 	 */
517 	if (rgid != (gid_t)-1)
518 		pc->p_rgid = rgid;
519 	if (egid != (gid_t)-1) {
520 		/*
521 		 * Copy credentials so other references do not see our changes.
522 		 */
523 		pc->pc_ucred = crcopy(pc->pc_ucred);
524 		pc->pc_ucred->cr_gid = egid;
525 	}
526 	if (sgid != (gid_t)-1)
527 		pc->p_svgid = sgid;
528 
529 	p->p_flag |= P_SUGID;
530 	return (0);
531 }
532 
533 /* ARGSUSED */
534 int
535 sys_setuid(p, v, retval)
536 	struct proc *p;
537 	void *v;
538 	register_t *retval;
539 {
540 	struct sys_setuid_args /* {
541 		syscallarg(uid_t) uid;
542 	} */ *uap = v;
543 	struct pcred *pc = p->p_cred;
544 	uid_t uid;
545 	int error;
546 
547 	uid = SCARG(uap, uid);
548 
549 	if (pc->pc_ucred->cr_uid == uid &&
550 	    pc->p_ruid == uid &&
551 	    pc->p_svuid == uid)
552 		return (0);
553 
554 	if (uid != pc->p_ruid &&
555 	    uid != pc->p_svuid &&
556 	    uid != pc->pc_ucred->cr_uid &&
557 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
558 		return (error);
559 
560 	/*
561 	 * Everything's okay, do it.
562 	 */
563 	if (uid == pc->pc_ucred->cr_uid ||
564 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
565 		/*
566 		 * Transfer proc count to new user.
567 		 */
568 		if (uid != pc->p_ruid) {
569 			(void)chgproccnt(pc->p_ruid, -1);
570 			(void)chgproccnt(uid, 1);
571 		}
572 		pc->p_ruid = uid;
573 		pc->p_svuid = uid;
574 	}
575 
576 	/*
577 	 * Copy credentials so other references do not see our changes.
578 	 */
579 	pc->pc_ucred = crcopy(pc->pc_ucred);
580 	pc->pc_ucred->cr_uid = uid;
581 	p->p_flag |= P_SUGID;
582 	return (0);
583 }
584 
585 /* ARGSUSED */
586 int
587 sys_seteuid(p, v, retval)
588 	struct proc *p;
589 	void *v;
590 	register_t *retval;
591 {
592 	struct sys_seteuid_args /* {
593 		syscallarg(uid_t) euid;
594 	} */ *uap = v;
595 	struct pcred *pc = p->p_cred;
596 	uid_t euid;
597 	int error;
598 
599 	euid = SCARG(uap, euid);
600 
601 	if (pc->pc_ucred->cr_uid == euid)
602 		return (0);
603 
604 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
605 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
606 		return (error);
607 
608 	/*
609 	 * Copy credentials so other references do not see our changes.
610 	 */
611 	pc->pc_ucred = crcopy(pc->pc_ucred);
612 	pc->pc_ucred->cr_uid = euid;
613 	p->p_flag |= P_SUGID;
614 	return (0);
615 }
616 
617 /* ARGSUSED */
618 int
619 sys_setgid(p, v, retval)
620 	struct proc *p;
621 	void *v;
622 	register_t *retval;
623 {
624 	struct sys_setgid_args /* {
625 		syscallarg(gid_t) gid;
626 	} */ *uap = v;
627 	struct pcred *pc = p->p_cred;
628 	gid_t gid;
629 	int error;
630 
631 	gid = SCARG(uap, gid);
632 
633 	if (pc->pc_ucred->cr_gid == gid &&
634 	    pc->p_rgid == gid &&
635 	    pc->p_svgid == gid)
636 		return (0);
637 
638 	if (gid != pc->p_rgid &&
639 	    gid != pc->p_svgid &&
640 	    gid != pc->pc_ucred->cr_gid &&
641 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
642 		return (error);
643 
644 	if (gid == pc->pc_ucred->cr_gid ||
645 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
646 		pc->p_rgid = gid;
647 		pc->p_svgid = gid;
648 	}
649 
650 	/*
651 	 * Copy credentials so other references do not see our changes.
652 	 */
653 	pc->pc_ucred = crcopy(pc->pc_ucred);
654 	pc->pc_ucred->cr_gid = gid;
655 	p->p_flag |= P_SUGID;
656 	return (0);
657 }
658 
659 /* ARGSUSED */
660 int
661 sys_setegid(p, v, retval)
662 	struct proc *p;
663 	void *v;
664 	register_t *retval;
665 {
666 	struct sys_setegid_args /* {
667 		syscallarg(gid_t) egid;
668 	} */ *uap = v;
669 	struct pcred *pc = p->p_cred;
670 	gid_t egid;
671 	int error;
672 
673 	egid = SCARG(uap, egid);
674 
675 	if (pc->pc_ucred->cr_gid == egid)
676 		return (0);
677 
678 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
679 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
680 		return (error);
681 
682 	/*
683 	 * Copy credentials so other references do not see our changes.
684 	 */
685 	pc->pc_ucred = crcopy(pc->pc_ucred);
686 	pc->pc_ucred->cr_gid = egid;
687 	p->p_flag |= P_SUGID;
688 	return (0);
689 }
690 
691 /* ARGSUSED */
692 int
693 sys_setgroups(p, v, retval)
694 	struct proc *p;
695 	void *v;
696 	register_t *retval;
697 {
698 	struct sys_setgroups_args /* {
699 		syscallarg(int) gidsetsize;
700 		syscallarg(gid_t *) gidset;
701 	} */ *uap = v;
702 	struct pcred *pc = p->p_cred;
703 	u_int ngrp;
704 	int error;
705 
706 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
707 		return (error);
708 	ngrp = SCARG(uap, gidsetsize);
709 	if (ngrp > NGROUPS)
710 		return (EINVAL);
711 	pc->pc_ucred = crcopy(pc->pc_ucred);
712 	error = copyin((caddr_t)SCARG(uap, gidset),
713 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
714 	if (error)
715 		return (error);
716 	pc->pc_ucred->cr_ngroups = ngrp;
717 	p->p_flag |= P_SUGID;
718 	return (0);
719 }
720 
721 /*
722  * Check if gid is a member of the group set.
723  */
724 int
725 groupmember(gid, cred)
726 	gid_t gid;
727 	struct ucred *cred;
728 {
729 	gid_t *gp;
730 	gid_t *egp;
731 
732 	egp = &(cred->cr_groups[cred->cr_ngroups]);
733 	for (gp = cred->cr_groups; gp < egp; gp++)
734 		if (*gp == gid)
735 			return (1);
736 	return (0);
737 }
738 
739 /*
740  * Test whether the specified credentials imply "super-user"
741  * privilege; if so, and we have accounting info, set the flag
742  * indicating use of super-powers.
743  * Returns 0 or error.
744  */
745 int
746 suser(cred, acflag)
747 	struct ucred *cred;
748 	u_short *acflag;
749 {
750 	if (cred->cr_uid == 0) {
751 		if (acflag)
752 			*acflag |= ASU;
753 		return (0);
754 	}
755 	return (EPERM);
756 }
757 
758 /*
759  * Allocate a zeroed cred structure.
760  */
761 struct ucred *
762 crget()
763 {
764 	struct ucred *cr;
765 
766 	cr = pool_get(&ucred_pool, PR_WAITOK);
767 	bzero((caddr_t)cr, sizeof(*cr));
768 	cr->cr_ref = 1;
769 	return (cr);
770 }
771 
772 /*
773  * Free a cred structure.
774  * Throws away space when ref count gets to 0.
775  */
776 void
777 crfree(cr)
778 	struct ucred *cr;
779 {
780 
781 	if (--cr->cr_ref == 0)
782 		pool_put(&ucred_pool, cr);
783 }
784 
785 /*
786  * Copy cred structure to a new one and free the old one.
787  */
788 struct ucred *
789 crcopy(cr)
790 	struct ucred *cr;
791 {
792 	struct ucred *newcr;
793 
794 	if (cr->cr_ref == 1)
795 		return (cr);
796 	newcr = crget();
797 	*newcr = *cr;
798 	crfree(cr);
799 	newcr->cr_ref = 1;
800 	return (newcr);
801 }
802 
803 /*
804  * Dup cred struct to a new held one.
805  */
806 struct ucred *
807 crdup(cr)
808 	struct ucred *cr;
809 {
810 	struct ucred *newcr;
811 
812 	newcr = crget();
813 	*newcr = *cr;
814 	newcr->cr_ref = 1;
815 	return (newcr);
816 }
817 
818 /*
819  * Get login name, if available.
820  */
821 /* ARGSUSED */
822 int
823 sys_getlogin(p, v, retval)
824 	struct proc *p;
825 	void *v;
826 	register_t *retval;
827 {
828 	struct sys_getlogin_args /* {
829 		syscallarg(char *) namebuf;
830 		syscallarg(u_int) namelen;
831 	} */ *uap = v;
832 
833 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
834 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
835 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
836 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
837 }
838 
839 /*
840  * Set login name.
841  */
842 /* ARGSUSED */
843 int
844 sys_setlogin(p, v, retval)
845 	struct proc *p;
846 	void *v;
847 	register_t *retval;
848 {
849 	struct sys_setlogin_args /* {
850 		syscallarg(char *) namebuf;
851 	} */ *uap = v;
852 	int error;
853 
854 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
855 		return (error);
856 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
857 	    (caddr_t) p->p_pgrp->pg_session->s_login,
858 	    sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0);
859 	if (error == ENAMETOOLONG)
860 		error = EINVAL;
861 	return (error);
862 }
863 
864 /*
865  * Check if a process is allowed to raise its privileges.
866  */
867 int
868 proc_cansugid(struct proc *p)
869 {
870 	/* ptrace(2)d processes shouldn't. */
871 	if ((p->p_flag & P_TRACED) != 0)
872 		return (0);
873 
874 	/* proceses with shared filedescriptors shouldn't. */
875 	if (p->p_fd->fd_refcnt > 1)
876 		return (0);
877 
878 	/* Allow. */
879 	return (1);
880 }
881