訳註: これは作業してる最中のもので、本来、訳作業者以外は見えぬべきものです。 訳作業者以外は見ないでください。意味が反対になったりとか当然にあるから、 内容は利用しないでください。この言語への変換作業(翻訳作業)物に関しては、現在、オープンなライセンス条件ではありません。 十進240のコードのキャラクターを<240>に置換してる場合あり
Chapter<240>18.<240>Pluggable Authentication Modules (PAM)

Table of Contents

18.1. About
18.2. Introduction
18.3. Terms and conventions
18.3.1. Definitions
18.3.2. Usage examples
18.4. PAM Essentials
18.4.1. Facilities and primitives
18.4.2. Modules
18.4.3. Chains and policies
18.4.4. Transactions
18.5. PAM Configuration
18.5.1. PAM policy files
18.5.2. Breakdown of a configuration line
18.5.3. Policies
18.6. PAM modules
18.6.1. Common Modules
18.6.2. NetBSD-specific PAM Modules
18.7. PAM Application Programming
18.8. PAM Module Programming
18.9. Sample PAM Application
18.10. Sample PAM Module
18.11. Sample PAM Conversation Function
18.12. Further Reading

日本語(のような言語)版訳者註:
そもそも、まだ作業そのもの最中ですし、
査読などの他の人による検証も何も、まだ、されていません。
訳者は英文のままだと、"どうにも"読む事ができないから訳しています。
学校でも赤点取ったほど、英語はわからないので、残念ながら誤訳があってもあたりまえです。
内容柄、誤解し、間違った理解/操作/対応等をすると、非常に危険ですから、
原文や、(訳者の過去の作業(がある章がある)以外の)誰かが
公開しているかもしれない日本語訳を利用してください。
(これは日本語"(のような言語)"版で、"日本語"そのものではありません)

日本語(のような言語)版訳者註おわり。

18.1.<240>About

この記事は、 Pluggable Authentication Modules (PAM) ライブラリーの 基礎をなす原理および mechanisms を記述し、 そして、 PAM の設定法、アプリケーションへの PAM の統合方法、および PAM モジュールの書き方を説明します。

この章のライセンスについては、 Section<240>D.3.2, “Networks Associates Technology's license on the PAM article” を見てください。

18.2.<240>Introduction

The Pluggable Authentication Modules (PAM) ライブラリーは 認証-関連サービスの一般化 APIで、 システム管理者に 新しい PAM モジュールのインストールと設定ファイルの編集による認証ポリシーの変更によって 新しい認証方法を簡単に追加することを許します。

PAM は 1995 年に Sun Microsystems の Vipin Samar と Charlie Lai によって定義および開発され、 それからあまり変わっていません。 1997 年に、 the Open Group は the X/Open Single Sign-on (XSSO) 暫定仕様を published 、それは PAM API を標準化し、そしてシングル(あるいは、より統合された)サインオン の拡張を追加しました。 これを書いている時点で、この仕様は未だ標準として採用されていません。

この記事は主として、 OpenPAM を使う FreeBSD 5.x および NetBSD 3.x に焦点を合わせていますが、 Linux-PAM を使う FreeBSD 4.x 、 Linux および Solaris™ のような他のオペレーティングシステムにも 等しく適用できるはずです。

18.3.<240>Terms and conventions

18.3.1.<240>Definitions

PAM を取り巻く用語は幾分混乱しています。 Samar and Lai の original の paper も the XSSO 規定も、 PAM に関連した various actors and entities の公式な用語定義の 何らの試みもしていなくて、 they の利用する用語 (しかし定義せず)は 時々、人を惑わせ不明瞭です。 整合し、明白な用語の確立の最初の試みは 1999年に Andrew G. Morgan (Linux-PAM の author) によって書かれた白書です。 Morgan の 用語選択は大きな前進ではありますが、この author の意見は決して完璧ではありません。 Morgan に強ーく影響を受け、 PAM に関連した全 actors and entities の正確で明白な用語の定義を 続いて試みるのは、いったい...。

アカウント(account)

調停者から要求される[requesting] 志願者の信用証明(credentials)のセット。

志願者(applicant)

認証を要求するユーザーや entity [エンティティー]。

調停者(arbitrator)

志願者の信用証明を verify するのに必要な特権および、 request を是認あるいは否認する権威をもつ user or entity 。

チェーン(chain)

PAM request に応じて invoked れるモジュールの sequence 。チェーンには モジュールを invoke する順序について、どの引数を渡すか、結果をどう解釈するか の情報が含まれています。

クライアント(client)

志願者に代わって認証 request を開始し、 必要な認証情報を彼から入手する責任のあるアプリケーション。

設備(facility)##とくに要用語チェック。カタカナ語のほうがいい?##

PAM が供給する基本的機能グループ 4つのうちの1つ: 認証、アカウント管理、 セッション管理 および 認証 トークン update.

モジュール

関連した特定の認証設備を実装する関数を、一つの (通常ダイナミックローダブル) バイナリーファイル中に集め、一つの名前で identified されるようにした collection 。

ポリシー(policy)

特定のサービスに対して PAM requests をどう取り扱うかを 記述した configuration statements の完全なセット。 ポリシーは通常4つのチェーンから成り、 設備ごとに一つですが、いくつかのサービスは 4つの設備のどれも使いません。

