Skip to content

第三章 身份与安全

1.用户、组、权限

用户和组

  • 用户user和组group在Linux系统中以数字形式进行管理。
  • 用户被分配的号码称为用户ID(UID)。
  • 每个Linux系统都有一个特权用户,即root用户。 root是系统管理员。 此用户的UID始终为0。
  • 普通用户的UID编号(默认情况下)为1000。
  • 每个组也分配了一个称为组ID(GID)的编号。
  • 每个用户有一个主要组(primary group),有零个或者任意个附加组(supplementary group)。

以openSUSE为例:

  • UID
  • 0: root
  • 1 – 99: System
  • 100 – 499: System accounts
  • ≥ 1000: Normal (unprivileged) accounts

  • GID

  • 0: root
  • 1 – 99: System Groups
  • 100 – 499: Dynamically Allocated System Groups
  • ≥ 1000: Normal Groups

举例:

$ id postfix
uid=51(postfix) gid=51(postfix) groups=482(mail),59(maildrop),51(postfix)

$ id vagrant
uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)

提示:

UID和GID等编号规则,是在文件/etc/login.defs中约定的。

2.SELinux

Security-Enhanced Linux (SELinux) 是一种Linux系统的安全架构,它允许管理员更好地控制谁可以访问系统。 SELinux于2000年向开源社区发布,并于2003年集成到上游 Linux 内核中。

SELinux为系统上的应用程序、进程和文件定义了访问控制。 它使用安全策略(一组规则告诉SELinux什么可以访问或不可以访问)来强制执行策略允许的访问。

当称为主体(subject)的应用程序或进程请求访问对象(如文件)时,SELinux会检查访问向量缓存(AVC, Access Vector Cache),其中缓存了主体和对象的权限。

如果SELinux无法根据缓存的权限做出访问决定,它会将请求发送到安全服务器。 安全服务器检查应用程序或进程和文件的安全上下文。 从SELinux策略数据库应用安全上下文(Security context),然后授予或拒绝许可。 如果权限被拒绝,avc: denied消息将在/var/log.messages中体现。

传统上,Linux和UNIX系统都使用DAC(Discretionary Access Control)。 SELinux是Linux的MAC(Mandatory Access Control)系统的一个示例。

在DAC方式下,文件和进程有自己的属主(所有者)。 用户可以拥有一个文件,一个组也可以拥有一个文件,或者其他人。 用户可以更改自己文件的权限。root用户对DAC系统具有完全访问控制权。

但是在像SELinux这样的MAC系统上,对于访问的管理是通过设置策略来实现的。即使用户主目录上的DAC设置发生更改,用于防止其他用户或进程访问该目录的SELinux策略也将继续确保系统安全。

MAC方式是控制一个进程对具体文件系统上面的文件或目录是否拥有访问权限。判断进程是否可以访问文件或目录的依据,取决于SELinux中设定的很多策略规则。

访问控制列表 (ACL,Access Control List) 为文件系统提供了一种额外的、更灵活的权限机制。 它旨在协助 UNIX 文件权限。ACL允许授予任何用户或组对任何磁盘资源的权限。ACL适用于在不使某个用户成为组成员的情况下,仍旧授予一些读或写访问权限。

下面示例对比说明了SELinux和ACL在文件属性展现上的特点。

  • -rwxr-xr-- vagrant wheel :没有selinux上下文,没有ACL
  • -rwx--xr-x+ vagrant wheel :只有ACL,没有selinux上下文
  • -rw-r--r--. vagrant wheel :只有selinux上下文,没有ACL
  • -rwxrwxr--+ vagrant wheel :有selinux上下文,有ACL

2.1.SELinux主要概念

  • 用户(Users):
  • SELinux的用户不等同与Linux用户。
  • SELinux用户以后缀_u结尾。

  • 角色(Roles):

  • 角色Roles是由策略Policies定义的,角色决定了使用哪个策略。
  • SELinux角色以后缀_r结尾。

  • 类型(Types):

  • SELinux是类型强制的,类型Types决定进程能否访问某个文件。
  • SELinux类型是以后缀_t结尾。

  • 上下文(Contexts):

  • 用来标记进程和文件。分别是用户Users,角色Roles,类型Types,范围Ranges。
  • 格式:user:role:type:range

  • 文件类型(Object Classes):

  • 每个文件类型Types都对应一套策略Policies。策略Policies决定了进程对这类文件的访问权限。
  • 访问权限有4种:

    • 创建create
    • 读取read
    • 写入write
    • 删除unlink(注意,这里不是链接的意思)
  • 规则(Rules)

  • 格式:allow user_t user_home_t:file {create read write unlink};
  • 含义:user_t类型对user_home_t类型有创建create,读取read,写入write,删除unlink权限。

2.2.SELinux in openSUSE

作为SELinux的替代品,2005年被Novell收购的Immunix公司开发了AppArmor。SUSE在openSUSE Leap中提供对SELinux框架的支持。这并不意味着openSUSE Leap的默认安装会在不久的将来从AppArmor切换到SELinux。

添加SELinux的源。可以从https://download.opensuse.org/repositories/security:/SELinux/下载对应的策略policy。

sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux

安装C++等基础开发包:

# 列出当前可安装的Pattern
sudo zypper pt

# 安装下面几个开发相关的Pattern
sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel

安装SELinux packages:

zypper se --search-descriptions selinux
sudo zypper in restorecond policycoreutils setools-console
sudo zypper in selinux-tools libselinux-devel

安装SELinux policy:

sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel

更新GRUB2 bootloader(GRUB2引导加载程序):

编辑文件/etc/default/grub,添加下面内容到GRUB_CMDLINE_LINUX_DEFAULT=这一行:

security=selinux selinux=1

记录这一行的原始信息:

GRUB_CMDLINE_LINUX_DEFAULT="splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor"

运行下面的命令生成新的GRUB2引导加载程序配置文件。

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

编辑文件/etc/selinux/config 并设置 SELINUX=permissive来启用SElinux。这与前面GRUB2的启动配置是一致的。 如文件不存在,则创建。

$ sudo cat /etc/selinux/config
SELINUX=permissive
SELINUXTYPE=targeted

重启系统。系统启动可能需要一些时间,SELinux需要给整个文件系统重新进行标签化。

重启后,运行下面的命令来查看SELinux是否运行正常。

$ sudo getenforce
Permissive
$ sudo sestatus -v
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   permissive
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     requested (insecure)
Max kernel policy version:      33

Process contexts:
Current context:                unconfined_u:unconfined_r:unconfined_t:s0
Init context:                   system_u:system_r:kernel_t:s0
/sbin/agetty                    system_u:system_r:kernel_t:s0
/usr/sbin/sshd                  system_u:system_r:kernel_t:s0

File contexts:
Controlling terminal:           unconfined_u:object_r:devpts_t:s0
/etc/passwd                     system_u:object_r:unlabeled_t:s0
/etc/shadow                     system_u:object_r:unlabeled_t:s0
/bin/bash                       system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
/bin/login                      system_u:object_r:unlabeled_t:s0
/bin/sh                         system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
/sbin/agetty                    system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
/sbin/init                      system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
/usr/sbin/sshd                  system_u:object_r:unlabeled_t:s0

参考:

GRUB2引导加载程序中添加的三个参数的解释:

security=selinux: This option tells the kernel to use SELinux and not AppArmor.

selinux=1: This option switches on SELinux.

enforcing=0: This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config.

小贴士:

在首次启用SELinux后,如果只在grub2里面添加selinux=1,通过getenforce命令看的SELinux一直就是disabled的状态,需要手工创建/etc/selinux/config文件添加配置才行。感觉grub2里面无需设置,直接配置/etc/selinux/config文件。不确定这个想法是否正确。

在grub2中设定selinux=1,在/etc/selinux/config文件中:

  • 设定SELINUX=permissive,重启后通过getenforce命令看到的是permissive。
  • 设定SELINUX=disabled,则重启后getenforce命令看到的是disabled。

这说明配置文件后启动,覆盖了内核设置。

注意,如果仅仅完成了上面的enable SELinux,立刻设定SELINUX=enforcing,会引起ssh无法登录,错误信息是/bin/bash: Permission denied

配置SELinux。

$ sudo semanage boolean -l
Failed to use semanage

添加下面内容到.bashrc文件。

export PATH=/usr/local/bin:/home/$USER/.local/bin:$PATH

更新pip3.

pip3 install --upgrade pip

安装下面几个包

sudo zypper in libselinux libselinux-devel
sudo zypper in python3-semanage
sudo zypper in libsemanage-devel libsemanage-devel-static
sudo zypper in policycoreutils-python-utils
sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile

sudo zypper in policycoreutils-devel

2.3.SELinux in Ubuntu

2.4.SELinux in Rocky

3.用户和组的配置文件

  • /etc/passwd:用户及其属性信息(用户名,UID,主组ID等)
  • /etc/shadow:用户密码机器属性
  • /etc/group:组及其属性
  • /etc/gshadow:组密码及其属性

3.1./etc/passwd

格式说明:

vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash
[-----] - [--] [-] [-----] [-----------] [-------]
   |    |  |    |     |          |           +--------> 7. Login shell
   |    |  |    |     |          +--------------------> 6. Home directory
   |    |  |    |     +-------------------------------> 5. GECOS or the full name of the user
   |    |  |    +-------------------------------------> 4. GID
   |    |  +------------------------------------------> 3. UID
   |    +---------------------------------------------> 2. Password
   +--------------------------------------------------> 1. Username

3.2./etc/shadow

格式说明:

vagrant:$6$.n.:17736:0:99999:7:::
[-----] [----] [---] - [---] ----
|         |      |   |   |   |||+-----------> 9. Unused
|         |      |   |   |   ||+------------> 8. Expiration date since Jan 1, 1970
|         |      |   |   |   |+-------------> 7. Inactivity period 密码过期后的宽限期
|         |      |   |   |   +--------------> 6. Warning period, default 7 days
|         |      |   |   +------------------> 5. Maximum password age
|         |      |   +----------------------> 4. Minimum password age
|         |      +--------------------------> 3. Last password change since Jan 1, 1970
|         +---------------------------------> 2. Encrypted Password
+-------------------------------------------> 1. Username

3.3./etc/group

格式说明:

audio:x:492:pulse
[---] - [-] [---]
  |   |  |    +----> 4. username-list, who have this group as their supplementary
  |   |  +---------> 3. GID
  |   +------------> 2. group-password. Real password is in /etc/gshadow
  +----------------> 1. groupname

3.4./etc/gshadow

格式说明:

general:!!:shelley:juan,bob
[-----] -- [-----] [------]
   |     |     |       +-------> 4. group members (in a comma delimited list)
   |     |     +---------------> 3. group adminstrators (in a comma delimited list)
   |     +---------------------> 2. encrypted password. `!`, `!!`, and null
   +---------------------------> 1. group name

Encrypted password

  • !:no user is allowed to access the group using the newgrp command.
  • !!:the same as a value of ! — however, it also indicates that a password has never been set before.
  • null:only group members can log into the group.

3.5.生成随机密码

# 通过`/dev/urandom`生成随机数,通过`tr -dc`过滤随机数,只保留字母和数字,通过`head -c`保留指定位数
$ tr -dc '[:alnum:]' < /dev/urandom | head -c 12
xFw7vfma54D8

$ openssl rand -base64 9
I5TZXJfpd3Pg

3.6.vipw/vigr/pwck/grpck命令

vipwvigr命令分别编辑文件/etc/passwd/etc/group。 如果指定了-s标志,这些命令将分别编辑其文件的影子(安全)版本:/etc/shadow/etc/gshadowvipwvigr命令在编辑文件时会设置锁以防止文件损坏。 vipwvigr命令会首先尝试环境变量$VISUAL,然后是环境变量$EDITOR,最后是默认编辑器vi

sudo vipw
sudo vipw -s
sudo vigr
sudo vigr -s

pwck命令实现验证系统认证信息的完整性。 检查/etc/passwd/etc/shadow中的所有条目每个字段是否具有正确的格式和有效数据。 系统会提示用户删除格式不正确或存在其他错误的条目。

pwck返回值:

  • 0: success
  • 1: invalid command syntax
  • 2: one or more bad password entries
  • 3: can’t open password files
  • 4: can’t lock password files
  • 5: can’t update password files

grpck命令实现验证系统认证信息的完整性。 检查/etc/group/etc/gshadow中的所有条目每个字段是否具有正确的格式和有效数据。 系统会提示用户删除格式不正确或存在其他错误的条目。

grpck返回值:

  • 0: success
  • 1: invalid command syntax
  • 2: one or more bad group entries
  • 3: can’t open group files
  • 4: can’t lock group files
  • 5: can’t update group files

4.用户管理

用户管理命令:

  • useradd
  • usermod
  • userdel

4.1.创建用户useradd

举例:

# 普通用户
$ useradd -m -g wheel -G root -c "vagrant" vagrant

# 非交互用户
$ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c "Apache" apache 2>/dev/null

useradd命令的默认值是在/etc/default/useradd文件中设定。

openSUSE的/etc/default/useradd文件内容:

GROUP=100
HOME=/home
INACTIVE=-1              # 对应/etc/shadow文件第7列,Inactivity period,密码过期后的宽限期,-1表示不限制
EXPIRE=                  # 对应/etc/shadow文件第8列,Expiration date since Jan 1, 1970,即账号有效期
SHELL=/bin/bash
SKEL=/etc/skel           # 用于生成用户主目录的模版文件
USRSKEL=/usr/etc/skel
CREATE_MAIL_SPOOL=yes

Rocky的/etc/default/useradd文件内容:

GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

在Ubuntu中/etc/default/useradd文件只有下面这一行。

SHELL=/bin/sh

4.1.1.批量创建用户newusers

格式:newusers <filename>。其中文件<filename>的格式如下:

<Username>:<Password>:<UID>:<GID>:<User Info>:<Home Dir>:<Default Shell>

举例,创建文件users.txt

$ cat ~/users.txt
tester1:123:600:1530:"Test User1,testuser1@abc.com":/home/tester1:/bin/bash
tester2:123:601:1529:::/bin/bash
tester3:123:::::
tester4:123::::/home/tester4:/bin/tsh

看结果:

$ cat /etc/passwd | grep tester
tester1:x:600:1530:"Test User1,testuser1@abc.com":/home/tester1:/bin/bash
tester2:x:601:1529:::/bin/bash
tester3:x:1001:1001:::
tester4:x:1002:1002::/home/tester4:/bin/tsh

$ cat /etc/group | grep tester
tester1:*:1530:
tester2:*:1529:
tester3:*:1001:
tester4:*:1002:

$ sudo cat /etc/shadow | grep tester
tester1:!:19321:0:99999:7:::
tester2:!:19321:0:99999:7:::
tester3:!:19321:0:99999:7:::
tester4:!:19321:0:99999:7:::

$ ls -ld /home/tester*
drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00:32 /home/tester1
drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00:32 /home/tester4

4.1.2.批量修改密码chpasswd

不同方法:

echo username:password | chpasswd

chpasswd < file.txt  # file.txt每行的格式是username:password

paste -d ":" user.txt passwd.txt | chpasswd

参数-e:口令以加密的方式传递。否则口令以明文的形式传递。

注意:

  • 用户名username必须是已存在的用户
  • 普通用户没有使用这个指令的权限
  • 如果输入文件是按非加密方式传递的话,请对该文件进行适当的加密。
  • 指令文件不能有空行

举例:

echo tester1:112233 | sudo chpasswd
$ cat chpasswd.txt
tester1:112233
tester2:33445566

$ sudo chpasswd < chpasswd.txt

4.1.3.生成加密密码openssl passwd

命令openssl passwd格式可以如下方法获得。

$ man -f passwd
passwd (1)           - change user password
passwd (1ssl)        - compute password hashes
passwd (5)           - password file

$ man passwd
Man: find all matching manual pages (set MAN_POSIXLY_CORRECT to avoid this)
 * passwd (1)
   passwd (5)
   passwd (1ssl)
Man: What manual page do you want?
Man: 1ssl

举例(这里用<your_pwsswd_string>代替实际密码):

# 基于给定字串newpasswd生成sha256加密码,
$ openssl passwd -6 newpasswd
<your_pwsswd_string>

# 创建新用户tester5,赋予加密密码
$ useradd -p '<your_pwsswd_string>' tester1

# 读取用户tester5的密码,可以验证是否和之前的一致
$ sudo getent shadow tester5
tester5:<your_pwsswd_string>:19321:0:99999:7:::

4.2.修改用户属性usermod

添加用户到附加组

usermod -a -G GROUP USER
usermod -a -G GROUP1,GROUP2,GROUP3 USER

修改用户主组

usermod -a -g GROUP USER

修改用户信息

usermod -c "GECOS Comments" USER

修改用户主目录,使用绝对路径,-m参数会把原主目录的内容移动到新主目录。

usermod -d NEW_HOME_DIR USER
usermod -d NEW_HOME_DIR -m USER

修改用户shell

usermod -s SHELL USER

修改用户UID

usermod -u UID USER

修改用户名(不常用),同时也需要修改用户主目录。

usermod -l NEW_USER USER

修改用户过期属性,日期格式是YYYY-MM-DD

usermod -e DATE USER

如果设定永不过期,则置空日期:

usermod -e "" USER

查看当前用户的过期日期

$ sudo chage -l vagrant
Last password change     : Oct 30, 2022
Password expires     : never
Password inactive     : never
Account expires      : never
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires : 7

锁定用户。 此命令将在加密密码前插入一个感叹号 (!) 标记。 当/etc/shadow文件中的密码字段包含感叹号时,用户将无法使用密码验证登录系统。 其他登录方法仍然允许,例如基于密钥的身份验证或切换到用户。 如果要锁定账户并禁用所有登录方式,还需要将到期日期设置为1。

usermod -L USER
usermod -L -e 1 USER

解锁用户

usermod -U USER

4.3.删除用户userdel

userdel命令执行时,会读取/etc/login.defs文件的内容。 此文件中定义的属性会覆盖userdel的默认行为。 如果在此文件中将USERGROUPS_ENAB设置为yesuserdel将删除与用户同名的组,前提是没有其他用户是该组的成员。

userdel命令从/etc/passwd/etc/shadow文件中删除用户条目。

