JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris 开发者安全性指南     Oracle Solaris 10 8/11 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

1.  面向开发者的 Oracle Solaris 安全(概述)

2.  开发特权应用程序

3.  编写 PAM 应用程序和服务

PAM 框架介绍

PAM 服务模块

PAM 库

PAM 验证过程

PAM 使用者的要求

PAM 配置

编写使用 PAM 服务的应用程序

简单 PAM 使用者示例

其他有用的 PAM 函数

编写对话函数

编写提供 PAM 服务的模块

PAM 服务提供者要求

PAM 提供者服务模块样例

4.  编写使用 GSS-API 的应用程序

5.  GSS-API 客户机示例

6.  GSS-API 服务器示例

7.  编写使用 SASL 的应用程序

8.  Oracle Solaris 加密框架介绍

9.  编写用户级加密应用程序和提供者

10.  使用智能卡框架

A.  基于 C 的 GSS-API 样例程序

B.  GSS-API 参考

C.  指定 OID

D.  SASL 示例的源代码

E.  SASL 参考表

F.  打包和签署加密提供者

词汇表

索引

编写使用 PAM 服务的应用程序

本节提供了使用多个 PAM 函数的应用程序样例。

简单 PAM 使用者示例

以下将以 PAM 使用者应用程序作为示例。该示例是一个基本的终端锁定应用程序,用于检验尝试访问终端的用户。此示例执行以下步骤:

  1. 初始化 PAM 会话。

    PAM 会话通过调用 pam_start(3PAM) 函数来启动。调用任何其他 PAM 函数之前,PAM 使用者应用程序必须首先建立 PAM 会话。pam_start(3PAM) 函数采用以下参数:

    • plock-服务名,即应用程序的名称。PAM 框架使用服务名来确定配置文件 /etc/pam.conf 中适用的规则。服务名通常用于日志记录和错误报告。

    • pw->pw_name-用户名,即 PAM 框架所作用的用户的名称。

    • &conv-对话函数 conv,用于提供 PAM 与用户或应用程序进行通信的通用方法。对话函数是必需的,因为 PAM 模块无法了解如何进行通信。通信可以采用 GUI、命令行、智能读卡器或其他设备等方式进行。有关更多信息,请参见编写对话函数

    • &pamh-PAM 句柄 pamh,即 PAM 框架用于存储有关当前操作信息的不透明句柄。成功调用 pam_start() 后将返回此句柄。


    注 - 调用 PAM 接口的应用程序必须具有足够的特权才能执行任何所需的操作,如验证、口令更改、进程凭证处理或审计状态初始化。在该示例中,应用程序必须可以读取 /etc/shadow 才能验证本地用户的口令。


  2. 验证用户。

    应用程序将调用 pam_authenticate(3PAM) 来验证当前用户。通常,系统会要求用户输入口令或其他验证令牌,具体取决于验证服务的类型。PAM 框架会调用 /etc/pam.conf 中为验证服务 auth 列出的模块。服务名 plock 用于确定要使用的 pam.conf 项。如果不存在与 plock 对应的项,则缺省情况下会使用 other 中的项。如果应用程序配置文件中明确禁止使用 NULL 口令,则应该传递 PAM_DISALLOW_NULL_AUTHTOK 标志。Solaris 应用程序将检查 /etc/default/login 中的 PASSREQ=YES 设置。

  3. 检查帐户有效性。

    该示例使用 pam_acct_mgmt(3PAM) 函数检查已验证的用户帐户的有效性。在该示例中,pam_acct_mgmt() 用于检查口令是否到期。

    pam_acct_mgmt() 函数还会使用 PAM_DISALLOW_NULL_AUTHTOK 标志。如果 pam_acct_mgmt() 返回 PAM_NEW_AUTHTOK_REQD,则应调用 pam_chauthtok(3PAM) 以允许已验证的用户更改口令。

  4. 如果系统发现口令已到期,则会强制用户更改口令。

    该示例使用循环调用 pam_chauthtok(),直到返回成功信息为止。如果用户成功更改其验证信息(通常为口令),则 pam_chauthtok() 函数将返回成功信息。在该示例中,循环将继续直到返回成功信息为止。通常,应用程序会设置终止前应尝试的最多次数。

  5. 调用 pam_setcred(3PAM)

    pam_setcred(3PAM) 函数用于建立、修改或删除用户凭证。pam_setcred() 通常在验证用户之后进行调用。调用是在检验帐户后和打开会话前进行的。将 pam_setcred() 函数与 PAM_ESTABLISH_CRED 标志结合使用可建立新的用户会话。如果该会话是对现有会话(如对于 lockscreen)的更新,则应调用带有 PAM_REFRESH_CRED 标志的 pam_setcred()。如果会话要更改凭证(如使用 su 或承担角色),则应调用带有 PAM_REINITIALIZE_CRED 标志的 pam_setcred()

  6. 关闭 PAM 会话。

    PAM 会话通过调用 pam_end(3PAM) 函数进行关闭。pam_end() 还将释放所有的 PAM 资源。