サーバー(server)

調停者の代理として クライアントと対話(converse)し, 認証 情報を検索し、志願者の信用証明を検証し、 requests を許可あるいは拒否するアプリケーション。

サービス(service)

類似したあるいは関連した 機能性を提供し、類似した認証を requiring するサーバーの class 。 PAM ポリシーはサービス毎 基準て定義され、そのため 同一サービス名を自称する全サーバーは同一ポリシーであるもの。

セッション(session)

サーバーによって志願者に与えられたサービス内部の context 。 PAM の4つの設備の一つ、セッション管理は、専ら この context の setting up および tearing down に関係している。

トークン(token)

パスワードあるいはパスフレーズのようなアカウントに関係した情報のチャンクで、 志願者の身元を証明するために、志願者は提供しなければなりません。

処理[・処置](transaction)

同一志願者から 同一サーバーの同一 instance への requests の sequence 、 認証および セッション set-up で始まり、 セッション tear-down で終わる。

18.3.2.<240>Usage examples

この節は、上で定義した用語のいくつかの意味を少数のシンプルな例を通し、 実例を出して説明することを狙っています。

18.3.2.1.<240>Client and server are one

この簡単な例は alicerootsu(1) するところを表しています。

$ whoami
alice
$ ls -l `which su`
-r-sr-xr-x  1 root  wheel  10744 Dec  6 19:06 /usr/bin/su
$ su -
Password: xi3kiune
# whoami
root
  • 志願者は alice

  • アカウントは root

  • su(1) プロセスはクライアントであり サーバーです。

  • 認証トークン(合言葉) は xi3kiune

  • 調停者は root 、これは su(1) が setuid root されているからです。

18.3.2.2.<240>Client and server are separate

以下の例は、 evelogin.example.comssh(1) 接続し bob としてログインを始めようと試み、 そして成功している様子を示しています。 Bob はもっと良いパスワードを選ばなければなりません!

$ whoami
eve
$ ssh bob@login.example.com
bob@login.example.com's password: god
Last login: Thu Oct 11 09:52:57 2001 from 192.168.0.1
NetBSD 3.0 (LOGIN) #1: Thu Mar 10 18:22:36 WET 2005

Welcome to NetBSD!
$
  • 志願者は eve

  • クライアントは Eve の ssh(1) プロセス。

  • サーバーは login.example.com 上の sshd(8) プロセス。

  • アカウントは bob

  • 認証 トークンは god

  • この例では現れていないけれども、 調停者は root

18.3.2.3.<240>Sample policy

以下は FreeBSD の sshd への default ポリシーで:

sshd	auth		required	pam_nologin.so	no_warn
sshd	auth		required	pam_unix.so	no_warn try_first_pass
sshd	account		required	pam_login_access.so
sshd	account		required	pam_unix.so
sshd	session		required	pam_lastlog.so	no_fail
sshd	password	required	pam_permit.so
  • このポリシーは sshd サービスに適応されます (これは必ずしも sshd(8) サーバーに限定される必要はない)

  • authaccountsession および password は設備。

  • pam_nologin.so, pam_unix.so, pam_login_access.so, pam_lastlog.so および pam_permit.so はモジュールです。 この例から、 pam_unix.so は少なくても二つの 設備(認証およびアカウント 管理) を提供している事が明らかです。

FreeBSD と NetBSD の PAM ポリシーにはいくつかの違いがあって:

  • default では、全ての設定は /etc/pam.d 以下で行われます。

  • 設定が現存しないなら、システムにアクセスできなくて、 default ポリシーで認証が許される FreeBSD とは対照的です。

  • 認証には、 NetBSD では少なくとも requiredrequisite あるいは binding モジュールの一つの 存在が強制されています。

18.4.<240>PAM Essentials

18.4.1.<240>Facilities and primitives

PAM API は 6つの異なる認証 関数(primitives) を 4つに grouped された設備で提供し、これらを下に記します。

auth

認証。 この設備は 志願者の認証に関与し アカウント信用証明を確立します。2つの 関数を提供し:

  • pam_authenticate(3) は、 通常、認証トークンの要求と、それを、 データベースに蓄えられた値あるいは認証 サーバーから得られた値と比較することによって志願者を認証する。

  • pam_setcred(3) は ユーザー ID 、 group membership および リソース制限のようなアカウント信用証明を確立します。

account

アカウント管理。 この設備は 時刻あるいはサーバーの動作負荷に基づいたアクセス制限のようなアカウント有効性の 非-認証-関係の 問題を取り扱います。一つの関数を提供し:

  • pam_acct_mgmt(3) は requested アカウントが利用可能か照合します。

session

セッション管理。 この 設備は、 login アカウントing のようなセッションの set-up および tear-down[取り壊す・分解] に関連した tasks を取り扱います。 2つの関数を提供し:

  • pam_open_session(3) は セッション set-up に関連した tasks を performs し: utmp および wtmp データベースに entry を加え、 SSH agent を start し、等。

  • pam_close_session(3) は セッション tear-down に関連した tasks を performs し: utmp および wtmp データベースに entry を加え、 SSH agent を stop し、等。

password

