Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1018962
  • 博文数量: 113
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3943
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-02 14:36
文章分类
文章存档

2019年(2)

2018年(10)

2017年(1)

2016年(50)

2015年(12)

2014年(9)

2013年(29)

分类: C/C++

2013-05-19 00:08:29

口令文件:
linux中的口令文件/etc/passwd中包含以下七个字段的信息,这些字段在passwd结构体中
用户名:加密口令:数值用户id:数值组id: 注释字段:初始工作目录:初始shell (各字段之间以 冒号 分割)



我们读/etc/passwd文件能得到类似下面的信息:(只截取了部分内容)
root:         x:             0:          0:              root:          /root:             /bin/bash
daemon:    x:             1:          1:              daemon:     /usr/sbin:       /bin/sh
feng:         x:            1000:      1000:         feng,,,:      /home/feng:    /bin/bash


 这里只是为了和上面的对齐,实际文件中没有空格。


加密口令字段为一个占位符(x),是因为此处为早期加密口令的放置位置,但存在安全隐患。便将此字段放在/etc/shadow文件中(后面介绍)


这些存放在口令文件中的信息我们如何获取呢,POSIX.1标准定义了两个获取口令文件项的函数。


#include


struct passwd *getpwuid(uid_t uid);//给出数值用户id后,可返回包含上面所说的七个段的结构体(passwd)指针

struct passwd *getpwnam(const char *name);//给出用户名后,可返回passwd结构体指针
两函数若成功返回指针,若无对应项则返回NULL,若出错返回NULL,并设置errno。


注意上面的 passwd 结构体是相关函数内的静态变量,只要调用相关函数,就会重写其内容
比如我们可以用这两个函数来获得feng 这个用户在/etc/passwd中的信息
 6 int main(void){
  7         struct passwd *p_uid;
  8         struct passwd *p_nam;
  9         errno=0;
 10         if((p_uid=getpwuid(1000))==NULL){
 11                 if(errno!=0)
 12                         perror("getpwuid error");
 13                 exit(1);
 14         }
 15         printf("%s\t%s\t%d\t%d\t%s\t%s\t%s\n",  p_uid->pw_name,
 16                                                 p_uid->pw_passwd,
 17                                                 p_uid->pw_uid,
 18                                                 p_uid->pw_gid,
 19                                                 p_uid->pw_gecos,
 20                                                 p_uid->pw_dir,
 21                                                 p_uid->pw_shell);
 22         printf("\n\n");
 23         errno=0;
 24         if((p_nam=getpwnam("feng"))==NULL){
 25                 if(errno!=0){
 26                         perror("getpwnam error");
 27                         exit(1);
 28                 }
 29         }
 30         printf("%s\t%s\t%d\t%d\t%s\t%s\t%s\n",  p_nam->pw_name,
 31                                                 p_nam->pw_passwd,
 32                                                 p_nam->pw_uid,
 33                                                 p_nam->pw_gid,
 34                                                 p_nam->pw_gecos,
 35                                                 p_nam->pw_dir,
 36                                                 p_nam->pw_shell);
 37         exit(0);
 38 }


输出信息如下:
feng@ubuntu:~/learn_linux_c_second/chapter_6$ ./a.out
feng x 1000 1000 feng,,, /home/feng /bin/bash




feng x 1000 1000 feng,,, /home/feng /bin/bash




但是这两个函数有个不足,他们只能查看 /etc/passwd中的一个用户信息。如果我需要查看整个口令文件。那么就需要下面这个函数
#include


struct passwd *getpwent(void);
成功则返回passwd指针,到文件尾返回NULL,出错返回NULL并设置errno
void setpwent(void); //反绕文件,让下次一的读从文件头开始。
void endwent(void); //关闭文件,用getpwent查完文件后要用它来关闭。


我们可以用这几个函数来遍历下/etc/passwd中的内容:
  6 int main(void){
  7         struct passwd *p;
  8 
  9         setpwent();
 10         errno=0;
 11         while((p=getpwent())!=NULL){
 12                 printf("%s\t%s\t%d\t%d\t%s\t%s\t%s\n",  p->pw_name,
 13                                                         p->pw_passwd,
 14                                                         p->pw_uid,
 15                                                         p->pw_gid,
 16                                                         p->pw_gecos,
 17                                                         p->pw_dir,
 18                                                         p->pw_shell);
 19 
 20         }
 21         endpwent();
 22         printf("\n");
 23         if(errno!=0){
 24                 perror("getpwend error");
 25                 exit(1);
 26         }
 27         exit(0);
 28 }
输出如下(截取部分):
feng@ubuntu:~/learn_linux_c_second/chapter_6$ ./a.out
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
sys x 3 3 sys /dev /bin/sh







阴影口令文件:
阴影口令文件/etc/shadow文件中包含以下 9 个字段,这些字段包含在spwd的机构体中,我们这里只说明他的前两个字段:


用户登录名(char *sp_namp): 加密口令(char *sp_pwdp)(剩余七个字段说明了 加密口令的一些性质 这里不介绍)


我们读/etc/shadow 文件能得到类似下面的内容:


        root:                                                $6$GpSUr90.$26sUXzQAPn4uLBIIxyXbXU9F5niawOvjNgnb1.HXFeHlLsVPDJiasQFDcJpHRoE4j3Gj.5OAPfxWlMO6szIdv.
      daemon:                                *
        feng:                                                $6$kh2XW8rM$mJwC2wlBf//AV9Mk.bwJ.q6sYkUIq5uC9DyLZM891LgeJMvLEMXwEJSVf2XukaT9z5u7KJX6ITDzT9bktb2uX.
这里我们只截取了前两个字段。


