在普通权限中,用户对文件只有三种身份,就是属主、属组和其他人;每种用户身份拥有读(read)、写(write)和执行(execute)三种权限。但是在实际工作中,这三种身份实在是不够用,我们举个例子来看看。先看看示意图,如下图所示:
在根目录中有一个/project目录,这是我们班级的项目目录。班级中的每个学员都可以访问和修改这个目录,老师也需要对这个目录拥有访问和修改权限,其他班级的学员当然不能访问这个目录。需要怎么规划这个目录的权限呢?应该这样:老师使用root用户,作为这个目录的属主,权限为rwx;班级所有的学员都加入tgroup组,使tgroup组作为/project目录的属组,权限是rwx;其他人的权限设定为0。这样这个目录的权限就可以符合我们的项目开发要求了。
有一天,我们班来了一位试听的学员st,她必须能够访问/project目录,所以必须对这个目录拥有r和x权限;但是她又没有学习过以前的课程,所以不能赋予她w权限,怕她改错了目录中的内容,所以学员st的权限就是r-x。可是如何分配她的身份呢?变为属主?当然不行,要不root该放哪里?加入tgroup组?也不行,因为tgroup组的权限是rwx,而我们要求学员st的权限是r-x。如果把其他人的权限改为r-x呢?这样一来,其他班级的所有学员都可以访问/project目录了。
当出现这种情况时,普通权限中的三种身份就不够用了。ACL权限就是为了解决这个问题的。在使用ACL权限给用户st赋予权限时,st既不是/project目录的属主,也不是属组,仅仅赋予用户st针对此目录的r-x权限。这有些类似于Windows系统中分配权限的方式,单独指定用户并单独分配权限,这样就解决了用户身份不足的问题。
在CentOS 6.x系统中ACL权限默认是开启的,不需要手工开启。不过,如果你的操作系统不是CentOS 6.x,那该如何查看ACL权限是否开启了呢?可以这样查看:
[root@localhost ~]# mount
/dev/sda1 on /boot type ext4 (rw)
/dev/sda3 on / type ext4 (rw)
…省略部分输出…
#使用mount命令可以看到系统中已经挂载的分区,但是并没有看到ACL权限的设置
[root@localhost ~]# dumpe2fs -h /dev/sda3
#dumpe2fs是查询指定分区文件系统详细信息的命令
选项:
-h: 仅显示超级块中的信息,而不显示磁盘块组的详细信息
...省略部分输出...
Default mount options: user_xattr acl
...省略部分输出...
使用mount命令可以查看到系统中已经挂载的分区,而使用dumpe2fs命令可以查看到这个分区文件系统的详细信息。大家可以看到,我们的ACL权限是/dev/sda3分区的默认挂载选项,所以不需要手工挂载。不过我的Linux系统如果没有不过我的Linux系统如果没有默认挂载,则可以手工挂载吗?当然可以,执行如下命令:
[root@localhost ~]# mount -o remount, acl /
#重新挂载根分区,并加入ACL权限
使用mount命令重新挂载,并加入ACL权限。不过使用此命令是临时生效的。要想永久生效,需要修改/etc/fstab文件,命令如下:
[root@localhost ~]# vi /etc/fstab
UUID=c2ca6f57-b15c-43ea-bca0-f239083d8bd2 / ext4 defaults, acl 1 1
#加入ACL权限
[root@localhost ~]# mount -o remount /
#重新挂载文件系统或重启系统,使修改生效
我们知道了ACL权限的作用,也知道了如何开启ACL权限,接下来学习如何查看和设定ACL权限。命令如下:
[root@localhost ~]# getfacle 文件名
#查看ACL权限
[root@localhost ~]# setfacl 选项 文件名
#设定ACL权限
选项:
-m: 设定ACL权限。如果是给予用户ACL权限,则使用“u:用户名:权限”格式赋予;
如果是给予组ACL权限,则使用“g:组名:权限”格式赋予
-x: 删除指定的ACL权限
-b: 删除所有的ACL权限
-d: 设定默认ACL权限。只对目录生效,指目录中新建立的文件拥有此默认权限
-k: 删除默认ACL权限
-R: 递归设定ACL权限。指设定的ACL权限会对目录下的所有子文件生效
举个例子,就来看看上图中的权限怎么分配。我们要求root是/project目录的属主,权限是rwx; tgroup是此目录的属组,tgroup组中拥有班级学员zhangsan和lisi,权限是rwx;其他人的权限是0。这时,试听学员st来了,她的权限是r-x。我们来看看具体的分配命令:
例子1:设定用户ACL权限
[root@localhost ~]# useradd zhangsan
[root@localhost ~]# useradd lisi
[root@localhost ~]# useradd st
[root@localhost ~]# groupadd tgroup
#添加需要试验的用户和用户组,省略设定密码的过程
[root@localhost ~]# mkdir /project
#建立需要分配权限的目录
[root@localhost ~]# chown root:tgroup /project/
#改变/project目录的属主和属组
[root@localhost ~]# chmod 770 /project/
#指定/project目录的权限
[root@localhost ~]# ll -d /project/
drwxrwx--- 2 root tgroup 4096 1月 19 04:21 /project/
#查看一下权限,已经符合要求了
#这时st学员来试听了,如何给她分配权限
[root@localhost ~]# setfacl -m u:st:rx /project/
#给用户st赋予r-x权限,使用“u:用户名:权限”格式
[root@localhost /]# cd /
[root@localhost /]# ll -d project/
drwxrwx---+ 3 root tgroup 4096 1月 19 05:20 project/
#使用ls –l查询时会发现,在权限位后面多了一个“+”,表示此目录拥有ACL权限
[root@localhost /]# getfacl project
#查看/project目录的ACL权限
# file: project ← 文件名
# owner: root ← 文件的属主
# group: tgroup ← 文件的属组
user::rwx ← 用户名栏是空的,说明是属主的权限
user:st:r-x ← 用户st的权限
group::rwx ← 组名栏是空的,说明是属组的权限
mask::rwx ← mask权限
other::--- ← 其他人的权限
大家可以看到,st用户既不是/project目录的属主、属组,也不是其他人,我们单独给st用户分配了r-x权限。这样分配权限太方便了,完全不用先辛苦地规划用户身份了。
我想给用户组赋予ACL权限可以吗?当然可以,命令如下:
例子2:设定用户组ACL权限
[root@localhost /]# groupadd tgroup2
#添加测试组
[root@localhost /]# setfacl -m g:tgroup2:rwx project/
#为组tgroup2分配ACL权限,使用“g:组名:权限”格式
[root@localhost /]# ll -d project/
drwxrwx---+ 2 root tgroup 4096 1月 19 04:21 project/
#属组并没有更改
[root@localhost /]# getfacl project/
# file: project/
# owner: root
# group: tgroup
user::rwx
user:st:r-x
group::rwx
group:tgroup2:rwx ← 用户组tgroup2拥有了rwx权限
mask::rwx
other::---
mask是用来指定最大有效权限的。mask的默认权限是rwx,如果我给st用户赋予了r-x的ACL权限,mj需要和mask的rwx权限“相与”才能得到st的真正权限,也就是r-x“相与”rwxtj出的值是r-x,所以st用户拥有r-x权限。如果把mask的权限改为r–,和st用户的权限相与,也就是r–“相与”r-x得出的值是r–,st用户的权限就会变为只读。大家可以这么理解:用户和用户组所设定的权限必须在mask权限设定的范围之内才能生效,mask权限就是最大有效权限。
不过我们一般不更改mask权限,只要给予mask最大权限rwx,那么任何权限和mask权限相与,得出的值都是权限本身。也就是说,我们通过给用户和用户组直接赋予权限,就可以生效,这样做更直观。
补充:逻辑与运算的运算符是“and”。可以理解为生活中所说的“并且”。也就是相与的两个值都为真,结果才为真;有一个值为假,与的结果就为假。比如A相与B,结果如下表所示:
那么两个权限相与和上面的结果类似,我们以读(r)权限为例,结果如下表所示:
所以,“rwx”相与“r-x”,结果是“r-x”;“r–”相与“r-x”,结果是“r–”。
修改最大有效权限的命令如下:
例子3:修改mask权限
[root@localhost /]# setfacl -m m:rx project/
#设定mask权限为r-x,使用“m:权限”格式
[root@localhost /]# getfacl project/
# file: project/
# owner: root
# group: tgroup
user::rwx
group::rwx #effective:r-x
mask::r-x
#mask权限变为r-x
other::---
我们已经给/project目录设定了ACL权限,那么,在这个目录中新建一些子文件和子目录,这些文件是否会继承父目录的ACL权限呢?我们试试吧。
默认ACL权限的作用是:如果给父目录设定了默认ACL权限,那么父目录中所有新建的子文件都会继承父目录的ACL权限。默认ACL权限只对目录生效。命令如下:
例子5:默认ACL权限
[root@localhost /]# setfacl -m d:u:st:rx /project/
#使用“d:u:用户名:权限”格式设定默认ACL权限
[root@localhost project]# getfacl project/
# file: project/
# owner: root
# group: tgroup
user::rwx
user:st:r-x
group::rwx
group:tgroup2:rwx
mask::rwx
other::---
default:user::rwx ← 多出了default字段
default:user:st:r-x
default:group::rwx
default:mask::rwx
default:other::---
[root@localhost /]# cd project/
[root@localhost project]# touch bcd
[root@localhost project]# mkdir d2
#新建子文件和子目录
[root@localhost project]# ll
总用量 8
-rw-r--r-- 1 root root 0 1月 19 05:20 abc
-rw-rw----+ 1 root root 0 1月 19 05:33 bcd
drwxr-xr-x 2 root root 4096 1月 19 05:20 d1
drwxrwx---+ 2 root root 4096 1月 19 05:33 d2
#新建的bcd和d2已经继承了父目录的ACL权限
大家发现了吗?原先的abc和d1还是没有ACL权限,因为默认ACL权限是针对新建立的文件生效的。
再说说递归ACL权限。递归是指父目录在设定ACL权限时,所有的子文件和子目录也会拥有相同的ACL权限。
例子6:递归ACL权限
[root@localhost project]# setfacl -m u:st:rx -R /project/
#-R 递归
[root@localhost project]# ll
总用量 8
-rw-r-xr--+ 1 root root 0 1月 19 05:20 abc
-rw-rwx---+ 1 root root 0 1月 19 05:33 bcd
drwxr-xr-x+ 2 root root 4096 1月 19 05:20 d1
drwxrwx---+ 2 root root 4096 1月 19 05:33 d2
#abc和d1也拥有了ACL权限
总结一下:默认ACL权限指的是针对父目录中新建立的文件和目录会继承父目录的ACL权限,格式是“setfacl -m d:u:用户名:权限 文件名”;递归ACL权限指的是针对父目录中已经存在的所有子文件和子目录继承父目录的ACL权限,格式是“setfacl -m u:用户名:权限 -R文件名”。
我们来看看怎么删除ACL权限,命令如下:
例子7:删除指定的ACL权限
[root@localhost /]# setfacl -x u:st /project/
#删除指定用户和用户组的ACL权限
[root@localhost /]# getfacl project/
# file: project/
# owner: root
# group: tgroup
user::rwx
group::rwx
group:tgroup2:rwx
mask::rwx
other::---
#st用户的权限已被删除
例子8:删除所有ACL权限
[root@localhost /]# setfacl -b project/
#会删除文件的所有ACL权限
[root@localhost /]# getfacl project/
# file: project/
# owner: root
# group: tgroup
user::rwx
group::rwx
other::---
#所有ACL权限已被删除
在Linux系统中我们已经学习过r(读)、w(写)、x(执行)这三种文件普通权限,但是我们在查询系统文件权限时会发现出现了一些其他权限字母,比如:
[root@localhost ~]# ll /usr/bin/passwd
-rwsr-xr-x 1 root root 25980 2月 222012 /usr/bin/passwd
大家发现了吗?在属主本来应该写x(执行)权限的位置出现了一个小写s,这是什么权限?我们把这种权限称作SetUID权限,也叫作SUID的特殊权限。这种权限有什么作用呢?我们知道,在Linux系统中,每个普通用户都可以更改自己的密码,这是合理的设置。问题是,普通用户的信息保存在/etc/passwd文件中,用户的密码实际保存在/etc/shadow文件中,也就是说,普通用户在更改自己的密码时修改了/etc/shadow文件中的加密密码,但是,看下面的代码:
[root@localhost ~]# ll /etc/passwd
-rw-r--r-- 1 root root 1728 1月 19 04:20 /etc/passwd
[root@localhost ~]# ll /etc/shadow
---------- 1 root root 1373 1月 19 04:21 /etc/shadow
/etc/passwd文件的权限是644,意味着只有超级用户root可以读/写,普通用户只有只读权限。/etc/shadow文件的权限是000,也就是没有任何权限。这意味着只有超级用户可以读取文件内容,并且可以强制修改文件内容;而普通用户没有任何针对/etc/shadow文件的权限。也就是说,普通用户对这两个文件其实都是没有写权限的,那为什么普通用户可以修改自己的权限呢?
其实,普通用户可以修改自己的密码的秘密不在于/etc/passwd和/etc/shadow这两个文件,而在于passwd命令。我们再来看看passwd命令的权限:
[root@localhost ~]# ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 25980 2月 222012 /usr/bin/passwd
passwd命令拥有特殊权限SetUID,也就是在属主的权限位的执行权限上是s。可以这样来理解它:当一个具有执行权限的文件设置SetUID权限后,用户在执行这个文件时将以文件所有者的身份来执行。passwd命令拥有SetUID权限,所有者为root(Linux中的命令默认所有者都是root),也就是说,当普通用户使用passwd命令更改自己的密码的时候,实际上是在用passwd命令所有者root的身份在执行passwd命令,root当然可以将密码写入/etc/shadow文件,所以普通用户也可以修改/etc/shadow文件,命令执行完成后,该身份也随之消失。
SetUID的功能可以这样理解:
举个例子,有一个用户lamp,她可以修改自己的权限,因为passwd命令拥有SetUID权限;但是她不能查看/etc/shadow文件的内容,因为查看文件的命令(如cat)没有SetUID权限。命令如下:
[root@localhost ~]# su - lamp
[lamp@localhost ~]$ passwd
更改用户 lamp 的密码 。
为 lamp 更改 STRESS 密码。
(当前)UNIX 密码: ← 输入旧密码
新的 密码: ← 输入新密码
重新输入新的 密码:
passwd: 所有的身份验证令牌已经成功更新
#lamp可以修改自己的密码
[lamp@localhost ~]$ cat /etc/shadow
cat: /etc/shadow: 权限不够
#但是不能查看/etc/shadow文件的内容
我们画一张示意图来理解上述过程,如上图所示:
从示意图中可以知道:
cat命令没有SetUID权限,所以就使用lamp用户身份去访问/etc/shadow文件,当然没有相应权限了。
如果把/usr/bin/passwd命令的SetUID权限取消,普通用户是不是就不能修改自己的密码了呢?试试吧:
[root@localhost ~]# chmod u-s /usr/bin/passwd
#属主取消SetUID权限
[root@localhost ~]# ll /usr/bin/passwd
-rwxr-xr-x. 1 root root 25980 2月 222012 /usr/bin/passwd
[root@localhost ~]# su - lamp
[lamp@localhost ~]$ passwd
更改用户 lamp 的密码 。
为 lamp 更改 STRESS 密码。
(当前)UNIX 密码: ← 看起来没有什么问题
新的 密码:
重新输入新的 密码:
passwd: 鉴定令牌操作错误 ← 但是最后密码没有生效
这个实验可以说明SetUID的作用了吧,不过记得一定要把/usr/bin/passwd命令的SetUID权限加回来。
那什么是SetGID呢?当s标志在属主的x位置时是SetUID,那么s标志在属组的x位置时是SetGID,简称为SGID。比如:
[root@localhost ~]# ll /usr/bin/locate
-rwx--s--x 1 root slocate 35612 8月 242010 /usr/bin/locate
1.SetGID针对文件的作用:
SetGID既可以针对文件生效,也可以针对目录生效,这和SetUID明显不同。如果针对文件,那么SetGID的含义如下:
和passwd命令类似,普通用户在执行locate命令的时候,会获取locate属组的组身份。locate命令是在系统中按照文件名查找符合条件的文件的,不过它不是直接搜索系统的,而是搜索/var/lib/mlocate/mlocate.db这个数据库的。
举个例子,默认系统中/tmp/目录拥有SBIT权限:
[root@localhost ~]# ll -d /tmp/
drwxrwxrwt 4 root root 4096 1月 20 06:17 /tmp/
在其他人的x权限位,被t符号占用了,代表/tmp/目录拥有SBIT权限。我们使用lamp用户在/tmp/目录中建立测试文件ftest,然后使用lamp1用户尝试删除。如果没有SBIT权限,而/tmp/目录的权限是777,那么lamp1用户应该可以删除ftest文件。但是拥有了SBIT权限,会是什么情况?我们来看看:
[root@localhost ~]# useradd lamp
[root@localhost ~]# useradd lamp1
#建立测试用户lamp和lamp1,省略设置密码过程
[root@localhost ~]# su – lamp
#切换为lamp用户
[lamp@localhost ~]$ cd /tmp/
[lamp@localhost tmp]$ touch ftest
#建立测试文件
[lamp@localhost tmp]$ ll ftest
-rw-rw-r-- 1 lamp lamp 0 1月 20 06:36 ftest
[lamp@localhost tmp]$ su - lamp1
密码: ← 输入lamp1用户的密码
#切换成lamp1用户
[lamp1@localhost ~]$ cd /tmp/
[lamp1@localhost tmp]$ rm -rf ftest
rm: 无法删除"ftest": 不允许的操作
#虽然/tmp/目录的权限是777,但是拥有SBIT权限,所以lamp1用户不能删除其他用户建立的文件
说了这么多,到底该如何设置特殊权限呢?其实还是依赖chmod命令的,只不过文件的普通权限只有三个数字,例如,“755”代表属主拥有读、写、执行权限;属组拥有读、执行权限;其他人拥有读、执行权限。如果把特殊权限也考虑在内,那么权限就应该写成“4755”,其中“4”就是特殊权限SetUID了,“755”还是代表属主、属组和其他人的权限。这几个特殊权限这样来表示:
举个例子,我们手工赋予一下特殊权限:
[root@localhost ~]# touch ftest
[root@localhost ~]# chmod 4755 ftest
#赋予SetUID权限
[root@localhost ~]# ll ftest
-rwsr-xr-x 1 root root 0 1月 20 23:54 ftest
#查看一下,属主的x位变成了s
[root@localhost ~]# chmod 2755 ftest
#赋予SetGID权限
[root@localhost ~]# ll ftest
-rwxr-sr-x 1 root root 0 1月 20 23:54 ftest
#查看一下,属组的x位变成了s
[root@localhost ~]# mkdir dtest
[root@localhost ~]# chmod 1755 dtest/
#SBIT只对目录有效,所以建立测试目录,并赋予SBIT权限
[root@localhost ~]# ll -d dtest/
drwxr-xr-t 2 root root 4096 1月 20 23:56 dtest/
#查看一下,其他人的x位变成了s
我们可以把特殊权限设置为“7777”吗?命令执行是没有问题的,这样会把SetUID、SetGID、SBIT权限都赋予一个文件,命令如下:
[root@localhost ~]# chmod 7777 ftest
#一次赋予SetUID、SetGID和SBIT权限
[root@localhost ~]# ll ftest
-rwsrwsrwt 1 root root 0 1月 20 23:54 ftest
[root@localhost ~]# chmod 0755 ftest
#取消特殊权限
[root@localhost ~]# ll ftest
-rwxr-xr-x 1 root root 0 1月 20 23:54 ftest
但是这样做没有任何意义,因为这几个特殊权限操作的对象不同,SetUID只对二进制程序文件有效,SetGID可以对二进制程序文件和目录有效,但是SBIT只对目录有效。所以,如果需要设置特殊权限,则还是需要分开设定的。
我们讲过,在赋予权限的时候可以采用字母的方式,这对特殊权限来讲是同样适用的。比如我们可以通过“u+s”赋予SetUID权限,通过“g+s”赋予SetGID权限,通过“o+t”赋予SBIT权限。命令如下:
[root@localhost ~]# chmod u+s, g+s, o+t ftest
#设置特殊权限
[root@localhost ~]# ll ftest
-rwsr-sr-t 1 root root 0 1月 20 23:54 ftest
[root@localhost ~]# chmod u-s, g-s, o-t ftest
#取消特殊权限
[root@localhost ~]# ll ftest
-rwxr-xr-x 1 root root 0 1月 20 23:54 ftest
最后,还有一个大家要注意的问题,特殊权限只针对具有可执行权限的文件有效,不具有x权限的文件被赋予了SetUID和SetGID权限会被标记为S, SBIT权限会被标记为T,仔细想一下,如果没有可执行权限,则设置特殊权限无任何意义。命令如下:
[root@localhost ~]# chmod 7666 ftest
[root@localhost ~]# ll ftest
-rwSrwSrwT 1 root root 0 1月 20 23:54 ftest
大家也可以这样理解:S和T代表“空的”,没有任何意义。
chatrr只有root用户可以使用,用来修改文件系统的权限属性,建立凌驾于rwx基础权限之上的授权。命令格式如下:
[root@localhost ~]# chattr [+-=] [选项] 文件或目录名
选项:
+: 增加权限
-: 删除权限
=: 等于某权限
i: 如果对文件设置i属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;
如果对目录设置i属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件
a: 如果对文件设置a属性,那么只能在文件中增加数据,但是不能删除和修改数据;如果
对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除文件
e: Linux中的绝大多数文件都默认拥有e属性,表示该文件是使用ext文件系统进行
存储的,而且不能使用“chattr -e”命令取消e属性
管理员作为特权用户,很容易误操作造成不必要的损失。再者,都由root管理也怪累的,管理员也是人,也需要留点时间去约约会、看看电影、装装傻、发发呆,不是吗?所以健康的管理方法是在Linux服务架构好后,可授权普通用户协助完成日常管理。现在较为流行的工具是sudo,几乎所有Linux都已默认安装。还要注意一点,我们在前面介绍的所有权限,比如普通权限、默认权限、ACL权限、特殊权限、文件系统属性权限等操作的对象都是文件和目录,但是sudo的操作对象是系统命令,也就是root把本来只能由超级用户执行的命令赋予普通用户执行。
sudo使用简单,管理员root使用visudo命令即可编辑其配置文件/etc/sudoers进行授权。命令如下:
[root@localhost ~]# visudo
…省略部分输出…
root ALL=(ALL) ALL
# %wheel ALL=(ALL) ALL ← 此行是注释的,没有生效
#这两行是系统为我们提供的模板,我们参照它写自己的就可以了
…省略部分输出…
解释一下文件的格式:
root ALL=(ALL) ALL
#用户名 被管理主机的地址=(可使用的身份) 授权命令(绝对路径)
# %wheel ALL=(ALL) ALL
#%组名 被管理主机的地址=(可使用的身份) 授权命令(绝对路径)
4个参数的具体含义如下:
例子1,授权用户lamp可以重启服务器,则由root用户添加如下行:
[root@localhost ~]# visudo
lamp ALL= /sbin/shutdown –r now
指定组名用百分号标记,如%admgroup,多个授权命令之间用逗号分隔。用户lamp可以使用sudo -l查看授权的命令列表。
[root@localhost ~]# su – lamp
#切换成lamp用户
[lamp@localhost ~]$ sudo -l
[sudo] password for lamp: ← 需要输入lamp用户的密码
User lamp may run the following commands on this host:
(root) /sbin/shutdown -r now
#可以看到lamp用户拥有了shutdown –r now的权限
提示输入密码为lamp普通用户的密码,是为了验证操作服务器的用户是不是lamp用户本人。lamp用户需要执行时,只需使用如下命令:
[lamp@localhost ~]$ sudo /sbin/shutdown -r now