一、口令文件
1.文件简介
由于历史原因,在Unix系统中,口令文件是/etc/passwd
。它的每一条记录都包含如下字段:
说明 | 字段 | 含义 |
---|---|---|
用户名 | char *pw_name | 用户用于登录系统的账号。 |
口令 | char *pw_passwd | 值为x,只用于占位,不是真正的口令。 |
用户ID | uid_t pw_uid | 一个非负整数,用于唯一标识每位用户。 |
组ID | gid_t pw_gid | 一个非负整数,标识每位用户分别属于哪个组。 |
注释 | char *pw_gecos | 用户的备注信息。 |
家目录 | char *pw_dir | 用户登录系统后默认进入的目录。 |
shell | char *pw_shell | 该用户使用的命令解释器。 |
示例:
root:x:0:0:root:/root:/bin/bash
- 字段之间以冒号分隔
- root:第一个root是用户名
- x:口令占位符
- 0:用户ID
- 0:组ID
- root:第二个root是注释
- /root:家目录
- /bin/bash:shell解释器
2.基本函数
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
通过用户ID或用户名获取用户信息。
struct passwd *getpwent();
打开并从/etc/passwd文件流中读取下一个用户登录项。
void setpwent();
把passwd文件流的读写地址指向文件开头。
void endpwent();
关闭passwd文件流。
二、阴影口令
1.文件格式
Unix把实际的用户口令放到/etc/shadow
文件中,但是该文件记录的是经过加密处理的口令。每一个用户对应该文件中的一项,文件中的每一项都包含如下字段:
说明 | 字段 | 含义 |
---|---|---|
用户名 | char *sp_namp | 对应passwd文件中的用户名。 |
加密口令 | char *sp_pwdp | 经过加密处理的用户口令。 |
距离上次更改口令的时间 | int sp_lstchg | 现在距离上次更改口令的秒数。 |
经过多少天后允许更改 | int sp_min | 指定可以在多少天后更改口令。 |
要求更改尚余天数 | int sp_max | 该天数内必须修改口令。 |
超期警告天数 | int sp_warn | 到期前多少天发出警告。 |
账户不活动之前尚余天数 | int sp_inact | 多少天后账户进入inactive状态,可登录不可操作。 |
账户超期天数 | int sp_expire | 多少天后账户过期,无法登录 |
保留 | unsigned int sp_flag | 保留字段 |
2.基本函数
struct spwd *getspnam(const char *name);
通过用户名获取口令项。
struct spwd *getspent();
打开并从/etc/shadow文件流中读取下一个口令项。
void setspent();
把shadow文件流的读写地址指向文件开头。
void endspent();
关闭shadow文件流。
三、组文件
1.文件格式
Unix把组信息记录在/etc/group
文件中,其中每一项都包含以下字段:
说明 | 字段 |
---|---|
组名 | char *gr_name |
加密口令 | char *gr_passwd |
组ID | int gr_gid |
指向各用户名指针的数组 | char **gr_mem |
2.基本函数
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
通过组ID或组名获取组信息。
struct group *getgrent();
打开并从/etc/group文件流中读取下一个组信息。
void setgrent();
把group文件流的读写地址指向文件开头。
void endgrent();
关闭group文件流。
四、附属组
1.简介
Unix在创建用户的同时会以该用户名创建一个初始组,如果不做任何更改,新用户就属于该组。但是,用户不仅可以属于口令文件记录项中组ID所对应的组,还可属于最多16个其他组。
如果以项目划分组,则用户可能同时参与多个项目。如果每次切换项目都要更改用户组,就会很麻烦,而附属组的优点是不必再显式地经常更改组。
2.基本函数
int getgroups(int gidsetsize, gid_t grouplist[]);
获取进程所属用户的最多gidsetsize个附属组ID,存于grouplist数组中,实际获取到的个数为返回值。
int setgroups(int ngroups, const gid_t grouplist[]);
由超级用户调用,为调用进程设置附属组ID表。
int initgroups(const char *username, gid_t basegid);
把basegid映射的组加入到username所指用户的附属组中。
- initgroups底层是调用setgroups,所以也需要由超级用户调用。
五、其他数据文件
Unix系统使用的系统数据文件有很多,而开发中常用的文件如下:
说明 | 文件 | 头文件 | 结构名 | 键搜索函数 |
---|---|---|---|---|
口令 | /etc/passwd | <pwd.h> | passwd | getpwnam、getpwuid |
组 | /etc/group | <grp.h> | group | getgrnam、getgrgid |
阴影 | /etc/group | <shadow.h> | spwd | getspnam |
主机 | /etc/hosts | <netdb.h> | hostent | getnameinfo、getaddrinfo |
网络 | /etc/networks | <netdb.h> | netent | getnetbyname、getnetbyaddr |
协议 | /etc/protocols | <netdb.h> | protoent | getprotobyname、getprotobynumber |
服务 | /etc/services | <netdb.h> | servent | getservbyname、getservbyport |
六、登录账户记录
Unix系统使用/var/run/utmp
文件记录当前登录到系统的各个用户,使用命令who
和uptime
可查看相关信息。另外,/var/log/wtmp
文件用于跟踪各个登录和注销事件,使用命令last
可查看相关信息。Unix使用如下结构保存以上文件的记录项:
struct utmp
{
short int ut_type; // 登录类型
pid_t ut_pid; // 登录的进程ID
char ut_line[UT_LINESIZE]; // 设备名称
char ut_id[4]; // Inittab ID
char ut_user[UT_NAMESIZE]; // 用户名
char ut_host[UT_HOSTSIZE]; // 远程登录的主机名
struct exit_status ut_exit; // 进程的退出状态
int32_t ut_session; // 会话ID
struct
{
int32_t tv_sec; // 秒
int32_t tv_usec; // 毫秒
} ut_tv; // 时间
int32_t ut_addr_v6[4]; // 远程主机的IPv6地址 */
char __unused[20]; // 保留字段
};
七、系统标识
Unix系统提供了以下接口,返回与主机和操作系统有关的信息:
int uname(struct utsname *name);
获取主机和操作系统相关信息,缓存于utsname结构体中;若成功,返回非负值,若出错,返回-1。
int gethostname(char *name, size_t len);
获取当前主机名,缓存于name中;如果主机名长度小于len,则name以null字节结尾,否则结果未知。
八、时间和日期
1.日历时间
Unix内核提供的基本时间服务是计算自协调世界时公元1970年1月1日00:00:00以来经过的秒数,又称为日历时间。其数据类型以time_t表示,并提供以下函数获取:
time_t time(time_t *calptr);
把日历时间缓存于calptr指针指向的内存中,也作为结果返回。
2.其他时间函数
1)tm与time_t转换
struct tm *gmtime(const time_t *calptr);
把日历时间转换成协调统一时间的年、月、日、时、分、秒、周日分解结构。
struct tm *localtime(const time_t *calptr);
把日历时间转换成本地时间(考虑到本地时区和夏令时标志)。
time_t mktime(struct tm *tmptr);
以本地时间的年、月、日等作为参数,转换成time_t值。
2)字符串与tm转换
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
把tm指向的时间结构按照format指定的格式转换成字符串,把其中最多max个字符缓存于s中。
char *strptime(const char *s, const char *format, struct tm *tm);
把格式为format的字符串s转换成时间值,缓存于tm指向的结构体中。