ONC+ 開発ガイド

第 5 章 NIS+ プログラミングガイド

この章は、NIS+ アプリケーションのプログラミングインタフェースの基礎について説明し、詳しいサンプルプログラムを示します。NIS+ API は、Solaris を使用するネットワーク用のアプリケーションを構築するプログラマを対象としています。NIS+ API には、アプリケーションをサポートするための基本的な機能が用意されています。

NIS+ ネットワークネームサービスが対象とするクライアント/サーバーネットワークは、数個のサーバーが 10 個のクライアントをサポートする程度の単純なローカルエリアネットワークから、全世界のさまざまなサイトに位置する 20 〜 100 個の専用サーバーが 10,000 個ものマルチベンダークライアントをサポートし、さまざまな公衆ネットワークで連結された大規模なものまであります。

NIS+ の概要

ドメイン

NIS+ は、階層ドメインをサポートします。図 5-1 に、簡単な例を示します。

図 5-1 NIS+ のドメイン

Graphic

NIS+ の各ドメインは、組織の各部分のワークステーション、ユーザー、ネットワークサービスを記述するデータの集合です。NIS+ の各ドメインは、他のドメインとは独立に管理できます。この機能のおかげで、NIS+ は、小さなものから大きなものまでさまざまな規模のネットワークで使用できます。

サーバー

各ドメインはいくつかのサーバーでサポートされています。このうち中心となるサーバーをマスターサーバー、バックアップサーバーを複製サーバーといいます。マスターサーバーと複製サーバーの両方で NIS+ プログラムを実行します。オリジナルテーブルはマスターサーバーが保管し、複製サーバーはそのコピーを保存します。

NIS+ では、段階的に複製を更新します。最初にマスターサーバーを変更すると、次にその変更が自動的に複製サーバーに伝えられ、名前空間全体で有効となります。

テーブル

NIS+ では、情報がマップやゾーンファイルではなくテーブルに保存されます。NIS+ には 図 5-2 で示されている 16 種類の定義済みテーブル (システムテーブル) があります。

図 5-2 NIS+ のテーブル

Graphic

各テーブルにはそれぞれ違う種類の情報が保存されます。たとえば、Hosts テーブルには、ホスト名とインターネットアドレスのペアが保存され、Password テーブルにはネットワークユーザーに関する情報が保存されます。

NIS+ テーブルは、次の 2 つの点で NIS マップから大きく改善されています。1 つは、NIS+ テーブルでは第 1 カラム (「キー」ともいう) だけでなく任意のカラムにアクセスできる点です。このため、NIS の hosts.byname マップや hosts.byaddr マップのような重複マップが不要になりました。もう 1 つは、NIS+ テーブルの情報には、テーブルレベル、エントリレベル、カラムレベルの 3 つのレベルでアクセスできる点です。

NIS+ のセキュリティ

NIS+ のセキュリティモデルには、許可と認証の 2 つの機能があります。まず、名前空間上の各オブジェクトごとに、どのような主体にどの種類の操作を許すかを指定します。これを許可といいます。名前空間へのアクセスが要求されると、NIS+ はその要求を出した主体を確認します。NIS+ は、要求の発信元を認識すると、その特定の主体に対する特定の操作をオブジェクトが認可しているか確かめます。NIS+ はこのように、認証情報とオブジェクトごとの許可情報に基づいて、アクセス要求を許すか拒否するかを決定します。

ネームサービススイッチ

NIS+ はネームサービススイッチとともに使用できます。ネームサービススイッチ (単に「スイッチ」ともいう) を使用すると、Solaris 2.x を使用するワークステーションで、複数のネットワーク情報サービスから情報を得ることができます。特に、ローカルファイル、/etc ファイル、NIS マップ、DNS ゾーンファイル、NIS+ テーブルから情報が得られます。ネームサービススイッチを使用すると、単に情報源を選択するだけでなく、ワークステーションで情報の種類別に異なる情報源を使用できます。ネームサービスの設定は、/etc/nsswitch.conf ファイルで行います。

NIS+ の管理コマンド

