Back to index

glibc  2.9
faccessat.c
Go to the documentation of this file.
00001 /* Test for access to file, relative to open directory.  Linux version.
00002    Copyright (C) 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <stddef.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <sys/types.h>
00027 #include <alloca.h>
00028 #include <kernel-features.h>
00029 #include <sysdep.h>
00030 
00031 
00032 int
00033 faccessat (fd, file, mode, flag)
00034      int fd;
00035      const char *file;
00036      int mode;
00037      int flag;
00038 {
00039   if (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS))
00040     {
00041       __set_errno (EINVAL);
00042       return -1;
00043     }
00044 
00045 #ifdef __NR_faccessat
00046   if ((flag == 0 || ((flag & ~AT_EACCESS) == 0 && ! __libc_enable_secure))
00047 # ifndef __ASSUME_ATFCTS
00048       && __have_atfcts >= 0
00049 # endif
00050       )
00051     {
00052       int result = INLINE_SYSCALL (faccessat, 3, fd, file, mode);
00053 # ifndef __ASSUME_ATFCTS
00054       if (result == -1 && errno == ENOSYS)
00055        __have_atfcts = -1;
00056       else
00057 # endif
00058        return result;
00059     }
00060 #endif
00061 
00062 #ifndef __ASSUME_ATFCTS
00063   if ((!(flag & AT_EACCESS) || ! __libc_enable_secure)
00064 # ifndef __NR_laccess              /* Linux so far has no laccess syscall.  */
00065       && !(flag & AT_SYMLINK_NOFOLLOW)
00066 # endif
00067       )
00068     {
00069       /* If we are not set-uid or set-gid, access does the same.  */
00070       char *buf = NULL;
00071 
00072       if (fd != AT_FDCWD && file[0] != '/')
00073        {
00074          size_t filelen = strlen (file);
00075          static const char procfd[] = "/proc/self/fd/%d/%s";
00076          /* Buffer for the path name we are going to use.  It consists of
00077             - the string /proc/self/fd/
00078             - the file descriptor number
00079             - the file name provided.
00080             The final NUL is included in the sizeof.   A bit of overhead
00081             due to the format elements compensates for possible negative
00082             numbers.  */
00083          size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
00084          buf = alloca (buflen);
00085 
00086          __snprintf (buf, buflen, procfd, fd, file);
00087          file = buf;
00088        }
00089 
00090       int result;
00091       INTERNAL_SYSCALL_DECL (err);
00092 
00093 # ifdef __NR_laccess
00094       if (flag & AT_SYMLINK_NOFOLLOW)
00095        result = INTERNAL_SYSCALL (laccess, err, 2, file, mode);
00096       else
00097 # endif
00098        result = INTERNAL_SYSCALL (access, err, 2, file, mode);
00099 
00100       if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
00101        {
00102          __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
00103          result = -1;
00104        }
00105 
00106       return result;
00107     }
00108 #endif
00109 
00110   struct stat64 stats;
00111   if (fstatat64 (fd, file, &stats, flag & AT_SYMLINK_NOFOLLOW))
00112     return -1;
00113 
00114   mode &= (X_OK | W_OK | R_OK);    /* Clear any bogus bits. */
00115 #if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
00116 # error Oops, portability assumptions incorrect.
00117 #endif
00118 
00119   if (mode == F_OK)
00120     return 0;               /* The file exists. */
00121 
00122   uid_t uid = (flag & AT_EACCESS) ? __geteuid () : __getuid ();
00123 
00124   /* The super-user can read and write any file, and execute any file
00125      that anyone can execute. */
00126   if (uid == 0 && ((mode & X_OK) == 0
00127                  || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
00128     return 0;
00129 
00130   int granted = (uid == stats.st_uid
00131                ? (unsigned int) (stats.st_mode & (mode << 6)) >> 6
00132                : (stats.st_gid == ((flag & AT_EACCESS)
00133                                  ? __getegid () : __getgid ())
00134                   || __group_member (stats.st_gid))
00135                ? (unsigned int) (stats.st_mode & (mode << 3)) >> 3
00136                : (stats.st_mode & mode));
00137 
00138   if (granted == mode)
00139     return 0;
00140 
00141   __set_errno (EACCES);
00142   return -1;
00143 }