#include <unistd.h> int access(const char *pathname, int mode); #include <fcntl.h> /* AT_* 定数の定義 */ #include <unistd.h> int faccessat(int dirfd, const char *pathname, int mode, int flags);
glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
faccessat():
mode はチェックを行うアクセス権を指定するもので、その値は F_OK、 もしくは R_OK, W_OK, X_OK の 1個以上のビット単位の論理和から構成されるマスクである。 F_OK はファイルが存在するかどうかのみを検査する。 R_OK, W_OK, X_OK は、ファイルが存在して、それぞれ読み込み、書き込み、実行の許可があるか を検査する。
チェックは、実際に操作が行われる際に使用される実効 (effective) ID でなく、 呼び出し元プロセスの 実 (real) UID と 実 (real) GID を使って行われる。 同様に、root ユーザーに対しては、実効ケーパビリティではなく、 許可されたケーパビリティのセットをチェックする。 root 以外のユーザでは、ケーパビリティの空のセットをチェックする。
これにより、set-user-ID プログラムと、 ケーパビリティが与えられたプログラムで、 プログラムを起動するユーザーの権限を簡単に決定することができる。 言い換えると、 access() は「私がこのファイルに対して読み出し/書き込み/実行ができるか?」という 質問には答えない。 access() は少し異なった質問 「(私が setuid バイナリであると仮定して) 私をよびだしたユーザーが このファイルに対して読み出し/書き込み/実行ができるか?」に答える。 これにより、set-user-ID プログラムに対して、 悪意のあるユーザーが、読み込みの出来ないファイルを 読み込むことを防止できるようになる。
呼び出し元プロセスが特権プロセス (つまり、プロセスの実 UID が 0) の場合、 通常のファイルに対する X_OK のチェックは、そのファイルの所有者、グループ、他人のいずれかの 実行許可が有効になっていれば成功する。
pathname で指定されたパス名が相対パスの場合、このパス名はファイルディスクリプター dirfd が参照するディレクトリに対する相対パスと解釈される (access() に相対パス名を渡した場合のように、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。
pathname で指定されたパス名が相対パスで、 dirfd が特別な値 AT_FDCWD の場合、 (access() と同様に) pathname は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈される。
pathname で指定されたパス名が絶対パスの場合、 dirfd は無視される。
flags は以下に示す値の 0 個以上の OR (論理和) をとって作成される。
faccessat() の必要性についての説明については openat(2) を参照。
access() と faccessat() は以下の理由により失敗することがある。
faccessat() では以下のエラーも発生する。
警告: あるユーザーが、例えば open(2) によるアクセスが可能かどうかを、 (実際に行う前に) これらのシステムコールを使ってチェックするのは、セキュリティホールの原因になる。なぜならチェックをしてから 実際にファイルのオープン操作をする間の短い間隔を悪用できるからである。 この理由があるので、このシステムコールを使うのは避けるべきである。 (ここで説明した例の場合には、より安全な方法としては、 そのプロセスの実効ユーザー ID を実ユーザー ID に一時的に切り替えてから open(2) を呼び出す方法がある。)
access() は常にシンボリックリンクの展開を行う。 シンボリックリンクのアクセス許可を確認する必要がある場合は、 AT_SYMLINK_NOFOLLOW フラグ付きで faccessat() を使うこと。
mode で指定されたアクセス種別のいずれか一つでも拒否されると、 たとえ mode で指定された他のアクセス種別が許可されたとしても、 これらのシステムコールはエラーを返す。
POSIX.1-2001 では、 呼び出し元プロセスが適切な特権を持っている場合 (つまり、スーパーユーザーの場合)、 たとえファイルの実行許可ビットが全くセットされていなくても X_OK のチェックとして成功を返す実装が認められている。 Linux はこのようにはなっていない。
pathname のプレフィックスを構成するディレクトリの全てに対して 検索アクセス (すなわち、実行アクセス) が許可された場合にのみ、 ファイルはアクセス可能となる。 いずれかのディレクトリがアクセス不可の場合、 ファイル自身のアクセス許可に関わらず、 access() は失敗する。
アクセスビットのみがチェックされ、ファイルの種類や内容はチェックされない。 従って、ディレクトリが書き込み可能となった場合は、ディレクトリに ファイルを作成することが可能なことを意味するのであり、ディレクトリに ファイルとして書き込むことができるわけではない。 同様に DOS のファイルは「実行可能」と判断されるが、 execve(2) コールは失敗するだろう。
これらのシステムコールは、 UID マッピングを使用した NFSv2 ファイルシステムでは正常に機能しないかもしれない。なぜならば UID のマッピングはサーバーで 行なわれ、権利のチェックをするクライアントには見えないからである。 (NFS バージョン 3 以降ではサーバー側でチェックが実行される。) 同様の問題は FUSE マウントでも起こり得る。
2.6.20 より前のカーネルでは、 これらのシステムコールはファイルが存在するファイルシステムを mount(2) する際に指定された MS_NOEXEC フラグの効果を無視していた。 カーネル 2.6.20 以降では、 MS_NOEXEC フラグは考慮されるようになっている。