实际上本篇的内容与上篇是前后关联的,因为篇幅原因拆分成了两篇发布。
使用者的特殊shell与PAM模块
/sbin/nologin
像之前说的,在账户设置中使用作为登录用shell的账号将不能登录。特别的,如果需要给这些用户在不能登录时显式特定的内容,可以将内容写入/etc/nologin.txt
:
[root@xyz ~]# usermod -s '/sbin/nologin' user1
[root@xyz ~]# echo 'you use a shell without login' >> /etc/nologin.txt
[root@xyz ~]# cat /etc/nologin.txt
you use a shell without login
如果使用user1
进行登录,将看到:
❯ ssh user1@192.168.1.105
user1@192.168.1.105's password:
Last login: Sat Aug 21 17:29:44 2021
you use a shell without login
Connection to 192.168.1.105 closed.
当然,如果有必要,记得将
user1
的登录用shell修改回来。
PAM
PAM的全称是Pluggable Authentication Modules(插入式验证模块)。实际上PAM是一组API,可以定制验证流程,并在程序的实际运行中调用以完成身份验证。
PAM设置
通常,我们会为PAM添加一个与程序同名的配置文件作为验证流程的配置项,比如当你执行passwd
时,涉及身份验证的部分的执行流程是这样的:
-
执行
/bin/passwd
,并输入密码。 -
调用PAM进行验证工作。
-
PAM从
/etc/pam.d/
目录中寻找与passwd
同名的配置文件,并加载。 -
根据加载的配置内容,调用相应的PAM模块完成验证工作。
-
将验证结果返回给
passwd
程序。
如果查看/etc/pam.d/passwd
,其内容如下:
[root@xyz ~]# cat /etc/pam.d/passwd
#%PAM-1.0
auth include system-auth
account include system-auth
password substack system-auth
-password optional pam_gnome_keyring.so use_authtok
password substack postlogin
内容包含三列信息,分别是:验证类型,控制标识以及模块。
验证类型
验证类型主要分为以下几种:
-
auth
auth(authentication)主要用于验证用户身份,通常需要使用密码。
-
account
主要用于授权,检验用户是否有相应的权限。
-
session
用于管理该次命令执行时PAM设置的环境信息。
-
password
提供验证的修订任务,主要是修改密码。
需要说明的是这四种验证类型通常是有执行顺序的,通常需要先进行身份验证(auth),通过后才会进行授权(account),然后才是管理环境信息(session),最后根据需要可能会修改密码(password)。但这也并不绝对。
验证控制标识
验证控制标识(control flag)的作用有点像编程语言或shell scripts
中的控制流程,即使用不同的控制标识可以控制其后的验证模块的执行过程。
看完主要的控制标识介绍你就会明白我说的是什么意思:
-
required
无论成功失败,都将继续后续的验证流程。通常用于日志功能。
-
requisite(必要)
如果失败,则立即终止验证流程,并返回
failure
,如果成功,继续验证流程。 -
sufficient(充分)
如果成功,则立即终止验证流程,并返回
success
,如果失败,则继续验证流程。与requisite
逻辑相反。 -
optional
大多数情况下只起显式信息的作用,不影响验证流程。
那个include
并非控制标识,而是类似于C++或PHP中的效果,可以使用include
加载额外的PAM配置。
常用模块简介
PAM相关的文件主要有:
-
/etc/pam.d/*
:PAM配置文件 -
/lib64/security/*
:PAM模块文件 -
/etc/security/
:PAM环境配置文件 -
/usr/share/doc/pam-*/
:PAM说明文件
下面通过login
程序介绍主要的PAM模块。
先查看login
的PAM配置:
[root@xyz ~]# cat /etc/pam.d/login
#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth substack system-auth
auth include postlogin
account required pam_nologin.so
account include system-auth
password include system-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
session optional pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session include system-auth
session include postlogin
-session optional pam_ck_connector.so
用到的PAM模块主要有:
-
pam_securetty.so
:限制管理员仅能从安全的终端登录。 -
pam_nologin.so
:控制一般用户能否登录主机,当存在/etc/nologin
文件时,root
以外的所有用户都将不能登录Linux主机。 -
pam_selinux.so
:通过这个模块,可以暂时关闭SELinux
功能,并可以在验证通过后开启。 -
pam_loginuid.so
:这个模块可以验证登录的UID是否符合要求(大于1000)。 -
pam_console.so
:可以帮助用户在特殊情况下通过特殊的终端接口进行登录。 -
pam_env.so
:用于设置环境变量。 -
pam_unix.so
:功能相当丰富,包括账户认证、账户权限管理、日志记录等。 -
pam_pwquality.so
:检验密码强度。 -
pam_limits.so
:之前提到过的ulimit
命令使用的就是该模块提供的功能。
其它相关文件
limits.conf
之前有提到过ulimit
命令,事实上管理员可以通过修改/etc/security/limits.conf
的方式对Linux主机上的用户使用的容量限制进行统一设置,实质上这都是利用pam_limits.so
这个PAM模块的功能实现的。
假设我们要限制user1
可以创建的单一文件大小:
[root@xyz ~]# vim /etc/security/limits.conf
...省略...
#@faculty hard nproc 50
#ftp hard nproc 0
#@student - maxlogins 4
user1 soft fsize 90000
user1 hard fsize 100000
# End of file
这个配置文件中的数据字段的含义为:
-
用户名或用户组(用户组前要加一个符号
@
)。 -
限制方式,
hard
为严格,soft
为警告。 -
限制类型,
fsize
为对单一文件大小进行限制。 -
限制值,这个例子中单位为kb。
所以上边修改的配置含义为:限制user1
可以建立的单一文件大小,最大为100M,超过90M会发出警告。
下面进行测试:
[user1@xyz tmp]$ dd if=/dev/zero of=limit_test bs=1MB count=110
文件大小超出限制(吐核)
[user1@xyz tmp]$ ll -h limit_test
-rw-rw-r--. 1 user1 user1 88M 8月 22 12:12 limit_test
可以看到dd
命令创建的文件只有88M就被终止了。
除此之外,还可以添加一些其它的限制,比如说限制用户同时可登录数目。因为Linux系统是多用户系统,并且同一个账号同时可以有多个人同时登录,而我们可以加上限制,某个账号同一时间只允许一个人登录:
@user1 hadr maxlogins 1
这里不是直接使用用户名,而是用其主用户组进行限制,只是为了展示如何通过用户组进行限制。此类限制似乎只有用主用户组才会生效。
在已经有一个user1
连接的基础上打开一个新的user1
连接:
❯ ssh user1@192.168.1.105
user1@192.168.1.105's password:
Too many logins for 'user1'.
Last login: Sun Aug 22 12:10:20 2021 from icexmoon-book
Connection to 192.168.1.105 closed.
可以看到,会提示这个用户的登录数过多。
Linux 主机上的用户信息传递
下面说明Linux主机上不同用户进行通讯的相关内容。
查询用户
如果想知道当前Linux主机上有哪些已经登录的用户,可以使用w
或who
命令:
[root@xyz ~]# w
13:45:45 up 3:04, 2 users, load average: 0.08, 0.04, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
icexmoon pts/0 icexmoon-book 10:05 1.00s 0.83s 0.62s sshd: icexmoon [priv]
user1 pts/1 icexmoon-book 12:10 8:33 0.09s 0.09s -bash
[root@xyz ~]# who
icexmoon pts/0 2021-08-22 10:05 (icexmoon-book)
user1 pts/1 2021-08-22 12:10 (icexmoon-book)
w
比who
命令输出的信息更多一些。
此外,如果想知道每个用户最后一次登录系统的时间,可以使用lastlog
命令:
[root@xyz ~]# lastlog | grep -v '从未登录' 用户名 端口 来自 最后登陆时间 root pts/0 日 8月 22 10:06:40 +0800 2021 gdm :0 日 8月 22 09:58:05 +0800 2021 sshd pts/0 六 8月 21 16:09:43 +0800 2021 icexmoon pts/0 icexmoon-book 日 8月 22 10:05:58 +0800 2021 user1 pts/2 icexmoon-book 日 8月 22 13:41:20 +0800 2021 chagetest pts/1 icexmoon-book 五 8月 20 21:01:39 +0800 2021 myuser1 pts/1 六 8月 21 19:38:13 +0800 2021 pro1 pts/1 六 8月 21 16:57:34 +0800 2021
事实上这个命令是读取的/etc/log/lastlog
文件获取的登录信息。
用户通信
用户之间如果需要互相发送消息,可以使用write
这个命令:
[root@xyz ~]# who
icexmoon pts/0 2021-08-22 10:05 (icexmoon-book)
user1 pts/1 2021-08-22 12:10 (icexmoon-book)
[root@xyz ~]# write user1 pts/1
Hellow,user1
I'm the system administrator.
write
命令后需要指定用户名和终端(因为一个用户是可以多个终端同时登录的),在输入完信息后需要按Ctrl+D
输入EOF字符以结束输入。
此时在user1
的连接中就可以看到:
[user1@xyz tmp]$
Message from icexmoon@xyz.icexmoon.centos (as root) on pts/0 at 13:52 ...
Hellow,user1
I'm the system administrator.
EOF
这有可能会影响你正在执行的操作,如果你不希望收到别人发来的消息,可以:
[user1@xyz tmp]$ mesg n
[user1@xyz tmp]$ mesg
is n
如果此时用其它普通用户给user1
发送消息:
[myuser1@xyz ~]$ write user1 pts/1
write: user1 has messages disabled on pts/1
当然,这并不能阻止root
发送消息。
如果需要再次启用消息接收功能,可以:
[user1@xyz tmp]$ mesg y
[user1@xyz tmp]$ mesg
is y
mesg
是一对一进行消息发送,如果你相对所有人进行广播,可以:
[user1@xyz tmp]$ wall 'Hellow, everyone.'
[user1@xyz tmp]$
Broadcast message from user1@xyz.icexmoon.centos (pts/1) (Sun Aug 22 14:01:13 2021):
Hellow, everyone.
当前登录的所有用户都会收到这个消息。
用户邮箱
除了向其它用户发送短消息,还可以通过邮件进行通信:
[user1@xyz tmp]$ mail -s 'my first mail' myuser1
Hellow, this is my first mail.
How are you.
.
EOT
理论上mail
命令需要指明邮件地址,即xxx@hostname
之类的带主机名的邮件地址,但如果是写信给本地Linux主机的其它用户,则只需要用户名即可。
此外,邮件正文写完后可以用单独一行输入一个英文句号.
作为结束符号,会自动结束输入。
邮件发送后,接受方刷新一下Bash终端就会收到这样的提示:
您在 /var/spool/mail/myuser1 中有新邮件
[myuser1@xyz ~]$
除了从键盘输入邮件内容,也可以使用stdin重定向符号使用已有文件作为内容进行发送:
[myuser1@xyz ~]$ mail -s 'passwd file contents' user1 < /etc/passwd
mail
命令同样用于查收邮件:
[myuser1@xyz ~]$ mail
Heirloom Mail version 12.5 7/5/10. Type ? for help.
"/var/spool/mail/myuser1": 1 message 1 new
>N 1 user1@xyz.icexmoon.c Sun Aug 22 14:03 19/643 "my first 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
A <message list> consists of integers, ranges of same, or other criteria
separated by spaces. If omitted, mail uses the last message typed.
其中比较重要的命令有:
-
h
:列出邮件标题,如果要列出第10封邮件的标题,可以h 10
。 -
d
:删除邮件,如果要删除第10封邮件,可以d 10
,如果删除20~30封邮件,可以d 20-30
。 -
s
:将邮件存储为文件,如果要保存第5封邮件,可以s 5 ~/mail.file.bak
。 -
x
:不执行任何操作退出。 -
q
:执行所有操作后退出。
mail
处理邮件时的操作逻辑类似于分区,所有的删除等操作并非会立即执行,而是在退出时根据你的退出方式再决定是否一起执行变更操作。
批量创建账号
账号相关的检查工具
pwck
pwck
(passwd check)命令可以帮助检查/etc/passwd
文件格式是否正常,以及其中设置的家目录是否存在等,此外还会比对/etc/passwd
和/etc/shadow
中的内容是否一致:
[root@xyz ~]# pwck
用户“ftp”:目录 /var/ftp 不存在
用户“saslauth”:目录 /run/saslauthd 不存在
用户“pulse”:目录 /var/run/pulse 不存在
用户“gluster”:目录 /run/gluster 不存在
用户“gnome-initial-setup”:目录 /run/gnome-initial-setup/ 不存在
用户“user3”:目录 /home/user3 不存在
pwck:无改变
[root@xyz ~]# grep user3 /etc/passwd
user3:x:988:982::/home/user3:/bin/bash
myuser3:x:1504:1506:3rd user:/home/myuser3:/sbin/nologin
[root@xyz ~]# ll -d /home/user3
ls: 无法访问/home/user3: 没有那个文件或目录
的确缺少/home/user3
目录。其它诸如ftp
等目录的缺失都不需要担心,因为这些是非登录的系统用户。
pwconv
pwconv
的用途是将/etc/passwd
中的密码移动到/etc/shadow
中。
我们之前说过,早期的Linux是将密码直接写入/etc/passwd
的,但后来已经改为写入/etc/shadow
了,但如果你有系统迁移的需求,要从早期Linux版本改为比较新的版本,需要处理这种问题,就可能需要pwconv
这个工具。
pwunconv
pwunconv
的作用正好与pwconv
相反,会将/etc/shadow
中的密码移动到/etc/passwd
中。
或许某些需要从新版本Linux改回老版本的情况下会用到此工具?总之如果没有需要,不要随便尝试,会把当前系统搞坏掉。
chpasswd
虽然CentOS7的passwd
命令本身已经支持--stdin
参数,可以结合管道命令直接设置密码,但某些Linux发行版是不支持此参数的,当然也就不能结合管道命令那么使用。但是chpasswd
可以实现同样的效果:
[root@xyz ~]# echo 'user1:password' | chpasswd
用shell脚本批量创建账号
结合上一篇内容和本篇内容,以及中的内容,我们就可以通过编写Shell
脚本的方式批量创建账号。
下面是我编写的批处理脚本(部分参考了《鸟哥的私房菜》中的写法):
#!/bin/bash
# auto create accounts
function getRandomPassword(){
new_password=''
for i in $(seq 1 10)
do
declare -i random_num=$RANDOM*10/32767
new_password=${new_password}${random_num}
done
}
action=$1
account_names=$(cat ./account_names.txt)
echo "accounts\tpassword" > ./accounts_password.txt
for account_name in $account_names
do
if [ "${action}" == 'create' ]
then
getRandomPassword
random_password=$new_password
useradd $account_name
echo $random_password | passwd --stdin $account_name
chage -d 0 $account_name
echo $account_name"\t"$random_password >> ./accounts_password.txt
echo "account ${account_name} is created"
elif [ "$action" == 'delete' ]
then
userdel -r $account_name
echo "account ${account_name} is deleted"
else
:
fi
done
使用脚本进行批量创建(预先需要在./account_names.txt
中写入账号名称):
[root@xyz shell_scripts]# sh create_accounts.sh create
更改用户 student1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
account student1 is created
更改用户 student2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
account student2 is created
更改用户 student3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
account student3 is created
[root@xyz shell_scripts]# cat accounts_password.txt
accounts\tpassword
student1\t6585224301
student2\t2545494826
student3\t9444627632
使用创建好的账号和密码登录系统:
❯ ssh student1@192.168.1.105
student1@192.168.1.105's password:
You are required to change your password immediately (root enforced)
WARNING: Your password has expired.
You must change your password now and login again!
更改用户 student1 的密码 。
为 student1 更改 STRESS 密码。
(当前)UNIX 密码:
登录后会被要求立即修改密码,完美。
最后还可以使用脚本批量将创建的账号删除:
[root@xyz shell_scripts]# sh create_accounts.sh delete
account student1 is deleted
account student2 is deleted
account student3 is deleted
文章评论