当前位置:Linux教程 - Linux - 使用PAM进行统一身份的认证

使用PAM进行统一身份的认证



         蓝森林 http://www.lslnet.com 2000年4月20日 09:25


    作 者: bricks


    PAM是 PLUGGABLE AUTHENTICATION MODULES 的缩写.
    可插入的认证模块(并不是Linux指的模块)用于实现应用程序的认证机制,
    是程序员或管理员不需要重新编写或编译程序就可以改变认证机制.
    在linux它已经被广泛的应用了, 例如: /etc/securitty /etc/onlogin
    /etc/ftpusers 实际上都是给它用的.你在登陆的时候的输入密码和你修改密码
    时也都用的是它./etc/pam.conf和/etc/pam/* 都是它的配置文件.

    它最大的优点是它的弹性和可扩充性. 你可以随意修改认证机制, 按你的实
    际需要来定制系统.你了解后就会非常清楚了.

    DESIGN GOALS(设计目标)

    (a) 管理员可以选择认证方式, 从简单的密码到智能卡系统.

    (b) 可以为不同的程序配置不同的认证机制.如 使telnet使用 S/Key认证.
    而本机的 login 缺使用一般的 UNIX password.

    (c) 支持程序的显示方式的需求. 如login 需要基于终端的显示, 而dtlogin
    需要 X 显示, 而`ftp\" 和 `telnet\"需要透过网络来认证.

    (d) 支持为一个程序配置同时使用多种认证机制.

    (e) 可是用户在使用多种认证机制时,不必为同一个密码敲入多次.

    (f) 可是用户在认真时需要输入多个密码.

    (g) 当底层的认证机制改变时上层软件不需要修改.

    (h) 结构为system authentication提供一个 _pluggable_ model.

    (i) 必须能满足现有的服务需要.

    4. OVERVIEW OF THE PAM FRAMEWORK (纵览PAM的框架)

    其核心实际上是一些库函数. 你写的应用程序要调用它们.PAM为你提供
    了一套入口(the front end). 而这套函数互调用 特定认证机制所定义的模块
    (the back end).
    简单的说是这样的: 你调用一个函数仅仅告诉它你要认正,这就足够了.至于
    用那一种机制来认证是由配置文件规定的. 你只需要看一看返回值就知道认证是
    否成功了. 对于开发应用程序的人来说只需要记住几个函数.

    ftp telnet login (Applications)
    | | |
    | | |
    +--------+--------+
    |
    +-----+-----+
    | PAM API | <-- pam.conf file
    +-----+-----+
    |
    +--------+--------+
    UNIX Kerberos Smart Cards (Mechanisms)

    Figure 1: 基本的 PAM 结构

    PAM的功能被分为四个部分: (1) authentication(认证), (2)account
    (账号管理), (3) session (对话管理), 和 (4) password (密码管理).

    这四个东东都是什么呢?

    (a) Authentication management:
    包括 `pam_authenticate()\" 来认证用户, `pam_setcred()\" 来
    设置 刷新和销毁用户的 credentials.

    (b) Account management:
    包括 `pam_acct_mgmt()\" 来检查用的账号是否还有效.可以被用来
    检查用户是否超时或账号是否过期.

    (c) Session management:
    包括 `pam_open_session()\" 和 `pam_close_session()\" 用于对话
    过程的管理. 例如: 可以用来纪录用户的连接时间. 一次telnet过程
    实际上也是一个session.

    (d) Password management:
    `pam_chauthtok()\" 用来修该密码.


    程序通过调用 `pam_start()\"和 `pam_end()\" 来开始或结束一次PAM 事务.
    `pam_get_item()\" 和 `pam_set_item()\" 读写有关事务的信息.

    可以用`pam_strerror()\"来取得错误信息.

    如何配置你的系统呢?

    pam.conf的一个例子:
    #服务名 模块类型 控制标志 模块的名字 选项
    #------- ----------- ------------ ----------- -------
    login auth required pam_unix_auth.so nowarn
    login session required pam_unix_session.so
    login account required pam_unix_account.so
    ftp auth required pam_skey_auth.so debug
    ftp session required pam_unix_session.so
    telnet session required pam_unix_session.so
    login password required pam_unix_passwd.so
    passwd password required pam_unix_passwd.so
    OTHER auth required pam_unix_auth.so
    OTHER session required pam_unix_session.so
    OTHER account required pam_unix_account.so

    `OTHER\" 被用来为没有它数指定的服务用的.
    选项是随着模块的参数.为一个服务是可以指定多个auth模块的.它们一次被调用
    来验证用户的身份.这叫做 Stacked Modules.
    下面的例子为LOGIN指定了三个模块.
    login
    |
    +--------+--------+
    | | |
    session auth account
    | | |
    +--+--+ +--+--+ +--+--+
    | PAM | | PAM | | PAM |
    +--+--+ +--+--+ +--+--+
    | | |
    UNIX UNIX UNIX
    session auth account
    |
    Kerberos
    auth
    |
    RSA
    auth

    Figure 2: Stacking With the PAM Architecture

    pam.conf中的 `控制标志\" 实际上是指明这些 Stacked module 的工作方式.
    它可取的值如下:
    (a) `required\":
    该模块的让正必须通过,失败者立即返回错误信息.

    (b) `optional\":
    表示可以忽略它的错误而继续下面一个模块.

    (c) `sufficient\":
    表明该模块的让正已经是足够了,下面的模块就不用调用了.立即
    返回成功的消息.


    Password-Mapping 密码的映射

    多层的模块认证可能会需要多个密码. 则会使用户感到厌烦.一个简单的方法是
    是用户使用同一个密码而透过mapping机制来加强安全性. 其实是通过一个密码来产
    生另一个密码,使一个密码可被多个模块使用. 当然要保证第一个密码是强壮的.

    auth的模块多有下列 `选项\":
    (a) `use_first_pass\":
    使用第一个模块要求输入的密码.不再向用户提示要密码.

    (b) `try_first_pass\":
    先试着使用第一个模块要求输入的密码, 不对再要求用户输入.

    (c) `use_mapped_pass\":
    使用 password-mapping 来得到密码, 不再向用户提示要密码.

    (d) `try_mapped_pass\":
    先试着使用 password-mapping 来得到密码, 不对再向用户提示要密码.

    下面的例子可以看懂了吧:
    pam.conf
    login auth required pam_unix.so debug
    login auth required pam_kerb.so use_mapped_pass
    login auth optional pam_rsa.so use_first_pass


    这种设计使你没有办法来知道执行的具体情况. 当然它也是与应用程序无关的.
    Notes:
    在linux下, 也可以用/etc/pam.d中的文件来配置.这些文件的格式与pam.conf
    类似,只是没有服务名. 其服务名就是它的文件名.
    入上述的login也可以配置如下:
    /etc/pam.d/login
    auth required pam_unix.so debug
    auth required pam_kerb.so use_mapped_pass
    auth optional pam_rsa.so use_first_pass


    APPENDIX A. PAM API\"S

    A.1. Framework Layer API\"s

    int
    pam_start(
    char *service_name, // pam.conf中的服务的名字
    char *user, // 用户名
    struct pam_conv *pam_conversation,
    // 一个用于互交的函数
    pam_handle_t **pamh // 一个句柄
    );

    `pam_start()\" 用于初始化一次pam事务
    PAM modules 透过struct pam_conv *pam_conversation中定义的函数来与应用程序
    通信.

    int
    pam_end(
    pam_handle_t *pamh,
    int pam_status //上一个pam函数的返回值
    );

    `pam_end()\" 结束一次PAM 事务, 释放相关的内存.

    int
    pam_set_item(
    pam_handle_t *pamh,
    int item_type,
    void *item
    );

    int
    pam_get_item(
    pam_handle_t *pamh,
    int item_type,
    void **item
    );

    `pam_get_item()\" 和 `pam_set_item()\" 用于一些特殊处理.读一些信息.

    Table 5: Possible Values for Item_type

    Item Name Description
    --------- -----------
    PAM_SERVICE The service name
    PAM_USER The user name
    PAM_TTY The tty name
    PAM_RHOST The remote host name
    PAM_CONV The pam_conv structure
    PAM_AUTHTOK The authentication token (password)
    PAM_OLDAUTHTOK The old authentication token
    PAM_RUSER The remote user name


    char *
    pam_strerror(
    int errnum
    );


    int
    pam_set_data(
    pam_handle_t *pamh,
    char *module_data_name,
    char *data,
    (*cleanup)(pam_handle_t *pamh, char *data,
    int error_status)
    );

    int
    pam_get_data(
    pam_handle_t *pamh,
    char *module_data_name,
    void **datap
    );

    用于读取与模块相关的数据.

    A.2. Authentication API\"s

    int
    pam_authenticate(
    pam_handle_t *pamh,
    int flags
    );

    int
    pam_setcred(
    pam_handle_t *pamh,
    int flags
    );

    A.3. Account Management API

    int
    pam_acct_mgmt(
    pam_handle_t *pamh,
    int flags
    );

    A.4. Session Management API\"s

    int
    pam_open_session(
    pam_handle_t *pamh,
    int flags
    );

    int
    pam_close_session(
    pam_handle_t *pamh,
    int flags
    );

    A.5. Password Management API\"s

    int
    pam_chauthtok(
    pam_handle_t *pamh,
    int flags
    );

    APPENDIX B. SAMPLE PAM APPLICATION
    /*
    /etc/pam.conf
    check_user auth required /lib/security/pam_unix_auth.so
    check_user account required /lib/security/pam_unix_acct.so
    注意要和你的系统一致redhat是这样
    编译时要这样:
    gcc check.c -ldl -lpam -lpam_misc -o check_user
    */

    #include
    #include
    #include

    static struct pam_conv conv = {
    misc_conv, //定义在pam_misc.h中, 方便你编程
    NULL
    };

    int main(int argc, char *argv[])
    {
    pam_handle_t *pamh=NULL;
    int retval;
    const char *user=\"nobody\";

    if(argc == 2) {
    user = argv[1];
    }

    if(argc > 2) {
    fprintf(stderr, \"Usage: check_user [username]\\n\");
    exit(1);
    }

    retval = pam_start(\"check_user\", user, &conv, &pamh);
    /* 开始 */
    if (retval == PAM_SUCCESS)
    retval = pam_authenticate(pamh, 0);
    /* 认证是不是该用户? 提示你输入一个密码 */

    if (retval == PAM_SUCCESS)
    retval = pam_acct_mgmt(pamh, 0);
    /* 账号是否有效? */

    if (retval == PAM_SUCCESS) {
    fprintf(stdout, \"Authenticated\\n\");
    } else {
    fprintf(stdout, \"Not Authenticated\\n\");
    }

    if (pam_end(pamh,retval) != PAM_SUCCESS) {
    /* 结束 */
    pamh = NULL;
    fprintf(stderr, \"check_user: failed to release authenticator\\n\");
    exit(1);
    }

    return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */
    }

    - Bricks Team

    发布人:netbull 来自:蓝森林