【P.S.】使用python版本为2.7~py3有点小惊喜哦(我不写C,原因暂不深究了)
1.一个基本用户验证接口无非包括两点:用户名、密码
2.在密码部分还需要考虑输入不显示提高安全性
大体只要实现这两点功能,乞丐版功能便做完了。
对于第一点:
Linux系统的用户及认证信息,保存在passwd和shadow文件中,可以轻易通过遍历文件内容行对用户名进行辨别,当然,也可以使用python内置模块pwd对用户名进行辨别。不幸的是,Linux中的密码字段的信息是加密的,在文件中体现的形式要么是一个x字符,要么是一个哈希值。获取正确密码对输入密码做匹配成了重中之重。首先可以明确,获取正确的明文密码是肯定不可能的。一开始自然以为可以通过查找官方文档找到对应的摘要算法对输入的密码进行摘要对比就可以了,但实际上也是不可能的。Linux生成的密码摘要并不是单纯的密码字符的摘要,是密码字符串加一个随机的salt字符串一起进行hash,so,放弃吧。
通过查找Linux相关资料,看到《UNIX高级编程》这么个宝贝,虽然不会写C,但是乍一看发现Linux是有库支持将输入字符串hash的,只要再跟正确密码hash值一对比就可以了。于是思路清晰,python跟C混编,通过调用C动态链接库调用系统接口。
对于第二点
输入密码不显示以提高安全性,可以通过python内置的getpass模块实现。
上代码:(●ˇ∀ˇ●)
[C接口文件:auth.c]
// Author: BaoJunxian
// Date: 2018/11/29
#include <shadow.h>
// Call Format: auth(<user>, <passwd>)
// Return 0 if success.
int auth(char *user, char *passwd){
char *obtpwd;
struct spwd *spasswd;
spasswd = getspnam(user);
obtpwd = crypt(passwd, spasswd->sp_pwdp);
if(strcmp(spasswd->sp_pwdp, obtpwd) == 0)
return 0;
else return 1;
}
注意:
执行命令gcc -o auth.so --shared -fPIC auth.c -lcrypt
生成用户验证使用的动态链接库文件auth.so
[python程序文件:login.py]
# coding=utf-8
# Author : BaoJunxian
# Date : 11/29/18
import ctypes, pwd, getpass
cAPI = ctypes.cdll.LoadLibrary
lib = cAPI('./auth.so')
def login():
user = raw_input('User:').strip()
try:
pwd.getpwnam(user)[0]
except KeyError:
print('User not existed.')
return False
for i in range(3):
passwd = getpass.getpass('password:')
if not lib.auth(user,passwd):
break
print('Password not correct.')
else:
print('Log in failed.')
return False
print('Login successfully.')
return True
if __name__ == '__main__':
login()
如此便大功告成,来验证一下:
[root@kilo-k5-controller test]# python login.py
User:re
User not existed.
[root@kilo-k5-controller test]# python login.py
User:root
password:
Password not correct.
password:
Password not correct.
password:
Password not correct.
Log in failed.
[root@kilo-k5-controller test]# python login.py
User:root
password:
Login successfully.
功能完好,perfect!