root/kern/kern_prot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_getpid
  2. sys_getthrid
  3. sys_getppid
  4. sys_getpgrp
  5. sys_getpgid
  6. sys_getsid
  7. sys_getuid
  8. sys_geteuid
  9. sys_issetugid
  10. sys_getgid
  11. sys_getegid
  12. sys_getgroups
  13. sys_setsid
  14. sys_setpgid
  15. sys_getresuid
  16. sys_setresuid
  17. sys_getresgid
  18. sys_setresgid
  19. sys_setregid
  20. sys_setreuid
  21. sys_setuid
  22. sys_seteuid
  23. sys_setgid
  24. sys_setegid
  25. sys_setgroups
  26. groupmember
  27. suser
  28. suser_ucred
  29. crget
  30. crfree
  31. crcopy
  32. crdup
  33. sys_getlogin
  34. sys_setlogin
  35. proc_cansugid

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

/* [<][>][^][v][top][bottom][index][help] */