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