初识Linux(十)------ Linux 帐号管理与 ACL 权限设置

  要登陆 Linux 系统一定要有帐号与密码,不同的使用者应该要拥有不同的权限。我们还可以通过 user/group 的特殊权限设置, 来规范出不同的群组开发。在 Linux 的环境下,可以通过很多方式来限制使用者能够使用的系统资源, 包括 bash 的 ulimit 限制、还有特殊权限限制,如 umask 等等。 通过这些举动,我们可以规范出不同使用者的使用资源。另外,还记得系统管理员的帐号root 吗?除了 root 之外,是否可以有其他的系统管理员帐号? 为什么大家都要尽量避免使用数字形态的帐号?如何修改使用者相关的信息呢?这就是下面讲的内容了。

1. Linux 的帐号与群组

   在管理 Linux 主机的帐号时,我们必须先来了解一下 Linux 到底是如何辨别每一个使用者的。

1.1 使用者识别码: UID 与 GID

  虽然我们登陆 Linux 主机的时候,输入的是我们的帐号,但是其实 Linux 主机并不会直接认识你的“帐号名称”的,他仅认识 ID  (ID 就是一组号码)。 由于计算机仅认识 0 与 1,所以主机对于数字比较有概念的;至于帐号只是为了让人们容易记忆而已。 而你的 ID 与帐号的对应就在 /etc/passwd 当中。

  那么到底有几种 ID 呢?在之前有提到过, 每一个文件都具有“拥有人与拥有群组”的属性吗?没错~每个登陆的使用者至少都会取得两个 ID ,一个是使用者 ID (User ID ,简称 UID)、一个是群组 ID (Group ID ,简称 GID)。

  每一个文件都会有所谓的拥有者 ID 与拥有群组 ID ,当有要显示文件属性的需求时,系统会依据 /etc/passwd 与 /etc/group 的内容, 找到 UID / GID 对应的帐号与群组名称再显示出来。

  可以作个小实验,可以用 root 的身份 vim /etc/passwd ,然后将你的一般身份的使用者的 ID 随便改一个号码,然后再到你的一般身份的目录下看看原先该帐号拥有的文件,你会发现该文件的拥有人变成了 “数字了”。

# 1. 先查看一下,系统里面有没有一个名为 dmtsai 的用户?
[root@study ~]# id dmtsai
uid=1000(dmtsai) gid=1000(dmtsai) groups=1000(dmtsai),10(wheel)  <==确定有这个帐号

[root@study ~]# ll -d /home/dmtsai
drwx------. 17 dmtsai dmtsai 4096 Jul 17 19:51 /home/dmtsai
# 使用者的字段正是 dmtsai 本身

# 2. 修改一下,将刚刚我们的 dmtsai 的 1000 UID 改为 2000 看看:
[root@study ~]# vim /etc/passwd
....(前面省略)....
dmtsai:x:2000:1000:dmtsai:/home/dmtsai:/bin/bash <==修改一下特殊字体部分,由 1000 改过来
[root@study ~]# ll -d /home/dmtsai
drwx------. 17 1000 dmtsai 4096 Jul 17 19:51 /home/dmtsai
# 变成 1000 了,因为文件只会记录 UID 的数字而已
# 因为我们乱改,所以导致 1000 找不到对应的帐号,因此显示数字!

# 3. 记得将刚刚的 2000 改回来!
[root@study ~]# vim /etc/passwd
....(前面省略)....
dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash  <==务必一定要改回来!

  上面的例子仅是在说明 UID 与帐号的对应性,在一部正常运行的 Linux 主机环境下,上面的动作不可随便进行, 这是因为系统上已经有很多的数据被创建存在了,随意修改系统上某些帐号的 UID 很可能会导致某些程序无法进行,这将导致系统无法顺利运行的结果, 因为权限问题。

1.2 使用者帐号

  Linux 系统上面的使用者如果需要登陆主机以取得 shell 的环境来工作时,他需要如何进行呢? 首先,他必须要在计算机前面利用 tty1~tty6 的终端机提供的 login 接口,并输入帐号与密码后才能够登陆。 如果是通过网络的话,那至少使用者就得要学习 ssh 这个功能了 。 那么你输入帐号密码后,系统帮你处理了什么呢?

  1. 先找寻 /etc/passwd 里面是否有你输入的帐号?如果没有则跳出,如果有的话则将该帐号对应的 UID 与 GID (在 /etc/group 中) 读出来,另外,该帐号的主文件夹与 shell 设置也一并读出;
  2. 再来则是核对密码表,这时 Linux 会进入 /etc/shadow 里面找出对应的帐号与 UID,然后核对一下你刚刚输入的密码与里面的密码是否相符;
  3. 如果一切都 OK 的话,就进入 Shell 控管的阶段。

  由上面的流程我们也知道,跟使用者帐号有关的有两个非常重要的文件,一个是管理使用者 UID/GID 重要参数的 /etc/passwd ,一个则是专门管理密码相关数据的 /etc/shadow 。那这两个文件的内容就非常值得进行研究,下面我们会简单的介绍这两个文件,详细的说明可以参考 man 5 passwd 及 man 5 shadow 。


/etc/passwd 文件结构

  这个文件的构造是这样的:每一行都代表一个帐号,有几行就代表有几个帐号在你的系统中。不过需要特别留意的是,里面很多帐号本来就是系统正常运行所必须要的,我们可以简称他为系统帐号, 例如 bin, daemon, adm, nobody 等等,这些帐号请不要随意的删掉,这个文件的内容有点像这样:

[root@study ~]# head -n 4 /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

  每个 Linux 系统都会有的第一行,就是 root 这个系统管理员那一行, 可以明显的看出来,每一行使用“:”分隔开,共有七个,分别是:

1. 帐号名称
  就是帐号,用来提供给对数字不太敏感的人类使用来登陆系统的,需要用来对应 UID 。例如 root 的 UID 对应就是 0 (第三字段);

2. 密码
  早期 Unix 系统的密码就是放在这字段上!但是因为这个文件的特性是所有的程序都能够读取,这样一来很容易造成密码数据被窃取, 因此后来就将这个字段的密码数据改放到 /etc/shadow 中了,所以这里你会看到一个“ x ”。

3. UID
  这个就是使用者识别码,通常 Linux 对于 UID 有几个限制:

4. GID

  这个与 /etc/group 有关,其实 /etc/group 与 /etc/passwd 差不多,只是他是用来规范群组名称与 GID 的对应而已。

5. 使用者信息说明栏

  这个字段基本上并没有什么重要用途,只是用来解释这个帐号的意义而已。不过,如果使用 finger 的功能时, 这个字段可以提供很多的信息。

6. 主文件夹

  这是使用者的主文件夹,以上面为例, root 的主文件夹在 /root ,所以当 root 登陆之后,就会立刻跑到 /root 目录。如果你有个帐号的使用空间特别的大,你想要将该帐号的主文件夹移动到其他的硬盘去该怎么作? 可以在这个字段进行修改,默认的使用者主文件夹在 /home/【yourIDname】。

7. Shell

  我们在 BASH 这一章提到很多次,当使用者登陆系统后就会取得一个 Shell 来与系统的核心沟通以进行使用者的操作任务。那为何默认 shell 会使用 bash 呢?就是在这个字段指定的。这里比较需要注意的是,有一个 shell 可以用来替代成让帐号无法取得 shell 环境的登陆动作,那就是 /sbin/nologin 。


/etc/shadow 文件结构

  我们知道很多程序的运行都与权限有关,而权限与 UID/GID 有关。因此各程序当然需要读取 /etc/passwd 来了解不同帐号的权限。 因此 /etc/passwd 的权限需设置为 -rw-r--r-- 这样的情况, 虽然早期的密码也有加密过,但却放置到 /etc/passwd 的第二个字段上,这样一来很容易被有心人士所窃取的, 加密过的密码也能够通过暴力破解法去 trial and error (试误) 找出来。

  因为这样的关系,所以后来发展出将密码移动到 /etc/shadow 这个文件分隔开来的技术, 而且还加入很多的密码限制参数在 /etc/shadow 里面。/etc/shadow 文件有点像这样:

[root@study ~]# head -n 4 /etc/shadow
root:$6$wtbCCce/PxMeE5wm$KE2IfSJr.YLP7Rcai6oa/T7KFhO...:16559:0:99999:7:::  <==下面说明用
bin:*:16372:0:99999:7:::
daemon:*:16372:0:99999:7:::
adm:*:16372:0:99999:7:::

  基本上, shadow 同样以“:”作为分隔符号,共有九个字段,这九个字段的用途是这样的:

1. 帐号名称
  由于密码也需要与帐号对应~因此,这个文件的第一栏就是帐号,必须要与 /etc/passwd 相同才行。

2. 密码

  这个字段内的数据才是真正的密码,而且是经过编码的密码 (加密) 。 只能看到有一些特殊符号的字母,需要特别留意的是,虽然这些加密过的密码很难被解出来, 但是“很难”不等于“不会”,所以,这个文件的默认权限是“-rw-------”或者是“----------”,只有 root 才可以读写。你得随时注意,不要不小心更改了这个文件的权限。

  另外,由于各种密码编码的技术不一样,因此不同的编码系统会造成这个字段的长度不相同。 举例来说,旧式的 DES, MD5 编码系统产生的密码长度就与目前惯用的 SHA 不同。SHA 的密码长度明显的比较长些。由于固定的编码系统产生的密码长度必须一致,因此“当你让这个字段的长度改变后,该密码就会失效(算不出来)”。 很多软件通过这个功能,在此字段前加上 ! 或 * 改变密码字段长度,就会让密码“暂时失效”了。 

3. 最近变更密码的日期

  这个字段记录了“更动密码那一天”的日期,不过,很奇怪,在我的例子中怎么会是 16559 呢?这个是因为计算 Linux 日期的时间是以 1970 年 1 月 1 日作为 1 而累加的日期,1971 年 1 月 1 日则为 366 。上述的 16559 指的就是 2015-05-04 那一天,想要了解该日期可以使用本章后面 chage 指令的帮忙,至于想要知道某个日期的累积日数, 可使用如下的程序计算:

[root@study ~]# echo $(($(date --date="2015/05/04" +%s)/86400+1))
16559

  上述指令中,2015/05/04 为你想要计算的日期,86400 为每一天的秒数, %s 为 1970/01/01 以来的累积总秒数。 由于 bash 仅支持整数,因此最终需要加上 1 补齐 1970/01/01 当天。

4. 密码不可被变更的天数(与第 3 字段相比)

  第四个字段记录了:这个帐号的密码在最近一次被更改后需要经过几天才可以再被变更!如果是 0 的话, 表示密码随时可以更动的意思。这的限制是为了怕密码被某些人一改再改而设计的。如果设置为 20 天的话,那么当你设置了密码之后, 20 天之内都无法改变这个密码。

5. 密码需要重新变更的天数(与第 3 字段相比)

  为了强制要求使用者变更密码,这个字段可以指定在最近一次更改密码后, 在多少天数内需要再次的变更密码才行。你必须要在这个天数内重新设置你的密码,否则这个帐号的密码将会“变为过期特性”。 而如果像上面的 99999 (计算为 273 年) 的话,那就表示,密码的变更没有强制性之意。

6. 密码需要变更期限前的警告天数:(与第 5 字段相比)

  当帐号的密码有效期限快要到的时候,系统会依据这个字段的设置,发出“警告”给这个帐号,提醒他“再过 n 天你的密码就要过期了,请尽快重新设置你的密码!”,如上面的例子,则是密码到期之前的 7 天之内,系统会警告该用户。

7. 密码过期后的帐号宽限时间(密码失效日)(与第 5 字段相比)

  密码有效日期为“更新日期(第3字段)”+“重新变更日期(第5字段)”,过了该期限后使用者依旧没有更新密码,那该密码就算过期了。 虽然密码过期但是该帐号还是可以用来进行其他工作的,包括登陆系统取得 bash 。不过如果密码过期了, 那当你登陆系统时,系统会强制要求你必须要重新设置密码才能登陆继续使用,这就是密码过期特性。

  那这个字段的功能是什么呢?是在密码过期几天后,如果使用者还是没有登陆更改密码,那么这个帐号的密码将会“失效”, 亦即该帐号再也无法使用该密码登陆了。要注意密码过期与密码失效并不相同。

8. 帐号失效日期

  这个日期跟第三个字段一样,都是使用 1970 年以来的总日数设置。这个字段表示: 这个帐号在此字段规定的日期之后,将无法再使用。 就是所谓的“帐号失效”,此时不论你的密码是否有过期,这个“帐号”都不能再被使用! 这个字段会被使用通常应该是在“收费服务”的系统中,你可以规定一个日期让该帐号不能再使用。

9. 保留

  最后一个字段是保留的,看以后有没有新功能加入。

  由于 shadow 有这样的重要性,因此可不能随意修改。但在某些情况下面你得要使用各种方法来处理这个文件的。举例来说,常常听到人家说:“我的密码忘记了”, 或者是“我的密码不晓得被谁改过,跟原先的不一样了”,这个时候怎么办?

  • 一般用户的密码忘记了:这个最容易解决,请系统管理员帮忙, 他会重新设置好你的密码而不需要知道你的旧密码,利用 root 的身份使用 passwd 指令来处理即可。
  • root 密码忘记了:这就麻烦了!因为你无法使用 root 的身份登陆了。但我们知道 root 的密码在 /etc/shadow 当中,因此你可以使用各种可行的方法开机进入 Linux 再去修改。 例如重新开机进入单人维护模式后,系统会主动的给予 root 权限的 bash 接口, 此时再以 passwd 修改密码即可;或以 Live CD 开机后挂载根目录去修改 /etc/shadow,将里面的 root 的密码字段清空, 再重新开机后 root 将不用密码即可登陆!登陆后再赶快以 passwd 指令去设置 root 密码即可。

  另外,由于 Linux 的新旧版本差异颇大,旧的版本 (CentOS 5.x 以前) 还活在很多服务器内。因此,如果你想要知道 shadow 是使用哪种加密的机制时, 可以通过下面的方法去查询:

[root@study ~]# authconfig --test | grep hashing
 password hashing algorithm is sha512
# 这就是目前的密码加密机制

1.3 关于群组: 有效与初始群组、groups, newgrp

  认识了帐号相关的两个文件 /etc/passwd 与 /etc/shadow 之后,你或许还是会觉得奇怪, 那么群组的配置文件在哪里?还有,在 /etc/passwd 的第四栏不是所谓的 GID 吗?那又是啥? 此时就需要了解 /etc/group 与 /etc/gshadow。


