32 读书笔记:第6章 口令文件 (2)

6.4 组文件

        查看组名或数值组ID。

       #include <grp.h>

       struct group *getgrnam(const char *name);
       struct group *getgrgid(gid_t gid);
        // 两个函数的返回值:若成功则返回指针,若出错则返回NULL

        如同对口令文件进行操作的函数一样,这两个函数也通常返回一个指向静态变量的指针,在每次调用时都重写该静态变量。

        group结构定义如下:

           struct group {
               char   *gr_name;       /* group name */
               char   *gr_passwd;     /* group password */
               gid_t   gr_gid;        /* group ID */
               char  **gr_mem;        /* group members */
           };

        字段gr_men是一个指针数组,其中每个指针各指向一个属于该组的用户名,该数组以空指针结尾。

        如果需要搜索整个组文件,则需要使用另外几个函数。下列三个函数类似于针对口令文件的三个函数。

       #include <grp.h>

       struct group *getgrent(void);
        // 返回值:若成功则返回指针,若出错或到达文件结尾则返回NULL
       void setgrent(void);
       void endgrent(void);

        setgrent函数打开组文件(如果它尚未被打开)并反绕它。getgrent函数从组文件中读取下一个记录,如若该文件尚未打开则先打开它。endgrent函数关闭组文件。

6.5 附加组ID

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

        为了获取和设置附加组ID,提供了下列三个函数:

       #include <unistd.h>

       int getgroups(int size, gid_t list[]);
        // 返回值:若成功则返回附加组ID数,若出错则返回-1

       #include <grp.h>

       int setgroups(size_t size, const gid_t *list);
        // 返回值:若成功则返回0,若出错则返回-1

       #include <grp.h>

       int initgroups(const char *user, gid_t group);
        // 返回值:若成功则返回0,若出错则返回-1

        getgroups将各个附加组ID添写到数组list中,该数组中存放的元素最多为size个。实际填写到数组中的附加组ID数由函数返回。

        作为一个特例,如果size为0,则函数只返回附加组ID数,而对数组list则不作修改。

        setgroups可由超级用户调用以便为调用进程设置附加组ID表。list是组ID数组,而size指定了数组中的元素个数。

        通常只有initgroups函数调用setgroups,initgroups读取整个组文件(前面说明的函数getgrent、setgrent和endgrent),然后对user确定其组的成员关系。然后,它调用setgroups,以便为该用户初始化附加组ID表。只有超级用户才能调用initgroups。除了在组文件中找到user时成员的所有组,initgroups也在附加组ID表中包括了group。group是user在口令文件中的组ID。

        下列程序获取附加组ID,并输出组名:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <grp.h>

#define SIZE 20

int main(int argc, char *argv[])
{
    int size, i;
    gid_t list[SIZE];
    struct group *ptr;;

    size = getgroups(SIZE, list);

    for (i = 0; i < size; i++) {
        ptr = getgrgid(list[i]);
        printf("group[%d] = %5d, %s\n", i, list[i], ptr->gr_name);
    }   
    exit(0);
}

6.6 实现的区别

        在很多系统中,用户和组数据库是用网络信息服务(NIS)实现的。这使管理员可编辑数据库的主副本,然后将它自动分发到组织中的所有服务器上。客户端系统可以联系服务器以查看用户和组的有关信息。NIS+和轻量级目录访问协议(LDAP)提供了类似功能。很多系统通过配置文件/etc/nsswitch.conf来管理每一类信息的方法。

6.7 其他数据文件

        UNIX还使用还能多其他文件:记录各网络服务器所提供服务的数据文件(/etc/services),记录协议信息的数据文件(/etc/protocols),记录网络信息的数据文件(/etc/networks)等。针对这些数据文件的接口都与上述对口令文件和组文件的接口相似。

        一般情况下,对于每个数据文件至少有三个函数:

        (1) get函数:读下一个记录,如果需要,还可打开文件。这些函数通常返回指向一个结构的指针,当已到达文件尾端时则返回空指针。大多数get函数返回指向一个静态结构的指针,如果需要保存其内容,则需复制它。

        (2) set函数:打开相应数据文件(如果尚未打开),然后反绕文件。如果希望在相应文件起始处开始处理,则调用此函数。

        (3) end函数:关闭相应数据文件。在结束了对相应数据文件的读、写操作后,总应调用此函数以关闭所有相关文件。

        如果数据文件支持某种形式的关键字搜索,则会提供搜索具有指定关键字记录的例程。

说明
数据文件
头文件
结构
附加的关键字查找函数
口令

阴影
主机
网络
协议
服务
/etc/passwd
/etc/group
/etc/shadow
/etc/hosts
/etc/networks
/etc/protocols
/etc/services
<pwd.h>
<grp.h>
<shadow.h>
<netdb.h>
<netdb.h>
<netdb.h>
<netdb.h>
passwd
group
spwd
hostent
netent
protoent
servent
getpwnam、getpwuid
getgrnam、getgrgid
getspnam
gethostbyname、gethostbyaddr
getnetbyname、getnetbyaddr
getprotobyname、getprotobynumber
getservbyname、getservbyport


你可能感兴趣的:(读书笔记,《UNIX环境高级编程》)