与访问口令文件一样,也有一组函数用来访问阴影口令文件的全部内容
#include
struct spwd *getspnam(char *name);


struct spwd *getspent(void);
void setspent(void);
void endspent(void);


同样spwd结构也是相关函数内的静态变量。


阴影口令文件一般用户是不能读取的。所以下面的例子我们用切换到root运行


我们写一个实例程序来使用它们:
int main(void){
        struct spwd *p_nam;
        struct spwd *p_ent;


        if((p_nam=getspnam("feng"))==NULL){
                perror("getspnam error");
                exit(1);


        }
        printf("%s\t%s\n\n",p_nam->sp_namp,p_nam->sp_pwdp);


        setspent();
        while((p_ent=getspent())!=NULL){
                printf("%s\t%s\n",p_ent->sp_namp,p_ent->sp_pwdp);       
        }
        endspent();
        exit(0);
}
程序的输出如下:(部分截取)
root@ubuntu:/home/feng/learn_linux_c_second/chapter_6# ./a.out
feng $6$kh2XW8rM$mJwC2wlBf//AV9Mk.bwJ.q6sYkUIq5uC9DyLZM891LgeJMvLEMXwEJSVf2XukaT9z5u7KJX6ITDzT9bktb2uX.


root $6$GpSUr90.$26sUXzQAPn4uLBIIxyXbXU9F5niawOvjNgnb1.HXFeHlLsVPDJiasQFDcJpHRoE4j3Gj.5OAPfxWlMO6szIdv.
daemon *
bin *
sys *
sync *


组文件:
组文件/etc/group中定义了4个字段,这些字段包含在 group 结构体中


组名(char *gr_nam): 加密口令(char *ge_passwd): 数值组id(int gr_gid): 包含的用户(char **gr_mem)


我们读取/etc/group 文件可得到类似下面的内容:


root:                         x:                                          0:
daemon:                    x:                                          1:
bin:                         x:                                             2:
sys:                          x:                                         3:
feng:                         x:                                          1000:
adm:                          x:                                         4:                             feng


下面两个函数可用来查看单个组的信息
#include
struct group *getgrgid(ged_t);
struct group *getgrnam(const char *name);
成功则返回指针,出错返回NULL

如果要搜索真个文件,则用以下几个函数
#include
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
使用方法和 访问口令文件一样,这么不做测试

附加组:
我们知道一个用户可以属于多个组,那么下面的一组函数就是用来获得和设置附加组id的
#include
#include


int getgroups(int gidsetsize,gid_t grouplist);//附加组id写到grouplist中,该数组最多存放元素gidsetsize个
                        成功返回附加组id数,出错返回-1
int setgroups(int ngroups,const gid_t grouplist[]);//该函数由超级用户调用,以便为调用进程设置附加组id表
                        成功返回0,出错返回-1
int initgroups(const char *username,gid_t basegid);//由超级用户调用,,根据etc/group文件确定username所属的组,然后调用setgroups设置,用来初始化附加组(basegid是username在口令文件中的组id)
                        成功返回0,出错返回-1


我们来写两个针对getgroups和setgroups的测试。(initgroups一般只是初始化用户的附加组)


测试getgroups:
 7 int main(void){
  8         gid_t groups[16];
  9         int val;
 10         if((val=getgroups(sizeof(groups),groups))==-1){
 11                 perror("getgroups error");
 12                 exit(1);
 13         }
 14         int i;
 15         for(i=0;i
 16                 printf("%d\t",groups[i]);
 17 
 18         }
 19         printf("\n");
 20         exit(0);
 21 
 22 }
我么用 feng 用户运行这个程序输出如下:
feng@ubuntu:~/learn_linux_c_second/chapter_6$ ./a.out
4 24 27 30 46 109 124 1000


我们来查看一下/etc/group 文件看看feng 用户是不是属于这几个组
feng@ubuntu:~/learn_linux_c_second/chapter_6$ grep feng /etc/group
adm:x:4:feng
cdrom:x:24:feng
sudo:x:27:feng
dip:x:30:feng
plugdev:x:46:feng
lpadmin:x:109:feng
feng:x:1000:
sambashare:x:124:feng


从/etc/group 文件中我们看到 feng 的确是属于这几个组


测试 setgroups:
 8 int main(void){
  9         gid_t groups[16];
 10         int val;
 11         if((val=getgroups(sizeof(groups),groups))==-1){
 12                 perror("getgroups error");
 13                 exit(1);
 14         }
 15         int i;
 16         for(i=0;i
 17                 printf("%d\t",groups[i]);
 18 
 19         }
 20         printf("\n");
 21 
 22         groups[0]=1;
 23         groups[1]=2;
 24         if((setgroups(2,groups))==-1){
 25                 perror("setgroups error");
 26                 exit(1);
 27         }
 28         if((val=getgroups(sizeof(groups),groups))==-1){
 29                 perror("getgroups error");
 30                 exit(1);
 31         }
 32         for(i=0;i
 33                 printf("%d\t",groups[i]);
 34 
 35         }
 36         printf("\n");
 37 
 38 
 39 exit(0);


我们先输出原先的附加组,然后改变他的附加组后在此输出;


注意setgroups 是超级用户调用的,所以我们要切换到超级用户运行上面的程序:
root@ubuntu:/home/feng/learn_linux_c_second/chapter_6# ./a.out
0
1 2
root@ubuntu:/home/feng/learn_linux_c_second/chapter_6# groups
root


我们看到root的附加组 只有0(root组),然后我们设置他的附加组为 1 和2。
程序结束后,我们用groups命令查看root的所属组,发现root只有root(0)组,也就是说,附加组的改变只会在程序内起作用。

阅读(2295) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~