/etc/group 文件结构

/etc/group 内容有点像这样:

[root@study ~]# head -n 4 /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:

  这个文件每一行代表一个群组,也是以冒号“:”作为字段的分隔符号,共分为四栏,每一字段的意义是:

1. 群组名称
 就是群组名称,同样用来给人类使用的,基本上需要与第三字段的 GID 对应。

2. 群组密码
 通常不需要设置,这个设置通常是给“群组管理员”使用的,目前很少有这个机会设置群组管理员。同样的,密码已经移动到 /etc/gshadow 去,因此这个字段只会存在一个“x”而已;

3. GID
 就是群组的 ID ,/etc/passwd 第四个字段使用的 GID 对应的群组名,就是由这里对应出来的。

4. 此群组支持的帐号名称:
    一个帐号可以加入多个群组,那某个帐号想要加入此群组时,将该帐号填入这个字段即可。 举例来说,如果我想要让 dmtsai 与 alex 也加入 root 这个群组,那么在第一行的最后面加上“dmtsai,alex”,注意不要有空格, 使成为“ root:x:0:dmtsai,alex ”就可以。

帐号相关文件之间的 UID/GID 与密码相关性示意图

帐号相关文件之间的 UID/GID 与密码相关性示意图


有效群组(effective group)与初始群组(initial group)

  还记得每个使用者在他的 /etc/passwd 里面的第四栏有所谓的 GID 吧?那个 GID 就是所谓的“初始群组 (initial group) ”!也就是说,当使用者一登陆系统,立刻就拥有这个群组的相关权限的意思。 举例来说,我们上面提到 dmtsai 这个使用者的 /etc/passwd 与 /etc/group 还有 /etc/gshadow 相关的内容如下:

[root@study ~]# usermod -a -G users dmtsai  <==先设置好次要群组
[root@study ~]# grep dmtsai /etc/passwd /etc/group /etc/gshadow
/etc/passwd:dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
/etc/group:wheel:x:10:dmtsai    <==次要群组的设置、安装时指定的
/etc/group:users:x:100:dmtsai   <==次要群组的设置
/etc/group:dmtsai:x:1000:       <==因为是初始群组,所以第四字段不需要填入帐号
/etc/gshadow:wheel:::dmtsai     <==次要群组的设置
/etc/gshadow:users:::dmtsai     <==次要群组的设置
/etc/gshadow:dmtsai:!!::

  仔细看到上面,在 /etc/passwd 里面,dmtsai 这个使用者所属的群组为 GID=1000 ,搜索一下 /etc/group 得到 1000 是那个名为 dmtsai 的群组,这就是 initial group。因为是初始群组, 使用者一登陆就会主动取得,不需要在 /etc/group 的第四个字段写入该帐号。

  但是非 initial group 的其他群组可就不同了。举上面这个例子来说,我将 dmtsai 加入 users 这个群组当中,由于 users 这个群组并非是 dmtsai 的初始群组,因此, 我必须要在 /etc/group 这个文件中,找到 users 那一行,并且将 dmtsai 这个帐号加入第四栏, 这样 dmtsai 才能够加入 users 这个群组。

  在这个例子当中,因为 dmtsai 帐号同时支持 dmtsai, wheel 与 users 这三个群组, 因此,在读取/写入/可执行文件时,针对群组部分,只要是 users, wheel 与 dmtsai 这三个群组拥有的功能,  dmtsai 这个使用者都能够拥有。不过,这是针对已经存在的文件而言, 如果今天我要创建一个新的文件或者是新的目录,请问一下,新文件的群组是 dmtsai, wheel 还是 users ?这就得要检查一下当时的有效群组了 (effective group)。

groups: 有效与支持群组的观察

  如果以 dmtsai 这个使用者的身份登陆后,该如何知道所有支持的群组呢? 很简单,直接输入 groups 就可以了。

[dmtsai@study ~]$ groups
dmtsai wheel users

  在这个输出的信息中,可知道 dmtsai 这个用户同时属于 dmtsai, wheel 及 users 这三个群组,而且, 第一个输出的群组即为有效群组 (effective group) 了。 也就是说,有效群组为 dmtsai ~此时,如果以 touch 去创建一个新文件,例如: “ touch test ”,那么这个文件的拥有者为 dmtsai ,而且群组也是 dmtsai 。

[dmtsai@study ~]$ touch test
[dmtsai@study ~]$ ll test
-rw-rw-r--. 1 dmtsai dmtsai 0 Jul 20 19:54 test

  这样是否可以了解什么是有效群组了?通常有效群组的作用是在新建文件。那么有效群组是否能够变更?

newgrp: 有效群组的切换

  那么如何变更有效群组呢?就使用 newgrp ,不过使用 newgrp 是有限制的,那就是你想要切换的群组必须是你已经有支持的群组。举例来说, dmtsai 可以在 dmtsai/wheel/users 这三个群组间切换有效群组,但是 dmtsai 无法切换有效群组成为 sshd 。使用的方式如下:

[dmtsai@study ~]$ newgrp users
[dmtsai@study ~]$ groups
users wheel dmtsai
[dmtsai@study ~]$ touch test2
[dmtsai@study ~]$ ll test*
-rw-rw-r--. 1 dmtsai dmtsai 0 Jul 20 19:54 test
-rw-r--r--. 1 dmtsai users  0 Jul 20 19:56 test2
[dmtsai@study ~]$ exit   # 注意!记得离开 newgrp 的环境!

   此时,dmtsai 的有效群组就成为 users 了。我们额外的来讨论一下 newgrp 这个指令,这个指令可以变更目前使用者的有效群组, 而且是另外以一个 shell 来提供这个功能,所以,以上面的例子来说, dmtsai 这个使用者目前是以另一个 shell 登陆的,而且新的 shell 给予 dmtsai 有效 GID 为 users 。如下图所示:

newgrp 的运行示意图

  虽然使用者的环境设置(例如环境变量等等其他数据)不会有影响,但是使用者的“群组权限”将会重新被计算。 但是需要注意,由于是新取得一个 shell ,因此如果你想要回到原本的环境中,请输入 exit 回到原本的 shell 。

  那么如何让一个帐号加入不同的群组。你要加入一个群组有两个方式,一个是通过系统管理员 (root) 利用 usermod 帮你加入,如果 root 太忙了而且你的系统有设置群组管理员,那么你可以通过群组管理员以 gpasswd 帮你加入他所管理的群组中。


/etc/gshadow

  刚刚讲了很多关于“有效群组”的概念,另外,也提到 newgrp 这个指令的用法,但是,如果 /etc/gshadow 这个设置没有搞懂得话,那么 newgrp 是无法动作的。 /etc/gshadow 的内容有点像这样:

[root@study ~]# head -n 4 /etc/gshadow
root:::
bin:::
daemon:::
sys:::

  这个文件内同样还是使用冒号“:”来作为字段的分隔字符,而且你会发现,这个文件几乎与 /etc/group 一模一样~不过,要注意的大概就是第二个字段~第二个字段是密码栏, 如果密码栏上面是“!”或空的时,表示该群组不具有群组管理员!至于第四个字段也就是支持的帐号名称~ 这四个字段的意义为:

1. 群组名称;
2. 密码栏,同样的,开头为 ! 表示无合法密码,所以无群组管理员;
3. 群组管理员的帐号 (相关信息在 gpasswd 中介绍);
4. 有加入该群组支持的所属帐号 (与 /etc/group 内容相同)。

  以系统管理员的角度来说,这个 gshadow 最大的功能就是创建群组管理员,群组管理员能够将帐号加入自己管理的群组中。

2. 帐号管理

  既然要管理帐号,当然要有新增与移除使用者的操作。

2.1 新增与移除使用者: useradd, 相关配置文件, passwd, usermod, userdel

  帐号可以使用 useradd 来新建使用者,密码的给予则使用 passwd 这个指令。这两个指令下达方法如下:


useradd

[root@study ~]$ useradd [-u UID] [-g 初始群组] [-G 次要群组] [-mM] [-c 说明栏] [-d 主文件夹绝对路径] [-s shell] 使用者帐号名
选项与参数:
-u  :后面接的是 UID ,是一组数字。直接指定一个特定的 UID 给这个帐号;
-g  :后面接的那个群组名称就是我们上面提到的 initial group 啦~
      该群组的 GID 会被放置到 /etc/passwd 的第四个字段内。
-G  :后面接的群组名称则是这个帐号还可以加入的群组。
      这个选项与参数会修改 /etc/group 内的相关数据喔!
-M  :强制!不要创建使用者主文件夹!(系统帐号默认值)
-m  :强制!要创建使用者主文件夹!(一般帐号默认值)
-c  :这个就是 /etc/passwd 的第五栏的说明内容啦~可以随便我们设置的啦~
-d  :指定某个目录成为主文件夹,而不要使用默认值。务必使用绝对路径!
-r  :创建一个系统的帐号,这个帐号的 UID 会有限制 (参考 /etc/login.defs)
-s  :后面接一个 shell ,若没有指定则默认是 /bin/bash 的啦~
-e  :后面接一个日期,格式为“YYYY-MM-DD”此项目可写入 shadow 第八字段,
      亦即帐号失效日的设置项目啰;
-f  :后面接 shadow 的第七字段项目,指定密码是否会失效。0为立刻失效,
      -1 为永远不失效(密码只会过期而强制于登陆时重新设置而已。)

 

范例一:完全参考默认值创建一个使用者,名称为 vbird1
[root@study ~]# useradd vbird1
[root@study ~]# ll -d /home/vbird1
drwx------. 3 vbird1 vbird1 74 Jul 20 21:50 /home/vbird1
# 默认会创建使用者主文件夹,且权限为 700 !这是重点!

[root@study ~]# grep vbird1 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird1:x:1003:1004::/home/vbird1:/bin/bash
/etc/shadow:vbird1:!!:16636:0:99999:7:::
/etc/group:vbird1:x:1004:     <==默认会创建一个与帐号一模一样的群组名

  

  其实系统已经帮我们规定好非常多的默认值了,所以我们可以简单的使用“ useradd 帐号 ”来创建使用者即可。 CentOS 这些默认值主要会帮我们处理几个项目:

  • 在 /etc/passwd 里面创建一行与帐号相关的数据,包括创建 UID/GID/主文件夹等;
  • 在 /etc/shadow 里面将此帐号的密码相关参数填入,但是尚未有密码;
  • 在 /etc/group 里面加入一个与帐号名称一模一样的群组名称;
  • 在 /home 下面创建一个与帐号同名的目录作为使用者主文件夹,且权限为 700;
  • 由于在 /etc/shadow 内仅会有密码参数而不会有加密过的密码数据,因此我们在创建使用者帐号时, 还需要使用“ passwd 帐号 ”来给予密码才算是完成了使用者创建的流程。如果由于特殊需求而需要改变使用者相关参数时, 就得要通过上述useradd中的选项参数来进行创建了,参考下面的案例:
范例二:假设我已知道我的系统当中有个群组名称为 users ,且 UID 1500 并不存在,
        请用 users 为初始群组,以及 uid 为 1500 来创建一个名为 vbird2 的帐号
[root@study ~]# useradd -u 1500 -g users vbird2
[root@study ~]# ll -d /home/vbird2
drwx------. 3 vbird2 users 74 Jul 20 21:52 /home/vbird2

[root@study ~]# grep vbird2 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird2:x:1500:100::/home/vbird2:/bin/bash
/etc/shadow:vbird2:!!:16636:0:99999:7:::
# 看一下,UID 与 initial group 确实改变成我们需要的了!

   在这个范例中,我们创建的是指定一个已经存在的群组作为使用者的初始群组,因为群组已经存在, 所以在 /etc/group 里面就不会主动的创建与帐号同名的群组了! 此外,我们也指定了特殊的 UID 来作为使用者的专属 UID 。

   了解了一般帐号后,来看看系统帐号 (system account)。

范例三:创建一个系统帐号,名称为 vbird3
[root@study ~]# useradd -r vbird3
[root@study ~]# ll -d /home/vbird3
ls: cannot access /home/vbird3: No such file or directorya   <==不会主动创建主文件夹

[root@study ~]# grep vbird3 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird3:x:699:699::/home/vbird3:/bin/bash
/etc/shadow:vbird3:!!:16636::::::
/etc/group:vbird3:x:699:

  我们在谈到 UID 的时候曾经说过一般帐号应该是 1000 号以后,那使用者自己创建的系统帐号则一般是小于 1000 号以下的。 所以在这里我们加上 -r 这个选项以后,系统就会主动将帐号与帐号同名群组的 UID/GID 都指定小于 1000 以下, 在本案例中则是使用 699(UID) 与 699(GID)。此外,由于系统帐号主要是用来进行运行系统所需服务的权限设置, 所以系统帐号默认都不会主动创建主文件夹的!

  由这几个范例我们知道,使用 useradd 创建使用者帐号时,其实会更改不少地方,至少我们就知道下面几个文件:

  • 使用者帐号与密码参数方面的文件:/etc/passwd, /etc/shadow
  • 使用者群组相关方面的文件:/etc/group, /etc/gshadow
  • 使用者的主文件夹:/home/帐号名称

  你有没有想过,为何“ useradd vbird1 ”会主动在 /home/vbird1 创建起使用者的主文件夹?主文件夹内有什么数据来自哪里?为何默认使用的是 /bin/bash 这个 shell ?为何密码字段已经都规范好了 (0:99999:7 那一串)?这就得要说明一下 useradd 所使用的参考文件。


useradd 参考文件 

   useradd 的默认值可以使用下面的方法调用出来:

[root@study ~]# useradd -D
GROUP=100		<==默认的群组
HOME=/home		<==默认的主文件夹所在目录
INACTIVE=-1		<==密码失效日,在 shadow 内的第 7 栏
EXPIRE=			<==帐号失效日,在 shadow 内的第 8 栏
SHELL=/bin/bash		<==默认的 shell
SKEL=/etc/skel		<==使用者主文件夹的内容数据参考目录
CREATE_MAIL_SPOOL=yes   <==是否主动帮使用者创建邮件信箱(mailbox)

   这个数据其实是由 /etc/default/useradd 调用出来的!你可以自行用 vim 去观察该文件的内容。搭配上面刚刚谈过的范例一的运行结果,上面这些设置项目所造成的行为分别是:

  • GROUP=100:新建帐号的初始群组使用 GID 为 100

  系统上面 GID 为 100 即是 users 这个群组,此设置项目指的就是让新设使用者帐号的初始群组为 users 这一个的意思。 但是我们知道 CentOS 上面并不是这样的,在 CentOS 上面默认的群组为与帐号名相同的群组。 举例来说, vbird1 的初始群组为 vbird1 。怎么会这样啊?这是因为针对群组的角度有两种不同的机制所致, 这两种机制分别是:

  • 私有群组机制:

  系统会创建一个与帐号一样的群组给使用者作为初始群组。 这种群组的设置机制会比较有保密性,这是因为使用者都有自己的群组,而且主文件夹权限将会设置为 700 (仅有自己可进入自己的主文件夹) 之故。使用这种机制将不会参考 GROUP=100 这个设置值。代表性的 distributions 有 RHEL, Fedora, CentOS 等;

  • 公共群组机制:

  就是以 GROUP=100 这个设置值作为新建帐号的初始群组,因此每个帐号都属于 users 这个群组, 且默认主文件夹通常的权限会是“ drwxr-xr-x ... username users ... ”,由于每个帐号都属于 users 群组,因此大家都可以互相分享主文件夹内的数据之故。代表 distributions 如 SuSE等。

  由于我们的 CentOS 使用私有群组机制,因此这个设置项目是不会生效的。

  • HOME=/home:使用者主文件夹的基准目录(basedir)

  使用者的主文件夹通常是与帐号同名的目录,这个目录将会摆放在此设置值的目录后。所以 vbird1 的主文件夹就会在 /home/vbird1/ 。

  • INACTIVE=-1:密码过期后是否会失效的设置值

  我们在 shadow 文件结构当中谈过,第七个字段的设置值将会影响到密码过期后, 在多久时间内还可使用旧密码登陆。这个项目就是在指定该日数。如果是 0 代表密码过期立刻失效, 如果是 -1 则是代表密码永远不会失效,如果是数字,如 30 ,则代表过期 30 天后才失效。

  • EXPIRE=:帐号失效的日期

  就是 shadow 内的第八字段,你可以直接设置帐号在哪个日期后就直接失效,而不理会密码的问题。 通常不会设置此项目,但如果是付费的会员制系统,或许这个字段可以设置。

  • SHELL=/bin/bash:默认使用的 shell 程序文件名

  系统默认的 shell 就写在这里。假如你的系统为 mail server ,你希望每个帐号都只能使用 email 的收发信件功能, 而不许使用者登陆系统取得 shell ,那么可以将这里设置为 /sbin/nologin ,如此一来,新建的使用者默认就无法登陆, 也免去后续使用 usermod 进行修改的操作!

  • SKEL=/etc/skel:使用者主文件夹参考基准目录

  指定使用者主文件夹的参考基准目录。以我们的范例一为例, vbird1 主文件夹 /home/vbird1 内的各项数据,都是由 /etc/skel 所复制过去的~所以呢,未来如果我想要让新增使用者时,该使用者的环境变量 ~/.bashrc 就设置妥当的话,可以到 /etc/skel/.bashrc 去编辑一下,也可以创建 /etc/skel/www 这个目录,那么未来新增使用者后,在他的主文件夹下就会有 www 那个目录了。

  • CREATE_MAIL_SPOOL=yes:创建使用者的 mailbox

  你可以使用“ ll /var/spool/mail/vbird1 ”看一下,会发现有这个文件的存在,这就是使用者的邮件信箱。

  除了这些基本的帐号设置值之外, UID/GID 还有密码参数又是在哪里参考的呢?那就得要看一下 /etc/login.defs 啦! 这个文件的内容有点像下面这样:

MAIL_DIR        /var/spool/mail  <==使用者默认邮件信箱放置目录

PASS_MAX_DAYS   99999    <==/etc/shadow 内的第 5 栏,多久需变更密码日数
PASS_MIN_DAYS   0        <==/etc/shadow 内的第 4 栏,多久不可重新设置密码日数
PASS_MIN_LEN    5        <==密码最短的字符长度,已被 pam 模块取代,失去效用!
PASS_WARN_AGE   7        <==/etc/shadow 内的第 6 栏,过期前会警告的日数

UID_MIN          1000    <==使用者最小的 UID,意即小于 1000 的 UID 为系统保留
UID_MAX         60000    <==使用者能够用的最大 UID
SYS_UID_MIN       201    <==保留给使用者自行设置的系统帐号最小值 UID
SYS_UID_MAX       999    <==保留给使用者自行设置的系统帐号最大值 UID
GID_MIN          1000    <==使用者自订群组的最小 GID,小于 1000 为系统保留
GID_MAX         60000    <==使用者自订群组的最大 GID
SYS_GID_MIN       201    <==保留给使用者自行设置的系统帐号最小值 GID
SYS_GID_MAX       999    <==保留给使用者自行设置的系统帐号最大值 GID

