GSS-API のプログラミング

call_server()

call_server() はプログラムの中心部分です。


例 A–4 call_server()


/*
 * 関数: call_server
 *
 * 目的: 「署名」サービスを呼び出す
 *
 * 引数:
 *
 *      host            (r) サービスを提供するホスト
 *      port            (r) ホストに接続するためのポート
 *      service_name    (r) 認証する GSS-API サービス名
 *      msg             (r) 「署名」されたメッセージ
 *
 * 戻り値: 成功した場合は 0、失敗した場合は -1
 *
 * 効果:
 *
 * call_server は <host:port> への TCP 接続を開き、その接続上で 
 * service_name との GSS-API コンテキストを確立する。次に、gss_wrap で 
 * msg を GSS-API トークンにラップし、サーバーに送信し、サーバーから
 * 戻された msg の GSS-API の署名ブロックを読み取り、gss_verify で検証する。
 * どこかで失敗した場合は -1 を戻し、そうでない場合は 0 を戻す。
 */
int call_server(host, port, oid, service_name, deleg_flag, msg, use_file)
     char *host;
     u_short port;
     gss_OID oid;
     char *service_name;
     OM_uint32 deleg_flag;
     char *msg;
     int use_file;
{
     gss_ctx_id_t context;
     gss_buffer_desc in_buf, out_buf, context_token;
     int s, state;
     OM_uint32 ret_flags;
     OM_uint32 maj_stat, min_stat;
     gss_name_t         src_name, targ_name;
     gss_buffer_desc    sname, tname;
     OM_uint32          lifetime;
     gss_OID            mechanism, name_type;
     int                is_local;
     OM_uint32          context_flags;
     int                is_open;
     gss_qop_t          qop_state;
     gss_OID_set        mech_names;
     gss_buffer_desc    oid_name;
     int        i;
     int conf_req_flag = 0;
     int req_output_size = 1012;
     OM_uint32 max_input_size = 0;
        char *mechStr;

/* 接続を開く */
     if ((s = connect_to_server(host, port)) < 0)
          return -1;

     /* 接続を確立する */
     if (client_establish_context(s, service_name, deleg_flag, oid, &context,
                                  &ret_flags) < 0) {
          (void) close(s);
          return -1;
     }

 /* 保存後、コンテキストを復元する */
     maj_stat = gss_export_sec_context(&min_stat,
                                           &context,
                                           &context_token);
     if (maj_stat != GSS_S_COMPLETE) {
             display_status("exporting context", maj_stat, min_stat);
             return -1;
     }
     maj_stat = gss_import_sec_context(&min_stat,
                                           &context_token,
                                           &context);
     if (maj_stat != GSS_S_COMPLETE) {
        display_status("importing context", maj_stat, min_stat);
        return -1;
     }
     (void) gss_release_buffer(&min_stat, &context_token);

     /* フラグを表示する */
     display_ctx_flags(ret_flags);

     /* コンテキスト情報を取得する */
     maj_stat = gss_inquire_context(&min_stat, context,
                                    &src_name, &targ_name, &lifetime,
                                    &mechanism, &context_flags,
                                    &is_local,
                                    &is_open);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("inquiring context", maj_stat, min_stat);
         return -1;
     }

     if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
     printf(" context expired\n");
         display_status("Context is expired", maj_stat, min_stat);
         return -1;
     }

