1.密码文件、shadow密码文件和组文件
系统密码文件/etc/passwd,每行包含7个字段:
mtk:x:1000:100:Michael Kerrisk:/home/mtk:bin/bash
- 登录名
- 经过加密的密码,实际存储到shadow密码文件中
- 用户ID
- 组ID
- 注释
- 主目录,用户登陆后所处的初始路径
- 登录shell
组文件 /etc/group,每条记录包含4个字段:
jambit:x:106:claus,felli,frank....
- 组名
- 经过加密的组密码
- 组ID
- 用户列表
2.获取用户和组的信息
2.1 从etc/passwd文件获取记录
struct passwd *getpwnam(const char *name); //name参数为用户名
name 提供一个登录名,getpwnam()函数就会返回一个指针,指向如下类型的结构,其
中包含了与密码记录相对应的信息:
struct passwd{
char *pw_name;
char *pw_passwd
uid_t pw_uid
...
}
注意仅当未启用 shadow 密码的情况下,pw_passwd 字段才会包含有效信息。
2.2 从etc/group文件中获取记录
struct group *getgrname(const char *name); //name参数为组名
getgrname函数返回指针指向结构体:
struct group{
char *gr_name;
char *gr_passwd;
....
}
2.3 遍历etc/passwd文件
struct passwd *pwd;
while((pwd = getpwent()) != NULL)
printf(...)
endpwent();
如上代码段,遍历密码文件使用getpwent()函数,处理完毕后,使用endpwent()将其关闭。
2.4从shadow文件中获取记录
struct spwd *getspnam(const char *name);
返回指针指向的结构体为spwd,不详细给出了
3.用户验证的过程与程序示例
过程:
程序首先读取用户名,然后会获取相应的密码记录以及(如开启了 shadow 密码功能)shadow 密码记录。若未能发现密码记录,或程序没有权限读取 shadow 密码文件,该程序会打印一条错误消息并退出。接下来,该程序会使用 getpass()函数,读取用户密码,使用 getpass()读取密码之后,对密码进行验证—使用 crypt()加密密码,并将结果与 shadow 密码文件中经过加密的密码记录进行比对。
示例程序:
char *usrname;*password;
struct passwd *pwd;
struct spwd *spwd;
printf("Username: ");
fflush(stdout);
if(fgets(username,lnmax,stdin) == NULL) //获取用户名
exit(EXIT_FAILURE)
...
pwd=getpwnam(username); //获取passwd记录
if(pwd==NULL)
exit(FATAL);
spwd=fetspnam(username); //获取shadow文件记录
if(spwd ==NULL && errno ==EACCES) //无权限获取shadow
exit(...);
if(spwd != NULL) //能获取到shadow记录就使用shadow密码
pwd->pw_passwd = spwd ->sp_pwdp
password = getpass("password: "); //获取用户输入密码
encrypted =ctypt(password,pwd->pw_passwd); //用户密码加密计算
...
authok=strcmp(encrypted,pwd->pw_passwd)==0; //加密计算的结果与shadow的记录进行比对
if(!authok){
...
}