《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(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 类似,同样是每行代表一个用户组,只是这个文件比较简单,被冒号“:”分割成了四段。行结构如下所示:
从 /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”,即 groupadd、groupmod、groupdel。
如果你对前面介绍的这些命令还有什么疑问,那就千万不要忘记我们在第一章中介绍的那个 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 用户可以使用 sudo 特权以 root 权限执行任何命令。显然又是一句废话,root 用户有必要运用它的 sudo 特权吗?但是学着它的样子,自己添加一行,比如:
那么 jason 用户就可以使用 sudo 特权以 root 权限执行任何命令了。
如果需要赋予 sudo 特权的用户只有少数那么几个,这样单独授权的方式没有什么问题。但是 Linux 还支持另外一种授权方法,那就是针对用户组授权,如下所示:
这一行的作用就是让 wheel 用户组的所有用户默认拥有 sudo 特权。那么当需要给某个用户授权时,只要将其加入到 wheel 用户组即可。通过对比,与单独针对用户授权,针对用户组授权的区别在于在名称前面加了一个百分号“%”。
sudo 还有另外一个更为霸气的功能,就是在下面的这一行中。
同样是给 wheel 用户组授权,但是关键的就是这个 NOPASSWD,可以使得不需要输入密码即可拥有 root 权限。这个 NOPASSWD 并不仅仅作用于用户组,对于我们前面所说的针对单个用户授权的方法也是有效的。
上面所介绍的这些修改,会让拥有 sudo 特权的用户能够以 root 权限执行任何命令,很多时候会觉得这个权限给的太过宽松,显然会威胁到管理员的地位。所以做必要的限制还是合理的。下面的代码能够满足这一需求:
这一行主要描述了 users 用户组,可以执行:
/sbin/mount/mnt/cdrom
/sbin/umount/mnt/cdrom
这两个命令,其他的都将被 Linux 系统拒绝。需要注意,这里一定要写明命令的完全路径,两个命令之间使用逗号“,”分割。
显然一个命令一个命令地写是非常麻烦的,只允许执行这几个命令也是有违背赋予 sudo 特权的初衷的。但是别着急,sudo 还有另外一种写法,可以是这样:
这一行使得 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 命令进行任意切换的,也就是真正决定权限高低的用户,一般情况下,实际用户和有效用户是相同的,只有发生用户身份切换的时候,才会有差异。对那些经常需要切换用户的系统管理员来说,就经常需要搞清当前使用的是什么身份,毕竟切来切去的换做谁都有可能凌乱。