GSS-API のプログラミング

client_establish_context()

client_establish_context()gss_init_sec_context() を呼び出して、サーバーとのコンテキストを確立します。


例 A–6 client_establish_context()


/*
 * 関数: client_establish_context
 *
 * 目的: 指定されたサービスとの GSS-API コンテキストを確立し、
 * コンテキストハンドルを返す
 *
 * 引数:
 *
 *      s               (r) サーバーとの間で確立された TCP 接続
 *      service_name    (r) サービスの ASCII 名
 *      context         (w) 確立された GSS-API コンテキスト
 *      ret_flags       (w) init_sec_context から戻されたフラグ
 *
 * 戻り値: 成功した場合は 0、失敗した場合は -1
 *
 * 効果:
 *
 * service_name が GSS-API 名としてインポートされ、
 * 対応するサービスとの間で GSS-API コンテキストが確立される。
 * サービスは TCP 接続 s 上で応答待ちとする。デフォルトの
 * GSS-API 機構が使用され、相互認証とリプレイの検出が
 * 要求される。
 *
 * 成功した場合、コンテキストハンドルが context に戻される。
 * 失敗した場合、GSS-API エラーメッセージが stderr に表示され
 * -1 が戻される。
 */
     int client_establish_context(s, service_name, deleg_flag, oid,
                             gss_context, ret_flags)
     int s;
     char *service_name;
     gss_OID oid;
     OM_uint32 deleg_flag;
     gss_ctx_id_t *gss_context;
     OM_uint32 *ret_flags;
{
     gss_buffer_desc send_tok, recv_tok, *token_ptr;
     gss_name_t target_name;
     OM_uint32 maj_stat, min_stat;

     /*
      * 名前を target_name にインポートする。send_tok で
      * ローカル変数空間を保存する。 
      */

     send_tok.value = service_name;
     send_tok.length = strlen(service_name) + 1;
     maj_stat = gss_import_name(&min_stat, &send_tok,
                        (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &target_name);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("parsing name", maj_stat, min_stat);
          return -1;
     }


     /*
      * コンテキスト確立ループを実行する。
      *
      * ループを通過するごとに、token_ptr はサーバーに送信されるトークンに
      * 設定される (最初に通過するときは GSS_C_NO_BUFFER)。
      * 生成された各トークンは send_tok に格納され、サーバーに送信される。
      * 受信された各トークンは recv_tok に格納され、token_ptr は次の
      * gss_init_sec_context の呼び出しで処理されるトークンに
      * 設定される。
      *
      * GSS-API は、以下の 2 つのことを保証する。
      * 1. サーバーがクライアントからこれ以上トークンを期待していない場合にのみ~
、
      * send_tok の length の値が 0 になる。
      * 2. サーバーにクライアントへ送るトークンが存在する場合のみ、
      * gss_init_sec_context が GSS_S_CONTINUE_NEEDED を戻す。
      */

     token_ptr = GSS_C_NO_BUFFER;
     *gss_context = GSS_C_NO_CONTEXT;

     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,       /* チャネルバインディングなし */
                                    token_ptr,
                                    NULL,       /* 機構の型を無視する */
                                    &send_tok,
                                    ret_flags,
                                    NULL);      /* 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);

     (void) gss_release_name(&min_stat, &target_name);
     return 0;
}