CREATE_HOME     yes      <==在不加 -M 及 -m 时,是否主动创建使用者主文件夹?
UMASK           077      <==使用者主文件夹创建的 umask ,因此权限会是 700
USERGROUPS_ENAB yes      <==使用 userdel 删除时,是否会删除初始群组
ENCRYPT_METHOD SHA512    <==密码加密的机制使用的是 sha512 这一个机制!

  这个文件规范的数据则是如下所示:

  • mailbox 所在目录:

  使用者的默认 mailbox 文件放置的目录在 /var/spool/mail,所以 vbird1 的 mailbox 就是在 /var/spool/mail/vbird1 。

  • shadow 密码第 4, 5, 6 字段内容:

  通过 PASS_MAX_DAYS 等等设置值来指定的!所以你知道为何默认的 /etc/shadow 内每一行都会有“ 0:99999:7 ”的存在了吗?^_^!不过要注意的是,由于目前我们登陆时改用 PAM 模块来进行密码检验,所以那个 PASS_MIN_LEN 是失效的。

  • UID/GID 指定数值:

  虽然 Linux 核心支持的帐号可高达 232 这么多个,不过一部主机要作出这么多帐号在管理上也是很麻烦的! 所以在这里就针对 UID/GID 的范围进行规范就是了。上表中的 UID_MIN 指的就是可登陆系统的一般帐号的最小 UID ,至于 UID_MAX 则是最大 UID 之意。

  要注意的是,系统给予一个帐号 UID 时,他是 (1)先参考 UID_MIN 设置值取得最小数值; (2)由 /etc/passwd 搜寻最大的 UID 数值, 将 (1) 与 (2) 相比,找出最大的那个再加一就是新帐号的 UID 了。我们上面已经作出 UID 为 1500 的 vbird2 , 如果再使用“ useradd vbird4 ”时,你猜 vbird4 的 UID 会是多少?答案是: 1501 。 所以中间的 1004~1499 的号码就空下来啦!

  而如果想要创建系统用的帐号,所以使用 useradd -r sysaccount 这个 -r 的选项时,就会找“比 201 大但比 1000 小的最大的 UID ”。

  • 使用者主文件夹设置值:

  为何我们系统默认会帮使用者创建主文件夹?就是这个“CREATE_HOME = yes”的设置值啦!这个设置值会让你在使用 useradd 时, 主动加入“ -m ”这个产生主文件夹的选项。如果不想要创建使用者主文件夹,就只能强制加上“ -M ”的选项在 useradd 指令执行时。至于创建主文件夹的权限设置呢?就通过 umask 这个设置值。因为是 077 的默认设置,因此使用者主文件夹默认权限才会是“ drwx------ ”

  • 使用者删除与密码设置值:

  使用“USERGROUPS_ENAB yes”这个设置值的功能是: 如果使用 userdel 去删除一个帐号时,且该帐号所属的初始群组已经没有人隶属于该群组了, 那么就删除掉该群组,举例来说,我们刚刚有创建 vbird4 这个帐号,他会主动创建 vbird4 这个群组。 若 vbird4 这个群组并没有其他帐号将他加入支持的情况下,若使用 userdel vbird4 时,该群组也会被删除的意思。 至于“ENCRYPT_METHOD SHA512”则表示使用 SHA512 来加密密码明文,而不使用旧式的 MD5。

  现在我们知道,使用 useradd 这支程序在创建 Linux 上的帐号时,至少会参考:

  • /etc/default/useradd
  • /etc/login.defs
  • /etc/skel/*

  这些文件,不过,最重要的其实是创建 /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow 还有使用者主文件夹就是了~所以,如果你了解整个系统运行的状态,也是可以手动直接修改这几个文件。OK!帐号创建了,接下来处理一下使用者的密码。


passwd

  刚刚我们讲到了,使用 useradd 创建了帐号之后,在默认的情况下,该帐号是暂时被封锁的, 也就是说,该帐号是无法登陆的,你可以去看看 /etc/shadow 内的第二个字段就知道了~ 那该如何是好?直接给他设置新密码就好了,设置密码使用 passwd。

[root@study ~]# passwd [--stdin] [帐号名称]  <==所有人均可使用来改自己的密码
[root@study ~]# passwd [-l] [-u] [--stdin] [-S] \
>  [-n 日数] [-x 日数] [-w 日数] [-i 日期] 帐号 <==root 功能
选项与参数:
--stdin :可以通过来自前一个管线的数据,作为密码输入,对 shell script 有帮助!
-l  :是 Lock 的意思,会将 /etc/shadow 第二栏最前面加上 ! 使密码失效;
-u  :与 -l 相对,是 Unlock 的意思!
-S  :列出密码相关参数,亦即 shadow 文件内的大部分信息。
-n  :后面接天数,shadow 的第 4 字段,多久不可修改密码天数
-x  :后面接天数,shadow 的第 5 字段,多久内必须要更动密码
-w  :后面接天数,shadow 的第 6 字段,密码过期前的警告天数
-i  :后面接“日期”,shadow 的第 7 字段,密码失效日期
范例一:请 root 给予 vbird2 密码
[root@study ~]# passwd vbird2
Changing password for user vbird2.
New UNIX password: <==这里直接输入新的密码,屏幕不会有任何反应
BAD PASSWORD: The password is shorter than 8 characters <==密码太简单或过短的错误!
Retype new UNIX password:  <==再输入一次同样的密码
passwd: all authentication tokens updated successfully.  <==竟然还是成功修改了!

  当我们要给予使用者密码时,通过 root 来设置即可。 root 可以设置各式各样的密码,系统几乎一定会接受!所以,如同上面的范例一,明明输入的密码太短了, 但是系统依旧可接受 vbird2 这样的密码设置。这个是 root 帮忙设置的结果,那如果是使用者自己要改密码呢? 包括 root 也是这样修改的。

范例二:用 vbird2 登陆后,修改 vbird2 自己的密码
[vbird2@study ~]$ passwd   <==后面没有加帐号,就是改自己的密码!
Changing password for user vbird2.
Changing password for vbird2
(current) UNIX password: <==这里输入“原有的旧密码”
New UNIX password: <==这里输入新密码
BAD PASSWORD: The password is shorter than 8 characters <==密码太短!不可以设置!重新想
New password:  <==这里输入新想的密码
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
# 同样的,密码设置在字典里面找的到该字串,所以也是不建议!无法通过,再想新的!
New UNIX password: <==这里再想个新的密码来输入吧
Retype new UNIX password: <==通过密码验证!所以重复这个密码的输入
passwd: all authentication tokens updated successfully. <==有无成功看关键字

  passwd 的使用要注意,尤其是 root ,passwd后面没有跟账户名,是在修改自己当前账户的密码。

  与 root 不同的是,一般帐号在更改密码时需要先输入自己的旧密码 (亦即 current 那一行),然后再输入新密码 (New 那一行)。 要注意的是,密码的规范是非常严格的,尤其新的 distributions 大多使用 PAM 模块来进行密码的检验,包括太短、 密码与帐号相同、密码为字典常见字串等,都会被 PAM 模块检查出来而拒绝修改密码,此时会再重复出现“ New ”这个关键字! 那时请再想个新密码!若出现“ Retype ”才是你的密码被接受了!重复输入新密码并且看到“ successfully ”这个关键字时才是修改密码成功。

   与一般使用者不同的是, root 并不需要知道旧密码就能够帮使用者或 root 自己创建新密码!

  新的 distributions 是使用较严格的 PAM 模块来管理密码,这个管理的机制写在 /etc/pam.d/passwd 当中。而该文件与密码有关的测试模块就是使用:pam_cracklib.so,这个模块会检验密码相关的信息, 并且取代 /etc/login.defs 内的 PASS_MIN_LEN 的设置啦!关于 PAM 我们在本章后面继续介绍,这里先谈一下, 理论上,你的密码最好符合如下要求:

  • 密码不能与帐号相同;
  • 密码尽量不要选用字典里面会出现的字串;
  • 密码需要超过 8 个字符;
  • 密码不要使用个人信息,如身份证、手机号码、其他电话号码等;
  • 密码不要使用简单的关系式,如 1+1=2, Iamvbird 等;
  • 密码尽量使用大小写字符、数字、特殊字符($,_,-等)的组合。

  为了方便系统管理,新版的 passwd 还加入了很多创意选项,比如“ --stdin ”了! 举例来说,你想要帮 vbird2 变更密码成为 abc543CC ,可以这样下达指令:

范例三:使用 standard input 创建用户的密码
[root@study ~]# echo "abc543CC" | passwd --stdin vbird2
Changing password for user vbird2.
passwd: all authentication tokens updated successfully.

  这个动作会直接更新使用者的密码而不用再次的手动输入!好处是方便处理,缺点是这个密码会保留在指令中, 未来若系统被攻破,人家可以在 /root/.bash_history 找到这个密码。所以这个动作通常仅用在 shell script 的大量创建使用者帐号当中。要注意的是,这个选项并不存在所有 distributions 版本中, 请使用 man passwd 确认你的 distribution 是否有支持此选项。

   如果你想要让 vbird2 的密码具有相当的规则,举例来说你要让 vbird2 每 60 天需要变更密码, 密码过期后 10 天未使用就宣告帐号失效,那该如何处理?

范例四:管理 vbird2 的密码使具有 60 天变更、密码过期 10 天后帐号失效的设置
[root@study ~]# passwd -S vbird2
vbird2 PS 2015-07-20 0 99999 7 -1 (Password set, SHA512 crypt.)
# 上面说明密码创建时间 (2015-07-20)、0 最小天数、99999 变更天数、7 警告日数与密码不会失效 (-1)

[root@study ~]# passwd -x 60 -i 10 vbird2
[root@study ~]# passwd -S vbird2
vbird2 PS 2015-07-20 0 60 7 10 (Password set, SHA512 crypt.)

  那如果我想要让某个帐号暂时无法使用密码登陆主机呢?

范例五:让 vbird2 的帐号失效,观察完毕后再让它失效
[root@study ~]# passwd -l vbird2
[root@study ~]# passwd -S vbird2
vbird2 LK 2015-07-20 0 60 7 10 (Password locked.)
# 嘿嘿!状态变成“ LK, Lock ”了啦!无法登陆喔!
[root@study ~]# grep vbird2 /etc/shadow
vbird2:!!$6$iWWO6T46$uYStdkB7QjcUpJaCLB.OOp...:16636:0:60:7:10::
# 其实只是在这里加上 !! 而已!

[root@study ~]# passwd -u vbird2
[root@study ~]# grep vbird2 /etc/shadow
vbird2:$6$iWWO6T46$uYStdkB7QjcUpJaCLB.OOp...:16636:0:60:7:10::
# 密码字段恢复正常!

 chage

   除了使用 passwd -S 之外,有没有更详细的密码参数显示功能呢?有的!那就是 chage 了!他的用法如下:

[root@study ~]# chage [-ldEImMW] 帐号名
选项与参数:
-l :列出该帐号的详细密码参数;
-d :后面接日期,修改 shadow 第三字段(最近一次更改密码的日期),格式 YYYY-MM-DD
-E :后面接日期,修改 shadow 第八字段(帐号失效日),格式 YYYY-MM-DD
-I :后面接天数,修改 shadow 第七字段(密码失效日期)
-m :后面接天数,修改 shadow 第四字段(密码最短保留天数)
-M :后面接天数,修改 shadow 第五字段(密码多久需要进行变更)
-W :后面接天数,修改 shadow 第六字段(密码过期前警告日期)
范例一:列出 vbird2 的详细密码参数
[root@study ~]# chage -l vbird2
Last password change                                    : Jul 20, 2015
Password expires                                        : Sep 18, 2015
Password inactive                                       : Sep 28, 2015
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 60
Number of days of warning before password expires       : 7

  chage 有一个功能很不错,如果你想要让“使用者在第一次登陆时, 强制她们一定要更改密码后才能够使用系统资源”,可以利用如下的方法来处理的:

范例二:创建一个名为 agetest 的帐号,该帐号第一次登陆后使用默认密码,但必须要更改过密码后,
        使用新密码才能够登陆系统使用 bash 环境
[root@study ~]# useradd agetest
[root@study ~]# echo "agetest" | passwd --stdin agetest
[root@study ~]# chage -d 0 agetest
[root@study ~]# chage -l agetest | head -n 3
Last password change                : password must be changed
Password expires                    : password must be changed
Password inactive                   : password must be changed
# 此时此帐号的密码创建时间会被改为 1970/1/1 ,所以会有问题!

范例三:尝试以 agetest 登陆的情况
You are required to change your password immediately (root enforced)
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user agetest.
Changing password for agetest
(current) UNIX password:  <==这个帐号被强制要求必须要改密码!

usermod

  对帐号相关数据的微调。

[root@study ~]# usermod [-cdegGlsuLU] username
选项与参数:
-c  :后面接帐号的说明,即 /etc/passwd 第五栏的说明栏,可以加入一些帐号的说明。
-d  :后面接帐号的主文件夹,即修改 /etc/passwd 的第六栏;
-e  :后面接日期,格式是 YYYY-MM-DD 也就是在 /etc/shadow 内的第八个字段数据啦!
-f  :后面接天数,为 shadow 的第七字段。
-g  :后面接初始群组,修改 /etc/passwd 的第四个字段,亦即是 GID 的字段!
-G  :后面接次要群组,修改这个使用者能够支持的群组,修改的是 /etc/group 啰~
-a  :与 -G 合用,可“增加次要群组的支持”而非“设置”喔!
-l  :后面接帐号名称。亦即是修改帐号名称, /etc/passwd 的第一栏!
-s  :后面接 Shell 的实际文件,例如 /bin/bash 或 /bin/csh 等等。
-u  :后面接 UID 数字啦!即 /etc/passwd 第三栏的数据;
-L  :暂时将使用者的密码冻结,让他无法登陆。其实仅改 /etc/shadow 的密码栏。
-U  :将 /etc/shadow 密码栏的 ! 拿掉,解冻啦!

  如果你仔细的比对,会发现 usermod 的选项与 useradd 非常类似。

范例一:修改使用者 vbird2 的说明栏,加上“VBird's test”的说明。
[root@study ~]# usermod -c "VBird's test" vbird2
[root@study ~]# grep vbird2 /etc/passwd
vbird2:x:1500:100:VBird's test:/home/vbird2:/bin/bash

范例二:使用者 vbird2 这个帐号在 2015/12/31 失效。
[root@study ~]# usermod -e "2015-12-31" vbird2
[root@study ~]# chage -l vbird2 | grep 'Account expires'
Account expires                     : Dec 31, 2015

范例三:我们创建 vbird3 这个系统帐号时并没有给予主文件夹,请创建他的主文件夹
[root@study ~]# ll -d ~vbird3
ls: cannot access /home/vbird3: No such file or directory  <==确认一下,确实没有主文件夹的存在!
[root@study ~]# cp -a /etc/skel /home/vbird3
[root@study ~]# chown -R vbird3:vbird3 /home/vbird3
[root@study ~]# chmod 700 /home/vbird3
[root@study ~]# ll -a ~vbird3
drwx------.  3 vbird3 vbird3   74 May  4 17:51 .   <==使用者主文件夹权限
drwxr-xr-x. 10 root   root   4096 Jul 20 22:51 ..
-rw-r--r--.  1 vbird3 vbird3   18 Mar  6 06:06 .bash_logout
-rw-r--r--.  1 vbird3 vbird3  193 Mar  6 06:06 .bash_profile
-rw-r--r--.  1 vbird3 vbird3  231 Mar  6 06:06 .bashrc
drwxr-xr-x.  4 vbird3 vbird3   37 May  4 17:51 .mozilla
# 使用 chown -R 是为了连同主文件夹下面的使用者/群组属性都一起变更的意思;
# 使用 chmod 没有 -R ,是因为我们仅要修改目录的权限而非内部文件的权限!

userdel

  删除使用者的相关数据,而使用者的数据有:

  • 使用者帐号/密码相关参数:/etc/passwd, /etc/shadow
  • 使用者群组相关参数:/etc/group, /etc/gshadow
  • 使用者个人文件数据: /home/username, /var/spool/mail/username..

  整个指令的语法非常简单:

[root@study ~]# userdel [-r] username
选项与参数:
-r  :连同使用者的主文件夹也一起删除

范例一:删除 vbird2 ,连同主文件夹一起删除
[root@study ~]# userdel -r vbird2

  这个指令下达的时候要小心了!通常我们要移除一个帐号的时候,你可以手动的将 /etc/passwd 与 /etc/shadow 里头的该帐号取消即可。一般而言,如果该帐号只是“暂时不启用”的话,那么将 /etc/shadow 里头帐号失效日期 (第八字段) 设置为 0 就可以让该帐号无法使用,但是所有跟该帐号相关的数据都会留下来! 使用 userdel 的时机通常是“你真的确定不要让该用户在主机上面使用任何数据了!”

  另外,其实使用者如果在系统上面操作过一阵子了,那么该使用者其实在系统内可能会含有其他文件的。 举例来说,他的邮件信箱 (mailbox) 或者是例行性工作调度 (crontab) 之类的文件。 所以,如果想要完整的将某个帐号完整的移除,最好可以在下达 userdel -r username 之前, 先以“ find / -user username ”查出整个系统内属于 username 的文件,然后再加以删除。

2.2 使用者功能

  不论是 useradd/usermod/userdel ,那都是系统管理员所能够使用的指令, 如果我是一般身份使用者,那么我是否除了密码之外,就无法更改其他的数据呢? 当然不是啦!这里我们介绍几个一般身份使用者常用的帐号数据变更与查询指令。


id

  id 这个指令可以查询某人或自己的相关 UID/GID 等等的信息,他的参数也不少,不过,都不需要记~反正使用 id 就全部都列出。

[root@study ~]# id [username]

范例一:查阅 root 自己的相关 ID 信息!
[root@study ~]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:
s0-s0:c0.c1023
# 上面信息其实是同一行的数据!包括会显示 UID/GID 以及支持的所有群组!
# 至于后面那个 context=... 则是 SELinux 的内容,先不要理会

finger

  finger 可以查阅很多使用者相关的信息,大部分都是在 /etc/passwd 这个文件里面的信息。不过,这个指令有点危险,所以新的版本中已经默认不安装这个软件。

[root@study ~]# finger [-s] username
选项与参数:
-s  :仅列出使用者的帐号、全名、终端机代号与登陆时间等等;
-m  :列出与后面接的帐号相同者,而不是利用部分比对 (包括全名部分)

范例一:观察 vbird1 的使用者相关帐号属性
[root@study ~]# finger vbird1
Login: vbird1                           Name:
Directory: /home/vbird1                 Shell: /bin/bash
Never logged in.
No mail.
No Plan.

  由于 finger 类似指纹的功能,他会将使用者的相关属性列出来!如上表所示,其实他列出来的几乎都是 /etc/passwd 文件里面的东西。列出的信息说明如下:

  • Login:为使用者帐号,亦即 /etc/passwd 内的第一字段;
  • Name:为全名,亦即 /etc/passwd 内的第五字段(或称为注解);
  • Directory:就是主文件夹了;
  • Shell:就是使用的 Shell 文件所在;
  • Never logged in.:figner 还会调查使用者登陆主机的情况;
  • No mail.:调查 /var/spool/mail 当中的信箱数据;
  • No Plan.:调查 ~vbird1/.plan 文件,并将该文件取出来说明。

  不过是否能够查阅到 Mail 与 Plan 则与权限有关了!因为 Mail / Plan 都是与使用者自己的权限设置有关, root 当然可以查阅到使用者的这些信息,但是 vbird1 就不见得能够查到 vbird3 的信息, 因为 /var/spool/mail/vbird3 与 /home/vbird3/ 的权限分别是 660, 700 ,那 vbird1 当然就无法查阅的到。

  此外,我们可以创建自己想要执行的预定计划,当然,最多是给自己看的,可以这样做:

范例二:利用 vbird1 创建自己的计划档
[vbird1@study ~]$ echo "I will study Linux during this year." > ~/.plan
[vbird1@study ~]$ finger vbird1
Login: vbird1                           Name:
Directory: /home/vbird1                 Shell: /bin/bash
Last login Mon Jul 20 23:06 (CST) on pts/0
No mail.
Plan:
I will study Linux during this year.

范例三:找出目前在系统上面登陆的使用者与登陆时间
[vbird1@study ~]$ finger
Login     Name       Tty      Idle  Login Time   Office     Office Phone   Host
dmtsai    dmtsai     tty2      11d  Jul  7 23:07
dmtsai    dmtsai     pts/0          Jul 20 17:59     

  在范例三当中,我们发现输出的信息还会有 Office, Office Phone 等信息,那这些信息要如何记录呢? 下面我们会介绍 chfn 这个指令,来看看如何修改使用者的 finger 数据。


chfn

  chfn 有点像是: change finger 的意思!这玩意的使用方法如下:

[root@study ~]# chfn [-foph] [帐号名]
选项与参数:
-f  :后面接完整的大名;
-o  :您办公室的房间号码;
-p  :办公室的电话号码;
-h  :家里的电话号码!

范例一:vbird1 自己更改一下自己的相关信息!
[vbird1@study ~]$ chfn
Changing finger information for vbird1.
Name []: VBird Tsai test         <==输入你想要呈现的全名
Office []: DIC in KSU            <==办公室号码
Office Phone []: 06-2727175#356  <==办公室电话
Home Phone []: 06-1234567        <==家里电话号码

Password:  <==确认身份,所以输入自己的密码
Finger information changed.

[vbird1@study ~]$ grep vbird1 /etc/passwd
vbird1:x:1003:1004:VBird Tsai test,DIC in KSU,06-2727175#356,06-1234567:/home/vbird1:/bin/bash
# 其实就是改到第五个字段,该字段里面用多个“ , ”分隔就是了!

[vbird1@study ~]$ finger vbird1
Login: vbird1                           Name: VBird Tsai test
Directory: /home/vbird1                 Shell: /bin/bash
Office: DIC in KSU, 06-2727175#356      Home Phone: 06-1234567
Last login Mon Jul 20 23:12 (CST) on pts/0
No mail.
Plan:
I will study Linux during this year.
# 就是上面特殊字体呈现的那些地方是由 chfn 所修改出来的!

  可以说,基本用不到。


chsh

  这就是 change shell 的简写,使用方法就更简单。

[vbird1@study ~]$ chsh [-ls]
选项与参数:
-l  :列出目前系统上面可用的 shell ,其实就是 /etc/shells 的内容!
-s  :设置修改自己的 Shell 

范例一:用 vbird1 的身份列出系统上所有合法的 shell,并且指定 csh 为自己的 shell
[vbird1@study ~]$ chsh -l
/bin/sh
/bin/bash
/sbin/nologin   <==所谓:合法不可登陆的 Shell 就是这玩意!
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh        <==这就是 C shell 啦!
# 其实上面的信息就是我们在 bash 中谈到的 /etc/shells 啦!

[vbird1@study ~]$ chsh -s /bin/csh; grep vbird1 /etc/passwd
Changing shell for vbird1.
Password:  <==确认身份,请输入 vbird1 的密码
Shell changed.
vbird1:x:1003:1004:VBird Tsai test,DIC in KSU,06-2727175#356,06-1234567:/home/vbird1:/bin/csh

[vbird1@study ~]$ chsh -s /bin/bash
# 测试完毕后,立刻改回来!

[vbird1@study ~]$ ll $(which chsh)
-rws--x--x. 1 root root 23856 Mar  6 13:59 /bin/chsh

   不论是 chfn 与 chsh ,都是能够让一般使用者修改 /etc/passwd 这个系统文件的!所以你猜猜,这两个文件的权限是什么? 一定是 SUID 的功能(临时具备root权限)。

 2.3 新增与移除群组

  OK!了解了帐号的新增、删除、更动与查询后,还有群组的相关内容了。 基本上,群组的内容都与这两个文件有关:/etc/group, /etc/gshadow。 群组的内容其实很简单,都是上面两个文件的新增、修改与移除而已, 不过,如果再加上有效群组的概念,还有 newgrp 与 gpasswd 。


groupadd

[root@study ~]# groupadd [-g gid] [-r] 群组名称
选项与参数:
-g  :后面接某个特定的 GID ,用来直接给予某个 GID ~
-r  :创建系统群组啦!与 /etc/login.defs 内的 GID_MIN 有关。

范例一:新建一个群组,名称为 group1
[root@study ~]# groupadd group1
[root@study ~]# grep group1 /etc/group /etc/gshadow
/etc/group:group1:x:1503:
/etc/gshadow:group1:!::
# 群组的 GID 也是会由 1000 以上最大 GID+1 来决定!

groupmod

  跟 usermod 类似的,这个指令仅是在进行 group 相关参数的修改而已。

[root@study ~]# groupmod [-g gid] [-n group_name] 群组名
选项与参数:
-g  :修改既有的 GID 数字;
-n  :修改既有的群组名称

范例一:将刚刚上个指令创建的 group1 名称改为 mygroup , GID 为 201
[root@study ~]# groupmod -g 201 -n mygroup group1
[root@study ~]# grep mygroup /etc/group /etc/gshadow
/etc/group:mygroup:x:201:
/etc/gshadow:mygroup:!::

  不过,不要随意的更动 GID ,容易造成系统资源的错乱。


groupdel

  删除群组

[root@study ~]# groupdel [groupname]

范例一:将刚刚的 mygroup 删除!
[root@study ~]# groupdel mygroup

范例二:若要删除 vbird1 这个群组的话?
[root@study ~]# groupdel vbird1
groupdel: cannot remove the primary group of user 'vbird1'

  为什么 mygroup 可以删除,但是 vbird1 就不能删除呢?原因很简单,“有某个帐号 (/etc/passwd) 的 initial group 使用该群组!” 如果查阅一下,你会发现在 /etc/passwd 内的 vbird1 第四栏的 GID 就是 /etc/group 内的 vbird1 那个群组的 GID ,当然无法删除~否则 vbird1 这个使用者登陆系统后, 就会找不到 GID ,那可是会造成很大的困扰的!那么如果硬要删除 vbird1 这个群组呢? 你“必须要确认 /etc/passwd 内的帐号没有任何人使用该群组作为 initial group ”才行!所以,你可以:

  • 修改 vbird1 的 GID ,或者是:
  • 删除 vbird1 这个使用者。

gpasswd:群组管理员功能

  创建一个群组管理员,这个群组管理员可以管理哪些帐号可以加入/移出该群组。

# 关于系统管理员(root)做的动作:
[root@study ~]# gpasswd groupname
[root@study ~]# gpasswd [-A user1,...] [-M user3,...] groupname
[root@study ~]# gpasswd [-rR] groupname
选项与参数:
    :若没有任何参数时,表示给予 groupname 一个密码(/etc/gshadow)
-A  :将 groupname 的主控权交由后面的使用者管理(该群组的管理员)
-M  :将某些帐号加入这个群组当中!
-r  :将 groupname 的密码移除
-R  :让 groupname 的密码栏失效

# 关于群组管理员(Group administrator)做的动作:
[someone@study ~]$ gpasswd [-ad] user groupname
选项与参数:
-a  :将某位使用者加入到 groupname 这个群组当中!
-d  :将某位使用者移除出 groupname 这个群组当中。
范例一:创建一个新群组,名称为 testgroup 且群组交由 vbird1 管理:
[root@study ~]# groupadd testgroup  <==先创建群组
[root@study ~]# gpasswd testgroup   <==给这个群组一个密码吧!
Changing the password for group testgroup
New Password:
Re-enter new password:
# 输入两次密码就对了!
[root@study ~]# gpasswd -A vbird1 testgroup  <==加入群组管理员为 vbird1
[root@study ~]# grep testgroup /etc/group /etc/gshadow
/etc/group:testgroup:x:1503:
/etc/gshadow:testgroup:$6$MnmChP3D$mrUn.Vo.buDjObMm8F2emTkvGSeuWikhRzaKHxpJ...:vbird1:
# 很有趣吧!此时 vbird1 则拥有 testgroup 的主控权喔!身份有点像板主啦!

范例二:以 vbird1 登陆系统,并且让他加入 vbird1, vbird3 成为 testgroup 成员
[vbird1@study ~]$ id
uid=1003(vbird1) gid=1004(vbird1) groups=1004(vbird1) ...
# 看得出来,vbird1 尚未加入 testgroup 群组喔!

[vbird1@study ~]$ gpasswd -a vbird1 testgroup
[vbird1@study ~]$ gpasswd -a vbird3 testgroup
[vbird1@study ~]$ grep testgroup /etc/group
testgroup:x:1503:vbird1,vbird3

2.4 帐号管理实例

  帐号管理不是随意创建几个帐号就算了,有时候我们需要考虑到一部主机上面可能有多个帐号在协同工作! 举例来说,在大学时,我们是需要分组的,这些同一组的同学间必须要能够互相修改对方的数据文件, 但是同时这些同学又需要保留自己的私密数据,因此直接公开主文件夹是不适宜的。那该如何是好? 为此,我们下面提供几个例子来让大家思考:

任务一:单纯的完成上头交代的任务,假设我们需要的帐号数据如下

  处理的方法如下所示:

# 先处理帐号相关属性的数据:
[root@study ~]# groupadd mygroup1
[root@study ~]# useradd -G mygroup1 -c "1st user" myuser1
[root@study ~]# useradd -G mygroup1 -c "2nd user" myuser2
[root@study ~]# useradd -c "3rd user" -s /sbin/nologin myuser3

# 再处理帐号的密码相关属性的数据:
[root@study ~]# echo "password" | passwd --stdin myuser1
[root@study ~]# echo "password" | passwd --stdin myuser2
[root@study ~]# echo "password" | passwd --stdin myuser3

  要注意的地方主要有:myuser1 与 myuser2 都有支持次要群组,但该群组不见得会存在,因此需要先手动创建他! 然后 myuser3 是“不可登陆系统”的帐号,因此需要使用 /sbin/nologin 这个 shell 来给予,这样该帐号就无法登陆。

任务二:我的使用者 pro1, pro2, pro3 是同一个组的开发人员,我想要让这三个用户在同一个目录下面工作, 但这三个用户还是拥有自己的主文件夹与基本的私有群组。假设我要让这个组在 /srv/projecta 目录下开发。

# 1. 假设这三个帐号都尚未创建,可先创建一个名为 projecta 的群组,
#    再让这三个用户加入其次要群组的支持即可:
[root@study ~]# groupadd projecta
[root@study ~]# useradd -G projecta -c "projecta user" pro1
[root@study ~]# useradd -G projecta -c "projecta user" pro2
[root@study ~]# useradd -G projecta -c "projecta user" pro3
[root@study ~]# echo "password" | passwd --stdin pro1
[root@study ~]# echo "password" | passwd --stdin pro2
[root@study ~]# echo "password" | passwd --stdin pro3

# 2. 开始创建此专案的开发目录:
[root@study ~]# mkdir /srv/projecta
[root@study ~]# chgrp projecta /srv/projecta
[root@study ~]# chmod 2770 /srv/projecta
[root@study ~]# ll -d /srv/projecta
drwxrws---. 2 root projecta 6 Jul 20 23:32 /srv/projecta

  由于只能够给 pro1, pro2, pro3 三个人使用,所以 /srv/projecta 的权限设置一定要正确才行! 所以该目录群组一定是 projecta ,但是权限怎么会是 2770 呢?还记得之前谈到的 SGID ,为了让三个使用者能够互相修改对方的文件, 这个 SGID 是必须要存在的。

  但接下来有个困扰的问题发生了!假如任务一的 myuser1 是 projecta 这个组的助理,他需要这个专案的内容, 但是他“不可以修改”专案目录内的任何数据。那该如何是好?你或许可以这样做:

  • 将 myuser1 加入 projecta 这个群组的支持,但是这样会让 myuser1 具有完整的 /srv/projecta 的使用权限, myuser1 是可以删除该目录下的任何数据的!这样是有问题的;
  • 将 /srv/projecta 的权限改为 2775 ,让 myuser1 可以进入查阅数据。但此时会发生所有其他人均可进入该目录查阅的困扰! 这也不是我们要的环境。

  传统的 Linux 权限无法针对某个个人设置专属的权限吗?其实是可以啦!接下来我们就来谈谈ACL这个功能吧。

2.5 使用外部身份认证系统

  有时候,除了本机的帐号之外,可能还会使用到其他外部的身份验证服务器所提供的验证身份的功能。举例来说, windows 下面有个很有名的身份验证系统,称为 Active Directory (AD)的东西,还有 Linux 为了提供不同主机使用同一组帐号密码, 也会使用到 LDAP, NIS 等服务器提供的身份验证等等。

   CentOS 提供一只名为 authconfig-tui 的指令给我们参考,这个指令的执行结果如下:

3. 主机的详细权限规划:ACL 的使用

  Linux 的权限概念很重要,但是传统的权限仅有三种身份 (owner, group, others) 搭配三种权限 (r,w,x) 而已,并没有办法单纯的针对某一个使用者或某一个群组来设置特定的权限需求,例如2.4最后的那个任务,此时就得要使用 ACL 这个机制。

3.1 什么是 ACL 与如何支持启动 ACL

  ACL(Access Control List),主要的目的是在提供传统的 owner,group,others 的 read,write,execute 权限之外的详细权限设置。ACL 可以针对单一使用者,单一文件或目录来进行 r,w,x 的权限规范,对于需要特殊权限的使用状况非常有帮助。

  那 ACL 主要针对几个项目:

  • 使用者 (user):可以针对使用者来设置权限;
  • 群组 (group):针对群组为对象来设置其权限;
  • 默认属性 (mask):还可以针对在该目录下在创建新文件/目录时,规范新数据的默认权限;

  也就是说,如果你有一个目录,需要给一堆人使用,每个人或每个群组所需要的权限并不相同时,在过去,传统的 Linux 三种身份的三种权限是无法达到的, 因为基本上,传统的 Linux 权限只能针对一个用户、一个群组及非此群组的其他人设置权限而已,无法针对单一用户或个人来设计权限,而 ACL 就是为了要改变这个问题。

如何启动 ACL

  事实上,原本 ACL 是 unix-like 操作系统的额外支持项目,但因为近年以来 Linux 系统对权限细部设置的热切需求, 因此目前 ACL 几乎已经默认加入在所有常见的 Linux 文件系统的挂载参数中 (ext2/ext3/ext4/xfs等等)!所以你无须进行任何动作, ACL 就可以被你使用。不过,如果你不放心系统是否真的有支持 ACL 的话,那么就来检查一下核心挂载时显示的信息:

[root@study ~]# dmesg | grep -i acl
[    0.330377] systemd[1]: systemd 208 running in system mode. (+PAM +LIBWRAP +AUDIT 
+SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)
[    0.878265] SGI XFS with ACLs, security attributes, large block/inode numbers, no 
debug enabled

  xfs 已经支持这个 ACL 的功能。

3.2 ACL 的设置技巧: getfacl, setfacl

  filesystem 有支持 ACL 之后,利用这两个指令就可以了:

  • getfacl:取得某个文件/目录的 ACL 设置项目;
  • setfacl:设置某个目录/文件的 ACL 规范。

setfacl 指令用法介绍及最简单的“ u:帐号:权限 ”设置

[root@study ~]# setfacl [-bkRd] [{-m|-x} acl参数] 目标文件名
选项与参数:
-m :设置后续的 acl 参数给文件使用,不可与 -x 合用;
-x :删除后续的 acl 参数,不可与 -m 合用;
-b :移除“所有的” ACL 设置参数;
-k :移除“默认的” ACL 参数,关于所谓的“默认”参数于后续范例中介绍;
-R :递回设置 acl ,亦即包括次目录都会被设置起来;
-d :设置“默认 acl 参数”的意思!只对目录有效,在该目录新建的数据会引用此默认值

  上面谈到的是 acl 的选项功能,那么如何设置 ACL 的特殊权限呢?特殊权限的设置方法有很多, 我们先来谈谈最常见的,就是针对单一使用者的设置方式:

# 1. 针对特定使用者的方式:
# 设置规范:“ u:[使用者帐号列表]:[rwx] ”,例如针对 vbird1 的权限规范 rx :
[root@study ~]# touch acl_test1
[root@study ~]# ll acl_test1
-rw-r--r--. 1 root root 0 Jul 21 17:33 acl_test1
[root@study ~]# setfacl -m u:vbird1:rx acl_test1
[root@study ~]# ll acl_test1
-rw-r-xr--+ 1 root root 0 Jul 21 17:33 acl_test1
# 权限部分多了个 + ,且与原本的权限 (644) 看起来差异很大!但要如何查阅呢?

[root@study ~]# setfacl -m u::rwx acl_test1
[root@study ~]# ll acl_test1
-rwxr-xr--+ 1 root root 0 Jul 21 17:33 acl_test1
# 设置值中的 u 后面无使用者列表,代表设置该文件拥有者,所以上面显示 root 的权限成为 rwx 了

  上述动作为最简单的 ACL 设置,利用“ u:使用者:权限 ”的方式来设置的啦!设置前请加上 -m 这个选项。 如果一个文件设置了 ACL 参数后,他的权限部分就会多出一个 + 号了,但是此时你看到的权限与实际权限可能就会有点误差。 那要如何观察呢?就通过 getfacl 。


getfacl

[root@study ~]# getfacl filename
选项与参数:
getfacl 的选项几乎与 setfacl 相同,所以这里就免去选项的说明。

# 请列出刚刚我们设置的 acl_test1 的权限内容:
[root@study ~]# getfacl acl_test1
# file: acl_test1   <==说明文档名而已!
# owner: root       <==说明此文件的拥有者,亦即 ls -l 看到的第三使用者字段
# group: root       <==此文件的所属群组,亦即 ls -l 看到的第四群组字段
user::rwx           <==使用者列表栏是空的,代表文件拥有者的权限
user:vbird1:r-x     <==针对 vbird1 的权限设置为 rx ,与拥有者并不同!
group::r--          <==针对文件群组的权限设置仅有 r 
mask::r-x           <==此文件默认的有效权限 (mask)
other::r--          <==其他人拥有的权限!

 特定的单一群组的权限设置:“ g:群组名:权限 ”

# 2. 针对特定群组的方式:
# 设置规范:“ g:[群组列表]:[rwx] ”,例如针对 mygroup1 的权限规范 rx :
[root@study ~]# setfacl -m g:mygroup1:rx acl_test1
[root@study ~]# getfacl acl_test1
# file: acl_test1
# owner: root
# group: root
user::rwx
user:vbird1:r-x
group::r--
group:mygroup1:r-x  <==这里就是新增的部分!多了这个群组的权限设置!
mask::r-x
other::r--

 针对有效权限设置:“ m:权限 ”

  基本上,群组与使用者的设置并没有什么太大的差异。不过,奇怪的是, 那个 mask 是什么东西?其实他有点像是“有效权限”的意思!他的意义是: 使用者或群组所设置的权限必须要存在于 mask 的权限设置范围内才会生效,此即“有效权限 (effective permission)” 我们举个例子来看,如下所示:

# 3. 针对有效权限 mask 的设置方式:
# 设置规范:“ m:[rwx] ”,例如针对刚刚的文件规范为仅有 r :
[root@study ~]# setfacl -m m:r acl_test1
[root@study ~]# getfacl acl_test1
# file: acl_test1
# owner: root
# group: root
user::rwx
user:vbird1:r-x        #effective:r-- <==vbird1+mask均存在者,仅有 r 而已,x 不会生效
group::r--
group:mygroup1:r-x     #effective:r--
mask::r--
other::r--

例题:
  将2.4中任务二中 /srv/projecta 这个目录,让 myuser1 可以进入查阅,但 myuser1 不具有修改的权力。
答:
  由于 myuser1 是独立的使用者与群组,因此无法使用传统的 Linux 权限设置。此时使用 ACL 的设置如下:

# 1. 先测试看看,使用 myuser1 能否进入该目录?
[myuser1@study ~]$ cd /srv/projecta
-bash: cd: /srv/projecta: Permission denied  <==确实不可进入!

# 2. 开始用 root 的身份来设置一下该目录的权限吧!
[root@study ~]# setfacl -m u:myuser1:rx /srv/projecta
[root@study ~]# getfacl /srv/projecta
# file: srv/projecta
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x  <==还是要看看有没有设置成功喔!
group::rwx
mask::rwx
other::---

# 3. 还是得要使用 myuser1 去测试看看结果!
[myuser1@study ~]$ cd /srv/projecta
[myuser1@study projecta]$ ll -a
drwxrws---+ 2 root projecta 4096 Feb 27 11:29 .  <==确实可以查询文件名
drwxr-xr-x  4 root root     4096 Feb 27 11:29 ..

[myuser1@study projecta]$ touch testing
touch: cannot touch `testing': Permission denied <==确实不可以写入

   接下来让我们来测试一下,如果我用 root 或者是 pro1 的身份去 /srv/projecta 增加文件或目录时,该文件或目录是否能够具有 ACL 的设置? 意思就是说,ACL 的权限设置是否能够被次目录所“继承?”先试看看:

[root@study ~]# cd /srv/projecta
[root@study ~]# touch abc1
[root@study ~]# mkdir abc2
[root@study ~]# ll -d abc*
-rw-r--r--. 1 root projecta 0 Jul 21 17:49 abc1
drwxr-sr-x. 2 root projecta 6 Jul 21 17:49 abc

   你可以明显的发现,权限后面都没有 + ,代表这个 acl 属性并没有继承喔!如果你想要让 acl 在目录下面的数据都有继承的功能,那就得如下这样做了。


 使用默认权限设置目录未来文件的 ACL 权限继承“ d:[u|g]:[user|group]:权限 ”

# 4. 针对默认权限的设置方式:
# 设置规范:“ d:[ug]:使用者列表:[rwx] ”

# 让 myuser1 在 /srv/projecta 下面一直具有 rx 的默认权限!
[root@study ~]# setfacl -m d:u:myuser1:rx /srv/projecta
[root@study ~]# getfacl /srv/projecta
# file: srv/projecta
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

[root@study ~]# cd /srv/projecta
[root@study projecta]# touch zzz1
[root@study projecta]# mkdir zzz2
[root@study projecta]# ll -d zzz*
-rw-rw----+ 1 root projecta 0 Jul 21 17:50 zzz1
drwxrws---+ 2 root projecta 6 Jul 21 17:51 zzz2
# 看吧!确实有继承喔!然后我们使用 getfacl 再次确认看看!

[root@study projecta]# getfacl zzz2
# file: zzz2
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

  通过这个“针对目录来设置的默认 ACL 权限设置值”的项目,我们可以让这些属性继承到次目录下面。

  那如果想要让 ACL 的属性全部消失又要如何处理?通过“ setfacl -b 文件名 ”即可。

问:
  针对刚刚的 /srv/projecta 目录的权限设置中,我需要 1. 取消 myuser1 的设置(连同默认值),以及 2.我不能让 pro3 这个用户使用该目录,亦即 pro3 在该目录下无任何权限, 该如何设置?
答:
  取消全部的 ACL 设置可以使用 -b 来处理,但单一设置值的取消,就得要通过 -x 才行。所以你应该这样作:

# 1.1 找到针对 myuser1 的设置值
[root@study ~]# getfacl /srv/projecta | grep myuser1
user:myuser1:r-x
default:user:myuser1:r-x

# 1.2 针对每个设置值来处理,注意,取消某个帐号的 ACL 时,不需要加上权限项目!
[root@study ~]# setfacl -x u:myuser1 /srv/projecta
[root@study ~]# setfacl -x d:u:myuser1 /srv/projecta

# 2.1 开始让 pro3 这个用户无法使用该目录
[root@study ~]# setfacl -m u:pro3:- /srv/projecta

  只需要留意,当设置一个用户/群组没有任何权限的 ACL 语法中,在权限的字段不可留白,而是应该加上一个减号 (-) 才是正确的作法。

4. 使用者身份切换

   我们都是使用一般帐号登陆系统的,等有需要进行系统维护或软件更新时才转为 root 的身份来动作。 那如何让一般使用者转变身份成为 root 呢?主要有两种方式:

  •  以“ su - ”直接将身份变成 root 即可,但是这个指令却需要 root 的密码,也就是说,如果你要以 su 变成 root 的话,你的一般使用者就必须要有 root 的密码才行;
  •  以“ sudo 指令 ”执行 root 的指令串,由于 sudo 需要事先设置妥当,且 sudo 需要输入使用者自己的密码, 因此多人共管同一部主机时, sudo 要比 su 好。

4.1 su

   su 是最简单的身份切换指令了,他可以进行任何身份的切换。

[root@study ~]# su [-lm] [-c 指令] [username]
选项与参数:
-   :单纯使用 - 如“ su - ”代表使用 login-shell 的变量文件读取方式来登陆系统;
      若使用者名称没有加上去,则代表切换为 root 的身份。
-l  :与 - 类似,但后面需要加欲切换的使用者帐号!也是 login-shell 的方式。
-m  :-m 与 -p 是一样的,表示“使用目前的环境设置,而不读取新使用者的配置文件”
-c  :仅进行一次指令,所以 -c 后面可以加上指令

  这个 su 的用法当中,有没有加上那个减号“ - ”差很多,因为涉及 login-shell 与 non-login shell 的变量读取方法。这里让我们以一个小例子来说明:

范例一:假设你原本是 dmtsai 的身份,想要使用 non-login shell 的方式变成 root
[dmtsai@study ~]$ su       <==注意提示字符,是 dmtsai 的身份
Password:                  <==这里输入 root 的密码
[root@study dmtsai]# id    <==提示字符的目录是 dmtsai 
uid=0(root) gid=0(root) groups=0(root) context=unconf....  <==确实是 root 的身份!
[root@study dmtsai]# env | grep 'dmtsai'
USER=dmtsai                                         <==竟然还是 dmtsai 这家伙!
PATH=...:/home/dmtsai/.local/bin:/home/dmtsai/bin   <==这个影响最大! 
MAIL=/var/spool/mail/dmtsai                         <==收到的 mailbox 是 vbird1
PWD=/home/dmtsai                                    <==并非 root 的主文件夹
LOGNAME=dmtsai
# 虽然你的 UID 已经是具有 root 的身份,但是看到上面的输出信息吗?
# 还是有一堆变量为原本 dmtsai 的身份,所以很多数据还是无法直接利用。
[root@study dmtsai]# exit   <==这样可以离开 su 的环境!

   单纯使用“ su ”切换成为 root 的身份,读取的变量设置方式为 non-login shell 的方式,这种方式很多原本的变量不会被改变, 尤其是PATH 这个变量,由于没有改变成为 root 的环境, 因此很多 root 惯用的指令就只能使用绝对路径来执行。其他的还有 MAIL 这个变量,你输入 mail 时, 收到的邮件竟然还是 dmtsai 的,而不是 root 本身的邮件!是否觉得很奇怪啊!所以切换身份时,请务必使用如下的范例二:

范例二:使用 login shell 的方式切换为 root 的身份并观察变量
[dmtsai@study ~]$ su -
Password:   <==这里输入 root 的密码喔!
[root@study ~]# env | grep root
USER=root
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root
HOME=/root
LOGNAME=root
# 了解差异了吧?下次变换成为 root 时,记得最好使用 su - 
[root@study ~]# exit   <==这样可以离开 su 的环境!

  那我如果只是想要执行“一个只有 root 才能进行的指令,且执行完毕就恢复原本的身份”呢?那就可以加上 -c 这个选项。

范例三:dmtsai 想要执行“ head -n 3 /etc/shadow ”一次,且已知 root 密码
[dmtsai@study ~]$ head -n 3 /etc/shadow
head: cannot open `/etc/shadow' for reading: Permission denied
[dmtsai@study ~]$ su - -c "head -n 3 /etc/shadow"
Password: <==这里输入 root 的密码喔!
root:$6$wtbCCce/PxMeE5wm$KE2IfSJr.YLP7Rcai6oa/T7KFhOYO62vDnqfLw85...:16559:0:99999:7:::
bin:*:16372:0:99999:7:::
daemon:*:16372:0:99999:7:::
[dmtsai@study ~]$ <==注意看,身份还是 dmtsai

   如果我是 root 或者是其他人, 想要变更成为某些特殊帐号,可以使用如下的方法来切换:

范例四:原本是 dmtsai 这个使用者,想要变换身份成为 vbird1 时?
[dmtsai@study ~]$ su -l vbird1
Password: <==这里输入 vbird1 的密码
[vbird1@study ~]$ su -
Password: <==这里输入 root 的密码
[root@study ~]# id sshd
uid=74(sshd) gid=74(sshd) groups=74(sshd) ... <==确实有存在此人
[root@study ~]# su -l sshd
This account is currently not available.      <==竟然说此人无法切换?
[root@study ~]# finger sshd
Login: sshd                             Name: Privilege-separated SSH
Directory: /var/empty/sshd              Shell: /sbin/nologin
[root@study ~]# exit    <==离开第二次的 su 
[vbird1@study ~]$ exit  <==离开第一次的 su 
[dmtsai@study ~]$ exit  <==这才是最初的环境

 总结一下 su 的用法是这样的:

  • 若要完整的切换到新使用者的环境,必须要使用“ su - username ”或“ su -l username ”, 才会连同 PATH/USER/MAIL 等变量都转成新使用者的环境;
  • 如果仅想要执行一次 root 的指令,可以利用“ su - -c "指令串" ”的方式来处理;
  • 使用 root 切换成为任何使用者时,并不需要输入新使用者的密码;

4.2 sudo

   对于 su 需要了解新切换的使用者密码 (常常是需要 root 的密码), sudo 的执行则仅需要自己的密码即可。甚至可以设置不需要密码即可执行 sudo ,由于 sudo 可以让你以其他用户的身份执行指令 (通常是使用 root 的身份来执行指令),因此并非所有人都能够执行 sudo , 而是仅有规范到 /etc/sudoers 内的用户才能够执行 sudo 这个指令。

  事实上,一般用户能够具有 sudo 的使用权,就是管理员事先审核通过后,才开放 sudo 的使用权的。因此,除非是信任用户,否则一般用户默认是不能操作 sudo 的。

  但是平时明明创建账户后能用sudo,这是因为创建帐号的时候,默认将此用户加入 sudo 的支持中了。


sudo 的指令用法 

  由于一开始系统默认仅有 root 可以执行 sudo ,因此下面的范例我们先以 root 的身份来执行,等到谈到 visudo 时,再以一般使用者来讨论其他 sudo 的用法吧。sudo 的语法如下:

[root@study ~]# sudo [-b] [-u 新使用者帐号]
选项与参数:
-b  :将后续的指令放到背景中让系统自行执行,而不与目前的 shell 产生影响
-u  :后面可以接欲切换的使用者,若无此项则代表切换身份为 root 。

范例一:你想要以 sshd 的身份在 /tmp 下面创建一个名为 mysshd 的文件
[root@study ~]# sudo -u sshd touch /tmp/mysshd
[root@study ~]# ll /tmp/mysshd
-rw-r--r--. 1 sshd sshd 0 Jul 21 23:37 /tmp/mysshd
# 特别留意,这个文件的权限是由 sshd 所创建的情况喔!

范例二:你想要以 vbird1 的身份创建 ~vbird1/www 并于其中创建 index.html 文件
[root@study ~]# sudo -u vbird1 sh -c "mkdir ~vbird1/www; cd ~vbird1/www; \
>  echo 'This is index.html file' > index.html"
[root@study ~]# ll -a ~vbird1/www
drwxr-xr-x. 2 vbird1 vbird1   23 Jul 21 23:38 .
drwx------. 6 vbird1 vbird1 4096 Jul 21 23:38 ..
-rw-r--r--. 1 vbird1 vbird1   24 Jul 21 23:38 index.html
# 要注意,创建者的身份是 vbird1 ,且我们使用 sh -c "一串指令" 来执行的

   sudo 可以让你切换身份来进行某项任务,例如上面的两个范例。范例一中,我们的 root 使用 sshd 的权限去进行某项任务! 要注意,因为我们无法使用“ su - sshd ”去切换系统帐号 (因为系统帐号的 shell 是 /sbin/nologin)。

  但是 sudo 默认仅有 root 能使用,为什么呢?因为 sudo 的执行是这样的流程:

  • 当使用者执行 sudo 时,系统于 /etc/sudoers 文件中搜索该使用者是否有执行 sudo 的权限;
  • 若使用者具有可执行 sudo 的权限后,便让使用者“输入使用者自己的密码”来确认;
  • 若密码输入成功,便开始进行 sudo 后续接的指令(但 root 执行 sudo 时,不需要输入密码);
  • 若欲切换的身份与执行者身份相同,那也不需要输入密码。

   由于能否使用与 /etc/sudoers 有关, 所以我们当然要去编辑 sudoers 文件。不过,因为该文件的内容是有一定的规范的,因此直接使用 vi 去编辑是不好的。 此时,我们得要通过 visudo 去修改这个文件。


visudo 与 /etc/sudoers

  从上面的说明我们可以知道,除了 root 之外的其他帐号,若想要使用 sudo 执行属于 root 的权限指令,则 root 需要先使用 visudo 去修改 /etc/sudoers ,让该帐号能够使用全部或部分的 root 指令功能。为什么要使用 visudo 呢?这是因为 /etc/sudoers 是有设置语法的,如果设置错误那会造成无法使用 sudo 指令的不良后果。因此才会使用 visudo 去修改, 并在结束离开修改画面时,系统会去检验 /etc/sudoers 的语法

  一般来说,visudo 的设置方式有几种简单的方法,下面我们以几个简单的例子来分别说明:

1. 单一使用者可进行 root 所有指令,与 sudoers 文件语法:

  假如我们要让 vbird1 这个帐号可以使用 root 的任何指令,基本上有两种作法,第一种是直接通过修改 /etc/sudoers ,方法如下:

[root@study ~]# visudo
....(前面省略)....
root    ALL=(ALL)       ALL  <==找到这一行,大约在 98 行左右
vbird1  ALL=(ALL)       ALL  <==这一行是你要新增的!
....(下面省略)....

  其实 visudo 只是利用 vi 将 /etc/sudoers 文件调用出来进行修改而已,如上面所示,如果你找到 98 行 (有 root 设置的那行) 左右,看到的数据就是:

使用者帐号  登陆者的来源主机名称=(可切换的身份)  可下达的指令
root                         ALL=(ALL)           ALL   <==这是默认值

上面这一行的四个元件意义是:

  • “使用者帐号”:系统的哪个帐号可以使用 sudo 这个指令的意思;
  • “登陆者的来源主机名称”:当这个帐号由哪部主机连线到本 Linux 主机,意思是这个帐号可能是由哪一部网络主机连线过来的, 这个设置值可以指定用户端计算机(信任的来源的意思)。默认值 root 可来自任何一部网络主机
  • “(可切换的身份)”:这个帐号可以切换成什么身份来下达后续的指令,默认 root 可以切换成任何人;
  • “可下达的指令”:可用该身份下达什么指令?这个指令请务必使用绝对路径写。 默认 root 可以切换任何身份且进行任何指令之意。

  那个 ALL 是特殊的关键字,代表任何身份、主机或指令的意思。所以,我想让 vbird1 可以进行任何身份的任何指令, 就如同上表特殊字体写的那样,其实就是复制上述默认值那一行,再将 root 改成 vbird1 即可。此时“vbird1 不论来自哪部主机登陆,他可以变换身份成为任何人,且可以进行系统上面的任何指令”之意。

2. 利用 wheel 群组以及免密码的功能处理 visudo

  我们在本章前面曾经创建过 pro1, pro2, pro3 ,这三个用户能否通过群组的功能让这三个人可以管理系统? 可以的,同样我们使用实际案例来说明:


[root@study ~]# visudo  <==同样的,请使用 root 先设置
....(前面省略)....
%wheel     ALL=(ALL)    ALL <==大约在 106 行左右,请将这行的 # 拿掉!
# 在最左边加上 % ,代表后面接的是一个“群组”之意!改完请储存后离开

[root@study ~]# usermod -a -G wheel pro1 <==将 pro1 加入 wheel 的支持

  上面的设置值会造成“任何加入 wheel 这个群组的使用者,就能够使用 sudo 切换任何身份来操作任何指令”的意思。 你当然可以将 wheel 换成你自己想要的群组名。

  从 CentOS 7 开始,在 sudoers 文件中,默认已经开放 %wheel 那一行。

  不过,既然我们都信任这些 sudo 的用户了,能否提供“不需要密码即可使用 sudo ”呢? 就通过如下的方式:

[root@study ~]# visudo  <==同样的,请使用 root 先设置
....(前面省略)....
%wheel     ALL=(ALL)   NOPASSWD: ALL <==大约在 109 行左右,请将 # 拿掉!
# 在最左边加上 % ,代表后面接的是一个“群组”之意!改完请储存后离开

  那个 NOPASSWD ,该关键字是免除密码输入的意思。

3. 有限制的指令操作

  上面两点都会让使用者能够利用 root 的身份进行任何事情,这样总是不太好~如果我想要让使用者仅能够进行部分系统任务, 比方说,系统上面的 myuser1 仅能够帮 root 修改其他使用者的密码时,亦即“当使用者仅能使用 passwd 这个指令帮忙 root 修改其他用户的密码”时,可以这样做:

[root@study ~]# visudo  <==注意是 root 身份
myuser1      ALL=(root)    /usr/bin/passwd  <==最后指令务必用绝对路径

  上面的设置值指的是“myuser1 可以切换成为 root 使用 passwd 这个指令”的意思。其中要注意的是: 指令字段必须要填写绝对路径才行,否则 visudo 会出现语法错误的状况发生。此外,上面的设置是有问题的!我们使用下面的指令操作来了解:

[myuser1@study ~]$ sudo passwd myuser3  <==注意,身份是 myuser1
[sudo] password for myuser1:  <==输入 myuser1 的密码
Changing password for user myuser3. <==下面改的是 myuser3 的密码喔!这样是正确的
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

[myuser1@study ~]$ sudo passwd
Changing password for user root.  <==见鬼!怎么会去改 root 的密码?

  竟然 root 的密码被 myuser1 给改变了!所以我们必须要限制使用者的指令参数,修改的方法为:

[root@study ~]# visudo  <==注意是 root 身份
myuser1	ALL=(root)  !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

  在设置值中加上惊叹号“ ! ”代表“不可执行”的意思。因此上面这一行会变成:可以执行“ passwd 任意字符”,但是“ passwd ”与“ passwd root ”这两个指令例外。 如此一来 myuser1 就无法改变 root 的密码了,这样这位使用者可以具有 root 的能力帮助你修改其他用户的密码, 而且也不能随意改变 root 的密码。

4. 通过别名创建 visudo

  如果我有多个用户需要加入刚刚的管理员行列,那么我要将上述那长长的设置写入很多,而且如果想要修改命令或者是新增命令时,那我每行都需要重新设置,很麻烦!有没有更简单的方式? 通过别名即可! visudo 的别名可以是“指令别名、帐号别名、主机别名”等。不过这里我们仅介绍帐号别名, 其他的设置值有兴趣的话,可以自行玩玩。

  假设我的 pro1, pro2, pro3 与 myuser1, myuser2 要加入上述的密码管理员的 sudo 列表中, 那我可以创立一个帐号别名称为 ADMPW 的名称,然后将这个名称处理一下即可。处理的方式如下:

[root@study ~]# visudo  <==注意是 root 身份
User_Alias ADMPW = pro1, pro2, pro3, myuser1, myuser2
Cmnd_Alias ADMPWCOM = !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
ADMPW   ALL=(root)  ADMPWCOM

  通过 User_Alias 创建出一个新帐号,这个帐号名称一定要使用大写字符来处理,包括 Cmnd_Alias(命令别名)、Host_Alias(来源主机名称别名) 都需要使用大写字符的!这个 ADMPW 代表后面接的那些实际帐号。 而该帐号能够进行的指令就如同 ADMPWCOM 后面所指定的那样,上表最后一行则写入这两个别名 (帐号与指令别名), 未来要修改时,我只要修改 User_Alias 以及 Cmnd_Alias 这两行即可。

5. sudo 的时间间隔问题

  如果我使用同一个帐号在短时间内重复操作 sudo 来运行指令的话, 在第二次执行 sudo 时,并不需要输入自己的密码,sudo 还是会正确的运行。为什么? 第一次执行 sudo 需要输入密码,是担心由于使用者暂时离开座位,但有人跑来你的座位使用你的帐号操作系统之故。 所以需要你输入一次密码重新确认一次身份。

  两次执行 sudo 的间隔在五分钟内,那么再次执行 sudo 时就不需要再次输入密码了, 这是因为系统相信你在五分钟内不会离开你的作业,所以执行 sudo 的是同一个人。

6. sudo 搭配 su 的使用方式

  很多时候我们需要大量执行很多 root 的工作,所以一直使用 sudo 觉得很烦。那有没有办法使用 sudo 搭配 su , 一口气将身份转为 root ,而且还用使用者自己的密码来变成 root 呢?是有的!而且方法简单的会让你想笑! 我们创建一个 ADMINS 帐号别名,然后这样做:

[root@study ~]# visudo
User_Alias  ADMINS = pro1, pro2, pro3, myuser1
ADMINS ALL=(root)  /bin/su -

  接下来,上述的 pro1, pro2, pro3, myuser1 这四个人,只要输入“ sudo su - ”并且输入“自己的密码”后, 立刻变成 root 的身份。不但 root 密码不会外流,使用者的管理也变的非常方便。

5 使用者的特殊 shell 与 PAM 模块

  我们前面一直谈到的大多是一般身份使用者与系统管理员 (root) 的相关操作, 而且大多是讨论关于可登陆系统的帐号来说。那么换个角度想,如果我今天想要创建的, 是一个“仅能使用 mail server 相关邮件服务的帐号,而该帐号并不能登陆 Linux 主机”呢?如果不能给予该帐号一个密码,那么该帐号就无法使用系统的各项资源,当然也包括 mail 的资源, 而如果给予一个密码,那么该帐号就可能可以登陆 Linux 主机。难搞~ 所以,下面让我们来谈一谈这些有趣的话题。

  另外,在本章之前谈到过 /etc/login.defs 文件中,关于密码长度应该默认是 5 个字串长度,但是我们上面也谈到,该设置值已经被 PAM 模块所取代了,那么 PAM 是什么?为什么他可以影响我们使用者的登陆呢?

5.1 特殊的 shell, /sbin/nologin

  系统帐号是不需要登陆的,它在passwd文件中显示shell使用的是/sbin/nologin,所以我们就给他这个无法登陆的合法 shell。使用了这个 shell 的用户即使有了密码,你想要登陆时也无法登陆,因为会出现如下的信息:

This account is currently not available.

  所谓的“无法登陆”指的仅是:“这个使用者无法使用 bash 或其他 shell 来登陆系统”,并不是说这个帐号就无法使用其他的系统资源。

  另外,如果我想要让某个具有 /sbin/nologin 的使用者知道,他们不能登陆主机时, 其实可以创建“ /etc/nologin.txt ”这个文件, 并且在这个文件内说明不能登陆的原因,那么下次当这个使用者想要登陆系统时, 屏幕上出现的就会是 /etc/nologin.txt 这个文件的内容,而不是默认的内容了。

[root@study ~]# vim /etc/nologin.txt
This account is system account or mail account.
Please DO NOT use this account to login my Linux server.

[root@study ~]# su - myuser3
This account is system account or mail account.
Please DO NOT use this account to login my Linux server.

5.2 PAM 模块简介

  在过去,我们想要对一个使用者进行认证 (authentication),得要求使用者输入帐号密码, 然后通过自行编写的程序来判断该帐号密码是否正确。也因为如此,我们常常得使用不同的机制来判断帐号密码, 所以搞的一部主机上面拥有多个各别的认证系统,也造成帐号密码可能不同步的验证问题。为了解决这个问题因此有了 PAM (Pluggable Authentication Modules, 嵌入式模块) 的机制。

  PAM 是一套应用程序接口 (Application Programming Interface, API),他提供了一连串的验证机制,只要使用者将验证阶段的需求告知 PAM 后, PAM 就能够回报使用者验证的结果 (成功或失败)。由于 PAM 仅是一套验证的机制,又可以提供给其他程序所调用引用,因此不论你使用什么程序,都可以使用 PAM 来进行验证,如此一来,就能够让帐号密码或者是其他方式的验证具有一致的结果。

  PAM 用来进行验证的数据称为模块 (Modules),每个 PAM 模块的功能都不太相同。

5.3 PAM 模块设置语法

  PAM 借助一个与程序相同文件名的配置文件来进行一连串的认证分析需求。以 passwd 这个指令的调用 PAM 来说明好了。 当你执行 passwd 后,这支程序调用 PAM 的流程是:

  1. 使用者开始执行 /usr/bin/passwd 这支程序,并输入密码;
  2. passwd 调用 PAM 模块进行验证;
  3. PAM 模块会到 /etc/pam.d/ 找寻与程序 (passwd) 同名的配置文件;
  4. 依据 /etc/pam.d/passwd 内的设置,引用相关的 PAM 模块逐步进行验证分析;
  5. 将验证结果 (成功、失败以及其他信息) 回传给 passwd 这支程序;
  6. passwd 这支程序会根据 PAM 回传的结果决定下一个动作 (重新输入新密码或者通过验证!)

  重点其实是 /etc/pam.d/ 里面的配置文件,以及配置文件所调用的 PAM 模块进行的验证工作。既然一直谈到 passwd 这个密码修改指令,那我们就来看看 /etc/pam.d/passwd 这个配置文件的内容。

[root@study ~]# cat /etc/pam.d/passwd
#%PAM-1.0  <==PAM版本的说明而已!
auth       include      system-auth   <==每一行都是一个验证的过程
account    include      system-auth
password   substack     system-auth
-password   optional    pam_gnome_keyring.so use_authtok
password   substack     postlogin
验证类别   控制标准     PAM 模块与该模块的参数

  上面出现的“ include ”这个关键字,他代表的是“请调用后面的文件来作为这个类别的验证”, 所以,上述的每一行都要重复调用 /etc/pam.d/system-auth 那个文件来进行验证的意思。


第一个字段:验证类别 (Type)

  验证类别主要分为四种,分别说明如下:

  • auth

  authentication (认证) 的缩写,所以这种类别主要用来检验使用者的身份验证,这种类别通常是需要密码来检验的, 所以后续接的模块是用来检验使用者的身份。

  • account

  account (帐号) 则大部分是在进行 authorization (授权),这种类别则主要在检验使用者是否具有正确的使用权限, 举例来说,当你使用一个过期的密码来登陆时,当然就无法正确的登陆了。

  • session

  session (会话期间),所以 session 管理的就是使用者在这次登陆 (或使用这个指令) 期间,PAM 所给予的环境设置。 这个类别通常用在记录使用者登陆与登出时的信息。

  • password

  password 就主要在提供密码的验证修改工作。

  这四个验证的类型通常是有顺序的。


第二个字段:验证的控制标识(control flag)

  验证通过的标准,这个字段在管控该验证的放行方式,主要也分为四种控制方式:

  • required

  此验证若成功则带有 success (成功) 的标志,若失败则带有 failure 的标志,但不论成功或失败都会继续后续的验证流程。 由于后续的验证流程可以继续进行,因此相当有利于数据的登录 (log) ,这也是 PAM 最常使用 required 。

  • requisite

  若验证失败则立刻回报原程序 failure 的标志,并终止后续的验证流程。若验证成功则带有 success 的标志并继续后续的验证流程。 这个项目与 required 最大的差异,就在于失败就终止。

  • sufficient

  若验证成功则立刻回传 success 给原程序,并终止后续的验证流程;若验证失败则带有 failure 标志并继续后续的验证流程,与 requisits 刚好相反。

  • optional

  这个模块控制项目大多是在显示信息而已,并不是用在验证方面的。

5.4 常用模块简介

  登陆所需要的 PAM 流程为何:

cat /etc/pam.d/login

  可以看到,其实 login 也调用多次的 system-auth 

cat /etc/pam.d/system-auth

  详细的模块情报可以在你的系统中找到:

  • /etc/pam.d/*:每个程序的 PAM 配置文件;
  • /lib64/security/*:PAM 模块文件的实际放置目录;
  • /etc/security/*:其他 PAM 环境的配置文件;
  • /usr/share/doc/pam-*/:详细的 PAM 说明文档。

  CentOS 7 ,pam_nologin 说明文档在: /usr/share/doc/pam-1.1.8/txts/README.pam_nologin