NIS+ では、名前空間を管理するのに必要なコマンドがすべて提供されています。

表 5-1 にその要約を示します。

表 5-1 NIS+ の名前空間管理コマンド

コマンド 

説明 

nischgrp

NIS+ オブジェクトのグループ所有者を変更する 

nischmod

オブジェクトのアクセス権を変更する 

nischown

NIS+ オブジェクトの所有者を変更する 

nisgrpadm

NIS+ グループの作成と破棄、グループメンバーリストの表示を行う。また、グループにメンバーを追加または削除したり、グループメンバーかどうかのテストを行う 

niscat

NIS+ テーブルの内容を表示する 

nisgrep

NIS+ テーブルのエントリを検索する 

nisls

NIS+ ディレクトリの内容をリストする 

nismatch

NIS+ テーブルのエントリを検索する 

nisaddent

/etc ファイル、または、NIS マップの情報を NIS+ テーブルに追加する

nistbladm

NIS+ テーブルの作成や削除を行う。また、NIS+ テーブルのエントリを追加、変更、削除する 

nisaddcred

NIS+ 主体の資格を作成し、それを Cred テーブルに保存する

nispasswd

NIS+ の Passwd テーブルのパスワード情報を変更する

nisupdkeys

NIS+ オブジェクトに保存されている公開鍵を更新する 

nisinit

NIS+ のクライアントまたはサーバーを初期化する 

nismkdir

NIS+ ディレクトリを作成し、そのマスタサーバーと複製サーバーを指定する 

nisrmdir

名前空間から、NIS+ ディレクトリとその複製を削除する 

nissetup

org_dirgroups_dir の 2 つのディレクトリを作成し、NIS+ ドメインに対する全種類の NIS+ テーブル (空のテーブル) を作成する。

rpc.nisd

NIS+ のサーバープロセス 

nis_cachemgr

NIS+ クライアントの NIS+ キャッシュマネージャを起動する 

nischttl

NIS+ オブジェクトの有効時間を変更する 

nisdefaults

NIS+ オブジェクトのデフォルト値 (ドメイン名、グループ名、ワークステーション名、NIS+ 主体名、アクセス権、ディレクトリの検索パス、有効時間) を表示する 

nisln

2 つの NIS+ オブジェクト間のシンボリックリンクを作成する 

nisrm

ディレクトリ以外の NIS+ オブジェクトを名前空間から削除する 

nisshowcache

NIS+ キャッシュマネージャが管理している NIS+ 共有キャッシュの内容を表示する

NIS+ の API

NIS+ の アプリケーションプログラマーズインタフェース (API) は関数の集合です。アプリケーションでは、これらの関数を呼び出して NIS+ オブジェクトにアクセスしたり変更したりできます。NIS+ の API には 54 個の関数があり、それらは次の 9 つのグループに分類されます。

表 5-2 では、これらの関数をグループごとにまとめて簡単に説明します。グループ名は、NIS+ のマニュアルページのグループ名と同じです。

表 5-2 NIS+ の API 関数

関数 

説明 

nis_names()

オブジェクトの検索と操作 

nis_lookup()

NIS+ オブジェクトのコピーを返す。リンクをたどることができる。エントリオブジェクトの検索はできないが、リンクがエントリオブジェクトを指している場合は、それを返すことができる。 

nis_add()

NIS+ オブジェクトを名前空間に追加する 

nis_remove()

NIS+ オブジェクトを名前空間から削除する 

nis_modify()

名前空間の NIS+ オブジェクトを変更する 

nis_tables()

テーブルの検索と更新を行う 

nis_list()

NIS+ 名前空間内のテーブルを検索して、検索条件に一致するエントリオブジェクトを返す。テーブル間のリンクと検索パスをたどることができる 

nis_add_entry()

NIS+ テーブルにエントリオブジェクトを追加する。既存オブジェクトがあれば操作を中止するか上書きするかを指定できる。操作が正常終了した場合は、追加したオブジェクトのコピーが返される 

nis_freeresult()

nis_result 構造体に割り当てられたメモリーをすべて解放する

