APUE 系统数据文件和信息

《UNIX环境高级编程》第6章 系统数据文件和信息 笔记

口令文件

UNX系统口令文件(POSX1则将其称为用户数据库)包含了如下图所示的各字段,这些字段包含在<pwd.h>中定义的 passwd结构中。

由于历史原因,口令文件是/etc/passwd,而且是一个ASCII文件。字段之间用冒号分隔。

关于这些信息有以下这些注意事项:

  • 通常有一个用户名为root的登录项,其用户ID是0(超级用户)
  • 加密口令包含一个字段,现在出于安全的考虑把加密口令存放在另一个文件中
  • 口令文件项中的某些字段可能是空。如果加密口令字段为空,这通常就意味着该用户没有口令(不推荐这样做)。
  • shel字段包含了一个可执行程序名,它被用作该用户的登录 shell.若该字段为空,则取系统默认值,通常是/bin/sh
  • 为了阻止一个特定用户登录系统,除使用/dev/nu11外,还有若干种替代方法。

有两个获取口令文件项的函数。在给出用户登录名或数值用户ID后,这两个函数就能查看相关项。

1
2
3
4
5
6
7
#include <pwd.h>

struct passwd *getpwuid(uid_t uid);

struct passwd *getpwnam(const char *name);

// Both return: pointer if OK, NULL on error

如果想要查看整个口令文件,下面3个函数可以用于此目的:

1
2
3
4
5
6
7
8
9
#include <pwd.h>

struct passwd *getpwent(void);

// Returns: pointer if OK, NULL on error or end of file

void setpwent(void);

void endpwent(void);

调用getpwent时,它返回口令文件中的下一个记录项。函数setpwent反绕它所使用的文件(倒回到所有口令文件的开始), endpwent则关闭这些文件

阴影口令

加密口令是经单向加密算法处理过的用户口令副本。因为此算法是单向的,所以不能从加密口令猜测到原来的口令。

现在,某些系统将加密口令存放在另个通常称为阴影口令( shadow password)的文件中。该文件至少要包含用户名和加密囗令。

阴影口令文件不应是一般用户可以读取的。仅有少数几个程序需要访问加密口令,如1ogin(1)和 passwd(1),这些程序常常是设置用户ID为root的程序。

组文件

UNIX组文件中包含如下的字段,这些字段在<grp.h>所定义的group的数据结构中

查看组名或数值组ID:

1
2
3
4
5
6
#include <grp.h> 

struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);

// Both return: pointer if OK, NULL on error

和用户信息一样查看所有组文件函数:

1
2
3
4
5
6
7
8
#include <grp.h> 

struct group *getgrent(void);
// Returns: pointer if OK, NULL on error or end of file

void setgrent(void);

void endgrent(void);

附属组ID

我们不仅可以属于口令文件记录项中组ID所对应的组,也可属于多至16个另外的组。文件访问权限检查相应被修改为:不仅将进程的有效组ID与文件的组ID相比较,而且也将所有附属组ID与文件的组ID进行比较

使用附属组ID的优点是不必再显式地经常更改组。一个用户会参与多个项目,因此也就要同时属于多个组,此类情况是常有的。

以下3个函数用于获取和设置附属组ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <unistd.h> 

int getgroups(int gidsetsize, gid_t grouplist[]);

// Returns: number of supplementary group IDs if OK, −1 on error

#include <grp.h> /* on Linux */
#include <unistd.h> /* on FreeBSD, Mac OS X, and Solaris */

int setgroups(int ngroups, const gid_t grouplist[]);

#include <grp.h> /* on Linux and Solaris */
#include <unistd.h> /* on FreeBSD and Mac OS X */

int initgroups(const char *username, gid_t basegid);

// Both return: 0 if OK, −1 on error

getgroups将进程所属用户的各附属组ID填写到数组grouplist中,填写入该数组的附属组ID数最多为 gidsetsize个。实际填写到数组中的附属组ID数由函数返回。

setgroups可由超级用户调用以便为调用进程设置附属组ID表。grouplist是组ID数组,而 ngroups说明了数组中的元素数。 ngroups的值不能大于 NGROUPS_MAX.

登录账户记录

大多数UNIX系统都提供下列两个数据文件:utmp文件记录当前登录到系统的各个用户;wtmp文件跟踪各个登录和注销事件。

系统标识

有一个uname函数,它返回与主机和操作系统有关的信息

1
2
3
4
5
6

#include <sys/utsname.h>

int uname(struct utsname *name);

// Returns: non-negative value if OK, −1 on error

时间和日期例程

由UNIX内核提供的基本时间服务是计算自协调世界时公元1970年1月1日00:00:00这一特定时间以来经过的秒数。

用数据结构time_t表示,据类型 time_t表示的,我们称它们为日历时间。日历时间包括时间和日期。UNIX在这方面与其他操作系统的区别是:(a)以协调统一时间而非本地时间计时;(b)可自动进行转换,如变换到夏令时;(c)将时间和日期作为一个量值保存。

time函数返回当前时间和日期

1
2
3
4
5
#include <time.h> 

time_t time(time_t *calptr);

// Returns: value of time if OK, −1 on error

时间值作为函数值返回。如果参数非空,则时间值也存放在由calptr指向的单元内

关于日期和时间,有许多相关的函数,以下列出其中一些函数的关系: