1.口令文件
UNIX系统的口令文件(/etc/passwd)包含如下个字段,这些字段包含在<pwd.h>中定义的passwd文件中。
POSIX只定义了两个获取口令文件项的函数,在给出用户登录名或者数值用户ID后,这两个函数就能查询相关项。
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
两个函数返回值,如果成功返回指针,出错则返回NULL。
实践:
#include <stdio.h>
#include <pwd.h>
int main(void){
struct passwd* pwd;
if((pwd = getpwuid(1)) == NULL){
perror("getpwuid");
return -1;
}
printf("%s,%s,%ld,%ld,%s,%s,%s\n",pwd->pw_name,pwd->pw_passwd,pwd->pw_uid,pwd->pw_gid,pwd->pw_gecos,pwd->pw_dir,pwd->pw_shell);
if((pwd = getpwnam("daemon")) == NULL){
perror("getpwnam");
return -1;
}
printf("%s,%s,%ld,%ld,%s,%s,%s\n",pwd->pw_name,pwd->pw_passwd,pwd->pw_uid,pwd->pw_gid,pwd->pw_gecos,pwd->pw_dir,pwd->pw_shell);
return 0;
}
运行结果:
daemon,x,1,1,daemon,/usr/sbin,/bin/sh
daemon,x,1,1,daemon,/usr/sbin,/bin/sh
如果要查看整个口令文件,可使用以下三个函数。
#include <pwd.h>
struct passwd* getpwent(void); //如果成功返回指针,出错或者达到文件末尾则返回NULL。
void setpwent(void); //反绕所使用的文件,使指针指向文件的第一行
void endpwent(void); //关闭文件。
实践:
#include <stdio.h>
#include <pwd.h>
int main(void){
struct passwd* pwd;
if((pwd = getpwent()) == NULL){
perror("getpwent");
return -1;
}
printf("%s,%s,%ld,%ld,%s,%s,%s\n",pwd->pw_name,pwd->pw_passwd,pwd->pw_uid,pwd->pw_gid,pwd->pw_gecos,pwd->pw_dir,pwd->pw_shell);
setpwent();
while((pwd = getpwent()) != NULL){
printf("%s,%s,%ld,%ld,%s,%s,%s\n",pwd->pw_name,pwd->pw_passwd,pwd->pw_uid,pwd->pw_gid,pwd->pw_gecos,pwd->pw_dir,pwd->pw_shell);
}
endpwent();
return 0;
}
运行结果:
root,x,0,0,root,/root,/bin/bash
root,x,0,0,root,/root,/bin/bash
daemon,x,1,1,daemon,/usr/sbin,/bin/sh
bin,x,2,2,bin,/bin,/bin/sh
.......此处省略多行
hplip,x,112,7,HPLIP system user,,,,/var/run/hplip,/bin/false
pulse,x,113,121,PulseAudio daemon,,,,/var/run/pulse,/bin/false
saned,x,114,123,,/home/saned,/bin/false
yan,x,1000,1000,yanwenjie,,,,/home/yan,/bin/bash
sshd,x,115,65534,,/var/run/sshd,/usr/sbin/nologin
2.阴影文件
因为/etc/passwd文件对普通用户来说是可见的,所以现在的系统都将加密的密码存放在一个阴影文件(shadow password)中,
该文件至少包含用户名和密码。阴影文件(/etc/shadow)各字段说明如下:
与口令文件一组函数类似,有另一组函数可以访问阴影文件。(只有root用户才能权限调用该组函数)
#include <pwd.h>
struct spwd *getspnam(const char *name); //如果成功返回指针, 如果出错则返回NULL。
struct spwd *getspent(void); //如果成功返回指针, 如果出错则返回NULL。
void setspent(void); //反绕阴影文件,将指针指向文件的第一行。
void entspent(void); //关闭文件。
实践:
#include <stdio.h>
#include <shadow.h>
int main(void){
struct spwd* spwd;
if((spwd = getspnam("yan")) == NULL){
perror("getspnam");
return -1;
}
printf("%s,%s,%ld,%ld,%ld,%ld,%ld,%ld,%lu\n",spwd->sp_namp,spwd->sp_pwdp,spwd->sp_lstchg,spwd->sp_min,spwd->sp_max,spwd->sp_warn,spwd->sp_inact,spwd->sp_expire,spwd->sp_flag);
if((spwd = getspent()) == NULL){
perror("getspent");
return -1;
}
setspent();
while((spwd = getspent()) != NULL){
printf("%s,%s,%ld,%ld,%ld,%ld,%ld,%ld,%lu\n",spwd->sp_namp,spwd->sp_pwdp,spwd->sp_lstchg,spwd->sp_min,spwd->sp_max,spwd->sp_warn,spwd->sp_inact,spwd->sp_expire,spwd->sp_flag);
}
endspent();
return 0;
}
运行结果:
yan,$6$OGnTte0B$fAq8CO01RIyf2mkaBUaY2LZjYyZDyLrQVbv94im4tpMgs1SdTjHIC9ls1p9MDI4TP5meeI8HWxgrkKWqJII.D.,15807,0,99999,7,-1,-1,4294967295
root,$6$sr2Imb6g$hbPz1T3OJTszUFgQXR36oW1l4qnzEA8cZR1qgqCMq3jIpv4Ev4Kyt3Nbfv/2PcOLYKoLk9sA.aGtV.srKGZM8.,15807,0,99999,7,-1,-1,4294967295
daemon,*,15630,0,99999,7,-1,-1,4294967295
bin,*,15630,0,99999,7,-1,-1,4294967295
.......此处省略多行
saned,*,15630,0,99999,7,-1,-1,4294967295
yan,$6$OGnTte0B$fAq8CO01RIyf2mkaBUaY2LZjYyZDyLrQVbv94im4tpMgs1SdTjHIC9ls1p9MDI4TP5meeI8HWxgrkKWqJII.D.,15807,0,99999,7,-1,-1,4294967295
sshd,*,15807,0,99999,7,-1,-1,4294967295
3.组文件
UNIX组文件包含了下表所示的字段,这些字段包含在<grp.h>所定义的group结构中。
字段gr_mem是一个指针数组,其中每个指针各指向一个属于该组的用户名,该数组以空指针结尾。
对组文件的访问函数如下,形式基本与口令文件和阴影文件相同。
#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);
4.附加组
我们不仅可以属于口令文件记录项中组ID所对应的组,也可以属于多达16个另外的组。为了获取和设置附加组ID,提供以
下函数。
#include <unistd.h>
int getgroup(int gidsetsize, gid_t grouplist[]); //如果成功返回附加组ID,出错则返回-1.
//函数将个附加组ID填写到数组grouplist中,数组中存放的元素最多为gidsetsize个。
#include <grp.h> //on linux
#include <unistd.h> //on FreeBSD and Mac OS X and Solaris
int setgroups(int ngroups, const gid_t grouplist[]); //如果成功返回0,出错则返回-1.
//由root调用,为进程设置附加组ID表,grouplist是组ID数组,ngroups指定了数组中的元素个数。
#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.
//
initgroups()用来从组文件(/etc/group)读取整个组文件,然后对username确定其组的成员关系,然后调用setgroups,
为该用户初始化附加组ID表。除了在组文件中找到username是成员的所有组,initgroups也在附加组ID表中包括了
basegid,basegid是username在口令文件中的组ID。
5.其他数据文件
至此讨论了口令文件,阴影文件和组文件,在日常操作中,UNIX还使用其他文件。一般情况下,对于每个数据文件至少
有三个函数:get函数,set函数,end函数。下面列出了UNIX常用的文件对应的函数。