JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris 11 开发者安全性指南     Oracle Solaris 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.  Oracle Solaris 密钥管理框架介绍

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

B.  GSS-API 参考

C.  指定 OID

D.  SASL 示例的源代码

E.  SASL 参考表

词汇表

索引

编写使用 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 标志。 Oracle 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 下载中心获取。 请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


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

/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. */

#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() 将返回要与现有环境合并的新环境。