5.5 其他相关文件

  PAM 相关文件都在/etc/security 这个目录内,介绍两个可能用到的:


limits.conf

  之前说过的 ulimit 功能中, 除了修改使用者的 ~/.bashrc 配置文件之外,其实系统管理员可以统一借由 PAM 来管理的,那就是 /etc/security/limits.conf 这个文件的设置了。

范例一:vbird1 这个用户只能创建 100MB 的文件,且大于 90MB 会警告
[root@study ~]# vim /etc/security/limits.conf
vbird1	soft		fsize		 90000
vbird1	hard		fsize		100000
#帐号   限制依据	限制项目 	限制值
# 第一字段为帐号,或者是群组!若为群组则前面需要加上 @ ,例如 @projecta
# 第二字段为限制的依据,是严格(hard),还是仅为警告(soft);
# 第三字段为相关限制,此例中限制文件大小,
# 第四字段为限制的值,在此例中单位为 KB。
# 若以 vbird1 登陆后,进行如下的操作则会有相关的限制出现!

[vbird1@study ~]$ ulimit -a
....(前面省略)....
file size               (blocks, -f) 90000
....(后面省略)....

[vbird1@study ~]$ dd if=/dev/zero of=test bs=1M count=110
File size limit exceeded
[vbird1@study ~]$ ll --block-size=K test
-rw-rw-r--. 1 vbird1 vbird1 90000K Jul 22 01:33 test
# 果然有限制到了