パスワード 管理。 この 設備は、期限切れのためあるいはユーザーが変更したいと願ったために、 アカウントに関連した認証トークンの変更に使われます。 一つの関数を提供し:

  • pam_chauthtok(3) は認証 トークンを変更し、 optionally として 十分に推測か困難か、以前に用いられていないかなどを確かめます。

18.4.2.<240>Modules

モジュールは PAM において非常に中心的な概念で; 何といっても、 PAM の中の M ですもん。 PAM モジュールは、一つの特定の mechanism に対し 一つ以上の設備の関数を実装する各モジュール独立式なプログラムコードで; 認証設備が可能な mechanisms、例えば、 UNIX® パスワード・データベース、 NIS 、 LDAP および Radius を含みます。

18.4.2.1.<240>Module Naming

FreeBSD 及び NetBSD は各メカニズムをシングルモジュールで実装し、 pam_メカニズム.so (例えば、 UNIX® mechanism には pam_unix.so) と名付けられます。 他の実装では時には独立した設備に独立したモジュールがあり、 モジュール名中の mechanism 名と同じく設備名を含みます。名付けの一つの例として、 Solaris™ には dialup users を認証するのに通例使われる pam_dial_auth.so.1 モジュールがあります。 また、各モジュール、ほとんど全てのものは同一名の man page があり、 すなわち: pam_unix(8) は、 pam_unix.so モジュールがどう働くのかを述べています。

18.4.2.2.<240>Module Versioning

FreeBSD の、Linux-PAM に基づいたオリジナルの PAM 実装 は PAM モジュール には バージョン番号を使っていません。 これは、 required モジュールと matching なバージョンのロード方法がなく、 より古いバージョンのシステムライブラリーに対してリンクされるかもしれない legacy アプリケーションで一般的な問題の原因となります。

OpenPAM, は一方、 PAM ライブラリーと同一バージョン番号 (現在 FreeBSD では 2 そして NetBSD は 0)のモジュールを探し、 バージョン番号の付いたモジュールがロードできなかった場合に限り、 unversioned モジュール に falls back します。このように、新しい (あるいは新しくビルトされた) アプリケーションを最近の モジュールに便乗することを許しつつ、 legacy アプリケーションに legacy モジュールを提供することかできます。

Solaris™ PAM モジュールには通例、バージョン番号がありますけれども、 番号はモジュール名の一部で、 configuration 中に含まれなければならないので それは真の versioned ではありません。

18.4.2.3.<240>Module Path

PAM モジュールを storing するためのディレクトリーが共通ではありません。 FreeBSD では、それらは /usr/lib にあり、 そして、 NetBSD では、それらは /usr/lib/security の中にみつかあります。

18.4.3.<240>Chains and policies

サーバーが PAM 処理を始めるとき、 PAM ライブラリーは pam_start(3) call 中に指定されたサービスのためのポリシーのロードを試みます。 ポリシーは 認証 requests がどのように処理されるべきかを規定し、 設定ファイルで定義されています。これは PAM の the other 中心 concept で: admin に対する、 テキストファイルの編集で、単純なる(広い意味で)システムセキュリティーポリシーの tune の の可能性です。

ポリシーは4つのチェーンから成っていて、4つの PAM 設備ごとに一つです。各チェーンは configuration statements の sequence で、 それぞれ、 invoke するモジュール、 モジュールに渡す(オプションの) パラメーターおよび モジュールからの return code の interpret 法を記述したコントロールフラグ を規定しています。

コントロールフラグの理解は PAM 設定ファイルの理解の本質です。 沢山の異なる制御フラグがあって:

binding

モジュールが成功し、チェーン中の先のどのモジュールも 失敗しなかったなら、チェーンは直ちに終了し、 request は是認されます。もし、モジュールが失敗すると、 チェーンの残りは実行されますが、しかし、 request は最後に 拒まれます。

このコントロールフラグは Sun によって Solaris™ 9 (SunOS™ 5.9) で導入され、また、 OpenPAM にも supported れてます。

required

モジュールが succeeds すると、チェーンの残りを実行し、 他のモジュールが失敗しないかぎり request は認められます。 もしモジュールが失敗すると、チェーンの残りは、それもまた実行されますが、 しかし、 request は最後に 拒まれます。

requisite

モジュールが成功するとチェーンの残りを実行し、 他のモジュールが失敗しないかぎり request は認められます。 もしモジュールが失敗すると、チェーンは直ちに終了し、 request は拒まれます。

sufficient

モジュールが成功し、チェーン中の先のどのモジュールも 失敗しなかったなら、チェーンは直ちに終了し、 request は是認されます。もし、モジュールが失敗なら、 モジュールは無視され、チェーンの残りが 実行されます。

このフラグの解釈は何らかの混乱を起こすかもしれないので、 とりわけチェーン中の最後のモジュールに使われるときは、 もし実装が対応しているならば、代わりに、 binding コントロール フラグを使うことが推奨されます。

optional

モジュールは実行されますが、しかし、結果は無視されます。 もし、チェーン中の全モジュールが optional と marked なら、 全ての requests は常に是認されます。

サーバーが6つの PAM 関数の一つを invokes するとき、 PAM は 関数が属する設備のチェーンを検索し、 チェーン中に listed された各モジュールを、 終わりにたどり着くまで、あるいは、 ( binding のためか、 sufficient モジュールが succeeded のため、 または、 requisite モジュールが failed のためか) 更なる処理が必要ないと決定するまで listed された順序で invokes します。 request は、少なくても一つのモジュールが invoked され、 non-optional な 全モジュールが成功の時だけ是認されます。

