ファイルの属性情報を探る 権限編

前回からの続き。

伝統的なUNIXのアクセス権限

  • 伝統的なUNIXでは、すべてのファイルやディレクトリにアクセス権限が設定されている。
  • ここで言うアクセス権限とは、読み・書き・実行を許可するか、しないかの選択である。
    • 但し、ディレクトリの場合はちょっと意味合いが違ってくる。
      • 読み = ls可能かどうか(許可されていなくても、その中のファイルやディレクトリをパス指定したcatやlsならできる)
      • 書き = 新規追加・削除可能かどうか(許可されていなくても、修正はできる。子以下のディレクトリに対する新規追加・削除はできる)
      • 実行 = そのディレクトリ以下にアクセス可能かどうか(許可されていないと、すべての操作が禁止される)
  • 以上のアクセス権限を、所有者・グループ・その他のユーザーに区分して、それぞれ設定するのである。
  • アクセス権限は、lsコマンドで確認できる。
 $ cd ~/Desktop
 $ ls -l
 drwxr-xr-x  6 zari  staff    204  4  9 10:53 folder
 -rw-r--r--  1 zari  staff     10  4  4 17:05 sample.txt
  • 太字部分がアクセス権限を表現している。
  • 先頭の1文字、dまたは-がファイルの種類を意味している。(d=ディレクトリ、-=通常のファイル)
  • 次の9文字、rwxはたは-がアクセス権限を意味している。(r=読み許可、w=書き許可、x=実行許可、-=許可しない)
  • つまり、sample.txtのアクセス権限は、以下のように解釈できるのだ。
    • 所有者は、読み書きOK。
    • グループは、読みOK。
    • その他のユーザーも、読みOK。
種別 所有者 グループ その他
- rw- r-- r--
通常ファイル 読み・書き 読み 読み

OSXUNIXなので、以上のアクセス権限が属性情報としてすべてのファイルに設定されているのである。

  • ところで、上記の仕組みはアクセスを制限する最も基本的な仕組みの1つでしかない。
  • UNIXOSXには、より細かくアクセスをコントロールする仕組みが備わっているのだ。

実行ファイルのsビット(setuid・setgid)

  • 以下のlsコマンドを実行してみる。
 $ sudo find /{,usr/,usr/local/}{,s}bin -type f -perm -4000 -print0 | xargs -0 ls -l
 -rwsr-xr-x  1 root  wheel   46800  9 19  2012 /bin/ps
 -r-sr-xr-x  1 root  wheel   29424  9 19  2012 /bin/rcp
 -r-sr-xr-x  4 root  wheel   75664  3 19 13:23 /usr/bin/at
 -r-sr-xr-x  4 root  wheel   75664  3 19 13:23 /usr/bin/atq
 -r-sr-xr-x  4 root  wheel   75664  3 19 13:23 /usr/bin/atrm
 -r-sr-xr-x  4 root  wheel   75664  3 19 13:23 /usr/bin/batch
 -rwsr-xr-x  1 root  wheel   39296  9 19  2012 /usr/bin/crontab
 -rws--x--x  1 root  wheel   23008  9 24  2012 /usr/bin/ipcs
 -r-sr-xr-x  1 root  wheel   68480  3 19 13:23 /usr/bin/login
 -r-sr-xr-x  1 root  wheel   44560  3 19 13:23 /usr/bin/newgrp
 -r-sr-xr-x  1 root  wheel   44560  9 19  2012 /usr/bin/quota
 -r-sr-xr-x  1 root  wheel   24832  9 19  2012 /usr/bin/rlogin
 -r-sr-xr-x  1 root  wheel   19856  9 19  2012 /usr/bin/rsh
 -rwsr-xr-x  1 root  wheel   21472  9 19  2012 /usr/bin/su
 -r-s--x--x  1 root  wheel  164496  9 24  2012 /usr/bin/sudo
 -r-sr-xr-x  1 root  wheel  178000  9 19  2012 /usr/bin/top
 -rwsr-xr-x  1 root  wheel   25192  1 16 17:12 /usr/local/bin/timer-add-schedule
 -rwsr-xr-x  1 root  wheel   25024  1 16 17:33 /usr/local/bin/timer-rm-schedule
 -r-sr-xr-x  1 root  wheel   20720  3 19 13:23 /usr/sbin/scselect
 -r-sr-xr-x  1 root  wheel   33680  9 19  2012 /usr/sbin/traceroute
 -r-sr-xr-x  1 root  wheel   29344  9 19  2012 /usr/sbin/traceroute6

 $ sudo find /{,usr/,usr/local/}{,s}bin -type f -perm -2000 -print0 | xargs -0 ls -l
 -rwxr-sr-x  1 root  mail        24512  9 19  2012 /usr/bin/lockfile
 -rwxr-sr-x  1 root  mail        92864  9 19  2012 /usr/bin/procmail
 -r-xr-sr-x  1 root  tty         20800  9 19  2012 /usr/bin/wall
 -r-xr-sr-x  1 root  tty         19920  9 19  2012 /usr/bin/write
 -rwxr-sr-x  1 root  _postdrop  203088  3 19 13:23 /usr/sbin/postdrop
 -rwxr-sr-x  1 root  _postdrop  234976  3 19 13:23 /usr/sbin/postqueue
  • すると、アクセス権限に見慣れないsが表示されている!
  • 本来なら実行を許可するxが表示されるべき位置である。

