一般に、コンテキストの確立時には、クライアントとサーバー間で一連のトークンが交換されます。プログラムの移植性を保つには、コンテキストの受け入れと起動の両方を、ループ内で実行する必要があります。コンテキスト受け入れループは、コンテキスト起動ループと非常によく似ています (ある意味で逆ですが)。「サーバーとのセキュリティーコンテキストの確立」と比較してみてください。
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);
}