註として、それは可能ではあります全然一般的ではない事として、 何度か listed された同一モジュールを同一チェーン中に入れることがあります。 例えば、directory サーバー中でユーザー名およびパスワードを検索するモジュールは contact する異なる directory サーバーを指定する異なるパラメーターで 複数回invoked できます。 PAM は、同一チェーン中の同一モジュールの異なる出来事[occurrences]を、 異なる、無関係のモジュールとして扱います。

18.4.4.<240>Transactions

代表的な PAM 処理の lifecycle は下に記述します。 註として、もしこれらのどれかの steps が失敗すると、サーバーはクライアントに対して 適切なエラーメッセージを report し、 処理を中止するでしょう。

  1. もし必要なら、 PAM と独立の mechanism — 最も一般的である root によって started されたこと、 あるいは setuid root であること、 それによってサーバーは調停者信用証明を取得します。

  2. サーバーは PAM ライブラリーを初期化し、そのサービス名および target アカウントを規定し、適切な 対話(conversation)関数を登録するために pam_start(3) を呼びます。

  3. サーバーは(志願者のユーザー名および クライアントが走っているホスト名のような)処理に関する様々な情報を取得し、 pam_set_item(3) を用いて PAM に提出します。

  4. 志願者を認証するために、サーバーは pam_authenticate(3) を呼びます。

  5. requested アカウントが利用可能で正当かを確認するために サーバーは pam_acct_mgmt(3) を calls。 パスワードは正しいけど期限切れしている場合は、 pam_acct_mgmt(3)PAM_SUCCESS の代わりに PAM_NEW_AUTHTOK_REQD を返します。

  6. もし前のステップで PAM_NEW_AUTHTOK_REQD が返されたなら、 クライアントに requested アカウントの 認証トークンを強制的に変更させるために、サーバーはここで pam_chauthtok(3) を呼びます。

  7. さて、志願者はきちんと 認証され、サーバーは requested アカウントの信用証明を確立するために pam_setcred(3) を呼びます。 it は調停者の代理として acts 、そして、調停者の信用証明を holds なのでこれをすることができます。

  8. ひとたび間違いのない信用証明が確立されると、 サーバーはセッションをセットアップするために pam_open_session(3) を呼びます。

  9. これでサーバーはクライアントが requested したどんなサービスでも performs し—例えば、志願者にシェルを提供 します。

  10. サーバーは、クライアントの serving を終えるや否や、セッションの to tear down ために pam_close_session(3) を呼びます。

  11. 最後にサーバーは、 PAM ライブラリーに対し、完了したこと、 処理中に割り当てられたあらゆるリソースを release できることを notify するために pam_end(3) を calls します。

18.5.<240>PAM Configuration

18.5.1.<240>PAM policy files

18.5.1.1.<240>The /etc/pam.conf file

traditional PAM ポリシーファイルは /etc/pam.conf です。このファイルは、 システムの PAM ポリシーの全てを保持しています。そのファイルの各行は チェーン中の一ステップを記述し、下に示され:

login   auth    required        pam_nologin.so  no_warn

各欄は順に: サービス名、設備名、 コントロールフラグ、モジュール名、そして、モジュールの引数です。 あらゆる追加の欄は追加のモジュール引数としてinterpreted されます。

単独のチェーンは サービス/設備 のペア毎に組み立てられ、よって、 現れた同一サービスおよび設備の lines の順序は意味が有りますが、 listed された個々のサービスおよび設備の順序にはありません。 original の PAM paper の例は、設備によって configuration lines を grouped し、そして Solaris™ stock pam.conf は今でもそうしていますが、しかし、 FreeBSD の stock 設定 は、サービスで configuration lines を groups します。 どちらの方法も申し分なく; どちらの方法も同じ意味となります。

18.5.1.2.<240>The /etc/pam.d directory

OpenPAM および Linux-PAM は代わりの設定 mechanism をサポートしていて、これが FreeBSD および NetBSD で好まれる mechanism です。 この scheme では、各ポリシーは適用されるサービス名がついた ファイルに入っています。これらのファイルは /etc/pam.d/ に入っています。

pam.conf の fields が5つであるのに対し、 これらのサービスごとのポリシーファイルは fields は 4つだけで: サービス名 field は削除します。このように、前の節の pam.conf 行のサンプルの代わりに、 /etc/pam.d/login に次の行を入れます:

auth    required        pam_nologin.so  no_warn

この simplified syntax の結果として、 各サービス名を同一ポリシーファイルへリンクする事で、多数のサービスに 同一ポリシーを使うことが可能です。例えば、同一ポリシーを su および sudo サービスに使うには、 次の様にできて:

# cd /etc/pam.d
# ln -s su sudo

サービス名は、 ポリシーファイル中の指定よりもファイル名で決まり、それで 同一ファイルが多数の異なる名前の サービスで使えるのでこれは働きます。

各サービスのポリシーは別々のファイルに蓄えられるので、 pam.d の mechanism はまた、 third-party ソフトウェアパッケージのための追加のポリシーのインストールを非常に簡単にします。

18.5.1.3.<240>The policy search order