このsは何なのか?

  • 実行権限xの位置に表示されるsは、sビットと呼ばれる。
  • 通常は(xが表示されていれば)、そのファイルを起動したユーザーの権限で実行される仕組みであるが...
    • 所有者のsが表示されている(setuid)と、誰がそのファイルを実行しても所有者の権限で実行されることになる。
    • グループのsが表示されている(setgid)と、誰がそのファイルを実行してもグループの権限で実行されることになる。
      • 例:zariユーザー(staffグループ)がprocmailコマンドを実行してファイルが出力されたとしたら、ファイルの所有者=zari、グループ=mail になるのだ。
  • そんな必要性があるのかと言えば、意外と身近な状況で起こりうる。例えば、crontabコマンド。
  • 誰もが自分のcron設定を変更できるべきなのだが、cronの設定を保存する/var/at/tabs/はroot権限で厳重に管理されている。
  • よって本来ならcrontabを実行する時はroot権限の場所にアクセスする必要があるのだが、一般ユーザーのままでもちゃんと設定を変更できている。
  • なぜ一般ユーザーのままroot権限のファイルを変更できているかと言えば、所有者のsビット(setuid)がセットされているからである。
 -rwsr-xr-x  1 root  wheel   39296  9 19  2012 /usr/bin/crontab
  • 所有者rootの権限がrwsとなっている!
  • つまり、誰がcrontabを実行しても、root権限で実行されるのだ。
設定方法
 -rwsr-xr-x  1 root  wheel   39296  9 19  2012 /usr/bin/crontab
 -rwxr-sr-x  1 root  mail    24512  9 19  2012 /usr/bin/lockfile
  • sビットが設定されている8進数のアクセス権限は、以下のように表示された。
$ stat -f '%N %A' /usr/bin/crontab
/usr/bin/crontab 4755

$ stat -f '%N %A' /usr/bin/lockfile
/usr/bin/lockfile 2755
  • 4桁目のアクセス権限が4=setuid、2=setgid となるのだ。
  • つまり、chmodコマンドで、以下のように設定できるのだ。
$ chmod 4755 /usr/bin/crontab
$ chmod 2755 /usr/bin/lockfile
  • あるいは+sを利用しても設定可能である。
$ chmod u+s /usr/bin/crontab
$ chmod g+s /usr/bin/lockfile
危険性
  • root権限のsビット(setuid・setgid)をセットすると、誰もがroot権限で実行できるため、
  • 悪意のあるユーザーが利用したとしても、OS環境に不要な攻撃をされない工夫が必要である。
    • 標準インストールされるコマンドには、そう言った工夫がされている筈である。
  • ちなみに、そう言った危険性回避のためか...
  • 基本的には、C言語等からビルドしたバイナリファイルでしか、sビットは有効にならない。
  • 手軽に利用できるスクリプトコードのファイルにsビットを設定しても、無視されるらしい。
    • 但し、Perlスクリプトだけは、sビットを有効にする仕組みがあるようだ。
参考ページ

以下のページがたいへん参考になりました。感謝です!

実は以前、timerコマンドを作った時にも利用している。

