(root)/
tar-1.35/
gnu/
euidaccess.c
       1  /* euidaccess -- check if effective user id can access file
       2  
       3     Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2023 Free
       4     Software Foundation, Inc.
       5  
       6     This file is part of the GNU C Library.
       7  
       8     This file is free software: you can redistribute it and/or modify
       9     it under the terms of the GNU Lesser General Public License as
      10     published by the Free Software Foundation; either version 2.1 of the
      11     License, or (at your option) any later version.
      12  
      13     This file is distributed in the hope that it will be useful,
      14     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16     GNU Lesser General Public License for more details.
      17  
      18     You should have received a copy of the GNU Lesser General Public License
      19     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      20  
      21  /* Written by David MacKenzie and Torbjorn Granlund.
      22     Adapted for GNU C library by Roland McGrath.  */
      23  
      24  #ifndef _LIBC
      25  # include <config.h>
      26  #endif
      27  
      28  #include <fcntl.h>
      29  #include <sys/types.h>
      30  #include <sys/stat.h>
      31  #include <unistd.h>
      32  #if defined _WIN32 && ! defined __CYGWIN__
      33  # include <io.h>
      34  #else
      35  # include "root-uid.h"
      36  #endif
      37  
      38  #if HAVE_LIBGEN_H
      39  # include <libgen.h>
      40  #endif
      41  
      42  #include <errno.h>
      43  #ifndef __set_errno
      44  # define __set_errno(val) errno = (val)
      45  #endif
      46  
      47  #if defined EACCES && !defined EACCESS
      48  # define EACCESS EACCES
      49  #endif
      50  
      51  #ifndef F_OK
      52  # define F_OK 0
      53  # define X_OK 1
      54  # define W_OK 2
      55  # define R_OK 4
      56  #endif
      57  
      58  
      59  #ifdef _LIBC
      60  
      61  # define access __access
      62  # define getuid __getuid
      63  # define getgid __getgid
      64  # define geteuid __geteuid
      65  # define getegid __getegid
      66  # define group_member __group_member
      67  # define euidaccess __euidaccess
      68  # undef stat
      69  # define stat stat64
      70  
      71  #endif
      72  
      73  /* Return 0 if the user has permission of type MODE on FILE;
      74     otherwise, return -1 and set 'errno'.
      75     Like access, except that it uses the effective user and group
      76     id's instead of the real ones, and it does not always check for read-only
      77     file system, text busy, etc.  */
      78  
      79  int
      80  euidaccess (const char *file, int mode)
      81  {
      82  #if HAVE_FACCESSAT                   /* glibc, AIX 7, Solaris 11, Cygwin 1.7 */
      83    return faccessat (AT_FDCWD, file, mode, AT_EACCESS);
      84  #elif defined EFF_ONLY_OK               /* IRIX, OSF/1, Interix */
      85    return access (file, mode | EFF_ONLY_OK);
      86  #elif defined ACC_SELF                  /* AIX */
      87    return accessx (file, mode, ACC_SELF);
      88  #elif HAVE_EACCESS                      /* FreeBSD */
      89    return eaccess (file, mode);
      90  #elif defined _WIN32 && ! defined __CYGWIN__  /* mingw */
      91    return _access (file, mode);
      92  #else              /* Mac OS X, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, BeOS */
      93  
      94    uid_t uid = getuid ();
      95    gid_t gid = getgid ();
      96    uid_t euid = geteuid ();
      97    gid_t egid = getegid ();
      98    struct stat stats;
      99  
     100  # if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS
     101  
     102    /* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to
     103       return the correct result even if this would make it
     104       nonreentrant.  Define this only if your entire application is
     105       safe even if the uid or gid might temporarily change.  If your
     106       application uses signal handlers or threads it is probably not
     107       safe.  */
     108  
     109    if (mode == F_OK)
     110      {
     111        int result = stat (file, &stats);
     112        return result != 0 && errno == EOVERFLOW ? 0 : result;
     113      }
     114    else
     115      {
     116        int result;
     117        int saved_errno;
     118  
     119        if (uid != euid)
     120          setreuid (euid, uid);
     121        if (gid != egid)
     122          setregid (egid, gid);
     123  
     124        result = access (file, mode);
     125        saved_errno = errno;
     126  
     127        /* Restore them.  */
     128        if (uid != euid)
     129          setreuid (uid, euid);
     130        if (gid != egid)
     131          setregid (gid, egid);
     132  
     133        errno = saved_errno;
     134        return result;
     135      }
     136  
     137  # else
     138  
     139    /* The following code assumes the traditional Unix model, and is not
     140       correct on systems that have ACLs or the like.  However, it's
     141       better than nothing, and it is reentrant.  */
     142  
     143    unsigned int granted;
     144    if (uid == euid && gid == egid)
     145      /* If we are not set-uid or set-gid, access does the same.  */
     146      return access (file, mode);
     147  
     148    if (stat (file, &stats) == -1)
     149      return mode == F_OK && errno == EOVERFLOW ? 0 : -1;
     150  
     151    /* The super-user can read and write any file, and execute any file
     152       that anyone can execute.  */
     153    if (euid == ROOT_UID
     154        && ((mode & X_OK) == 0
     155            || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
     156      return 0;
     157  
     158    /* Convert the mode to traditional form, clearing any bogus bits.  */
     159    if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0)
     160      mode &= 7;
     161    else
     162      mode = ((mode & R_OK ? 4 : 0)
     163              + (mode & W_OK ? 2 : 0)
     164              + (mode & X_OK ? 1 : 0));
     165  
     166    if (mode == 0)
     167      return 0;                   /* The file exists.  */
     168  
     169    /* Convert the file's permission bits to traditional form.  */
     170    if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6)
     171        && S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3)
     172        && S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0))
     173      granted = stats.st_mode;
     174    else
     175      granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0)
     176                 + (stats.st_mode & S_IWUSR ? 2 << 6 : 0)
     177                 + (stats.st_mode & S_IXUSR ? 1 << 6 : 0)
     178                 + (stats.st_mode & S_IRGRP ? 4 << 3 : 0)
     179                 + (stats.st_mode & S_IWGRP ? 2 << 3 : 0)
     180                 + (stats.st_mode & S_IXGRP ? 1 << 3 : 0)
     181                 + (stats.st_mode & S_IROTH ? 4 << 0 : 0)
     182                 + (stats.st_mode & S_IWOTH ? 2 << 0 : 0)
     183                 + (stats.st_mode & S_IXOTH ? 1 << 0 : 0));
     184  
     185    if (euid == stats.st_uid)
     186      granted >>= 6;
     187    else if (egid == stats.st_gid || group_member (stats.st_gid))
     188      granted >>= 3;
     189  
     190    if ((mode & ~granted) == 0)
     191      return 0;
     192    __set_errno (EACCESS);
     193    return -1;
     194  
     195  # endif
     196  #endif
     197  }
     198  #undef euidaccess
     199  #ifdef weak_alias
     200  weak_alias (__euidaccess, euidaccess)
     201  #endif
     202  
     203  #ifdef TEST
     204  # include <error.h>
     205  # include <stdio.h>
     206  # include <stdlib.h>
     207  
     208  int
     209  main (int argc, char **argv)
     210  {
     211    char *file;
     212    int mode;
     213    int err;
     214  
     215    if (argc < 3)
     216      abort ();
     217    file = argv[1];
     218    mode = atoi (argv[2]);
     219  
     220    err = euidaccess (file, mode);
     221    printf ("%d\n", err);
     222    if (err != 0)
     223      error (0, errno, "%s", file);
     224    exit (0);
     225  }
     226  #endif