上で見られたように、 PAM ポリシーは幾つかの場所にあります。 もし、特定のサービスについての設定ファイルが見つからなければ、 /etc/pam.d/other が代わりに使われます。 もし、そのファイルが無ければ、指定のサービスに matching する /etc/pam.conf のエントリーを探し、 さもなければ、 "other" サービスに failing します。

チェーンの中心に PAM の設定システムがあるということ が理解の本質です。

18.5.2.<240>Breakdown of a configuration line

PAM policy files セクションで説明の通り /etc/pam.conf の各行は 4つ以上の 欄からなっていて: サービス名、設備名、制御フラグ、 モジュール名、およびゼロもしくは更なるモジュール引数。

サービス名は通常 (常時ではないけれども) statement を適用するアプリケーションの名前です。もし不確かなら、 どんなサービス名を使うかを決定するために 個々のアプリケーションの documentation を参照してください。

註として、 /etc/pam.conf の代わりに /etc/pam.d/ を使うと、 サービス名はポリシーファイルの名前で指定され、 実際の設定行からのは無視され、 設備名とともに開始します。

設備は Facilities and primitives 節で記述された4つの設備キーワードの1つです。

同様に、コントロールフラグは Chains and policies 節に記述された4つのキーワードの1つで、 モジュールからの return code をどのように interpret するか記述します。 Linux-PAM は、 取り得る return code 毎に連携する action が規定できる 代替 syntax を supports しますが、 非標準で、 Linux-PAM dispatches サービス calls (これは Solaris™ の方法および OpenPAM の動作と大いに異なります) の方法に密接に結合されていて、これは避けるべきです。 意外でもなく、 OpenPAM はこの syntax に対応していません。

18.5.3.<240>Policies

PAM を正しく設定するためには、 ポリシーがどう interpreted されるかの理解が最も重要な事です。

アプリケーションが pam_start(3) を呼ぶとき、 PAM ライブラリーは特定のサービスのポリシーをロードし、 4つのモジュールチェーン(各設備に一つ)を構成します。 もしこれらのチェーンの一つ以上が空なら、 そのポリシーから other サービスに対応するチェーンに 代用されます。

アプリケーションが後から 6つの PAM 関数の一つを呼んだ時、PAM ライブラリーはチェーンを 対応する[corresponding]設備の検索をし、 the configuration で listed れた順序で チェーンに listed れた各モジュール内の適切なサービス 関数を呼びます。 サービス関数のコールの後毎に、モジュール type および サービス関数が返したエラーコードによって次に何が起こるか決定されます。 幾つか例外があって下で論じますが、 以下の表を適用し:

Table<240>18.1.<240>PAM chain execution summary

<240> PAM_SUCCESS PAM_IGNORE other
binding if (!fail) break; - fail = true;
required - - fail = true;
requisite - - fail = true; break;
sufficient if (!fail) break; - -
optional - - -

もし、チェーンの終わりに於いて fail が true 、 或いは break に到達した時、 dispatcher は 失敗した first モジュールが返したエラーコードを返します。 さもなければ、 PAM_SUCCESS を返します。

重要な最初の例外は、どのモジュールも失敗しなくて、かつ、少なくても一つの モジュールが PAM_NEW_AUTHTOK_REQD を返した場合に dispatcher が PAM_NEW_AUTHTOK_REQD を返すこと以外は、 エラーコード PAM_NEW_AUTHTOK_REQD は 成功のように扱われます。

2つ目の例外として pam_setcred(3) は、 binding および sufficient モジュールを、 それらが required であったかの様に扱います。

3番目と最後の例外として、 pam_chauthtok(3) は チェーン全体を2度 (一度は予備的な checks のため、 そして一度は実際にパスワードを set するため)に runs し、 予備的な phase では、 binding および sufficient モジュールは、 required であったかの様に扱います。

18.6.<240>PAM modules

18.6.1.<240>Common Modules

18.6.1.1.<240>pam_deny(8)

pam_deny(8) モジュールは利用可能な モジュールの最もシンプルなものの一つで; あらゆるリクエストに PAM_AUTH_ERR を responds します。 これは、急いでサービスを disabling にする(それを各チェーンの top に追加)、あるいは、 sufficient(資格のある) モジュールのチェーンの末尾を成すのに便利です。

18.6.1.2.<240>pam_echo(8)

pam_echo(8) モジュール は単純に、その引数を対話(conversation)関数に PAM_TEXT_INFO メッセージとして渡します。 デバッグにおいてもっとも便利ですが、また、 Unauthorized access will be prosecuted のようなメッセージを 認証手続き開始前に serve to display することもできます。

18.6.1.3.<240>pam_exec(8)

pam_exec(8) モジュールは最初の引数に 実行するプログラムの名前を、残りの引数はコマンドライン引数として that プログラムに渡します。アプリケーションとして可能なものの一つとして、 ログイン時にユーザーのホームディレクトリーをマウントするプログラムの run に使う事です。

18.6.1.4.<240>pam_ftpusers(8)

ユーザーが /etc/ftpusers に リストされているときだけ pam_ftpusers(8) モジュールは successes です。 現在、 NetBSD では、このモジュールは ftpd(8) の拡張文法を理解しませんが、これは将来 fixed れるでしょう。

18.6.1.5.<240>pam_group(8)

