from : https://segmentfault.com/a/1190000004419381


口令文件

使用过Unix系统的朋友应该知道/etc/passwd文件,这就是Unix系统口令文件,在POSIX1.x规范中规定Unix系统必须存在用户数据库,这些用户数据库里每个用户都需要包含一些字段,具体需要查看<pwd.h>头文件。

struct passwd {
        char    *pw_name;               /* user name */
        char    *pw_passwd;             /* encrypted password */
        uid_t   pw_uid;                 /* user uid */
        gid_t   pw_gid;                 /* user gid */
        __darwin_time_t pw_change;      /* password change time */
        char    *pw_class;              /* user access class */
        char    *pw_gecos;              /* Honeywell login info */
        char    *pw_dir;                /* home directory */
        char    *pw_shell;              /* default shell */
        __darwin_time_t pw_expire;      /* account expiration */
};

在很多Unix系统中,passwd是一个ASCII文件,每一行是一个用户,然后每个用户都包含这些字段,字段之间使用冒号分隔,但是在苹果系统中,则是使用opendirectory守护进程来存储用户数据库等数据。

系统提供了两个获取口令文件项的函数:

struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *login);

这两个函数都会返回passwd结构体,而且需要注意的是,这个结构体指针实际上是指向一块静态区域的指针,也就是说,不通过保留指针来让后面使用。


struct passwd *getpwent(void);

void setpwent(void);
void endpwent(void);

getpwent函数则是一项一项读取,然后将其以passwd结构体返回,非常适合需要读取全部内容的情况。setpwent和endpwent清理读取的缓存,其中endpwent则是关闭所有的文件,当使用getpwent后一定要使用endpwent关闭文件。


阴影口令

在最初的Unix系统实现中,密码是存放在/etc/passwd文件的第二个字段中,但是由于有很多程序读取这个文件,所以这个字段被专门移出来放在/etc/shadow中,通常情况下,只有root权限才能读取。在Solaris和Linux中,有一组函数用于访问阴影口令文件,但是,非常遗憾的是,苹果系统中没有,所以这里也就只能讲一讲,而不能列出实际的代码。


组文件

struct group {
        char    *gr_name;               /* [XBD] group name */
        char    *gr_passwd;             /* [???] group password */
        gid_t   gr_gid;                 /* [XBD] group id */
        char    **gr_mem;               /* [XBD] group members */
};

上面是苹果系统定义的group结构体

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

struct group *getgrent(void);
void setgrent(void);
void endgrent(void);

就如同口令文件的函数一样,上面的函数用法也是一样的。


附属组ID

在早期Unix系统实现中,是不存在附属组的。直到后来BSD的一个版本引入了附属组ID的概念,这样在权限检查的时候也需要检查附属组ID的权限

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

int setgroups(int ngroups, const gid_t *gidset);

int initgroups(const char *name, int basegid);

getgroups函数将进程所属用户的附属组ID放入grouplist参数中,groupsize参数用于确定放入的大小,但是实际上,我们可以将groupsize设置为0,然后函数会返回实际的附属组个数,然后就可以很方便的分配grouplist数组,用不着去猜测究竟应该分配多少。
setgroups是一个root权限操作,用于为进程设置附属组ID。
initgroups是一系列操作的集合,实际上用到的机会极少,如果有需要的朋友可以自行观看系统手册。


其他数据文件

除了上面讲到的两个文件以外,系统还有很多其他的文件,但是基本上都是提供了同样的接口(get,set,end),而且和前面的用法基本一样,所以这里也不再讲解。


登录账户记录

在实际的运维中,经常会需要查看用户的登录日志,所以系统也有相关的数据文件和接口函数用于开发使用。

原著中讲解了utemp结构体的内容,这里不再多讲,但是在苹果系统中,实际上已经被utempx等结构体所取代

struct utmpx {
        char ut_user[_UTX_USERSIZE];    /* login name */
        char ut_id[_UTX_IDSIZE];        /* id */
        char ut_line[_UTX_LINESIZE];    /* tty name */
        pid_t ut_pid;                   /* process id creating the entry */
        short ut_type;                  /* type of this entry */
        struct timeval ut_tv;           /* time entry was created */
        char ut_host[_UTX_HOSTSIZE];    /* host name */
        __uint32_t ut_pad[16];          /* reserved for future use */
};

struct lastlogx {
        struct timeval ll_tv;           /* time entry was created */
        char ll_line[_UTX_LINESIZE];    /* tty name */
        char ll_host[_UTX_HOSTSIZE];    /* host name */
};

其实,不光是苹果系统,其他的Unix系统的字段也已经被修改扩充了,而且其实这个并不重要,所以只需要了解即可。


系统标识

POSIX定义了uname函数,用于返回主机和操作系统相关的信息,uname命令就是使用了这个函数。

int uname(struct utsname *name);

struct  utsname {
        char    sysname[_SYS_NAMELEN];  /* [XSI] Name of OS */
        char    nodename[_SYS_NAMELEN]; /* [XSI] Name of this network node */
        char    release[_SYS_NAMELEN];  /* [XSI] Release level */
        char    version[_SYS_NAMELEN];  /* [XSI] Version level */
        char    machine[_SYS_NAMELEN];  /* [XSI] Hardware type */
};

所有的成员都是以null字节结尾,并且BSD派生系统也提供了gethostname函数

int gethostname(char *name, size_t namelen);

实际上还有一个sethostname函数,但是这里也不多讲,除此以外,上面的一些函数实际上有一些已经被移到标准C库中了,所以也能作为跨平台开发使用。


日期和时间

Unix系统都使用的是Unix时间戳,也就是UTC时间1970年1月1日0时0分0秒以来的秒数,在前面我们提到过它,这个就是日历时间,并且是使用time_t类型存储的。

time_t time(time_t *tloc);

time函数就是很简单的获取日历时间,在一般的情况下,都是传入null然后获得函数返回值来使用。

原著中也讲到了指定时间的获取,但是非常不幸,苹果系统又没有这些方法,所以这里也只能不提及了。

results matching ""

    No results matching ""