摘要:本文描述的是Linux手册页中access函数的使用说明,使用access函数检查实际用户的文件访问权限.原文来自:http://www.kernel.org/doc/man-pages/.
accesss - 检查实际用户的文件访问权限
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, int mode);
#include <fcntl.h> /* Definition of AT_* constants */
#include <unistd.h>
int faccessat(int dirfd, const char *pathname, int mode, int flags);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
faccessat():
Since glibc 2.10:
_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
Before glibc 2.10:
_ATFILE_SOURCE
DESCRIPTION
access()函数检查进程是否可以访问文件路径名.如果文件名是一个符号链接,那它是个引用.
访问权限将以指定的模式mode去检查,模式mode的值可以是F_OK,或者是和R_OK、W_OK及X_OK做按位或运算组合. F_OK是测试文件是否存在,R_OK,W_OK和X_OK分别用来测试文件是否具有可写、可读和可执行权限.当用户对文件执行某个操作时(如打开),内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试.有时,进程也希望按其实际用户ID和实际组ID来测试其访问能力.
如果一个进程已超级用户权限运行,那它可以执行任何一个可运行文件.
faccessat()
除了在描述上有些差异外,faccessat()系统调用和access()完全相同.
如果参数pathname是一个相对路径名,那它是相对于dirfd的路径,而不是相对应于当前工作目录.
如果参数pathname是一个相对路径名,并且参数dirfd指定为AT_FDCWD,那pathname被解析为相对应的当前工作目录.
如果参数pathname是一个绝对路径名,参数dirfd被忽略.
flags是由下例几个值做或运算的组合:
AT_EACCESS 使用有效用户ID和有效用户组ID执行访问权限,默认情况下,faccessat()是以实际用户ID和实际组ID来检查其访问能力.
AT_SYMLINK_NOFOLLOW 如果参数pathname是一个符号链接,不要放弃处理,而是返回一个关于符号链接本身的信息.
RETURN VALUE
成功返回0(所有检测权限都通过检查),失败返回-1(模式mode至少有一访问权限被禁止),出错设置errno指明出错信息.
ERROES
access()将会失败,如果出现下一情况:
EACCES 参数pathname所指定的文件不符合测试权限要求.
ELOOP 参数pathname有太多连接符.
ENAMETOOLONG 参数panthname太长.
ENOTDIR 参数panthname是一个目录.
EROFS 在一个只读的文件上测试写入权限.
access()可能会失败,如果出现下一情况:
EFAULT 参数panthname指针超出可存取内存空间.
EINVAL 指定的参数mode不正确.
EIO IO存取出错.
ENOMEM 主内存存储空间不足.
ETXTBSY 在一个正在运行的文件上测试写入权限.
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
警告:使用access()做用户认证方面的判断要特别小心,例如在access()后再做open()的空文件可能会造成系统安全上的问题.因为用户可能利用检查和打开中间这个短暂的时间间隔来操作它.所以用户应该避免这种情况.(例子已说明,一个更安全的选择是暂时切换进程的有效用户ID到实际用户ID,然后再调用open().)
access()取消对符号链接的检查,如果需要对一个符号链接进行检查,请使用faccessat()函数,将标志位置为AT_SYMLINK_NOFOLLOW.
如果任意一位访问权限被禁止,access()将出错,尽管其他访问权限位通过.
如果进程有适当的访问权限,比如超级用户,在POSIX.1-2001规定中,允许检查一个没有设置可执行位的文件,且成功返回,但在Linux下不行.文件所在的每一个目录都可以访问,才可以使用access()检查文件的访问权限.如果文件所在目录不能访问,则调用access()函数将会失败,尽管待检查的文件有访问的权限.
access()只作权限的检查, 并不理会文件状态或文件内容,因此,如果一目录表示为"可写入",表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理.例如:你会发现DOS
的文件都具有"可执行"权限,但用execve()执行时则会失败.
这些调用在NFSv2文件系统用户ID映射中可能无法正常工作,因为检查UID映射文件时,UID映射文件是在服务器端的,而在客户端是不可见的,类似的问题也可能会出现在挂载的文件系统中.
C library/kernel ABI differences
原始的faccessat()系统调用只需要前三个参数,标志AT_EACCESS 和AT_SYMLINK_NOFOLLOW是在glibc函数库中使用,如果指定其中一个标志,那函数库调用fstastat(2)函数来检查文件的访问权限.
Glibc notes
在老版本的内核系统中,如果没有指定AT_EACCESS和AT_SYMLINK_NOFOLLOW标志的话,函数faccessat()是不可用的,glibc函数库将会调用access().当参数pathname是相对路径时,glibc函数库会在/proc/self/fd中构造一个符号链接作为对应的dirfd参数.
BUGS
在内核2.4(或更早)处理X_OK检查不是很成熟,对一个没有目录的文件,如果所有用户的可执行权限都被禁止,当access()指定mode为X_OK来检查文件权限时,将会返回-1,如果指定mode为R_OK或者W_OK,则access()返回0.在早期的内核2.6中也有类似的问题.
在内核2.6.20版本前,如果是底层的挂载文件系统,这些函数调用都忽略了标志MS_NOEXEC,但从内核2.6.20标志MS_NOEXEC才得到重视.
access函数
NAME
accesss - 检查实际用户的文件访问权限
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, int mode);
#include <fcntl.h> /* Definition of AT_* constants */
#include <unistd.h>
int faccessat(int dirfd, const char *pathname, int mode, int flags);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
faccessat():
Since glibc 2.10:
_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
Before glibc 2.10:
_ATFILE_SOURCE
DESCRIPTION
access()函数检查进程是否可以访问文件路径名.如果文件名是一个符号链接,那它是个引用.
访问权限将以指定的模式mode去检查,模式mode的值可以是F_OK,或者是和R_OK、W_OK及X_OK做按位或运算组合. F_OK是测试文件是否存在,R_OK,W_OK和X_OK分别用来测试文件是否具有可写、可读和可执行权限.当用户对文件执行某个操作时(如打开),内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试.有时,进程也希望按其实际用户ID和实际组ID来测试其访问能力.
如果一个进程已超级用户权限运行,那它可以执行任何一个可运行文件.
faccessat()
除了在描述上有些差异外,faccessat()系统调用和access()完全相同.
如果参数pathname是一个相对路径名,那它是相对于dirfd的路径,而不是相对应于当前工作目录.
如果参数pathname是一个相对路径名,并且参数dirfd指定为AT_FDCWD,那pathname被解析为相对应的当前工作目录.
如果参数pathname是一个绝对路径名,参数dirfd被忽略.
flags是由下例几个值做或运算的组合:
AT_EACCESS 使用有效用户ID和有效用户组ID执行访问权限,默认情况下,faccessat()是以实际用户ID和实际组ID来检查其访问能力.
AT_SYMLINK_NOFOLLOW 如果参数pathname是一个符号链接,不要放弃处理,而是返回一个关于符号链接本身的信息.
RETURN VALUE
成功返回0(所有检测权限都通过检查),失败返回-1(模式mode至少有一访问权限被禁止),出错设置errno指明出错信息.
ERROES
access()将会失败,如果出现下一情况:
EACCES 参数pathname所指定的文件不符合测试权限要求.
ELOOP 参数pathname有太多连接符.
ENAMETOOLONG 参数panthname太长.
ENOTDIR 参数panthname是一个目录.
EROFS 在一个只读的文件上测试写入权限.
access()可能会失败,如果出现下一情况:
EFAULT 参数panthname指针超出可存取内存空间.
EINVAL 指定的参数mode不正确.
EIO IO存取出错.
ENOMEM 主内存存储空间不足.
ETXTBSY 在一个正在运行的文件上测试写入权限.
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
警告:使用access()做用户认证方面的判断要特别小心,例如在access()后再做open()的空文件可能会造成系统安全上的问题.因为用户可能利用检查和打开中间这个短暂的时间间隔来操作它.所以用户应该避免这种情况.(例子已说明,一个更安全的选择是暂时切换进程的有效用户ID到实际用户ID,然后再调用open().)
access()取消对符号链接的检查,如果需要对一个符号链接进行检查,请使用faccessat()函数,将标志位置为AT_SYMLINK_NOFOLLOW.
如果任意一位访问权限被禁止,access()将出错,尽管其他访问权限位通过.
如果进程有适当的访问权限,比如超级用户,在POSIX.1-2001规定中,允许检查一个没有设置可执行位的文件,且成功返回,但在Linux下不行.文件所在的每一个目录都可以访问,才可以使用access()检查文件的访问权限.如果文件所在目录不能访问,则调用access()函数将会失败,尽管待检查的文件有访问的权限.
access()只作权限的检查, 并不理会文件状态或文件内容,因此,如果一目录表示为"可写入",表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理.例如:你会发现DOS
的文件都具有"可执行"权限,但用execve()执行时则会失败.
这些调用在NFSv2文件系统用户ID映射中可能无法正常工作,因为检查UID映射文件时,UID映射文件是在服务器端的,而在客户端是不可见的,类似的问题也可能会出现在挂载的文件系统中.
C library/kernel ABI differences
原始的faccessat()系统调用只需要前三个参数,标志AT_EACCESS 和AT_SYMLINK_NOFOLLOW是在glibc函数库中使用,如果指定其中一个标志,那函数库调用fstastat(2)函数来检查文件的访问权限.
Glibc notes
在老版本的内核系统中,如果没有指定AT_EACCESS和AT_SYMLINK_NOFOLLOW标志的话,函数faccessat()是不可用的,glibc函数库将会调用access().当参数pathname是相对路径时,glibc函数库会在/proc/self/fd中构造一个符号链接作为对应的dirfd参数.
BUGS
在内核2.4(或更早)处理X_OK检查不是很成熟,对一个没有目录的文件,如果所有用户的可执行权限都被禁止,当access()指定mode为X_OK来检查文件权限时,将会返回-1,如果指定mode为R_OK或者W_OK,则access()返回0.在早期的内核2.6中也有类似的问题.
在内核2.6.20版本前,如果是底层的挂载文件系统,这些函数调用都忽略了标志MS_NOEXEC,但从内核2.6.20标志MS_NOEXEC才得到重视.
END
笔者:个人能力有限,只是学习...读者若发现文中错误,敬请提出.
--
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------