Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / kern / kern_prot.c
CommitLineData
984263bc
MD
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 * $FreeBSD: src/sys/kern/kern_prot.c,v 1.53.2.9 2002/03/09 05:20:26 dd Exp $
40 */
41
42/*
43 * System calls related to processes and protection
44 */
45
46#include "opt_compat.h"
47
48#include <sys/param.h>
49#include <sys/acct.h>
50#include <sys/systm.h>
51#include <sys/sysproto.h>
52#include <sys/kernel.h>
53#include <sys/proc.h>
54#include <sys/malloc.h>
55#include <sys/pioctl.h>
56#include <sys/resourcevar.h>
57
58static MALLOC_DEFINE(M_CRED, "cred", "credentials");
59
60#ifndef _SYS_SYSPROTO_H_
61struct getpid_args {
62 int dummy;
63};
64#endif
65
66/*
67 * NOT MP SAFE due to p_pptr access
68 */
69/* ARGSUSED */
70int
71getpid(p, uap)
72 struct proc *p;
73 struct getpid_args *uap;
74{
75
76 p->p_retval[0] = p->p_pid;
77#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
78 p->p_retval[1] = p->p_pptr->p_pid;
79#endif
80 return (0);
81}
82
83#ifndef _SYS_SYSPROTO_H_
84struct getppid_args {
85 int dummy;
86};
87#endif
88/* ARGSUSED */
89int
90getppid(p, uap)
91 struct proc *p;
92 struct getppid_args *uap;
93{
94
95 p->p_retval[0] = p->p_pptr->p_pid;
96 return (0);
97}
98
99/*
100 * Get process group ID; note that POSIX getpgrp takes no parameter
101 *
102 * MP SAFE
103 */
104#ifndef _SYS_SYSPROTO_H_
105struct getpgrp_args {
106 int dummy;
107};
108#endif
109
110int
111getpgrp(p, uap)
112 struct proc *p;
113 struct getpgrp_args *uap;
114{
115
116 p->p_retval[0] = p->p_pgrp->pg_id;
117 return (0);
118}
119
120/* Get an arbitary pid's process group id */
121#ifndef _SYS_SYSPROTO_H_
122struct getpgid_args {
123 pid_t pid;
124};
125#endif
126
127int
128getpgid(p, uap)
129 struct proc *p;
130 struct getpgid_args *uap;
131{
132 struct proc *pt;
133
134 pt = p;
135 if (uap->pid == 0)
136 goto found;
137
138 if ((pt = pfind(uap->pid)) == 0)
139 return ESRCH;
140found:
141 p->p_retval[0] = pt->p_pgrp->pg_id;
142 return 0;
143}
144
145/*
146 * Get an arbitary pid's session id.
147 */
148#ifndef _SYS_SYSPROTO_H_
149struct getsid_args {
150 pid_t pid;
151};
152#endif
153
154int
155getsid(p, uap)
156 struct proc *p;
157 struct getsid_args *uap;
158{
159 struct proc *pt;
160
161 pt = p;
162 if (uap->pid == 0)
163 goto found;
164
165 if ((pt = pfind(uap->pid)) == 0)
166 return ESRCH;
167found:
168 p->p_retval[0] = pt->p_session->s_sid;
169 return 0;
170}
171
172
173/*
174 * getuid() - MP SAFE
175 */
176#ifndef _SYS_SYSPROTO_H_
177struct getuid_args {
178 int dummy;
179};
180#endif
181
182/* ARGSUSED */
183int
184getuid(p, uap)
185 struct proc *p;
186 struct getuid_args *uap;
187{
188
189 p->p_retval[0] = p->p_cred->p_ruid;
190#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
191 p->p_retval[1] = p->p_ucred->cr_uid;
192#endif
193 return (0);
194}
195
196/*
197 * geteuid() - MP SAFE
198 */
199#ifndef _SYS_SYSPROTO_H_
200struct geteuid_args {
201 int dummy;
202};
203#endif
204
205/* ARGSUSED */
206int
207geteuid(p, uap)
208 struct proc *p;
209 struct geteuid_args *uap;
210{
211
212 p->p_retval[0] = p->p_ucred->cr_uid;
213 return (0);
214}
215
216/*
217 * getgid() - MP SAFE
218 */
219#ifndef _SYS_SYSPROTO_H_
220struct getgid_args {
221 int dummy;
222};
223#endif
224
225/* ARGSUSED */
226int
227getgid(p, uap)
228 struct proc *p;
229 struct getgid_args *uap;
230{
231
232 p->p_retval[0] = p->p_cred->p_rgid;
233#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
234 p->p_retval[1] = p->p_ucred->cr_groups[0];
235#endif
236 return (0);
237}
238
239/*
240 * Get effective group ID. The "egid" is groups[0], and could be obtained
241 * via getgroups. This syscall exists because it is somewhat painful to do
242 * correctly in a library function.
243 */
244#ifndef _SYS_SYSPROTO_H_
245struct getegid_args {
246 int dummy;
247};
248#endif
249
250/* ARGSUSED */
251int
252getegid(p, uap)
253 struct proc *p;
254 struct getegid_args *uap;
255{
256
257 p->p_retval[0] = p->p_ucred->cr_groups[0];
258 return (0);
259}
260
261#ifndef _SYS_SYSPROTO_H_
262struct getgroups_args {
263 u_int gidsetsize;
264 gid_t *gidset;
265};
266#endif
267int
268getgroups(p, uap)
269 struct proc *p;
270 register struct getgroups_args *uap;
271{
272 register struct pcred *pc = p->p_cred;
273 register u_int ngrp;
274 int error;
275
276 if ((ngrp = uap->gidsetsize) == 0) {
277 p->p_retval[0] = pc->pc_ucred->cr_ngroups;
278 return (0);
279 }
280 if (ngrp < pc->pc_ucred->cr_ngroups)
281 return (EINVAL);
282 ngrp = pc->pc_ucred->cr_ngroups;
283 if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
284 (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
285 return (error);
286 p->p_retval[0] = ngrp;
287 return (0);
288}
289
290#ifndef _SYS_SYSPROTO_H_
291struct setsid_args {
292 int dummy;
293};
294#endif
295
296/* ARGSUSED */
297int
298setsid(p, uap)
299 register struct proc *p;
300 struct setsid_args *uap;
301{
302
303 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
304 return (EPERM);
305 } else {
306 (void)enterpgrp(p, p->p_pid, 1);
307 p->p_retval[0] = p->p_pid;
308 return (0);
309 }
310}
311
312/*
313 * set process group (setpgid/old setpgrp)
314 *
315 * caller does setpgid(targpid, targpgid)
316 *
317 * pid must be caller or child of caller (ESRCH)
318 * if a child
319 * pid must be in same session (EPERM)
320 * pid can't have done an exec (EACCES)
321 * if pgid != pid
322 * there must exist some pid in same session having pgid (EPERM)
323 * pid must not be session leader (EPERM)
324 */
325#ifndef _SYS_SYSPROTO_H_
326struct setpgid_args {
327 int pid; /* target process id */
328 int pgid; /* target pgrp id */
329};
330#endif
331/* ARGSUSED */
332int
333setpgid(curp, uap)
334 struct proc *curp;
335 register struct setpgid_args *uap;
336{
337 register struct proc *targp; /* target process */
338 register struct pgrp *pgrp; /* target pgrp */
339
340 if (uap->pgid < 0)
341 return (EINVAL);
342 if (uap->pid != 0 && uap->pid != curp->p_pid) {
343 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
344 return (ESRCH);
345 if (targp->p_pgrp == NULL || targp->p_session != curp->p_session)
346 return (EPERM);
347 if (targp->p_flag & P_EXEC)
348 return (EACCES);
349 } else
350 targp = curp;
351 if (SESS_LEADER(targp))
352 return (EPERM);
353 if (uap->pgid == 0)
354 uap->pgid = targp->p_pid;
355 else if (uap->pgid != targp->p_pid)
356 if ((pgrp = pgfind(uap->pgid)) == 0 ||
357 pgrp->pg_session != curp->p_session)
358 return (EPERM);
359 return (enterpgrp(targp, uap->pgid, 0));
360}
361
362/*
363 * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
364 * compatable. It says that setting the uid/gid to euid/egid is a special
365 * case of "appropriate privilege". Once the rules are expanded out, this
366 * basically means that setuid(nnn) sets all three id's, in all permitted
367 * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid())
368 * does not set the saved id - this is dangerous for traditional BSD
369 * programs. For this reason, we *really* do not want to set
370 * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
371 */
372#define POSIX_APPENDIX_B_4_2_2
373
374#ifndef _SYS_SYSPROTO_H_
375struct setuid_args {
376 uid_t uid;
377};
378#endif
379/* ARGSUSED */
380int
381setuid(p, uap)
382 struct proc *p;
383 struct setuid_args *uap;
384{
385 register struct pcred *pc = p->p_cred;
386 register uid_t uid;
387 int error;
388
389 /*
390 * See if we have "permission" by POSIX 1003.1 rules.
391 *
392 * Note that setuid(geteuid()) is a special case of
393 * "appropriate privileges" in appendix B.4.2.2. We need
394 * to use this clause to be compatable with traditional BSD
395 * semantics. Basically, it means that "setuid(xx)" sets all
396 * three id's (assuming you have privs).
397 *
398 * Notes on the logic. We do things in three steps.
399 * 1: We determine if the euid is going to change, and do EPERM
400 * right away. We unconditionally change the euid later if this
401 * test is satisfied, simplifying that part of the logic.
402 * 2: We determine if the real and/or saved uid's are going to
403 * change. Determined by compile options.
404 * 3: Change euid last. (after tests in #2 for "appropriate privs")
405 */
406 uid = uap->uid;
407 if (uid != pc->p_ruid && /* allow setuid(getuid()) */
408#ifdef _POSIX_SAVED_IDS
409 uid != pc->p_svuid && /* allow setuid(saved gid) */
410#endif
411#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */
412 uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */
413#endif
414 (error = suser_xxx(0, p, PRISON_ROOT)))
415 return (error);
416
417#ifdef _POSIX_SAVED_IDS
418 /*
419 * Do we have "appropriate privileges" (are we root or uid == euid)
420 * If so, we are changing the real uid and/or saved uid.
421 */
422 if (
423#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */
424 uid == pc->pc_ucred->cr_uid ||
425#endif
426 suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
427#endif
428 {
429 /*
430 * Set the real uid and transfer proc count to new user.
431 */
432 if (uid != pc->p_ruid) {
433 change_ruid(p, uid);
434 setsugid(p);
435 }
436 /*
437 * Set saved uid
438 *
439 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
440 * the security of seteuid() depends on it. B.4.2.2 says it
441 * is important that we should do this.
442 */
443 if (pc->p_svuid != uid) {
444 pc->p_svuid = uid;
445 setsugid(p);
446 }
447 }
448
449 /*
450 * In all permitted cases, we are changing the euid.
451 * Copy credentials so other references do not see our changes.
452 */
453 if (pc->pc_ucred->cr_uid != uid) {
454 change_euid(p, uid);
455 setsugid(p);
456 }
457 return (0);
458}
459
460#ifndef _SYS_SYSPROTO_H_
461struct seteuid_args {
462 uid_t euid;
463};
464#endif
465/* ARGSUSED */
466int
467seteuid(p, uap)
468 struct proc *p;
469 struct seteuid_args *uap;
470{
471 register struct pcred *pc = p->p_cred;
472 register uid_t euid;
473 int error;
474
475 euid = uap->euid;
476 if (euid != pc->p_ruid && /* allow seteuid(getuid()) */
477 euid != pc->p_svuid && /* allow seteuid(saved uid) */
478 (error = suser_xxx(0, p, PRISON_ROOT)))
479 return (error);
480 /*
481 * Everything's okay, do it. Copy credentials so other references do
482 * not see our changes.
483 */
484 if (pc->pc_ucred->cr_uid != euid) {
485 change_euid(p, euid);
486 setsugid(p);
487 }
488 return (0);
489}
490
491#ifndef _SYS_SYSPROTO_H_
492struct setgid_args {
493 gid_t gid;
494};
495#endif
496/* ARGSUSED */
497int
498setgid(p, uap)
499 struct proc *p;
500 struct setgid_args *uap;
501{
502 register struct pcred *pc = p->p_cred;
503 register gid_t gid;
504 int error;
505
506 /*
507 * See if we have "permission" by POSIX 1003.1 rules.
508 *
509 * Note that setgid(getegid()) is a special case of
510 * "appropriate privileges" in appendix B.4.2.2. We need
511 * to use this clause to be compatable with traditional BSD
512 * semantics. Basically, it means that "setgid(xx)" sets all
513 * three id's (assuming you have privs).
514 *
515 * For notes on the logic here, see setuid() above.
516 */
517 gid = uap->gid;
518 if (gid != pc->p_rgid && /* allow setgid(getgid()) */
519#ifdef _POSIX_SAVED_IDS
520 gid != pc->p_svgid && /* allow setgid(saved gid) */
521#endif
522#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */
523 gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
524#endif
525 (error = suser_xxx(0, p, PRISON_ROOT)))
526 return (error);
527
528#ifdef _POSIX_SAVED_IDS
529 /*
530 * Do we have "appropriate privileges" (are we root or gid == egid)
531 * If so, we are changing the real uid and saved gid.
532 */
533 if (
534#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */
535 gid == pc->pc_ucred->cr_groups[0] ||
536#endif
537 suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
538#endif
539 {
540 /*
541 * Set real gid
542 */
543 if (pc->p_rgid != gid) {
544 pc->p_rgid = gid;
545 setsugid(p);
546 }
547 /*
548 * Set saved gid
549 *
550 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
551 * the security of setegid() depends on it. B.4.2.2 says it
552 * is important that we should do this.
553 */
554 if (pc->p_svgid != gid) {
555 pc->p_svgid = gid;
556 setsugid(p);
557 }
558 }
559 /*
560 * In all cases permitted cases, we are changing the egid.
561 * Copy credentials so other references do not see our changes.
562 */
563 if (pc->pc_ucred->cr_groups[0] != gid) {
564 pc->pc_ucred = crcopy(pc->pc_ucred);
565 pc->pc_ucred->cr_groups[0] = gid;
566 setsugid(p);
567 }
568 return (0);
569}
570
571#ifndef _SYS_SYSPROTO_H_
572struct setegid_args {
573 gid_t egid;
574};
575#endif
576/* ARGSUSED */
577int
578setegid(p, uap)
579 struct proc *p;
580 struct setegid_args *uap;
581{
582 register struct pcred *pc = p->p_cred;
583 register gid_t egid;
584 int error;
585
586 egid = uap->egid;
587 if (egid != pc->p_rgid && /* allow setegid(getgid()) */
588 egid != pc->p_svgid && /* allow setegid(saved gid) */
589 (error = suser_xxx(0, p, PRISON_ROOT)))
590 return (error);
591 if (pc->pc_ucred->cr_groups[0] != egid) {
592 pc->pc_ucred = crcopy(pc->pc_ucred);
593 pc->pc_ucred->cr_groups[0] = egid;
594 setsugid(p);
595 }
596 return (0);
597}
598
599#ifndef _SYS_SYSPROTO_H_
600struct setgroups_args {
601 u_int gidsetsize;
602 gid_t *gidset;
603};
604#endif
605/* ARGSUSED */
606int
607setgroups(p, uap)
608 struct proc *p;
609 struct setgroups_args *uap;
610{
611 register struct pcred *pc = p->p_cred;
612 register u_int ngrp;
613 int error;
614
615 if ((error = suser_xxx(0, p, PRISON_ROOT)))
616 return (error);
617 ngrp = uap->gidsetsize;
618 if (ngrp > NGROUPS)
619 return (EINVAL);
620 /*
621 * XXX A little bit lazy here. We could test if anything has
622 * changed before crcopy() and setting P_SUGID.
623 */
624 pc->pc_ucred = crcopy(pc->pc_ucred);
625 if (ngrp < 1) {
626 /*
627 * setgroups(0, NULL) is a legitimate way of clearing the
628 * groups vector on non-BSD systems (which generally do not
629 * have the egid in the groups[0]). We risk security holes
630 * when running non-BSD software if we do not do the same.
631 */
632 pc->pc_ucred->cr_ngroups = 1;
633 } else {
634 if ((error = copyin((caddr_t)uap->gidset,
635 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
636 return (error);
637 pc->pc_ucred->cr_ngroups = ngrp;
638 }
639 setsugid(p);
640 return (0);
641}
642
643#ifndef _SYS_SYSPROTO_H_
644struct setreuid_args {
645 uid_t ruid;
646 uid_t euid;
647};
648#endif
649/* ARGSUSED */
650int
651setreuid(p, uap)
652 register struct proc *p;
653 struct setreuid_args *uap;
654{
655 register struct pcred *pc = p->p_cred;
656 register uid_t ruid, euid;
657 int error;
658
659 ruid = uap->ruid;
660 euid = uap->euid;
661 if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
662 (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
663 euid != pc->p_ruid && euid != pc->p_svuid)) &&
664 (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
665 return (error);
666
667 if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
668 change_euid(p, euid);
669 setsugid(p);
670 }
671 if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
672 change_ruid(p, ruid);
673 setsugid(p);
674 }
675 if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
676 pc->p_svuid != pc->pc_ucred->cr_uid) {
677 pc->p_svuid = pc->pc_ucred->cr_uid;
678 setsugid(p);
679 }
680 return (0);
681}
682
683#ifndef _SYS_SYSPROTO_H_
684struct setregid_args {
685 gid_t rgid;
686 gid_t egid;
687};
688#endif
689/* ARGSUSED */
690int
691setregid(p, uap)
692 register struct proc *p;
693 struct setregid_args *uap;
694{
695 register struct pcred *pc = p->p_cred;
696 register gid_t rgid, egid;
697 int error;
698
699 rgid = uap->rgid;
700 egid = uap->egid;
701 if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
702 (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
703 egid != pc->p_rgid && egid != pc->p_svgid)) &&
704 (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
705 return (error);
706
707 if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
708 pc->pc_ucred = crcopy(pc->pc_ucred);
709 pc->pc_ucred->cr_groups[0] = egid;
710 setsugid(p);
711 }
712 if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
713 pc->p_rgid = rgid;
714 setsugid(p);
715 }
716 if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
717 pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
718 pc->p_svgid = pc->pc_ucred->cr_groups[0];
719 setsugid(p);
720 }
721 return (0);
722}
723
724/*
725 * setresuid(ruid, euid, suid) is like setreuid except control over the
726 * saved uid is explicit.
727 */
728
729#ifndef _SYS_SYSPROTO_H_
730struct setresuid_args {
731 uid_t ruid;
732 uid_t euid;
733 uid_t suid;
734};
735#endif
736/* ARGSUSED */
737int
738setresuid(p, uap)
739 register struct proc *p;
740 struct setresuid_args *uap;
741{
742 register struct pcred *pc = p->p_cred;
743 register uid_t ruid, euid, suid;
744 int error;
745
746 ruid = uap->ruid;
747 euid = uap->euid;
748 suid = uap->suid;
749 if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
750 ruid != pc->pc_ucred->cr_uid) ||
751 (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
752 euid != pc->pc_ucred->cr_uid) ||
753 (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
754 suid != pc->pc_ucred->cr_uid)) &&
755 (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
756 return (error);
757 if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
758 change_euid(p, euid);
759 setsugid(p);
760 }
761 if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
762 change_ruid(p, ruid);
763 setsugid(p);
764 }
765 if (suid != (uid_t)-1 && pc->p_svuid != suid) {
766 pc->p_svuid = suid;
767 setsugid(p);
768 }
769 return (0);
770}
771
772/*
773 * setresgid(rgid, egid, sgid) is like setregid except control over the
774 * saved gid is explicit.
775 */
776
777#ifndef _SYS_SYSPROTO_H_
778struct setresgid_args {
779 gid_t rgid;
780 gid_t egid;
781 gid_t sgid;
782};
783#endif
784/* ARGSUSED */
785int
786setresgid(p, uap)
787 register struct proc *p;
788 struct setresgid_args *uap;
789{
790 register struct pcred *pc = p->p_cred;
791 register gid_t rgid, egid, sgid;
792 int error;
793
794 rgid = uap->rgid;
795 egid = uap->egid;
796 sgid = uap->sgid;
797 if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
798 rgid != pc->pc_ucred->cr_groups[0]) ||
799 (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
800 egid != pc->pc_ucred->cr_groups[0]) ||
801 (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
802 sgid != pc->pc_ucred->cr_groups[0])) &&
803 (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
804 return (error);
805
806 if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
807 pc->pc_ucred = crcopy(pc->pc_ucred);
808 pc->pc_ucred->cr_groups[0] = egid;
809 setsugid(p);
810 }
811 if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
812 pc->p_rgid = rgid;
813 setsugid(p);
814 }
815 if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
816 pc->p_svgid = sgid;
817 setsugid(p);
818 }
819 return (0);
820}
821
822#ifndef _SYS_SYSPROTO_H_
823struct getresuid_args {
824 uid_t *ruid;
825 uid_t *euid;
826 uid_t *suid;
827};
828#endif
829/* ARGSUSED */
830int
831getresuid(p, uap)
832 register struct proc *p;
833 struct getresuid_args *uap;
834{
835 struct pcred *pc = p->p_cred;
836 int error1 = 0, error2 = 0, error3 = 0;
837
838 if (uap->ruid)
839 error1 = copyout((caddr_t)&pc->p_ruid,
840 (caddr_t)uap->ruid, sizeof(pc->p_ruid));
841 if (uap->euid)
842 error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
843 (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
844 if (uap->suid)
845 error3 = copyout((caddr_t)&pc->p_svuid,
846 (caddr_t)uap->suid, sizeof(pc->p_svuid));
847 return error1 ? error1 : (error2 ? error2 : error3);
848}
849
850#ifndef _SYS_SYSPROTO_H_
851struct getresgid_args {
852 gid_t *rgid;
853 gid_t *egid;
854 gid_t *sgid;
855};
856#endif
857/* ARGSUSED */
858int
859getresgid(p, uap)
860 register struct proc *p;
861 struct getresgid_args *uap;
862{
863 struct pcred *pc = p->p_cred;
864 int error1 = 0, error2 = 0, error3 = 0;
865
866 if (uap->rgid)
867 error1 = copyout((caddr_t)&pc->p_rgid,
868 (caddr_t)uap->rgid, sizeof(pc->p_rgid));
869 if (uap->egid)
870 error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
871 (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
872 if (uap->sgid)
873 error3 = copyout((caddr_t)&pc->p_svgid,
874 (caddr_t)uap->sgid, sizeof(pc->p_svgid));
875 return error1 ? error1 : (error2 ? error2 : error3);
876}
877
878
879#ifndef _SYS_SYSPROTO_H_
880struct issetugid_args {
881 int dummy;
882};
883#endif
884/* ARGSUSED */
885int
886issetugid(p, uap)
887 register struct proc *p;
888 struct issetugid_args *uap;
889{
890 /*
891 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
892 * we use P_SUGID because we consider changing the owners as
893 * "tainting" as well.
894 * This is significant for procs that start as root and "become"
895 * a user without an exec - programs cannot know *everything*
896 * that libc *might* have put in their data segment.
897 */
898 p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
899 return (0);
900}
901
902/*
903 * Check if gid is a member of the group set.
904 */
905int
906groupmember(gid, cred)
907 gid_t gid;
908 register struct ucred *cred;
909{
910 register gid_t *gp;
911 gid_t *egp;
912
913 egp = &(cred->cr_groups[cred->cr_ngroups]);
914 for (gp = cred->cr_groups; gp < egp; gp++)
915 if (*gp == gid)
916 return (1);
917 return (0);
918}
919
920/*
921 * Test whether the specified credentials imply "super-user"
922 * privilege; if so, and we have accounting info, set the flag
923 * indicating use of super-powers.
924 * Returns 0 or error.
925 */
926int
927suser(p)
928 struct proc *p;
929{
930 return suser_xxx(0, p, 0);
931}
932
933int
934suser_xxx(cred, proc, flag)
935 struct ucred *cred;
936 struct proc *proc;
937 int flag;
938{
939 if (!cred && !proc) {
940 printf("suser_xxx(): THINK!\n");
941 return (EPERM);
942 }
943 if (!cred)
944 cred = proc->p_ucred;
945 if (cred->cr_uid != 0)
946 return (EPERM);
947 if (proc && proc->p_prison && !(flag & PRISON_ROOT))
948 return (EPERM);
949 if (proc)
950 proc->p_acflag |= ASU;
951 return (0);
952}
953
954/*
955 * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise.
956 */
957
958int
959p_trespass(struct proc *p1, struct proc *p2)
960{
961
962 if (p1 == p2)
963 return (0);
964 if (!PRISON_CHECK(p1, p2))
965 return (ESRCH);
966 if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
967 return (0);
968 if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
969 return (0);
970 if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
971 return (0);
972 if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
973 return (0);
974 if (!suser_xxx(0, p1, PRISON_ROOT))
975 return (0);
976 return (EPERM);
977}
978
979/*
980 * Allocate a zeroed cred structure.
981 */
982struct ucred *
983crget()
984{
985 register struct ucred *cr;
986
987 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
988 bzero((caddr_t)cr, sizeof(*cr));
989 cr->cr_ref = 1;
990 return (cr);
991}
992
993/*
994 * Claim another reference to a ucred structure
995 */
996void
997crhold(cr)
998 struct ucred *cr;
999{
1000 cr->cr_ref++;
1001}
1002
1003/*
1004 * Free a cred structure.
1005 * Throws away space when ref count gets to 0.
1006 */
1007void
1008crfree(cr)
1009 struct ucred *cr;
1010{
1011 if (cr->cr_ref == 0)
1012 panic("Freeing already free credential! %p", cr);
1013
1014 if (--cr->cr_ref == 0) {
1015 /*
1016 * Some callers of crget(), such as nfs_statfs(),
1017 * allocate a temporary credential, but don't
1018 * allocate a uidinfo structure.
1019 */
1020 if (cr->cr_uidinfo != NULL)
1021 uifree(cr->cr_uidinfo);
1022 FREE((caddr_t)cr, M_CRED);
1023 }
1024}
1025
1026/*
1027 * Copy cred structure to a new one and free the old one.
1028 */
1029struct ucred *
1030crcopy(cr)
1031 struct ucred *cr;
1032{
1033 struct ucred *newcr;
1034
1035 if (cr->cr_ref == 1)
1036 return (cr);
1037 newcr = crget();
1038 *newcr = *cr;
1039 uihold(newcr->cr_uidinfo);
1040 crfree(cr);
1041 newcr->cr_ref = 1;
1042 return (newcr);
1043}
1044
1045/*
1046 * Dup cred struct to a new held one.
1047 */
1048struct ucred *
1049crdup(cr)
1050 struct ucred *cr;
1051{
1052 struct ucred *newcr;
1053
1054 newcr = crget();
1055 *newcr = *cr;
1056 uihold(newcr->cr_uidinfo);
1057 newcr->cr_ref = 1;
1058 return (newcr);
1059}
1060
1061/*
1062 * Fill in a struct xucred based on a struct ucred.
1063 */
1064void
1065cru2x(cr, xcr)
1066 struct ucred *cr;
1067 struct xucred *xcr;
1068{
1069
1070 bzero(xcr, sizeof(*xcr));
1071 xcr->cr_version = XUCRED_VERSION;
1072 xcr->cr_uid = cr->cr_uid;
1073 xcr->cr_ngroups = cr->cr_ngroups;
1074 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
1075}
1076
1077/*
1078 * Get login name, if available.
1079 */
1080#ifndef _SYS_SYSPROTO_H_
1081struct getlogin_args {
1082 char *namebuf;
1083 u_int namelen;
1084};
1085#endif
1086/* ARGSUSED */
1087int
1088getlogin(p, uap)
1089 struct proc *p;
1090 struct getlogin_args *uap;
1091{
1092
1093 if (uap->namelen > MAXLOGNAME)
1094 uap->namelen = MAXLOGNAME;
1095 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
1096 (caddr_t) uap->namebuf, uap->namelen));
1097}
1098
1099/*
1100 * Set login name.
1101 */
1102#ifndef _SYS_SYSPROTO_H_
1103struct setlogin_args {
1104 char *namebuf;
1105};
1106#endif
1107/* ARGSUSED */
1108int
1109setlogin(p, uap)
1110 struct proc *p;
1111 struct setlogin_args *uap;
1112{
1113 int error;
1114 char logintmp[MAXLOGNAME];
1115
1116 if ((error = suser_xxx(0, p, PRISON_ROOT)))
1117 return (error);
1118 error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
1119 sizeof(logintmp), (size_t *)0);
1120 if (error == ENAMETOOLONG)
1121 error = EINVAL;
1122 else if (!error)
1123 (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
1124 sizeof(logintmp));
1125 return (error);
1126}
1127
1128void
1129setsugid(p)
1130 struct proc *p;
1131{
1132 p->p_flag |= P_SUGID;
1133 if (!(p->p_pfsflags & PF_ISUGID))
1134 p->p_stops = 0;
1135}
1136
1137/*
1138 * Helper function to change the effective uid of a process
1139 */
1140void
1141change_euid(p, euid)
1142 struct proc *p;
1143 uid_t euid;
1144{
1145 struct pcred *pc;
1146 struct uidinfo *uip;
1147
1148 pc = p->p_cred;
1149 /*
1150 * crcopy is essentially a NOP if ucred has a reference count
1151 * of 1, which is true if it has already been copied.
1152 */
1153 pc->pc_ucred = crcopy(pc->pc_ucred);
1154 uip = pc->pc_ucred->cr_uidinfo;
1155 pc->pc_ucred->cr_uid = euid;
1156 pc->pc_ucred->cr_uidinfo = uifind(euid);
1157 uifree(uip);
1158}
1159
1160/*
1161 * Helper function to change the real uid of a process
1162 *
1163 * The per-uid process count for this process is transfered from
1164 * the old uid to the new uid.
1165 */
1166void
1167change_ruid(p, ruid)
1168 struct proc *p;
1169 uid_t ruid;
1170{
1171 struct pcred *pc;
1172 struct uidinfo *uip;
1173
1174 pc = p->p_cred;
1175 (void)chgproccnt(pc->p_uidinfo, -1, 0);
1176 uip = pc->p_uidinfo;
1177 /* It is assumed that pcred is not shared between processes */
1178 pc->p_ruid = ruid;
1179 pc->p_uidinfo = uifind(ruid);
1180 (void)chgproccnt(pc->p_uidinfo, 1, 0);
1181 uifree(uip);
1182}