系统数据文件和信息之口令文件

UNIX系统的口令文件(POSIX.1则将其称为用户数据库)包含了表6-1中所示的各字段,这些字段包含在<pwd.h>中定义的passwd结构中。

注意,POSIX.1只指定了passwd结构包含的10个字段中的5个。大多数平台至少支持其中7个字段。

                                                        表6-1 /etc/passwd文件中的字段

20131024210705703

由于历史原因,口令文件存储在/etc/passwd中,而且是一个ASCII文件。每一行包含6-1中所示的各字段,字段之间用冒号分隔。例如,在Linux上,该文件中可能有下列四行:

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin

关于这些登录项请注意下列各点:

  • 通常有一个用户名为root的登录项,其用户ID是0(超级用户)。
  • 加密口令字段包含了一个占位符。在早期的UNIX系统版本中,该字段存放加密口令。将加密口令存放在一个人人可读的文件中构成了一个安全性漏洞,所以现在将加密口令存放在另一个位置。
  • 口令文件项中某些字段可能是空。如果加密口令字段为空,这通常就意味着该用户没有口令(不推荐这样做)。注释字段为空,不产生任何影响。
  • shell字段包含了一个可执行程序名,它被用作该用户的登录shell。若该字段为空,则取系统默认值,通常是/bin/sh。注意,若某登录项的该字段为/dev/null,显然,这是一个设备,不能执行,因此将其用于此处的目的是,阻止任何人以该用户的名义登录到该系统。
  • 为了阻止一个特定用户登录系统,除使用/dev/null之外,还有若干种替代方法。一种常见的方法是,将/bin/false用作登录shell。它简单地以不成功(非0)状态终止,该shell将此种终止状态判断为假。另一种常见的方法是,用/bin/ture禁止一个账户。它所作的一切是以成功(0)状态终止。某些系统提供nologin命令,它打印可自定义的出错信息,然后以非0状态终止。
  • 使用nobody用户名的目的是,使任何人都可登录至系统,但其用户ID(65534)和组ID(65534)不提供任何特权。该用户ID和组ID只能访问人人皆可读、写的文件(假定用户ID65534和组ID65534并不拥有任何文件,而实际情况就应如此)。
  • 提供finger(1)命令的某些UNIX系统支持注释字段中的附加信息。其中,各部分之间都用逗号分隔:用户姓名、办公室地点、办公室电话号码以及家庭电话号码等。另外,如果注释字段中的用户姓名是一个&,则将其替换为登录名。

即使你所使用的系统并不支持finger命令,这些信息仍可存放在注释字段中,该字段只是一个注释,并不由系统使用程序解释。

某些系统提供了vipw命令,允许管理员使用该命令编辑口令文件。vipw命令串行化对口令文件所作的更改,并且确保所作的更改与其他相关文件保持一致。系统也常常经由图形用户界面(GUI)提供类似的功能。

POSIX.1只定义了两个获取口令文件项的函数。在给出用户登录名或数值用户ID后,这两个函数就能查询相关项

#include <pwd.h>
struct passwd *getpwuid( uid_t uid );
struct passwd *getpwnam( const char *name );
两个函数返回值:若成功则返回指针,若出错则返回NULL

getpwuid函数由ls(1)程序使用,它将i节点中的数值用户ID映射为用户登录名。在键入登录名时,getpwnam函数由login(1)程序使用。

这两个函数都返回一个指向passwd结构的指针,该结构已由这两个函数在执行时填入信息。passwd结构通常是相关函数内的静态变量,只要调用相关函数,其内容就会被重写。

如果要查看的只是指定的某个登录名或用户ID所对应的passwd记录项,那么这两个函数能满足要求,但是也有些程序要查看整个口令文件。下列三个函数则可用于此种目的。

#include <pwd.h>

struct passwd *getpwent( void );
返回值:若成功则返回指针,若出错或到达文件结尾则返回NULL

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

调用getpwent时,它返回口令文件中的下一个记录项。如果上面所述的两个POSIX.1函数一样,它返回一个由它填写好的passwd结构的指针。每次调用此函数时都重写该结构。在第一次调用该函数时,它打开它所使用的各个文件。在使用本函数时,对口令文件中各个记录项的安排顺序并无要求。某些系统采用散列算法对/etc/passwd文件中的各项排序。

函数setpwent反绕它所使用的文件(rewinds  to  the  beginning  of the password database),endpwent则关闭这些文件(close the  password  database  after all processing has been performed)。在使用getpwent查看完口令文件后,一定要调用endpwent关闭这些文件。getpwent知道什么时间它应当打开它所使用的文件(第一次被调用时),但是它并不知道何时关闭这些文件。

程序清单6-1 getpwnam函数的一个实现

[root@localhost apue]# cat prog6-1.c
#include <pwd.h>
#include <stddef.h>
#include <string.h>

struct passwd *
getpwnam( const char *name )
{
        struct passwd *ptr;

        setpwent();
        while((ptr = getpwent()) != NULL)
                if(strcmp(name, ptr->pw_name) == 0)
                        break;          /* found a match */
        endpwent();
        return(ptr);    /* ptr is NULL if no match found */
}

在程序开始处调用setpwent是自我保护性的措施,以便在调用者在此之前已经调用getpwent打开了有关文件情况下,反绕有关文件使它们定位到文件开始处。getpwent和getpwuid调用完成后不应使有关文件仍处于打开状态,所以应调用endpwent关闭它们。

本篇博文内容摘自《UNIX环境高级编程》(第二版)。关于本书的更多内容可参考:http://www.apuebook.com/

posted @ 2014-01-06 10:57  ITtecman  阅读(548)  评论(0编辑  收藏  举报