系统数据文件操作函数介绍

UNIX 中有个和用户登录密切相关的口令文件 /etc/passwd,POSIX.1 定义了下面两个可获取口令文件项的函数。

#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
/* 返回值:若成功,都返回指针;否则,都返回 NULL */

struct passwd{
char *pw_name; // 用户名
char *pw_passwd; // 加密口令
uid_t *pw_uid; // 数值用户 ID
gid_t *pw_gid; // 数值组 ID
char *pw_gecos; // 注释字段
char *pw_dir; // 初始工作目录
char *pw_shell; // 初始 shell(用户程序)
char *pw_class; // 用户访问类
time_t *pw_change; // 下次更改口令时间
time_t *pw_expire; // 账户有效期时间
};

getpwuid 函数由 ls 程序使用,它将 i 节点中的数字用户 ID 映射为用户登录名。而在键入登录名时,getpwnam 函数由 login 程序使用。这两个函数都返回一个指向 passwd 结构的指针,该结构包含了组成 /etc/passwd 文件的各个字段,它通常是函数内部的静态变量,所以只要调用任一相关函数,其内容就会被重写。
如果要查看的只是登录名或用户 ID,那么这两个函数能满足要求,而如果要查看整个口令文件时,则可使用 XSI 扩展中提供的下列 3 个函数。

#include <pwd.h>
struct passwd *getpwent(void);
/* 返回值:若成功,返回指针;若出错或到达文件尾端,返回 NULL */
void setpwent(void);
void endpwent(void);

调用 getpwent 时,它返回口令文件中的下一个记录项。每次调用此函数都会重写 passwd 结构。在第一次调用时,它就会打开它所使用的各个文件。函数 setpwent 打开(如果文件尚未打开)并反绕它所使用的文件,endpwent 则关闭这些文件。在使用 getpwent 查看完口令文件后,一定要调用 endpwent 关闭来这些文件。因为 getpwent 知道什么时间应当打开它所使用的文件(第一次被调用时),但是却不知道何时关闭它们。
下面是一个利用这 3 个函数实现的一个 getpwnam 程序。

#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;
}
endpwent();
return ptr; // ptr is NULL if no match found.
}

在函数开始处调用 setpwent 是自我保护性的措施,以便确保如果在此之前已经调用 getpwent 打开了有关文件的情况下,反绕这些文件使它们定位到开始处。getpwnam 和 getpwuid 完成后不应使有关文件仍处于打开状态,所以要调用 endpwent 关闭它们。
不过为了安全,加密口令一般是存放在阴影口令文件 /etc/shadow 中,该文件至少要包含用户名和加密口令,与该口令相关的其它信息也可存放在该文件中。一般用户是不可以读取该文件的,仅有少数几个程序需要访问加密口令,如 login 和 passwd 等,这些程序常常是设置用户 ID 为 root 的程序。在 Linux 3.2.0 和 Solaris 10 中,与访问口令文件的一组函数相类似,有另一组函数可用于访问阴影口令文件(在 FreeBSD 8.0 和 Mac OS X 10.6.8 中,没有阴影口令结构,附加的账户信息存放在口令文件中)。

#include <shadow.h>
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
/* 返回值:若成功,都返回指针;否则,都返回 NULL */
void setspent(void);
void endspent(void);

struct spwd{
char *sp_namp; // 用户登录名
char *sp_pwdp; // 加密口令
int sp_lstchg; // 上次更改口令以来经过的时间
int sp_min; // 经多少天后允许修改
int sp_max; // 要求更改尚余天数
int sp_warn; // 超期警告天数
int sp_inact; // 账户不活动之前尚余天数
int sp_expire; // 账户超期天数
unsigned int sp_flag; // 保留
};

UNIX 中的每个账户除了这些个人信息外,还拥有所属组的相关信息,这些信息保存在 /etc/group 文件中。UNIX 也提供了类似上面的一组函数来操作该文件。

#include <grp.h>
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
/* 返回值:若成功,都返回指针;否则,都返回 NULL */

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

struct group{
char *gr_name; // 组名
char *gr_passwd; // 加密口令
int gr_gid; // 数值组 ID
char **gr_mem; // 指向各用户名指针的数组,以 null 指针结尾
};

当用户登录时,系统就按口令文件记录项中的数值组 ID 赋给他实际组 ID(可以在任何时候使用 newgrp 更改组 ID,执行不带参数的 newgrp 则可返回到原来的组)。在 4.2 BSD 引入了附属组 ID 的概念后,一个账户还可属于多至 16(由 NGROUPS_MAX 规定)个另外的组。所以文件访问权限检查时不仅将进程的有效组 ID 与文件的组 ID 相比较,而且也将所有附属组 ID 与文件的组 ID 进行比较。
可使用下面 3 个函数来获取和设置附属组 ID。

#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);
/* 返回值:若成功,返回附属组 ID 数量;否则,返回 -1 */
#include <grp.h> // on Linux
#include <unistd.h> // on FreeBSD, Mac OS X, and Solaris
int setgroups(int ngroups, const gid_t groupslist[]);
#include <grp.h> // on Linux and Solaris
#include <unistd.h> // on FreeBSD and Mac OS X
int initgroups(const char *username, gid_t basegid);
/* 返回值:若成功,都返回 0;否则,都返回 -1 */

getgroups 将进程所属用户的各附属组填写到数组 grouplist 中,填写入的附属组 ID 数最多为 gidsetsize 个,实际填写的附属组 ID 数由函数返回。特殊地,如若 gidsetsize 为 0,则函数只返回附属组 ID 数,而不修改 grouplist(这使得调用者可以确定 grouplist 的长度,以便进行分配)。
setgroups 可由超级用户调用以便为调用进程设置附属组 ID 表。grouplist 是组 ID 数组,而 ngroups 说明了数组中的元素数,ngroups 的值不能大于 NGROUPS_MAX。
通常,只有 initgroups 函数调用 setgroups,initgroups 使用 getgrent 等函数读整个组文件,然后对 username 确定其组的成员关系,然后调用 setgroups,以便为该用户初始化附属组 ID 表。除了在组文件中找到 username 是成员的所有组,initgroups 也在附属组 ID 表中包括了 basegid,basegid 是 username 在口令文件中的组 ID。只有 login 等少数几个程序会调用 initgroups 函数。
除了口令文件和组文件外,UNIX 系统还使用很多其他文件。比如,记录各网络服务器所提供服务的数据文件 /etc/services,记录协议信息的数据文件 /etc/protocols,以及记录网络信息的数据文件 /etc/networks 等。这些数据文件一般都至少提供了类似的 get、set 和 end 函数。如果数据文件支持某种形式的键搜索,则也提供类似于口令文件中的 getpwnam 和 getpwuid 之类的可搜索具有指定键的记录的例程。下表列出了 UNIX 常用的这类例程。
[img]http://dl2.iteye.com/upload/attachment/0126/5338/48343d61-f10a-364d-b736-47ce98e15b32.png[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值