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