在最近完成老师布置的作业的时候遇到了如何让shell脚本中的命令自动判断一个用户是否已设置密码的问题,虽然看似不是很难的一个问题,但是在这一功能实现的过程中却包含了许多细小的而重要的知识。刚开始小编对此很是头疼,虽然我们查看一个用户是否有密码并不是很难,直接cat /etc/shadow这个文件看看密码位是否有加密的字符就行了,但是让命令自己去判断和匹配就不是很顺利了,小编上网查看后,并没有得到很好的答案,大多数都是人工查看的答案,并不适用于shell脚本中自动的判断,所以在认真对比/etc/passwd 和/etc/shadow这两个文件之后,又结合自己的想法,实现了这个自动判断的功能,接下来小编将我这一过程实现中遇到的问题和扩展的知识,罗列出来,以便于给像小编一样没有在网上找到合适答案的童鞋们参考,本文纯属个人思考产物,如有更好方法,请赐教。
我们知道用户的密码是存储到/etc/passwd和/etc/shadow这两个文件中的,为什么这么说呢?因为当系统开启了用户的投影密码后,才会把密码映射到shadow这个文件中,如果没有开启投影密码,则用户的密码是保存在passwd 这个文件中的,为了提高系统的安全性,一般这个功能是默认开启的,但是我们可以手动将其关闭:pwconv开启投影密码,pwunconv关闭投影密码。
为了接下来的命令实现,小编在这里将passwd文件和shadow文件的关系进行图形化的详细分析,以便小伙伴们能看懂:
如果没有开启影子密码功能,则不会存在shadow这个文件,密码就被保存在了passwd文件的密码位上,此时,创建的用户一直都没有设置密码的情况下,该密码位是两个!!符号,如果用户的密码通过passwd -d username这个命令给清空的话,该密码位上没有任何东西。
如果开启了影子密码功能,passwd中密码位的密码将会投射到shadow中,同样,如果用户还没设置过密码,则密码位为两个!!符号,如果用户的密码通过passwd -d username清空了的话,在shadow的密码位上为空。
有图有真相:
存在上述的两种情况啊!针对shell脚本而言,编写的脚本要有较高的准确性和可移植性,所以命令的执行一定要有绝对的把握,如果我们定义查看匹配shadow文件,那如果有的主机上没有开启影子密码功能,那么找不到shadow这个文件,命令的执行结果就不对了,所以为了保证命令的绝对性,小编采用如下思想:
不管系统有没有开启影子投射功能,我们在进行筛选判断之前,先执行pwconv命令开启影子密码功能。这样一来,我们就完全的确定了密码存在于shadow文件中,我们就可以针对shadow文件进行一些操作。
没有密码的情况有两种,一种是密码位为空,一种是密码位一个!或!!,一个!是因为该用户被锁定了。如果用户有密码的情况是密码位为:“$加密方式编号$salt$密码位” 所以我们可以将密码位的参数提取出来运用正则表达式进行对比,如果不是“$加密方式编号$salt$密码位”形式的参数,就说明该用户没有密码。
开启影子密码的命令为:pwconv
提取shadow文件中密码位参数的命令为:getent shadow |grep ^username |cut -d: -f2
将取出的参数进行匹配,判断出是否有密码:[[ "$(pwconv ;getent shadow |grep ^username |cut -d: -f2)" =~ ^'$'.* ]] && echo true || echo false
该命令中使用到了:
$( ):调用括号中的命令执行的结果
[[ ]]:条件测试,可以进行条件测试的还有 [ ],但是我们使用到了扩展正则表达式,而[ ]不支持引用正则表达式,所以我们使用双引号的条件测试符。
=~:该符号是进行字符串的测试,含义为:左侧字符串是否能够被右侧的PATTERN所匹配。
&&:根据退出状态而定,命令可以有条件地运行,代表条件性的AND THEN ,根据前一条命令的返回值来判断,返回值为真(0),则执行自身后面的命令。
|:代表条件性的OR ELSE,若前一条命令的返回值为假(非0),则执行自身后面的命令。
命令执行的结果为:(两种结果展示)
我们可以可以将用户名设置为一个变量,通过传递的用户名参数,实现指定用户的查看,将这个方法用户在shell脚本中,就可以进行有条件的判断了。嘻嘻~