ディレクトリのsビット(setuid・setgid)

但し、ディレクトリのsビットの扱いは、OS環境によってずいぶん変わってくるようだ。

  • 少なくともOSX 10.8環境で自分が調べた限りでは、OSX環境ではディレクトリのsビットは設定できるが、その効力は発揮されていないように見える。
  • そもそもOSX 10.8環境では、sビットが設定されていなくても、ファイルやサブディレクトリを作成すると、親ディレクトリと同じグループが設定される。
  • これはデフォルトでsetgidが有効になっている状況と同じだ。
  • 所有者については、常にコマンドを実行したユーザーとなった。

スティッキービット

  • 例えば、/private/tmpや/Users/Sharedのアクセス権限の最後のフラグはtとなっている。
 $ ls -ld /private/tmp
 drwxrwxrwt  14 root  wheel  476  4  9 14:41 /private/tmp/

$ ls -ld /Users/Shared
drwxrwxrwt  11 root  wheel  374  4 10 15:11 /Users/Shared/
  • この、その他のユーザーの実行権限xの部分に表示されるtが、スティッキービットである。
  • 上記のようにスティッキービットが有効になっていると...
    • 誰もが/private/tmp/以下にファイルやディレクトリを作成できるが、
    • それらを削除できるのは、所有者だけとなる。
  • 仮にもしスティッキービットが無効であれば...
    • 誰もがファイルやディレクトリを作成できて、
    • 誰もがそれらを削除できる扱いになる。
設定方法
  • sビットが設定されている8進数のアクセス権限は、以下のように表示された。
$ stat -f '%N %A' /private/tmp
/private/tmp 1777

$ stat -f '%N %A' /Users/Shared
/Users/Shared 1777
  • 4桁目のアクセス権限が1=スティッキービットが有効となるのだ。
  • よって、chmod 1777 あるいは chmod a+t コマンドで設定する。(o+t、u+t、g+t では設定できなかった)
$ mkdir sticky_folder
$ ls -ld sticky_folder
drwxr-xr-x  2 zari  staff  68  4 10 08:53 sticky_folder

$ chmod a+rwxt sticky_folder
$ ls -ld sticky_folder
drwxrwxrwt  2 zari  staff  68  4 10 08:53 sticky_folder
  • その他のユーザーの実行権限を無効(アクセス不可)にした場合は、大文字のTが表示された。
$ chmod o-x sticky_folder
$ ls -ld sticky_folder
drwxrwxrwT  2 zari  staff  68  4 10 08:53 sticky_folder/
  • この場合、その他のユーザーは、ディレクトリ以下にアクセスできない。
  • グループに属するユーザーならファイルやディレクトリを作成できるが、
  • それらを削除できるのは、その所有者だけとなる。

ファイルフラグ

  • ファイルフラグの状態はls -lOコマンドで確認できるのだ。
$ command ls -lO ~
total 0
drwx------+  16 zari  staff  -        544  4 10 14:15 Desktop
drwx------+ 399 zari  staff  -      13566  3 14 14:03 Documents
drwx------+ 234 zari  staff  -       7956  4  8 14:26 Downloads
drwx------@  67 zari  staff  hidden  2278  4  3 09:05 Library
drwx------+   7 zari  staff  -        238  3 28 09:51 Movies
drwx------+   9 zari  staff  -        306  2 28 09:28 Music
drwx------+  11 zari  staff  -        374 10 23 16:53 Pictures
drwxr-xr-x+  11 zari  staff  -        374  9 16  2012 Public
drwxr-xr-x    4 zari  staff  -        136  2 25 10:59 Sites
  • ファイルフラグの設定は、chflagsコマンドで行う。
  • マニュアル chflags(1) によると、以下のフラグを可能だという。
必要なユーザー権限 ファイルフラグ 意味
管理者権限 arch archived
所有者 opaque
所有者 nodump
管理者権限 sappnd sappend フォルダにおいて追加のみ可能。変更はできない。
管理者権限 schg schange simmutable 変更不可フラグ。設定するとFinderのロック属性がオンになる。
所有者 uappnd uappend フォルダにおいて追加のみ可能。変更はできない。
所有者 uchg uchange uimmutable 変更不可フラグ。設定するとFinderのロック属性がオンになる。
所有者 hidden GUI環境からアイテムを隠す。
/*
 * Definitions of flags stored in file flags word.
 *
 * Super-user and owner changeable flags.
 */
