Jason's Blog

《Linux 就是这个范儿 - 阅读笔记2》 融于心而表于行(1)

用户的身份

Linux 下的用户等级实际上是非常简单的,就两个等级 root 和非 root。root 用户在 Linux 下是拥有至高无上的权利的,也就是说它可以胡作非为。但是比较幸运的是,只有一个用户是 root,它的用户名就叫 root。而非 root 用户的权利是严格受限的,只能访问由 root 规定的文件。

澡堂子模型

我们把 Linux 的用户管理方式比喻成一个澡堂子模型,因为这非常形象。所有非 root 用户,都只是这个澡堂子的顾客:root 用户则是这个澡堂子的服务生;Linux 系统就是这个大澡堂子。

去过澡堂子的人都知道,一进门就会有服务生接待你,让你登记并发给你一个带有号牌的钥匙。这个过程跟 root 用户给其他用户分配帐号是一个道理。登记是向系统中添加用户,钥匙是给你登录系统的密码,而号牌上的号码就是你的用户名。

当你获得钥匙之后,就可以进入更衣室了。更衣室一般都会有几组大柜子。每个大柜子又有 n 多的小柜子组成,其中有一个小柜子是属于你的。怎么找到属于你的柜子呢?看柜子上面的号码!这个号码与你钥匙号牌上的号码是一致的。

这个过程跟我们登录 Linux 系统的过程很相似。正确登陆后,我们就会拥有一个自己的文件目录,这个目录一般是 /home/[username],后面的 [username] 与你的用户名相同。一般称这个目录为“home 目录”。更衣室的柜子就是你的 home 目录,里面可以放入一些你的私人物品,可以保证别人偷不走。

只要离开你的 home 目录,就进入了公共区间。一般都是只读的,但有少数的位置是能够写入数据的,比如 /temp 目录。在使用 Linux 的过程中如果忘记了自己的密码,只要向 root 用户申请,就能够变更新的密码。

理解用户角色

在 Linux 系统中还有一些用户是用来完成特定任务的,比如 nobody、admin、ftp 等。需要注意,在 Linux 中不管用户名看起来有多牛,只要不是 root ,它就一定是个普通用户,权力大小都是相同的。很多资料上说的所谓用户角色的概念,尤其是说角色不同然后权限不同的观点不是十分精准,很容易造成 Linux 用户有权限大小的印象。其实所谓的权限,则是不同的用户所能访问的文件不同而产生的一种假象。而这种假象又不是单独一个用户的概念能决定的,还要用到用户组的概念。

什么是用户组呢?可以把它理解为用户的职业。一个用户可以属于多个用户组,而且还要注意,一个用户至少应该属于一个用户组。

虽然用户角色不能跟权限靠上关系,但不同角色有些时候还是有待遇差别的,所谓的待遇就是是否拥有密码、home 目录以及 shell 这些资源。有些用户的主要任务就是运行某些服务程序以确保安全的,比如 nobody 用户就可以用于 Nginx(一个高性能的 HTTP 和反向代理服务器) 的工作进程。对于这类用户一般是不分配密码和 shell(严格来说还是分配 shell 了的,只是分配的是 /sbin/nologin 这个特殊的 shell。) 的,甚至 home 目录也没有。为什么要这么做呢?

首先,可能会有很多服务程序默认使用这个用户,如果设置了密码,程序就无法自动使用了;其次,因为不会有人使用这个用户登录系统,也就没有必要分配一个 shell 给它,然而私有的 home 目录也显得有些多余。

/etc/passwd文件查看用户

从这个文件名上看,应该是跟密码有关。的确是这样,只是那已经成为历史了。现在保存密码的文件是 /etc/shadow,也就是传说中的“影子文件”。/etc/passwd 文件,它是用来存放用户基本信息的。这个文件的部分内容如下:

[root@linux lixin]# more /etc/passwd
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
......
pulse:x:496:494:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin
piranha:x:60:60::/etc/sysconfig/ha:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/bash
luci:x:141:141:luci high availability management application:/var/lib/luci:/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
dovecot:x:97:97:Dovecot IMAP server:/usr/libexec/dovecot:/sbin/nologin
dovenull:x:495:491:Dovecot's unauthorized user:/usr/libexec/dovecot:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
jason:x:500:500:Jason Yang:/home/jason:/bin/bash

文件的每一行都代表一个用户。换句话说,这个文件有几行你的系统中就拥有几个用户。每一行由冒号“:”分割成7个字段,其结构如下所示:

