ONC+ 開発ガイド

AUTH_KERB 認証プロトコル

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

  1. KGETKCRED

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

  2. KSETKCRED

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

  3. UNIX 固有の KGETUCRED

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

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

NFS マウント例

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

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

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

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

この時に返される可能性のある 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 の暗号化された部分を複号化し、ベリファイアの妥当性検査を行います。

この時に返される可能性のある 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;  /* 暗号化されたウィンドウベリファイア */
};
 
/*
ベリファイア:サーバー側
 * クライアントによりサーバーは、タイムスタンプ(暗号化)が与えられた。
 * また、サーバーは、クライアントがニックネームを今後の(暗号化されて
 * いない)トランザクションで使用するように指定します。
 */
struct authkerb_verf_svr {
 	timestamp akv_timeverf;    /* 暗号化されたベリファイア */
 	unsigned long akv_nickname; /* クライアントの新しいニックネーム */
};