范例二:限制 pro1 这个群组,每次仅能有一个使用者登陆系统 (maxlogins)
[root@study ~]# vim /etc/security/limits.conf
@pro1   hard   maxlogins   1
# 如果要使用群组功能的话,这个功能似乎对初始群组才有效喔!而如果你尝试多个 pro1 的登陆时,
# 第二个以后就无法登陆了。而且在 /var/log/secure 文件中还会出现如下的信息:
# pam_limits(login:session): Too many logins (max 1) for pro1

  这个文件设置完成就生效了,不用重新启动任何服务。但是 PAM 有个特殊的地方,由于他是在程序调用时才予以设置的,因此你修改完成的数据, 对于已登陆系统中的使用者是没有效果的,要等他再次登陆时才会生效。


/var/log/secure, /var/log/messages

  如果发生任何无法登陆或者是产生一些你无法预期的错误时,由于 PAM 模块都会将数据记载在 /var/log/secure 当中。

6. Linux 主机上的使用者信息传递

  在多人使用同一Linux下的情况。

6.1 查询用户: w, who, last, lastlog

  之前就提过了 id, finger 等指令可以查询用户的信息,使用 last 可以查看用户最近的登录时间。

  那如果想要知道目前已登陆在系统上面的使用者呢?可以通过 w 或 who 来查询。

