Part 3 では NIS+ のための API について説明します。
この章は、NIS+ アプリケーションのプログラミングインタフェースの基礎について説明し、詳しいサンプルプログラムを示します。NIS+ API は、Solaris を使用するネットワーク用のアプリケーションを構築するプログラマを対象としています。NIS+ API には、アプリケーションをサポートするための基本的な機能が用意されています。
NIS+ ネットワークネームサービスが対象とするクライアント-サーバネットワークは、数個のサーバが 10 個のクライアントをサポートする程度の単純なローカルエリアネットワークから、全世界のさまざまなサイトに位置する 20 〜 100 個の専用サーバが 10,000 個ものマルチベンダクライアントをサポートし、さまざまな公衆ネットワークで連結された大規模なものまであります。
NIS+ は、階層ドメインをサポートします。図 5-1 に、簡単な例を示します。
NIS+ の各ドメインは、組織の各部分のワークステーション、ユーザ、ネットワークサービスを記述するデータの集合です。NIS+ の各ドメインは、他のドメインとは独立に管理できます。この機能のおかげで、NIS+ は、小さなものから大きなものまでさまざまな規模のネットワークで使用できます。
各ドメインはいくつかのサーバでサポートされています。このうち中心となるサーバをマスタサーバ、バックアップサーバをレプリカサーバといいます。マスタサーバとレプリカサーバの両方で NIS+ プログラムを実行します。オリジナルテーブルはマスタサーバが保管し、レプリカサーバはそのコピーを保存します。
NIS+ では、段階的にレプリカを更新します。最初にマスタサーバを変更すると、次にその変更が自動的にレプリカサーバに伝えられ、ネーム空間全体で有効となります。
NIS+ では、情報がマップやゾーンファイルではなくテーブルに保存されます。NIS+ には 図 5-2 で示されている 16 種類の定義済みテーブル (システムテーブル) があります。
各テーブルにはそれぞれ違う種類の情報が保存されます。たとえば、Hosts テーブルには、ホスト名とインターネットアドレスのペアが保存され、Password テーブルにはネットワークユーザに関する情報が保存されます。
NIS+ テーブルは、次の 2 つの点で NIS マップから大きく改善されています。1 つは、NIS+ テーブルでは第 1 カラム (キーともいう) だけでなく任意のカラムをアクセスできる点です。このため、NIS の hosts.byname マップや hosts.byaddr マップのような重複マップが不要になりました。もう 1 つは、NIS+ テーブルの情報には、テーブルレベル、エントリレベル、カラムレベルの 3 つのレベルでアクセスできる点です。
NIS+ のセキュリティモデルには、許可と認証の 2 つの機能があります。まず、ネーム空間上の各オブジェクトごとに、どのようなプリンシパルにどの種類の操作を許すかを指定します。これを許可といいます。ネーム空間へのアクセスが要求されると、NIS+ はその要求を出したプリンシパルを確認します。NIS+ は、要求の発信元を認識すると、その特定のプリンシパルに対する特定の操作をオブジェクトが認可しているか確かめます。NIS+ はこのように、認証情報とオブジェクトごとの許可情報に基づいて、アクセス要求を許すか拒否するかを決定します。
NIS+ はネームサービス切り換えとともに使用できます。ネームサービス切り換え (単に切り換えともいう) を使用すると、Solaris 2.x を使用するワークステーションで、複数のネットワーク情報サービスから情報を得ることができます。特に、ローカルファイル、/etc ファイル、NIS マップ、DNS ゾーンファイル、NIS+ テーブルから情報が得られます。ネームサービス切り換えを使用すると、単に情報源を選択するだけでなく、ワークステーションで情報の種類別に異なる情報源を使用できます。ネームサービスの設定は、/etc/nsswitch.conf ファイルで行います。
NIS+ では、ネーム空間を管理するのに必要なコマンドがすべて提供されています。
表 5-1 にその要約を示します。
表 5-1 NIS+ のネーム空間管理コマンド
コマンド |
説明 |
---|---|
NIS+ オブジェクトのグループ所有者を変更する。 |
|
オブジェクトのアクセス権を変更する。 |
|
NIS+ オブジェクトの所有者を変更する。 |
|
NIS+ グループの作成と破棄、グループメンバリストの表示を行う。また、グループにメンバを追加または削除したり、グループメンバかどうかのテストを行う。 |
|
NIS+ テーブルの内容を表示する。 |
|
NIS+ テーブルのエントリを検索する。 |
|
NIS+ ディレクトリの内容をリストする。 |
|
NIS+ テーブルのエントリを検索する。 |
|
/etc ファイル、または、NIS マップの情報を NIS+ テーブルに追加する。 |
|
NIS+ テーブルの作成や削除を行う。また、NIS+ テーブルのエントリを追加、変更、削除する。 |
|
NIS+ プリンシパルの資格を作成し、それを Cred テーブルに保存する。 |
|
NIS+ の Passwd テーブルのパスワード情報を変更する。 |
|
NIS+ オブジェクトに保存されているパブリックキーを更新する。 |
|
NIS+ のクライアントまたはサーバを初期化する。 |
|
NIS+ ディレクトリを作成し、そのマスタサーバとレプリカサーバを指定する。 |
|
ネーム空間から、NIS+ ディレクトリとその複製を削除する。 |
|
org_dir と groups_dir の 2 つのディレクトリを作成し、NIS+ ドメインに対する全種類の NIS+ テーブル (空のテーブル) を作成する。 |
|
NIS+ のサーバプロセス。 |
|
NIS+ クライアントの NIS+ キャッシュマネージャを起動する。 |
|
NIS+ オブジェクトの生存時間を変更する。 |
|
NIS+ オブジェクトのデフォルト値 (ドメイン名、グループ名、ワークステーション名、NIS+ プリンシパル名、アクセス権、ディレクトリの検索パス、生存時間) をリストする。 |
|
2 つの NIS+ オブジェクト間のシンボリックリンクを作成する。 |
|
ディレクトリ以外の NIS+ オブジェクトをネーム空間から削除する。 |
|
NIS+ の アプリケーションプログラマーズインタフェース (API) は関数の集合です。アプリケーションでは、これらの関数を呼び出して NIS+ オブジェクトにアクセスしたり変更したりできます。NIS+ の API には 54 個の関数があり、それらは次の 9 つのグループに分類されます。
表 5-2 では、これらの関数をグループごとにまとめて簡単に説明します。グループ名は、NIS+ のマニュアルページのグループ名と同じです。
表 5-2 NIS+ の API 関数
関数 |
説明 |
---|---|
nis_names() |
オブジェクトの検索と操作。 |
NIS+ オブジェクトのコピーを返す。リンクをたどることができる。エントリオブジェクトの検索はできないが、リンクがエントリオブジェクトを指している場合は、それを返すことができる。 |
|
NIS+ オブジェクトをネーム空間に追加する。 |
|
NIS+ オブジェクトをネーム空間から削除する。 |
|
ネーム空間の NIS+ オブジェクトを変更する。 |
|
テーブルの検索と更新を行う。 |
|
NIS+ ネーム空間内のテーブルを検索して、検索条件に一致するエントリオブジェクトを返す。テーブル間のリンクと検索パスをたどることができる。 |
|
NIS+ テーブルにエントリオブジェクトを追加する。既存オブジェクトがあれば操作を中止するか上書きするかを指定できる。操作が正常終了した場合は、追加したオブジェクトのコピーが返される。 |
|
nis_result 構造体に割り当てられたメモリをすべて解放する。 |
|
NIS+ テーブルからエントリオブジェクトを削除する。削除するオブジェクトは、検索条件で指定するか、キャッシュされたオブジェクトコピーへのポインタで指定できる。検索条件で指定する場合は、その条件に一致するオブジェクトをすべて削除できる。したがって、検索条件を適切に指定すれは、テーブル内の全エントリを削除することもできる。操作が正常終了した場合は、削除したオブジェクトのコピーが返される。 |
|
NIS+ テーブルのエントリオブジェクトを変更する。変更するオブジェクトは、検索条件で指定するか、キャッシュされたオブジェクトコピーへのポインタで指定する。 |
|
NIS+ テーブルの最初のエントリオブジェクトのコピーを返す |
|
NIS+ テーブルの「次」のエントリオブジェクトのコピーを返す。この関数への呼び出しと呼び出しの間に、テーブルの更新やエントリの追加・変更が行われる可能性があるので、返されたエントリの順序が実際のテーブル内のエントリ順序と一致しない場合がある。 |
|
現在のプロセスのデフォルト名を取り出す。 |
|
ワークステーションの NIS+ ドメイン名を返す。 |
|
修飾子付きのワークステーション名を返す。修飾子付きのワークステーション名は、host-name、domain-nameという形式になる。 |
|
現在の NIS+ グループ名を返す。現在の NIS+ グループは、環境変数 NIS_GROUP で指定される。 |
|
NIS+ プリンシパル名 (そのプリンシパルの UID は呼び出し側プロセスに結合) を返す。 |
|
特定のネームに対する可能な展開形のリストを返す。 |
|
nis_getnames()が生成したリストが使用するメモリを解放する。 |
|
グループ操作と許可。 |
|
あるプリンシパルがグループのメンバかどうか調べる。 |
|
グループにメンバを追加する。メンバはプリンシパル、グループ、ドメインのどれか。 |
|
グループからメンバを削除する。 |
|
グループオブジェクトを作成する。 |
|
グループオブジェクトを削除する。 |
|
グループオブジェクトが存在しているかどうか調べる。 |
|
グループオブジェクトのメンバになっているプリンシパルをリストする。 |
|
NIS+ アプリケーションのための種々のサービス。 |
|
特定ホストの特定ディレクトリに対するサービスをサポートするためのデータベースを作成する。 |
|
ホストからディレクトリを削除する。 |
|
NIS+ サーバの状態変数の設定と読み込みを行い、内部キャッシュをフラッシュする。 |
|
サーバのパフォーマンスに関する統計情報を取り出す。 |
|
特定のドメインをサポートするサーバのリストを返す。 |
|
nis_getservlist() が返したサーバリストが使用するメモリを解放する。 |
|
NIS+ サーバとデータベースの間のインタフェース。NIS+ クライアントでは使用不可。 |
|
指定したテーブルの最初のエントリのコピーを返す。 |
|
指定したエントリの次のエントリのコピーを返す。 |
|
最初または次のエントリシーケンスを終了する。 |
|
指定した属性に一致するエントリのコピーを返す。 |
|
指定した属性に一致するエントリをすべて削除する。 |
|
指定した属性に一致するテーブルエントリを、指定したオブジェクトのコピーで置き換える。または、指定したオブジェクトをテーブルに追加する |
|
テーブルの内容を再編成して、テーブルのアクセス効率を改善する。 |
|
データベースマネージャに資源の解放を勧める。 |
|
NIS+ のステータス値に対応するメッセージ文字列を取り出す関数。 |
|
メッセージ文字列定数へのポインタを返す。 |
|
メッセージ文字列定数を標準出力に表示する。 |
|
メッセージ文字列定数を syslog に送信する。 |
|
strdup() 使用するかまたはでコピーするために静的領域に割り当てられた文字列へのポインタを返す。 |
|
トランザクションのログを取る関数。サーバで使用。 |
|
ディレクトリのマスタサーバが、ディレクトリのタイムスタンプを作成するのに使用する。この関数を実行すると、複製も強制的に更新される。 |
|
ログデータを強制的にディスク上のテーブルに保存する。 |
|
NIS+ のネームとオブジェクトの操作のための補助関数。 |
|
NIS+ ネームの最初のラベルを返す。返されたネームには、末尾のピリオドは付いていない。 |
|
ネームからドメイン関連のラベルをすべて削除して、固有のオブジェクト部分だけを返す。この関数に渡されたネームは、ローカルドメイン、または、その子ドメインでなければならない。それ以外の場合は NULL が返される。 |
|
オブジェクトが入っているドメイン名を返す。返されたドメイン名はピリオドで終わっている。 |
|
2 つの NIS+ 名を比較する。大文字小文字の違いは無視して比較し、ネームが同じか、派生関係にあるか、無関係かを返す。. |
|
nis_clone_object() で作成したオブジェクトを破棄する。 |
|
ローカルプリンシパルとローカルドメインを決定します。
ローカルディレクトリオブジェクトのルックアップを行います。
ローカルドメインの下に foo というディレクトリを作成します。
ドメイン foo の下に groups_dir と org_dir というディレクトリを作成します。
グループオブジェクト admins.foo を作成します。
admins グループにローカルプリンシパルを追加します。
org_dir.foo の下にテーブルを作成します。
org_dir.foo テーブルにエントリを 2 つ追加します。
admins グループの新たなメンバリストを取り出して表示します。
コールバックを使用して、ドメイン foo の下のネーム空間をリストします。
コールバックを使用して、作成したテーブルの内容をリストします。
次のものを削除して、作成した全オブジェクトを削除します。
admins グループのローカルプリンシパル。
admins グループ。
はじめにテーブル内のエントリ、次にテーブル自体。
groups_dir と org_dir のディレクトリオブジェクト。
foo ディレクトリオブジェクト。
サンプルプログラムは典型的なアプリケーションとはいえません。通常は、ディレクトリとテーブルの作成と削除はコマンド行インタフェースで行い、アプリケーションでは NIS+ エントリオブジェクトの操作だけを行います。
サンプルプログラムでは <rpcsvc/nis.h> ファイルで定義されているマクロを使用しています。ここで定義されているマクロは、サポートが保証されている正式な API ではなく、将来変更されたりなくなったりする可能性があります。ここではサンプルプログラムで使用方法を説明するために使用していますが、実際のプログラムで使用するときはユーザ自身の責任で使用してください。サンプルプログラムで使用しているマクロを次に示します。
NIS_RES_OBJECT
ENTRY_VAL
DEFAULT_RIGHTS
サンプルプログラムでは、次の NIS+ API 関数を C 言語で使用する方法を示します。
nis_add()、nis_add_entry()、nis_addmember()
nis_creategroup()、nis_destroygroup()、nis_domain_of()
nis_freeresult()、nis_leaf_of()、nis_list()
nis_local_directory()、nis_local_principal()、nis_lookup()
nis_mkdir()、nis_perror()、nis_remove()
nis_remove_entry()、nis_removemember()
例 5-1 が示すサンプルプログラムは、これを実行する NIS+ プリンシパルがローカルドメインにディレクトリオブジェクトを作成することを許可されているものとして書かれています。このプログラムをコンパイルするコマンドを次に示します。
yourhost% cc -o example.c example -lnsl
このプログラムを実行するコマンドを次に示します。
yourhost% example [dir]
ここで、dir には NIS+ ディレクトリを指定します。サンプルプログラムは、すべての NIS+ オブジェクトをそのディレクトリに作成します。引数 dir を指定しないと、ローカルドメインの親ディレクトリにオブジェクトが作成されます。nis_lookup() の呼び出しでは、ディレクトリを指定する文字列に空白とローカルドメイン名が追加されることに注意してください。引数で指定するのは、作成した NIS+ オブジェクトを入れるための NIS+ ディレクトリ名です。このプログラムを実行するプリンシパルは、そのディレクトリ内でのオブジェクト作成許可を持っている必要があります。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <rpcsvc/nis.h> #define MAX_MESG_SIZE 512 #define BUFFER_SIZE 64 #define TABLE_TYPE "test_data" main(argc, argv) int argc; char *argv[]; { char *saved_grp, *saved_name, *saved_owner; char dir_name[NIS_MAXNAMELEN]; char local_domain[NIS_MAXNAMELEN]; char local_princip [NIS_MAXNAMELEN]; char org_dir_name [NIS_MAXNAMELEN]; char grp_name [NIS_MAXNAMELEN]; char grp_dir_name [NIS_MAXNAMELEN]; char table_name [NIS_MAXNAMELEN]; nis_object *dirobj, entdata; nis_result *pres; u_int saved_num_servers; int err; if (argc == 2) sprintf (local_domain, "%s.", argv[1]); else strcpy (local_domain, ""); strcat (local_domain, (char *) nis_local_directory()); strcpy (local_princip, (char *) nis_local_principal()); /* * 次の 2 つの目的で、ディレクトリオブジェクトからローカルドメインを探す。 * 1.nis_object のテンプレートを得る。 * 2.返されたディレクトリオブジェクトに含まれる情報を再利用する。 * static で宣言した nis_object があり、それをほとんどそのままで * 使用できる場合は、nis_object 構造体を初期化するより、それを変更して * 使用するほうが簡単である。 */ pres = nis_lookup (local_domain, 0); if (pres->status != NIS_SUCCESS) { nis_perror (pres->status, "unable to lookup local directory"); exit (1); } /* * 親ディレクトリオブジェクトのほとんどのフィールドを再利用 - 変更する * フィールドへのポインタを保存しておき、元のオブジェクトを解放しても * ポインタ参照が残らないようにする。 */ dirobj = NIS_RES_OBJECT (pres); saved_name = dirobj->DI_data.do_name; saved_owner = dirobj--->zo_owner; saved_grp = dirobj---->zo_group; /* * 新たなネーム、グループ、所有者、および、foo ドメインへの新たな * アクセス権を設定する。 */ sprintf (dir_name, "%s.%s", "foo", local_domain); sprintf (grp_name, "%s.%s", "admins", dir_name); dirobj->DI_data.do_name = dir_name; dirobj->zo_group = grp_name; dirobj->zo_owner = local_princip; /* * NIS+ のアクセス権は u_long 型に保存される。最上位バイトは使用不可で、 * 次の 8 バイトは所有者に、続いて、グループ、ワールドの順に保存される。 * この例では、ディレクトリへのアクセス権は "----rmcdrmcd----" の * パターンに従って与える。 */ dirobj->zo_access = ((NIS_READ_ACC + NIS_MODIFY_ACC + NIS_CREATE_ACC + NIS_DESTROY_ACC) << 16) | ((NIS_READ_ACC + NIS_MODIFY_ACC + NIS_CREATE_ACC + NIS_DESTROY_ACC) << 8); /* * 親ディレクトリオブジェクトが持っていたサーバ数を保存しておき、 * 後に nis_freeresult() を呼び出す前にこの値を元に戻して、 * メモリリークを避ける。 */ saved_num_servers = dirobj- >DI_data.do_servers.do_servers_len; /* このディレクトリは 1 つのサーバだけで管理する。 */ dirobj->DI_data.do_servers.do_servers_len = 1; dir_create (dir_name, dirobj); /* foo の下に groups_dir と org_dir という 2 つのディレクトリを作成する。 */ sprintf (grp_dir_name, "groups_dir.%s", dir_name); dirobj->DI_data.do_name = grp_dir_name; dir_create (grp_dir_name, dirobj); sprintf (org_dir_name, "org_dir.%s", dir_name); dirobj->DI_data.do_name = org_dir_name; dir_create (org_dir_name, dirobj); grp_create (grp_name); printf ("¥nAdding principal %s to group %s ... ¥n", local_princip, grp_name); err = nis_addmember (local_princip, grp_name); if (err != NIS_SUCCESS) { nis_perror (err, "unable to add local principal to group."); exit (1); } sprintf (table_name, "test_table.org_dir.%s", dir_name); tbl_create (dirobj, table_name); /* * 作成したばかりのテーブルに、NIS+ エントリオブジェクトを作成する。 */ stuff_table (table_name); /* 作成したオブジェクトを表示する。 */ list_objs(dir_name, table_name, grp_name); /* 作成したものすべてのクリーンアップ。 */ cleanup (local_princip, grp_name, table_name, dir_name, dirobj); /* * オリジナルの pres 構造体から保存しておいたポインタを元に戻し、 * 関連メモリを解放してもメモリリークが起こらないようにする */ dirobj->DI_data.do_name = saved_name; dirobj->zo_group = saved_grp; dirobj->zo_owner = saved_owner; dirobj->DI_data.do_servers.do_servers_len = saved_num_servers; (void) nis_freeresult (pres); }
例 5-2 が示すルーチンは main() から呼び出され、ディレクトリオブジェクトを作成します。
void dir_create (dir_name, dirobj) nis_name dir_name; nis_object *dirobj; { nis_result *cres; nis_error err; printf ("¥n Adding Directory %s to namespace ... ¥n", dir_name); cres = nis_add (dir_name, dirobj); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "unable to add directory foo."); exit (1); } (void) nis_freeresult (cres); /* * 注: nis_mkdir を実行して、作成するディレクトリの内容を保存する * テーブルを作成する必要がある。 */ err = nis_mkdir (dir_name, dirobj->DI_data.do_servers.do_servers_val); if (err != NIS_SUCCESS) { (void) nis_remove (dir_name, 0); nis_perror (err, "unable to create table for directory object foo."); exit (1); } }
次のルーチンは main() から呼び出され、グループオブジェクトを作成します。nis_creategroup() はグループオブジェクトだけを対象としているので、グループ名には groups_dir というリテラルは必要ありません。
void grp_create (grp_name) nis_name grp_name; { nis_error err; printf ("¥n Adding %s group to namespace ... ¥n", grp_name); err = nis_creategroup (grp_name, 0); if (err != NIS_SUCCESS) { nis_perror (err, "unable to create group."); exit (1); } }
例 5-3 が示すルーチンは main() から呼び出され、テーブルオブジェクトを表 5-3 のようなレイアウトで作成します。
表 5-3 NIS+ テーブルオブジェクト
|
カラム 1 |
カラム 2 |
---|---|---|
ネーム: |
id |
name |
属性: |
検索可能、テキスト |
検索可能、テキスト |
アクセス権 |
----rmcdr---r--- |
----rmcdr---r--- |
定数 TA_SEARCHABLE を指定すると、サービスカラムを検索可能とします。TEXT カラム(デフォルト属性)だけが検索可能です。TA_CASE を指定すると、サービスは、カラムの値を検索するときに大文字小文字を区別しません。
#define TABLE_MAXCOLS 2 #define TABLE_COLSEP ':' #define TABLE_PATH 0 void tbl_create (dirobj, table_name) nis_object *dirobj; /* フィールドによっては必要 */ nis_name table_name; { nis_result *cres; static nis_object tblobj; static table_col tbl_cols[TABLE_MAXCOLS] = { {"Id", TA_SEARCHABLE | TA_CASE, DEFAULT_RIGHTS}, {"Name", TA_SEARCHABLE | TA_CASE, DEFAULT_RIGHTS} }; tblobj.zo_owner = dirobj->zo_owner; tblobj.zo_group = dirobj->zo_group; tblobj.zo_access = DEFAULT_RIGHTS; /* nis.h で定義されたマクロ */ tblobj.zo_data.zo_type = TABLE_OBJ; /* nis.h で定義された列挙型 */ tblobj.TA_data.ta_type = TABLE_TYPE; tblobj.TA_data.ta_maxcol = TABLE_MAXCOLS; tblobj.TA_data.ta_sep = TABLE_COLSEP; tblobj.TA_data.ta_path = TABLE_PATH; tblobj.TA_data.ta_cols.ta_cols_len = tblobj.TA_data.ta_maxcol; /* 常にこの指定 ! */ tblobj.TA_data.ta_cols.ta_cols_val = tbl_cols; /* * 修飾子付きのテーブル名、すなわち、org_dir というリテラルが埋め込まれた * テーブル名を使用する。nis_add はあらゆるタイプの NIS+ オブジェクトを * 操作するからであり、テーブルが作成済みならばそのフルパス名も必要である。 */ printf ("¥n Creating table %s ... ¥n", table_name); cres = nis_add (table_name, &tblobj); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "unable to add table."); exit (1); } (void) nis_freeresult (cres); }
例 5-5 が示すルーチンは main() から呼び出され、テーブルオブジェクトにエントリオブジェクトを追加します。2 つのエントリがテーブルオブジェクトに追加されます。どちらのエントリのカラム幅も、文字列のターミネータとしての NULL 文字を含む値で設定することに注意してください。
#define MAXENTRIES 2 void stuff_table(table_name) nis_name table_name; { int i; nis_object entdata; nis_result *cres; static entry_col ent_col_data[MAXENTRIES][TABLE_MAXCOLS] = { {0, 2, "1", 0, 5, "John"}, {0, 2, "2", 0, 5, "Mary"} }; printf ("¥n Adding entries to table ... ¥n"); /* * テーブルに追加するエントリは、テーブルと同じ所有者、グループ所有者、 * アクセス権を持たなければならないので、はじめにテーブルオブジェクトを * 調べる。 */ cres = nis_lookup (table_name, 0); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "Unable to lookup table"); exit(1); } entdata.zo_owner = NIS_RES_OBJECT (cres)->zo_owner; entdata.zo_group = NIS_RES_OBJECT (cres)->zo_group; entdata.zo_access = NIS_RES_OBJECT (cres)->zo_access; /* cres を解放して再利用できるようにする。 */ (void) nis_freeresult (cres); entdata.zo_data.zo_type = ENTRY_OBJ; /* nis.h で定義された列挙型 */ entdata.EN_data.en_type = TABLE_TYPE; entdata.EN_data.en_cols.en_cols_len = TABLE_MAXCOLS; for (i = 0; i < MAXENTRIES; ++i) { entdata.EN_data.en_cols.en_cols_val = &ent_col_data[i][0]; cres = nis_add_entry (table_name, &entdata, 0); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "unable to add entry."); exit (1); } (void) nis_freeresult (cres); } }
例 5-6 が示すルーチンは nis_list() の呼び出しで使用する印刷関数です。list_objs() が nis_list() を呼び出すときに、引数の 1 つとして print_info() へのポインタを渡します。サービスが print_info() を呼び出すたびに、エントリオブジェクトの内容が印刷されます。戻り値は、ライブラリに対して、テーブルの次のエントリを呼び出すように指示します。
int print_info (name, entry, cbdata) nis_name name; /* 未使用 */ nis_object *entry; /* NIS+ エントリオブジェクト */ void *cbdata; /* 未使用 */ { static u_int firsttime = 1; entry_col *tmp; /* ソースを読みやすくするためだけに使用 */ u_int i, terminal; if (firsttime) { printf ("¥tId.¥t¥t¥tName¥n"); printf ("¥t---¥t¥t¥t----¥n"); firsttime = 0; } for (i = 0; i < entry->EN_data.en_cols.en_cols_len; ++i) { tmp = &entry->EN_data.en_cols.en_cols_val[i]; terminal = tmp->ec_value.ec_value_len; tmp->ec_value.ec_value_val[terminal] = '¥0'; } /* * ENTRY_VAL は、指定したエントリの特定カラムの値を返すマクロ */ printf("¥t%s¥t¥t¥t%s¥n", ENTRY_VAL (entry, 0), ENTRY_VAL (entry, 1)); return (0); /* さらに呼出しを行う */ }
例 5-7 が示すルーチンは main() から呼び出され、グループ、テーブル、ディレクトリオブジェクトの内容をリストします。次のルーチンで、コールバックの使用方法を示します。グループのメンバを取り出して表示します。グループのメンバリストは、オブジェクトの中に保存されていないので、nis_list() ではなく、nis_lookup() で調べます。nis_lookup() は、グループだけでなくあらゆるタイプの NIS+ オブジェクトを扱うため、グループ名は groups_dir を付けた形式で指定しなければなりません。
void list_objs(dir_name, table_name, grp_name) nis_name dir_name, table_name, grp_name; { group_obj *tmp; /* ソースを読みやすくするためだけに使用 */ u_int i; char grp_obj_name [NIS_MAXNAMELEN]; nis_result *cres; char index_name [BUFFER_SIZE]; sprintf (grp_obj_name, "%s.groups_dir.%s", nis_leaf_of (grp_name), nis_domain_of (grp_name)); printf ("¥nGroup %s membership is: ¥n", grp_name); cres = nis_lookup(grp_obj_name, 0); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "Unable to lookup group object."); exit(1); } tmp = &(NIS_RES_OBJECT(cres)->GR_data); for (i = 0; i < tmp->gr_members.gr_members_len; ++i) printf ("¥t %s¥n", tmp->gr_members.gr_members_val[i]); (void) nis_freeresult (cres); /* * ドメイン foo の内容を、コールバックを使用しないで表示する。 */ printf ("¥nContents of Directory %s are: ¥n", dir_name); cres = nis_list (dir_name, 0, 0, 0); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status,"Unable to list Contents of Directory foo."); exit(1); } for (i = 0; i < NIS_RES_NUMOBJ(cres); ++i) printf("¥t%s¥n", NIS_RES_OBJECT(cres)[i].zo_name); (void) nis_freeresult (cres); /* * 作成したテーブルの内容を、nis_list()でコールバックを使用してリスト * する。 */ printf ("¥n Contents of Table %s are: ¥n", table_name); cres = nis_list (table_name, 0, print_info, 0); if(cres->status != NIS_CBRESULTS && cres->status != NIS_NOTFOUND){ nis_perror (cres->status, "Listing entries using callback failed"); exit(1); } (void) nis_freeresult (cres); /* * 作成したテーブルの 1 エントリだけをリストする。エントリの取り出しには、 * インデックスの付いた名前を使用する。 */ printf("¥n Entry corresponding to id 1 is:¥n"); /* * 通常、カラム名はテーブルオブジェクトから抽出できるので、 * 始めにそれを取り出す。 */ sprintf(index_name, "[Id=1],%s", table_name); cres = nis_list (index_name, 0, print_info, 0); if(cres->status != NIS_CBRESULTS && cres->status != NIS_NOTFOUND){ nis_perror (cres->status, "Listing entry using indexed names and callback failed"); exit(1); } (void) nis_freeresult (cres); }
例 5-8 のルーチンは cleanup() から呼び出され、ネーム空間からディレクトリオブジェクトを削除します。また、このディレクトリを管理しているサーバにも、ネーム空間から削除したことを通知します。ポインタ cres が指している戻り値の構造体が入ったメモリは、戻り値が使用済みになってから解放しなければならないことに注意してください。
void dir_remove(dir_name, srv_list, numservers) nis_name dir_name; nis_server *srv_list; u_int numservers; { nis_result *cres; nis_error err; u_int i; printf ("¥nRemoving %s directory object from namespace ... ¥n",dir_name); cres = nis_remove (dir_name, 0); if (cres->status != NIS_SUCCESS) { nis_perror (cres->status, "unable to remove directory"); exit (1); } (void) nis_freeresult (cres); for (i = 0; i < numservers; ++i) { err = nis_rmdir (dir_name, &srv_list[i]); if (err != NIS_SUCCESS) { nis_perror (err, "unable to remove server from directory"); exit (1); } } }
例 5-9 のルーチンは main() から呼び出され、このサンプルプログラムで作成したオブジェクトをすべて削除します。nis_remove_entry() を呼び出すときのフラグ REM_MULTIPLE の使用法に注意してください。テーブルを削除するときは、その前にテーブル内の全エントリを削除しておく必要があります。
void cleanup(local_princip, grp_name, table_name, dir_name, dirobj) nis_name local_princip, grp_name, table_name, dir_name; nis_object *dirobj; { char grp_dir_name [NIS_MAXNAMELEN]; char org_dir_name [NIS_MAXNAMELEN]; nis_error err; nis_result *cres; sprintf(grp_dir_name, "%s.%s", "groups_dir", dir_name); sprintf(org_dir_name, "%s.%s", "org_dir", dir_name); printf("¥n¥n¥nStarting to Clean up ... ¥n"); printf("¥n¥nRemoving principal %s from group %s ¥n", local_princip, grp_name); err = nis_removemember (local_princip, grp_name); if (err != NIS_SUCCESS) { nis_perror (err, "unable to delete local principal from group."); exit (1); } /* * admins グループを削除する。グループ削除の API は、グループだけを * 対象にしているので、グループ名に group_dir は不要。 * グループ名には、自動的にリテラル group_dir が埋め込まれる。 */ printf("¥nRemoving %s group from namespace ... ¥n", grp_name); err = nis_destroygroup (grp_name); if (err != NIS_SUCCESS) { nis_perror (err, "unable to delete group."); exit (1); } printf("¥n Deleting all entries from table %s ... ¥n", table_name); cres = nis_remove_entry(table_name, 0, REM_MULTIPLE); switch (cres->status) { case NIS_SUCCESS: case NIS_NOTFOUND: break; default: nis_perror(cres->status, "Could not delete entries from table"); exit(1); } (void) nis_freeresult (cres); printf("¥n Deleting table %s itself ... ¥n", table_name); cres = nis_remove(table_name, 0); if (cres->status != NIS_SUCCESS) { nis_perror(cres->status, "Could not delete table."); exit(1); } (void) nis_freeresult (cres); /* groups_dir、org_dir、foo の各ディレクトリオブジェクトを削除する。*/ dir_remove (grp_dir_name, dirobj->DI_data.do_servers.do_servers_val, dirobj->DI_data.do_servers.do_servers_len); dir_remove (org_dir_name, dirobj->DI_data.do_servers.do_servers_val, dirobj->DI_data.do_servers.do_servers_len); dir_remove (dir_name, dirobj->DI_data.do_servers.do_servers_val, dirobj->DI_data.do_servers.do_servers_len); }
このプログラムを実行すると、画面は 図 5-3 のように表示されます。
myhost% domainname sun.com myhost% ./sample Adding Directory foo.sun.com. to namespace ... Adding Directory groups_dir.foo.sun.com. to namespace ... Adding Directory org_dir.foo.sun.com. to namespace ... Adding admins.foo.sun.com. group to namespace ... Adding principal myhost.sun.com. to group admins.foo.sun.com. ... Creating table test_table.org_dir.foo.sun.com. ... Adding entries to table ... Group admins.foo.sun.com. membership is: myhost.sun.com. Contents of Directory foo.sun.com. are: groups_dir org_dir Contents of Table test_table.org_dir.foo.sun.com. are: Id. Name --- ---- 1 John 2 Mary Entry corresponding to id 1 is: 1 John Starting to Clean up ... Removing principal myhost.sun.com. from group admins.foo.sun.com. Removing admins.foo.sun.com. group from namespace ... Deleting all entries from table test_table.org_dir.foo.sun.com. ... Deleting table test_table.org_dir.foo.sun.com. itself ... Removing groups_dir.foo.sun.com. directory object from namespace ... Removing org_dir.foo.sun.com. directory object from namespace ... Removing foo.sun.com. directory object from namespace ... myhost%
デバッグのために、次の一連のコマンドを入力して、これと同じ操作を実行することもできます。最初のコマンド
% niscat -o domainname.
を実行すると、マスタサーバ名が表示されます。以下に示すコマンドを入力するときは、master のところを、表示されたマスタサーバ名に置き換えて入力します。
% nismkdir -m master foo.domainname.
# 指定されたマスタでサブディレクトリ org_dir.foo を作成します。 % nismkdir -m master org_dir.foo.domainname. # 指定されたマスタでサブディレクトリ groups_dir.foo を作成します。 % nismkdir -m master groups_dir.foo.domainname. # グループ admins を作成します。 % nisgrpadm -c admins.foo.domainname.
# 自分自身をこのグループのメンバとして追加します。 % nisgrpadm -a admins.foo.domainname. `nisdefaults -p`
# Id と Name の 2 つのカラムで test_table を作成します。 % nistbladm -c test_data id=SI Name=SI ¥ test_table.org_dir.foo.domainname.
# そのテーブルにエントリを 1 つ追加します。 % nistbladm -a id=1 Name=John test_table.org_dir.foo.domainname. # そのテーブルに別のエントリを追加します。 % nistbladm -a id=2 Name=Mary test_table.org_dir.foo.domainname.
# グループ admins のメンバをリストする。 % nisgrpadm -l admins.foo.domainname. # ディレクトリ foo の内容をリストする。 % nisls foo.domainname. # test_table の内容とヘッダをリストする。 % niscat -h test_table.org_dir.foo.domainname.
# test_table から id が 1 のエントリを取り出す。 % nismatch id=1 test_table.org_dir.foo.domainname.
# 作成したものをすべて削除する。 # 初めに、グループ admins から自分自身を削除する。 % nisgrpadm -r admins.foo.domainname. `nisdefaults -p` # グループ admins を削除する。 % nisgrpadm -d admins.foo.domainname. # test_table からすべてのエントリを削除する。 % nistbladm -r "[],test_table.org_dir.foo.domainname." # test_table を削除する。 % nistbladm -d test_table.org_dir.foo.domainname. # 作成した 3 つのディレクトリをすべて削除する。 % nisrmdir groups_dir.foo.domainname. % nisrmdir org_dir.foo.domainname. % nisrmdir foo.domainname.