The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_prot.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: kern_prot.c,v 1.37 2008/11/01 05:59:21 deraadt 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         struct session *newsess;
  237         struct pgrp *newpgrp;
  238 
  239         newsess = pool_get(&session_pool, PR_WAITOK);
  240         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
  241 
  242         if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
  243                 pool_put(&pgrp_pool, newpgrp);
  244                 pool_put(&session_pool, newsess);
  245                 return (EPERM);
  246         } else {
  247                 (void) enterpgrp(p, p->p_pid, newpgrp, newsess);
  248                 *retval = p->p_pid;
  249                 return (0);
  250         }
  251 }
  252 
  253 /*
  254  * set process group (setpgid/old setpgrp)
  255  *
  256  * caller does setpgid(targpid, targpgid)
  257  *
  258  * pid must be caller or child of caller (ESRCH)
  259  * if a child
  260  *      pid must be in same session (EPERM)
  261  *      pid can't have done an exec (EACCES)
  262  * if pgid != pid
  263  *      there must exist some pid in same session having pgid (EPERM)
  264  * pid must not be session leader (EPERM)
  265  */
  266 /* ARGSUSED */
  267 int
  268 sys_setpgid(struct proc *curp, void *v, register_t *retval)
  269 {
  270         struct sys_setpgid_args /* {
  271                 syscallarg(pid_t) pid;
  272                 syscallarg(int) pgid;
  273         } */ *uap = v;
  274         struct proc *targp;             /* target process */
  275         struct pgrp *pgrp, *newpgrp;    /* target pgrp */
  276         pid_t pid;
  277         int pgid, error;
  278 
  279         pid = SCARG(uap, pid);
  280         pgid = SCARG(uap, pgid);
  281 
  282         if (pgid < 0)
  283                 return (EINVAL);
  284 
  285         newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
  286 
  287         if (pid != 0 && pid != curp->p_pid) {
  288                 if ((targp = pfind(pid)) == 0 || !inferior(targp)) {
  289                         error = ESRCH;
  290                         goto out;
  291                 }
  292                 if (targp->p_session != curp->p_session) {
  293                         error = EPERM;
  294                         goto out;
  295                 }
  296                 if (targp->p_flag & P_EXEC) {
  297                         error = EACCES;
  298                         goto out;
  299                 }
  300         } else
  301                 targp = curp;
  302         if (SESS_LEADER(targp)) {
  303                 error = EPERM;
  304                 goto out;
  305         }
  306         if (pgid == 0)
  307                 pgid = targp->p_pid;
  308         else if (pgid != targp->p_pid)
  309                 if ((pgrp = pgfind(pgid)) == 0 ||
  310                     pgrp->pg_session != curp->p_session) {
  311                         error = EPERM;
  312                         goto out;
  313                 }
  314         return (enterpgrp(targp, pgid, newpgrp, NULL));
  315 out:
  316         pool_put(&pgrp_pool, newpgrp);
  317         return (error);
  318 }
  319 
  320 /* ARGSUSED */
  321 int
  322 sys_getresuid(struct proc *p, void *v, register_t *retval)
  323 {
  324         struct sys_getresuid_args /* {
  325                 syscallarg(uid_t *) ruid;
  326                 syscallarg(uid_t *) euid;
  327                 syscallarg(uid_t *) suid;
  328         } */ *uap = v;
  329         struct pcred *pc = p->p_cred;
  330         uid_t *ruid, *euid, *suid;
  331         int error1 = 0, error2 = 0, error3 = 0;
  332 
  333         ruid = SCARG(uap, ruid);
  334         euid = SCARG(uap, euid);
  335         suid = SCARG(uap, suid);
  336 
  337         if (ruid != NULL)
  338                 error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid));
  339         if (euid != NULL)
  340                 error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid));
  341         if (suid != NULL)
  342                 error3 = copyout(&pc->p_svuid, suid, sizeof(*suid));
  343 
  344         return (error1 ? error1 : error2 ? error2 : error3);
  345 }
  346 
  347 /* ARGSUSED */
  348 int
  349 sys_setresuid(struct proc *p, void *v, register_t *retval)
  350 {
  351         struct sys_setresuid_args /* {
  352                 syscallarg(uid_t) ruid;
  353                 syscallarg(uid_t) euid;
  354                 syscallarg(uid_t) suid;
  355         } */ *uap = v;
  356         struct pcred *pc = p->p_cred;
  357         uid_t ruid, euid, suid;
  358         int error;
  359 
  360         ruid = SCARG(uap, ruid);
  361         euid = SCARG(uap, euid);
  362         suid = SCARG(uap, suid);
  363 
  364         if ((ruid == -1 || ruid == pc->p_ruid) &&
  365             (euid == -1 || euid == pc->pc_ucred->cr_uid) &&
  366             (suid == -1 || suid == pc->p_svuid))
  367                 return (0);                     /* no change */
  368 
  369         /*
  370          * Any of the real, effective, and saved uids may be changed
  371          * to the current value of one of the three (root is not limited).
  372          */
  373         if (ruid != (uid_t)-1 &&
  374             ruid != pc->p_ruid &&
  375             ruid != pc->pc_ucred->cr_uid &&
  376             ruid != pc->p_svuid &&
  377             (error = suser(p, 0)))
  378                 return (error);
  379 
  380         if (euid != (uid_t)-1 &&
  381             euid != pc->p_ruid &&
  382             euid != pc->pc_ucred->cr_uid &&
  383             euid != pc->p_svuid &&
  384             (error = suser(p, 0)))
  385                 return (error);
  386 
  387         if (suid != (uid_t)-1 &&
  388             suid != pc->p_ruid &&
  389             suid != pc->pc_ucred->cr_uid &&
  390             suid != pc->p_svuid &&
  391             (error = suser(p, 0)))
  392                 return (error);
  393 
  394         /*
  395          * Note that unlike the other set*uid() calls, each
  396          * uid type is set independently of the others.
  397          */
  398         if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
  399                 /*
  400                  * Transfer proc count to new user.
  401                  */
  402                 (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt);
  403                 (void)chgproccnt(ruid, p->p_p->ps_refcnt);
  404                 pc->p_ruid = ruid;
  405         }
  406         if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
  407                 /*
  408                  * Copy credentials so other references do not see our changes.
  409                  */
  410                 pc->pc_ucred = crcopy(pc->pc_ucred);
  411                 pc->pc_ucred->cr_uid = euid;
  412         }
  413         if (suid != (uid_t)-1 && suid != pc->p_svuid)
  414                 pc->p_svuid = suid;
  415 
  416         atomic_setbits_int(&p->p_flag, P_SUGID);
  417         return (0);
  418 }
  419 
  420 /* ARGSUSED */
  421 int
  422 sys_getresgid(struct proc *p, void *v, register_t *retval)
  423 {
  424         struct sys_getresgid_args /* {
  425                 syscallarg(gid_t *) rgid;
  426                 syscallarg(gid_t *) egid;
  427                 syscallarg(gid_t *) sgid;
  428         } */ *uap = v;
  429         struct pcred *pc = p->p_cred;
  430         gid_t *rgid, *egid, *sgid;
  431         int error1 = 0, error2 = 0, error3 = 0;
  432 
  433         rgid = SCARG(uap, rgid);
  434         egid = SCARG(uap, egid);
  435         sgid = SCARG(uap, sgid);
  436 
  437         if (rgid != NULL)
  438                 error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid));
  439         if (egid != NULL)
  440                 error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid));
  441         if (sgid != NULL)
  442                 error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid));
  443 
  444         return (error1 ? error1 : error2 ? error2 : error3);
  445 }
  446 
  447 /* ARGSUSED */
  448 int
  449 sys_setresgid(struct proc *p, void *v, register_t *retval)
  450 {
  451         struct sys_setresgid_args /* {
  452                 syscallarg(gid_t) rgid;
  453                 syscallarg(gid_t) egid;
  454                 syscallarg(gid_t) sgid;
  455         } */ *uap = v;
  456         struct pcred *pc = p->p_cred;
  457         gid_t rgid, egid, sgid;
  458         int error;
  459 
  460         rgid = SCARG(uap, rgid);
  461         egid = SCARG(uap, egid);
  462         sgid = SCARG(uap, sgid);
  463 
  464         if ((rgid == -1 || rgid == pc->p_rgid) &&
  465             (egid == -1 || egid == pc->pc_ucred->cr_gid) &&
  466             (sgid == -1 || sgid == pc->p_svgid))
  467                 return (0);                     /* no change */
  468 
  469         /*
  470          * Any of the real, effective, and saved gids may be changed
  471          * to the current value of one of the three (root is not limited).
  472          */
  473         if (rgid != (gid_t)-1 &&
  474             rgid != pc->p_rgid &&
  475             rgid != pc->pc_ucred->cr_gid &&
  476             rgid != pc->p_svgid &&
  477             (error = suser(p, 0)))
  478                 return (error);
  479 
  480         if (egid != (gid_t)-1 &&
  481             egid != pc->p_rgid &&
  482             egid != pc->pc_ucred->cr_gid &&
  483             egid != pc->p_svgid &&
  484             (error = suser(p, 0)))
  485                 return (error);
  486 
  487         if (sgid != (gid_t)-1 &&
  488             sgid != pc->p_rgid &&
  489             sgid != pc->pc_ucred->cr_gid &&
  490             sgid != pc->p_svgid &&
  491             (error = suser(p, 0)))
  492                 return (error);
  493 
  494         /*
  495          * Note that unlike the other set*gid() calls, each
  496          * gid type is set independently of the others.
  497          */
  498         if (rgid != (gid_t)-1)
  499                 pc->p_rgid = rgid;
  500         if (egid != (gid_t)-1) {
  501                 /*
  502                  * Copy credentials so other references do not see our changes.
  503                  */
  504                 pc->pc_ucred = crcopy(pc->pc_ucred);
  505                 pc->pc_ucred->cr_gid = egid;
  506         }
  507         if (sgid != (gid_t)-1)
  508                 pc->p_svgid = sgid;
  509 
  510         atomic_setbits_int(&p->p_flag, P_SUGID);
  511         return (0);
  512 }
  513 
  514 /* ARGSUSED */
  515 int
  516 sys_setregid(struct proc *p, void *v, register_t *retval)
  517 {
  518         struct sys_setregid_args /* {
  519                 syscallarg(gid_t) rgid;
  520                 syscallarg(gid_t) egid;
  521         } */ *uap = v;
  522         struct pcred *pc = p->p_cred;
  523         struct sys_setresgid_args sresgidargs;
  524         gid_t rgid, egid;
  525 
  526         rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid);
  527         egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid);
  528 
  529         /*
  530          * The saved gid presents a bit of a dilemma, as it did not
  531          * exist when setregid(2) was conceived.  We only set the saved
  532          * gid when the real gid is specified and either its value would
  533          * change, or where the saved and effective gids are different.
  534          */
  535         if (rgid != (gid_t)-1 && (rgid != pc->p_rgid ||
  536             pc->p_svgid != (egid != (gid_t)-1 ? egid : pc->pc_ucred->cr_gid)))
  537                 SCARG(&sresgidargs, sgid) = rgid;
  538         else
  539                 SCARG(&sresgidargs, sgid) = (gid_t)-1;
  540 
  541         return (sys_setresgid(p, &sresgidargs, retval));
  542 }
  543 
  544 /* ARGSUSED */
  545 int
  546 sys_setreuid(struct proc *p, void *v, register_t *retval)
  547 {
  548         struct sys_setreuid_args /* {
  549                 syscallarg(uid_t) ruid;
  550                 syscallarg(uid_t) euid;
  551         } */ *uap = v;
  552         struct pcred *pc = p->p_cred;
  553         struct sys_setresuid_args sresuidargs;
  554         uid_t ruid, euid;
  555 
  556         ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid);
  557         euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid);
  558 
  559         /*
  560          * The saved uid presents a bit of a dilemma, as it did not
  561          * exist when setreuid(2) was conceived.  We only set the saved
  562          * uid when the real uid is specified and either its value would
  563          * change, or where the saved and effective uids are different.
  564          */
  565         if (ruid != (uid_t)-1 && (ruid != pc->p_ruid ||
  566             pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid)))
  567                 SCARG(&sresuidargs, suid) = ruid;
  568         else
  569                 SCARG(&sresuidargs, suid) = (uid_t)-1;
  570 
  571         return (sys_setresuid(p, &sresuidargs, retval));
  572 }
  573 
  574 /* ARGSUSED */
  575 int
  576 sys_setuid(struct proc *p, void *v, register_t *retval)
  577 {
  578         struct sys_setuid_args /* {
  579                 syscallarg(uid_t) uid;
  580         } */ *uap = v;
  581         struct pcred *pc = p->p_cred;
  582         uid_t uid;
  583         int error;
  584 
  585         uid = SCARG(uap, uid);
  586 
  587         if (pc->pc_ucred->cr_uid == uid &&
  588             pc->p_ruid == uid &&
  589             pc->p_svuid == uid)
  590                 return (0);
  591 
  592         if (uid != pc->p_ruid &&
  593             uid != pc->p_svuid &&
  594             uid != pc->pc_ucred->cr_uid &&
  595             (error = suser(p, 0)))
  596                 return (error);
  597 
  598         /*
  599          * Everything's okay, do it.
  600          */
  601         if (uid == pc->pc_ucred->cr_uid ||
  602             suser(p, 0) == 0) {
  603                 /*
  604                  * Transfer proc count to new user.
  605                  */
  606                 if (uid != pc->p_ruid) {
  607                         (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt);
  608                         (void)chgproccnt(uid, p->p_p->ps_refcnt);
  609                 }
  610                 pc->p_ruid = uid;
  611                 pc->p_svuid = uid;
  612         }
  613 
  614         /*
  615          * Copy credentials so other references do not see our changes.
  616          */
  617         pc->pc_ucred = crcopy(pc->pc_ucred);
  618         pc->pc_ucred->cr_uid = uid;
  619         atomic_setbits_int(&p->p_flag, P_SUGID);
  620         return (0);
  621 }
  622 
  623 /* ARGSUSED */
  624 int
  625 sys_seteuid(struct proc *p, void *v, register_t *retval)
  626 {
  627         struct sys_seteuid_args /* {
  628                 syscallarg(uid_t) euid;
  629         } */ *uap = v;
  630         struct pcred *pc = p->p_cred;
  631         uid_t euid;
  632         int error;
  633 
  634         euid = SCARG(uap, euid);
  635 
  636         if (pc->pc_ucred->cr_uid == euid)
  637                 return (0);
  638 
  639         if (euid != pc->p_ruid && euid != pc->p_svuid &&
  640             (error = suser(p, 0)))
  641                 return (error);
  642 
  643         /*
  644          * Copy credentials so other references do not see our changes.
  645          */
  646         pc->pc_ucred = crcopy(pc->pc_ucred);
  647         pc->pc_ucred->cr_uid = euid;
  648         atomic_setbits_int(&p->p_flag, P_SUGID);
  649         return (0);
  650 }
  651 
  652 /* ARGSUSED */
  653 int
  654 sys_setgid(struct proc *p, void *v, register_t *retval)
  655 {
  656         struct sys_setgid_args /* {
  657                 syscallarg(gid_t) gid;
  658         } */ *uap = v;
  659         struct pcred *pc = p->p_cred;
  660         gid_t gid;
  661         int error;
  662 
  663         gid = SCARG(uap, gid);
  664 
  665         if (pc->pc_ucred->cr_gid == gid &&
  666             pc->p_rgid == gid &&
  667             pc->p_svgid == gid)
  668                 return (0);
  669 
  670         if (gid != pc->p_rgid &&
  671             gid != pc->p_svgid &&
  672             gid != pc->pc_ucred->cr_gid &&
  673             (error = suser(p, 0)))
  674                 return (error);
  675 
  676         if (gid == pc->pc_ucred->cr_gid ||
  677             suser(p, 0) == 0) {
  678                 pc->p_rgid = gid;
  679                 pc->p_svgid = gid;
  680         }
  681 
  682         /*
  683          * Copy credentials so other references do not see our changes.
  684          */
  685         pc->pc_ucred = crcopy(pc->pc_ucred);
  686         pc->pc_ucred->cr_gid = gid;
  687         atomic_setbits_int(&p->p_flag, P_SUGID);
  688         return (0);
  689 }
  690 
  691 /* ARGSUSED */
  692 int
  693 sys_setegid(struct proc *p, void *v, register_t *retval)
  694 {
  695         struct sys_setegid_args /* {
  696                 syscallarg(gid_t) egid;
  697         } */ *uap = v;
  698         struct pcred *pc = p->p_cred;
  699         gid_t egid;
  700         int error;
  701 
  702         egid = SCARG(uap, egid);
  703 
  704         if (pc->pc_ucred->cr_gid == egid)
  705                 return (0);
  706 
  707         if (egid != pc->p_rgid && egid != pc->p_svgid &&
  708             (error = suser(p, 0)))
  709                 return (error);
  710 
  711         /*
  712          * Copy credentials so other references do not see our changes.
  713          */
  714         pc->pc_ucred = crcopy(pc->pc_ucred);
  715         pc->pc_ucred->cr_gid = egid;
  716         atomic_setbits_int(&p->p_flag, P_SUGID);
  717         return (0);
  718 }
  719 
  720 /* ARGSUSED */
  721 int
  722 sys_setgroups(struct proc *p, void *v, register_t *retval)
  723 {
  724         struct sys_setgroups_args /* {
  725                 syscallarg(int) gidsetsize;
  726                 syscallarg(const gid_t *) gidset;
  727         } */ *uap = v;
  728         struct pcred *pc = p->p_cred;
  729         u_int ngrp;
  730         int error;
  731 
  732         if ((error = suser(p, 0)) != 0)
  733                 return (error);
  734         ngrp = SCARG(uap, gidsetsize);
  735         if (ngrp > NGROUPS)
  736                 return (EINVAL);
  737         pc->pc_ucred = crcopy(pc->pc_ucred);
  738         error = copyin((caddr_t)SCARG(uap, gidset),
  739             (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
  740         if (error)
  741                 return (error);
  742         pc->pc_ucred->cr_ngroups = ngrp;
  743         atomic_setbits_int(&p->p_flag, P_SUGID);
  744         return (0);
  745 }
  746 
  747 /*
  748  * Check if gid is a member of the group set.
  749  */
  750 int
  751 groupmember(gid_t gid, struct ucred *cred)
  752 {
  753         gid_t *gp;
  754         gid_t *egp;
  755 
  756         egp = &(cred->cr_groups[cred->cr_ngroups]);
  757         for (gp = cred->cr_groups; gp < egp; gp++)
  758                 if (*gp == gid)
  759                         return (1);
  760         return (0);
  761 }
  762 
  763 /*
  764  * Test whether this process has special user powers.
  765  * Returns 0 or error.
  766  */
  767 int
  768 suser(struct proc *p, u_int flags)
  769 {
  770         struct ucred *cred = p->p_ucred;
  771 
  772         if (cred->cr_uid == 0) {
  773                 if (!(flags & SUSER_NOACCT))
  774                         p->p_acflag |= ASU;
  775                 return (0);
  776         }
  777         return (EPERM);
  778 }
  779 
  780 /*
  781  * replacement for old suser, for callers who don't have a process
  782  */
  783 int
  784 suser_ucred(struct ucred *cred)
  785 {
  786         if (cred->cr_uid == 0)
  787                 return (0);
  788         return (EPERM);
  789 }
  790 
  791 /*
  792  * Allocate a zeroed cred structure.
  793  */
  794 struct ucred *
  795 crget(void)
  796 {
  797         struct ucred *cr;
  798 
  799         cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO);
  800         cr->cr_ref = 1;
  801         return (cr);
  802 }
  803 
  804 /*
  805  * Free a cred structure.
  806  * Throws away space when ref count gets to 0.
  807  */
  808 void
  809 crfree(struct ucred *cr)
  810 {
  811 
  812         if (--cr->cr_ref == 0)
  813                 pool_put(&ucred_pool, cr);
  814 }
  815 
  816 /*
  817  * Copy cred structure to a new one and free the old one.
  818  */
  819 struct ucred *
  820 crcopy(struct ucred *cr)
  821 {
  822         struct ucred *newcr;
  823 
  824         if (cr->cr_ref == 1)
  825                 return (cr);
  826         newcr = crget();
  827         *newcr = *cr;
  828         crfree(cr);
  829         newcr->cr_ref = 1;
  830         return (newcr);
  831 }
  832 
  833 /*
  834  * Dup cred struct to a new held one.
  835  */
  836 struct ucred *
  837 crdup(struct ucred *cr)
  838 {
  839         struct ucred *newcr;
  840 
  841         newcr = crget();
  842         *newcr = *cr;
  843         newcr->cr_ref = 1;
  844         return (newcr);
  845 }
  846 
  847 /*
  848  * Get login name, if available.
  849  */
  850 /* ARGSUSED */
  851 int
  852 sys_getlogin(struct proc *p, void *v, register_t *retval)
  853 {
  854         struct sys_getlogin_args /* {
  855                 syscallarg(char *) namebuf;
  856                 syscallarg(u_int) namelen;
  857         } */ *uap = v;
  858 
  859         if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
  860                 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
  861         return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
  862             (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
  863 }
  864 
  865 /*
  866  * Set login name.
  867  */
  868 /* ARGSUSED */
  869 int
  870 sys_setlogin(struct proc *p, void *v, register_t *retval)
  871 {
  872         struct sys_setlogin_args /* {
  873                 syscallarg(const char *) namebuf;
  874         } */ *uap = v;
  875         int error;
  876 
  877         if ((error = suser(p, 0)) != 0)
  878                 return (error);
  879         error = copyinstr((caddr_t) SCARG(uap, namebuf),
  880             (caddr_t) p->p_pgrp->pg_session->s_login,
  881             sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0);
  882         if (error == ENAMETOOLONG)
  883                 error = EINVAL;
  884         return (error);
  885 }
  886 
  887 /*
  888  * Check if a process is allowed to raise its privileges.
  889  */
  890 int
  891 proc_cansugid(struct proc *p)
  892 {
  893         /* ptrace(2)d processes shouldn't. */
  894         if ((p->p_flag & P_TRACED) != 0)
  895                 return (0);
  896 
  897         /* proceses with shared filedescriptors shouldn't. */
  898         if (p->p_fd->fd_refcnt > 1)
  899                 return (0);
  900 
  901         /* Allow. */
  902         return (1);
  903 }

Cache object: a2e23748031df94234ebdb28bd52b61b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.