/* gss_wrap_size_limit をテストする */
     maj_stat = gss_wrap_size_limit(&min_stat, context,
                                conf_req_flag,
                                GSS_C_QOP_DEFAULT,
                                req_output_size,
                                &max_input_size
                                );
     if (maj_stat != GSS_S_COMPLETE) {
           display_status("wrap_size_limit call", maj_stat, min_stat);
     } else
           fprintf (stderr, "gss_wrap_size_limit returned "
                "max input size = %d \n"
                "for req_output_size = %d with Integrity only\n",
                max_input_size , req_output_size , conf_req_flag);

     conf_req_flag = 1;
     maj_stat = gss_wrap_size_limit(&min_stat, context,
                                conf_req_flag,
                                GSS_C_QOP_DEFAULT,
                                req_output_size,
                                &max_input_size
                                );
     if (maj_stat != GSS_S_COMPLETE) {
           display_status("wrap_size_limit call", maj_stat, min_stat);
     } else
           fprintf (stderr, "gss_wrap_size_limit returned "
                " max input size = %d \n"
                "for req_output_size = %d with "
                "Integrity & Privacy \n",
                max_input_size , req_output_size );

     maj_stat = gss_display_name(&min_stat, src_name, &sname,
                                 &name_type);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("displaying source name", maj_stat, min_stat);
         return -1;
     }
     maj_stat = gss_display_name(&min_stat, targ_name, &tname,
                                 (gss_OID *) NULL);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("displaying target name", maj_stat, min_stat);
         return -1;
     }
     fprintf(stderr, "\"%.*s\" to \"%.*s\", lifetime %u, flags %x, %s, %s\n",
             (int) sname.length, (char *) sname.value,
             (int) tname.length, (char *) tname.value, lifetime,
             context_flags,
             (is_local) ? "locally initiated" : "remotely initiated",
             (is_open) ? "open" : "closed");

     (void) gss_release_name(&min_stat, &src_name);
     (void) gss_release_name(&min_stat, &targ_name);
     (void) gss_release_buffer(&min_stat, &sname);
     (void) gss_release_buffer(&min_stat, &tname);


     maj_stat = gss_oid_to_str(&min_stat,
                               name_type,
                               &oid_name);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("converting oid->string", maj_stat, min_stat);
         return -1;
     }
     fprintf(stderr, "Name type of source name is %.*s.\n",
             (int) oid_name.length, (char *) oid_name.value);
     (void) gss_release_buffer(&min_stat, &oid_name);

     /* この機構によってサポートされる名前を取得する */
     maj_stat = gss_inquire_names_for_mech(&min_stat,
                                           mechanism,
                                           &mech_names);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("inquiring mech names", maj_stat, min_stat);
         return -1;
     }

     maj_stat = gss_oid_to_str(&min_stat,
                               mechanism,
                               &oid_name);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("converting oid->string", maj_stat, min_stat);
         return -1;
     }
        mechStr = (char *)__gss_oid_to_mech(mechanism);
     fprintf(stderr, "Mechanism %.*s (%s) supports %d names\n",
                (int) oid_name.length, (char *) oid_name.value,
                (mechStr == NULL ? "NULL" : mechStr),
                mech_names->count);
     (void) gss_release_buffer(&min_stat, &oid_name);

     for (i=0; i < mech_names->count; i++) {
         maj_stat = gss_oid_to_str(&min_stat,
                                   &mech_names->elements[i],
                                   &oid_name);
         if (maj_stat != GSS_S_COMPLETE) {
             display_status("converting oid->string", maj_stat, min_stat);
             return -1;
         }
         fprintf(stderr, "  %d: %.*s\n", i,
                 (int) oid_name.length, (char *) oid_name.value);

         (void) gss_release_buffer(&min_stat, &oid_name);
     }
     (void) gss_release_oid_set(&min_stat, &mech_names);

     if (use_file) {
         read_file(msg, &in_buf);
     } else {
         /* メッセージ内容を構造体へ設定完了 */
         in_buf.value = msg;
         in_buf.length = strlen(msg) + 1;
     }

     if (ret_flag & GSS_C_CONF_FLAG) {
          state = 1;
     else
          state = 0;
     }

     maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
                         &in_buf, &state, &out_buf);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("wrapping message", maj_stat, min_stat);
          (void) close(s);
          (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
          return -1;
     } else if (! state) {
          fprintf(stderr, "Warning!  Message not encrypted.\n");
     }

     /* サーバーに送信する */
     if (send_token(s, &out_buf) < 0) {
          (void) close(s);
          (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
          return -1;
     }
     (void) gss_release_buffer(&min_stat, &out_buf);

     /* 署名ブロックを out_buf に読み取る */
     if (recv_token(s, &out_buf) < 0) {
          (void) close(s);
          (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
          return -1;
     }

     /* 署名ブロックを検証する */
     maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
                               &out_buf, &qop_state);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("verifying signature", maj_stat, min_stat);
          (void) close(s);
          (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
          return -1;
     }
     (void) gss_release_buffer(&min_stat, &out_buf);

     if (use_file)
         free(in_buf.value);

     printf("Signature verified.\n");

     /* コンテキストを削除する */
     maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("deleting context", maj_stat, min_stat);
          (void) close(s);
          (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
          return -1;
     }

     (void) gss_release_buffer(&min_stat, &out_buf);
     (void) close(s);
     return 0;
}