[root@study ~]# w
 01:49:18 up 25 days,  3:34,  3 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
dmtsai   tty2                      07Jul15 12days  0.03s  0.03s -bash
dmtsai   pts/0    172.16.200.254   00:18    6.00s  0.31s  0.11s sshd: dmtsai [priv]
# 第一行显示目前的时间、开机 (up) 多久,几个使用者在系统上平均负载等;
# 第二行只是各个项目的说明,
# 第三行以后,每行代表一个使用者。如上所示,dmtsai 登陆并取得终端机名 tty2 之意。

[root@study ~]# who
dmtsai   tty2         2015-07-07 23:07
dmtsai   pts/0        2015-07-22 00:18 (192.168.1.100)

  另外,如果想要知道每个帐号的最近登陆的时间,则可以使用 lastlog 这个指令,lastlog 会去读取 /var/log/lastlog 文件,结果将数据输出。

[root@study ~]# lastlog
Username         Port     From             Latest
root             pts/0                     Wed Jul 22 00:26:08 +0800 2015
bin                                        **Never logged in**
....(中间省略)....
dmtsai           pts/1    192.168.1.100    Wed Jul 22 01:08:07 +0800 2015
vbird1           pts/0                     Wed Jul 22 01:32:17 +0800 2015
pro3                                       **Never logged in**
....(以下省略)....