userdel命令删除用户帐户时,一般不会删除用户主目录和邮件假脱机mail spool目录。 使用-r选项强制删除用户的主目录和邮件假脱机目录。

如果要删除的用户仍然处于登录状态,或者有属于该用户的正在运行的进程,则userdel命令不允许删除该用户。

使用-f选项强制删除用户帐户,即使用户仍然登录或有属于该用户的正在运行的进程也是如此。

userdel USER
userdel -r USER

4.4.查看用户信息id

类Unix操作系统中的每个用户都由一个不同的整数标识,这个唯一的数字称为UserID。

为进程process定义了三种类型的UID,可以根据任务的权限动态更改。

定义的三种不同类型的UID是:

  1. 真实用户ID(Real UserId):对于一个进程,Real UserId就是启动它的用户的 UserID。 它定义了这个进程可以访问哪些文件。
  2. 有效用户名(Effective UserID):它通常与 Real UserID 相同,但有时会更改为使非特权用户能够访问那些只能由特权用户(如root)访问的文件。
  3. 保存的用户ID(Saved UserID) :当一个以提升的权限(通常是root)运行的进程需要做一些低权限的任务时使用,可以通过临时切换到非特权帐户来实现。在执行低权限任务时,有效的UID被更改为某个较低权限的值,并且euid被保存到已保存的userID(suid)中,以便在任务完成时用于切换回特权帐户。

在一个终端窗口执行下面命令,暂停在新密码输入这一步。

$ ls -ltr /usr/bin/passwd
-rwsr-xr-x. 1 root shadow 65208 May  8  2022 /usr/bin/passwd

$ passwd
Changing password for vagrant.
Current password:
New password:

新开一个终端窗口。

$ ps -a | grep passwd
  3040 pts/0    00:00:00 passwd

$ ps -eo pid,euid,ruid | grep 3040
  3040     0  1000

上面输出可以看出,passwd这个进程的Effective UserID是0。Real UserId是1000.

id命令查看用户有效的UID和GID。

查看当前用户的信息:

$ id
uid=1000(vagrant) gid=478(wheel) groups=478(wheel),0(root) context=unconfined_u:unconfined_r:unconfined_t:s0

查看指定用户的信息:

$ id vagrant
uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)

查看当前用户的GID:

$ id -g
478

查看当前用户的UID:

$ id -u
1000

查看当前用户所有组的GID:

$ id -G
478 0

查看当前用户名:

$ id -un
vagrant

查看当前用户的GID

$ id -ur
1000

只有SELinux激活后才有

$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0

类似于whoami命令

$ id -znG
wheelroot

4.5.切换用户su

命令su - username是登录式切换用户。会读取目标用户的配置文件,切换至目标用户的主目录。

命令su username是非登录式切换用户。不读取目标用户的配置文件,不改变当前工作目录。

切换成root用户,并使用zsh shell。

su -s /usr/bin/zsh
su -s /usr/bin/zsh root

切换成tester1用户,使用bash shell

su - tester1 -s /bin/bash
su - -s /bin/bash tester1

保留当前用户环境不变。

su -p root

不交互式切换用户,只用目标用户执行某些命令。

su -c ps
su - root -c "getent passwd"
su - root -s /bin/bash -c "getent passwd"

root用户切换至其他用户不需要密码,非root用户切换其他用户需要密码。

4.6.设置密码

4.6.1.passwd

修改当前用户自己的密码:

passwd

修改其他用户的密码:

sudo passwd root

查看某个用户密码状态:

$ sudo passwd -S root
root P 10/30/2022 -1 -1 -1 -1

$ sudo passwd -S vagrant
vagrant P 10/30/2022 0 99999 7 -1

检查全部用户的密码状态:

sudo passwd -Sa

密码状态说明:

Username  Status  Date Last Changed  Minimum Age  Maximum Age  Warning Period   Inactivity Period
vagrant     P       10/30/2022          0               99999           7                -1
root        P       10/30/2022          -1              -1              -1               -1

Status的描述:

  • P: Usable password
  • NP: No password
  • L: Locked password

Age的一些特殊值:

  • 9999: Never expires
  • 0: Can be changed at anytime
  • -1: Not active

强制要求用户下次登录时修改密码:

$ sudo passwd -e tester1

$ sudo passwd -S tester1
tester1 P 01/01/1970 0 99999 7 -1

用户tester1的密码日期已经被改成01/01/1970了。这个日期算是Unix的“纪元(epoch)”日期,意味着Unix的日期起点,0天。

锁定某个用户:

$ sudo passwd -l tester1

$ sudo passwd -S tester1
tester1 L 01/01/1970 0 99999 7 -1

此时用户tester1的状态栏已经变成了L,锁定状态。

解锁某个用户:

$ sudo passwd -u tester1

$ sudo passwd -S tester1
tester1 P 01/01/1970 0 99999 7 -1

此时用户tester1的状态栏已经从L变回了P,解除了锁定状态。

删除用户密码。这个操作慎重,密码删除后该用户可以不需要密码就能访问系统。

$ sudo passwd -d tester1

$ sudo passwd -S tester1
tester1 NP 01/01/1970 0 99999 7 -1

此时用户tester1的状态栏是NP

4.6.2.pwgen

安装包。

mkpasswd命令有歧义,2个同名命令实现不同功能,生成随机密码建议使用pwgen命令。Rocky9没有找到pwgen包。

sudo zypper in pwgen
sudo apt install pwgen

随机生成长度8位安全密码。

pwgen -s -1

随机生成长度14位安全密码。

pwgen -s -1 14

随机生成2个长度15位安全密码。

pwgen -s -1 15 2

随机生成5个密码,长度10位,每个密码至少含一个特殊字符,结果以列形式输出。

pwgen -s -1 -y 10 5

生成长度8,含有数字,含有大小写字母的密码4个,列打印

pwgen -s -n -c -C -1 8 4

生成长度8,不含数字,只含小写字母,列打印

pwgen -s -c -A -0 -1 8 4

生成长度16,含有数字,含有大小写字母,含有特殊字符的密码3个,行打印

pwgen -s -n -c -y -1 16 3

生成长度80,不含元音和数字,至少含有一个大写字母,行打印

pwgen -s -v -c -0 80 1

4.6.3.非交互式设置密码

方法1:

$ echo -e '123456\n123456' | sudo passwd tester1
New password: BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password: passwd: password updated successfully

方法2:

Rocky中可以使用下面方法。

pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1

openSUSE和Ubuntu可以用下面方法。

echo "tester1:"`pwgen -ncy1 16 1` | tee passwd.txt | sudo chpasswd

方法3:根据预先给定的用户列表,批量生成密码。

$ cat > user-list.txt <<EOF
user0
user1
user2
user3
user4
user5
user6
user7
user8
user9
EOF

