一般に、コンテキストの確立時には、クライアントとサーバー間で一連のトークンが交換されます。プログラムの移植性を保つには、コンテキストの受け入れと起動の両方を、ループ内で実行する必要があります。コンテキスト受け入れループは、コンテキスト起動ループと非常によく似ています (ある意味で逆ですが)。「サーバーとのセキュリティーコンテキストの確立」と比較してみてください。
server_establish_context() 関数のソースコードを、次に示します。
このソースコード例は、Sun ダウンロードセンターからダウンロードすることも可能です。http://www.sun.com/download/products.xml?id=41912db5 を参照してください。
/* * Function: server_establish_context * * Purpose: establishes a GSS-API context as a specified service with * an incoming client, and returns the context handle and associated * client name * * Arguments: * * s (r) an established TCP connection to the client * service_creds (r) server credentials, from gss_acquire_cred * context (w) the established GSS-API context * client_name (w) the client's ASCII name * * Returns: 0 on success, -1 on failure * * Effects: * * Any valid client request is accepted. If a context is established, * its handle is returned in context and the client name is returned * in client_name and 0 is returned. If unsuccessful, an error * message is displayed and -1 is returned. */ int server_establish_context(s, server_creds, context, client_name, ret_flags) int s; gss_cred_id_t server_creds; gss_ctx_id_t *context; gss_buffer_t client_name; OM_uint32 *ret_flags; { gss_buffer_desc send_tok, recv_tok; gss_name_t client; gss_OID doid; OM_uint32 maj_stat, min_stat, acc_sec_min_stat; gss_buffer_desc oid_name; *context = GSS_C_NO_CONTEXT; do { if (recv_token(s, &recv_tok) < 0) return -1; if (verbose && log) { fprintf(log, "Received token (size=%d): \n", recv_tok.length); print_token(&recv_tok); } maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, server_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid, &send_tok, ret_flags, NULL, /* ignore time_rec */ NULL); /* ignore del_cred_handle */ (void) gss_release_buffer(&min_stat, &recv_tok); if (send_tok.length != 0) { if (verbose && log) { fprintf(log, "Sending accept_sec_context token (size=%d):\n", send_tok.length); print_token(&send_tok); } if (send_token(s, &send_tok) < 0) { fprintf(log, "failure sending token\n"); return -1; } (void) gss_release_buffer(&min_stat, &send_tok); } if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { display_status("accepting context", maj_stat, acc_sec_min_stat); if (*context == GSS_C_NO_CONTEXT) gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); return -1; } if (verbose && log) { if (maj_stat == GSS_S_CONTINUE_NEEDED) fprintf(log, "continue needed...\n"); else fprintf(log, "\n"); fflush(log); } } while (maj_stat == GSS_S_CONTINUE_NEEDED); /* display the flags */ display_ctx_flags(*ret_flags); if (verbose && log) { maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name); if (maj_stat != GSS_S_COMPLETE) { display_status("converting oid->string", maj_stat, min_stat); return -1; } fprintf(log, "Accepted connection using mechanism OID %.*s.\n", (int) oid_name.length, (char *) oid_name.value); (void) gss_release_buffer(&min_stat, &oid_name); } maj_stat = gss_display_name(&min_stat, client, client_name, &doid); if (maj_stat != GSS_S_COMPLETE) { display_status("displaying name", maj_stat, min_stat); return -1; } maj_stat = gss_release_name(&min_stat, &client); if (maj_stat != GSS_S_COMPLETE) { display_status("releasing name", maj_stat, min_stat); return -1; } return 0; }
sign_server() 関数は、コンテキストを受け入れる際に、次のソースコードを使って server_establish_context() を呼び出します。
/* Establish a context with the client */ if (server_establish_context(s, server_creds, &context, &client_name, &ret_flags) < 0) return(-1);
server_establish_context() 関数はまず、クライアントがコンテキスト起動中に送信したトークンを探します。GSS-API 自身はトークンの送受信を行わないため、これらの作業を行うにはプログラムが独自のルーチンを持つ必要があります。サーバーは、次のように recv_token() を使ってトークンを受信します。
do { if (recv_token(s, &recv_tok) < 0) return -1;
次に、server_establish_context() は、GSS-API 関数 gss_accept_sec_context() を次のように呼び出します。
maj_stat = gss_accept_sec_context(&min_stat, context, server_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid, &send_tok, ret_flags, NULL, /* ignore time_rec */ NULL); /* ignore del_cred_handle */
min_stat は実際の機構から戻されるエラー状態です。
context は確立されているコンテキストです。
server_creds は提供するサービスに対する資格です (「資格の獲得」を参照)。
recv_tok は recv_token() でクライアントから受信したトークンです。
GSS_C_NO_CHANNEL_BINDINGS はチャネルバインディングを使用しないことを示すフラグです (「GSS-API におけるチャネルバインディングの使用」を参照)。
client はクライアント名 (ASCII 文字) です。
oid は機構です (OID 形式)。
send_tok はクライアントに送信するトークンです。
ret_flags は、コンテキストが特定のオプション (message-sequence-detection など) をサポートするかどうかを示すさまざまなフラグです。
2 つの NULL 引数は、コンテキストの有効期間と、サーバーがクライアントのプロキシとして動作できるかどうかを、プログラムが知る必要がないことを示しています。
gss_accept_sec_context() が maj_stat に GSS_S_CONTINUE_NEEDED を設定している限り、受け入れループは継続します (エラーの場合を除く)。maj_stat の値が GSS_S_CONTINUE_NEEDED でも GSS_S_COMPLETE でもない場合、問題が発生したことを示しており、ループは終了します。
クライアントに送り返すべきトークンが存在するかどうかに関係なく、gss_accept_sec_context() は send_tok の長さを表す正の値を返します。次のステップでは、送信すべきトークンの存在の有無を確認し、存在する場合はそのトークンを送信します。
if (send_tok.length != 0) { . . . if (send_token(s, &send_tok) < 0) { fprintf(log, "failure sending token\n"); return -1; } (void) gss_release_buffer(&min_stat, &send_tok); }