tkd2017の勉強ブログ

日々の勉強をアウトプットするブログ

[ふつりな 2版] 第4章 Linuxとユーザ

www.high-novice.com

  • P.54〜P.70

4.1 ユーザとグループ

Linuxではユーザー名とパスワードを入力することでログインができる。なぜログインが必要かといえば、複数のユーザーで同時に使うことを前提としているため。そのようなシステムを マルチユーザーシステム と呼ぶ。

逆に複数のユーザーではなく一人のユーザーが使うことを前提としたシステムは シングルユーザーシステム と呼ぶ。たとえば少し前のiOSやAndroidなど。

深く考えなければ、「1人向け」より「複数人向け」の方が、機能が多くてよさそう。しかし、一人向けであればログインが省けるなどメリットもあるはず。

Linuxがマルチユーザーシステムである理由はいくつか挙げられる。一番わかりやすい理由は「UNIXがそうだったから」。昔は非常に高価だったため、複数人でシェアするのが当然だった。

では現在は? コストメリットではなくセキュリティ(安全性)の面で意義がある。システムファイルなどは普段のユーザーとは別のユーザーを所有者としておくことで、うっかり消してしまうなどの誤操作からシステムを守ることができる。

Windowsもかつてはシングルユーザーシステムだったが、XP以降はマルチユーザーシステムとなった。

マルチユーザーによるセキュリティ確保のためには、権限管理(パーミッション)が必要不可欠。各ユーザーに権限を分割することで、不必要な操作をできないようにする。例外的にあらゆる権限をもつ スーパーユーザー がいて、普通は root という名前。あらゆるファイルを変更し、削除し、プロセスを停止できる権限を持っている。

今ならセキュアOS(たとえばSELinux)の機能を利用することで、rootユーザーの権限も制限できますね。面倒だからあまり使っていないのかな?

ユーザーとパーミッションだけでも権限管理はできるが、より柔軟に扱うためにグループという機能もある。システムはグループに対してパーミッションを付与できる。ユーザーは複数のグループに所属すことができ、所属しているグループに許可されている操作が可能となる。-gで追加できる最初のグループを単に「ユーザーのグループ」と呼び、-Gで追加できるその他のグループを「補足グループ(supplementary groups)」と呼ぶ。

ファイルのパーミッションについて復習。

ファイルには次の3種類のユーザー区別がある。

  • ファイルを所有するユーザー
  • ファイルを所有するグループに所属するユーザー
  • それ以外のユーザー

権限の種類としては次の3種類がある。

  • 読み込み(read, r)
  • 書き込み(write, w)
  • 実行(execute, x)

そのため、3種類のユーザー区別 x 3種類の権限で、合計9個の項目があることになる。ls -lで確認してみる。

[vagrant@localhost ~]$ ls -l /
total 16
lrwxrwxrwx.  1 root    root       7 1028 11:03 bin -> usr/bin
dr-xr-xr-x.  5 root    root    4096 1028 11:07 boot
drwxr-xr-x. 18 root    root    2960 1127 15:23 dev
drwxr-xr-x. 80 root    root    8192 123 10:59 etc
drwxr-xr-x.  3 root    root      21 1028 11:06 home
lrwxrwxrwx.  1 root    root       7 1028 11:03 lib -> usr/lib
lrwxrwxrwx.  1 root    root       9 1028 11:03 lib64 -> usr/lib64
drwxr-xr-x.  2 root    root       6 115  2016 media
drwxr-xr-x.  2 root    root       6 115  2016 mnt
drwxr-xr-x.  2 root    root       6 115  2016 opt
dr-xr-xr-x. 96 root    root       0 1127 15:23 proc
dr-xr-x---.  3 root    root     149 123 11:05 root
drwxr-xr-x. 26 root    root     840 123 19:05 run
lrwxrwxrwx.  1 root    root       8 1028 11:03 sbin -> usr/sbin
drwxr-xr-x.  2 root    root       6 115  2016 srv
dr-xr-xr-x. 13 root    root       0 1127 15:23 sys
drwxrwxrwt.  8 root    root     221 124 03:43 tmp
drwxr-xr-x. 13 root    root     155 1028 11:03 usr
drwxr-xr-x.  2 vagrant vagrant   25 1127 15:23 vagrant
drwxr-xr-x. 18 root    root     254 1127 15:23 var

各行の先頭にあるのがファイル種別(lとかd)で、その後の9桁がパーミッション(rwxr-xr-x)となっている。

またパーミッションは記号表記のほかに8進数表記もある。

