• 《Linux/Unix系统编程手册》读书笔记5


    《Linux/Unix系统编程手册》读书笔记 目录

    第8章

    本章讲了用户和组,还有记录用户的密码文件/etc/passwd,shadow密码文件/etc/shadow还有组文件/etc/group。

    每个用户都有唯一的用户名和相关的用户标识符(UID)。用户可以属于一个或多个组,每个组都有唯一的组名和相关的组标识符(GID)。

    用户和组的用途为:1、可以确定各种系统资源的所有权;2、对赋予进程访问上述资源的权限加以控制。

    首先来看一下密码文件/etc/passwd

    lancelot@debian:~$ cat /etc/passwd
    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
    sync:x:4:65534:sync:/bin:/bin/sync
    games:x:5:60:games:/usr/games:/bin/sh
    man:x:6:12:man:/var/cache/man:/bin/sh
    lp:x:7:7:lp:/var/spool/lpd:/bin/sh
    mail:x:8:8:mail:/var/mail:/bin/sh
    news:x:9:9:news:/var/spool/news:/bin/sh
    uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
    proxy:x:13:13:proxy:/bin:/bin/sh
    www-data:x:33:33:www-data:/var/www:/bin/sh
    backup:x:34:34:backup:/var/backups:/bin/sh
    list:x:38:38:Mailing List Manager:/var/list:/bin/sh
    irc:x:39:39:ircd:/var/run/ircd:/bin/sh
    gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
    nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
    libuuid:x:100:101::/var/lib/libuuid:/bin/sh
    messagebus:x:101:105::/var/run/dbus:/bin/false
    colord:x:102:106:colord colour management daemon,,,:/var/lib/colord:/bin/false
    usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
    Debian-exim:x:104:112::/var/spool/exim4:/bin/false
    avahi:x:105:115:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
    pulse:x:106:116:PulseAudio daemon,,,:/var/run/pulse:/bin/false
    speech-dispatcher:x:107:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
    hplip:x:108:7:HPLIP system user,,,:/var/run/hplip:/bin/false
    sshd:x:109:65534::/var/run/sshd:/usr/sbin/nologin
    rtkit:x:110:118:RealtimeKit,,,:/proc:/bin/false
    statd:x:111:65534::/var/lib/nfs:/bin/false
    saned:x:112:119::/home/saned:/bin/false
    Debian-gdm:x:113:120:Gnome Display Manager:/var/lib/gdm3:/bin/false
    lancelot:x:1000:1000:lancelot,,,:/home/lancelot:/bin/bash
    mysql:x:114:121:MySQL Server,,,:/nonexistent:/bin/false
    ftp:x:115:122:ftp daemon,,,:/srv/ftp:/bin/false
    telnetd:x:116:124::/nonexistent:/bin/false

    第一个字段是登录名;第二个字段是经过加密后的密码(x),实际上经过加密后的密码是存放在shadow密码文件;

    第三个字段是用户的ID(UID);第四个字段是组ID(GID);第五个字段是注释;

    第六个字段是主目录,是用户登录后的初始路径;第七个字段是登录shell。

    接着来看实际存放密码的shadow 密码文件/etc/shadow

    格式如下:

    lancelot:$6$tnTgvJYU$OhoUNZNIeNU7rlZf/f14oD2g.Uz8SbrnWeZbR4yL4XXRvzbCeijsAZE7Y9HlzU4thKVBVcqucwntJBi/4BoY60:15880:0:99999:7:::
    mysql:!:15905:0:99999:7:::
    ftp:*:16039:0:99999:7:::
    telnetd:*:16180:0:99999:7:::

    很明显可以看到第一个字段为用户登录名,第二个字段为见过加密后的密码,后面的字段为与安全性相关的字段。

    看完用户,我们来看组文件/etc/group

    lancelot@debian:~$ cat /etc/group
    root:x:0:
    daemon:x:1:
    bin:x:2:
    sys:x:3:
    adm:x:4:
    tty:x:5:
    disk:x:6:
    lp:x:7:
    mail:x:8:
    news:x:9:
    uucp:x:10:
    man:x:12:
    proxy:x:13:
    kmem:x:15:
    dialout:x:20:
    fax:x:21:
    voice:x:22:
    cdrom:x:24:lancelot
    floppy:x:25:lancelot
    tape:x:26:
    sudo:x:27:
    audio:x:29:pulse,lancelot
    dip:x:30:lancelot
    www-data:x:33:
    backup:x:34:
    operator:x:37:
    list:x:38:
    irc:x:39:
    src:x:40:
    gnats:x:41:
    shadow:x:42:
    utmp:x:43:telnetd
    video:x:44:lancelot
    sasl:x:45:
    plugdev:x:46:lancelot
    staff:x:50:
    games:x:60:
    users:x:100:
    nogroup:x:65534:
    libuuid:x:101:
    crontab:x:102:
    fuse:x:103:
    scanner:x:104:saned,lancelot
    messagebus:x:105:
    colord:x:106:
    lpadmin:x:107:
    ssl-cert:x:108:
    bluetooth:x:109:lancelot
    utempter:x:110:
    netdev:x:111:lancelot
    Debian-exim:x:112:
    mlocate:x:113:
    ssh:x:114:
    avahi:x:115:
    pulse:x:116:
    pulse-access:x:117:
    rtkit:x:118:
    saned:x:119:
    Debian-gdm:x:120:
    lancelot:x:1000:
    mysql:x:121:
    ftp:x:122:
    vboxusers:x:123:
    telnetd:x:124:

    第一个字段是组的名称,第二个字段是经过加密的密码,第三个字段是组ID(GID),第四个字段是用户列表。

    对于加密后的密码存放在类似/etc/shadow的文件(/etc/gshadow),格式如下:

    cdrom:*::lancelot
    floppy:*::lancelot
    tape:*::
    sudo:*::
    audio:*::pulse,lancelot
    dip:*::lancelot
    www-data:*::
    backup:*::
    operator:*::
    list:*::
    irc:*::
    src:*::
    gnats:*::
    shadow:*::
    utmp:*::telnetd
    video:*::lancelot

    最后一个字段很明显是用户列表。

    接着,我们来看如何通过库函数来获取上面提到的信息。

    一、从/etc/shadow获取记录:

    1 #include <pwd.h>
    2 
    3 struct passwd *getpwnam(const char *name);
    4 
    5 struct passwd *getpwuid(uid_t uid);

    getpwnam()是根据提供的登录名返回一个指向对应的密码记录的指针。getpwuid()是根据提供的uid来返回一个指向对应的密码记录的指针。

    如果出现错误返回NULL。

    PS:对于getpwnam和getpwuid返回的指针都是指向由静态分配而成的内存,因此都是不可重入。

    这个应该是练习8-1的答案。

    8-1:执行下列代码时,将会发现,尽管这两个用户在密码文件中对应不同的ID,但该程序的输出还是会将同一个数字显示两次。请问为什么?

    printf("%ld %ld ", (long)(getpwnam("avr")->pw_uid), (long)(getpwnam("tsr")->pw_uid));

    书本的答案是这样的:getpwnam()的调用在printf()输出之前,那么getpwnam()返回的结果存放在静态分配的缓冲区中,第二个getpwnam()的返回结果会覆盖第一个的结果。

    然后我测试了一下,代码如下:

     1 /*
     2  * =====================================================================================
     3  *
     4  *       Filename:  tt1.c
     5  *
     6  *    Description:  
     7  *
     8  *        Version:  1.0
     9  *        Created:  2014年04月22日 14时56分10秒
    10  *       Revision:  none
    11  *       Compiler:  gcc
    12  *
    13  *         Author:  alan (), alan19920626@gmail.com
    14  *   Organization:  
    15  *
    16  * =====================================================================================
    17  */
    18 
    19 #include <stdio.h>
    20 #include <pwd.h>
    21 
    22 int main(int argc, char *argv[]){
    23     printf("%ld %ld
    ", (long)(getpwnam("lancelot")->pw_uid), (long)(getpwnam("root")->pw_uid));
    24     return 0;
    25 }
    View Code

    测试结果:

    lancelot@debian:~/Code/tlpi$ ./a.out 
    1000 0

    然后整个人就凌乱了。。。。。。。。。。。。。。

    后来,我把程序改成这样:

     1 #include <stdio.h>
     2 #include <pwd.h>
     3 
     4 int main(int argc, char *argv[]){
     5     struct passwd *p1, *p2;
     6     p1 = getpwnam("lancelot");
     7     p2 = getpwnam("root");
     8     printf("%ld %ld
    ", p1->pw_uid, p2->pw_uid);
     9     //printf("%ld %ld
    ", (long)(getpwnam("lancelot")->pw_uid), (long)(getpwnam("root")->pw_uid));
    10     return 0;
    11 }

    才能输出相同的值,因为两个指针变量指向的地址是一样的。但是之前那种是正确的,因为函数的参数是一值传递的方式传递,所以不存在题目说的两个值相同。

    后来我查找了作者的网站的磡误:http://www.man7.org/tlpi/errata/index.html

    发现这条题的题目修改了!!!!!!

    这样传递指针,两个输出的名字就是一样的。。。。。。。。。。。。。。

    下面是作者的解释:

    好吧,以后还要把书上的错误修改。。。。。。。

    PS:再次证明不管例子多简单也要试一试。。。。。

    二、从/etc/group获取记录

    1 #include <grp.h>
    2 
    3 struct group *getgrnam(const char *name);
    4 
    5 struct group *getgrgid(gid_t gid);

    getgrnam根据提供的组名返回指向组的密码记录的指针,getgrigid则根据提供的组号GID返回该指针。失败调用返回NULL

    PS:这两个函数也是不可重入的函数。

    三、扫描密码文件和组文件

    1 #include <pwd.h>
    2 
    3 struct passwd *getpwent(void);
    4 
    5 void setpwent(void);
    6 
    7 void endpwent(void);

    getpwent()可以逐条返回记录。setpwent()可以重置为。/etc/passwd文件的起始处。endpwent()可以关闭文件。

    四、从/etc/shadow密码文件中获取记录

    1 #include <shadow.h>
    2 
    3 struct spwd *getspnam(const char *name);
    4 
    5 struct spwd *getspent(void);
    6 
    7 void setspent(void);
    8 
    9 void endspent(void);

    getspnam和getspent会返回指向shadow密码记录的指针,失败调用返回NULL。

    setspent会重置为文件的起始位置,endspent会关闭文件。

    五、密码加密

    1 #define _XOPEN_SOURCE
    2 #include <unistd.h>
    3 
    4 char *crypt(const char *key, const key *salt);

    #define _XOPEN_SOURCE 是为了获取crypt的声明。

    key为输入的密码,salt指向一个两字节的字符串,用来改变DES算法。成功调用返回加密后的密码,失败返回NULL。

    ---------------------吐槽:好好写博客,写博客的时候思考的感觉真好,要多读书,多code,多思考---------------------------

    听同学说有很多厉害的人已经找到实习了,真的后悔大一大二的无作为。正因为后悔,所以要做得更好!!!!

    继续努力!!!!!!

    ---------------------------------------------------------------------------------------------------------------------------------------------------

    练习:

    8-2: 使用sptwent()、getpwent()和endpwent()来实现getpwnam()。

    这题个人觉得很简单,因为getpwent()是逐条查找,查找匹配就输出。输出完应该调用sptwent将文件的偏移量重置为文件的起始位置。结束的时候调用endpwent关闭文件。

     1 /*
     2  * =====================================================================================
     3  *
     4  *       Filename:  8-2.c
     5  *
     6  *    Description:  
     7  *
     8  *        Version:  1.0
     9  *        Created:  2014年04月22日 16时48分09秒
    10  *       Revision:  none
    11  *       Compiler:  gcc
    12  *
    13  *         Author:  alan (), alan19920626@gmail.com
    14  *   Organization:  
    15  *
    16  * =====================================================================================
    17  */
    18 
    19 #include <pwd.h>
    20 #include <string.h>
    21 #include <stdio.h>
    22 #include "tlpi_hdr.h"
    23 
    24 struct passwd * Getpwnam(const char *name){
    25     struct passwd *pwd;
    26     while((pwd = getpwent()) != NULL){
    27         if(strcmp(pwd->pw_name, name) == 0){
    28             setpwent();
    29             return pwd;
    30         }
    31     }
    32     setpwent();
    33     return NULL;
    34 }
    35 
    36 int main(int argc, char *argv[]){
    37     int i;
    38     struct passwd *p;
    39     if(argc < 2 || strcmp(argv[1], "--help") == 0)
    40         usageErr("%s user-names...", argv[0]);
    41 
    42     for(i = 1; i < argc; ++i){
    43         p = Getpwnam((const char *)argv[i]);
    44         if(p == NULL)
    45             printf("%s does not exit
    ", argv[i]);
    46         else{
    47             printf("%s, UID: %ld, GID: %ld
    ", argv[i], (long)p->pw_uid, (long)p->pw_gid);
    48         }
    49     }
    50     
    51     endpwent();
    52     exit(EXIT_SUCCESS);
    53 }

    测试结果:

    lancelot@debian:~/Code/tlpi$ ./a.out lancelot root
    lancelot, UID: 1000, GID: 1000
    root, UID: 0, GID: 0
  • 相关阅读:
    Python 42 mysql用户管理 、pymysql模块
    Python 41 多表查询 和 子查询
    Python 41 完整查询语句 和 一堆关键字
    Python 40 数据库-外键约束 、多对一与多对多的处理
    Python 40 数据库-约束
    Python 38 注册和修改密码
    eas之关于编码规则
    eas之界面之间传递参数
    eas之获取集合
    eas之单据删除代码
  • 原文地址:https://www.cnblogs.com/alan-forever/p/3680261.html
Copyright © 2020-2023  润新知