#define	UF_SETTABLE	0x0000ffff	/* mask of owner changeable flags */
#define	UF_NODUMP	0x00000001	/* do not dump file */
#define	UF_IMMUTABLE	0x00000002	/* file may not be changed */
#define	UF_APPEND	0x00000004	/* writes to file may only append */
#define UF_OPAQUE	0x00000008	/* directory is opaque wrt. union */
/*
 * The following bit is reserved for FreeBSD.  It is not implemented
 * in Mac OS X.
 */
/* #define UF_NOUNLINK	0x00000010 */	/* file may not be removed or renamed */
#define UF_COMPRESSED	0x00000020	/* file is hfs-compressed */
#define UF_TRACKED	0x00000040	/* file renames and deletes are tracked */
/* Bits 0x0080 through 0x4000 are currently undefined. */
#define UF_HIDDEN	0x00008000	/* hint that this item should not be */
					/* displayed in a GUI */
/*
 * Super-user changeable flags.
 */
#define	SF_SETTABLE	0xffff0000	/* mask of superuser changeable flags */
#define	SF_ARCHIVED	0x00010000	/* file is archived */
#define	SF_IMMUTABLE	0x00020000	/* file may not be changed */
#define	SF_APPEND	0x00040000	/* writes to file may only append */

/*
 * The following two bits are reserved for FreeBSD.  They are not
 * implemented in Mac OS X.
 */
/* #define SF_NOUNLINK	0x00100000 */	/* file may not be removed or renamed */
/* #define SF_SNAPSHOT	0x00200000 */	/* snapshot inode */
/* NOTE: There is no SF_HIDDEN bit. */
  • すると興味深いことに、chflagsのマニュアルで紹介されている8つのフラグ以外に、さらに2つのフラグが用意されていることに気付いた。
#define UF_COMPRESSED	0x00000020	/* file is hfs-compressed */......ファイルがHFS圧縮されている
#define UF_TRACKED	0x00000040	/* file renames and deletes are tracked */......ファイルの名称変更と削除を追跡する
UF_COMPRESSED
  • UF_COMPRESSEDは、HFS+に備わる圧縮機能に関するフラグらしい。
    • 例えば、/usr/binやプレビュー.appやテキストエディット.appのアプリケーションバンドルの中を覗いてみると、compressedが確認できた!
 $ ls -lO /usr/bin
 total 163656
 ...中略...
 -rwxr-xr-x   6 root   wheel  compressed      925  9 19  2012 2to3*
 -rwxr-xr-x   6 root   wheel  compressed      925  9 19  2012 2to3-*
 lrwxr-xr-x   1 root   wheel  -                74  9 19  2012 2to3-2.7@ -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/2to3-2.7
 lrwxr-xr-x   1 root   wheel  -                73  9 19  2012 2to32.6@ -> ../../System/Library/Frameworks/Python.framework/Versions/2.6/bin/2to32.6
 -rwxr-xr-x   1 root   wheel  compressed    18832  3 22 14:09 BuildStrings*
 -rwxr-xr-x   1 root   wheel  compressed    25264  3 22 14:09 CpMac*
 -rwxr-xr-x   1 root   wheel  compressed   100960  3 22 14:09 DeRez*
 -rwxr-xr-x   1 root   wheel  compressed    14480  3 22 14:09 GetFileInfo*
 -rwxr-xr-x   1 root   wheel  compressed    62480  3 22 14:09 MergePef*
 -rwxr-xr-x   1 root   wheel  compressed    18976  3 22 14:09 MvMac*
...中略...

 $ ls -lO /Applications/TextEdit.app/Contents 
 total 0
 -rw-r--r--   1 root  wheel  compressed 7868  9 19  2012 Info.plist
 drwxr-xr-x   3 root  wheel  -           102  6 23  2012 MacOS/
 -rw-r--r--   1 root  wheel  compressed    8  9 19  2012 PkgInfo
 drwxr-xr-x  42 root  wheel  -          1428  9 19  2012 Resources/
 drwxr-xr-x   3 root  wheel  -           102  6 23  2012 _CodeSignature/
 -rw-r--r--   1 root  wheel  compressed  456  9 19  2012 version.plist
