linux编程手册第8章用户和组

时间:2022-07-25 04:45:26

1.密码文件:/etc/passwd
该文件保存了各个用户的一些信息,按顺序包括:登录名,经过加密的密码,用户ID(UID),组ID(GID),注释,主目录,登陆shell,用冒号分隔。
登陆名:登陆系统时,输入的唯一登陆名。
经过加密的密码:该字段包含的是经过加密处理的密码,长度为13个字节。如果启用了shadow密码(常规做法),则该字段一般为x,真正的加密密码存放在/etc/shadow文件中。目的就是为了将密码和其他字段分开存放,shadow文件只有特权用户才可以访问。
UID:用户的数值型ID,0表示超级用户,就是root。
GID:组ID,用户属组中首选属组的id。
注释:描述性文字。
主目录:用户登录后所处的初始目录,会以该字段内容来设置HOME
环境变量。
登录shell:
2.shadow文件:
开始的时候没有shadow文件,加密的密码存放在passwd文件中,由于很多进程需要读取passwd文件的其他字段,所以passwd文件需要对所有用户开放,这样就导致所有用户都可以获取加密后的密码,给密码攻击提供了便利,所以后来将加密后的密码单独放入shadow文件中。shadow文件只对特权程序开放。
shadow文件包含登录名,经过加密的密码,以及若干与安全相关的字段。
3.组文件/etc/group
组信息分两部分,一部分记录在passwd文件中,但该文件只记录了该用户的首选组ID,没有记录该用户的所有组的id。另一部分则记录在组文件中/etc/group。组文件中列出了各个组的所有成员名称。每条记录包括组名,经过加密的组密码(一般没有),组ID,用户列表。如果有组密码的话,也和passwd一样,如果密码字符串为x,则真正的密码存在/etc/gshadow中。
4.获取用户和组的信息的库函数:
下面介绍的函数可以从密码文件,shasow文件和组文件中读取信息。

#include<pwd.h>
struct passwd *getpwnam(const char *name);//利用name来查询
struct passwd *getpwuid(uid_t uid);//利用uid来查询
struct passwd {
char *pw_name; //Login name(user name)
char *pw_passwd;//Encrypted password,未启用shadow时有效
char *pw_uid;//User ID
char *pw_gid;//Group ID
char *pw_gecos;//User information
char *pw_dir;//Initial working directory
char *pw_shell;//Login shell
}

上面两个函数返回的结果都是指向静态存储区的内存,所以其结果可能会被其他函数改写,所以这两个函数都是不可重入的。如果未发现匹配记录,则返回NULL。
从组文件中获取记录:

#include<grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(pid_t gid);
struct group {
char *gr_name;//group name
char *gr_passwd;//Encrypted passwd(if not passwd shadowing)
char *gr_gid;//group id
char **gr_mem;//NULL-terminated array of pointers to names of members listed in /etc/group
}

扫描密码文件和组文件的所有记录

#include <pwd.h>
struct passwd *getpwent(void)//return pointer on success,or NULL on end of stream or error
void setpwent(void);
void endpwent(void);

getpwent()会自动打开密码文件,处理完毕后调用endpwent可以关闭密码文件。setpwent函数将指针重新指向文件头。

从shadow文件中获取记录:

#include <shadow.h>
struct spwd *getspnam(const char *name)
struct spwd *getspnet(void);
void setspent(void);
void endspent(void);
spwd定义P131

5.密码加密和用户认证
有些程序如ssh和ftp等,需要验证user的用户名和密码,这是就需要利用加密算法将输入的密码加密,然后和/etc/shadow文件中的密码进行匹配。用户的密码加密算法封装在crypt函数中。

#define _XOPEN_SOURCE
#include <unistd.h>
char *crypt(const char *key, const char *salt);

该函数接受一个最长可达8字节的密钥(即密码),并利用加密算法来加密。salt参数指向一个两字节的字符串,用来扰动des算法,该函数返回一个长度为13字符的字符串,静态分配而成,就是加密后的密码。crypt函数所返回的经过加密的密码中,头两个字节是对原始salt值得拷贝,所以这两个字节可以从shadow文件中读出来。要想用crypt函数,编译时需要-lcrypt来链接crypt库。

从终端读取密码的函数:

#define _BSD_SOURCE
#include <unistd.h>
char *getpass(const char *prompt);

该函数可以将回显屏蔽,不会讲输入的密码打印在终端屏幕上,来保护隐私。输入的参数会被打印出来。事例可以参考P133