Go to main content
Oracle® Solaris 11 セキュリティー開発者ガイド

印刷ビューの終了

更新: 2016 年 11 月
 
 

PAM サービスを使用するアプリケーションの記述

アプリケーションに応じて、PAM サービスは 32 ビットまたは 64 ビットのバイナリとしてコンパイルできます。PAM モジュールは dlopen を介して共有オブジェクトとしてロードされるため、32 ビットと 64 ビットのどちらの形式のアプリケーションでも使用できるようにするには、両方のバージョンで提供する必要があります。詳細は、dlopen(3C) のマニュアルページを参照してください。

PAM フレームワークがアプリケーションの適切なバージョンをロードできるように、32 ビットと 64 ビットの両バージョンのモジュールをインストールする方法については、Oracle Solaris 11.3 での Kerberos およびその他の認証サービスの管理 の PAM モジュールを追加する方法を参照してください

単純な PAM コンシューマ例

次の PAM コンシューマアプリケーションは、例示のために提供されています。この例は、端末へのアクセスを試みるユーザーを検証する基本的な端末ロックアプリケーションです。

    この例では、次の手順を実行します。

  1. PAM セッションを初期化します。

    PAM セッションは、pam_start(3PAM) 関数の呼び出しによって初期化されます。PAM コンシューマアプリケーションは、ほかの PAM 関数を呼び出す前に PAM セッションを最初に確立する必要があります。

      pam_start (3PAM) 関数は、次の引数を使用します。

    • plock – サービス名、つまり、アプリケーションの名前。サービス名は、PAM フレームワークで構成ファイル /etc/pam.conf 内または /etc/pam.d 内のどの規則が適切かを決定するために使用されます。通常、サービス名はロギングとエラーレポートに使用されます。

    • 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 内の、または Oracle Solaris 11.3 OS の場合は /etc/pam.d/plock 内の、認証のサービスモジュールタイプ auth に対応するサービス名 plock に構成されているモジュールを起動します。plock サービスの auth エントリが /etc/pam.conf または /etc/pam.d/plock に存在しない場合は、other サービスの auth エントリが /etc/pam.conf で検索され、最後に /etc/pam.d/other ファイルで検索されます。

  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_setcred() を PAM_REFRESH_CRED フラグとともに呼び出すべきです。su を使用したり特定の役割を引き受けたりする場合のように、セッションが資格を変更する場合、pam_setcred() を PAM_REINITIALIZE_CRED フラグとともに呼び出すべきです。

  6. PAM セッションをクローズします。

    PAM セッションは、pam_end(3PAM) 関数の呼び出しによってクローズします。また、pam_end() は、すべての PAM リソースを解放します。

この PAM コンシューマアプリケーション例のソースコードを、次に示します。

使用例 4  PAM コンシューマアプリケーションの例
/*
 * Copyright (c) 2005, 2012, 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();
    }
    /* Establish the requested credentials */
    if ((err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
        logout();



    /* Open a session */
    if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
        logout();
   


    /* Close a session */
    if ((err = pam_close_session(pamh, 0)) != PAM_SUCCESS)
        logout();


   /* Delete the requested credentials */
    if ((err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
        logout();

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

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

その他の有用な PAM 関数

先述の例の 使用例 4 は、主な PAM 関数のほんの一部を示す単純なアプリケーションです。このセクションでは、その他の有用な PAM 関数をいくつか紹介します。

  • pam_open_session(3PAM) 関数は、ユーザー認証が成功したあと、新しいセッションをオープンする際に呼び出されます。

  • pam_getenvlist(3PAM) 関数は、新しい環境を確立する際に呼び出されます。pam_getenvlist() は、既存環境にマージすべき新しい環境を返します。

  • pam_eval(3PAM) 関数は、呼び出し元によって指定されたファイルに格納されている PAM 構成を読み込み、評価します。この関数は pam_user_policy(5) PAM モジュールによって呼び出されます。