Oracle® Solaris 11 セキュリティー開発者ガイド

印刷ビューの終了

更新: 2014 年 7 月
 
 

コンテキストの受け入れ

一般に、コンテキストの確立時には、クライアントとサーバー間で一連のトークンが交換されます。プログラムの移植性を保つには、コンテキストの受け入れと起動の両方を、ループ内で実行する必要があります。コンテキスト受け入れループは、コンテキスト起動ループと非常によく似ています (ある意味で逆ですが)。Establishing a Security Context With the Serverと比較してみてください。

server_establish_context() 関数のソースコードを、次に示します。


注 - このソースコード例は、Oracle ダウンロードセンターからダウンロードすることも可能です。http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html を参照してください。
使用例 6-4  server_establish_context() 関数
/*
 * 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 は提供するサービスに対する資格です (Acquiring Credentialsを参照)。

  • recv_tokrecv_token() でクライアントから受信したトークンです。

  • GSS_C_NO_CHANNEL_BINDINGS はチャネルバインディングを使用しないことを示すフラグです (Using Channel Bindings in GSS-APIを参照)。

  • client はクライアント名 (ASCII 文字) です。

  • oid はメカニズムです (OID 形式)。

  • send_tok はクライアントに送信するトークンです。

  • ret_flags は、コンテキストが特定のオプション (message-sequence-detection など) をサポートするかどうかを示すさまざまなフラグです。

  • 2 つの NULL 引数は、コンテキストの有効期間と、サーバーがクライアントのプロキシとして動作できるかどうかを、プログラムが知る必要がないことを示しています。

gss_accept_sec_context()maj_statGSS_S_CONTINUE_NEEDED を設定しているかぎり、受け入れループは継続します (エラーの場合を除く)。maj_stat の値がその値でも 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);
          }