Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / kern / kern_prot.c
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
58 static MALLOC_DEFINE(M_CRED, "cred", "credentials");
59
60 #ifndef _SYS_SYSPROTO_H_
61 struct getpid_args {
62         int     dummy;
63 };
64 #endif
65
66 /*
67  * NOT MP SAFE due to p_pptr access
68  */
69 /* ARGSUSED */
70 int
71 getpid(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_
84 struct getppid_args {
85         int     dummy;
86 };
87 #endif
88 /* ARGSUSED */
89 int
90 getppid(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_
105 struct getpgrp_args {
106         int     dummy;
107 };
108 #endif
109
110 int
111 getpgrp(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_
122 struct getpgid_args {
123         pid_t   pid;
124 };
125 #endif
126
127 int
128 getpgid(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;
140 found:
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_
149 struct getsid_args {
150         pid_t   pid;
151 };
152 #endif
153
154 int
155 getsid(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;
167 found:
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_
177 struct getuid_args {
178         int     dummy;
179 };
180 #endif
181
182 /* ARGSUSED */
183 int
184 getuid(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_
200 struct geteuid_args {
201         int     dummy;
202 };
203 #endif
204
205 /* ARGSUSED */
206 int
207 geteuid(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_
220 struct getgid_args {
221         int     dummy;
222 };
223 #endif
224
225 /* ARGSUSED */
226 int
227 getgid(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_
245 struct getegid_args {
246         int     dummy;
247 };
248 #endif
249
250 /* ARGSUSED */
251 int
252 getegid(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_
262 struct getgroups_args {
263         u_int   gidsetsize;
264         gid_t   *gidset;
265 };
266 #endif
267 int
268 getgroups(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_
291 struct setsid_args {
292         int     dummy;
293 };
294 #endif
295
296 /* ARGSUSED */
297 int
298 setsid(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_
326 struct setpgid_args {
327         int     pid;    /* target process id */
328         int     pgid;   /* target pgrp id */
329 };
330 #endif
331 /* ARGSUSED */
332 int
333 setpgid(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_
375 struct setuid_args {
376         uid_t   uid;
377 };
378 #endif
379 /* ARGSUSED */
380 int
381 setuid(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_
461 struct seteuid_args {
462         uid_t   euid;
463 };
464 #endif
465 /* ARGSUSED */
466 int
467 seteuid(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_
492 struct setgid_args {
493         gid_t   gid;
494 };
495 #endif
496 /* ARGSUSED */
497 int
498 setgid(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_
572 struct setegid_args {
573         gid_t   egid;
574 };
575 #endif
576 /* ARGSUSED */
577 int
578 setegid(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_
600 struct setgroups_args {
601         u_int   gidsetsize;
602         gid_t   *gidset;
603 };
604 #endif
605 /* ARGSUSED */
606 int
607 setgroups(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_
644 struct setreuid_args {
645         uid_t   ruid;
646         uid_t   euid;
647 };
648 #endif
649 /* ARGSUSED */
650 int
651 setreuid(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_
684 struct setregid_args {
685         gid_t   rgid;
686         gid_t   egid;
687 };
688 #endif
689 /* ARGSUSED */
690 int
691 setregid(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_
730 struct setresuid_args {
731         uid_t   ruid;
732         uid_t   euid;
733         uid_t   suid;
734 };
735 #endif
736 /* ARGSUSED */
737 int
738 setresuid(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_
778 struct setresgid_args {
779         gid_t   rgid;
780         gid_t   egid;
781         gid_t   sgid;
782 };
783 #endif
784 /* ARGSUSED */
785 int
786 setresgid(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_
823 struct getresuid_args {
824         uid_t   *ruid;
825         uid_t   *euid;
826         uid_t   *suid;
827 };
828 #endif
829 /* ARGSUSED */
830 int
831 getresuid(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_
851 struct getresgid_args {
852         gid_t   *rgid;
853         gid_t   *egid;
854         gid_t   *sgid;
855 };
856 #endif
857 /* ARGSUSED */
858 int
859 getresgid(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_
880 struct issetugid_args {
881         int dummy;
882 };
883 #endif
884 /* ARGSUSED */
885 int
886 issetugid(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  */
905 int
906 groupmember(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  */
926 int
927 suser(p)
928         struct proc *p;
929 {
930         return suser_xxx(0, p, 0);
931 }
932
933 int
934 suser_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
958 int
959 p_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  */
982 struct ucred *
983 crget()
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  */
996 void
997 crhold(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  */
1007 void
1008 crfree(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  */
1029 struct ucred *
1030 crcopy(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  */
1048 struct ucred *
1049 crdup(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  */
1064 void
1065 cru2x(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_
1081 struct getlogin_args {
1082         char    *namebuf;
1083         u_int   namelen;
1084 };
1085 #endif
1086 /* ARGSUSED */
1087 int
1088 getlogin(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_
1103 struct setlogin_args {
1104         char    *namebuf;
1105 };
1106 #endif
1107 /* ARGSUSED */
1108 int
1109 setlogin(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
1128 void
1129 setsugid(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  */
1140 void
1141 change_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  */
1166 void
1167 change_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 }