記号 数字 ファイルの場合 ディレクトリの場合
r 4 catなどで読める lsなどで一覧が得られる
w 2 viなどで書き込める touchなどでファイルが作れる
x 1 プログラムとして実行できる cdなどでアクセスできる

前述のrwxr-xr-xであれば755となる。

たとえば所有者がvagrantユーザーであるファイルのパーミッションがrw-r--r--だとする。そうすると、vagrantユーザーとしてアクセスすればファイルを読み書きできる。ところで「vagrantユーザーとしてアクセスする」とはどういうことなのか? 実は「vagrantユーザーの属性をもったプロセスがアクセスする」ということ。Linuxにおいて、活動する主体はユーザーではなく プロセス ということになる。

プロセスの属性としてのユーザーのことを クレデンシャル と呼ぶ。カーネルはプロセスがもっているクレデンシャルを確認することで操作の可否を判断している。逆にいえば、クレデンシャルさえもっていれば、誰が起動したプロセスかということは問われない。

Linuxで最初に行うログインという操作によって、ログインしたユーザーのクレデンシャルをもったプロセスが生成される。このプロセスから作られるプロセス(サブプロセス)はコピーされたクレデンシャルをもつため、普段は意識せずとも操作ができるようになっている。

またログイン時にはユーザー名を入力するが、カーネルはユーザーID(UID)で認識しており、クレデンシャルもIDとなる。ユーザー名とユーザーIDの対応は/etc/passwdに記録されている。

[vagrant@localhost ~]$ cat /etc/passwd | head -5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

passwdのフォーマットは2.2 パスワードファイル /etc/passwd の構造を参考のこと。

またグループの情報は/etc/groupで管理されている。

[vagrant@localhost ~]$ cat /etc/group | head -5
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:

プログラムの中でユーザー名からユーザーIDを取得したい場合などは専用のAPIがあるため、それを利用する。直接変換ロジックを実装してはいけない理由として、ユーザー情報はこれらのファイル以外に、NIS(Network Information Service)やLDAP(Lightweight Directory Access Protocol)などでも管理されていることがあるため。APIを利用することでこれらを意識することなく取得できる(第14章の話し)。

4.2 シェルと端末

端末(ターミナル)とは、人が直接に接する部分を指す。現代の典型的な環境なら手元のPCのこと。端末の種類をざっと挙げてみる。

  • テレタイプ
    • ディスプレイ装置がなく、出力は長い紙に打ち出された
    • UNIXでは端末のことを TTY と呼ぶが、これはテレタイプ(TeleTYpe)からきている
  • ダム端末
    • 文字だけを表示可能なディスプレイとキーボード、それに付随するハードウェアが付いていた
    • 有名な機種としては VT100 など
  • キャラクタ端末
    • VT100をはじめとする初期のダム端末は キャラクタ端末 と呼ばれ、ディスプレイに文字しか表示できなかった
  • ビットマップディスプレイ
    • 細かい点(ビットマップ)で表現し、文字以外にも絵などが表示できる
    • 一例として、X Window Systemを動作させるために使われた X端末 などがある
  • 端末エミュレータ
    • ハードウェアであった端末をソフトウェアで実現したもの
    • GNOME terminalやKonsole、macOSのTerminalやiTerm2など

端末と似た意味のものに「コンソール」がある。端末が「人が直接に接する」部分だったのに対し、コンソールは「カーネルと直接対話する」装置を指す(より具体的にはキーボードとディスプレイなど)。物理的にはキーボードとディスプレイが1組しかなかったとしても、Linuxの場合は内部で仮想コンソールが起動しており、切り替えて使用できる。

ベルを鳴らすサンプル:bell.c

#include <stdio.h>
#include <stdlib.h>

int
main (int argc, char *argv[])
{
    printf("\007");
    exit(0);
}

LinuxではSSDやHDDがデバイスファイルとして表現されていた。端末も例外ではなく、/dev以下に、端末に対応するデバイスファイルが用意されている。たとえば最初の仮想コンソールは/dev/tty0である。

端末がファイルとして表現されていると何がうれしいのか? それは接続するためのストリームが得られること。端末につながったストリームを読み込むとキーボードからの入力が得られ、端末につながったストリームへ書き込むとディスプレイに文字が出力できる。このようなしくみによって、端末はファイルおよびストリームとして抽象化され、一見しただけではプロセスからは見えなくなっている。

最後にシェルについて。シェルはユーザーからの命令を解釈して実行するプログラムのこと。bashzshなど、ほかにもたくさん。それ自体はストリームからコマンドを読み込んで実行しているだけだが、そのストリームは端末につながっていることもあれば、つながっていないこともある。