ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris 11 セキュリティーサービス開発ガイド Oracle Solaris 11 Information Library (日本語) |
1. Oracle Solaris の開発者向けセキュリティー機能 (概要)
3. PAM アプリケーションおよび PAM サービスの記述
8. Oracle Solaris 暗号化フレームワークの紹介
9. ユーザーレベルの暗号化アプリケーションとプロバイダの記述
ここでは、PAM サービスモジュールの記述方法を説明します。
PAM サービスモジュールは、pam_get_item(3PAM) と pam_set_item(3PAM) を使ってアプリケーションとの通信を行います。 サービスモジュール同士の通信には、pam_get_data(3PAM) と pam_set_data(3PAM) が使用されます。 同一プロジェクト内のサービスモジュール間でデータを交換する必要がある場合、そのプロジェクト内で一意に決まるデータ名が確立されます。 その後、サービスモジュールは、関数 pam_get_data() と pam_set_data() を使ってそのデータを共有できます。
サービスモジュールは、次の 3 種類の PAM 戻りコードのいずれかを返す必要があります。
PAM_SUCCESS: 要求されているポリシーに合致しているという肯定的な決定を、モジュールが行なった場合。
PAM_IGNORE: モジュールがポリシー決定を行わなかった場合。
PAM_error: モジュールが参加していた決定が失敗した場合。 error は、汎用エラーコード、サービスモジュールタイプに固有のコードのいずれかです。 別のサービスモジュールタイプのエラーコードは使えません。 エラーコードについては、pam_sm_module-type のマニュアルページを参照してください。
1 つのサービスモジュール内に複数の機能が含まれている場合、それらの機能はそれぞれ個別のモジュールに分割することをお勧めします。 そうすることで、システム管理者は、ポリシー設定時によりきめ細かい制御を行えるようになります。
新しいサービスモジュールを作成した場合、対応するマニュアルページを提供する必要があります。 マニュアルページには、次の情報を含める必要があります。
モジュールが受け入れる引数。
モジュールが実装しているすべての関数。
アルゴリズムに対するフラグの効果。
必要とされるすべての PAM アイテム。
このモジュールに固有のエラー戻りコード。
サービスモジュールは、メッセージを抑制するための PAM_SILENT フラグを尊重することが求められます。 デバッグ情報を syslog に記録するには、debug 引数を指定することをお勧めします。 デバッグ情報を記録するには、syslog(3C) 使用時に LOG_AUTH と LOG_DEBUG を指定します。 その他のメッセージは、LOG_AUTH と適切な優先度を指定して syslog() に送るべきです。openlog(3C)、closelog(3C)、および setlogmask(3C) という 3 つの関数はアプリケーションの設定に悪影響を与えるので、決して使用しないでください。
ここでは、PAM サービスモジュールの例を示します。 この例では、ユーザーがこのサービスへのアクセスが許可されているグループのメンバーかどうかを確認します。 プロバイダは、成功の場合にアクセスを許可し、失敗の場合にエラーメッセージをログに記録します。
この例では、次の手順を実行します。
/etc/pam.conf の構成行からこのモジュールに渡されたオプションを解析します。
このモジュールは、nowarn オプションおよび debug オプション、さらに固有のオプション group を受け入れます。 group オプションを使用する場合、デフォルトで使用されるグループ root 以外の特定のグループに対してアクセスを許可するようにモジュールを構成できます。 この例については、ソースコードの DEFAULT_GROUP の定義を参照してください。 たとえば、グループ staff に属するユーザーによる telnet(1) アクセスを許可するには、/etc/pam.conf の telnet スタックにある次の行を使用できます。
telnet account required pam_members_only.so.1 group=staff
ユーザー名、サービス名、およびホスト名を取得します。
ユーザー名は、現在のユーザー名を PAM ハンドルから取り出す、pam_get_user(3PAM) の呼び出しによって取得されます。 ユーザー名が設定されていない場合、アクセスは拒否されます。 サービス名とホスト名は、pam_get_item(3PAM) の呼び出しによって取得されます。
有効にする情報を検証します。
ユーザー名が設定されていない場合、アクセスは拒否されます。 有効にするグループが定義されていない場合、アクセスは拒否されます。
現在のユーザーが、このホストへのアクセスが許可されている特殊グループのメンバーであることを確認し、アクセスを許可します。
固有のグループが定義されていてもメンバーが 1 つも含まれていない場合は、このモジュールがどのアカウント検証プロセスにも参加しないことを示す、PAM_IGNORE が返されます。 決定は、スタック上のほかのモジュールに委ねられます。
ユーザーが特殊グループのメンバーではない場合は、アクセスが拒否されたことをユーザーに知らせるメッセージを表示します。
メッセージをログに記録してこのイベントを記録します。
次の例は、PAM プロバイダ例のソースコードです。
注 - このソースコード例は、Oracle ダウンロードセンターからダウンロードすることも可能です。 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html を参照してください。
例 3-3 PAM サービスモジュール例
/* * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> #include <stdlib.h> #include <grp.h> #include <string.h> #include <syslog.h> #include <libintl.h> #include <security/pam_appl.h> /* * by default, only users who are a member of group "root" are allowed access */ #define DEFAULT_GROUP "root" static char *NOMSG = "Sorry, you are not on the access list for this host - access denied."; int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc, const char **argv) { char *user = NULL; char *host = NULL; char *service = NULL; const char *allowed_grp = DEFAULT_GROUP; char grp_buf[4096]; struct group grp; struct pam_conv *conversation; struct pam_message message; struct pam_message *pmessage = &message; struct pam_response *res = NULL; int i; int nowarn = 0; int debug = 0; /* Set flags to display warnings if in debug mode. */ for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "nowarn") == 0) nowarn = 1; else if (strcasecmp(argv[i], "debug") == 0) debug = 1; else if (strncmp(argv[i], "group=", 6) == 0) allowed_grp = &argv[i][6]; } if (flags & PAM_SILENT) nowarn = 1; /* Get user name,service name, and host name. */ (void) pam_get_user(pamh, &user, NULL); (void) pam_get_item(pamh, PAM_SERVICE, (void **) &service); (void) pam_get_item(pamh, PAM_RHOST, (void **) &host); /* Deny access if user is NULL. */ if (user == NULL) { syslog(LOG_AUTH|LOG_DEBUG, "%s: members_only: user not set", service); return (PAM_USER_UNKNOWN); } if (host == NULL) host = "unknown"; /* * Deny access if vuser group is required and user is not in vuser * group */ if (getgrnam_r(allowed_grp, &grp, grp_buf, sizeof (grp_buf)) == NULL) { syslog(LOG_NOTICE|LOG_AUTH, "%s: members_only: group \"%s\" not defined", service, allowed_grp); return (PAM_SYSTEM_ERR); } /* Ignore this module if group contains no members. */ if (grp.gr_mem[0] == 0) { if (debug) syslog(LOG_AUTH|LOG_DEBUG, "%s: members_only: group %s empty: " "all users allowed.", service, grp.gr_name); return (PAM_IGNORE); } /* Check to see if user is in group. If so, return SUCCESS. */ for (; grp.gr_mem[0]; grp.gr_mem++) { if (strcmp(grp.gr_mem[0], user) == 0) { if (debug) syslog(LOG_AUTH|LOG_DEBUG, "%s: user %s is member of group %s. " "Access allowed.", service, user, grp.gr_name); return (PAM_SUCCESS); } } /* * User is not a member of the group. * Set message style to error and specify denial message. */ message.msg_style = PAM_ERROR_MSG; message.msg = gettext(NOMSG); /* Use conversation function to display denial message to user. */ (void) pam_get_item(pamh, PAM_CONV, (void **) &conversation); if (nowarn == 0 && conversation != NULL) { int err; err = conversation->conv(1, &pmessage, &res, conversation->appdata_ptr); if (debug && err != PAM_SUCCESS) syslog(LOG_AUTH|LOG_DEBUG, "%s: members_only: conversation returned " "error %d (%s).", service, err, pam_strerror(pamh, err)); /* free response (if any) */ if (res != NULL) { if (res->resp) free(res->resp); free(res); } } /* Report denial to system log and return error to caller. */ syslog(LOG_NOTICE | LOG_AUTH, "%s: members_only: " "Connection for %s not allowed from %s", service, user, host); return (PAM_PERM_DENIED); }