6.2 用户对谈: write, mesg, wall

   write 可以直接将讯息传给接收者。

  举例来说,Linux 目前有 vbird1 与 root 两个人在线上, 我的 root 要跟 vbird1 讲话,可以这样做:

[root@study ~]# write 使用者帐号 [使用者所在终端接口]

[root@study ~]# who
vbird1   tty3         2015-07-22 01:55  <==有看到 vbird1 在线上
root     tty4         2015-07-22 01:56  

[root@study ~]# write vbird1 pts/2
Hello, there:
Please don't do anything wrong...  <==这两行是 root 写的信息!
# 结束时,请按下 [crtl]-d 来结束输入。此时在 vbird1 的画面中,会出现:

Message from root@study.centos.vbird on tty4 at 01:57 ...
Hello, there:
Please don't do anything wrong...
EOF

  立刻会将信息传给 vbird1 ,不过如果当 vbird1 正在查数据,这些信息会立刻打断 vbird1 原本的工作。所以,如果 vbird1 这个人不想要接受任何讯息,直接下达这个动作:


[vbird1@study ~]$ mesg n
[vbird1@study ~]$ mesg
is n

  不过,这个 mesg 的功能对 root 传送来的信息无效,所以如果是 root 传送讯息, vbird1 还是得要收下。

  但是如果 root 的 mesg 是 n 的,那么 vbird1 写给 root 的信息会变这样:

[vbird1@study ~]$ write root
write: root has messages disabled

  如果想要解开的话,再次下达“ mesg y ”就好啦!想要知道目前的 mesg 状态,直接下达“ mesg ”即可。

  如果对所有系统上面的用户传送简讯 (广播)”,用 wall 即可啊!他的语法也是很简单:

[root@study ~]# wall "I will shutdown my linux server..."

  所有的人都会收到这个简讯,连发送者自己也会收到。

6.3 使用者邮件信箱: mail

  使用 wall, write 毕竟要等到使用者在线上才能够进行,有没有其他方式来联络? 不是说每个 Linux 主机上面的使用者都具有一个 mailbox 吗? 我们可以寄、收 mailbox 内的信件。一般来说, mailbox 都会放置在 /var/spool/mail 里面,一个帐号一个 mailbox (文件)。

  寄信可以这么写 mail -s "邮件标题" username@localhost  一般来说,如果是寄给本机上的使用者,基本上,连“ @localhost ”都不用写。

[root@study ~]# mail -s "nice to meet you" vbird1
Hello, D.M. Tsai
Nice to meet you in the network.
You are so nice.  byebye!
.    <==这里很重要喔,结束时,最后一行输入小数点 . 即可!
EOT
[root@study ~]#  <==出现提示字符,表示输入完毕了!

  还可以使用数据量重导向来完成。

mail -s "nice to meet you" vbird1 < filename 

  收信的话,输入 mail

[vbird1@study ~]$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/vbird1": 1 message 1 new
>N  1 root                  Wed Jul 22 02:09  20/671   "nice to meet you"
&  <==这里可以输入很多的指令,如果要查阅,输入 ? 即可!

  在 mail 当中的提示字符是 & 符号,这封信件的前面那个 > 代表目前处理的信件,而在大于符号的右边那个 N 代表该封信件尚未读过。

  如果我想要知道这个 mail 内部的指令有哪些,可以在 & 之后输入“ ? ”,就可以看到如下的画面:

& ?
               mail commands
type <message list>             type messages
next                            goto and type next message
from <message list>             give head lines of messages
headers                         print out active message headers
delete <message list>           delete messages
undelete <message list>         undelete messages
save <message list> folder      append messages to folder and mark as saved
copy <message list> folder      append messages to folder without marking them
write <message list> file       append message texts to file, save attachments
preserve <message list>         keep incoming messages in mailbox even if saved
Reply <message list>            reply to message senders
reply <message list>            reply to message senders and all recipients
mail addresses                  mail to specific recipients
file folder                     change to another folder
quit                            quit and apply changes to folder
xit                             quit and discard changes made to folder
!                               shell escape
cd <directory>                  chdir to directory or home if none given
list                            list names of all available commands

  <message list> 指的是每封邮件的左边那个数字,几个比较常见的指令是:

7. CentOS 7 环境下大量创建帐号

7.1 帐号相关的检查工具

  先来检查看看使用者的主文件夹、密码等数据有没有问题?这时会使用到的主要有 pwck 以及 pwconv / pwuconv 等。


pwck

  pwck 这个指令会检查 /etc/passwd 这个帐号配置文件内的信息,与实际的主文件夹是否存在等信息, 还可以比对 /etc/passwd 与 /etc/shadow 的信息是否一致,另外,如果 /etc/passwd 内的数据字段错误时,会提示使用者修改。 一般来说,只利用这个来检查输入是否正确。

[root@study ~]# pwck
user 'ftp': directory '/var/ftp' does not exist
user 'avahi-autoipd': directory '/var/lib/avahi-autoipd' does not exist
user 'pulse': directory '/var/run/pulse' does not exist
pwck: no changes

  上面仅是告知我,这些帐号并没有主文件夹,由于那些帐号绝大部分都是系统帐号,确实也不需要主文件夹的,所以,那是“正常的错误!”。

  相对应的群组检查可以使用 grpck 这个指令。


pwconv

  这个指令主要的目的是在“将 /etc/passwd 内的帐号与密码,移动到 /etc/shadow 当中。早期的 Unix 系统当中并没有 /etc/shadow。

  使用 pwconv 后,可以:

  • 比对 /etc/passwd 及 /etc/shadow ,若 /etc/passwd 内存在的帐号并没有对应的 /etc/shadow 密码时,则 pwconv 会去 /etc/login.defs 取用相关的密码数据,并创建该帐号的 /etc/shadow 数据;
  • 若 /etc/passwd 内存在加密后的密码数据时,则 pwconv 会将该密码栏移动到 /etc/shadow 内,并将原本的 /etc/passwd 内相对应的密码栏变成 x !

  一般来说,如果正常使用 useradd 增加使用者时,使用 pwconv 并不会有任何的动作。不过,如果手动设置帐号,这个 pwconv 就很重要。


pwunconv

  相对于 pwconv , pwunconv 则是将 /etc/shadow 内的密码栏数据写回 /etc/passwd 当中, 并且删除 /etc/shadow 文件。

  最好不要使用!


chpasswd

  chpasswd 可以“读入未加密前的密码,并且经过加密后, 将加密后的密码写入 /etc/shadow 当中。”这个指令很常被使用在大量创建帐号的情况中。他可以由 Standard input 读入数据,每笔数据的格式是“ username:password ”。

  举例来说,我的系统当中有个使用者帐号为 vbird3 ,我想要更新他的密码 (update) , 假如他的密码是 abcdefg 的话,那么我可以这样做:

echo "vbird3:abcdefg" | chpasswd

7.2 大量创建帐号范本(适用 passwd --stdin 选项)

  简单的 script 来执行新增用户。

[root@study ~]# vim accountadd.sh
#!/bin/bash
# This shell script will create amount of linux login accounts for you.
# 1. check the "accountadd.txt" file exist? you must create that file manually.
#    one account name one line in the "accountadd.txt" file.
# 2. use openssl to create users password.
# 3. User must change his password in his first login.
# 4. more options check the following url:
# 0410accountmanager.html#manual_amount
# 2015/07/22    VBird
export PATH=/bin:/sbin:/usr/bin:/usr/sbin

# 0. userinput
usergroup=""                   # if your account need secondary group, add here.
pwmech="openssl"               # "openssl" or "account" is needed.
homeperm="no"                  # if "yes" then I will modify home dir permission to 711

# 1. check the accountadd.txt file
action="${1}"                  # "create" is useradd and "delete" is userdel.
if [ ! -f accountadd.txt ]; then
	echo "There is no accountadd.txt file, stop here."
        exit 1
fi

[ "${usergroup}" != "" ] && groupadd -r ${usergroup}
rm -f outputpw.txt
usernames=$(cat accountadd.txt)

for username in ${usernames}
do
    case ${action} in
        "create")
            [ "${usergroup}" != "" ] && usegrp=" -G ${usergroup} " || usegrp=""
            useradd ${usegrp} ${username}               # 新增帐号
            [ "${pwmech}" == "openssl" ] && usepw=$(openssl rand -base64 6) || usepw=${username}
            echo ${usepw} | passwd --stdin ${username}  # 创建密码
            chage -d 0 ${username}                      # 强制登陆修改密码
            [ "${homeperm}" == "yes" ] && chmod 711 /home/${username}
	    echo "username=${username}, password=${usepw}" >> outputpw.txt
            ;;
        "delete")
            echo "deleting ${username}"
            userdel -r ${username}
            ;;
        *)
            echo "Usage: $0 [create|delete]"
            ;;
    esac
done

  接下来只要创建 accountadd.txt 这个文件即可。

[root@study ~]# vim accountadd.txt
std01
std02
std03
std04
std05

[root@study ~]# sh accountadd.sh create
Changing password for user std01.
passwd: all authentication tokens updated successfully.
....(后面省略)....

 

posted @ 2022-11-28 11:31  莫莫君不恋爱  阅读(173)  评论(0编辑  收藏  举报