口令文件:
/* The passwd structure. */ struct passwd { char *pw_name; /* Username. */ char *pw_passwd; /* Password. */ __uid_t pw_uid; /* User ID. */ __gid_t pw_gid; /* Group ID. */ char *pw_gecos; /* Real name. */ char *pw_dir; /* Home directory. */ char *pw_shell; /* Shell program. */ };
定义于pwd.h
相应的数据以ASSIC文本形式存在于/etc/passed文件中
每一行包含一个结构体中指示的7个字段,以冒号隔开
Password字段是经过单项加密的字符串,但是在使用阴影文件时是无意义字符
通常有root用户和nobody用户。root用户的用户ID和组ID都是0,表示超级用户。nobody用户的用户ID和组ID都是65534,表示没有优先权,并且没有密码,提供大家都可读写的文件
pw_gecos表示附加信息,其中的内容以逗号隔开,其中如果使用&符号表示替换为登录名
查看单个口令函数:
sys/types.h;pwd.h
struct passwd *getpwuid(uid_t uid) struct passwd *getpwnam(const char *name)
成功返回指针,出错返回NULL
getpwuid函数由ls(1)程序调用,通过i节点中的数值用户ID获取其对应的passwd结构
getpwnam函数在输入登录名的时候由login(1)程序调用,通过用户名获取对应的passwd结构
两个函数返回指针对应的结构存储在静态区,每次调用都会重写该区域的内容
查看整个口令文件函数:
sys/types.h;pwd.h
struct passed *getpwent(void)/* 成功返回值真,出错或达到文件尾返回NULL */ void setpwent(void) void endpwent(void)
getpwent获取口令文件中的下一条记录,每次调用都存储在相同的静态区并替换上一次调用的结果
setpwent重置获取开始的位置到文件起始,通常会在程序开始的地方调用setpwent以起保护作用
endpwent关闭文件,在使用getpwent结束后必须使用此函数关闭文件
阴影口令:
为了增加获取到原始加密口令,某些系统会将至少用户名和加密口令等信息存放到阴影口令文件中而不是口令文件中,系统通常要求用户每隔一段时间修改口令,该时间间隔也会存放到阴影口令文件中
SVR4:/etc/shadow;4.3+BSD:/etc/master.passwd
组文件:
struct group { char *gr_name; /* Group name. */ char *gr_passwd; /* Password. */ __gid_t gr_gid; /* Group ID. */ char **gr_mem; /* Member list. */ };
定义于grp.h文件
组文件存在于/etc/group
查看一条组文件函数:
sys/types.h;grp.h
struct group *getgrgid(gid_t gid)
struct *getgrnam(const char *name)
成功返回指针,出错返回NULL
和口令文件类似,返回的指针指向静态区的地址,每次调用都会覆盖上次调用产生的内容
查看整个组文件函数:
sys/types.h;grp.h
struct group *getgrent(void)
void setgrent(void)
void endgrent(void)
添加组ID:
文件存取权限检查不仅检查进程的有效组ID还检查添加组ID。因为一个用户经常参加多个项目,所以理应同时属于多个组
存取和设置添加组ID的函数:
sys/types.h;unistd.h
int getgroups(int gidsetsize,gid_t grouplist[])/* 成功返回添加组ID个数,出错返回-1 */
int setgroups(int ngroups,const gid_t grouplist[])/* 成功返回0,出错返回-1 */
int initgroups(const char *username,gid_t basegid)/* 成功返回0,出错返回-1 */
getgroups函数获取进程所属用户的各添加组ID并放到数组grouplist中,groupsize指定了可以放到grouplist中的最多个数,如果进程的实际添加组ID数大于groupsize而且groupsize非0,就会出错。没有明确说明有效组ID是否包含在返回列表中
特别的,如果groupsize为0,那么函数将返回进程的添加组ID数但是不将内容放到grouplist中
setgroups设置进程的添加组ID,grouplist是需要设置的添加组ID列表,ngroups说明数组中的元素个数。此函数需要超级用户权限,通常只有initgroups函数调用此函数,所以initgroups函数也需要超级用户权限
initgroups函数,读取整个组文件,根据username确定其组成员关系,调用setgroups函数为用户初始化添加组ID表。basegid是额外添加的组ID。此函数只有少数程序调用,比如login(1)在用户登录时调用
其他数据文件:
其他数据文件的处理都和上面描述的口令文件和组文件类似
一般数据文件都至少有三个函数:
• get函数:获取下一条记录,通常返回指向存储在静态存储区结构的指针,下一次调用将覆盖
• set函数:将get的获取位置重置到文件起始位置
• end函数:关闭文件
登录会计:
utmp文件:记录当前登录进系统的各个用户
wtmp文件:跟踪各个登录和注销事件
有如下结构:
struct utmp { char ut_line[8]; /* tty line: "ttyh0", "ttyd0", "ttyp0", ... */ char ut_name[8]; /* login name */ long ut_time; /* seconds since Epoch */ } ;
登录时login程序会填写这样一个结构然后写入到utmp文件中,同时写入wtmp文件中。注销时,init程序将utmp文件中对应的记录清零(字节填0),并将一个新的记录填入wtmp文件中
大多数UNIX版本提供utmp和wtmp文件,但是相应的utmp结构体变得更加复杂
系统标识:
sys/utsname.h
int uname(struct utsname *name)
函数返回主机和操作系统相关的信息
函数参数是一个utsname结构的地址,函数会向这个地址中填写内容
时间和日期例程:
UNIX内核提供的时间服务提供的是时间戳的形式,并以time_t格式存储。函数为:
time.h
time_t time(time_t *calptr)
函数返回时间值,如果参数非NULL,也会将时间值存放到calptr指向的存储空间中
之后其他的函数会将时间戳转化为可读的形式
/* ISO C `broken-down time' structure. */ struct tm { int tm_sec; /* Seconds. [0-60] (1 leap second) */ int tm_min; /* Minutes. [0-59] */ int tm_hour; /* Hours. [0-23] */ int tm_mday; /* Day. [1-31] */ int tm_mon; /* Month. [0-11] */ int tm_year; /* Year - 1900. */ int tm_wday; /* Day of week. [0-6] */ int tm_yday; /* Days in year.[0-365] */ int tm_isdst; /* DST. [-1/0/1]*/ };
localtime和gmtime函数:
区别是localtime将时间戳转化为本地时间,gmtime将时间戳转化为国际标准时间
mktime将tm结构体转化为时间戳
asctime和ctime将产生26字节字符串
strftime函数可以格式化输出自定义的时间格式