nis_remove_entry()

NIS+ テーブルからエントリオブジェクトを削除する。削除するオブジェクトは、検索条件で指定するか、キャッシュされたオブジェクトコピーへのポインタで指定できる。検索条件で指定する場合は、その条件に一致するオブジェクトをすべて削除できる。したがって、検索条件を適切に指定すれば、テーブル内の全エントリを削除することもできる。操作が正常終了した場合は、削除したオブジェクトのコピーが返される 

nis_modify_entry()

NIS+ テーブルのエントリオブジェクトを変更する。変更するオブジェクトは、検索条件で指定するか、キャッシュされたオブジェクトコピーへのポインタで指定する 

nis_first_entry()

NIS+ テーブルの最初のエントリオブジェクトのコピーを返す 

nis_next_entry()

NIS+ テーブルの「次」のエントリオブジェクトのコピーを返す。この関数への呼び出しと呼び出しの間に、テーブルの更新やエントリの追加、削除、変更が行われる可能性があるので、返されたエントリの順序が実際のテーブル内のエントリ順序と一致しない場合がある 

nis_local_names()

現在のプロセスのデフォルト名を取り出す 

nis_local_directory()

ワークステーションの NIS+ ドメイン名を返す 

nis_local_host()

完全指定のワークステーション名を返す。完全指定のワークステーション名は、host-namedomain-name という形式になる

nis_local_group()

現在の NIS+ グループ名を返す。現在の NIS+ グループは、環境変数 NIS_GROUP で指定される 

nis_local_principal()

NIS+ 主体名 (その主体の UID は呼び出し側プロセスに結合) を返す 

nis_getnames()

特定の名前に対する可能な展開形のリストを返す 

nis_freenames()

nis_getnames()が生成したリストが使用するメモリーを解放する

nis_groups()

グループ操作と許可 

nis_ismember()

ある主体がグループのメンバーかどうか調べる 

nis_addmember()

グループにメンバーを追加する。メンバーは主体、グループ、ドメインのどれか 

nis_removemember()

グループからメンバーを削除する 

nis_creategroup()

グループオブジェクトを作成する 

nis_destroygroup()

グループオブジェクトを削除する 

nis_verifygroup()

グループオブジェクトが存在しているかどうか調べる 

nis_print_group_entry()

グループオブジェクトのメンバーになっている主体を表示する 

nis_server()

NIS+ アプリケーションのための種々のサービス 

nis_mkdir()

特定ホストの特定ディレクトリに対するサービスをサポートするためのデータベースを作成する 

nis_rmdir()

ホストからディレクトリを削除する 

nis_servstate()

NIS+ サーバーの状態変数の設定と読み込みを行い、内部キャッシュをフラッシュする 

nis_stats()

サーバーのパフォーマンスに関する統計情報を取り出す 

nis_getservlist()

特定のドメインをサポートするサーバーのリストを返す 

nis_freeservlist()

nis_getservlist() が返したサーバーリストが使用するメモリーを解放する

nis_freetags()

nis_servstate()nis_stats() の戻り値が使用するメモリーを解放する

nis_db()

NIS+ サーバーとデータベースの間のインタフェース。NIS+ クライアントでは使用不可 

db_first_entry()

指定したテーブルの最初のエントリのコピーを返す 

db_next_entry()

指定したエントリの次のエントリのコピーを返す 

db_reset_next_entry()

最初または次のエントリシーケンスを終了する 

db_list_entries()

指定した属性に一致するエントリのコピーを返す 

db_remove_entry()

指定した属性に一致するエントリをすべて削除する 

db_add_entry()

指定した属性に一致するテーブルエントリを、指定したオブジェクトのコピーで置き換える。または、指定したオブジェクトをテーブルに追加する 

db_checkpoint()

テーブルの内容を再編成して、テーブルのアクセス効率を改善する 

db_standby()

データベースマネージャに資源の解放を勧める 

nis_error()

NIS+ のステータス値に対応するメッセージ文字列を取り出す関数。 

nis_sperrno()