pam_group(8) モジュールは、志願者を 特定のファイルグループの membership に基づいて承認或いは拒否します (通常 su(1) には wheel )。 BSD su(1) の伝統的挙動を保守するのが本来の目的ですが、 特定のサービスからあるグループのユーザーを除外するらような、 多くの他の利用法があります。

NetBSD では、 ユーザーが自身のパスワードを用いて認証するため尋ねられた物を引数として authenticate が呼ばれます。

18.6.1.6.<240>pam_guest(8)

pam_guest(8) モジュールは fixed ログイン名での guest の ログインを認めます。パスワードの位置に様々な物を置かせることができますが、 しかし、 default の挙動としては ゲストアカウントのログイン名である限りにおいて、どんなパスワードも認めます。 pam_guest(8) モジュールは anonymous FTP logins の実装に簡単に利用できます。

18.6.1.7.<240>pam_krb5(8)

pam_krb5(8) モジュールは ユーザーの identity を verify し、ユーザー固有の信用証明を Kerberos 5 を 用いてセットする機能を提供します。ユーザーにパスワードを prompts し、 認証対象(principal)の新しい Kerberos TGT を手に入れます。 TGT は local host の サービス ticket を手に入れることで verified されます。新しく獲得した信用証明は 信用証明キャッシュに蓄えられ、環境変数 KRB5CCNAME が適切に set されます。信用証明キャッシュは、ユーザーによるログアウト時に kdestroy(1) で destroyed されるべきです。

18.6.1.8.<240>pam_ksu(8)

pam_ksu(8) モジュールは、 志願者が target アカウントの特権を取得する権利が有るか無いかを裁定するために、 Kerberos 5 の認証サービスだけを提供します。

18.6.1.9.<240>pam_lastlog(8)

pam_lastlog(8) モジュールはセッション 管理サービスだけを提供します。 utmp(5)utmpx(5)wtmp(5)wtmpx(5)lastlog(5) および lastlogx(5) データベースのセッションを記録します。

18.6.1.10.<240>pam_login_access(8)

pam_login_access(8) モジュールは login.access(5) table に規定された login 制限を実施するアカウント管理関数の実装を提供します。

18.6.1.11.<240>pam_nologin(8)

pam_nologin(8) モジュールは /var/run/nologin 存在時に、 非-root logins を拒絶します。このファイルは 通常 shutdown(8) によって 予定されたシャットダウン時刻まで5分を切った時に作られます。

18.6.1.12.<240>pam_permit(8)

pam_permit(8) モジュールは利用可能な モジュールの最もシンプルなものの一つで; どんな request にも PAM_SUCCESS を responds します。 サービス用として、チェーン上にとっておく場所として便利です。

18.6.1.13.<240>pam_radius(8)

pam_radius(8) モジュールは RADIUS (Remote Authentication Dial In User Service) プロトコル ベースの認証サービスを提供します。

18.6.1.14.<240>pam_rhosts(8)

pam_rhosts(8) モジュールは 認証サービスだけを提供します。 target ユーザーの ID が 0 ではなくて、 /etc/hosts.equiv あるいは target ユーザーの ~/.rhosts の中にリストされている remote host and user である場合のみ成功を reports 。

18.6.1.15.<240>pam_rootok(8)

pam_rootok(8) モジュールは、 プロセス (ここでは 志願者によって run されたと仮定して) を calling it た real user id が 0 の時だけ 成功を reports します。これは su(1) あるいは passwd(1) のようなネットワークではないサービスを root が自動的にアクセスするのに 便利です。

18.6.1.16.<240>pam_securetty(8)

pam_securetty(8) モジュールは アカウント サービスだけを提供します。 志願者がスーパーユーザーとして認証しようと挑戦する時、及び、プロセスが insecure TTY に attached されている時に使われます。

18.6.1.17.<240>pam_self(8)

pam_self(8) モジュールは 志願者の names が target アカウントのものと matches した場合のみ success を reports します。 su(1) のような 非-ネットワーク化サービスでもっとも便利で、志願者の identity を簡単に verified できます。

18.6.1.18.<240>pam_ssh(8)

pam_ssh(8) モジュールは、認証およびセッションサービス両方を提供します。 認証サービスは、自分の ~/.ssh ディレクトリーに パスフレーズ-プロテクトされた SSH secret keys のあるユーザーを、 パスフレーズの typing によって認証します。セッションサービスは ssh-agent(1) を開始し、 認証 phaseフェーズ(段階)で decrypted されたキーで preloads します。 この機能は、 X 中( xdm(1) や他の PAM-aware X login manager の利用) あるいは コンソールでの local logins に特に便利です。

このモジュールは、パスワード 認証 scheme の基礎的な実装です。 このモジュールは、 over a secure セッション (secure TTY 、 encrypted セッション、等) でのみ扱われるべきで、 さもなければ、 SSH パスフレーズは危険に晒されることになります。

pam_ssh(8) の利用には特別の配慮がされるべきです。 ユーザーは大抵、ファイルパーミッションが自分の SSH キーを protect するのに十分だと 決め込み、よって、弱っちぃパスフレーズを使ったり、パスフレーズを使わなかったりします。 システム管理者には、 SSH パスフレーズ品質を効果的にさせる強制的な手段がないために、これは、 システムをセキュリティーのリスクにさらす可能性があります。

18.6.1.19.<240>pam_unix(8)

pam_unix(8) モジュールは traditional UNIX® パスワード認証を実装し、 target アカウントのパスワードの取得に、 FreeBSD の下での getpwnam(3) 、あるいは、 NetBSD の下での getpwnam_r(3) を利用し、 それを志願者より provided されたものと比較します。また、アカウント管理サービス (カウントおよびパスワード失効寿命の強制) および パスワード-変更サービスも提供します。 少なくてもいくつかのサービスで歴史的挙動を保守したい 大多数の admins には、これは多分、 single ではもっとも便利なモジュールです。

18.6.2.<240>NetBSD-specific PAM Modules

18.6.2.1.<240>pam_skey(8)

pam_skey(8) モジュール S/Key One Time Password (OTP) 認証法を実装し、 /etc/skeykeys データベースを使います。

18.7.<240>PAM Application Programming

この節はまだ書かれていません。

18.8.<240>PAM Module Programming

この節はまだ書かれていません。

18.9.<240>Sample PAM Application

以下は PAM を使った su(1) の最低限の実装です。註として、 security/openpam.h に prototyped ている OpenPAM-specific の openpam_ttyconv(3) 対話関数を使っています。 このアプリケーションを違う PAM ライブラリーのシステム上で構築したいと すると、独自に対話機能を提供しなければなりません。 robust[丈夫]な 対話機能は実装するのが驚くべき困難なことで ; Sample PAM Conversation Function 節 に presented な one が good starting point ですが、 しかし、実世界のアプリケーションとして使うべきではありません。

#include <sys/param.h>
#include <sys/wait.h>

#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

#include <security/pam_appl.h>
#include <security/openpam.h>	/* for openpam_ttyconv() */

extern char **environ;

static pam_handle_t *pamh;
static struct pam_conv pamc;

static void
usage(void)
{

	fprintf(stderr, "Usage: su [login [args]]\n");
	exit(1);
}

int
main(int argc, char *argv[])
{
	char hostname[MAXHOSTNAMELEN];
	const char *user, *tty;
	char **args, **pam_envlist, **pam_env;
	struct passwd *pwd;
	int o, pam_err, status;
	pid_t pid;

	while ((o = getopt(argc, argv, "h")) != -1)
		switch (o) {
		case 'h':
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	if (argc > 0) {
		user = *argv;
		--argc;
		++argv;
	} else {
		user = "root";
	}

	/* initialize PAM */
	pamc.conv = &openpam_ttyconv;
	pam_start("su", user, &pamc, &pamh);

	/* set some items */
	gethostname(hostname, sizeof(hostname));
	if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
		goto pamerr;
	user = getlogin();
	if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
		goto pamerr;
	tty = ttyname(STDERR_FILENO);
	if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
		goto pamerr;

	/* 志願者を認証する */
	if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
		goto pamerr;
	if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
		pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
	if (pam_err != PAM_SUCCESS)
		goto pamerr;

	/* establish the requested 信用証明 */
	if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
		goto pamerr;

	/* 認証成功; open a session */
	if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
		goto pamerr;

	/* get mapped user name; PAM may have changed it */
	pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
	if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
		goto pamerr;

	/* export PAM environment */
	if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
		for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
			putenv(*pam_env);
			free(*pam_env);
		}
		free(pam_envlist);
	}

	/* build argument list */
	if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
		warn("calloc()");
		goto err;
	}
	*args = pwd->pw_shell;
	memcpy(args + 1, argv, argc * sizeof *args);

	/* fork and exec */
	switch ((pid = fork())) {
	case -1:
		warn("fork()");
		goto err;
	case 0:
		/* child: give up privs and start a shell */

		/* set uid and groups */
		if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
			warn("initgroups()");
			_exit(1);
		}
		if (setgid(pwd->pw_gid) == -1) {
			warn("setgid()");
			_exit(1);
		}
		if (setuid(pwd->pw_uid) == -1) {
			warn("setuid()");
			_exit(1);
		}
		execve(*args, args, environ);
		warn("execve()");
		_exit(1);
	default:
		/* parent: wait for child to exit */
		waitpid(pid, &status, 0);

		/* close the session and release PAM resources */
		pam_err = pam_close_session(pamh, 0);
		pam_end(pamh, pam_err);

		exit(WEXITSTATUS(status));
	}

pamerr:
	fprintf(stderr, "Sorry\n");
err:
	pam_end(pamh, pam_err);
	exit(1);
}

18.10.<240>Sample PAM Module

以下は、 pam_unix(8) の最小限の実装で、認証サービスだけを提供します。 ほとんどの PAM 実装とで構築および実行ができるはずですが、しかし、 もし利用可能なら、 OpenPAM 拡張を利用します: pam_get_authtok(3) 利用の註として、これはユーザーにパスワードを prompting するのを 非常に簡単化します。

#include <sys/param.h>

#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <security/pam_modules.h>
#include <security/pam_appl.h>

#ifndef _OPENPAM
static char password_prompt[] = "Password:";
#endif

#ifndef PAM_EXTERN
#define PAM_EXTERN
#endif

PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{
#ifndef _OPENPAM
	const void *ptr;
	const struct pam_conv *conv;
	struct pam_message msg;
	const struct pam_message *msgp;
	struct pam_response *resp;
#endif
	struct passwd *pwd;
	const char *user;
	char *crypt_password, *password;
	int pam_err, retry;

	/* identify user */
	if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
		return (pam_err);
	if ((pwd = getpwnam(user)) == NULL)
		return (PAM_USER_UNKNOWN);

	/* get password */
#ifndef _OPENPAM
	pam_err = pam_get_item(pamh, PAM_CONV, &ptr);
	if (pam_err != PAM_SUCCESS)
		return (PAM_SYSTEM_ERR);
	conv = ptr;
	msg.msg_style = PAM_PROMPT_ECHO_OFF;
	msg.msg = password_prompt;
	msgp = &msg;
#endif
	password = NULL;
	for (retry = 0; retry < 3; ++retry) {
#ifdef _OPENPAM
		pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
		    (const char **)&password, NULL);
#else
		resp = NULL;
		pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
		if (resp != NULL) {
			if (pam_err == PAM_SUCCESS)
				password = resp->resp;
			else
				free(resp->resp);
			free(resp);
		}
#endif
		if (pam_err == PAM_SUCCESS)
			break;
	}
	if (pam_err == PAM_CONV_ERR)
		return (pam_err);
	if (pam_err != PAM_SUCCESS)
		return (PAM_AUTH_ERR);

	/* compare passwords */
	if ((!pwd->pw_passwd[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
	    (crypt_password = crypt(password, pwd->pw_passwd)) == NULL ||
	    strcmp(crypt_password, pwd->pw_passwd) != 0)
		pam_err = PAM_AUTH_ERR;
	else
		pam_err = PAM_SUCCESS;
#ifndef _OPENPAM
	free(password);
#endif
	return (pam_err);
}

PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{

	return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{

	return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{

	return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{

	return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{

	return (PAM_SERVICE_ERR);
}

#ifdef PAM_MODULE_ENTRY
PAM_MODULE_ENTRY("pam_unix");
#endif

18.11.<240>Sample PAM Conversation Function

下に出てくる対話機能は OpenPAM の openpam_ttyconv(3) の顕著に簡素化したバージョンです。 それは、完全に機能し、そして読み手に、対話機能はどう振舞うべきか、 良いアイデアを与えるはずです、しかし、実世界での利用にはシンプルすぎます。 OpenPAM を使っていないとしても、 ソースコードのダウンロード、およびあなたの利用法に openpam_ttyconv(3) の適応を自由にでき ; tty-oriented の対話[機能/関数]と同じくらいの丈夫さ(robust)のものが が適度に手に入ると考えます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <security/pam_appl.h>

int
converse(int n, const struct pam_message **msg,
	struct pam_response **resp, void *data)
{
	struct pam_response *aresp;
	char buf[PAM_MAX_RESP_SIZE];
	int i;

	data = data;
	if (n <= 0 || n > PAM_MAX_NUM_MSG)
		return (PAM_CONV_ERR);
	if ((aresp = calloc(n, sizeof *aresp)) == NULL)
		return (PAM_BUF_ERR);
	for (i = 0; i < n; ++i) {
		aresp[i].resp_retcode = 0;
		aresp[i].resp = NULL;
		switch (msg[i]->msg_style) {
		case PAM_PROMPT_ECHO_OFF:
			aresp[i].resp = strdup(getpass(msg[i]->msg));
			if (aresp[i].resp == NULL)
				goto fail;
			break;
		case PAM_PROMPT_ECHO_ON:
			fputs(msg[i]->msg, stderr);
			if (fgets(buf, sizeof buf, stdin) == NULL)
				goto fail;
			aresp[i].resp = strdup(buf);
			if (aresp[i].resp == NULL)
				goto fail;
			break;
		case PAM_ERROR_MSG:
			fputs(msg[i]->msg, stderr);
			if (strlen(msg[i]->msg) > 0 &&
			    msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
				fputc('\n', stderr);
			break;
		case PAM_TEXT_INFO:
			fputs(msg[i]->msg, stdout);
			if (strlen(msg[i]->msg) > 0 &&
			    msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
				fputc('\n', stdout);
			break;
		default:
			goto fail;
		}
	}
	*resp = aresp;
	return (PAM_SUCCESS);
 fail:
        for (i = 0; i < n; ++i) {
                if (aresp[i].resp != NULL) {
                        memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                        free(aresp[i].resp);
                }
        }
        memset(aresp, 0, n * sizeof *aresp);
	*resp = NULL;
	return (PAM_CONV_ERR);
}

18.12.<240>Further Reading

Bibliography

Papers

[sun-pam] Making Login Services Independent of Authentication Technologies. Vipin Samar and Charlie Lai. Sun Microsystems.

[opengroup-singlesignon] X/Open Single Sign-on Preliminary Specification. The Open Group. 1-85912-144-6. June 1997.

[kernelorg-pamdraft] Pluggable Authentication Modules. Andrew G. Morgan. October 6, 1999.

User Manuals

[sun-pamadmin] PAM Administration. Sun Microsystems.

Related Web pages

[openpam-website] OpenPAM homepage. Dag-Erling Smørgrav. ThinkSec AS.

[linuxpam-website] Linux-PAM homepage. Andrew G. Morgan.

[solarispam-website] Solaris PAM homepage. Sun Microsystems.