以下示例给出了 PAM 使用者应用程序样例的源代码。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=Security_code-Dev1.1-G-F@CDS-CDS_SMI


示例 3-1 PAM 使用者应用程序样例

/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include <security/pam_appl.h>

extern int pam_tty_conv(int num_msg, struct pam_message **msg,
         struct pam_response **response, void *appdata_ptr);

/* Disable keyboard interrupts (Ctrl-C, Ctrl-Z, Ctrl-\) */
static void
disable_kbd_signals(void)
{
    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGTSTP, SIG_IGN);
    (void) signal(SIGQUIT, SIG_IGN);
}

/* Terminate current user session, i.e., logout */
static void
logout()
{
    pid_t pgroup = getpgrp();

    (void) signal(SIGTERM, SIG_IGN);
    (void) fprintf(stderr, "Sorry, your session can't be restored.\n");
    (void) fprintf(stderr, "Press return to terminate this session.\n");
    (void) getchar();
    (void) kill(-pgroup, SIGTERM);
    (void) sleep(2);
    (void) kill(-pgroup, SIGKILL);
    exit(-1);
}

int
/*ARGSUSED*/
main(int argc, char *argv)
{
    struct pam_conv conv = { pam_tty_conv, NULL };
    pam_handle_t *pamh;
    struct passwd *pw;
    int err;

    disable_kbd_signals();
    if ((pw = getpwuid(getuid())) == NULL) {
        (void) fprintf(stderr, "plock: Can't get username: %s\n",
            strerror(errno));
        exit(1);
    }
    
    /* Initialize PAM framework */
    err = pam_start("plock", pw->pw_name, &conv, &pamh);
    if (err != PAM_SUCCESS) {
        (void) fprintf(stderr, "plock: pam_start failed: %s\n",
            pam_strerror(pamh, err));
        exit(1);
    }

    /* Authenticate user in order to unlock screen */
    do {
        (void) fprintf(stderr, "Terminal locked for %s. ", pw->pw_name);
        err = pam_authenticate(pamh, 0);
        if (err == PAM_USER_UNKNOWN) {
            logout();
        } else if (err != PAM_SUCCESS) {
            (void) fprintf(stderr, "Invalid password.\n");
        }
    } while (err != PAM_SUCCESS);

    /* Make sure account and password are still valid */
    switch (err = pam_acct_mgmt(pamh, 0)) {
    case PAM_SUCCESS:
        break;
    case PAM_USER_UNKNOWN:
    case PAM_ACCT_EXPIRED:
        /* User not allowed in anymore */
        logout();
        break;
    case PAM_NEW_AUTHTOK_REQD:
        /* The user's password has expired. Get a new one */
        do {
            err = pam_chauthtok(pamh, 0);
        } while (err == PAM_AUTHTOK_ERR);
        if (err != PAM_SUCCESS)
            logout();
        break;
    default:
        logout();
    }

if (pam_setcred(pamh, PAM_REFRESH_CRED) != PAM_SUCCESS){
    logout();
}

    (void) pam_end(pamh, 0);
    return(0);
    /*NOTREACHED*/
}

其他有用的 PAM 函数

前面的示例 3-1 是一个简单的应用程序,它仅说明了几个主要的 PAM 函数。本节将介绍一些其他有用的 PAM 函数。

成功验证用户后,将会调用 pam_open_session(3PAM) 函数打开新会话。

调用 pam_getenvlist(3PAM) 函数可以建立新环境。pam_getenvlist() 将返回要与现有环境合并的新环境。