サービスの 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を参照してください。