用户名 : 密码 : UID : GID : 用户全名 : home 目录 : shell

这个文件中比较重要的是 UID(User ID)GID(Group ID),无论是用户还是用户组,Linux 只靠它们来识别。所以 UID 和 GID 都只是一个数字。为了区别不同的用户或用户组,需要保持它们自身在系统中的唯一性。UID 和 GID 是可以相同的,因为它们代表的是不同的概念(可以把他们理解为两张数据库表中的主键值),都为 0 的 UID 和 GID 是 Linux 系统中比较特殊的,它们分配给 root 用户和 root 用户组。UID 和 GID 是可以通过程序获取的,所以可以通过这个特殊的值来判断是否能够胡作非为。

虽然系统只区别 0 和 非零的 UID 和 GID,但是在使用习惯上还是进行了一些分段的(类似我们的平时分配端口号那样)。0 自然不用说,就是给 root 的;1~499是属于系统用户的,比如前面提到的那些待遇比较差的和一些甚至是占坑的就属于这类;500~4294967295是分配普通用户的。所以你会发现,你系统中的第一个被添加的用户的 UID 和 GID 都是 500。

/etc/group文件查看用户组

跟用户组有关的文件就是 /etc/group 文件了,也就是 /etc/passwd 中 GID 的来源。这个文件的部分内容如下所示:

[root@linux ~]# more /etc/group
root:x:0:
bin:x:1:bin,daemon
daemon:x:2:bin,daemon
sys:x:3:bin,adm
adm:x:4:adm,daemon
tty:x:5:
disk:x:6:
lp:x:7:daemon
mem:x:8:
kmem:x:9:
wheel:x:10:
mail:x:12:mail,postfix
uucp:x:14:
man:x:15:
games:x:20:
gopher:x:30:
......
fuse:x:492:
stapusr:x:156:
stapsys:x:157:
stapdev:x:158:
webalizer:x:67:
piranha:x:60:
sshd:x:74:
postgres:x:26:
luci:x:141:
mysql:x:27:
dovecot:x:97:
dovenull:x:491:
sfcb:x:490:root
tcpdump:x:72:
slocate:x:21:
jason:x:500:

与 /etc/passwd 类似,同样是每行代表一个用户组,只是这个文件比较简单,被冒号“:”分割成了四段。行结构如下所示:

组名 : 用户组密码 : GID : 用户组内的用户名

从 /etc/group 文件的结构可以看出,不但用户有密码,用户组也是有密码的。那么用户组密码是做什么的呢?是给用户组管理员用的。不过目前很少有这个机会要配置用户组管理员,与 /etc/passwd 一样,组密码是存储在 /etc/gshadow 文件中。那么这个字段也就是纯粹的“歪歪”了,它永远都是“x”。

比较怪异的是“用户组内的用户名”这个字段,因为从上述文件中会发现,有很多组是没有使用这个字段的。而使用这个字段的,则会使用逗号“,”来分割每个用户名。那么这个字段到底是什么含义呢?前面我们就说过,一个用户是可以身兼数职的(多个用户组)。那么,只要用户兼职了这个用户组,它的名字就会出现在这个字段里。那么那些没有使用这个字段的组呢?很显然,就是没有人兼职呗。但是没有人兼职,并不代表没人专职。在 /etc/passwd 文件中,某个用户的 GID 字段所代表的就是专职用户组。按照 Linux 中的术语,这叫“初始用户组”;那些兼职的用户组,就被叫做“支持用户组”。对于专职的用户来讲,是可以不出现在“用户组内的用户名”这个字段的。使用 groups 命令可以查看所有的“支持用户组”,而且在“支持用户组”的列表中第一个出现的那个组还有一个称呼,叫“有效用户组”。

管理用户和组

Linux 系统为用户和用户组的增、删、改提供了一些基本的命令。这些命令的作用就是对 /etc/passwd 和 /etc/group 这两个文件进行增、删、改来完成的。外加一个 /etc/shadow 文件专门用来管理密码。

Linux 中添加一个新的用户,可以使用 useradd 命令,同时还可以使用 adduser 命令。但 useradd 命令在任何 Linux 发行版都是一样的,所以我们最好牢记的是它,那么,添加一个新用户最简单的方法,可以使用这样的命令(注意,需要 root 权限):

[root@linux ~]# useradd lucky

这样名为 lucky 的用户就添加到系统中了。同时,系统已经帮我们设定好了很多的默认值了,这包括:

1、创建一个唯一的 UID;
        2、添加一个与用户名相同的用户组和一个唯一的 GID,并将用户设置为改组的专职用户;
        3、在 /home 目录下创建一个与用户名相同的目录;
        4、设置 shell 为 bin/bash

唯一还没有设置的就是密码了,使用 passwd 命令可以做到这一点,如下所示:

[root@linux ~]# passwd lucky
更改用户 lucky 的密码 。
新的 密码:######
重新输入新的 密码:######
passwd: 所有的身份验证令牌已经成功更新。

当录入密码时,光标是不会有任何反映的,不会有类似图形界面的“***”或“###”什么的出现。在文本状态下,所有有关密码的操作都是这样,包括使用文本界面登录的时候。虽然这种方式不允许我们在输入密码时被打断,但是安全性更好。

刚才的操作只是给指定用户修改密码(passwd 命令传递要修改的用户名),如果要修改当前登录用户的密码,不带用户名参数即可。更复杂的,比如修改密码的时效性等高级的内容,还有 chage 命令。

我们在添加新用户的时候难免不犯点错误,比如名字给弄错了。这个时候能有修正错误的方法将会是很可爱的事情,正好 usermod 命令能干这事。实际上 usermod 并不是弥补错误而提供的,因为修正用户的某些细微的配置参数实际上是更常见的操作,比如希望使用一个与众不同的 shell,usermod 命令简单示例如下:

[root@linux ~]# usermod -l lucky123 lucky

这样名为 lucky 的用户,登录名将被更改为 lucky123,关于 usermod 命令更多使用方式,请参考《usermod 命令详解》,或使用 man 命令查看帮助。

要删除某个用户,可以使用 userdel 命令。这个命令相当简单,希望删掉谁就把谁的用户写在它后面就行。如果你是 root,userdel 命令基本上就是你的判官笔了,“写谁”谁就消失了。此外,它还有一个“-r”的命令选项,把用户的 home 目录一同删掉。所以这个命令不但会“杀人”,还会“抄家”。

至于用户组的管理实际上是跟用户很像的,也拥有差不多相同的命令,差别就是将“user”这个前缀替换成“group”,即 groupaddgroupmodgroupdel

如果你对前面介绍的这些命令还有什么疑问,那就千万不要忘记我们在第一章中介绍的那个 man 命令,它能帮助你了解到全部。后面的内容中所出现的命令我们也不会太多地去讲述具体用法,我们希望你能养成一个自学的好习惯。

利用sudo假借身份

Linux 用户在执行某些操作的时候,时常会借用一下其他用户的身份,那么借用谁的身份呢?答案是 root 的,也就是以 root 身份来执行某些操作。比如 /etc/shadow 文件,由于其特殊性,普通用户是不被允许查看其内容的。但是拥有 sudo 特权的用户,可以执行以下命令,查看到这个文件的内容:

[jason@linux ~]$ sudo cat /etc/shadow

普通用户一旦拥有 sudo 的特权,几乎就可以胡作非为了,但是需要付出一点代价,需要在将要执行的命令前面冠上 sudo 这个前缀(别忘了空格分割)。同时被系统提示要求输入密码。但是,你现在可能不能立即验证这个功能,因为你现在所使用的这个用户(非root)未必具备 sudo 特权。那么,可以利用 root 用户让某个普通用户具备 sudo 特权。

给某个用户赋予 sudo 特权,实际上就是更改 /etc/sudoers 文件中的内容。这个文件比较重要的内容如下所示:

[root@linux ~]# cat /etc/sudoers
......
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL

## Allows people in group wheel to run all commands
# %wheel        ALL=(ALL)       ALL

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL

## Allows members of the users group to mount and unmount the
## cdrom as root
# %users  ALL=/sbin/mount/mnt/cdrom, /sbin/umount/mnt/cdrom
......

在这个文件中,所有以“#”开头的行都是注释内容。所以这个文件中的内容绝大多数都是废话,因为只有一行没有以“#”开头。那一行的内容就是:

root        ALL=(ALL)        ALL

它的含义是说 root 用户可以使用 sudo 特权以 root 权限执行任何命令。显然又是一句废话,root 用户有必要运用它的 sudo 特权吗?但是学着它的样子,自己添加一行,比如:

jason        ALL=(ALL)        ALL

那么 jason 用户就可以使用 sudo 特权以 root 权限执行任何命令了。

如果需要赋予 sudo 特权的用户只有少数那么几个,这样单独授权的方式没有什么问题。但是 Linux 还支持另外一种授权方法,那就是针对用户组授权,如下所示:

%wheel        ALL=(ALL)        ALL

这一行的作用就是让 wheel 用户组的所有用户默认拥有 sudo 特权。那么当需要给某个用户授权时,只要将其加入到 wheel 用户组即可。通过对比,与单独针对用户授权,针对用户组授权的区别在于在名称前面加了一个百分号“%”。

sudo 还有另外一个更为霸气的功能,就是在下面的这一行中。

%wheel        ALL=(ALL)        NOPASSWD:ALL

同样是给 wheel 用户组授权,但是关键的就是这个 NOPASSWD,可以使得不需要输入密码即可拥有 root 权限。这个 NOPASSWD 并不仅仅作用于用户组,对于我们前面所说的针对单个用户授权的方法也是有效的。

上面所介绍的这些修改,会让拥有 sudo 特权的用户能够以 root 权限执行任何命令,很多时候会觉得这个权限给的太过宽松,显然会威胁到管理员的地位。所以做必要的限制还是合理的。下面的代码能够满足这一需求:

%users   ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom

这一行主要描述了 users 用户组,可以执行:

/sbin/mount/mnt/cdrom

/sbin/umount/mnt/cdrom

这两个命令,其他的都将被 Linux 系统拒绝。需要注意,这里一定要写明命令的完全路径,两个命令之间使用逗号“,”分割。

显然一个命令一个命令地写是非常麻烦的,只允许执行这几个命令也是有违背赋予 sudo 特权的初衷的。但是别着急,sudo 还有另外一种写法,可以是这样:

%users   ALL=(ALL)   ALL,!/usr/sbin/adduser, !/usr/sbin/useradd

这一行使得 users 用户组无法使用 sudo 特权给系统添加新的用户。关键就在叹号“!”这里,它表示禁止使用某些命令。

使用 sudo 特权,必须在每个命令前冠以 sudo,这会给管理员的很多工作造成不需要的麻烦,su 命令可以解决这个问题。

su 命令就是做零时用户切换的,默认是切换到 root 用户。su 在做用户切换的时候也会提示输入密码,但是与 sudo 需要输入自己的密码不同,su 要求输入目标用户的密码,如果是切换到 root,那么要求的是 root 密码。一旦切换完成,就会将当前的用户转换为目标用户。如果希望再切换回原始用户,就可以使用 exit 命令。

如果不给 su 命令任何参数,它切换的用户是 root 用户,同时不会更改当前所在的目录。比如说你当前所在的目录是 /home/jason,那么执行完 su 命令后,依然是在这个目录。当给 su 命令传递一个“-”参数时,即执行“su -”,则会改变当前目录到目标用户的 home 目录。

顺便说一下,拥有 sudo 特权的用户,是可以通过执行:

[jason@linux ~]$ sudo su

命令,直接使用自己的密码切换成 root 用户的。原理就是 root 用户使用 su 命令切换到任何用户都不提示密码。这显然是不安全的。为了避免这种问题发生,应该在 /etc/sudoers 文件中明确禁止 su 被 sudo 特权执行。

我是谁?

我们需要先做一些准备,请以普通用户登录系统,比如我是 jason,然后执行命令:

[jason@linux ~]$ whoami
jason
[jason@linux ~]$ who am i
jason    pts/0       2014-09-23 00:38 (192.168.0.100)

接着我们使用 su 命令切换到 root 用户下再试一下:

[root@linux ~]# whoami
root
[root@linux ~]# who am i
jason    pts/0       2014-09-23 00:38 (192.168.0.100)

看出区别来了吗?whoami 这个命令的结果是不同的,但是 who am i 命令却有相同结果,要解释这背后的机制,需要引入另外两个新的概念--实际用户(UID)和有效用户(EUID,即 Effective UID)。

所谓的实际用户是指用户登录时所使用的用户,所以在整个登录会话中,实际用户是不会发生变化的(who am i 执行的结果);而有效用户则是指当前执行操作的用户(whoami 执行的结果),这个是能够利用 su 或 sudo 命令进行任意切换的,也就是真正决定权限高低的用户,一般情况下,实际用户和有效用户是相同的,只有发生用户身份切换的时候,才会有差异。对那些经常需要切换用户的系统管理员来说,就经常需要搞清当前使用的是什么身份,毕竟切来切去的换做谁都有可能凌乱。

posted @ 2014-09-17 00:24  jasonsoop  阅读(334)  评论(1编辑  收藏  举报