$ for i in $(cat user-list.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done

$ for i in $(cat user-list.txt); do sudo userdel $i; done

4.7.设置用户密码策略

命令chage修改用户密码策略。

总结:

  • -d: Last password change : 上一次密码更改的日期。
  • -M: Password expires : 密码保持有效的最大天数。基于Last password change日期计算。设为-1表示不过期。
  • -I: Password inactive : 密码失效时间,在Password expires后,直至账号锁定之间的天数。设为-1表示不过期。
  • -E: Account expires : 帐号到期的日期。到期后,此帐号将不可用。设为-1表示不过期。
  • -m: Minimum number of days between password change : 两次改变密码之间相距的最小天数。
  • -M: Maximum number of days between password change : 两次改变密码之间相距的最大天数。
  • -W: Number of days of warning before password expires : 用户密码到期前,提前收到警告信息的天数。

显示用户密码策略(时效信息):

$ sudo chage -l tester1
Last password change     : Nov 27, 2022
Password expires     : never
Password inactive     : never
Account expires      : never
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires : 7

设置用户密码的最后修改日期:

$ sudo chage -d 2022-11-11 tester1

$ sudo chage -l tester1
Last password change     : Nov 11, 2022
Password expires     : never
Password inactive     : never
Account expires      : never
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires : 7

设置用户账号的过期日期:

$ sudo chage -E 2022-12-31 tester1

$ sudo chage -l tester1
Last password change     : Nov 11, 2022
Password expires     : never
Password inactive     : never
Account expires      : Dec 31, 2022
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires : 7

设置用户密码最小/最大修改天数。注意,密码过期日期Password expires是按照max days来计算的。

$ sudo chage -M 35 tester1
$ sudo chage -m 30 tester1

$ sudo chage -l tester1
Last password change     : Nov 11, 2022
Password expires     : Dec 16, 2022
Password inactive     : never
Account expires      : Dec 31, 2022
Minimum number of days between password change  : 30
Maximum number of days between password change  : 35
Number of days of warning before password expires : 7

设置用户账号在密码过期Password expires后,直至账号锁定之间的天数,即密码失效时间Password inactive。

$ sudo chage -I 3 tester1

$ sudo chage -l tester1
Last password change     : Nov 11, 2022
Password expires     : Dec 16, 2022
Password inactive     : Dec 19, 2022
Account expires      : Dec 31, 2022
Minimum number of days between password change  : 30
Maximum number of days between password change  : 35
Number of days of warning before password expires : 7

设置用户密码到期前,提前收到警告信息的天数。默认值是7天。

$ sudo chage -W 5 tester1

$ sudo chage -l tester1
Last password change     : Nov 11, 2022
Password expires     : Dec 16, 2022
Password inactive     : Dec 19, 2022
Account expires      : Dec 31, 2022
Minimum number of days between password change  : 30
Maximum number of days between password change  : 35
Number of days of warning before password expires : 5

5.组管理

组管理命令:

  • groupadd
  • groupmod
  • groupdel
  • groupmems

5.1.创建组groupadd

创建普通组。

sudo groupadd developers

创建系统组,并指定GID。

sudo groupadd -g 48 -r apache
sudo groupadd -g 1100 -r developers

覆盖配置文件/ect/login.defs

groupadd -K GID_MIN=500 -K GID_MAX=700

5.2.修改组groupmod

命令groupmod涉及下面这些文件:

/etc/group: Group Account Information. /etc/gshadow: Secured group account information. /etc/login.def: Shadow passwd suite configuration. /etc/passwd: User account information.

组改名:

sudo groupmod -n group_new group_old

5.3.删除组groupdel

命令groupdel涉及下面这些文件:

  • /etc/group : It contains the account information of the Group.
  • /etc/gshadow: It contains the secure group account information.

如果组中包含有用户,则必须先删除这些用户后,才能删除组。

sudo groupdel group_name

5.4.更改组成员和密码gpasswd

命令gpasswd用来修改组成员和密码。

涉及到的文件:

  • /etc/group: Group account information.
  • /etc/gshadow: Secure group account information.

给组developers设密码。

sudo gpasswd developers

取消组developers密码。

sudo gpasswd -r developers

给组developers添加用户。

sudo gpasswd -a tester1,tester2,tester3 developers

从组developers中删除用户。

sudo gpasswd -d tester3 developers

设定用户tester1成为组developers的管理员。

sudo gpasswd -A tester1 developers

注意:添加用户到某一个组 也可以通过usermod -G group_name user_name这个实现,但是该用户以前的组会被清空掉。 所以,如果要添加一个用户到一个新组,同时希望保留该用户以前的组时,使用gpasswd这个命令来添加用户到新组中。

5.5.修改组成员groupmems

使用命令groupmems,需要安装软件包。

# openSUSE
sudo zypper in libvshadow-tools
# Ubuntu
sudo apt install libvshadow-utils
# Rocky
sudo yum search shadow-utils

添加用户到组。

$ sudo groupmems -a tester1 -g developers
$ sudo groupmems -a tester2 -g developers

$ cat /etc/group | grep developers
developers:x:1002:tester1,tester2

从组中删除用户。

$ sudo groupmems -d tester2 -g developers

$ cat /etc/group | grep developers
developers:x:1002:tester1

列出组中用户。

$ sudo groupmems -l -g developers
tester1

切换当前组为developers_sre,添加用户tester2到当前组,可以不用在后续命令中使用-g指定组。

$ sudo groupmems -g developers_sre

$ sudo groupmems -a tester2

$ sudo groupmems -l
tester2

切换当前组为developers_sre,从当前组中删除所有用户(这里无法指定某用户)。

sudo groupmems -g developers_sre
sudo groupmems -p

5.6.查看组关系group

显示当前用户所属主的信息。

$ whoami
vagrant

$ groups
sudo adm cdrom dip plugdev lxd

查看指定用户所属组的信息。

$ groups vagrant
vagrant : sudo adm cdrom dip plugdev lxd

6.练习

创建用户gentoo,附加组为binroot,默认shell为/bin/csh,注释信息为"Gentoo Distribution"

sudo useradd -G bin,root -s /bin/csh -c "Gentoo Distribution" gentoo

创建下面的用户、组和组成员关系

  • 名字为webs的组
  • 用户nginx,使用webs作为附属组
  • 用户varnish,也使用webs作为附属组
  • 用户mysql,不可交互登录系统,且不是webs的成员,nginxvarnishmysql密码都是opensuse
sudo groupadd webs
sudo useradd -G webs nginx
sudo useradd -G webs varnish
sudo useradd -s /sbin/nologin mysql

echo "nginx:opensuse" | sudo chpasswd
echo -e "opensuse\nopensuse" | sudo passwd varnish
echo "mysql:opensuse" | sudo chpasswd

查看UID、GID范围的配置文件,修改为501-60000。并查看密码加密算法

$ cat /etc/login.defs
...
GID_MIN    1000
GID_MAX   60000
...
UID_MIN    1000
UID_MAX   60000
...
ENCRYPT_METHOD SHA512
...

查看创建用户时的模板配置文件

$ cat /etc/default/useradd
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
USRSKEL=/usr/etc/skel
CREATE_MAIL_SPOOL=yes

创建一个新用户webuser,指定登录时起始目录/www,同时加入apache附加组中,指定UID为999且不检查uid唯一性。

sudo useradd -d /www -G apache -u 999 -o webuser

修改创建用户时的默认设置,主目录/www,默认shell csh。查看创建用户的配置文件是否更改,若更改则恢复默认值

$ sudo useradd -Db /www -s /bin/csh

$ sudo cat /etc/default/useradd
# useradd defaults file
GROUP=100
HOME=/www
INACTIVE=-1
EXPIRE=
SHELL=/bin/csh
SKEL=/etc/skel
USRSKEL=/usr/etc/skel
CREATE_MAIL_SPOOL=yes

$ sudo useradd -Db /home -s /bin/bash

批量创建用户admin1admin2admin3

$ cat > user.txt <<EOF
admin1
admin2
admin3
EOF

$ for i in $(cat user.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done

只查看用户admin2admin3/etc/passwd的配置信息。

$ getent passwd admin2 admin3
admin2:x:1019:100::/home/admin2:/bin/bash
admin3:x:1020:100::/home/admin3:/bin/bash

修改admin2用户UID为2002、主组root、添加新的附加组apache且保留旧的附加组。然后锁定用户。

$ sudo usermod -u 2002 -g root -G apache -a admin2
$ sudo usermod -L admin2

$ getent passwd admin2
admin2:x:2002:0::/home/admin2:/bin/bash

$ sudo passwd -S admin2
admin2 L 11/27/2022 0 99999 7 -1

修改用户admin2用户名为smith,设置账号过期时间为2022-12-31

$ sudo usermod -l smith -e 2022-12-31 admin2

$ sudo chage -l smith
Last password change     : Nov 27, 2022
Password expires     : never
Password inactive     : never
Account expires      : Dec 31, 2022
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires : 7

admin1设置密码hello,然后指定新的主目录并把旧目录移动过去。

sudo usermod -d /home/admin_new -m admin1
echo "admin1:hello" | sudo chpasswd 

显示smith用户UID、GID、显示用户名、显示用户所属组ID

$ id -u smith
2002

$ id -g smith
0

$ id -un smith
smith

$ id -gn smith
root

锁定smith用两种方法

sudo passwd -l smith
sudo usermod -L smith

指定admin3的密码最短使用日期为5天,最常使用日期为10天,提前2天提示修改密码。

$ sudo chage -M 10 -m 5 -W 2 admin3

$ sudo chage -l admin3
Last password change     : Nov 27, 2022
Password expires     : Dec 07, 2022
Password inactive     : never
Account expires      : never
Minimum number of days between password change  : 5
Maximum number of days between password change  : 10
Number of days of warning before password expires : 2

创建系统组newadm,指定GID为66

sudo groupadd -r -g 66 newadm

修改newadm组名为newgrp 修改GID为67

sudo groupmod -n newgrp -g 67 newadm

将用户admin1添加进组newgrp,然后删除组newgrp

sudo usermod -g newgrp admin1
sudo groupdel -f newgrp

设置smith用户的详细描述,然后用finger查看。

$ chfn smith

$ finger smith
Login: smith             Name:
Directory: /home/admin2              Shell: /bin/bash
Never logged in.
No Mail.
No Plan.

删除用户admin1,并删除其主目录。

sudo userdel -r admin1
sudo userdel -r admin2

7.权限管理

执行命令ls -ihl,可以得到下面的输出结果(Rocky 9)。

67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
33555262 drwxr-xr-x. 2 vagrant wheel  6 Nov  1 11:30 typelink

67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file为例:

  • 67274680: inode 索引节点编号。
  • -rw-r--r--:文件类型及权限
  • -:文件类型,例子中出现了三种,-ld
    • -:普通文件
    • d:目录
    • l:符号链接文件(link)
    • b:块设备(block)
    • c:字符设备(character)
    • p:管道文件(pipe)
    • s:套接字文件(socket)
  • rw-r--r--:文件权限,从左到右依次为:(用户的最终权限,是从左向右匹配,一旦匹配则权限立即生效,不再向右继续匹配)
    • rw-:文件属主权限(u),例子中是vagrant
    • r--:文件属组的权限(g),例子中是wheel
    • r--:其他组的权限(o)。
  • .:这个点表示文件带有SELinux的安全上下文(SELinux Contexts)。关闭SELinux,新创建的文件就不会再有这个点了。但是,以前创建的文件本来有这个点的还会显示这个点(虽然SELinux不起作用了)。
  • 3:硬链接数,例子中filehardlinkfile1hardlinkfile2之间是硬链接,所以这三个文件的硬链接数都是3
  • vagrant:文件属主owner
  • wheel:文件属组group
  • 31:文件或目录的大小
  • Nov 1 11:14:文件或目录的创建日期和时间
  • file:文件或目录名称

下面是命令ls -ihl在openSUSE和Ubuntu上的显示结果。

$ ls -ihl
233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 file
233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile1
233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile2
233648 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile1 -> file
233650 lrwxrwxrwx 1 vagrant wheel 12 Nov  1 15:52 symlinkfile1-1 -> symlinkfile1
233649 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile2 -> file
233646 drwxr-xr-x 1 vagrant wheel  0 Nov  1 15:51 typelink

7.1.修改属主chown

chown命令修改文件属主(所有者,owner)。

修改文件属主为root。

$ ll f1.txt
-rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt

$ sudo chown root f1.txt

$ ll f1.txt
-rw-r--r--. 1 root wheel 41 Nov 14 22:23 f1.txt

修改文件的属组为bin。

$ sudo chown :bin f1.txt

$ ll f1.txt
-rw-r--r--. 1 root bin 41 Nov 14 22:23 f1.txt

同时修改文件的属主和属组。

$ sudo chown vagrant.wheel f1.txt

$ ll f1.txt
-rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt

参照某文件修改另一文件的属性。

$ ll file.py
-rw-r--r--. 1 vagrant wheel  56 Nov 13 22:50 file.py

$ ll user.txt
-rw-r--r--. 1 root bin 21 Nov 27 23:59 user.txt

$ sudo chown root.bin user.txt

$ sudo chown --reference=user.txt file.py

$ ll file.py
-rw-r--r--. 1 root bin 56 Nov 13 22:50 file.py

递归修改所有子目录及文件的属主和属组。

sudo chown -R vagrant.wheel ~

7.2.修改属组chgrp

修改目录的属组。

sudo chgrp bin ~~

修改目录及子目录及文件的属组。

sudo chgrp -R bin ~~

7.3.文件和目录权限

文件:

  • r:可以读取该文件内容,比如通过cat命令。
  • w:可以修改该文件内容,可以只有w而没有r
  • x:可以把该文件提请内核启动为一个进程,即可以执行该文件(该文件的内容必须是可以执行)。

目录:(对目录而言,通常需要给rx权限)(从目录角度看,目录内文件列表等于目录节点的内容)

  • r:能看文件列表,但不能访问所含文件的内容及其属性信息,包括inode号。
  • w:能在该目录内创建和删除文件,不由目录内文件本身的权限决定。
  • x:能cd进目录,能通过ls -l filestat file查看该目录中制定文件的元数据。
  • X:表示只有当该文件是个子目录或者该文件已经被设定过为可执行。

  • 有只读权限的用户不能用cd进入该目录,还必须有执行权限才能进入。

  • 有执行权限的用户只有在知道文件名,并拥有读权利的情况下才可以访问目录下的文件。
  • 必须有读和执行权限才可以ls列出目录清单,或使用cd命令进入目录。
  • 有目录的写权限,可以创建、删除或修改目录下的任何文件或子目录,即使使该文件或子目录属于其他用户也是如此。

常用权限例子:

-rw------- (600) 只有所有者才有读和写的权限
-rw-r--r-- (644) 只有所有者才有读和写的权限,组和其他人只有读的权限
-rwx------ (700) 只有所有者才有读,写,执行的权限
-rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组和其他人只有读和执行的权限
-rwx--x--x (711) 只有所有者才有读,写,执行的权限,组和其他人只有执行的权限
-rw-rw-rw- (666) 每个人都有读写的权限
-rwxrwxrwx (777) 每个人都有读写和执行的权限

7.4.权限修改chmod

命令格式:

chmod [-cfvR] [--help] [--version] mode file

mode字串格式为:

[ugoa][+-=][rwxXst]

who:

  • u文件所有者
  • g文件所有者所在组
  • o其他用户
  • a所有用户,相当于ugo

operator:

  • +为指定的用户类型增加权限
  • -去除指定用户类型的权限
  • =设置指定用户权限的设置,即将用户类型的所有权限重新设置

permission:

  • r设置为可读权限
  • w设置为可写权限
  • x设置为可执行权限
  • X特殊执行权限,只有当文件为目录文件,或者其他类型的用户有可执行权限时,才将文件权限设置可执行
  • s当文件被执行时,根据who参数指定的用户类型设置文件的setuid或者setgid权限
  • t设置粘贴位,只有超级用户可以设置该位,只有文件所有者u可以使用该位。

示例:

将文件file1.txt设为所有人皆可读取。

chmod ugo+r file1.txt

将文件file1.txt设为所有人皆可读取。

chmod a+r file1.txt

将文件file1.txtfile2.txt设为该文件属主和属组都可写入,但其他用户不可写入。

chmod ug+w,o-w file1.txt file2.txt

ex1.py文件属主增加可执行权限。

chmod u+x ex1.py

将目前目录下的所有文件与子目录皆设为任何人可读取。

chmod -R a+r *

file的所有用户增加读权限

chmod a+r file

删除file的所有用户的执行权限

chmod a-x file

file的所有用户增加读写权限

chmod a+rw file

file的所有用户增加读写执行权限

chmod +rwx file

file的属主设置读写权限,清空属组和其他用户对file的所有权限(空格代表无权限)

chmod u=rw,go= file

对目录docs和其子目录中的所有文件给属主增加读权限,而对属组和其他用户删除读权限

chmod -R u+r,go-r docs

file的属主和属组设置读写权限, 为其他用户设置读权限

chmod 664 file

file的属主设置读写执行权限,相当于u=rwx(4+2+1),设置属组读和执行权限,相当于go=rx(4+1 & 4+1)。0没有特殊模式

chmod 0755 file

4设置了设置用户ID位,剩下的相当于u=rwx(4+2+1)和go=rx(4+1 & 4+1)。

chmod 4755 file

删除可执行权限对path/以及其所有的目录(不包括文件)的所有用户,使用-type f匹配文件

find path/ -type d -exec chmod a-x {} \;

允许所有用户浏览或通过目录path/

find path/ -type d -exec chmod a+x {} \;

7.5.默认权限umask

umask的值,定义了所有新建的文件和目录的初始权限的。

查看当前权限掩码:

$ umask
0022

在不考虑umask的情况下,文件的默认权限是666(rw-rw-rw-),目录的默认权限是777(rwxrwxrwx)。

umask的值为0022的情况下,文件的默认权限是644(rw-r--r--),目录的默认权限是755(rwxr-xr-x)。

计算方法:

 Files: 
  (Default) 6 6 6
  (umask)   0 2 2
  ----------------
  (Result)  6 4 4

  Directories: 
  (Default) 7 7 7
  (umask)   0 2 2
  ----------------
    (Result)  7 5 5

如果umask的值为0077的情况下,文件的默认权限是600(rw-------),目录的默认权限是700(rwx------)。

计算方法:

 Files: 
  (Default) 6 6 6
  (umask)   0 7 7
  ----------------
  (Result)  6 0 0

  Directories: 
  (Default) 7 7 7
  (umask)   0 7 7
  ----------------
    (Result)  7 0 0

举例:

$ umask 022
$ touch file2
$ ll file2
-rw-r--r--. 1 vagrant wheel 0 Nov 28 23:13 file2

$ umask 077
$ touch file1
$ ll file1
-rw-------. 1 vagrant wheel 0 Nov 28 23:12 file1
$ umask 022
$ mkdir ./tmp1
$ umask 077
$ mkdir ./tmp2

$ ls -dl tmp*
drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23:14 tmp1
drwx------. 1 vagrant wheel 0 Nov 28 23:14 tmp2

7.6.特殊权限

除了三种常见的权限rwx,还有三种特殊权限:SUID,SGID,Sticky。

SUID:属主s权限,称为Set UID

  • 前提:进程有属主和属组,文件有属主和属组
  • 任何可执行程序文件能不能启动为进程,取决于发起者对程序文件是否拥有执行权限。
  • 启动为进程之后,其进程的属主为发起者。
  • 进程访问文件是的权限,取决于进程的发起者。

  • 只对二进制可执行程序文件有效。当执行该文件时,发起者将自动具有该文件所有者的权限。

  • 对目录无效。
$ ll file1
-rw-------. 1 vagrant wheel   0 Nov 28 23:12 file1

$ sudo chmod u+s file1

$ ll file1
-rwS------. 1 vagrant wheel 0 Nov 28 23:12 file1

如果属主的x位上是-,则在属主的x位上标记大写S,否则标记小写s。如下:

$ chmod 777 file1

$ ll file1
-rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1

$ sudo chmod u+s file1

$ ll file1
-rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1

下面2组命令实现同样效果。

sudo chmod 4xxx file1

chmod 777 file1
sudo chmod u+s file1

取消SUID。

sudo chmod u-s file1

SGID:属组s权限,称为Set GID

  • 如果作用于二进制可执行文件上,当执行该文件为进程之后,发起者将自动具有该文件所属组的权限,进程的属组为发起者的属组。
  • 如果作用于目录上,则该目录下新建立的目录和文件都自动从此目录继承。
$ sudo chmod g+s file2

$ ll file2
-rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23:13 file2

如果属组的x位上是-,则在属组的x位上标记大写S,否则标记小写s。如下:

$ chmod 777 file2

$ ll file2
-rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:13 file2

$ sudo chmod g+s file2

$ ll file2
-rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23:13 file2

下面2组命令实现同样效果。

sudo chmod 2xxx file2

chmod 777 file2
sudo chmod g+s file2

取消SGID。

sudo chmod g-s file2

对于目录,下面演示可以看到目录下的文件和子目录的继承性。

$ ll -d data
drwxr-xr-x. 1 vagrant bin 0 Nov 28 20:55 data

$ sudo chmod g+s .~

$ ll -d data
drwxr-sr-x. 1 vagrant bin 0 Nov 28 20:55 data

$ cd data
$ touch file2
$ ll file2
-rw-r--r--. 1 vagrant bin 0 Nov 29 21:10 file2

$ mkdir tmp3
$ ll -d tmp3
drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:10 tmp3

Sticky Bit:简称为SBIT权限

  • 只针对目录有效。它表示只能让其属主以及root可以删除、重命名、移动该目录下的文件。
  • Sticky设置在文件上无意义。

如果其他的x位上是-,则在其他的x位上标记大写T,否则标记小写t

$ ll -d .~
drwxr-sr-x. 1 vagrant bin 18 Nov 29 21:10 .~

$ sudo chmod o+t .~

$ ll -d .~
drwxr-sr-t. 1 vagrant bin 18 Nov 29 21:10 .~

$ cd data
$ touch file1
$ mkdir tmp1

$ ll file1
-rw-r--r--. 1 vagrant bin 0 Nov 29 21:37 file1
$ ll -d tmp1
drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:37 tmp1

特殊权限设置数字法:

设置SUID

              User    Group   Others
              r w s   r w s   r w x
              r w S
    BIN 100   1 1 1   1 1 1   1 1 1
              1 1 0
    OCT   4       7       7       7
                  6

设置SGID

              User    Group   Others
              r w x   r w s   r w x
              r w S
    BIN 010   1 1 1   1 1 1   1 1 1
                      1 1 0
    OCT   2       7       7       7
                          6

设置Sticky Bit - SBIT

              User    Group   Others
              r w x   r w x   r w t
                      r w T
    BIN 001   1 1 1   1 1 1   1 1 1
                              1 1 0
    OCT   1       7       7       7
                                  6

7.7.设定文件特殊属性chattr

命令格式:chattr [ -RVf ] [ -v version ] [ mode ] files...

其中mode的字串格式:{+|-|=}[aAcCdDeijsStTu]

属性i

  • 如果对文件设置i属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;
  • 如果对目录设置i属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件;

在openSUSE下执行,分区文件类型是btrfs格式。

$ touch filetest
$ lsattr filetest
---------------------- filetest

$ chattr +i filetest
chattr: Operation not permitted while setting flags on filetest
$ sudo chattr +i filetest

$ lsattr filetest
----i----------------- filetest

$ rm filetest
rm: cannot remove 'filetest': Operation not permitted
$ sudo rm filetest
rm: cannot remove 'filetest': Operation not permitted

$ echo "test" >> filetest
-bash: filetest: Operation not permitted
$ sudo echo "test" >> filetest
-bash: filetest: Operation not permitted

$ sudo chattr -i filetest

属性a

  • 如果对文件设置a属性,那么只能在文件中増加数据,但是不能删除和修改数据;
  • 如果对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除文件;

在openSUSE下执行,分区文件类型是btrfs格式。

lsattr filetest
---------------------- filetest
$ chattr +a filetest
chattr: Operation not permitted while setting flags on filetest
$ sudo chattr +a filetest

$ echo "test" >> filetest

$ rm filetest
rm: cannot remove 'filetest': Operation not permitted
$ sudo rm filetest
rm: cannot remove 'filetest': Operation not permitted

$ sudo chattr -a filetest

属性u

  • 设置此属性的文件或目录,在删除时,其内容会被保存,以保证后期能够恢复,常用来防止意外删除文件或目录。

在Ubuntu下执行,分区文件类型是ext4格式。

$ touch filetest
$ sudo chattr +u filetest

$ lsattr filetest
-u------------e------- filetest

$ rm filetest

属性s

  • u相反,删除文件或目录时,会被彻底删除(直接从硬盘上删除,然后用0填充所占用的区域),不可恢复。

提示:

命令chattrlsattr的可操作属性依赖于文件所处分区的文件系统类型,例如,ext4和xfs的结果会有不同。

历史:命令chattr(用于操作属性)和lsattr(用于列出属性)最初专用于第二个扩展文件系统系列(ext2、ext3、ext4),并且作为e2fsprogs包的一部分提供。然而,此功能已全部或部分扩展到许多其他系统,包括 XFS、ReiserFS、JFS 和 OCFS2。 btrfs 文件系统包括属性功能,包括C标志,由于与CoW相关的性能较慢,它关闭了btrfs的内置写时复制 (CoW) 功能。

8.访问控制列表ACL

8.1.ACL

ACL的全称是Access Control List。

传统的POSIX权限概念使用三种用户类型来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。

  • 所有者Owning Owner权限(属主权限)
  • 属组Owning Group权限
  • 其他(经过身份验证的)用户Other Users的权限

传统的三种权限适用于大多数实际案例。但是,对于更复杂的场景或更高级的应用程序,系统管理员必须使用许多技巧来规避传统权限的限制。

访问控制列表ACL提供了对传统文件权限概念的扩展。它们允许我们为单个用户或组分配权限,即使这些用户或组与原始所有者或属组不对应。

ACL是Linux内核的一项功能,支持Ext⅔/4,XFS和BtrFS文件系统以及其他文件系统。

使用ACL,我们可以创建复杂的方案,而无需在应用程序级别上去实现复杂的权限模型。在使用提供Samba文件和打印服务的Linux服务器替换Windows服务器的情况下,ACL的优势非常明显。由于Samba支持ACL,因此可以在Linux服务器和Windows中配置用户权限。

通过ACL来允许对所有者用户之外的单个用户进行文件写权限是一种简单的方案。使用传统方法,我们必须创建一个新组,使两个用户成为该组的成员,将该文件的所有组更改为新组,然后授予该组文件的写权限。创建组并使两个用户成为该组的成员则需要利用root权限来实现。

使用ACL,我们可以通过使所有者和指定用户对文件具有写权限来实现相同的结果。

此方法的另一个优点是系统管理员无需参与创建组。用户可以自己决定授予谁访问其文件的权限。

提示:

使用ACL时ls的输出结果会发生变化。添加一个加号+ 来说明已为此文件定义ACL,且定义ACL后,所显示的属组权限是ACL掩码的值,而不再是原来属组的权限。

8.2.ACL的基本类型

  • Minimal ACLs(最小ACL)(实际用途:与POSIX权限相同)
  • 与文件模式权限位等效的ACL称为最小ACL
  • 分三种类型的ACL条目,这些对应于文件和目录的传统权限位
    • Owning User 所有者
    • Owning Group 所有者组
    • Others 其他组
  • Extended ACLs(扩展ACL)
  • 具有多于上述三个ACL条目的ACL称为扩展ACL
  • 扩展ACL还包含掩码条目,可以包含任意数量的指定用户和指定组条目

8.3.ACL术语

  • 用户类(User classes)。 传统的POSIX权限概念使用三种用户类来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。
  • Owner class 所有者类
  • Group class 组类
  • Other class 其他类
  • ACL访问权限(Access ACL):确定各种文件系统对象(文件和目录)的用户和组的访问权限。
  • 默认ACL(Default ACL):只能应用于目录。 它们确定文件系统对象在创建时从其父目录继承的权限。
  • ACL条目(ACL entry):
  • 每个ACL由一组ACL条目组成。
  • ACL条目包含类型(type),条目引用的用户或组的限定符(qualifier),以及一组权限(permissions)。
  • 对于某些条目类型,未定义组或用户的限定符。

The mapping of minimal ACLs

8.4.ACL权限分类

  • Named user 指定用户: Lets you assign permissions to individual users. 允许我们为指定用户分配权限。
  • Named group 指定组: Lets you assign permissions to individual groups. 允许我们为制定组分配权限。
  • Mask 掩码: Lets you limit the permissions granted to named users or groups. 允许我们限制给予指定用户或指定组的权限。

所以可能的ACL类型

Type Text Form
owner user::rwx
named user user:name:rwx
owning group group::rwx
named group group:name:rwx
mask mask::rwx
other other::rwx

与POSIX.1权限模型不同,组类group class可以包含具有不同权限集的ACL条目,因此单独的组类权限不再足以表示它包含的所有ACL条目的所有详细权限。

因此,组类型权限的含义被重新定义。在新语义下,组类型权限表示组类中的任何条目将授予的权限的**上限**(upper bound)。 此上限属性可确保在使用ACL控制后,应用程序不会突然或者意外地授予额外的权限。

在最小ACL中,组类权限与所有者组权限相同。在扩展ACL中,组类可以包含其他用户或组的条目。这会导致一个问题:这些附加条目中的一些可能拥有未包含在所有者组条目(owning group entry)中的权限,因此所有者组条目权限可能与组类权限(group class)不同。

通过掩码(mask entry)解决了这个问题。

  • 使用最小ACL,组类权限映射到所有者组条目权限。With minimal ACLs, the group class permissions map to the owning group entry permissions.
  • 使用扩展ACL时,组类权限映射到掩码条目权限,而所有者组条目仍定义拥有组权限。With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions.

8.5.ACL操作命令

设定ACL权限:setfacl

  • Syntax: setfacl [OPTIONS] [ACL-ENTRIES] <file>
  • Option Description
  • -m: Add or modify an ACL entry
  • -x: Remove an ACL entry
  • -d: Set a default ACL
  • -b: Remove all extended ACL entries
  • -M: restore ACLs that have been written to a file

注意:--set选项会把原有的ACL项都删除,用新的替代,所以一定要包含UGO的设置,不能像-m医院只添加ACL。

setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1

读取ACL权限:getfacl

  • Syntax: getfacl [OPTIONS] <file>
  • Option Description
  • -a: Display the file access control list
  • -d: Display the default access control list
  • -R: List the ACLs of all files and directories recursively

8.6.ACL实例解析

8.6.1.实例描述

  • 项目目录~/project1
  • 项目经理pm1对这个目录拥有访问和修改权限
  • 项目成员tm1可以访问和修改这个目录
  • 非项目成员tm2不能访问~/project1目录。
  • 项目目录~/project1的权限规划
  • 项目经理pm1是这个目录的属主,权限为rwx
  • 项目经理pm1属于project1
  • 项目成员tm1pm1在同一个project1组,权限是rw
  • 其他人的权限设定为0
  • 项目临时成员tm2的权限需求
  • 能访问project1目录,但只能具有rx权限

解决方法

  • 当出现这种情况时,普通权限中的三种身份(owner,group,others)就不能解决这个问题,而ACL权限可以。 在使用ACL权限给用户tm2陚予权限时,tm2既不是~/project1目录的属主,也不是属组,仅仅赋予用户tm2针对~/project1目录的r-x权限, 属于单独指定用户并单独分配权限,解决了用户身份不足的问题。

拓展问题

  • ~/project1目录添加其他组project2的访问权限
  • 通过mask来调整用户tm2实际有效权限
  • 默认ACL权限
  • 递归ACL权限
  • 删除ACL权限

8.6.2.初始化环境

创建测试用户

$ whoami
vagrant

$ sudo groupadd project1
$ sudo groupadd project2

$ sudo useradd -m -g project1 pm1
$ sudo useradd -m -g project1 tm1
$ sudo useradd -m -g project2 tm2

$ sudo passwd pm1
$ sudo passwd tm1
$ sudo passwd tm2

$ cat /etc/group
......
project1:x:1535:
project2:x:1536:
......

$ cat /etc/passwd
......
pm1:x:2003:1535::/home/pm1:/bin/bash
tm1:x:2004:1535::/home/tm1:/bin/bash
tm2:x:2005:1536::/home/tm2:/bin/bash
......

创建测试目录project1, 指定project1目录的权限,创建测试文件file1

$ su - pm1
$ cd ~

$ mkdir project1

$ ls -dl project1
drwxr-xr-x. 1 pm1 project1 0 Dec  4 06:25 project1

$ chmod 770 project1/

$ ls -dl project1
drwxrwx---. 1 pm1 project1 0 Dec  4 06:25 project1

$ echo "hello from $USER" > ./project1/file1

$  cat ./project1/file1
hello from pm1

目录project1当前权限快照

  • 属主:pm1,对~/project1目录有rwx权限
  • 属组:project1,包含用户pm1tm1,对~/project1目录有rwx权限
  • 其他组:没有访问权限

目录~/project1当前的ACL快照

$ getfacl ./project1/
# file: home/pm1/project1/
# owner: pm1
# group: project1
user::rwx
group::rwx
other::---

8.6.3.添加ACL权限

~/project1目录添加新用户tm2,权限为rwx。目录~/project1的更新后的权限位变成了drwxrwx---+

$ su - pm1

$ setfacl -m u:tm2:rx ./project1/

$ ls -dl ./project1
drwxrwx---+ 1 pm1 project1 0 Dec  4 06:25 project1

$ getfacl ~/project1/
# file: project1   (文件名)
# owner: pm1       (Owner 文件属主)
# group: project1  (Owing Group 文件属组)
user::rwx          (Ower文件属主的权限,用户名栏是空的,说明是属主Owner的权限)
user:tm2:r-x       (Named User 指定用户的权限,用户tm2的权限)
group::rwx         (Owing Group 文件属组的权限,组名栏是空的,说明是属组的权限)
                   (Named Group 指定用户组的权限,此时未指定)
mask::rwx          (mask权限)
other::---         (其他人other的权限)

~/project1目录添加新组project2的权限rwx

$ su - pm1

$ setfacl -m g:project2:rwx ./project1/

$ ls -dl ./project1
drwxrwx---+ 1 pm1 project1 0 Dec  4 06:46 ./project1

$ getfacl ./project1
# file: project1
# owner: pm1
# group: project1
user::rwx
user:tm2:r-x         (用户tm2拥有了r-x权限)
group::rwx
group:project2:rwx   (用户组project2拥有了rwx权限)
mask::rwx
other::---

有效权限的计算:

当前~/project1目录的maskrwxtm2的权限是r-x,二者进行AND操作,tm2的实际权限是r-x

   tm2: r - x (1 0 1)
  mask: r w x (1 1 1)
---------------------
result: r - x (1 0 1)

对照下面的规则,验证用户tm2~/project1目录的实际权限。

su - tm2

能进入目录project1,说明当前用户具有目录project1r-x权限。

$ whoami
tm2

$ cd /home/pm1/project1/

能列出目录project1下文件列表,可以查看文件file的内容,说明当前用户具有目录project1r-x权限。

$ pwd
/home/pm1/project1

$ whoami
tm2

$ ls -l
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1

$ cat file1
hello from pm1

对目录project1不具有w权限,所以无法创建、删除或修改目录下的任何文件或子目录。

$ pwd
/home/pm1/project1

$ whoami
tm2

$ touch file2
touch: cannot touch 'file2': Permission denied

$ echo "hello from $USER" >> file1
-bash: file1: Permission denied

8.6.4.修改mask权限

调整~/project1目录的maskr--,则tm2的实际权限是r--

$ su - pm1
$ cd ~
$ setfacl -m m::r ./project1/

$ getfacl ./project1/
# file: project1/
# owner: pm1
# group: project1
user::rwx
user:tm2:r-x          #effective:r--  (用户tm2的实际有效权限变为r--)
group::rwx            #effective:r--  (属组project1组的实际有效权限变为r--)
group:project2:rwx    #effective:r--  (其他组project2组的实际有效权限变为r--)
mask::r--                             (mask变化,导致上述两个group的有效权限都发生了变化)
other::---

有效权限的计算:

当前~/project1目录的maskr--,用户tm2、组project2的实际权限是r--

   tm2: r - w (1 0 1)
  mask: r - - (1 0 0)
---------------------
result: r - - (1 0 0)

提示:

用户和用户组所设定的权限必须在mask权限设定的范围之内才能生效,mask权限就是最大有效权限。

8.6.5.有效权限分析

在POSIX权限模型和ACL权限叠加作用下,用户的实际权限分析。

$ getfacl ./project1/
# file: project1/
# owner: pm1                            <----Owner
# group: project1                       <----owning group
user::rwx                               <----owner's permissions
user:tm2:r-x          #effective:r--    <----named user's permissions
group::rwx            #effective:r--    <----owning group's permissions
group:project2:rwx    #effective:r--    <----named group's permissions
mask::r--                               <----masks for named user and named group
other::---
default:user::rwx
default:user:tm2:r-x
default:group::rwx
default:mask::rwx
default:other::---

所有者ower和其他用户other条目中定义的权限总是有效的。上例中的user条目和other条目。 除了掩码条目,所有其他条目(比如指定用户named user)可以是有效的或被屏蔽的。

指定用户(named user),所有者组(owning group)或指定组(named group)以及掩码mask条目中定义的权限,有效权限是他们权限进行逻辑AND后的结果,而不是单独的掩码中定义的权限或者各自条目中定义的权。

有效权限计算方法如下,注意,ls命令中显示出来的权限,与实际的ACL权限是有差别的。

        tm2: r - w (1 0 1)
      group: r w x (1 1 1)
named group: r w x (1 1 1)
       mask: r - - (1 0 0)
---------------------------
     result: r - - (1 0 0)

小贴士:

与文件模式权限位等效的ACL称为最小ACL,即POSIX传统权限。

含掩码mask等其他权限条目的ACL称为扩展ACL。

在最小和扩展ACL情形下,所有者类权限(owner)都是映射到ACL的所有者条目。 其他类权限映射到其各自的ACL条目。

在扩展ACL情形下,组类权限的映射是不同的。

对于没有掩码的最小ACL,组类权限将映射到ACL所有者组条目。

对于带有掩码的扩展ACL,组类权限将映射到掩码条目。

通过权限位进行分配的权限代表了通过ACL进行分配的权限的上限。 没有在这里体现的任何权限,要么不在ACL中,要么无效。

对权限位所做的更改将由ACL反映,反之亦然。

8.6.6.默认ACL权限

$ su - pm1

$ touch ./project1/file2
$ mkdir ./project1/cloud

$ ll ./project1/
drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2

$ ll -d project1/
drwxr-----+ 1 pm1 project1 30 Dec  4 08:52 project1/

文件file1和目录cloud没有继承project1目录的ACL权限。

提示:

默认 ACL限只对目录生效。 默认ACL权限的作用是:如果给父目录设定了默认 ACL 权限,那么父目录中所有新建的子文件都会继承父目录的ACL权限。

下面增加~/project1目录的默认ACL权限。

$ su - pm1
$ cd ~

$ getfacl ./project1/
# file: project1/
# owner: pm1
# group: project1
user::rwx
user:tm2:r-x          #effective:r--
group::rwx            #effective:r--
group:project2:rwx    #effective:r--
mask::r--
other::---

$ setfacl -m d:u:tm2:rx ./project1/

$ getfacl ./project1/
# file: project1/
# owner: pm1
# group: project1
user::rwx
user:tm2:r-x         #effective:r--
group::rwx           #effective:r--
group:project2:rwx   #effective:r--
mask::r--
other::---
default:user::rwx
default:user:tm2:r-x
default:group::rwx
default:mask::rwx
default:other::---

创建新子目录leonardo,就继承了~/project1目录的default ACL权限设定。

注意,默认ACL权限是针对新建立的文件生效的,目录cloud和文件file1并没有因为增加了父目录的默认ACL设定而继承默认ACL权限设定.

$ su - pm1
$ cd ~
$ mkdir ./project1/leonardo

$ ll ./project1/
drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo

8.6.7.递归ACL权限

递归 ACL 权限,是指父目录在设定ACL权限时,所有的子目录也会拥有相同的ACL权限。

$ su - pm1
$ cd ~

$ getfacl ./project1/
# file: project1/
# owner: pm1
# group: project1
user::rwx
user:tm2:r-x          #effective:r--
group::rwx            #effective:r--
group:project2:rwx    #effective:r--
mask::r--
other::---
default:user::rwx
default:user:tm2:r-x
default:group::rwx
default:mask::rwx
default:other::---

$ setfacl -m d:u:tm2:rx -R ./project1/

$ ll ./project1
drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo

8.6.8.删除ACL权限

删除用户tm2的ACL权限。

$ su - pm1
$ cd ~

$ setfacl -x u:tm2 ./project1/

$ getfacl ./project1/
# file: project1/
# owner: pm1
# group: project1
user::rwx
group::rwx
group:project2:rwx
mask::rwx
other::---
default:user::rwx
default:user:tm2:r-x
default:group::rwx
default:mask::rwx
default:other::---

删除所有的ACL权限。

$ setfacl -b ./project1

$ getfacl ./project1
# file: project1/
# owner: pm1
# group: project1
user::rwx
group::rwx
other::---

$ ll ./project1
drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo

递归删除全部ACL权限。

$ setfacl -b -R ./project1

$ ll ./project1/
total 4
drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
drwxrwx---. 1 pm1 project1  0 Dec  4 09:07 leonardo

8.7.ACL目录实例解析

8.7.1.目录ACL

切换到pm1用户,在其主目录中,基于不同的掩码创建2个子目录。

$ su - pm1

$ umask 0022
$ mkdir mydir1

$ umask 0027
$ mkdir mydir2

$ ll -d mydir*
drwxr-xr-x. 1 pm1 project1 0 Dec  4 12:30 mydir1
drwxr-x---. 1 pm1 project1 0 Dec  4 12:31 mydir2

这2个目录当前的ACL状态如下:

$ getfacl mydir1
# file: mydir1
# owner: pm1
# group: project1
user::rwx
group::r-x
other::r-x

$ getfacl mydir2
# file: mydir2
# owner: pm1
# group: project1
user::rwx
group::r-x
other::---

修改目录mydir2的ACL。

$ setfacl -m u:tm2:rwx,g:project2:rwx mydir2

$ getfacl mydir2
getfacl mydir2
# file: mydir2
# owner: pm1
# group: project1
user::rwx
user:tm2:rwx
group::r-x
group:project2:rwx
mask::rwx
other::---

$ ll -d mydir2
drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2

现在,用户tm2和组project2对目录mydir2都具有rwx权限,传统POSIX权限和ACL权限一致。

现在对mydir2目录组权限撤销w权限。 用户tm2和组project2对目录mydir2的有效权限变成了r-x。 mask也受组权限变化影响,变成了r-x

$ chmod g-w mydir2

$ ll -d mydir2
drwxr-x---+ 1 pm1 project1 0 Dec  4 12:31 mydir2

$ getfacl mydir2
# file: mydir2
# owner: pm1
# group: project1
user::rwx
user:tm2:rwx          #effective:r-x
group::r-x
group:project2:rwx    #effective:r-x
mask::r-x
other::---

通过chmodsetfacl两种不同的方法对目录mydir2的组权限进行修改,在ls命令中体现是一样的,对组的实际有效权限的影响也是一样的。

chmod修改的是maskmask只影响除所有者和other的之外的人和组的最大权限,mask需要与用户的权限进行逻辑与运算后,才能变成有效权限,用户或组的设置必须在mask权限设定范围内才会生效。

setfacl可以不修改mask的情况下只修改owning group的权限,下面的例子说明了这一情况。POSIX组权限仍然是rwx,但ACL中所有者组的权限变成了r--

$ setfacl -m g::r mydir2

$ ll -d mydir2
drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2

$ getfacl mydir2
# file: mydir2
# owner: pm1
# group: project1
user::rwx
user:tm2:rwx
group::r--
group:project2:rwx
mask::rwx
other::---

8.7.2.目录的默认ACL

目录可以具有默认ACL,这是一种特殊的ACL,用于定义目录下的对象在创建时继承的访问权限。默认ACL会影响子目录和文件。

目录的默认ACL的权限有两种不同的方式传递给其中的文件和子目录:

  • 子目录继承父目录的默认ACL,既作为自己的默认ACL,又作为自己的访问ACL。
  • 文件继承目录默认ACL作为其自己的访问ACL。

创建文件系统对象的所有系统函数都使用mode参数,该参数定义了新创建的文件系统对象的访问权限。

  • 如果父目录没有默认ACL,则根据umask的设置设置权限位。
  • 如果父目录存在默认ACL,则分配给新对象的权限位则是mode参数权限与默认ACL中定义的权限的逻辑与的结果。在这种情况下,忽略umask命令。
  • 默认ACL不会立即影响访问权限。它们仅在创建文件系统对象时才起作用。这些新对象仅从其父目录的默认ACL继承权限。
  • 命令mkdir在创建目录时会继承默认ACL。
$ su - pm1

$ getfacl mydir2
# file: mydir2
# owner: pm1
# group: project1
user::rwx
user:tm2:rwx
group::r--
group:project2:rwx
mask::rwx
other::---

$ mkdir ./mydir2/sub1

$ ll ./mydir2
drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1

$ setfacl -d -m g:project2:-w- mydir2

$ mkdir ./mydir2/sub2

$ ll ./mydir2
drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1
drwxrw----+ 1 pm1 project1 0 Dec  4 13:27 sub2

$ getfacl ./mydir2/sub2
# file: mydir2/sub2
# owner: pm1
# group: project1
user::rwx
group::r--
group:project2:-w-
mask::rw-
other::---
default:user::rwx
default:group::r--
default:group:project2:-w-
default:mask::rw-
default:other::---

在对mydir2目录添加默认ACL前,创建子目录sub1,添加后创建子目录sub2。可以观察到sub2到继承了mydir2的默认ACL。

$ su - tm2

$ cd /home/pm1/mydir2/sub2
-bash: cd: /home/pm1/mydir2/sub2: Permission denied

上例中,默认ACL中指定组project2只具有w权限,所以无法执行cd命令进入该目录。 这说明模式值mode中给予的权限r被屏蔽了,只保留了ACL中最小的权限w

8.8.ACL检查逻辑

ACL检查顺序:

  • Owner
  • Named user
  • Owning group
  • Named group
  • Other
If
 进程的用户标识是Owner,则owner的ACL条目决定访问权限
else if
 进程的用户标识是named user,则name user的ACL条目的权限决定申请的访问权限
else if
 进程的组属于owning group,且owning group的ACL条目包含所请求的访问权限,则授予所请求的权限
else if
 进程的组属于named group,且named group的ACL条目包含所请求的访问权限,则授予所请求的权限
else if
 进程的组属于owning group或者named group,但owning group或者named group的ACL条目不包含所请求的访问权限,则拒绝所请求的权限
else
 ACL中的other条目处理申请的权限
If
 如果进程匹配到owner或者other条目中包含所申请的权限,则授予权限
else if
 如果进程匹配到named user,owning group,或者named group条目中包含所申请的权限,且maks条目也包含所申请的权限,则授予权限
else
 拒绝权限申请

实际应用举例:

  • udev使用ACL给予登录到图形界面的用户访问设备的权限,例如DVD驱动器
  • 某些应用程序不支持ACL
  • Star Archiver是一个完全保留ACL的备份应用程序,其他人可能会也可能不会保留它
  • 许多编辑器和文件管理器不允许在应用程序中查看或设置ACL