ONC+ 開発ガイド

AUTH_KERB 認証プロトコル

AUTH_KERB の SunOS 5.x 実装に使用されたカーネルは、Kerberos のコードをオペレーティングシステムのカーネルへコンパイルしないで、kerbd という代理の RPC デーモンを使用します。このデーモンは、以下の 3 つの手続きをエクスポートします。詳細については、kerbd(1M) マニュアルページを参照してください。

  1. クライアントによって提供された認証プロトコルを検査するために、サーバ側の RPC が使用する KGETKCRED

  2. 主体名、インスタンス、領域が指定されると、暗号化されたチケットおよび DES セッションキーを返す KSETKCRED

  3. UNIX 固有の KGETUCREDKGETUCRED は、主な名前がサーバにもわかるユーザ名にマップされると想定し、ユーザの ID、グループ ID、およびグループリストを返します。

Kerberos の内容を的確に説明するには、現在 Kerberos を実装しているサービスであるネットワークファイルシステム (NFS) を例として使用するのが良いでしょう。サーバ s の NFS サービスは、nfs.s という周知の一次名を持つとします。クライアント c の特権ユーザは、root という主体名と、インスタンス c をもっているとします。AUTH_DES の場合とは異なり、ユーザのチケット発行用のチケットの期限が切れた場合は、kinit() を再び呼び出さなければならないことに注意してください。Kerberos マウントの NFS サービスは、新しいチケット発行用のチケットを獲得するまで成功しません。

NFS マウント例

この節全体を通して、AUTH_KERB を使用した NFS マウント要求について説明します。マウント要求は、SunOS のルートで実行されるので、ユーザの識別情報は、root.c.になります。

クライアント c は、マウントするディレクトリのファイルハンドルを獲得するために、サーバ sMOUNTPROC_MOUNT 要求を実行します。クライアントのマウントプログラムは、ファイルハンドル、mountflavor、時間同期アドレス、サーバの既知の主体名である nfs.s を、クライアントのカーネルに渡して、NFS マウントシステムコールを実行します。次に、クライアントのカーネルが時間同期ホストでサーバに接続し、クライアント/ サーバ間の時間差を取得します。

クライアントのカーネルは、次の RPC 呼び出しを行います。(1) チケットおよびセッションキーを獲得するためにのローカルの kerbd への KSETKCRED 呼び出し。(2) フルネームの資格およびベリファイアを使用した、サーバのNFSサービスへの NFSPROC_GETATTR 呼び出し。サーバは、呼び出しを受信し、ローカルの kerbdKGETKCRED 呼び出しを行ってクライアントのチケットを検査します。

サーバの kerbd と Kerberos ライブラリは、チケットの暗号を解除し、主体名および DESセッションキーを他のデータの中に返します。サーバは、チケットがまだ有効であることをチェックし、セッションキーを使用して資格、ベリファイアの DES-encrypted の部分の暗号を解除し、ベリファイアが有効であることを検査します。

この時に返される可能性のある Kerberos 認証エラーは、下記のとおりです。

エラーを受信しない場合、サーバはクライアントの識別情報をキャッシュに書き込み、NFS 回答に返されるニックネーム (小さい整数) を割り当てります。その時サーバは、クライアントがサーバと同じ領域かどうかをチェックします。クライアントがサーバと同じ領域の場合、サーバは、KGETUCRED をローカルの kerbd に呼び出して、主体名を UNIX の資格に変換します。変換できない場合、ユーザは匿名であるとマークされます。サーバは、ファイルシステムのエクスポート情報に対するこれらの資格を検査します。次の 3 つのケースを考えてください。

  1. KGETUCRED 呼び出しが失敗し、匿名の要求が受け入れられた場合、匿名のユーザに UNIX 資格が割り当てられます。

  2. KGETUCRED 呼び出しが失敗し、匿名の要求が受け入れられない場合、NFS 呼び出しは失敗し、AUTH_TOOWEAK が返されます。

  3. KGETUCRED 呼び出しが成功する場合は、資格が割り当てられ、その後にルートのパーミッションのチェックも含む、正常な保護検査が行われます。

次に、サーバが、ニックネームおよびサーバのベリファイアを組み込んで NFS 回答を送信します。クライアントは回答を受信し、ベリファイアの暗号の解除と妥当性検査を行い、今後の呼び出しのためにニックネームを格納します。クライアントがサーバに 2 番目の NFS 呼び出しを行うと、先にサーバに書込まれた呼び出しが繰り返されます。クライアントのカーネルが、以前に記述されたニックネーム資格およびベリファイアを使用して、サーバの NFS サービスに NFSPROC_STATVFS 呼び出しを行います。サーバは呼び出しを受信し、ニックネームの妥当性検査を行います。これが範囲外であれば、エラー AUTH_BADCRED を返します。サーバは、獲得したばかりのセッションキーを使用して、ベリファイアの DES-encrypted 部分の暗号を解除し、ベリファイアの妥当性検査を行います。

この時に返される可能性のある Kerberos 認証エラーは、次のとおりです。

エラーが受信されない場合、サーバは、ニックネームを使用して、呼び出し側の UNIX 資格を検出します。それから、サーバはファイルシステムのエクスポート情報に対するこれらの資格を検査し、ニックネームおよびサーバのベリファイアを組み込んだ NFS 回答を送信します。クライアントは回答を受信し、ベリファイアの暗号の解除および妥当性検査を行い、これからの呼び出しのためにニックネームを格納します。最後に、クライアントのNFS マウントシステムコールが返り、要求が終了します。

KERB 認証プロトコル (XDR 言語で記述)

例 B-3 (AUTH_KERB) は、例 B-2 で示された AUTH_DES と似ています。両者の違いに注意してください。


例 B-3 Kerb 認証プロトコル

#define AUTH_KERB 4
/*
 * 資格には 2 種類あります。1 つはクライアントが (前もって暗号化された)
 * Kerberos チケット送信する資格で、もう 1 つはクライアントがサーバに指定され
 * た「ニックネーム」(符号なしの整数のみ) を使用する資格です。クライアントは、
 * サーバへの初めてのトランザクションでは、フルネームを使用しなければなりませ
 * ん。それに対してサーバはクライアントにニックネームを返します。クライアントは
 * それ以降、サーバへのトランザクションでニックネームを使用できます。
 * (チケットの期限が切れるまで)。 	必ずニックネームを使用しなけれ
 * ばならないわけではありませんが、パフォーマンスから考えても、ニック
 * ネームを使用する方がよいでしょう。
 */
enum authkerb_namekind {
 	AKN_FULLNAME = 0,
 	AKN_NICKNAME = 1
 };
/*
 * フルネームには、暗号化されたサービスチケットと有効期限が含まれます。
 * 実際、この有効期限は、資格の有効期限と同じです。ベリファイアの
 * タイムスタンプに示されている時間に有効期限を加えた時間がすでに経過すると、
 * サーバは要求を満了にして、もはや承諾しません。要求がやり直されないようにす
 * るため、サーバは、はじめのトランザクション以外の場合に、タイムスタンプが以
 * 前のタイムスタンプより大きくないかどうかをチェックする必要があります。はじ
 * めのトランザクションでは、サーバはウィンドウベリファイアがウィンドウより小
 * さいことを検査します。
 */
struct authkerb_fullname {
 	KTEXT_ST ticket;              /* Kerberos サービスチケット */
 	unsigned long window;        /* 暗号化されたウィンドウ */
};                             
/*
 * 資格はフルネームかニックネーム
 */
union authkerb_credswitch(authkerb_namekind akc_namekind){
 	case AKN_FULLNAME:
 		authkerb_fullname akc_fullname;
 	case AKN_NICKNAME:
 		unsigned long akc_nickname;
};
/*
 * タイムスタンプには、1970 年 1 月 1 日の午前 0 時からの秒数を符号化
 */
struct timestamp {
 	unsigned long seconds;      /* 秒 */
 	unsigned long useconds;     /* マイクロ秒 */
};
/*
 * ベリファイア:クライアント側
 */
struct authkerb_verf_clnt {
 	timestamp akv_timestamp;   /* 暗号化されたタイムスタンプ */
 	unsigned long akv_winverf;  /* 暗号化されたウィンドウベリファイア */
};

/*
ベリファイア:サーバ側Verifier: server variety
 * クライアントによりサーバは、タイムスタンプ(暗号化)が与えられた。
 * また、サーバは、クライアントがニックネームを今後の(暗号化されて
 * いない)トランザクションで使用するように指定します。
 */
struct authkerb_verf_svr {
 	timestamp akv_timeverf;    /* 暗号化されたベリファイア */
 	unsigned long akv_nickname; /* クライアントの新しいニックネーム */
};