LCOV - code coverage report
Current view: top level - bash-4.4.23/lib/sh - eaccess.c (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 15 35 42.9 %
Date: 2020-10-29 14:49:28 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* eaccess.c - eaccess replacement for the shell, plus other access functions. */
       2             : 
       3             : /* Copyright (C) 2006-2010 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of GNU Bash, the Bourne Again SHell.
       6             : 
       7             :    Bash is free software: you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation, either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    Bash is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #if defined (HAVE_CONFIG_H)
      22             : #  include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdio.h>
      26             : 
      27             : #include "bashtypes.h"
      28             : 
      29             : #if defined (HAVE_UNISTD_H)
      30             : #  include <unistd.h>
      31             : #endif
      32             : 
      33             : #include "bashansi.h"
      34             : 
      35             : #include <errno.h>
      36             : #if !defined (errno)
      37             : extern int errno;
      38             : #endif /* !errno */
      39             : 
      40             : #if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
      41             : #  include <sys/file.h>
      42             : #endif /* !_POSIX_VERSION */
      43             : #include "posixstat.h"
      44             : #include "filecntl.h"
      45             : 
      46             : #include "shell.h"
      47             : 
      48             : #if !defined (R_OK)
      49             : #define R_OK 4
      50             : #define W_OK 2
      51             : #define X_OK 1
      52             : #define F_OK 0
      53             : #endif /* R_OK */
      54             : 
      55             : static int path_is_devfd __P((const char *));
      56             : static int sh_stataccess __P((const char *, int));
      57             : #if HAVE_DECL_SETREGID && \
      58             :     !(defined (HAVE_FACCESSAT) && defined (AT_EACCESS)) && \
      59             :     !defined (HAVE_EACCESS) && !defined (EFF_ONLY_OK)
      60             : static int sh_euidaccess __P((const char *, int));
      61             : #endif
      62             : 
      63             : static int
      64     9171656 : path_is_devfd (path)
      65             :      const char *path;
      66             : {
      67     9171656 :   if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
      68             :     return 1;
      69     9171656 :   else if (STREQN (path, "/dev/std", 8))
      70             :     {
      71           0 :       if (STREQ (path+8, "in") || STREQ (path+8, "out") || STREQ (path+8, "err"))
      72             :         return 1;
      73             :       else
      74           0 :         return 0;
      75             :     }
      76             :   else
      77             :     return 0;
      78             : }
      79             : 
      80             : /* A wrapper for stat () which disallows pathnames that are empty strings
      81             :    and handles /dev/fd emulation on systems that don't have it. */
      82             : int
      83     5531740 : sh_stat (path, finfo)
      84             :      const char *path;
      85             :      struct stat *finfo;
      86             : {
      87     5531740 :   static char *pbuf = 0;
      88             : 
      89     5531740 :   if (*path == '\0')
      90             :     {
      91          14 :       errno = ENOENT;
      92          14 :       return (-1);
      93             :     }
      94     5531726 :   if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
      95             :     {
      96             : #if !defined (HAVE_DEV_FD)
      97             :       intmax_t fd;
      98             :       int r;
      99             : 
     100             :       if (legal_number (path + 8, &fd) && fd == (int)fd)
     101             :         {
     102             :           r = fstat ((int)fd, finfo);
     103             :           if (r == 0 || errno != EBADF)
     104             :             return (r);
     105             :         }
     106             :       errno = ENOENT;
     107             :       return (-1);
     108             : #else
     109             :   /* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
     110             :      trailing slash.  Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
     111             :      On most systems, with the notable exception of linux, this is
     112             :      effectively a no-op. */
     113           0 :       pbuf = xrealloc (pbuf, sizeof (DEV_FD_PREFIX) + strlen (path + 8));
     114           0 :       strcpy (pbuf, DEV_FD_PREFIX);
     115           0 :       strcat (pbuf, path + 8);
     116           0 :       return (stat (pbuf, finfo));
     117             : #endif /* !HAVE_DEV_FD */
     118             :     }
     119             : #if !defined (HAVE_DEV_STDIN)
     120             :   else if (STREQN (path, "/dev/std", 8))
     121             :     {
     122             :       if (STREQ (path+8, "in"))
     123             :         return (fstat (0, finfo));
     124             :       else if (STREQ (path+8, "out"))
     125             :         return (fstat (1, finfo));
     126             :       else if (STREQ (path+8, "err"))
     127             :         return (fstat (2, finfo));
     128             :       else
     129             :         return (stat (path, finfo));
     130             :     }
     131             : #endif /* !HAVE_DEV_STDIN */
     132    11063452 :   return (stat (path, finfo));
     133             : }
     134             : 
     135             : /* Do the same thing access(2) does, but use the effective uid and gid,
     136             :    and don't make the mistake of telling root that any file is
     137             :    executable.  This version uses stat(2). */
     138             : static int
     139           0 : sh_stataccess (path, mode)
     140             :      const char *path;
     141             :      int mode;
     142             : {
     143           0 :   struct stat st;
     144             : 
     145           0 :   if (sh_stat (path, &st) < 0)
     146             :     return (-1);
     147             : 
     148           0 :   if (current_user.euid == 0)
     149             :     {
     150             :       /* Root can read or write any file. */
     151           0 :       if ((mode & X_OK) == 0)
     152             :         return (0);
     153             : 
     154             :       /* Root can execute any file that has any one of the execute
     155             :          bits set. */
     156           0 :       if (st.st_mode & S_IXUGO)
     157             :         return (0);
     158             :     }
     159             : 
     160           0 :   if (st.st_uid == current_user.euid)   /* owner */
     161           0 :     mode <<= 6;
     162           0 :   else if (group_member (st.st_gid))
     163           0 :     mode <<= 3;
     164             : 
     165           0 :   if (st.st_mode & mode)
     166             :     return (0);
     167             : 
     168           0 :   errno = EACCES;
     169           0 :   return (-1);
     170             : }
     171             : 
     172             : #if HAVE_DECL_SETREGID && \
     173             :     !(defined (HAVE_FACCESSAT) && defined (AT_EACCESS)) && \
     174             :     !defined (HAVE_EACCESS) && !defined (EFF_ONLY_OK)
     175             : /* Version to call when uid != euid or gid != egid.  We temporarily swap
     176             :    the effective and real uid and gid as appropriate. */
     177             : static int
     178             : sh_euidaccess (path, mode)
     179             :      const char *path;
     180             :      int mode;
     181             : {
     182             :   int r, e;
     183             : 
     184             :   if (current_user.uid != current_user.euid)
     185             :     setreuid (current_user.euid, current_user.uid);
     186             :   if (current_user.gid != current_user.egid)
     187             :     setregid (current_user.egid, current_user.gid);
     188             : 
     189             :   r = access (path, mode);
     190             :   e = errno;
     191             : 
     192             :   if (current_user.uid != current_user.euid)
     193             :     setreuid (current_user.uid, current_user.euid);
     194             :   if (current_user.gid != current_user.egid)
     195             :     setregid (current_user.gid, current_user.egid);
     196             : 
     197             :   errno = e;
     198             :   return r;  
     199             : }
     200             : #endif
     201             : 
     202             : int
     203     9171656 : sh_eaccess (path, mode)
     204             :      const char *path;
     205             :      int mode;
     206             : {
     207     9171656 :   int ret;
     208             : 
     209     9171656 :   if (path_is_devfd (path))
     210           0 :     return (sh_stataccess (path, mode));
     211             : 
     212             : #if (defined (HAVE_FACCESSAT) && defined (AT_EACCESS)) || defined (HAVE_EACCESS)
     213             : #  if defined (HAVE_FACCESSAT) && defined (AT_EACCESS)
     214     9171656 :   ret = faccessat (AT_FDCWD, path, mode, AT_EACCESS);
     215             : #  else         /* HAVE_EACCESS */      /* FreeBSD */
     216             :   ret = eaccess (path, mode);   /* XXX -- not always correct for X_OK */
     217             : #  endif        /* HAVE_EACCESS */
     218             : #  if defined (__FreeBSD__) || defined (SOLARIS)
     219             :   if (ret == 0 && current_user.euid == 0 && mode == X_OK)
     220             :     return (sh_stataccess (path, mode));
     221             : #  endif        /* __FreeBSD__ || SOLARIS */
     222     9171656 :   return ret;
     223             : #elif defined (EFF_ONLY_OK)             /* SVR4(?), SVR4.2 */
     224             :   return access (path, mode|EFF_ONLY_OK);
     225             : #else
     226             :   if (mode == F_OK)
     227             :     return (sh_stataccess (path, mode));
     228             :     
     229             : #  if HAVE_DECL_SETREGID
     230             :   if (current_user.uid != current_user.euid || current_user.gid != current_user.egid)
     231             :     return (sh_euidaccess (path, mode));
     232             : #  endif
     233             : 
     234             :   if (current_user.uid == current_user.euid && current_user.gid == current_user.egid)
     235             :     {
     236             :       ret = access (path, mode);
     237             : #if defined (__FreeBSD__) || defined (SOLARIS)
     238             :       if (ret == 0 && current_user.euid == 0 && mode == X_OK)
     239             :         return (sh_stataccess (path, mode));
     240             : #endif
     241             :       return ret;
     242             :     }
     243             : 
     244             :   return (sh_stataccess (path, mode));
     245             : #endif
     246             : }

Generated by: LCOV version 1.14.0.6.4058