UNIX / Linux では、複数のユーザーで同一のマシンを使用することを前提に 設計されています(マルチユーザの概念). そこで, UNIX / Linux においてファイルへのアクセス権制御, 即ち他人に見せてもよいファイル・見せたくないファイルの制御が 重要となります.
UNIX / Linux では, 自分のホームディレクトリへ他人が勝手にファイルを 書いたり, 自分のメールを他人に読まれたりされないようにすることが 可能です. また特定のグループに所属するメンバーのみ読み書きが可能なファイルを 作ることもできます. ここでは, このようなファイルのアクセス権の制御について見ていきます.
自分のホームディレクトリで ls コマンドを幾つかのオプションを指定して 実行すると, 例えば以下のような出力が得られます.
$ ls -Flag total 36 drwxr-xr-x 3 foo 4096 Apr 27 18:45 ./ drwxr-xr-x 3 root 4096 Apr 6 18:47 ../ -rw------- 1 foo 371 Apr 27 11:41 .bash_history -rw-r--r-- 1 foo 220 Apr 6 18:47 .bash_logout -rw-r--r-- 1 foo 3198 Apr 7 18:15 .bashrc -rw-r--r-- 1 foo 3184 Apr 6 18:47 .bashrc~ drwxr-xr-x 3 foo 4096 Apr 7 18:16 .emacs.d/ -rw-r--r-- 1 foo 675 Apr 6 18:47 .profile -rw-r--r-- 1 foo 9 Apr 27 18:45 hoge.txt drwxr-xr-x 2 foo 4096 Apr 27 18:49 work/ |
この出力の下から 2 行目を例に取って, この読み方を解説します. 左から順に,
-rw-r--r-- | ファイルモード |
1 | ファイルへの"リンク数" |
foo | ファイルの所有者 |
9 | ファイルの大きさ(バイト単位) |
Apr 27 18:45 | ファイルの最終更新時刻 |
hoge.txt | ファイルの名前 |
$ man ls |
一番左側の表示の文字列はファイルの「モード」, すなわち ファイルの型 (type) と利用権限 (permission) を表しています. 例えば, hoge.txt のすぐ下の work/ を見ると,
d rwx r-x r-x
左端の1文字はファイルの型を示します. 取りうる文字と型は後述します.
続く文字列で利用権限を示しています. 利用権限の許可対象には,
があり, それぞれに対する許可情報を,
と読んでいます.
また利用権限には,
d rwx r-x r-x ^ ^^^ ^^^ ^^^ | | | | | | | アザーズパーミッション | | | | | グループパーミッション | | | ユーザーパーミッション | ファイルの型(type)
- --- --- --- d rwx rwx rwx l s s t s S S b c P
左端の文字とファイルの型は, 次のように対応づけられています.
- | 通常のファイル |
d | ディレクトリ |
l | シンボリックリンク |
s | ソケット |
b | ブロックデバイス |
c | キャラクタデバイス |
P | 名前つきパイプ |
また, 利用権限は以下の通りです.
- | その権限が出ていない |
r | 読み込み許可 |
w | 書き込み許可 |
x | 実行許可 |
s | s ビットが立っていて, かつ実行許可 |
S | s ビットが立っていて, かつ実行不可 |
t | スティッキー(sticky) |
s ビットについては後述します (スティッキー(sticky)については[付録2]参照).
上の出力結果において, ドット(.) で始まるファイルが存在したと思います. これはユーザの環境を設定する為のファイルで「ドットファイル」と呼ばれます. オプションをつけずに ls コマンドを打っても表示されません. その為隠しファイルと呼ばれることもあります. この実習では特に設定を変えることはありませんので, 詳細については触れないことにします.
ファイルの利用権限を設定するには chmod コマンドを用います. 基本的な使い方は次の通りです(詳しくは man chmod).
$ chmod <mode> file1 [file2 ...]
<mode> の部分には 0 から 7 までの数字を 3 桁並べたものが入ります. 左の桁から順にファイルの所有者, ファイルの所属グループ, その他のユーザーに対する利用権限を示します. 各々の読みだし, 書き込み, 実行権限は 4, 2, 1 の数字で表され, 上の <mode> にはこの数字の和が代入されます.
許可 | 記号 | 数字 |
---|---|---|
読込 | r | 4 |
書込 | w | 2 |
実行 | x | 1 |
例えば, モードを -rw-rw-r--
と変えたい場合,
-rw-rw-r-- 42 42 4 | | | 6 6 4 <mode>となるので,
$ chmod 664 fileとすれば変更できます.
上では <mode> を数字で与えましたが, 記号で与えることもできます. <mode> の数字列の代わりに,
対象 | 操作 | 許可 |
---|---|---|
[ugao] | [+-=] | [rwxst] |
対象と操作の文字は以下の意味を表します.
対象 | 操作 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
この場合, 先の例と同じ設定にするには次のようにします.
$ chmod u=rw,g=rw,o=r file
ここまでグループという語が何度か出てきました.
グループとは複数のユーザを管理する為の単位で, 共同作業する際に便利です.
例えば, 研究室において複数の人間がファイルを共通で管理したい場合に グループという概念は非常に重要なものとなるでしょう.
ここではグループの作成, ユーザのグループへの追加の方法を学び, グループの有用性を体感してみましょう.
グループを新たに作成する為には, addgroup というコマンドを用います. 但し, アカウントを新たに作成するコマンド adduser 同様, root でなければ addgroup コマンドを実行することは出来ません. VTA の人に addgroup コマンドを実行してもらいましょう (VTA の人は別ターミナルで su を使って一般ユーザになった後, sudo を実行して root になって下さい).
# addgroup inex
これで inex というグループが作成された筈です. 前回のレクチャーで少し触れましたが, グループの基本情報は /etc/group に記述されています. このファイルは一般ユーザでも閲覧できますので, 受講生の皆さんは /etc/group の中身を見てみましょう.
$ less /etc/group
/etc/group の最下行に以下のような記述があると思います. この行は addgroup を実行したことによって加わったものです.
inex:x:1005:
この時点で inex グループに所属するユーザはいません. 再び root である VTA の人の力を借りて, 皆さんと VTA の人をグループに追加してもらいましょう. グループの追加は adduser コマンドで行うことが出来ます.
# adduser foo inex
これで foo というユーザが inex グループに追加された筈です. /etc/group を見ると, 先程の行の一番右のコロン以下にユーザ名が記述されているのが 確認できると思います. 同様の手順で VTA のアカウントもグループに追加しましょう (これ以降 VTA の人のアカウント名が vta であるとして話を進めます).
inex:x:1005:foo, vta
もう 1 つ VTA の人に作業をしてもらいましょう. /home 以下に作業ディレクトリ work を作ります. 更に所有者・所有グループを変更するコマンド chown を用いて, work ディレクトリの所有者を foo, 所有グループを inex とします. またグループの書き込みを許可します.
# cd /home # mkdir work # chown foo:inex work # chmod g+w work
受講生の皆さんは ls -l コマンドを使って work ディレクトリの所有者・所有グループを確認してみてください.
$ ls -l /home/ drwxrwxr-x 2 foo inex 4096 Apr 28 02:28 work
ここで work ディレクトリ内にファイルを作成してみましょう. めでたくファイルが作成出来たと思います.
$ cd /home/work/ $ echo "test" > test.txt $ ls -l -rw-r--r-- 1 foo foo 7 2011-04-28 03:24 test.txt
ところが, 実はこれだとめでたくないのです. vta は inex グループに入っているのですが, この状態では vta が test.txt を編集することは出来ません. つまりこれでは inex グループに入っている foo, vta の 2 人がファイルを編集できる状態にはなっていないのです.
そこで次のコマンドを実行してみましょう.
$ sg inex $ echo "test" > test2.txt $ ls -l -rw-r--r-- 1 foo foo 7 2011-04-28 03:24 test.txt -rw-r--r-- 1 foo inex 7 2011-04-28 03:29 test2.txt
test2.txt の所有グループが inex になりましたね. sg コマンドは, 指定したグループでコマンドを実行する為のコマンドです. この場合 inex グループとして test2.txt を作成したので, 所有グループが inex となっています.
これで一見めでたくなったかに思われるのですが, 当初の目標である 「foo, vta の 2 人がファイルを直接編集できる状態」にはなっていません.
s ビットとは, あるファイルの実行者を「成り変わる」機能のことを言います.
s ビットには, SUID ビットと SGID ビットの二種類あります.
具体例で見て行きましょう. SUID の例として /usr/bin/passwd を見てみます.
第二回目の実習で, passwd コマンドが出てきました. この passwd は /usr/bin/ ディレクトリに存在します (前回登場した /etc/passwd とは別物であることに注意しましょう). passwd コマンドを実行してパスワードを変更すると, /etc/shadow が書き変わるのでしたね. そこで, /etc/shadow のパーミッションを見てみると,
$ ls -l /etc/shadow -rw-r----- 1 root root 22485 Apr 28 03:52 /etc/shadow |
ですから, このファイルの書き込みができるのは, このファイルの持ち主, すなわち root だけです. しかし, 誰もがパスワードを変更したい(/etc/shadow が書き変わって欲しい) と思っています. どうやって /etc/shadow を書き変えることができるのでしょうか?
そこで /usr/bin/passwd のパーミッションを見てみます. すると,
$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 24680 Apr 1 02:50 /usr/bin/passwd |
左から 4 番目に s という文字が書かれています. これが SUID ビットで, このファイルが実行されると, プログラムの持ち主がこのファイルを実行したものと解釈されることを表します. つまり, passwd コマンドを実行すると, root が実行したものと解釈される のですから, /etc/shadow を書き換えることができるという訳です.
root が所有者であるファイルやディレクトリに対して, SUID ビットを設定する場合は注意が必要です. 仮の話ですが(実際はそうなっていませんので安心してください), 例えば passwd にバグ(不具合)が含まれていて, 他のユーザのパスワードを変えることができるようになってしまっていたとしたら, SUID ビットを設定することによって大惨事が起こってしまうことになるでしょう (誰かに他のユーザや root のパスワードを変えられたら, 場合によっては恐ろしいことになるわけです).
SGID は上のグループ版です. 似たようなものなので説明は割愛します.
では, 実際にファイルを作ってみてパーミッションの変更等をしてみましょう.
以下の作業では, login, logout を繰り返すのが面倒なのでちょっとおまじないをします. まず, もう一つ mlterm を立ち上げ, 今 login しているアカウント(foo さん)の 相方(bar さん, 相方がいない場合は VTA さん)になりかわります.
$ mlterm & |
< kterm をもう一つ立ち上げる. |
新しく立ち上げた kterm を用いて以下のコマンドを打ち込んでみてください.
$ whoami foo $ su bar Password: $ whoami bar $ cd |
< 現在のログインアカウント名を尋ねる(foo だったとする). < bar になりかわる. このとき bar さんのパスワード入力が必要. < 無事 bar さんになっているか現在のアカウント名を尋ねる. < bar さんのホームディレクトリに移動しておく. |
以下, もともとあった kterm を "A ターミナル", あたらしく起動し bar さんになり変わった状態の kterm を "B ターミナル" と呼ぶことにします.
では, まず A,B 両ターミナルで以下の作業をして ディレクトリとファイルを作成してください.
$ cd $ mkdir secret $ echo 'secret-word' > ./secret/word.txt $ chmod ??? secret $ chmod ??? secret/word.txt |
< ホームディレクトリに移動. < secret ディレクトリを作成. < 'secret-word' 部分は好きな単語に置き換える. secret ディレクトリの中に ファイルを作成. < chmod をつかって secret ディレクトリのパーミッションを変える. ファイルが相方から見えないように ??? の部分を考えよう. < chmod をつかって secret/word.txt ファイルのパーミッションを変える. 上と同様にファイルが相方から見えないよう ??? の部分を考える. |
foo さん, bar さん共に, 今作った相手のファイルを見てみましょう.
$ cat ~foo/secret/word.txt |
$ cat ~bar/secret/word.txt |
お互いに相手のファイルが見えなければ成功です. もし見られてしまった場合は, 先の chmod コマンドを 先程とは違うモードで再度実行し, 見られない様にしてください.
見られないようにする方法がわかったら, 今度はいろいろな モードにしてその違いを確かめてください. ディレクトリのモードを変えると, そのディレクトリに移動できなくなったり するはずです. cd コマンドなどを試してみてください.
最後に自分の作った word.txt を消去してください. このとき, どのようなモードだとファイル消去できないかも是非試してください.
この知識は自分の卒論などを誤って消してしまわないためにも重要です! つまり, 消去できないようにファイルのモードを変更しておけば, 誤って rm コマンドを実行しそうになったときも, 消去されずに済むわけです!
UNIX / Linux ではファイルモードの設定によって, 他人のファイルを見る ことが可能です. 大抵の場合, 普通に作成したファイルは他人が見れる状態にあるでしょう. もし, 本当に見られては困る内容のファイルはモードを正しい設定にするように 心がけましょう. 他人がみても良い設定のファイルは基本的に "見ても良い" 訳ですが, "mail" といった文字列のつく名前のファイルやディレクトリの中, あるいは個人的な情報であることが推測できるファイルは, 仮に見れる状態にあっても絶対に見てはいけません. また, 同様に見られては困るファイルを見れる状態で置いておくことも 避けましょう. こういったファイルは, 見た方も見られた方も嫌な思いをしてしまいます.
リンクとは, あるファイルやディレクトリを, 別のファイルやディレクトリに関連付ける仕組みをいいます.
リンクには,
先に ls コマンドを用いた説明で, その実行結果の左から2番目に表示される数字は, リンク数を表すと述べました.
$ ls -l sample.txt -rw-r--r-- 1 inex epnetfan 363 Jun 20 12:11 sample.txt |
これは正しくは「ハードリンク」の数を表しています. ハードリンクの数は, 簡単に言うとファイルの「名前」の数を表しています.
人間は文字列(上の場合 'sample.txt')でファイルを識別しますが, システムはファイルを「番号」として管理しています. UNIX では, この番号を「i-ノード」と呼びます. ファイルと i-ノード番号は1対1に対応(リンク)しています.
i-ノードという概念は, そもそも UNIX のカーネルが, それぞれのパーティションに, 装置番号(device number)を割り当て, 「ディスク」ではなく「ファイルシステム」 という論理的なレベルで処理を行うことに由来しています. ファイルシステムは, 論理的なブロックの集まりから構成され, 単位となるブロックの大きさはシステムによって異なります.
ファイルシステムは, 次のような4つの部分に分けられます.
i-ノードには, 次のような情報が含まれています. ここで注意して欲しいことは, i-ノードにはファイル名は含まれていないということです.
ls -i
とするとファイルの i-ノード番号を実際に見ることができます.
$ ls -i sample.txt 31657 sample.txt |
ハードリンクの数は, 実はそのファイルの対応している i-ノード番号を 参照しているファイルの数を表しています.
したがって同じ i-ノード番号をもつ別名のファイルを作ること, 即ちファイルに複数の名前をつけることができます. これは "ln" コマンドで実行できます.
touch コマンドで空のファイル file1 を作り試してみましょう. 通常ファイルのリンク数は1です.
$ touch file1 $ ls -l file1 -rw-r--r-- 1 inex epnetfan 0 Jun 27 02:39 file1 |
$ ln file1 file2とすると file1 に新しい名前 file2 を加える(リンクを張る)ことができます.
$ ls -l file1 file2 -rw-r--r-- 2 inex epnetfan 0 Jun 27 02:39 file1 -rw-r--r-- 2 inex epnetfan 0 Jun 27 02:39 file2 |
リンク数が2に増えています. 一方ディレクトリのリンク数は必ず2以上になります. リンクを消すには rm コマンドを使います.
上の ln コマンドにオプション -s をつけて実行してみます. これは「シンボリックリンク」と呼ばれ, 簡単にいうとファイルの「別名」をつけるようなものです. 類似のものに, Windows では「ショートカット」, Mac では「エイリアス」があります.
$ ln -s file1 file3 $ ls -l file1 file3 -rw-r--r-- 2 inex epnetfan 0 Jun 27 02:39 file1 lrwxrwxrwx 1 inex epnetfan 5 Jun 27 02:45 file3 -> file1 |
ハードリンクの場合は i-ノードを直接参照しているのに対し, シンボリックリンクは「ファイル名」を参照しています. 従って、上の例でも file1 のリンク数も増えませんし, file3 のリンク数も1のままです.
シンボリックリンクの特徴をみるため, 次のようにコマンドを実行してみましょう.
$ rm file1 $ cat file3 cat: file3: No such file or directory |
$ ls file3 file3 |
これはシンボリックリンクでは「ファイル名」を参照しているためです. 参照先のファイル名が消去されてしまうと, 参照していたファイルの i-ノードを見ることができなくなり, 上の例では file3 を表示しようとするとエラーが返るのです.
ハードリンクとは異なり, ディレクトリに対するシンボリックリンクは可能です. シンボリックリンクを消すにはやはり rm コマンドを使います.
スティッキービットとは, ファイルまたはディレクトリの所有者だけが目的のファイルの削除や名前の変更を行えるようにする機能のことです.
s ビットの時と同様に具体例で見て行きましょう. ルートディレクトリ( / )の下には tmp というディレクトリがあります. このディレクトリのパーミッションを見ると,
$ ls -l / drwxrwxrwt 6 root root 1024 Jul 1 12:16 tmp |
これによるとこのディレクトリは誰でも読み書きができるようになって いますが, 「アザーズ」の実行許可のところに t と書かれています.
これがスティッキービットで, それによって, このディレクトリの中にあるファイルの消去や名前の変更は, そのファイルの所有者だけが行えるようになるということになります.
ls -l /dev
としてみると以下のような出力が得られます.
$ ls -l /dev/ total 50 -rwxr-xr-x 1 root root 14373 Nov 30 1996 MAKEDEV* -rwxr-xr-x 1 root root 28676 Nov 30 1996 MAKEDEV-C* -rw-r--r-- 1 root root 1035 Nov 30 1996 README.MAKEDEV -rw-r--r-- 1 root root 1434 Nov 30 1996 README.MAKEDEV-C lrwxrwxrwx 1 root root 4 Jan 15 21:46 X0R -> null crw-r--r-- 1 root root 10, 134 Jun 8 1996 apm_bios crw------- 1 root root 16, 1 Feb 19 1994 arp crw-rw-rw- 1 root sys 10, 3 Jul 18 1994 atibm crw-rw-rw- 1 root sys 14, 4 Jul 19 1994 audio crw-rw-rw- 1 root sys 14, 20 Jul 19 1994 audio1 brw-r----- 1 root disk 29, 0 Feb 16 1995 aztcd crw-r--r-- 1 root root 10, 128 May 25 1996 beep . . . crw-r----- 1 root disk 27, 25 Dec 8 1995 zqft1 crw-r----- 1 root disk 27, 26 Dec 8 1995 zqft2 crw-r----- 1 root disk 27, 27 Dec 8 1995 zqft3 |
ファイルモードを見ると, 一番左が見慣れない c や b になっています. このようなファイルは通常のファイルではありません.
UNIX では基本的にあらゆる物を抽象化して「ファイル」として扱います. たとえばマウス(/dev/mouse) や画面等もファイルに抽象化して取り扱ってしまいます.
このようなファイルは「デバイスファイル(device file)」と呼ばれます. デバイスファイルには, c で表されるキャラクタデバイスと, b で表されるブロックデバイスがあります.
★ /dev/null ★次を実行してみましょう.
$ ls > /dev/null何も出力されません. では, これはどうでしょう?
$ cat /dev/nullやはり何も表示されません.
/dev/null というファイルは, いかなる入力も捨ててしまう性質を持つデバイスファイルです. コマンドの出力がうるさい時などに, リダイレクトと組み合わせて使います.
※リダイレクトについては次回, 最低限 UNIX / Linux [III]で説明します.ソケットはプロセス間通信の終端点です. プロセス間通信には, パイプや TCP/IP (第 5 回) などいろいろな方法がありますが, その中に数えられる UNIX ドメインのソケット (同一コンピュータの内部で閉じたぷプロセス間通信で使うソケット) はファイルとして見えます.
代表的なソケットとしては以下の 2 つがあります.
$ ls -l /dev/{log,printer} srw-rw-rw- 1 root root 0 2011-04-27 06:25 /dev/log srw-rw---- 1 root lp 0 2011-04-25 06:47 /dev/printer |
ファイルタイプには s と書かれています. これがソケットを表します. /dev/printer はプリンタにつながっているソケットですが, 直接プリンタデバイスにつながっている訳ではありません. lpd (line printer daemon) が中継します. このソケットは, lpr コマンド (印刷するためのコマンド) が lpd デーモンと通信する時に使われます.
その名のとおり, 名前がついたパイプのことです. UNIX 内のプロセス間通信を行うために用いられます. 普通のパイプの場合, 親子または兄弟のプロセス間でしか通信できないという制限がありますが, 名前つき パイプの場合, 親子兄弟関係にないプロセスとも通信できます.
$ mknod pipe p $ ls -l pipe prw-r--r-- 1 foo foo 0 2011-04-28 22:21 pipe |
ファイルタイプに p と書かれていることが, 名前つきパイプであることを表しています.
実際に名前つきパイプを作ってみましょう.
もう一つ kterm を開きます.
$ kterm &
1 つ目のターミナルで cal コマンドを用いてを pipe に書き込みます.
$ cal > pipe
2 つ目のターミナルでカレンダー中の 2010 を抜き出します.
$ grep 2011 pipe 4月 2011 |
このように, 名前つきパイプを使うことで「cal | grep 2011」を分けて使うことができます.
最終更新日: 2011/04/27(山下達也) | Copyright © 2011 inex |