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