getspnam函数可以根据用户名返回对应shadow文件中的信息,函数原型为struct spwd *getspnam(char *name);,头文件为shadow.h。返回的信息存储在spwd结构中,
struct spwd {
char *sp_namp; /* Login name. */
char *sp_pwdp; /* Encrypted password. */
long int sp_lstchg; /* Date of last change. */
long int sp_min; /* Minimum number of days between changes. */
long int sp_max; /* Maximum number of days between changes. */
long int sp_warn; /* Number of days to warn user to change
the password. */
long int sp_inact; /* Number of days the account may be
inactive. */
long int sp_expire; /* Number of days since 1970-01-01 until
account expires. */
unsigned long int sp_flag; /* Reserved. */
};
其中sp_pwdp就是密钥,密钥长这样子:$1$myX2OIuo$3nLxWwvMqq/U44oqgDcRW1,对应的格式为$id$salt$encode,
id的值的含义是
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
那么例子里两个美元符号夹着的1就代表MD5了。
crypt函数将明文加密,原型为char * crypt (const char *key,const char * salt);
这里的key就是你密码的明文了。但是这里的salt和上面$id$salt$encode有很大的迷惑性,crypt中的salt指的是$id$salt,就是$1$myX2OIuo$3nLxWwvMqq/U44oqgDcRW1中的$1$myX2OIuo这一段,crypt加密后得到的密文也不是$id$salt$encode中的encode,而是$id$salt$encode本身,也就是说crypt加密后会得到$1$myX2OIuo$3nLxWwvMqq/U44oqgDcRW1。从getspnam中得到密文,再用明文通过crypt加密得到密文,两个密文对比,就可以校验用户输入的密码是否正确了。
使用crypt时需要加上-lcrypt编译参数