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

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

Version: -  FREEBSD  -  FREEBSD8  -  FREEBSD7  -  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  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

    1 /*
    2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
   29 /*
   30  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
   31  *      The Regents of the University of California.  All rights reserved.
   32  * (c) UNIX System Laboratories, Inc.
   33  * All or some portions of this file are derived from material licensed
   34  * to the University of California by American Telephone and Telegraph
   35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   36  * the permission of UNIX System Laboratories, Inc.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 3. All advertising materials mentioning features or use of this software
   47  *    must display the following acknowledgement:
   48  *      This product includes software developed by the University of
   49  *      California, Berkeley and its contributors.
   50  * 4. Neither the name of the University nor the names of its contributors
   51  *    may be used to endorse or promote products derived from this software
   52  *    without specific prior written permission.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   64  * SUCH DAMAGE.
   65  *
   66  *      @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
   67  */
   68 /*
   69  * NOTICE: This file was modified by McAfee Research in 2004 to introduce
   70  * support for mandatory and extensible security protections.  This notice
   71  * is included in support of clause 2.2 (b) of the Apple Public License,
   72  * Version 2.0.
   73  */
   74 /*
   75  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
   76  * support for mandatory and extensible security protections.  This notice
   77  * is included in support of clause 2.2 (b) of the Apple Public License,
   78  * Version 2.0.
   79  */
   80 
   81 /*
   82  * System calls related to processes and protection
   83  */
   84 
   85 #include <sys/param.h>
   86 #include <sys/acct.h>
   87 #include <sys/systm.h>
   88 #include <sys/ucred.h>
   89 #include <sys/proc_internal.h>
   90 #include <sys/user.h>
   91 #include <sys/kauth.h>
   92 #include <sys/timeb.h>
   93 #include <sys/times.h>
   94 #include <sys/malloc.h>
   95 
   96 #include <bsm/audit_kernel.h>
   97 
   98 #if CONFIG_LCTX
   99 #include <sys/lctx.h>
  100 #endif
  101 
  102 #if CONFIG_MACF
  103 #include <security/mac_framework.h>
  104 #if CONFIG_MACF_MACH
  105 #include <secuity/mac_mach_internal.h>
  106 #endif
  107 #endif
  108 
  109 #include <sys/mount_internal.h>
  110 #include <sys/sysproto.h>
  111 #include <mach/message.h>
  112 #include <mach/host_security.h>
  113 
  114 #include <kern/host.h>
  115 #include <kern/task.h>          /* for current_task() */
  116 #include <kern/assert.h>
  117 
  118 
  119 int groupmember(gid_t gid, kauth_cred_t cred);
  120 
  121 /*
  122  * Credential debugging; we can track entry into a function that might
  123  * change a credential, and we can track actual credential changes that
  124  * result.
  125  *
  126  * Note:        Does *NOT* currently include per-thread credential changes
  127  *
  128  *              We don't use kauth_cred_print() in current debugging, but it
  129  *              can be used if needed when debugging is active.
  130  */
  131 #if DEBUG_CRED
  132 #define DEBUG_CRED_ENTER                printf
  133 #define DEBUG_CRED_CHANGE               printf
  134 extern void kauth_cred_print(kauth_cred_t cred);
  135 #else   /* !DEBUG_CRED */
  136 #define DEBUG_CRED_ENTER(fmt, ...)      do {} while (0)
  137 #define DEBUG_CRED_CHANGE(fmt, ...)     do {} while (0)
  138 #endif  /* !DEBUG_CRED */
  139 
  140 
  141 
  142 /*
  143  * setprivexec
  144  *
  145  * Description: (dis)allow this process to hold task, thread, or execption
  146  *              ports of processes about to exec.
  147  *
  148  * Parameters:  uap->flag                       New value for flag
  149  *
  150  * Returns:     int                             Previous value of flag
  151  *
  152  * XXX:         Belongs in kern_proc.c
  153  */
  154 int
  155 setprivexec(proc_t p, struct setprivexec_args *uap, register_t *retval)
  156 {
  157         AUDIT_ARG(value, uap->flag);
  158         *retval = p->p_debugger;
  159         p->p_debugger = (uap->flag != 0);
  160         return(0);
  161 }
  162 
  163 
  164 /*
  165  * getpid
  166  *
  167  * Description: get the process ID
  168  *
  169  * Parameters:  (void)
  170  *
  171  * Returns:     pid_t                           Current process ID
  172  *
  173  * XXX:         Belongs in kern_proc.c
  174  */
  175 int
  176 getpid(proc_t p, __unused struct getpid_args *uap, register_t *retval)
  177 {
  178 
  179         *retval = p->p_pid;
  180         return (0);
  181 }
  182 
  183 
  184 /*
  185  * getppid
  186  *
  187  * Description: get the parent process ID
  188  *
  189  * Parameters:  (void)
  190  *
  191  * Returns:     pid_t                           Parent process ID
  192  *
  193  * XXX:         Belongs in kern_proc.c
  194  */
  195 int
  196 getppid(proc_t p, __unused struct getppid_args *uap, register_t *retval)
  197 {
  198 
  199         *retval = p->p_ppid;
  200         return (0);
  201 }
  202 
  203 
  204 /*
  205  * getpgrp
  206  *
  207  * Description: get the process group ID of the calling process
  208  *
  209  * Parameters:  (void)
  210  *
  211  * Returns:     pid_t                           Process group ID
  212  *
  213  * XXX:         Belongs in kern_proc.c
  214  */
  215 int
  216 getpgrp(proc_t p, __unused struct getpgrp_args *uap, register_t *retval)
  217 {
  218 
  219         *retval = p->p_pgrpid;
  220         return (0);
  221 }
  222 
  223 
  224 /*
  225  * getpgid
  226  *
  227  * Description: Get an arbitary pid's process group id
  228  *
  229  * Parameters:  uap->pid                        The target pid
  230  *
  231  * Returns:     0                               Success
  232  *              ESRCH                           No such process
  233  *
  234  * Notes:       We are permitted to return EPERM in the case that the target
  235  *              process is not in the same session as the calling process,
  236  *              which could be a security consideration
  237  *
  238  * XXX:         Belongs in kern_proc.c
  239  */
  240 int
  241 getpgid(proc_t p, struct getpgid_args *uap, register_t *retval)
  242 {
  243         proc_t pt;
  244         int refheld = 0;
  245 
  246         pt = p;
  247         if (uap->pid == 0)
  248                 goto found;
  249 
  250         if ((pt = proc_find(uap->pid)) == 0)
  251                 return (ESRCH);
  252         refheld = 1;
  253 found:
  254         *retval = pt->p_pgrpid;
  255         if (refheld != 0)
  256                 proc_rele(pt);
  257         return (0);
  258 }
  259 
  260 
  261 /*
  262  * getsid
  263  *
  264  * Description: Get an arbitary pid's session leaders process group ID
  265  *
  266  * Parameters:  uap->pid                        The target pid
  267  *
  268  * Returns:     0                               Success
  269  *              ESRCH                           No such process
  270  *
  271  * Notes:       We are permitted to return EPERM in the case that the target
  272  *              process is not in the same session as the calling process,
  273  *              which could be a security consideration
  274  *
  275  * XXX:         Belongs in kern_proc.c
  276  */
  277 int
  278 getsid(proc_t p, struct getsid_args *uap, register_t *retval)
  279 {
  280         proc_t pt;
  281         int refheld = 0;
  282         struct session * sessp;
  283 
  284         pt = p;
  285         if (uap->pid == 0)
  286                 goto found;
  287 
  288         if ((pt = proc_find(uap->pid)) == 0)
  289                 return (ESRCH);
  290         refheld = 1;
  291 found:
  292         sessp = proc_session(pt);
  293         *retval = sessp->s_sid;
  294         session_rele(sessp);
  295 
  296         if (refheld != 0)
  297                 proc_rele(pt);
  298         return (0);
  299 }
  300 
  301 
  302 /*
  303  * getuid
  304  *
  305  * Description: get real user ID for caller
  306  *
  307  * Parameters:  (void)
  308  *
  309  * Returns:     uid_t                           The real uid of the caller
  310  */
  311 int
  312 getuid(__unused proc_t p, __unused struct getuid_args *uap, register_t *retval)
  313 {
  314 
  315         *retval = kauth_getruid();
  316         return (0);
  317 }
  318 
  319 
  320 /*
  321  * geteuid
  322  *
  323  * Description: get effective user ID for caller
  324  *
  325  * Parameters:  (void)
  326  *
  327  * Returns:     uid_t                           The effective uid of the caller
  328  */
  329 int
  330 geteuid(__unused proc_t p, __unused struct geteuid_args *uap, register_t *retval)
  331 {
  332 
  333         *retval = kauth_getuid();
  334         return (0);
  335 }
  336 
  337 
  338 /*
  339  * gettid
  340  *
  341  * Description: Return the per-thread override identity.
  342  *
  343  * Parameters:  uap->uidp                       Address of uid_t to get uid
  344  *              uap->gidp                       Address of gid_t to get gid
  345  *
  346  * Returns:     0                               Success
  347  *              ESRCH                           No per thread identity active
  348  */
  349 int
  350 gettid(__unused proc_t p, struct gettid_args *uap, register_t *retval)
  351 {
  352         struct uthread *uthread = get_bsdthread_info(current_thread());
  353         int     error;
  354 
  355         /*
  356          * If this thread is not running with an override identity, we can't
  357          * return one to the caller, so return an error instead.
  358          */
  359         if (!(uthread->uu_flag & UT_SETUID))
  360                 return (ESRCH);
  361 
  362         if ((error = suword(uap->uidp, uthread->uu_ucred->cr_ruid)))
  363                 return (error);
  364         if ((error = suword(uap->gidp, uthread->uu_ucred->cr_rgid)))
  365                 return (error);
  366 
  367         *retval = 0;
  368         return (0);
  369 }
  370 
  371 
  372 /*
  373  * getgid
  374  *
  375  * Description: get the real group ID for the calling process
  376  *
  377  * Parameters:  (void)
  378  *
  379  * Returns:     gid_t                           The real gid of the caller
  380  */
  381 int
  382 getgid(__unused proc_t p, __unused struct getgid_args *uap, register_t *retval)
  383 {
  384 
  385         *retval = kauth_getrgid();
  386         return (0);
  387 }
  388 
  389 
  390 /*
  391  * getegid
  392  *
  393  * Description: get the effective group ID for the calling process
  394  *
  395  * Parameters:  (void)
  396  *
  397  * Returns:     gid_t                           The effective gid of the caller
  398  *
  399  * Notes:       As an implementation detail, the effective gid is stored as
  400  *              the first element of the supplementary group list.
  401  *
  402  *              This could be implemented in Libc instead because of the above
  403  *              detail.
  404  */
  405 int
  406 getegid(__unused proc_t p, __unused struct getegid_args *uap, register_t *retval)
  407 {
  408 
  409         *retval = kauth_getgid();
  410         return (0);
  411 }
  412 
  413 
  414 /*
  415  * getgroups
  416  *
  417  * Description: get the list of supplementary groups for the calling process
  418  *
  419  * Parameters:  uap->gidsetsize                 # of gid_t's in user buffer
  420  *              uap->gidset                     Pointer to user buffer
  421  *
  422  * Returns:     0                               Success
  423  *              EINVAL                          User buffer too small
  424  *      copyout:EFAULT                          User buffer invalid
  425  *
  426  * Retval:      -1                              Error
  427  *              !0                              # of groups
  428  *
  429  * Notes:       The caller may specify a 0 value for gidsetsize, and we will
  430  *              then return how large a buffer is required (in gid_t's) to
  431  *              contain the answer at the time of the call.  Otherwise, we
  432  *              return the number of gid_t's catually copied to user space.
  433  *
  434  *              When called with a 0 gidsetsize from a multithreaded program,
  435  *              there is no guarantee that another thread may not change the
  436  *              number of supplementary groups, and therefore a subsequent
  437  *              call could still fail, unless the maximum possible buffer
  438  *              size is supplied by the user.
  439  *
  440  *              As an implementation detail, the effective gid is stored as
  441  *              the first element of the supplementary group list, and will
  442  *              be returned by this call.
  443  */
  444 int
  445 getgroups(__unused proc_t p, struct getgroups_args *uap, register_t *retval)
  446 {
  447         int ngrp;
  448         int error;
  449         kauth_cred_t cred;
  450 
  451         /* grab reference while we muck around with the credential */
  452         cred = kauth_cred_get_with_ref();
  453 
  454         if ((ngrp = uap->gidsetsize) == 0) {
  455                 *retval = cred->cr_ngroups;
  456                 kauth_cred_unref(&cred);
  457                 return (0);
  458         }
  459         if (ngrp < cred->cr_ngroups) {
  460                 kauth_cred_unref(&cred);
  461                 return (EINVAL);
  462         }
  463         ngrp = cred->cr_ngroups;
  464         if ((error = copyout((caddr_t)cred->cr_groups,
  465                                         uap->gidset, 
  466                                         ngrp * sizeof(gid_t)))) {
  467                 kauth_cred_unref(&cred);
  468                 return (error);
  469         }
  470         kauth_cred_unref(&cred);
  471         *retval = ngrp;
  472         return (0);
  473 }
  474 
  475 
  476 /*
  477  * Return the per-thread/per-process supplementary groups list.
  478  */
  479 #warning XXX implement getsgroups
  480 int
  481 getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused register_t *retval)
  482 {
  483         /* XXX implement */
  484         return(ENOTSUP);
  485 }
  486 
  487 /*
  488  * Return the per-thread/per-process whiteout groups list.
  489  */
  490 #warning XXX implement getwgroups
  491 int
  492 getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused register_t *retval)
  493 {
  494         /* XXX implement */
  495         return(ENOTSUP);
  496 }
  497 
  498 
  499 /*
  500  * setsid
  501  *
  502  * Description: Create a new session and set the process group ID to the
  503  *              session ID
  504  *
  505  * Parameters:  (void)
  506  *
  507  * Returns:     0                               Success
  508  *              EPERM                           Permission denied
  509  *
  510  * Notes:       If the calling process is not the process group leader; there
  511  *              is no existing process group with its ID, and we are not
  512  *              currently in vfork, then this function will create a new
  513  *              session, a new process group, and put the caller in the
  514  *              process group (as the sole member) and make it the session
  515  *              leader (as the sole process in the session).
  516  *
  517  *              The existing controlling tty (if any) will be dissociated
  518  *              from the process, and the next non-O_NOCTTY open of a tty
  519  *              will establish a new controlling tty.
  520  *
  521  * XXX:         Belongs in kern_proc.c
  522  */
  523 int
  524 setsid(proc_t p, __unused struct setsid_args *uap, register_t *retval)
  525 {
  526         struct pgrp * pg = PGRP_NULL;
  527 
  528         if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
  529                 if (pg != PGRP_NULL)
  530                         pg_rele(pg);
  531                 return (EPERM);
  532         } else {
  533                 /* enter pgrp works with its own pgrp refcount */
  534                 (void)enterpgrp(p, p->p_pid, 1);
  535                 *retval = p->p_pid;
  536                 return (0);
  537         }
  538 }
  539 
  540 
  541 /*
  542  * setpgid
  543  *
  544  * Description: set process group ID for job control
  545  *
  546  * Parameters:  uap->pid                        Process to change
  547  *              uap->pgid                       Process group to join or create
  548  *
  549  * Returns:     0                       Success
  550  *              ESRCH                   pid is not the caller or a child of
  551  *                                      the caller
  552  *      enterpgrp:ESRCH                 No such process
  553  *              EACCES                  Permission denied due to exec
  554  *              EINVAL                  Invalid argument
  555  *              EPERM                   The target process is not in the same
  556  *                                      session as the calling process
  557  *              EPERM                   The target process is a session leader
  558  *              EPERM                   pid and pgid are not the same, and
  559  *                                      there is no process in the calling
  560  *                                      process whose process group ID matches
  561  *                                      pgid
  562  *
  563  * Notes:       This function will cause the target process to either join
  564  *              an existing process process group, or create a new process
  565  *              group in the session of the calling process.  It cannot be
  566  *              used to change the process group ID of a process which is
  567  *              already a session leader.
  568  *
  569  *              If the target pid is 0, the pid of the calling process is
  570  *              substituted as the new target; if pgid is 0, the target pid
  571  *              is used as the target process group ID.
  572  *
  573  * Legacy:      This system call entry point is also used to implement the
  574  *              legacy library routine setpgrp(), which under POSIX 
  575  *
  576  * XXX:         Belongs in kern_proc.c
  577  */
  578 int
  579 setpgid(proc_t curp, register struct setpgid_args *uap, __unused register_t *retval)
  580 {
  581         proc_t targp = PROC_NULL;       /* target process */
  582         struct pgrp *pg = PGRP_NULL;    /* target pgrp */
  583         int error = 0;
  584         int refheld = 0;
  585         int samesess = 0;
  586         struct session * curp_sessp = SESSION_NULL;
  587         struct session * targp_sessp = SESSION_NULL;
  588 
  589         curp_sessp = proc_session(curp);
  590 
  591         if (uap->pid != 0 && uap->pid != curp->p_pid) {
  592                 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
  593                         if (targp != PROC_NULL)
  594                                 refheld = 1;
  595                         error = ESRCH;
  596                         goto out;
  597                 }
  598                 refheld = 1;
  599                 targp_sessp = proc_session(targp);
  600                 if (targp_sessp != curp_sessp) {
  601                         error = EPERM;
  602                         goto out;
  603                 }
  604                 if (targp->p_flag & P_EXEC) {
  605                         error = EACCES;
  606                         goto out;
  607                 }
  608         } else {
  609                 targp = curp;
  610                 targp_sessp = proc_session(targp);
  611         }
  612 
  613         if (SESS_LEADER(targp, targp_sessp)) {
  614                 error = EPERM;
  615                 goto out;
  616         }
  617         if (targp_sessp != SESSION_NULL) {
  618                 session_rele(targp_sessp);
  619                 targp_sessp = SESSION_NULL;
  620         }
  621 
  622         if (uap->pgid < 0) {
  623                 error = EINVAL;
  624                 goto out;
  625         }
  626         if (uap->pgid == 0)
  627                 uap->pgid = targp->p_pid;
  628         else if (uap->pgid != targp->p_pid) {
  629                 if ((pg = pgfind(uap->pgid)) == 0){
  630                         error = EPERM;
  631                         goto out;
  632                 }
  633                 samesess = (pg->pg_session != curp_sessp); 
  634                 pg_rele(pg);
  635                 if (samesess != 0) {
  636                         error = EPERM;
  637                         goto out;
  638                 }
  639         }
  640         error = enterpgrp(targp, uap->pgid, 0);
  641 out:
  642         if (targp_sessp != SESSION_NULL)
  643                 session_rele(targp_sessp);
  644         if (curp_sessp != SESSION_NULL)
  645                 session_rele(curp_sessp);
  646         if (refheld != 0)
  647                 proc_rele(targp);
  648         return(error);
  649 }
  650 
  651 
  652 /*
  653  * issetugid
  654  *
  655  * Description: Is current process tainted by uid or gid changes system call
  656  *
  657  * Parameters:  (void)
  658  *
  659  * Returns:     0                               Not tainted
  660  *              1                               Tainted
  661  *
  662  * Notes:       A process is considered tainted if it was created as a retult
  663  *              of an execve call from an imnage that had either the SUID or
  664  *              SGID bit set on the executable, or if it has changed any of its
  665  *              real, effective, or saved user or group IDs since beginning
  666  *              execution.
  667  */
  668 int
  669 issetugid(proc_t p, __unused struct issetugid_args *uap, register_t *retval)
  670 {
  671         /*
  672          * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
  673          * we use P_SUGID because we consider changing the owners as
  674          * "tainting" as well.
  675          * This is significant for procs that start as root and "become"
  676          * a user without an exec - programs cannot know *everything*
  677          * that libc *might* have put in their data segment.
  678          */
  679 
  680         *retval = (p->p_flag & P_SUGID) ? 1 : 0;
  681         return (0);
  682 }
  683 
  684 
  685 /*
  686  * setuid
  687  *
  688  * Description: Set user ID system call
  689  *
  690  * Parameters:  uap->uid                        uid to set
  691  *
  692  * Returns:     0                               Success
  693  *      suser:EPERM                             Permission denied
  694  *
  695  * Notes:       If called by a privileged process, this function will set the
  696  *              real, effective, and saved uid to the requested value.
  697  *
  698  *              If called from an unprivileged process, but uid is equal to the
  699  *              real or saved uid, then the effective uid will be set to the
  700  *              requested value, but the real and saved uid will not change.
  701  *
  702  *              If the credential is changed as a result of this call, then we
  703  *              flag the process as having set privilege since the last exec.
  704  */
  705 int
  706 setuid(proc_t p, struct setuid_args *uap, __unused register_t *retval)
  707 {
  708         uid_t uid;
  709         uid_t svuid = KAUTH_UID_NONE;
  710         uid_t ruid = KAUTH_UID_NONE;
  711         uid_t gmuid = KAUTH_UID_NONE;
  712         int error;
  713         kauth_cred_t my_cred, my_new_cred;
  714 
  715 
  716         uid = uap->uid;
  717 
  718         my_cred = kauth_cred_proc_ref(p);
  719 
  720         DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid);
  721         AUDIT_ARG(uid, uid, 0, 0, 0);
  722 
  723         if (uid != my_cred->cr_ruid &&  /* allow setuid(getuid()) */
  724             uid != my_cred->cr_svuid && /* allow setuid(saved uid) */
  725             (error = suser(my_cred, &p->p_acflag))) {
  726                 kauth_cred_unref(&my_cred);
  727                 return (error);
  728         }
  729         /*
  730          * Everything's okay, do it.
  731          */
  732 
  733         /*
  734          * If we are priviledged, then set the saved and real UID too;
  735          * otherwise, just set the effective UID
  736          */
  737         if (suser(my_cred, &p->p_acflag) == 0) {
  738                 svuid = uid;
  739                 ruid = uid;
  740                 /*
  741                  * Transfer proc count to new user.
  742                  * chgproccnt uses list lock for protection
  743                  */
  744                 (void)chgproccnt(uid, 1);
  745                 (void)chgproccnt(kauth_getruid(), -1);
  746         }
  747 
  748         /* get current credential and take a reference while we muck with it */
  749         for (;;) {
  750                 /*
  751                  * Only set the gmuid if the current cred has not opt'ed out;
  752                  * this normally only happens when calling setgroups() instead
  753                  * of initgroups() to set an explicit group list, or one of the
  754                  * other group manipulation functions is invoked and results in
  755                  * a dislocation (i.e. the credential group membership changes
  756                  * to something other than the default list for the user, as
  757                  * in entering a group or leaving an exclusion group).
  758                  */
  759                 if (!(my_cred->cr_flags & CRF_NOMEMBERD))
  760                         gmuid = uid;
  761 
  762                 /* 
  763                  * Set the credential with new info.  If there is no change,
  764                  * we get back the same credential we passed in; if there is
  765                  * a change, we drop the reference on the credential we
  766                  * passed in.  The subsequent compare is safe, because it is
  767                  * a pointer compare rather than a contents compare.
  768                  */
  769                 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
  770                 if (my_cred != my_new_cred) {
  771 
  772                         DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
  773 
  774                         proc_lock(p);
  775                         /*
  776                          * We need to protect for a race where another thread
  777                          * also changed the credential after we took our
  778                          * reference.  If p_ucred has changed then we should
  779                          * restart this again with the new cred.
  780                          */
  781                         if (p->p_ucred != my_cred) {
  782                                 proc_unlock(p);
  783                                 kauth_cred_unref(&my_new_cred);
  784                                 my_cred = kauth_cred_proc_ref(p);
  785                                 /* try again */
  786                                 continue;
  787                         }
  788                         p->p_ucred = my_new_cred;
  789                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
  790                         proc_unlock(p);
  791                 }
  792                 break;
  793         }
  794         /* Drop old proc reference or our extra reference */
  795         kauth_cred_unref(&my_cred);
  796         
  797         set_security_token(p);
  798         return (0);
  799 }
  800 
  801 
  802 /*
  803  * seteuid
  804  *
  805  * Description: Set effective user ID system call
  806  *
  807  * Parameters:  uap->euid                       effective uid to set
  808  *
  809  * Returns:     0                               Success
  810  *      suser:EPERM                             Permission denied
  811  *
  812  * Notes:       If called by a privileged process, or called from an
  813  *              unprivileged process but euid is equal to the real or saved
  814  *              uid, then the effective uid will be set to the requested
  815  *              value, but the real and saved uid will not change.
  816  *
  817  *              If the credential is changed as a result of this call, then we
  818  *              flag the process as having set privilege since the last exec.
  819  */
  820 int
  821 seteuid(proc_t p, struct seteuid_args *uap, __unused register_t *retval)
  822 {
  823         uid_t euid;
  824         int error;
  825         kauth_cred_t my_cred, my_new_cred;
  826 
  827         DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
  828 
  829         euid = uap->euid;
  830         AUDIT_ARG(uid, 0, euid, 0, 0);
  831 
  832         my_cred = kauth_cred_proc_ref(p);
  833 
  834         if (euid != my_cred->cr_ruid && euid != my_cred->cr_svuid &&
  835             (error = suser(my_cred, &p->p_acflag))) {
  836                 kauth_cred_unref(&my_cred);
  837                 return (error);
  838         }
  839 
  840         /*
  841          * Everything's okay, do it.  Copy credentials so other references do
  842          * not see our changes.  get current credential and take a reference 
  843          * while we muck with it
  844          */
  845         for (;;) {
  846                 /* 
  847                  * Set the credential with new info.  If there is no change,
  848                  * we get back the same credential we passed in; if there is
  849                  * a change, we drop the reference on the credential we
  850                  * passed in.  The subsequent compare is safe, because it is
  851                  * a pointer compare rather than a contents compare.
  852                  */
  853                 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_cred->cr_gmuid);
  854         
  855                 if (my_cred != my_new_cred) {
  856 
  857                         DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
  858 
  859                         proc_lock(p);
  860                         /*
  861                          * We need to protect for a race where another thread
  862                          * also changed the credential after we took our
  863                          * reference.  If p_ucred has changed then we
  864                          * should restart this again with the new cred.
  865                          */
  866                         if (p->p_ucred != my_cred) {
  867                                 proc_unlock(p);
  868                                 kauth_cred_unref(&my_new_cred);
  869                                 my_cred = kauth_cred_proc_ref(p);
  870                                 /* try again */
  871                                 continue;
  872                         }
  873                         p->p_ucred = my_new_cred;
  874                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
  875                         proc_unlock(p);
  876                 }
  877                 break;
  878         }
  879         /* drop old proc reference or our extra reference */
  880         kauth_cred_unref(&my_cred);
  881 
  882         set_security_token(p);
  883         return (0);
  884 }
  885 
  886 
  887 /*
  888  * setreuid
  889  *
  890  * Description: Set real and effective user ID system call
  891  *
  892  * Parameters:  uap->ruid                       real uid to set
  893  *              uap->euid                       effective uid to set
  894  *
  895  * Returns:     0                               Success
  896  *      suser:EPERM                             Permission denied
  897  *
  898  * Notes:       A value of -1 is a special case indicating that the uid for
  899  *              which that value is specified not be changed.  If both values
  900  *              are specified as -1, no action is taken.
  901  *
  902  *              If called by a privileged process, the real and effective uid
  903  *              will be set to the new value(s) specified.
  904  *
  905  *              If called from an unprivileged process, the real uid may be
  906  *              set to the current value of the real uid, or to the current
  907  *              value of the saved uid.  The effective uid may be set to the
  908  *              current value of any of the effective, real, or saved uid.
  909  *
  910  *              If the newly requested real uid or effective uid does not
  911  *              match the saved uid, then set the saved uid to the new
  912  *              effective uid (potentially unrecoverably dropping saved
  913  *              privilege).
  914  *
  915  *              If the credential is changed as a result of this call, then we
  916  *              flag the process as having set privilege since the last exec.
  917  */
  918 int
  919 setreuid(proc_t p, struct setreuid_args *uap, __unused register_t *retval)
  920 {
  921         uid_t ruid, euid;
  922         int error;
  923         kauth_cred_t my_cred, my_new_cred;
  924 
  925         DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
  926 
  927         ruid = uap->ruid;
  928         euid = uap->euid;
  929         if (ruid == (uid_t)-1)
  930                 ruid = KAUTH_UID_NONE;
  931         if (euid == (uid_t)-1)
  932                 euid = KAUTH_UID_NONE;
  933         AUDIT_ARG(uid, euid, ruid, 0, 0);
  934 
  935         my_cred = kauth_cred_proc_ref(p);
  936 
  937         if (((ruid != KAUTH_UID_NONE &&         /* allow no change of ruid */
  938               ruid != my_cred->cr_ruid &&       /* allow ruid = ruid */
  939               ruid != my_cred->cr_uid &&        /* allow ruid = euid */
  940               ruid != my_cred->cr_svuid) ||     /* allow ruid = svuid */
  941              (euid != KAUTH_UID_NONE &&         /* allow no change of euid */
  942               euid != my_cred->cr_uid &&        /* allow euid = euid */
  943               euid != my_cred->cr_ruid &&       /* allow euid = ruid */
  944               euid != my_cred->cr_svuid)) &&    /* allow euid = svui */
  945             (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
  946                 kauth_cred_unref(&my_cred);
  947                 return (error);
  948         }
  949 
  950         /*
  951          * Everything's okay, do it.  Copy credentials so other references do
  952          * not see our changes.  get current credential and take a reference 
  953          * while we muck with it
  954          */
  955         for (;;) {
  956                 uid_t new_euid;
  957                 uid_t new_ruid;
  958                 uid_t svuid = KAUTH_UID_NONE;
  959 
  960                 new_euid = my_cred->cr_uid;
  961                 new_ruid = my_cred->cr_ruid;
  962         
  963                 /* 
  964                  * Set the credential with new info.  If there is no change,
  965                  * we get back the same credential we passed in; if there is
  966                  * a change, we drop the reference on the credential we
  967                  * passed in.  The subsequent compare is safe, because it is
  968                  * a pointer compare rather than a contents compare.
  969                  */
  970                 if (euid == KAUTH_UID_NONE && my_cred->cr_uid != euid) {
  971                         /* changing the effective UID */
  972                         new_euid = euid;
  973                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
  974                 }
  975                 if (ruid != KAUTH_UID_NONE && my_cred->cr_ruid != ruid) {
  976                         /* changing the real UID; must do user accounting */
  977                         /* chgproccnt uses list lock for protection */
  978                         (void)chgproccnt(ruid, 1);
  979                         (void)chgproccnt(my_cred->cr_ruid, -1);
  980                         new_ruid = ruid;
  981                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
  982                 }
  983                 /*
  984                  * If the newly requested real uid or effective uid does
  985                  * not match the saved uid, then set the saved uid to the
  986                  * new effective uid.  We are protected from escalation
  987                  * by the prechecking.
  988                  */
  989                 if (my_cred->cr_svuid != uap->ruid &&
  990                     my_cred->cr_svuid != uap->euid) {
  991                         svuid = new_euid;
  992                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
  993                 }
  994 
  995                 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_cred->cr_gmuid);
  996         
  997                 if (my_cred != my_new_cred) {
  998 
  999                         DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
 1000 
 1001                         proc_lock(p);
 1002                         /*
 1003                          * We need to protect for a race where another thread
 1004                          * also changed the credential after we took our
 1005                          * reference.  If p_ucred has changed then we should
 1006                          * restart this again with the new cred.
 1007                          */
 1008                         if (p->p_ucred != my_cred) {
 1009                                 proc_unlock(p);
 1010                                 kauth_cred_unref(&my_new_cred);
 1011                                 my_cred = kauth_cred_proc_ref(p);
 1012                                 /* try again */
 1013                                 continue;
 1014                         }
 1015                         p->p_ucred = my_new_cred;
 1016                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag); /* XXX redundant? */
 1017                         proc_unlock(p);
 1018                 }
 1019                 break;
 1020         }
 1021         /* drop old proc reference or our extra reference */
 1022         kauth_cred_unref(&my_cred);
 1023 
 1024         set_security_token(p);
 1025         return (0);
 1026 }
 1027 
 1028 
 1029 /*
 1030  * setgid
 1031  *
 1032  * Description: Set group ID system call
 1033  *
 1034  * Parameters:  uap->gid                        gid to set
 1035  *
 1036  * Returns:     0                               Success
 1037  *      suser:EPERM                             Permission denied
 1038  *
 1039  * Notes:       If called by a privileged process, this function will set the
 1040  *              real, effective, and saved gid to the requested value.
 1041  *
 1042  *              If called from an unprivileged process, but gid is equal to the
 1043  *              real or saved gid, then the effective gid will be set to the
 1044  *              requested value, but the real and saved gid will not change.
 1045  *
 1046  *              If the credential is changed as a result of this call, then we
 1047  *              flag the process as having set privilege since the last exec.
 1048  *
 1049  *              As an implementation detail, the effective gid is stored as
 1050  *              the first element of the supplementary group list, and
 1051  *              therefore the effective group list may be reordered to keep
 1052  *              the supplementary group list unchanged.
 1053  */
 1054 int
 1055 setgid(proc_t p, struct setgid_args *uap, __unused register_t *retval)
 1056 {
 1057         gid_t gid;
 1058         gid_t rgid = KAUTH_GID_NONE;
 1059         gid_t svgid = KAUTH_GID_NONE;
 1060         int error;
 1061         kauth_cred_t my_cred, my_new_cred;
 1062 
 1063         DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
 1064 
 1065         gid = uap->gid;
 1066         AUDIT_ARG(gid, gid, 0, 0, 0);
 1067 
 1068         my_cred = kauth_cred_proc_ref(p);
 1069 
 1070         if (gid != my_cred->cr_rgid &&  /* allow setgid(getgid()) */
 1071             gid != my_cred->cr_svgid && /* allow setgid(saved gid) */
 1072             (error = suser(my_cred, &p->p_acflag))) {
 1073                 kauth_cred_unref(&my_cred);
 1074                 return (error);
 1075         }
 1076 
 1077         /*
 1078          * If we are priviledged, then set the saved and real GID too;
 1079          * otherwise, just set the effective GID
 1080          */
 1081         if (suser(my_cred,  &p->p_acflag) == 0) {
 1082                 svgid = gid;
 1083                 rgid = gid;
 1084         }
 1085 
 1086         /* get current credential and take a reference while we muck with it */
 1087         for (;;) {
 1088                 
 1089                 /* 
 1090                  * Set the credential with new info.  If there is no change,
 1091                  * we get back the same credential we passed in; if there is
 1092                  * a change, we drop the reference on the credential we
 1093                  * passed in.  The subsequent compare is safe, because it is
 1094                  * a pointer compare rather than a contents compare.
 1095                  */
 1096                 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
 1097                 if (my_cred != my_new_cred) {
 1098 
 1099                         DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
 1100 
 1101                         proc_lock(p);
 1102                         /*
 1103                          * We need to protect for a race where another thread
 1104                          * also changed the credential after we took our
 1105                          * reference.  If p_ucred has changed then we
 1106                          * should restart this again with the new cred.
 1107                          */
 1108                         if (p->p_ucred != my_cred) {
 1109                                 proc_unlock(p);
 1110                                 kauth_cred_unref(&my_new_cred);
 1111                                 /* try again */
 1112                                 my_cred = kauth_cred_proc_ref(p);
 1113                                 continue;
 1114                         }
 1115                         p->p_ucred = my_new_cred;
 1116                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1117                         proc_unlock(p);
 1118                 }
 1119                 break;
 1120         }
 1121         /* Drop old proc reference or our extra reference */
 1122         kauth_cred_unref(&my_cred);
 1123         
 1124         set_security_token(p);
 1125         return (0);
 1126 }
 1127 
 1128 
 1129 /*
 1130  * setegid
 1131  *
 1132  * Description: Set effective group ID system call
 1133  *
 1134  * Parameters:  uap->egid                       effective gid to set
 1135  *
 1136  * Returns:     0                               Success
 1137  *      suser:EPERM
 1138  *
 1139  * Notes:       If called by a privileged process, or called from an
 1140  *              unprivileged process but egid is equal to the real or saved
 1141  *              gid, then the effective gid will be set to the requested
 1142  *              value, but the real and saved gid will not change.
 1143  *
 1144  *              If the credential is changed as a result of this call, then we
 1145  *              flag the process as having set privilege since the last exec.
 1146  *
 1147  *              As an implementation detail, the effective gid is stored as
 1148  *              the first element of the supplementary group list, and
 1149  *              therefore the effective group list may be reordered to keep
 1150  *              the supplementary group list unchanged.
 1151  */
 1152 int
 1153 setegid(proc_t p, struct setegid_args *uap, __unused register_t *retval)
 1154 {
 1155         gid_t egid;
 1156         int error;
 1157         kauth_cred_t my_cred, my_new_cred;
 1158 
 1159         DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
 1160 
 1161         egid = uap->egid;
 1162         AUDIT_ARG(gid, 0, egid, 0, 0);
 1163 
 1164         my_cred = kauth_cred_proc_ref(p);
 1165 
 1166         if (egid != my_cred->cr_rgid &&
 1167             egid != my_cred->cr_svgid &&
 1168             (error = suser(my_cred, &p->p_acflag))) {
 1169                 kauth_cred_unref(&my_cred);
 1170                 return (error);
 1171         }
 1172 
 1173         /* get current credential and take a reference while we muck with it */
 1174         for (;;) {
 1175                 /* 
 1176                  * Set the credential with new info.  If there is no change,
 1177                  * we get back the same credential we passed in; if there is
 1178                  * a change, we drop the reference on the credential we
 1179                  * passed in.  The subsequent compare is safe, because it is
 1180                  * a pointer compare rather than a contents compare.
 1181                  */
 1182                 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
 1183                 if (my_cred != my_new_cred) {
 1184 
 1185                         DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
 1186 
 1187                         proc_lock(p);
 1188                         /*
 1189                          * We need to protect for a race where another thread
 1190                          * also changed the credential after we took our
 1191                          * reference.  If p_ucred has changed then we
 1192                          * should restart this again with the new cred.
 1193                          */
 1194                         if (p->p_ucred != my_cred) {
 1195                                 proc_unlock(p);
 1196                                 kauth_cred_unref(&my_new_cred);
 1197                                 /* try again */
 1198                                 my_cred = kauth_cred_proc_ref(p);
 1199                                 continue;
 1200                         }
 1201                         p->p_ucred = my_new_cred;
 1202                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1203                         proc_unlock(p);
 1204                 }
 1205                 break;
 1206         }
 1207 
 1208         /* Drop old proc reference or our extra reference */
 1209         kauth_cred_unref(&my_cred);
 1210 
 1211         set_security_token(p);
 1212         return (0);
 1213 }
 1214 
 1215 /*
 1216  * setregid
 1217  *
 1218  * Description: Set real and effective group ID system call
 1219  *
 1220  * Parameters:  uap->rgid                       real gid to set
 1221  *              uap->egid                       effective gid to set
 1222  *
 1223  * Returns:     0                               Success
 1224  *      suser:EPERM                             Permission denied
 1225  *
 1226  * Notes:       A value of -1 is a special case indicating that the gid for
 1227  *              which that value is specified not be changed.  If both values
 1228  *              are specified as -1, no action is taken.
 1229  *
 1230  *              If called by a privileged process, the real and effective gid
 1231  *              will be set to the new value(s) specified.
 1232  *
 1233  *              If called from an unprivileged process, the real gid may be
 1234  *              set to the current value of the real gid, or to the current
 1235  *              value of the saved gid.  The effective gid may be set to the
 1236  *              current value of any of the effective, real, or saved gid.
 1237  *
 1238  *              If the new real and effective gid will not be equal, or the
 1239  *              new real or effective gid is not the same as the saved gid,
 1240  *              then the saved gid will be updated to reflect the new
 1241  *              effective gid (potentially unrecoverably dropping saved
 1242  *              privilege).
 1243  *
 1244  *              If the credential is changed as a result of this call, then we
 1245  *              flag the process as having set privilege since the last exec.
 1246  *
 1247  *              As an implementation detail, the effective gid is stored as
 1248  *              the first element of the supplementary group list, and
 1249  *              therefore the effective group list may be reordered to keep
 1250  *              the supplementary group list unchanged.
 1251  */
 1252 int
 1253 setregid(proc_t p, struct setregid_args *uap, __unused register_t *retval)
 1254 {
 1255         gid_t rgid, egid;
 1256         int error;
 1257         kauth_cred_t my_cred, my_new_cred;
 1258 
 1259         DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
 1260 
 1261         rgid = uap->rgid;
 1262         egid = uap->egid;
 1263 
 1264         if (rgid == (uid_t)-1)
 1265                 rgid = KAUTH_GID_NONE;
 1266         if (egid == (uid_t)-1)
 1267                 egid = KAUTH_GID_NONE;
 1268         AUDIT_ARG(gid, egid, rgid, 0, 0);
 1269 
 1270         my_cred = kauth_cred_proc_ref(p);
 1271 
 1272         if (((rgid != KAUTH_UID_NONE &&         /* allow no change of rgid */
 1273               rgid != my_cred->cr_rgid &&       /* allow rgid = rgid */
 1274               rgid != my_cred->cr_gid &&        /* allow rgid = egid */
 1275               rgid != my_cred->cr_svgid) ||     /* allow rgid = svgid */
 1276              (egid != KAUTH_UID_NONE &&         /* allow no change of egid */
 1277               egid != my_cred->cr_groups[0] &&  /* allow no change of egid */
 1278               egid != my_cred->cr_gid &&        /* allow egid = egid */
 1279               egid != my_cred->cr_rgid &&       /* allow egid = rgid */
 1280               egid != my_cred->cr_svgid)) &&    /* allow egid = svgid */
 1281             (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
 1282                 kauth_cred_unref(&my_cred);
 1283                 return (error);
 1284         }
 1285 
 1286         /* get current credential and take a reference while we muck with it */
 1287         for (;;) {
 1288                 uid_t new_egid = my_cred->cr_gid;
 1289                 uid_t new_rgid = my_cred->cr_rgid;
 1290                 uid_t svgid = KAUTH_UID_NONE;
 1291 
 1292                 
 1293                 /* 
 1294                  * Set the credential with new info.  If there is no change,
 1295                  * we get back the same credential we passed in; if there is
 1296                  * a change, we drop the reference on the credential we
 1297                  * passed in.  The subsequent compare is safe, because it is
 1298                  * a pointer compare rather than a contents compare.
 1299                  */
 1300                 if (egid == KAUTH_UID_NONE && my_cred->cr_groups[0] != egid) {
 1301                         /* changing the effective GID */
 1302                         new_egid = egid;
 1303                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1304                 }
 1305                 if (rgid != KAUTH_UID_NONE && my_cred->cr_rgid != rgid) {
 1306                         /* changing the real GID */
 1307                         new_rgid = rgid;
 1308                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1309                 }
 1310                 /*
 1311                  * If the newly requested real gid or effective gid does
 1312                  * not match the saved gid, then set the saved gid to the
 1313                  * new effective gid.  We are protected from escalation
 1314                  * by the prechecking.
 1315                  */
 1316                 if (my_cred->cr_svgid != uap->rgid &&
 1317                     my_cred->cr_svgid != uap->egid) {
 1318                         svgid = new_egid;
 1319                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1320                 }
 1321 
 1322                 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
 1323                 if (my_cred != my_new_cred) {
 1324 
 1325                         DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
 1326 
 1327                         proc_lock(p);
 1328                         /* need to protect for a race where another thread
 1329                          * also changed the credential after we took our
 1330                          * reference.  If p_ucred has changed then we
 1331                          * should restart this again with the new cred.
 1332                          */
 1333                         if (p->p_ucred != my_cred) {
 1334                                 proc_unlock(p);
 1335                                 kauth_cred_unref(&my_new_cred);
 1336                                 /* try again */
 1337                                 my_cred = kauth_cred_proc_ref(p);
 1338                                 continue;
 1339                         }
 1340                         p->p_ucred = my_new_cred;
 1341                         OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag); /* XXX redundant? */
 1342                         proc_unlock(p);
 1343                 }
 1344                 break;
 1345         }
 1346         /* Drop old proc reference or our extra reference */
 1347         kauth_cred_unref(&my_cred);
 1348 
 1349         set_security_token(p);
 1350         return (0);
 1351 }
 1352 
 1353 
 1354 /*
 1355  * Set the per-thread override identity.  The first parameter can be the
 1356  * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
 1357  * can be any UID.  If it is KAUTH_UID_NONE, then as a special case, this
 1358  * means "revert to the per process credential"; otherwise, if permitted,
 1359  * it changes the effective, real, and saved UIDs and GIDs for the current
 1360  * thread to the requested UID and single GID, and clears all other GIDs.
 1361  */
 1362 int
 1363 settid(proc_t p, struct settid_args *uap, __unused register_t *retval)
 1364 {
 1365         kauth_cred_t uc;
 1366         struct uthread *uthread = get_bsdthread_info(current_thread());
 1367         uid_t uid;
 1368         gid_t gid;
 1369 
 1370         uid = uap->uid;
 1371         gid = uap->gid;
 1372         AUDIT_ARG(uid, uid, gid, gid, 0);
 1373 
 1374         if (proc_suser(p) != 0) 
 1375                 return (EPERM);
 1376         
 1377         if (uid == KAUTH_UID_NONE) {
 1378 
 1379                 /* must already be assuming another identity in order to revert back */
 1380                 if ((uthread->uu_flag & UT_SETUID) == 0)
 1381                         return (EPERM);
 1382 
 1383                 /* revert to delayed binding of process credential */
 1384                 uc = kauth_cred_proc_ref(p);
 1385                 kauth_cred_unref(&uthread->uu_ucred);
 1386                 uthread->uu_ucred = uc;
 1387                 uthread->uu_flag &= ~UT_SETUID;
 1388         } else {
 1389                 kauth_cred_t my_cred, my_new_cred;
 1390 
 1391                 /* cannot already be assuming another identity */
 1392                 if ((uthread->uu_flag & UT_SETUID) != 0) {
 1393                         return (EPERM);
 1394                 }
 1395 
 1396                 /*
 1397                  * Get a new credential instance from the old if this one
 1398                  * changes; otherwise kauth_cred_setuidgid() returns the
 1399                  * same credential.  We take an extra reference on the
 1400                  * current credential while we muck with it, so we can do
 1401                  * the post-compare for changes by pointer.
 1402                  */
 1403                 kauth_cred_ref(uthread->uu_ucred); 
 1404                 my_cred = uthread->uu_ucred;
 1405                 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
 1406                 if (my_cred != my_new_cred)
 1407                         uthread->uu_ucred = my_new_cred;
 1408                 uthread->uu_flag |= UT_SETUID;
 1409 
 1410                 /* Drop old uthread reference or our extra reference */
 1411                 kauth_cred_unref(&my_cred);
 1412         }
 1413         /*
 1414          * XXX should potentially set per thread security token (there is
 1415          * XXX none).
 1416          * XXX it is unclear whether P_SUGID should be st at this point;
 1417          * XXX in theory, it is being deprecated.
 1418          */
 1419         return (0);
 1420 }
 1421 
 1422 
 1423 /*
 1424  * Set the per-thread override identity.  Use this system call for a thread to
 1425  * assume the identity of another process or to revert back to normal identity
 1426  * of the current process.
 1427  *
 1428  * When the "assume" argument is non zero the current thread will assume the
 1429  * identity of the process represented by the pid argument.
 1430  *
 1431  * When the assume argument is zero we revert back to our normal identity.
 1432  */
 1433 int
 1434 settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused register_t *retval)
 1435 {
 1436         proc_t target_proc;
 1437         struct uthread *uthread = get_bsdthread_info(current_thread());
 1438         kauth_cred_t my_cred, my_target_cred, my_new_cred;
 1439 
 1440         AUDIT_ARG(pid, uap->pid);
 1441         AUDIT_ARG(value, uap->assume);
 1442 
 1443         if (proc_suser(p) != 0) {
 1444                 return (EPERM);
 1445         }
 1446 
 1447         /*
 1448          * XXX should potentially set per thread security token (there is
 1449          * XXX none).
 1450          * XXX it is unclear whether P_SUGID should be st at this point;
 1451          * XXX in theory, it is being deprecated.
 1452          */
 1453 
 1454         /*
 1455          * assume argument tells us to assume the identity of the process with the
 1456          * id passed in the pid argument.
 1457          */
 1458         if (uap->assume != 0) {
 1459                 /* can't do this if we have already assumed an identity */
 1460                 if ((uthread->uu_flag & UT_SETUID) != 0)
 1461                         return (EPERM);
 1462         
 1463                 target_proc = proc_find(uap->pid);
 1464                 /* can't assume the identity of the kernel process */
 1465                 if (target_proc == NULL || target_proc == kernproc) {
 1466                         if (target_proc!= NULL)
 1467                                 proc_rele(target_proc);
 1468                         return (ESRCH);
 1469                 }
 1470         
 1471                 /*
 1472                  * Take a reference on the credential used in our target
 1473                  * process then use it as the identity for our current
 1474                  * thread.  We take an extra reference on the current
 1475                  * credential while we muck with it, so we can do the
 1476                  * post-compare for changes by pointer.
 1477                  *
 1478                  * The post-compare is needed for the case that our process
 1479                  * credential has been changed to be identical to our thread
 1480                  * credential following our assumption of a per-thread one,
 1481                  * since the credential cache will maintain a unique instance.
 1482                  */
 1483                 kauth_cred_ref(uthread->uu_ucred); 
 1484                 my_cred = uthread->uu_ucred;
 1485                 my_target_cred = kauth_cred_proc_ref(target_proc);
 1486                 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
 1487                 if (my_cred != my_new_cred)
 1488                         uthread->uu_ucred = my_new_cred;
 1489         
 1490                 uthread->uu_flag |= UT_SETUID;
 1491                 
 1492                 /* Drop old uthread reference or our extra reference */
 1493                 proc_rele(target_proc);
 1494                 kauth_cred_unref(&my_cred);
 1495                 kauth_cred_unref(&my_target_cred);
 1496 
 1497                 return (0);
 1498         }
 1499         
 1500         /*
 1501          * Otherwise, we are reverting back to normal mode of operation where
 1502          * delayed binding of the process credential sets the credential in
 1503          * the thread (uu_ucred)
 1504          */
 1505         if ((uthread->uu_flag & UT_SETUID) == 0)
 1506                 return (EPERM);
 1507 
 1508         /* revert to delayed binding of process credential */
 1509         my_new_cred = kauth_cred_proc_ref(p);
 1510         kauth_cred_unref(&uthread->uu_ucred);
 1511         uthread->uu_ucred = my_new_cred;
 1512         uthread->uu_flag &= ~UT_SETUID;
 1513         
 1514         return (0);
 1515 }
 1516 
 1517 
 1518 /*
 1519  * setgroups1
 1520  *
 1521  * Description: Internal implementation for both the setgroups and initgroups
 1522  *              system calls
 1523  *
 1524  * Parameters:  gidsetsize                      Number of groups in set
 1525  *              gidset                          Pointer to group list
 1526  *              gmuid                           Base gid (initgroups only!)
 1527  *
 1528  * Returns:     0                               Success
 1529  *      suser:EPERM                             Permision denied
 1530  *              EINVAL                          Invalid gidsetsize value
 1531  *      copyin:EFAULT                           Bad gidset or gidsetsize is
 1532  *                                              too large
 1533  *
 1534  * Notes:       When called from a thread running under an assumed per-thread
 1535  *              identity, this function will operate against the per-thread
 1536  *              credential, rather than against the process credential.  In
 1537  *              this specific case, the process credential is verified to
 1538  *              still be privileged at the time of the call, rather than the
 1539  *              per-thread credential for this operation to be permitted.
 1540  *
 1541  *              This effectively means that setgroups/initigroups calls in
 1542  *              a thread running a per-thread credential should occur *after*
 1543  *              the settid call that created it, not before (unlike setuid,
 1544  *              which must be called after, since it will result in privilege
 1545  *              being dropped).
 1546  *
 1547  *              When called normally (i.e. no per-thread assumed identity),
 1548  *              the per process credential is updated per POSIX.
 1549  *
 1550  *              If the credential is changed as a result of this call, then we
 1551  *              flag the process as having set privilege since the last exec.
 1552  */
 1553 static int
 1554 setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused register_t *retval)
 1555 {
 1556         u_int ngrp;
 1557         gid_t   newgroups[NGROUPS] = { 0 };
 1558         int     error;
 1559         kauth_cred_t my_cred, my_new_cred;
 1560         struct uthread *uthread = get_bsdthread_info(current_thread());
 1561 
 1562         DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), gidsetsize, gidset, gmuid);
 1563 
 1564         ngrp = gidsetsize;
 1565         if (ngrp > NGROUPS)
 1566                 return (EINVAL);
 1567 
 1568         if ( ngrp < 1 ) {
 1569                 ngrp = 1;
 1570         } else {
 1571                 error = copyin(gidset,
 1572                         (caddr_t)newgroups, ngrp * sizeof(gid_t));
 1573                 if (error) {
 1574                         return (error);
 1575                 }
 1576         }
 1577 
 1578         my_cred = kauth_cred_proc_ref(p);
 1579         if ((error = suser(my_cred, &p->p_acflag))) {
 1580                 kauth_cred_unref(&my_cred);
 1581                 return (error);
 1582         }
 1583 
 1584         if ((uthread->uu_flag & UT_SETUID) != 0) {
 1585 #if DEBUG_CRED
 1586                 int my_cred_flags = uthread->uu_ucred->cr_flags;
 1587 #endif  /* DEBUG_CRED */
 1588                 kauth_cred_unref(&my_cred);
 1589 
 1590                 /*
 1591                  * If this thread is under an assumed identity, set the
 1592                  * supplementary grouplist on the thread credential instead
 1593                  * of the process one.  If we were the only reference holder,
 1594                  * the credential is updated in place, otherwise, our reference
 1595                  * is dropped and we get back a different cred with a reference
 1596                  * already held on it.  Because this is per-thread, we don't
 1597                  * need the referencing/locking/retry required for per-process.
 1598                  */
 1599                 my_cred = uthread->uu_ucred;
 1600                 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
 1601 #if DEBUG_CRED
 1602                 if (my_cred != uthread->uu_ucred) {
 1603                         DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred , uthread->uu_ucred ->cr_flags);
 1604                 }
 1605 #endif  /* DEBUG_CRED */
 1606         } else {
 1607 
 1608                 /*
 1609                  * get current credential and take a reference while we muck
 1610                  * with it
 1611                  */
 1612                 for (;;) {
 1613                         /* 
 1614                          * Set the credential with new info.  If there is no
 1615                          * change, we get back the same credential we passed
 1616                          * in; if there is a change, we drop the reference on
 1617                          * the credential we passed in.  The subsequent
 1618                          * compare is safe, because it is a pointer compare
 1619                          * rather than a contents compare.
 1620                          */
 1621                         my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
 1622                         if (my_cred != my_new_cred) {
 1623 
 1624                                 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
 1625 
 1626                                 proc_lock(p);
 1627                                 /*
 1628                                  * We need to protect for a race where another
 1629                                  * thread also changed the credential after we
 1630                                  * took our reference.  If p_ucred has 
 1631                                  * changed then we should restart this again
 1632                                  * with the new cred.
 1633                                  */
 1634                                 if (p->p_ucred != my_cred) {
 1635                                         proc_unlock(p);
 1636                                         kauth_cred_unref(&my_new_cred);
 1637                                         my_cred = kauth_cred_proc_ref(p);
 1638                                         /* try again */
 1639                                         continue;
 1640                                 }
 1641                                 p->p_ucred = my_new_cred;
 1642                                 OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
 1643                                 proc_unlock(p);
 1644                         }
 1645                         break;
 1646                 }
 1647                 /* Drop old proc reference or our extra reference */
 1648                 AUDIT_ARG(groupset, my_cred->cr_groups, ngrp);
 1649                 kauth_cred_unref(&my_cred);
 1650 
 1651 
 1652                 set_security_token(p);
 1653         }
 1654 
 1655         return (0);
 1656 }
 1657 
 1658 
 1659 /*
 1660  * initgroups
 1661  *
 1662  * Description: Initialize the default supplementary groups list and set the
 1663  *              gmuid for use by the external group resolver (if any)
 1664  *
 1665  * Parameters:  uap->gidsetsize                 Number of groups in set
 1666  *              uap->gidset                     Pointer to group list
 1667  *              uap->gmuid                      Base gid
 1668  *
 1669  * Returns:     0                               Success
 1670  *      setgroups1:EPERM                        Permision denied
 1671  *      setgroups1:EINVAL                       Invalid gidsetsize value
 1672  *      setgroups1:EFAULT                       Bad gidset or gidsetsize is
 1673  *
 1674  * Notes:       This function opts *IN* to memberd participation
 1675  *
 1676  *              The normal purpose of this function is for a privileged
 1677  *              process to indicate supplementary groups and identity for
 1678  *              participation in extended group membership resolution prior
 1679  *              to dropping privilege by assuming a specific user identity.
 1680  *
 1681  *              It is the first half of the primary mechanism whereby user
 1682  *              identity is established to the system by programs such as
 1683  *              /usr/bin/login.  The second half is the drop of uid privilege
 1684  *              for a specific uid corresponding to the user.
 1685  *
 1686  * See also:    setgroups1()
 1687  */
 1688 int
 1689 initgroups(proc_t p, struct initgroups_args *uap, __unused register_t *retval)
 1690 {
 1691         DEBUG_CRED_ENTER("initgroups\n");
 1692 
 1693         return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
 1694 }
 1695 
 1696 
 1697 /*
 1698  * setgroups
 1699  *
 1700  * Description: Initialize the default supplementary groups list
 1701  *
 1702  * Parameters:  gidsetsize                      Number of groups in set
 1703  *              gidset                          Pointer to group list
 1704  *
 1705  * Returns:     0                               Success
 1706  *      setgroups1:EPERM                        Permision denied
 1707  *      setgroups1:EINVAL                       Invalid gidsetsize value
 1708  *      setgroups1:EFAULT                       Bad gidset or gidsetsize is
 1709  *
 1710  * Notes:       This functions opts *OUT* of memberd participation.
 1711  *
 1712  *              This function exists for compatibility with POSIX.  Most user
 1713  *              programs should use initgroups() instead to ensure correct
 1714  *              participation in group membership resolution when utilizing
 1715  *              a directory service for authentication.
 1716  *
 1717  *              It is identical to an initgroups() call with a gmuid argument
 1718  *              of KAUTH_UID_NONE.
 1719  *
 1720  * See also:    setgroups1()
 1721  */
 1722 int
 1723 setgroups(proc_t p, struct setgroups_args *uap, __unused register_t *retval)
 1724 {
 1725         DEBUG_CRED_ENTER("setgroups\n");
 1726 
 1727         return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
 1728 }
 1729 
 1730 
 1731 /*
 1732  * Set the per-thread/per-process supplementary groups list.
 1733  */
 1734 #warning XXX implement setsgroups
 1735 int
 1736 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused register_t *retval)
 1737 {
 1738         return(ENOTSUP);
 1739 }
 1740 
 1741 /*
 1742  * Set the per-thread/per-process whiteout groups list.
 1743  */
 1744 #warning XXX implement setwgroups
 1745 int
 1746 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused register_t *retval)
 1747 {
 1748         return(ENOTSUP);
 1749 }
 1750 
 1751 
 1752 /*
 1753  * Check if gid is a member of the group set.
 1754  *
 1755  * XXX This interface is going away; use kauth_cred_ismember_gid() directly
 1756  * XXX instead.
 1757  */
 1758 int
 1759 groupmember(gid_t gid, kauth_cred_t cred)
 1760 {
 1761         int is_member;
 1762 
 1763         if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
 1764                 return (1);
 1765         return (0);
 1766 }
 1767 
 1768 
 1769 /*
 1770  * Test whether the specified credentials imply "super-user"
 1771  * privilege; if so, and we have accounting info, set the flag
 1772  * indicating use of super-powers.
 1773  * Returns 0 or error.
 1774  *
 1775  * XXX This interface is going away; use kauth_cred_issuser() directly
 1776  * XXX instead.
 1777  *
 1778  * Note:        This interface exists to implement the "has used privilege"
 1779  *              bit (ASU) in the p_acflags field of the process, which is
 1780  *              only externalized via private sysctl and in process accounting
 1781  *              records.  The flag is technically not required in either case.
 1782  */
 1783 int
 1784 suser(kauth_cred_t cred, u_short *acflag)
 1785 {
 1786 #if DIAGNOSTIC
 1787         if (!IS_VALID_CRED(cred))
 1788                 panic("suser");
 1789 #endif
 1790         if (kauth_cred_getuid(cred) == 0) {
 1791                 if (acflag)
 1792                         *acflag |= ASU;
 1793                 return (0);
 1794         }
 1795         return (EPERM);
 1796 }
 1797 
 1798 
 1799 /*
 1800  * XXX This interface is going away; use kauth_cred_issuser() directly
 1801  * XXX instead.
 1802  */
 1803 int
 1804 is_suser(void)
 1805 {
 1806         proc_t p = current_proc();
 1807 
 1808         if (!p)
 1809                 return (0);
 1810 
 1811         return (proc_suser(p) == 0);
 1812 }
 1813 
 1814 
 1815 /*
 1816  * XXX This interface is going away; use kauth_cred_issuser() directly
 1817  * XXX instead.
 1818  */
 1819 int
 1820 is_suser1(void)
 1821 {
 1822         proc_t p = current_proc();
 1823         kauth_cred_t my_cred;
 1824         int err;
 1825 
 1826         if (!p)
 1827                 return (0);
 1828 
 1829         my_cred = kauth_cred_proc_ref(p);
 1830 
 1831         err =  (suser(my_cred, &p->p_acflag) == 0 ||
 1832                         my_cred->cr_ruid == 0 || my_cred->cr_svuid == 0);
 1833         kauth_cred_unref(&my_cred);
 1834         return(err);
 1835 }
 1836 
 1837 
 1838 /*
 1839  * getlogin
 1840  *
 1841  * Description: Get login name, if available.
 1842  *
 1843  * Parameters:  uap->namebuf                    User buffer for return
 1844  *              uap->namelen                    User buffer length
 1845  *
 1846  * Returns:     0                               Success
 1847  *      copyout:EFAULT
 1848  *
 1849  * Notes:       Intended to obtain a string containing the user name of the
 1850  *              user associated with the controlling terminal for the calling
 1851  *              process.
 1852  *
 1853  *              Not very useful on modern systems, due to inherent length
 1854  *              limitations for the static array in the session structure
 1855  *              which is used to store the login name.
 1856  *
 1857  *              Permitted to return NULL
 1858  *
 1859  * XXX:         Belongs in kern_proc.c
 1860  */
 1861 int
 1862 getlogin(proc_t p, struct getlogin_args *uap, __unused register_t *retval)
 1863 {
 1864         char buffer[MAXLOGNAME+1];
 1865         struct session * sessp;
 1866 
 1867         bzero(buffer, MAXLOGNAME+1);
 1868 
 1869         sessp = proc_session(p);
 1870 
 1871         if (uap->namelen > MAXLOGNAME)
 1872                 uap->namelen = MAXLOGNAME;
 1873 
 1874         if(sessp != SESSION_NULL) {
 1875                 session_lock(sessp);
 1876                 bcopy( sessp->s_login, buffer, uap->namelen);
 1877                 session_unlock(sessp);
 1878         }
 1879         session_rele(sessp);
 1880 
 1881         return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
 1882 }
 1883 
 1884 
 1885 /*
 1886  * setlogin
 1887  *
 1888  * Description: Set login name.
 1889  *
 1890  * Parameters:  uap->namebuf                    User buffer containing name
 1891  *
 1892  * Returns:     0                               Success
 1893  *      suser:EPERM                             Permission denied
 1894  *      copyinstr:EFAULT                        User buffer invalid
 1895  *      copyinstr:EINVAL                        Supplied name was too long
 1896  *
 1897  * Notes:       This is a utility system call to support getlogin().
 1898  *
 1899  * XXX:         Belongs in kern_proc.c
 1900  */
 1901 int
 1902 setlogin(proc_t p, struct setlogin_args *uap, __unused register_t *retval)
 1903 {
 1904         int error;
 1905         int dummy=0;
 1906         char buffer[MAXLOGNAME+1];
 1907         struct session * sessp;
 1908 
 1909         if ((error = proc_suser(p)))
 1910                 return (error);
 1911 
 1912         bzero(&buffer[0], MAXLOGNAME+1);
 1913 
 1914 
 1915         error = copyinstr(uap->namebuf,
 1916             (caddr_t) &buffer[0],
 1917             MAXLOGNAME - 1, (size_t *)&dummy);
 1918 
 1919         sessp = proc_session(p);
 1920 
 1921         if (sessp != SESSION_NULL) {
 1922                 session_lock(sessp);
 1923                 bcopy(buffer, sessp->s_login, MAXLOGNAME);
 1924                 session_unlock(sessp);
 1925                 session_rele(sessp);
 1926         }
 1927 
 1928 
 1929         if (!error) {
 1930                 AUDIT_ARG(text, buffer);
 1931          } else if (error == ENAMETOOLONG)
 1932                 error = EINVAL;
 1933         return (error);
 1934 }
 1935 
 1936 
 1937 /* Set the secrity token of the task with current euid and eguid */
 1938 /*
 1939  * XXX This needs to change to give the task a reference and/or an opaque
 1940  * XXX identifier.
 1941  */
 1942 int
 1943 set_security_token(proc_t p)
 1944 {
 1945         security_token_t sec_token;
 1946         audit_token_t    audit_token;
 1947         kauth_cred_t my_cred;
 1948         host_priv_t host_priv;
 1949 
 1950         /*
 1951          * Don't allow a vfork child to override the parent's token settings
 1952          * (since they share a task).  Instead, the child will just have to
 1953          * suffer along using the parent's token until the exec().  It's all
 1954          * undefined behavior anyway, right?
 1955          */
 1956         if (p->task == current_task()) {
 1957                 uthread_t        uthread;
 1958                 uthread = (uthread_t)get_bsdthread_info(current_thread());
 1959                 if (uthread->uu_flag & UT_VFORK)
 1960                         return (1);
 1961         }
 1962                 
 1963         my_cred = kauth_cred_proc_ref(p);
 1964         /* XXX mach_init doesn't have a p_ucred when it calls this function */
 1965         if (IS_VALID_CRED(my_cred)) {
 1966                 sec_token.val[0] = kauth_cred_getuid(my_cred);
 1967                 sec_token.val[1] = my_cred->cr_gid;
 1968         } else {
 1969                 sec_token.val[0] = 0;
 1970                 sec_token.val[1] = 0;
 1971         }
 1972 
 1973         /*
 1974          * The current layout of the Mach audit token explicitly
 1975          * adds these fields.  But nobody should rely on such
 1976          * a literal representation.  Instead, the BSM library
 1977          * provides a function to convert an audit token into
 1978          * a BSM subject.  Use of that mechanism will isolate
 1979          * the user of the trailer from future representation
 1980          * changes.
 1981          */
 1982         audit_token.val[0] = my_cred->cr_au.ai_auid;
 1983         audit_token.val[1] = my_cred->cr_uid;
 1984         audit_token.val[2] = my_cred->cr_gid;
 1985         audit_token.val[3] = my_cred->cr_ruid;
 1986         audit_token.val[4] = my_cred->cr_rgid;
 1987         audit_token.val[5] = p->p_pid;
 1988         audit_token.val[6] = my_cred->cr_au.ai_asid;
 1989         audit_token.val[7] = my_cred->cr_au.ai_termid.port;
 1990 
 1991 #if CONFIG_MACF_MACH
 1992         mac_task_label_update_cred(my_cred, p->task);
 1993 #endif
 1994         
 1995         host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
 1996 #if CONFIG_MACF
 1997         if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
 1998                 host_priv = HOST_PRIV_NULL;
 1999 #endif
 2000         kauth_cred_unref(&my_cred);
 2001 
 2002         return (host_security_set_task_token(host_security_self(),
 2003                                            p->task,
 2004                                            sec_token,
 2005                                            audit_token,
 2006                                            host_priv) != KERN_SUCCESS);
 2007 }
 2008 
 2009 
 2010 /*
 2011  * Fill in a struct xucred based on a kauth_cred_t.
 2012  */
 2013 __private_extern__
 2014 void
 2015 cru2x(kauth_cred_t cr, struct xucred *xcr)
 2016 {
 2017 
 2018         bzero(xcr, sizeof(*xcr));
 2019         xcr->cr_version = XUCRED_VERSION;
 2020         xcr->cr_uid = kauth_cred_getuid(cr);
 2021         xcr->cr_ngroups = cr->cr_ngroups;
 2022         bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
 2023 }
 2024 
 2025 #if CONFIG_LCTX
 2026 
 2027 /*
 2028  * Set Login Context ID
 2029  */
 2030 /*
 2031  * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
 2032  *          LCTX by its own locks.
 2033  */
 2034 int
 2035 setlcid(proc_t p0, struct setlcid_args *uap, __unused register_t *retval)
 2036 {
 2037         proc_t p;
 2038         struct lctx *l;
 2039         int error = 0;
 2040         int refheld = 0;
 2041 
 2042         AUDIT_ARG(pid, uap->pid);
 2043         AUDIT_ARG(value, uap->lcid);
 2044         if (uap->pid == LCID_PROC_SELF) {       /* Create/Join/Leave */
 2045                 p = p0;
 2046         } else {                                /* Adopt/Orphan */
 2047                 p = proc_find(uap->pid);
 2048                 if (p == NULL)
 2049                         return (ESRCH);
 2050                 refheld = 1;
 2051         }
 2052 
 2053 #if CONFIG_MACF
 2054         error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
 2055         if (error)
 2056                 goto out;
 2057 #endif
 2058 
 2059         switch (uap->lcid) {
 2060         /* Leave/Orphan */
 2061         case LCID_REMOVE:
 2062 
 2063                 /* Only root may Leave/Orphan. */
 2064                 if (!is_suser1()) {
 2065                         error = EPERM;
 2066                         goto out;
 2067                 }
 2068 
 2069                 /* Process not in login context. */
 2070                 if (p->p_lctx == NULL) {
 2071                         error = ENOATTR;
 2072                         goto out;
 2073                 }
 2074 
 2075                 l = NULL;
 2076 
 2077                 break;
 2078 
 2079         /* Create */
 2080         case LCID_CREATE:
 2081 
 2082                 /* Create only valid for self! */
 2083                 if (uap->pid != LCID_PROC_SELF) {
 2084                         error = EPERM;
 2085                         goto out;
 2086                 }
 2087 
 2088                 /* Already in a login context. */
 2089                 if (p->p_lctx != NULL) {
 2090                         error = EPERM;
 2091                         goto out;
 2092                 }
 2093 
 2094                 l = lccreate();
 2095                 if (l == NULL) {
 2096                         error = ENOMEM;
 2097                         goto out;
 2098                 }
 2099 
 2100                 LCTX_LOCK(l);
 2101 
 2102                 break;
 2103 
 2104         /* Join/Adopt */
 2105         default:
 2106 
 2107                 /* Only root may Join/Adopt. */
 2108                 if (!is_suser1()) {
 2109                         error = EPERM;
 2110                         goto out;
 2111                 }
 2112 
 2113                 l = lcfind(uap->lcid);
 2114                 if (l == NULL) {
 2115                         error = ENOATTR;
 2116                         goto out;
 2117                 }
 2118 
 2119                 break;
 2120         }
 2121 
 2122         ALLLCTX_LOCK;
 2123         leavelctx(p);
 2124         enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
 2125         ALLLCTX_UNLOCK;
 2126 
 2127 out:
 2128         if (refheld != 0)
 2129                 proc_rele(p);
 2130         return (error);
 2131 }
 2132 
 2133 /*
 2134  * Get Login Context ID
 2135  */
 2136 /*
 2137  * MPSAFE - membership of (visible) process in a login context
 2138  *          protected by the all-context lock.
 2139  */
 2140 int
 2141 getlcid(proc_t p0, struct getlcid_args *uap, register_t *retval)
 2142 {
 2143         proc_t p;
 2144         int error = 0;
 2145         int refheld = 0;
 2146 
 2147         AUDIT_ARG(pid, uap->pid);
 2148         if (uap->pid == LCID_PROC_SELF) {
 2149                 p = p0;
 2150         } else {
 2151                 p = proc_find(uap->pid);
 2152                 if (p == NULL)
 2153                         return (ESRCH);
 2154                 refheld = 1;
 2155         }
 2156 
 2157 #if CONFIG_MACF
 2158         error = mac_proc_check_getlcid(p0, p, uap->pid);
 2159         if (error)
 2160                 goto out;
 2161 #endif
 2162         ALLLCTX_LOCK;
 2163         if (p->p_lctx == NULL) {
 2164                 error = ENOATTR;
 2165                 ALLLCTX_UNLOCK;
 2166                 goto out;
 2167         }
 2168         *retval = p->p_lctx->lc_id;
 2169         ALLLCTX_UNLOCK;
 2170  out:
 2171         if (refheld != 0)
 2172                 proc_rele(p);
 2173 
 2174         return (error);
 2175 }
 2176 #else   /* LCTX */
 2177 int
 2178 setlcid(proc_t p0, struct setlcid_args *uap, register_t *retval)
 2179 {
 2180 
 2181         return (ENOSYS);
 2182 }
 2183 
 2184 int
 2185 getlcid(proc_t p0, struct getlcid_args *uap, register_t *retval)
 2186 {
 2187 
 2188         return (ENOSYS);
 2189 }
 2190 #endif  /* !LCTX */

Cache object: eb8c5d6a1d59f107e335fdf58b1f23e7


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