UF_TRACKED
  • UF_TRACKEDは、バージョン機能をサポートするアプリケーションが保存した書類に設定されていた。
    • 2度目の保存をして、バージョン管理され始めると UF_TRACKED が設定された。
    • 但し、UF_TRACKEDは、ls -lOコマンドでは確認できない...。
 $ ls -lO /Users/zari/Desktop/UF_TRACKEDのテスト.txt
 -rw-r--r--@ 1 zari  staff  - 24  4 11 06:06 /Users/zari/Desktop/UF_TRACKEDのテスト.txt
    • statコマンドで表示される st_flags=64 を見て確認できた。
    • (UF_TRACKED = 0x00000040 = 64)
 $ stat -s /Users/zari/Desktop/UF_TRACKEDのテスト.txt
 st_dev=16777218 st_ino=8135828 st_mode=0100644 st_nlink=1 st_uid=501 st_gid=20 st_rdev=0 st_size=24 st_atime=1365627974 st_mtime=1365627972 st_ctime=1365627972  st_birthtime=1365627885 st_blksize=4096 st_blocks=8 st_flags=64
設定方法
  • ファイルをロックしてみる。
 $ touch flag_test
 $ ls -lO flag_test
 -rw-r--r--  1 zari  staff  -    0  4 11 06:39 flag_test

 $ chflags uchg flag_test
 $ ls -lO flag_test
 -rw-r--r--  1 zari  staff  uchg 0  4 11 06:39 flag_test
  • ロックしたファイルを削除すると...
 $ rm -f flag_test
 rm: flag_test: Operation not permitted
  • ファイルフラグは複数設定できる。
 $ chflags hidden flag_test
 $ ls -lO flag_test
 -rw-r--r--@ 1 zari  staff  uchg,hidden 0  4 11 06:39 flag_test
  • すべてのファイルフラグを削除する。
    • 8進数コードで指定可能なのだ。
    • この場合ゼロ0を指定している。
 $ chflags 0 flag_test
 $ ls -lO flag_test
 -rw-r--r--  1 zari  staff  - 0  4 11 06:39 flag_test


以上、ファイルフラグはすべての設定が権限とは言えないが、全10種類のフラグを設定できる仕様なのであった。

ACL

  • 突然ではあるが、デスクトップを削除するという実験をしてみる。
  • 本当に削除されてしまうので、バックアップしてから作業に入るのだ。
  • さっそく、rmコマンドで削除してみると...
$ rm -fr ~/Desktop
rm: Desktop: Permission denied
  • デスクトップ上のアイテムはすべて削除されてしまったが、
  • デスクトップ(ディレクトリ)だけは、しっかり残るのだ。
  • デスクトップでは、伝統的なアクセス権限 所有者=rwxになっているし、ファイルフラグの設定もない。
$ ls -lOd ~/Desktop
drwx------+ 18 zari  staff  - 612  4 11 06:39 Desktop
  • 普通に考えれば削除できる筈なのだが、現実はPermission denied(アクセス権がない)と表示される。

なぜ削除できないのか?

  • よ〜く観察すると、伝統的なアクセス権限を示す項目の末尾に+が付加されている。これが重要なヒントになる。
  • この+は、ACLAccess Control Lists=アクセス制御リスト)という情報が付加されていることを示している。
  • このACLの中身は、lsコマンドのオプションにeを指定することで確認できる。
$ ls -lOed ~/Desktop
drwx------+ 18 zari  zari  - 612  4 11 15:50 Desktop
 0: group:everyone deny delete......ACLの中身
  • 通常出力に続くこの情報こそが、ACLの中身だ。
    • everyone deny delete = 全ユーザーに対して削除を禁止
  • 上記ACLによって、削除が阻止されているのだ。
  • なるほど!と思って改めてホーム直下のACLを確認してみると、標準インストールされるフォルダにはすべて everyone deny delete が設定されている。
$ ls -lOe ~
total 0
drwx------+  18 zari  staff  -        612  4 11 15:50 Desktop
 0: group:everyone deny delete
drwx------+ 399 zari  staff  -      13566  3 14 14:03 Documents
 0: group:everyone deny delete
