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/servers/fs/protect.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 /* This file deals with protection in the file system.  It contains the code
    2  * for four system calls that relate to protection.
    3  *
    4  * The entry points into this file are
    5  *   do_chmod:  perform the CHMOD system call
    6  *   do_chown:  perform the CHOWN system call
    7  *   do_umask:  perform the UMASK system call
    8  *   do_access: perform the ACCESS system call
    9  *   forbidden: check to see if a given access is allowed on a given inode
   10  */
   11 
   12 #include "fs.h"
   13 #include <unistd.h>
   14 #include <minix/callnr.h>
   15 #include "buf.h"
   16 #include "file.h"
   17 #include "fproc.h"
   18 #include "inode.h"
   19 #include "param.h"
   20 #include "super.h"
   21 
   22 /*===========================================================================*
   23  *                              do_chmod                                     *
   24  *===========================================================================*/
   25 PUBLIC int do_chmod()
   26 {
   27 /* Perform the chmod(name, mode) system call. */
   28 
   29   register struct inode *rip;
   30   register int r;
   31 
   32   /* Temporarily open the file. */
   33   if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
   34   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
   35 
   36   /* Only the owner or the super_user may change the mode of a file.
   37    * No one may change the mode of a file on a read-only file system.
   38    */
   39   if (rip->i_uid != fp->fp_effuid && !super_user)
   40         r = EPERM;
   41   else
   42         r = read_only(rip);
   43 
   44   /* If error, return inode. */
   45   if (r != OK)  {
   46         put_inode(rip);
   47         return(r);
   48   }
   49 
   50   /* Now make the change. Clear setgid bit if file is not in caller's grp */
   51   rip->i_mode = (rip->i_mode & ~ALL_MODES) | (m_in.mode & ALL_MODES);
   52   if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT;
   53   rip->i_update |= CTIME;
   54   rip->i_dirt = DIRTY;
   55 
   56   put_inode(rip);
   57   return(OK);
   58 }
   59 
   60 /*===========================================================================*
   61  *                              do_chown                                     *
   62  *===========================================================================*/
   63 PUBLIC int do_chown()
   64 {
   65 /* Perform the chown(name, owner, group) system call. */
   66 
   67   register struct inode *rip;
   68   register int r;
   69 
   70   /* Temporarily open the file. */
   71   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
   72   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
   73 
   74   /* Not permitted to change the owner of a file on a read-only file sys. */
   75   r = read_only(rip);
   76   if (r == OK) {
   77         /* FS is R/W.  Whether call is allowed depends on ownership, etc. */
   78         if (super_user) {
   79                 /* The super user can do anything. */
   80                 rip->i_uid = m_in.owner;        /* others later */
   81         } else {
   82                 /* Regular users can only change groups of their own files. */
   83                 if (rip->i_uid != fp->fp_effuid) r = EPERM;
   84                 if (rip->i_uid != m_in.owner) r = EPERM;  /* no giving away */
   85                 if (fp->fp_effgid != m_in.group) r = EPERM;
   86         }
   87   }
   88   if (r == OK) {
   89         rip->i_gid = m_in.group;
   90         rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
   91         rip->i_update |= CTIME;
   92         rip->i_dirt = DIRTY;
   93   }
   94 
   95   put_inode(rip);
   96   return(r);
   97 }
   98 
   99 /*===========================================================================*
  100  *                              do_umask                                     *
  101  *===========================================================================*/
  102 PUBLIC int do_umask()
  103 {
  104 /* Perform the umask(co_mode) system call. */
  105   register mode_t r;
  106 
  107   r = ~fp->fp_umask;            /* set 'r' to complement of old mask */
  108   fp->fp_umask = ~(m_in.co_mode & RWX_MODES);
  109   return(r);                    /* return complement of old mask */
  110 }
  111 
  112 /*===========================================================================*
  113  *                              do_access                                    *
  114  *===========================================================================*/
  115 PUBLIC int do_access()
  116 {
  117 /* Perform the access(name, mode) system call. */
  118 
  119   struct inode *rip;
  120   register int r;
  121 
  122   /* First check to see if the mode is correct. */
  123   if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK)
  124         return(EINVAL);
  125 
  126   /* Temporarily open the file whose access is to be checked. */
  127   if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
  128   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  129 
  130   /* Now check the permissions. */
  131   r = forbidden(rip, (mode_t) m_in.mode);
  132   put_inode(rip);
  133   return(r);
  134 }
  135 
  136 /*===========================================================================*
  137  *                              forbidden                                    *
  138  *===========================================================================*/
  139 PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
  140 {
  141 /* Given a pointer to an inode, 'rip', and the access desired, determine
  142  * if the access is allowed, and if not why not.  The routine looks up the
  143  * caller's uid in the 'fproc' table.  If access is allowed, OK is returned
  144  * if it is forbidden, EACCES is returned.
  145  */
  146 
  147   register struct inode *old_rip = rip;
  148   register struct super_block *sp;
  149   register mode_t bits, perm_bits;
  150   int r, shift, test_uid, test_gid, type;
  151 
  152   if (rip->i_mount == I_MOUNT)  /* The inode is mounted on. */
  153         for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
  154                 if (sp->s_imount == rip) {
  155                         rip = get_inode(sp->s_dev, ROOT_INODE);
  156                         break;
  157                 } /* if */
  158 
  159   /* Isolate the relevant rwx bits from the mode. */
  160   bits = rip->i_mode;
  161   test_uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
  162   test_gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
  163   if (test_uid == SU_UID) {
  164         /* Grant read and write permission.  Grant search permission for
  165          * directories.  Grant execute permission (for non-directories) if
  166          * and only if one of the 'X' bits is set.
  167          */
  168         if ( (bits & I_TYPE) == I_DIRECTORY ||
  169              bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
  170                 perm_bits = R_BIT | W_BIT | X_BIT;
  171         else
  172                 perm_bits = R_BIT | W_BIT;
  173   } else {
  174         if (test_uid == rip->i_uid) shift = 6;          /* owner */
  175         else if (test_gid == rip->i_gid ) shift = 3;    /* group */
  176         else shift = 0;                                 /* other */
  177         perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
  178   }
  179 
  180   /* If access desired is not a subset of what is allowed, it is refused. */
  181   r = OK;
  182   if ((perm_bits | access_desired) != perm_bits) r = EACCES;
  183 
  184   /* Check to see if someone is trying to write on a file system that is
  185    * mounted read-only.
  186    */
  187   type = rip->i_mode & I_TYPE;
  188   if (r == OK)
  189         if (access_desired & W_BIT)
  190                 r = read_only(rip);
  191 
  192   if (rip != old_rip) put_inode(rip);
  193 
  194   return(r);
  195 }
  196 
  197 /*===========================================================================*
  198  *                              read_only                                    *
  199  *===========================================================================*/
  200 PUBLIC int read_only(ip)
  201 struct inode *ip;               /* ptr to inode whose file sys is to be cked */
  202 {
  203 /* Check to see if the file system on which the inode 'ip' resides is mounted
  204  * read only.  If so, return EROFS, else return OK.
  205  */
  206 
  207   register struct super_block *sp;
  208 
  209   sp = ip->i_sp;
  210   return(sp->s_rd_only ? EROFS : OK);
  211 }

Cache object: d335aa31899533f21213a990abd756c0


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