Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1814686
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-03-29 12:24:15

UNIX系统的密码文件,被POSIX.1称为用户数据库,包含了下表所示的域。这些域包含在定义于里的一个passwd结构体里:

/etc/passwd文件的域
描述 结构体passwd的成员 POSIX.1 FreeBSD 5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9
用户名 char *pw_name * * * * *
加密密码 char *pw_passwd   * * * *
数值化用户ID uid_t pw_uid * * * * *
数值化组ID gid_t pw_gid * * * * *
注解域 char *pw_gecos   * * * *
初始工作目录 char *pw_dir * * * * *
初始外壳(用户程序) char *pw_shell * * * * *
用户访问类 char *pw_class   *   *  
下次修改密码的时间 time_t pw_change   *   *  
帐户到时时间 time_t pw_expire   *   *  


注意POSIX.1只指定了passwd结构里十个域里的五个。多数平台支持至少七个域。基于BSD的平台支持所有的域。


历史上,密码文件存储在/etc/passwd里,并且是个ASCII文件。每行包含着上表描述的域,以冒号分隔。例如,Linux上的/etc/passwd文件的四行可能是:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
rwhod:x:119:65534::/var/spool/rwho:/bin/null

注意关于这些项的以下几点:
1、通常有一个名为root的项。这个项有个值为0的用户ID(超级用户)。


2、加密密码域包含单个字符,作为占位符。早期UNIX系统版本使用该域存储加密密码。因为在一个对所有人可读的文件里存储加密密码是一个安全漏洞,所以加密密码被存储在其它地方。我们将在下节讨论密码时更深入地讨论这个问题。


3、密码文件项的一些域可以为空。如果加密密码域为空,它通常表示这个用户没有密码。(这不被提倡。)项rwhod有一个空白域:注解域。一个空注解域没有效果。


4、shell域包含了可执行程序的路径,它作为用户的登录shell。一个空的shell域的默认值通常为/bin/sh。虽然这样,注意,项 rwhod有一个/dev/null的登录shell。显然,这是一个设备,而且不能执行,所以它这里的使用是阻止任何人作为用户rwhod登录我们的系 统。许多服务都为后台进程(第13章)有独立的用户ID,来帮助实现这个服务。


5、/dev/null有几个替代品,都可以阻止特定用户登录一个系统。常见的有/bin/false,它简单地退出并返回一个不成功(非0)的状 态;shell视这个状态为false。另一个常见的是/bin/true,它做的只是返回一个成功(0)状态。一些系统提供nologin命令,它打印 一个可定制的错误信息,并返回一个非0状态并退出。


6、nobody用户名可以用来登录一个系统,但它的用户ID(65534)和组ID(65534)没有提供任何权限。这个用户ID和组ID能访问的文件只有对所有人可读可写的文件。(它假设没有任何属于用户ID65534和组ID65534的文件,这也应该是这样。)


7、一些提供finger命令的系统在注解域支持额外的信息。这些域的由冒号分隔:用户名、办公地点、办公电话以及家庭电话。此外,在注释域里的一个与号(ampersand,&)被一个(转换的)用户名通过一些工具代替。例如,我们可能有:


someone:x:988:1004:Mr. Someone, Shang hai NanJing Rd., 021-12345678, 021-87654321:/home/here:/bin/null


通过finger命令来打印someone的信息:


$ finger -p someone
Login: someone                    Name: Mr. Someone
Directory: /home/here                   Shell: /bin/null
Office:  Shang hai NanJing Rd.        Office Phone:  021-12345678
Home Phone:  021-87654321
Never logged in.
No mail.


即使你的系统不支持finger命令,这些域仍然可以在注释域中,只是这些域只是简单一个注解,而不被系统工具解释。


一些系统提供了vipw命令,允许管理员修改密码文件。vipw命令把改变序列化到密码文件,并保证额外的文件与做过的改变一致。这在通过GUI提供相似功能的系统上也很普遍。


POSIX.1只定义了两个函数来从密码文件中得到项。这些函数允许我们通过用户名或用户ID查找一个项。



  1. #include <pwd.h>

  2. struct passwd *getpwuid(uid_t uid);

  3. struct passwd *getpwnam(const char *name);

  4. 两者成功都返回指针,失败返回NULL。


getpwuid函数被ls程序使用,来把包含在一个i-node里的用户ID数值映射到一个用户登录名。getpwnam函数被login函数使用,当我们输入我们的登录名的时候。


两个函数都返回一个指向passwd结构体的指针,并填满它。这个结构体通常是这个函数的一个静态变量,所以它的内容在每次我们调用这些函数的时候会被覆写。


这两个POSIX.1函数在我们要查找登录名或用户ID时都很好,但一些程序想遍历整个密码文件。有以下三个函数可以用:



  1. #include <pwd.h>

  2. struct passwd *getpwent(void);

  3. 成功返回指针,失败或文件结尾返回NULL。

  4. void setpwent(void);

  5. void endpwent(void);


这三个函数不是基本POSIX.1的一部分,而是定义在SUS的XSI扩展里。如此,所有UNIX系统都需要支持它们。


我们调用getpwent函数来返回密码文件的下个项。和那两个POSIX.1函数一样,getpwent返回一个由它填满的结构体的指针。这个结构体通 常在我们每次调用这个函数的时候被覆写。如果这是第一次调用这个函数,它会打开任何它使用的文件。当我们使用这个函数时没有隐含的顺序:这些项可以是任何 顺序,因为一些系统使用文件/etc/passwd的哈希版本。 



函数setpwent回退任何它使用的文件,而endpwent关闭这些文件。当使用getpwent时,我们必须总是保证在完成后调用endpwent 来关闭它们。尽管getpwent足够智能,知道它何时必须打开它的文件(我们每一次调用它的时候),但它从不知道我们什么时候完成。


下面的代码是getpwnam的一个实现:



  1. #include <pwd.h>
  2. #include <stddef.h>
  3. #include <string.h>

  4. struct passwd *
  5. getpwnam(const char *name)
  6. {
  7.     struct passwd *ptr;

  8.     setpwent();
  9.     while((ptr = getpwent()) != NULL)
  10.         if (strcmp(name, ptr->pw_name) == 0)
  11.             break; /* founc a match */
  12.     endpwent();
  13.     return(ptr); /* a ptr is NULL if no match found */
  14. }


开头的setpwent调用是一个自我防御机制:我们保证文件被回退,以防调用者已经通过调用getpwent函数打开了这些文件。完成时的endpwent的调用是因为getpwnam或getpwuid应该关闭所有打开的文件。
阅读(816) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~