Linux系统的正常运行需要使用大量与系统有关的数据文件,例如口令文件“/etc/passwd”和组文件“/etc/group”,这两种文件是经常被使用的,此外还有网路服务“/etc/services”、协议信息“/etc/protocols”、网络信息“/etc/networks”、主机数据“/etc/hosts”等。下面主要说明一下口令文件。
口令文件——
Linux系统的口令文件为ASCII文本,一般有下面一行:
root:x:0:0:root:/root:/bin/bash
上面共七个字段,以冒号分割,其数据结构在头文件“pwd.h”中定义,是一个名为passwd的struct,如下所示:
/* 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. */
};
口令文件中每一行的各字段的含义分别为用户名、密码、用户ID、组ID、注释、用户根目录、登录shell。密码字段是一个占位符“x”,在早期的Linux系统版本中,该字段存放密码,但是将密码存放在一个人人可读的文件中构成了一个安全性漏洞,所以现在将密码存放在另一个位置,一种shadow口令文件中。命令finger可用于查看用户登录信息,命令vipw可以用于编辑相关口令文件。在头文件“pwd.h”中,还声明了一些与口令文件相关的函数,如下:
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
struct passwd *getpwent(void);
void setpwent(void);
void endpwent(void);
getpwuid以用户ID获取口令数据,getpwnam以用户名获取口令数据,getpwent用于读取口令文件,每次读取一行,setpwent设置口令文件读取偏移量到文件开始位置,endpwent用于关闭打开的口令文件。
shadow口令文件——
密码是用单向加密算法处理过的,如MD5算法,在某些Linux系统版本上,密码实际存放在shadow口令文件“/etc/shadow”中,例如我的用户名为evo,就有下面这么一行:
evo:$6$kuLgFlTH$eGxHb1X6PoyuIXJFNgB9IIKaLei6Xy3B19gY.UhPK7/Qv5HrF5D0q20AuvXIvzPjzizD7trj8Gutby3wtz3O9/:17058:0:99999:7:::
在头文件“shadow.h”中定义了对应的数据结构spwd和相关函数。
#include <shadow.h>
/* Structure of the password file. */
struct spwd
{
char *sp_namp; /* Login name. */
char *sp_pwdp; /* Encrypted password. */
long int sp_lstchg; /* Date of last change. */
long int sp_min; /* Minimum number of days between changes. */
long int sp_max; /* Maximum number of days between changes. */
long int sp_warn; /* Number of days to warn user to change
the password. */
long int sp_inact; /* Number of days the account may be
inactive. */
long int sp_expire; /* Number of days since 1970-01-01 until
account expires. */
unsigned long int sp_flag; /* Reserved. */
};
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
void setspent(void);
void endspent(void);
组文件——
同理,“/etc/group”为组文件,其中的一行如下:
root:x:0:
在头文件“grp.h”中定义了对应的数据结构group和相关函数。
#include <grp.h>
/* The group structure. */
struct group
{
char *gr_name; /* Group name. */
char *gr_passwd; /* Password. */
__gid_t gr_gid; /* Group ID. */
char **gr_mem; /* Member list. */
};
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
在Linux中,用户同时只属于一个组,但还有一个附加组,附加组可以为用户指定多个所属组,也就是说用户除了实际的所属组外,还可以同时是附加组内的任何组。
除了上文提到的数据文件之外,大多数Linux系统还提供了“/var/run/utmp”和“/var/log/wtmp”两个数据文件,前者记录当前登录的各个用户,后者跟踪各个登录和注销事件。在shell中,命令“uname”可查看系统信息,“hostname”可查看主机信息,对应的,函数“uname”和“gethostname”可做同样的事情。
时间相关——
Linux内核提供的时间是从国际标准时间1970年1月1日零点开始经过的秒数,函数time可以获得这段秒数,即日历时间,gettimeofday则可以获得更精确的时间值。日历时间可读性差,结构体tm一个可读性好数据形式,包括年、月、日、时、分、秒等,函数gmtime可以把日历时间转换成国际标准时间的tm形式,考虑到本地时区和夏时制,localtime把日历时间转换成本地时间。函数mktime把时间的tm形式转换为日历时间,而asctime把时间的tm形式转换成了26字节的字符串,strftime则是对时间进行格式化。ctime函数把时间秒数转换为字符串。需要注意的是,localtime、mktime、strftime、ctime四个函数与环境变量TZ有关联,一个设置时区的环境变量。
#include <time.h>
time_t time(time_t *tloc);
size_t strftime(char *s, size_t max, const char *format,
const struct tm *tm);
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of DST correction */
};
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
time_t mktime(struct tm *tm);
char *ctime(const time_t *timep);
char *asctime(const struct tm *tm);
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};