サービスの GSS-API 内部形式への変換が完了すると、コンテキストを確立できます。移植性を最大にするには、コンテキストの確立を常にループとして実行する必要があります。
ループに入る前に、client_establish_context() は、コンテキストと token_ptr パラメータを初期化します。token_ptr の使用には選択肢があります。token_ptr がポイントできるのは、サーバーに送信するトークンである send_tok、サーバーから返送されてきたトークンである recv_tok のいずれかです。
ループの内側では、次の 2 つの項目が検査されます。
gss_init_sec_context() から戻されるステータス
戻りステータスは、ループの異常終了を要求する可能性のあるすべてのエラーを捕捉します。gss_init_sec_context() が GSS_S_CONTINUE_NEEDED を戻すのは、別の送信すべきトークンがサーバー側に存在する場合に限ります。
サーバーに送信すべきトークンのサイズ (gss_init_sec_context() によって生成される)
トークンサイズ 0 は、サーバーに送信できる情報がこれ以上存在しないことと、ループが終了可能であることを意味します。トークンサイズは token_ptr で決定されます。
次に、このループの擬似コードを示します。
ループの最初で、gss_init_sec_context() が呼び出されます。この関数の引数は次のとおりです。
実際のメカニズムが設定するステータスコード。
資格ハンドル。例ではデフォルトの主体として動作させるために、GSS_C_NO_CREDENTIAL を使用します。
gss-context は、作成されるコンテキストハンドルを表します。
GSS_API 内部名としてのサービスの target-name。
oid はメカニズムの ID です。
要求フラグ。この場合にクライアントが要求することは、サーバーが自分自身を認証すること、メッセージの複製をオンにすること、要求された場合にサーバーがプロキシとして動作すること、のいずれかです。
コンテキストの時間制限はありません。
チャネルバインディングの要求はありません。
token_ptr は、サーバーから受け取るトークンを指します。
サーバーが実際に使用するメカニズム。アプリケーションがこの値を使用しないため、ここでは NULL に設定されています。
&send_tok は、gss_init_sec_context() がサーバーに送信するために作成するトークンです。
戻りフラグ。この例では無視するため、NULL に設定されています。
connect_to_server() は、コンテキストまたはその一部が存在しており、かつ gss_init_sec_context() が有効なステータスを返していることを確認したあと、gss_init_sec_context() がサーバーに送信すべきトークンを提供しているかどうかを検査します。トークンが存在しない場合、それはトークンがこれ以上必要ないことを、サーバーが示していると考えられます。トークンが提供された場合、そのトークンをサーバーに送信する必要があります。トークンの送信に失敗した場合、トークンとサービスの名前空間を決定できないため、connect_to_server() が終了します。次のアルゴリズムは、トークンの長さを調べることでトークンの存在の有無を検査しています。
if (send_tok_length != 0) {
if (send_token(s, &send_tok) < 0) {
(void) gss_release_buffer(&min_stat, &send_tok);
(void) gss_release_name(&min_stat, &target_name);
return -1;
}
}send_token() は GSS-API 関数ではなく、ユーザーによって記述される必要があります。send_token() 関数は、トークンをファイル記述子に書き込みます。send_token() は、正常終了時に 0 を、エラー時に –1 を返します。GSS-API 自身はトークンの送受信を行いません。GSS-API によって作成されたトークンを送受信することは、呼び出し元のアプリケーションの責任です。
コンテキスト確立ループのソースコードを、次に示します。
/*
* Perform the context establishment loop.
*
* On each pass through the loop, token_ptr points to the token
* to send to the server (or GSS_C_NO_BUFFER on the first pass).
* Every generated token is stored in send_tok which is then
* transmitted to the server; every received token is stored in
* recv_tok, which token_ptr is then set to, to be processed by
* the next call to gss_init_sec_context.
*
* GSS-API guarantees that send_tok's length will be non-zero
* if and only if the server is expecting another token from us,
* and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
* and only if the server has another token to send us.
*/
token_ptr = GSS_C_NO_BUFFER;
*gss_context = GSS_C_NO_CONTEXT;
1234567890123456789012345678901234567890123456789012345678901234567890123456
do {
maj_stat =
gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL,
gss_context, target_name, oid,
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | deleg_flag,
0, NULL, /* no channel bindings */
token_ptr, NULL, /* ignore mech type */
&send_tok, ret_flags, NULL); /* ignore time_rec */
if (gss_context == NULL){
printf("Cannot create context\n");
return GSS_S_NO_CONTEXT;
}
if (token_ptr != GSS_C_NO_BUFFER)
(void) gss_release_buffer(&min_stat, &recv_tok);
if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
display_status("initializing context", maj_stat, min_stat);
(void) gss_release_name(&min_stat, &target_name);
return -1;
}
if (send_tok.length != 0){
fprintf(stdout, "Sending init_sec_context token (size=%ld)...",
send_tok.length);
if (send_token(s, &send_tok) < 0) {
(void) gss_release_buffer(&min_stat, &send_tok);
(void) gss_release_name(&min_stat, &target_name);
return -1;
}
}
(void) gss_release_buffer(&min_stat, &send_tok);
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
fprintf(stdout, "continue needed...");
if (recv_token(s, &recv_tok) < 0) {
(void) gss_release_name(&min_stat, &target_name);
return -1;
}
token_ptr = &recv_tok;
}
printf("\n");
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
send_token() と recv_token() の動作方法についての詳細は、Miscellaneous GSS-API Sample Functionsを参照してください。