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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_prot.c,v 1.84 2004/05/04 21:27:28 pk Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
   37  */
   38 
   39 /*
   40  * System calls related to processes and protection
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.84 2004/05/04 21:27:28 pk Exp $");
   45 
   46 #include "opt_compat_43.h"
   47 
   48 #include <sys/param.h>
   49 #include <sys/acct.h>
   50 #include <sys/systm.h>
   51 #include <sys/ucred.h>
   52 #include <sys/proc.h>
   53 #include <sys/timeb.h>
   54 #include <sys/times.h>
   55 #include <sys/pool.h>
   56 #include <sys/syslog.h>
   57 #include <sys/resourcevar.h>
   58 
   59 #include <sys/mount.h>
   60 #include <sys/sa.h>
   61 #include <sys/syscallargs.h>
   62 
   63 POOL_INIT(cred_pool, sizeof(struct ucred), 0, 0, 0, "credpl",
   64     &pool_allocator_nointr);
   65 
   66 int     sys_getpid(struct lwp *, void *, register_t *);
   67 int     sys_getpid_with_ppid(struct lwp *, void *, register_t *);
   68 int     sys_getuid(struct lwp *, void *, register_t *);
   69 int     sys_getuid_with_euid(struct lwp *, void *, register_t *);
   70 int     sys_getgid(struct lwp *, void *, register_t *);
   71 int     sys_getgid_with_egid(struct lwp *, void *, register_t *);
   72 
   73 /* ARGSUSED */
   74 int
   75 sys_getpid(struct lwp *l, void *v, register_t *retval)
   76 {
   77         struct proc *p = l->l_proc;
   78 
   79         *retval = p->p_pid;
   80         return (0);
   81 }
   82 
   83 /* ARGSUSED */
   84 int
   85 sys_getpid_with_ppid(struct lwp *l, void *v, register_t *retval)
   86 {
   87         struct proc *p = l->l_proc;
   88 
   89         retval[0] = p->p_pid;
   90         retval[1] = p->p_pptr->p_pid;
   91         return (0);
   92 }
   93 
   94 /* ARGSUSED */
   95 int
   96 sys_getppid(struct lwp *l, void *v, register_t *retval)
   97 {
   98         struct proc *p = l->l_proc;
   99 
  100         *retval = p->p_pptr->p_pid;
  101         return (0);
  102 }
  103 
  104 /* Get process group ID; note that POSIX getpgrp takes no parameter */
  105 int
  106 sys_getpgrp(struct lwp *l, void *v, register_t *retval)
  107 {
  108         struct proc *p = l->l_proc;
  109 
  110         *retval = p->p_pgrp->pg_id;
  111         return (0);
  112 }
  113 
  114 /*
  115  * Return the process group ID of the session leader (session ID)
  116  * for the specified process.
  117  */
  118 int
  119 sys_getsid(struct lwp *l, void *v, register_t *retval)
  120 {
  121         struct sys_getsid_args /* {
  122                 syscalldarg(pid_t) pid;
  123         } */ *uap = v;
  124         struct proc *p = l->l_proc;
  125 
  126         if (SCARG(uap, pid) == 0)
  127                 goto found;
  128         if ((p = pfind(SCARG(uap, pid))) == 0)
  129                 return (ESRCH);
  130 found:
  131         *retval = p->p_session->s_sid;
  132         return (0);
  133 }
  134 
  135 int
  136 sys_getpgid(struct lwp *l, void *v, register_t *retval)
  137 {
  138         struct sys_getpgid_args /* {
  139                 syscallarg(pid_t) pid;
  140         } */ *uap = v;
  141         struct proc *p = l->l_proc;
  142 
  143         if (SCARG(uap, pid) == 0)
  144                 goto found;
  145         if ((p = pfind(SCARG(uap, pid))) == 0)
  146                 return (ESRCH);
  147 found:
  148         *retval = p->p_pgid;
  149         return (0);
  150 }
  151 
  152 /* ARGSUSED */
  153 int
  154 sys_getuid(struct lwp *l, void *v, register_t *retval)
  155 {
  156         struct proc *p = l->l_proc;
  157 
  158         *retval = p->p_cred->p_ruid;
  159         return (0);
  160 }
  161 
  162 /* ARGSUSED */
  163 int
  164 sys_getuid_with_euid(struct lwp *l, void *v, register_t *retval)
  165 {
  166         struct proc *p = l->l_proc;
  167 
  168         retval[0] = p->p_cred->p_ruid;
  169         retval[1] = p->p_ucred->cr_uid;
  170         return (0);
  171 }
  172 
  173 /* ARGSUSED */
  174 int
  175 sys_geteuid(struct lwp *l, void *v, register_t *retval)
  176 {
  177         struct proc *p = l->l_proc;
  178 
  179         *retval = p->p_ucred->cr_uid;
  180         return (0);
  181 }
  182 
  183 /* ARGSUSED */
  184 int
  185 sys_getgid(struct lwp *l, void *v, register_t *retval)
  186 {
  187         struct proc *p = l->l_proc;
  188 
  189         *retval = p->p_cred->p_rgid;
  190         return (0);
  191 }
  192 
  193 /* ARGSUSED */
  194 int
  195 sys_getgid_with_egid(struct lwp *l, void *v, register_t *retval)
  196 {
  197         struct proc *p = l->l_proc;
  198 
  199         retval[0] = p->p_cred->p_rgid;
  200         retval[1] = p->p_ucred->cr_gid;
  201         return (0);
  202 }
  203 
  204 /*
  205  * Get effective group ID.  The "egid" is groups[0], and could be obtained
  206  * via getgroups.  This syscall exists because it is somewhat painful to do
  207  * correctly in a library function.
  208  */
  209 /* ARGSUSED */
  210 int
  211 sys_getegid(struct lwp *l, void *v, register_t *retval)
  212 {
  213         struct proc *p = l->l_proc;
  214 
  215         *retval = p->p_ucred->cr_gid;
  216         return (0);
  217 }
  218 
  219 int
  220 sys_getgroups(struct lwp *l, void *v, register_t *retval)
  221 {
  222         struct sys_getgroups_args /* {
  223                 syscallarg(int) gidsetsize;
  224                 syscallarg(gid_t *) gidset;
  225         } */ *uap = v;
  226         struct proc *p = l->l_proc;
  227         struct pcred *pc = p->p_cred;
  228         u_int ngrp;
  229         int error;
  230 
  231         if (SCARG(uap, gidsetsize) == 0) {
  232                 *retval = pc->pc_ucred->cr_ngroups;
  233                 return (0);
  234         } else if (SCARG(uap, gidsetsize) < 0)
  235                 return (EINVAL);
  236         ngrp = SCARG(uap, gidsetsize);
  237         if (ngrp < pc->pc_ucred->cr_ngroups)
  238                 return (EINVAL);
  239         ngrp = pc->pc_ucred->cr_ngroups;
  240         error = copyout((caddr_t)pc->pc_ucred->cr_groups,
  241             (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
  242         if (error)
  243                 return (error);
  244         *retval = ngrp;
  245         return (0);
  246 }
  247 
  248 /* ARGSUSED */
  249 int
  250 sys_setsid(struct lwp *l, void *v, register_t *retval)
  251 {
  252         struct proc *p = l->l_proc;
  253 
  254         if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
  255                 return (EPERM);
  256         } else {
  257                 (void)enterpgrp(p, p->p_pid, 1);
  258                 *retval = p->p_pid;
  259                 return (0);
  260         }
  261 }
  262 
  263 /*
  264  * set process group (setpgid/old setpgrp)
  265  *
  266  * caller does setpgid(targpid, targpgid)
  267  *
  268  * pgid must be in valid range (EINVAL)
  269  * pid must be caller or child of caller (ESRCH)
  270  * if a child
  271  *      pid must be in same session (EPERM)
  272  *      pid can't have done an exec (EACCES)
  273  * if pgid != pid
  274  *      there must exist some pid in same session having pgid (EPERM)
  275  * pid must not be session leader (EPERM)
  276  *
  277  * Permission checks now in enterpgrp()
  278  */
  279 /* ARGSUSED */
  280 int
  281 sys_setpgid(struct lwp *l, void *v, register_t *retval)
  282 {
  283         struct sys_setpgid_args /* {
  284                 syscallarg(int) pid;
  285                 syscallarg(int) pgid;
  286         } */ *uap = v;
  287         struct proc *curp = l->l_proc;
  288         struct proc *targp;                     /* target process */
  289 
  290         if (SCARG(uap, pgid) < 0)
  291                 return EINVAL;
  292 
  293         /* XXX MP - there is a horrid race here with targp exiting! */
  294         if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
  295                 targp = pfind(SCARG(uap, pid));
  296                 if (targp == NULL)
  297                         return ESRCH;
  298         } else
  299                 targp = curp;
  300 
  301         if (SCARG(uap, pgid) == 0)
  302                 SCARG(uap, pgid) = targp->p_pid;
  303         return enterpgrp(targp, SCARG(uap, pgid), 0);
  304 }
  305 
  306 /*
  307  * Set real, effective and saved uids to the requested values.
  308  * non-root callers can only ever change uids to values that match
  309  * one of the processes current uid values.
  310  * This is further restricted by the flags argument.
  311  */
  312 
  313 int
  314 do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags)
  315 {
  316         int error;
  317         struct proc *p = l->l_proc;
  318         struct pcred *pcred = p->p_cred;
  319         struct ucred *cred = pcred->pc_ucred;
  320 
  321         /* Superuser can do anything it wants to.... */
  322         error = suser(cred, &p->p_acflag);
  323         if (error) {
  324                 /* Otherwise check new value is one of the allowed
  325                    existing values. */
  326                 if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_ruid)
  327                             && !((flags & ID_R_EQ_E) && r == cred->cr_uid)
  328                             && !((flags & ID_R_EQ_S) && r == pcred->p_svuid))
  329                         return error;
  330                 if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_ruid)
  331                             && !((flags & ID_E_EQ_E) && e == cred->cr_uid)
  332                             && !((flags & ID_E_EQ_S) && e == pcred->p_svuid))
  333                         return error;
  334                 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_ruid)
  335                             && !((flags & ID_S_EQ_E) && sv == cred->cr_uid)
  336                             && !((flags & ID_S_EQ_S) && sv == pcred->p_svuid))
  337                         return error;
  338         }
  339 
  340         /* If nothing has changed, short circuit the request */
  341         if ((r == -1 || r == pcred->p_ruid)
  342             && (e == -1 || e == cred->cr_uid)
  343             && (sv == -1 || sv == pcred->p_svuid))
  344                 /* nothing to do */
  345                 return 0;
  346 
  347         /* The pcred structure is not actually shared... */
  348         if (r != -1 && r != pcred->p_ruid) {
  349                 /* Update count of processes for this user */
  350                 (void)chgproccnt(pcred->p_ruid, -1);
  351                 (void)chgproccnt(r, 1);
  352                 pcred->p_ruid = r;
  353         }
  354         if (sv != -1)
  355                 pcred->p_svuid = sv;
  356         if (e != -1 && e != cred->cr_uid) {
  357                 /* Update a clone of the current credentials */
  358                 pcred->pc_ucred = cred = crcopy(cred);
  359                 cred->cr_uid = e;
  360         }
  361 
  362         /* Mark process as having changed credentials, stops tracing etc */
  363         p_sugid(p);
  364         return 0;
  365 }
  366 
  367 /*
  368  * Set real, effective and saved gids to the requested values.
  369  * non-root callers can only ever change gids to values that match
  370  * one of the processes current gid values.
  371  * This is further restricted by the flags argument.
  372  */
  373 
  374 int
  375 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags)
  376 {
  377         int error;
  378         struct proc *p = l->l_proc;
  379         struct pcred *pcred = p->p_cred;
  380         struct ucred *cred = pcred->pc_ucred;
  381 
  382         /* Superuser can do anything it wants to.... */
  383         error = suser(cred, &p->p_acflag);
  384         if (error) {
  385                 /* Otherwise check new value is one of the allowed
  386                    existing values. */
  387                 if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_rgid)
  388                             && !((flags & ID_R_EQ_E) && r == cred->cr_gid)
  389                             && !((flags & ID_R_EQ_S) && r == pcred->p_svgid))
  390                         return error;
  391                 if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_rgid)
  392                             && !((flags & ID_E_EQ_E) && e == cred->cr_gid)
  393                             && !((flags & ID_E_EQ_S) && e == pcred->p_svgid))
  394                         return error;
  395                 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_rgid)
  396                             && !((flags & ID_S_EQ_E) && sv == cred->cr_gid)
  397                             && !((flags & ID_S_EQ_S) && sv == pcred->p_svgid))
  398                         return error;
  399         }
  400 
  401         /* If nothing has changed, short circuit the request */
  402         if ((r == -1 || r == pcred->p_rgid)
  403             && (e == -1 || e == cred->cr_gid)
  404             && (sv == -1 || sv == pcred->p_svgid))
  405                 /* nothing to do */
  406                 return 0;
  407 
  408         /* The pcred structure is not actually shared... */
  409         if (r != -1)
  410                 pcred->p_rgid = r;
  411         if (sv != -1)
  412                 pcred->p_svgid = sv;
  413         if (e != -1 && e != cred->cr_gid) {
  414                 /* Update a clone of the current credentials */
  415                 pcred->pc_ucred = cred = crcopy(cred);
  416                 cred->cr_gid = e;
  417         }
  418 
  419         /* Mark process as having changed credentials, stops tracing etc */
  420         p_sugid(p);
  421         return 0;
  422 }
  423 
  424 /* ARGSUSED */
  425 int
  426 sys_setuid(struct lwp *l, void *v, register_t *retval)
  427 {
  428         struct sys_setuid_args /* {
  429                 syscallarg(uid_t) uid;
  430         } */ *uap = v;
  431         uid_t uid = SCARG(uap, uid);
  432 
  433         return do_setresuid(l, uid, uid, uid,
  434                             ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
  435 }
  436 
  437 /* ARGSUSED */
  438 int
  439 sys_seteuid(struct lwp *l, void *v, register_t *retval)
  440 {
  441         struct sys_seteuid_args /* {
  442                 syscallarg(uid_t) euid;
  443         } */ *uap = v;
  444 
  445         return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S);
  446 }
  447 
  448 int
  449 sys_setreuid(struct lwp *l, void *v, register_t *retval)
  450 {
  451         struct sys_setreuid_args /* {
  452                 syscallarg(uid_t) ruid;
  453                 syscallarg(uid_t) euid;
  454         } */ *uap = v;
  455         struct proc *p = l->l_proc;
  456         uid_t ruid, euid, svuid;
  457 
  458         ruid = SCARG(uap, ruid);
  459         euid = SCARG(uap, euid);
  460         if (ruid == -1)
  461                 ruid = p->p_cred->p_ruid;
  462         if (euid == -1)
  463                 euid = p->p_ucred->cr_uid;
  464         /* Saved uid is set to the new euid if the ruid changed */
  465         svuid = (ruid == p->p_cred->p_ruid) ? -1 : euid;
  466 
  467         return do_setresuid(l, ruid, euid, svuid,
  468                             ID_R_EQ_R | ID_R_EQ_E |
  469                             ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
  470                             ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
  471 }
  472 
  473 /* ARGSUSED */
  474 int
  475 sys_setgid(struct lwp *l, void *v, register_t *retval)
  476 {
  477         struct sys_setgid_args /* {
  478                 syscallarg(gid_t) gid;
  479         } */ *uap = v;
  480         gid_t gid = SCARG(uap, gid);
  481 
  482         return do_setresgid(l, gid, gid, gid,
  483                             ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
  484 }
  485 
  486 /* ARGSUSED */
  487 int
  488 sys_setegid(struct lwp *l, void *v, register_t *retval)
  489 {
  490         struct sys_setegid_args /* {
  491                 syscallarg(gid_t) egid;
  492         } */ *uap = v;
  493 
  494         return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S);
  495 }
  496 
  497 int
  498 sys_setregid(struct lwp *l, void *v, register_t *retval)
  499 {
  500         struct sys_setregid_args /* {
  501                 syscallarg(gid_t) rgid;
  502                 syscallarg(gid_t) egid;
  503         } */ *uap = v;
  504         struct proc *p = l->l_proc;
  505         gid_t rgid, egid, svgid;
  506 
  507         rgid = SCARG(uap, rgid);
  508         egid = SCARG(uap, egid);
  509         if (rgid == -1)
  510                 rgid = p->p_cred->p_rgid;
  511         if (egid == -1)
  512                 egid = p->p_ucred->cr_gid;
  513         /* Saved gid is set to the new egid if the rgid changed */
  514         svgid = rgid == p->p_cred->p_rgid ? -1 : egid;
  515 
  516         return do_setresgid(l, rgid, egid, svgid,
  517                         ID_R_EQ_R | ID_R_EQ_E |
  518                         ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
  519                         ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
  520 }
  521 
  522 int
  523 sys_issetugid(struct lwp *l, void *v, register_t *retval)
  524 {
  525         struct proc *p = l->l_proc;
  526 
  527         /*
  528          * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
  529          * we use P_SUGID because we consider changing the owners as
  530          * "tainting" as well.
  531          * This is significant for procs that start as root and "become"
  532          * a user without an exec - programs cannot know *everything*
  533          * that libc *might* have put in their data segment.
  534          */
  535         *retval = (p->p_flag & P_SUGID) != 0;
  536         return (0);
  537 }
  538 
  539 /* ARGSUSED */
  540 int
  541 sys_setgroups(struct lwp *l, void *v, register_t *retval)
  542 {
  543         struct sys_setgroups_args /* {
  544                 syscallarg(int) gidsetsize;
  545                 syscallarg(const gid_t *) gidset;
  546         } */ *uap = v;
  547         struct proc *p = l->l_proc;
  548         struct pcred *pc = p->p_cred;
  549         int ngrp;
  550         int error;
  551         gid_t grp[NGROUPS];
  552         size_t grsize;
  553 
  554         if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
  555                 return (error);
  556 
  557         ngrp = SCARG(uap, gidsetsize);
  558         if ((u_int)ngrp > NGROUPS)
  559                 return (EINVAL);
  560 
  561         grsize = ngrp * sizeof(gid_t);
  562         error = copyin(SCARG(uap, gidset), grp, grsize);
  563         if (error)
  564                 return (error);
  565         /*
  566          * Check if this is a no-op.
  567          */
  568         if (pc->pc_ucred->cr_ngroups == (u_int) ngrp &&
  569             memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0)
  570                 return (0);
  571 
  572         pc->pc_ucred = crcopy(pc->pc_ucred);
  573         (void)memcpy(pc->pc_ucred->cr_groups, grp, grsize);
  574         pc->pc_ucred->cr_ngroups = ngrp;
  575         p_sugid(p);
  576         return (0);
  577 }
  578 
  579 /*
  580  * Check if gid is a member of the group set.
  581  */
  582 int
  583 groupmember(gid_t gid, const struct ucred *cred)
  584 {
  585         const gid_t *gp;
  586         const gid_t *egp;
  587 
  588         egp = &(cred->cr_groups[cred->cr_ngroups]);
  589         for (gp = cred->cr_groups; gp < egp; gp++)
  590                 if (*gp == gid)
  591                         return (1);
  592         return (0);
  593 }
  594 
  595 /*
  596  * Test whether the specified credentials imply "super-user"
  597  * privilege; if so, and we have accounting info, set the flag
  598  * indicating use of super-powers.
  599  * Returns 0 or error.
  600  */
  601 int
  602 suser(const struct ucred *cred, u_short *acflag)
  603 {
  604 
  605         if (cred->cr_uid == 0) {
  606                 if (acflag)
  607                         *acflag |= ASU;
  608                 return (0);
  609         }
  610         return (EPERM);
  611 }
  612 
  613 /*
  614  * Allocate a zeroed cred structure.
  615  */
  616 struct ucred *
  617 crget(void)
  618 {
  619         struct ucred *cr;
  620 
  621         cr = pool_get(&cred_pool, PR_WAITOK);
  622         memset(cr, 0, sizeof(*cr));
  623         simple_lock_init(&cr->cr_lock);
  624         cr->cr_ref = 1;
  625         return (cr);
  626 }
  627 
  628 /*
  629  * Free a cred structure.
  630  * Throws away space when ref count gets to 0.
  631  */
  632 void
  633 crfree(struct ucred *cr)
  634 {
  635         int n;
  636 
  637         simple_lock(&cr->cr_lock);
  638         n = --cr->cr_ref;
  639         simple_unlock(&cr->cr_lock);
  640         if (n == 0)
  641                 pool_put(&cred_pool, cr);
  642 }
  643 
  644 /*
  645  * Compare cred structures and return 0 if they match
  646  */
  647 int
  648 crcmp(const struct ucred *cr1, const struct uucred *cr2)
  649 {
  650         return cr1->cr_uid != cr2->cr_uid ||
  651             cr1->cr_gid != cr2->cr_gid ||
  652             cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups ||
  653             memcmp(cr1->cr_groups, cr2->cr_groups, cr1->cr_ngroups);
  654 }
  655 
  656 /*
  657  * Copy cred structure to a new one and free the old one.
  658  */
  659 struct ucred *
  660 crcopy(struct ucred *cr)
  661 {
  662         struct ucred *newcr;
  663 
  664         if (cr->cr_ref == 1)
  665                 return (cr);
  666 
  667         newcr = crget();
  668         memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
  669                 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
  670         crfree(cr);
  671         return (newcr);
  672 }
  673 
  674 /*
  675  * Dup cred struct to a new held one.
  676  */
  677 struct ucred *
  678 crdup(const struct ucred *cr)
  679 {
  680         struct ucred *newcr;
  681 
  682         newcr = crget();
  683         memcpy(&newcr->cr_startcopy, &cr->cr_startcopy,
  684                 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy));
  685         return (newcr);
  686 }
  687 
  688 /*
  689  * convert from userland credentials to kernel one
  690  */
  691 void
  692 crcvt(struct ucred *uc, const struct uucred *uuc)
  693 {
  694 
  695         uc->cr_ref = 0;
  696         uc->cr_uid = uuc->cr_uid;
  697         uc->cr_gid = uuc->cr_gid;
  698         uc->cr_ngroups = uuc->cr_ngroups;
  699         (void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups));
  700 }
  701 
  702 /*
  703  * Get login name, if available.
  704  */
  705 /* ARGSUSED */
  706 int
  707 sys___getlogin(struct lwp *l, void *v, register_t *retval)
  708 {
  709         struct sys___getlogin_args /* {
  710                 syscallarg(char *) namebuf;
  711                 syscallarg(size_t) namelen;
  712         } */ *uap = v;
  713         struct proc *p = l->l_proc;
  714 
  715         if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
  716                 SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
  717         return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
  718             (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
  719 }
  720 
  721 /*
  722  * Set login name.
  723  */
  724 /* ARGSUSED */
  725 int
  726 sys___setlogin(struct lwp *l, void *v, register_t *retval)
  727 {
  728         struct sys___setlogin_args /* {
  729                 syscallarg(const char *) namebuf;
  730         } */ *uap = v;
  731         struct proc *p = l->l_proc;
  732         struct session *s = p->p_pgrp->pg_session;
  733         char newname[sizeof s->s_login + 1];
  734         int error;
  735 
  736         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  737                 return (error);
  738         error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL);
  739         if (error != 0)
  740                 return (error == ENAMETOOLONG ? EINVAL : error);
  741 
  742         if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid &&
  743             strncmp(newname, s->s_login, sizeof s->s_login) != 0)
  744                 log(LOG_WARNING, "%s (pid %d) changing logname from "
  745                     "%.*s to %s\n", p->p_comm, p->p_pid,
  746                     (int)sizeof s->s_login, s->s_login, newname);
  747         s->s_flags |= S_LOGIN_SET;
  748         strncpy(s->s_login, newname, sizeof s->s_login);
  749         return (0);
  750 }

Cache object: 89e211355545752150245f0296b8fcc1


[ 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.