メッセージ文字列定数へのポインタを返す 

nis_perror()

メッセージ文字列定数を標準出力に表示する 

nis_lerror()

メッセージ文字列定数を syslog に送信する

nis_sperror()

strdup() を使用するかまたはコピーするために静的領域に割り当てられた文字列へのポインタを返す

nis_admin()

トランザクションのログを取る関数。サーバーで使用 

nis_ping()

ディレクトリのマスターサーバーが、ディレクトリのタイムスタンプを作成するのに使用する。この関数を実行すると、複製も強制的に更新される 

nis_checkpoint()

ログデータを強制的にディスク上のテーブルに保存する 

nis_subr()

NIS+ の名前とオブジェクトの操作のための補助関数 

nis_leaf_of()

NIS+ の名前の最初のラベルを返す。返された名前には、末尾のピリオドは付いていない 

nis_name_of()

名前からドメイン関連のラベルをすべて削除して、固有のオブジェクト部分だけを返す。この関数に渡された名前は、ローカルドメイン、または、その子ドメインでなければならない。それ以外の場合は NULL が返される 

nis_domain_of()

オブジェクトが入っているドメイン名を返す。返されたドメイン名はピリオドで終わっている 

nis_dir_cmp()

2 つの NIS+ 名を比較する。大文字小文字の違いは無視して比較し、名前が同じか、派生関係にあるか、無関係かを返す 

nis_clone_object()

NIS+ オブジェクトの完全な複製を作成する

nis_destroy_object()

nis_clone_object() で作成したオブジェクトを破棄する

nis_print_object()

NIS+ オブジェクト構造体の内容を標準出力に表示する

NIS+ サンプルプログラム

サンプルプログラムでは次のタスクを実行します。

サンプルプログラムは典型的なアプリケーションとはいえません。通常は、ディレクトリとテーブルの作成と削除はコマンド行インタフェースで行い、アプリケーションでは NIS+ エントリオブジェクトの操作だけを行います。

サポートされないマクロの使用

サンプルプログラムでは <rpcsvc/nis.h> ファイルで定義されているマクロを使用しています。ここで定義されているマクロは、サポートが保証されている正式な API ではなく、将来変更されたりなくなったりする可能性があります。ここではサンプルプログラムで使用方法を説明するために使用していますが、実際のプログラムで使用するときはユーザー自身の責任で使用してください。サンプルプログラムで使用しているマクロを次に示します。

サンプルプログラムで使用する関数

サンプルプログラムでは、次の 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+ ディレクトリ名です。このプログラムを実行する主体は、そのディレクトリ内でのオブジェクト作成許可を持っている必要があります。


例 5-1 NIS+ のプログラム例 example.c

#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() から呼び出され、ディレクトリオブジェクトを作成します。


例 5-2 ディレクトリオブジェクトを作成する NIS+ ルーチン

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 というリテラルは必要ありません。


例 5-3 グループオブジェクトを作成する NIS+ ルーチン

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 を指定すると、サービスは、カラムの値を検索するときに大文字小文字を区別しません。


例 5-4 テーブルオブジェクトを作成する NIS+ ルーチン

#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 文字を含む値で設定することに注意してください。


例 5-5 テーブルにオブジェクトを追加する NIS+ ルーチン

#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() を呼び出すたびに、エントリオブジェクトの内容が印刷されます。戻り値は、ライブラリに対して、テーブルの次のエントリを呼び出すように指示します。


例 5-6 nis_list() を呼び出す NIS+ ルーチン

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 を付けた形式で指定しなければなりません。


例 5-7 オブジェクトをリストする NIS+ ルーチン

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 が指している戻り値の構造体が入ったメモリーは、戻り値が使用済みになってから解放しなければならないことに注意してください。


例 5-8 ディレクトリオブジェクトを削除する NIS+ ルーチン

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 の使用法に注意してください。テーブルを削除するときは、その前にテーブル内の全エントリを削除しておく必要があります。


例 5-9 オブジェクトをすべて削除する NIS+ ルーチン

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-10 NIS+ プログラムの実行

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.