以降のセクションでは、主な GSS-API データ型について説明します。すべての GSS-API データ型を確認するには、GSS-API Data Types and Valuesを参照してください。
int のサイズはプラットフォームによって異なるため、GSS-API は次の整数型を提供します。OM_uint32。これは、32 ビットの符号なし整数です。
GSS-API はすべてのデータを内部形式で処理するため、文字列も、GSS-API 形式に変換したあとで GSS-API 関数に渡す必要があります。GSS-API は、gss_buffer_desc 構造体を使って文字列を処理します。
typedef struct gss_buffer_desc_struct { size_t length; void *value; } gss_buffer_desc *gss_buffer_t;
gss_buffer_t は、そうした構造体へのポインタです。文字列は、それらを使用する関数に渡す前に gss_buffer_desc 構造体に変換しておく必要があります。次の例では、汎用的な GSS-API 関数を使って、送信前のメッセージに保護を適用しています。
使用例 4-1 GSS-API における文字列の使用法char *message_string; gss_buffer_desc input_msg_buffer; input_msg_buffer.value = message_string; input_msg_buffer.length = strlen(input_msg_buffer.value) + 1; gss_generic_function(arg1, &input_msg_buffer, arg2...); gss_release_buffer(input_msg_buffer);
ここで、input_msg_buffer を終了するときは、gss_release_buffer() を使って input_msg_buffer を解放する必要がある点に注意してください。
gss_buffer_desc オブジェクトは文字列だけに使用されるわけではありません。たとえば、トークンも gss_buffer_desc オブジェクトとして処理されます。詳細は、GSS-API Tokensを参照してください。
「名前」は主体を指します。ネットワークセキュリティーの用語では、「主体」とは、ユーザー、プログラム、またはマシンを指します。主体はクライアントまたはサーバーのどちらにでもなり得ます。
主体の例を、次にいくつか挙げます。
別のマシンにログインするユーザー (user@machine など)
ネットワークサービス (nfs@machine など)
アプリケーションを実行するマシン (myHost@example.com など)
GSS-API では、名前は gss_name_t オブジェクトとして格納されます。このオブジェクトはアプリケーションに対して不透明です。名前を gss_buffer_t オブジェクトから gss_name_t 形式に変換するには、gss_import_name() 関数を使用します。インポートされたすべての名前には関連する名前型が割り当てられます。名前型とは、その名前の形式を示すものです。名前型については、GSS-API OIDsを参照してください。有効な名前型の一覧については、Name Typesを参照してください。
gss_import_name() の構文は次のとおりです。
OM_uint32 gss_import_name ( OM_uint32 *minor-status, const gss_buffer_t input-name-buffer, const gss_OID input-name-type, gss_name_t *output-name)
実際のメカニズムから戻されるステータスコード。GSS-API Status Codesを参照してください。
インポートされた名前が格納される gss_buffer_desc 構造体。この構造体は、アプリケーション側で明示的に割り当てる必要があります。Strings and Similar Data in GSS-APIおよびExample 4–2 を参照してください。この引数は、アプリケーションでの使用終了後、gss_release_buffer() を使って解放する必要があります。
input-name-buffer の形式を示す gss_OID。Name Types in GSS-APIを参照してください。また、Name Typesに、有効な名前型の一覧表があります。
名前を受け取る gss_name_t 構造体。
次に示すのは、Example 4–1 の汎用例に若干の変更を加えたものであり、gss_import_name() の使用法を示しています。まず、通常の文字列が gss_buffer_desc 構造体に挿入されています。次に、その文字列が、gss_import_name () によって gss_name_t 構造体内に格納されています。
使用例 4-2 gss_import_name()() の使用例char *name_string; gss_buffer_desc input_name_buffer; gss_name_t output_name_buffer; input_name_buffer.value = name_string; input_name_buffer.length = strlen(input_name_buffer.value) + 1; gss_import_name(&minor_status, input_name_buffer, GSS_C_NT_HOSTBASED_SERVICE, &output_name); gss_release_buffer(input_name_buffer);
インポートされた名前は、人間が読める形式で表示できるように、元の gss_buffer_t オブジェクトに返すことが可能です。それには、gss_display_name() を使用します。ただし、gss_display_name() は、結果の文字列が元と同じであることを保証しません。その原因は、実際のメカニズムが名前を格納する方法にあります。GSS-API にはほかにも名前を処理する関数があります。GSS-API Functionsを参照してください。
gss_name_t 構造体には、単一の名前の複数のバージョンを格納できます。GSS-API によってサポートされているメカニズムごとに、1 つのバージョンが生成されます。つまり、user@company の gss_name_t 構造体には、Kerberos v5 から提供されたその名前の 1 つのバージョンと、別のメカニズムから提供された別のバージョンが含まれる可能性があります。関数 gss_canonicalize_name() は、入力として内部名とメカニズムを受け取ります。また、gss_canonicalize_name() は、出力としてそのメカニズムに固有の単一バージョン名だけを含む別の内部名を返します。
そうしたメカニズムに固有な名前のことをメカニズム名 (MN) と呼びます。メカニズム名とは、特定のメカニズムの名前ではなく、特定のメカニズムによって生成された主体の名前です。このプロセスを示したのが次の図です。
図 4-3 内部名とメカニズム名 (MN)
サーバーがクライアントからある名前を受け取り、その名前をアクセス制御リスト内で検索する必要がある場合を考えます。「アクセス制御リスト (Access Control List、ACL)」とは、特定のアクセス権を持つ主体のリストのことです。
そうした検索を行うには、次のような方法が考えられます。
gss_import_name() で、クライアント名を GSS-API 内部形式にインポートします (まだインポートされていない場合)。
場合によっては、サーバーは名前を内部形式で受け取ります。その場合、この手順は必要ありません。たとえば、サーバーはクライアント自身の名前を検索する可能性があります。コンテキストの起動中、クライアント自身の名前は内部形式で渡されます。
gss_import_name() で、各 ACL 名を インポートします。
次の図に、このプロセスを示します。ここでは手順 1 が必要であると仮定します。
図 4-4 名前の比較 (遅い)
名前の数が少ない場合は、名前を個別に比較する上記の方法でも問題ありません。名前の数が非常に多い場合は、gss_canonicalize_name() 関数を使用するほうが効率的です。
この方法では次の手順を使用します。
gss_import_name() で、クライアント名をインポートします (まだインポートされていない場合)。
名前を比較する前述の方法と同様に、名前がすでに内部形式である場合には、この手順は必要ありません。
gss_canonicalize_name() を使用してクライアント名のメカニズム名バージョンを生成します。
gss_export_name() を使用してエクスポート名を生成します。エクスポート名は、連続した文字列としてのクライアント名です。
memcmp() を使用してエクスポートされたクライアント名を ACL 内の個々の名前と比較します。これは、高速で動作するオーバーヘッドの少ない関数です。
次の図に、このプロセスを示します。ここでも、サーバーがクライアントから受信した名前をインポートする必要があると仮定します。
図 4-5 名前の比較 (速い)
gss_export_name() はメカニズム名 (MN) を期待するため、先にクライアント名に対して gss_canonicalize_name() を実行する必要があります。
詳細は、gss_export_name(3GSS)、gss_import_name(3GSS)、および gss_canonicalize_name(3GSS) を参照してください。
オブジェクト識別子 (Object Identifier、OID) は、次のようなデータを格納するときに使用します。
セキュリティーメカニズム
名前型
OID は、GSS-API の gss_OID_desc 構造体に格納されます。次の例のように、GSS-API はその構造体へのポインタ gss_OID を提供します。
使用例 4-3 OID の構造体typedef struct gss_OID_desc_struct { OM_uint32 length; void *elements; } gss_OID_desc, *gss_OID;
さらに、1 つ以上の OID を gss_OID_set_desc 構造体に格納することもできます。
使用例 4-4 OID セットの構造体typedef struct gss_OID_set_desc_struct { size_t count; gss_OID elements; } gss_OID_set_desc, *gss_OID_set;
GSS-API では、使用するセキュリティーメカニズムをアプリケーションが選択できるようになっていますが、GSS-API が選択したデフォルトのメカニズムをできるかぎり使用する必要があります。同様に、GSS-API では、データ保護の保護品質レベルをアプリケーションが指定できるようになっていますが、デフォルトの QOP をできる限り使用する必要があります。デフォルトのメカニズムを受け入れることを示すには、メカニズムまたは QOP を期待する関数に値 GSS_C_NULL_OID を引数として渡します。
注意 - セキュリティーメカニズムまたは QOP を明示的に指定することは、GSS-API の使用目的に反します。そうした特定の選択は、アプリケーションの移植性を制限します。ほかの GSS-API 実装は、その QOP またはメカニズムを意図した方法でサポートしていない可能性があります。ただし、Appendix D, Specifying an OIDでは、利用可能なメカニズムや QOP を知る方法と、それらの選択方法について、簡単に説明しています。 |
QOP とセキュリティーメカニズムのほかに、名前型を示すためにも OID が使用されます。名前型とは、関連する名前の形式を示すものです。たとえば、gss_import_name() 関数は主体の名前を文字列から gss_name_t 型に変換しますが、この関数は変換すべき文字列の形式を引数の 1 つとして受け取ります。たとえば、名前型が GSS_C_NT_HOSTBASED_SERVICE である場合、この関数は、入力された名前が service@host 形式であると判断します。名前型が GSS_C_NT_EXPORT_NAME である場合、この関数は GSS-API エクスポート名を期待します。アプリケーションは gss_inquire_names_for_mech() 関数を使用すると、指定したメカニズムで使用できる名前型を知ることができます。GSS-API によって使用される名前型の一覧については、Name Typesを参照してください。