drwx------+ 235 zari  staff  -       7990  4 11 14:30 Downloads
 0: group:everyone deny delete
drwx------@  67 zari  staff  hidden  2278  4  3 09:05 Library
 0: group:everyone deny delete
drwx------+   7 zari  staff  -        238  3 28 09:51 Movies
 0: group:everyone deny delete
drwx------+   9 zari  staff  -        306  2 28 09:28 Music
 0: group:everyone deny delete
drwx------+  11 zari  staff  -        374 10 23 16:53 Pictures
 0: group:everyone deny delete
drwxr-xr-x+  11 zari  staff  -        374  9 16  2012 Public
 0: group:everyone deny delete
設定方法
  • ACLを設定する。
 $ touch acl_test
 $ ls -lOe acl_test
 -rw-r--r--  1 zari  staff  - 0  4 11 16:45 acl_test

 $ chmod +a "everyone deny delete" acl_test
 $ ls -lOe acl_test
 -rw-r--r--+ 1 zari  staff  - 0  4 11 16:45 acl_test
  0: group:everyone deny delete
  • 削除してみると...
 $ rm -f acl_test
 rm: acl_test: Permission denied
  • ACLは複数設定できる。
 $ chmod +a "guest deny read" acl_test
 $ chmod +a "admin allow write" acl_test
 $ ls -lOe acl_test
 -rw-r--r--+ 1 zari  staff  - 0  4 11 16:45 acl_test
  0: user:Guest deny read
  1: group:everyone deny delete
  2: group:admin allow write
  • ACLを1つ削除する。
 $ chmod -a# 1 acl_test
 $ ls -lOe acl_test
 -rw-r--r--+ 1 zari  staff  - 0  4 11 16:45 acl_test
  0: user:Guest deny read
  1: group:admin allow write
  • ACLをすべて削除する。
 $ chmod -N acl_test
 $ ls -lOe acl_test
 -rw-r--r--  1 zari  staff  - 0  4 11 16:45 acl_test
その他
  • 基本的にOSをインストールした時に設定されたACLは、無闇に変更しない方が良さそう。
  • 基本的に自分の使い方では、ACLを積極的に活用する状況は思い浮かばない。
  • ほとんどの状況で、伝統的なアクセス権限とファイルフラグで十分だと思う。
  • ACLの仕組みを知識として理解しておき、未知の不具合に遭遇した時、ACLの設定を疑ってみる価値はありそう。


複数ユーザー・複数グループの追加
  • そう言えば、いつの頃からか所有者以外に、自由に好みのユーザー権限を追加できるようになっていた。
  • 伝統的なUNIXの権限では、所有者以外のユーザーは追加できないと思っていたので、不思議に思っていた。
  • 例えばFinderの情報を見る(command-I)で通常のacl_testファイルを開くと...

  • このacl_testファイルには、複数のユーザーやグループを自由に追加できるのだ!
    • AliceとBobを追加してみた。

どんな仕組みになっているんだ?

  • と思って、ls -lOeコマンドで確認してみる。
    • これはacl_testファイル作成直後の状態。
 $ ls -lOe /Users/bebe/Desktop/acl_test
 -rw-r--r--  1 bebe  staff  - 0  4 11 16:45 acl_test
    • AliceとBobを追加後、確認してみると...
 $ ls -lOe ~/Desktop/acl_test
 -rw-r--r--+ 1 bebe  staff  - 0  4 11 16:45 acl_test
  0: user:bob allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity
  1: user:alice allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity

なんと!ACLが追加されていたのであった。

  • 複数ユーザー、複数グループの権限を追加できる仕組みは、ACLによって実現されていた機能だったのである!
  • 上記で「ACLを積極的に活用する状況は思い浮かばない」と書いたが、実は知らず知らずのうちに活用していた。

まとめ

  • 以上、OSX環境のファイルやディレクトリは、実に様々な権限で、複雑に管理されていたのであった。
    • 伝統的なアクセス権限
      • 所有者・グループ・その他のユーザーごとの読み・書き・実行
      • sビット
      • スティッキービット
    • ファイルフラグ
    • ACL
  • 削除できないファイルなどがあったりしたら、これらの権限を1つずつチェックしていけば、いつかきっと削除できるはず。