Trusted Solaris 開発ガイド

第 13 章 トラステッドセキュリティ情報交換ライブラリ

トラステッドセキュリティ情報交換 (TSIX) ライブラリには、クライアントアプリケーションとサーバーアプリケーション内からネットワークメッセージのセキュリティ属性情報を管理するインタフェースが用意されています。TSIX ライブラリは、Berkeley ソケットに基づいており、トランスポートレイヤーインタフェース (TLI) をサポートします。

セキュリティ属性は、メッセージとは別のデータパケットヘッダーに格納されます。これは、セキュリティ属性が別々に読み取れるようにするためです。たとえば、アプリケーションは、TSIX ライブラリを使用してセキュリティ属性を取得でき、続いて機密ラベル属性を検査して、プロセスがパケット内のデータを読み取るために特権を必要とするかどうかを判断できます。

セキュリティ属性

デフォルトでは、Trusted Solaris 7 システムで生成されるメッセージは、送信プロセスから次のセキュリティ属性を取得します。TSIX ライブラリを使用すると、メッセージが送信される前に、ユーザー ID、グループ ID、機密ラベル、情報ラベル、プロセス認可上限、特権属性を変更できます。

Solaris 7 

Trusted Solaris 7 

実効ユーザー ID 

機密ラベル 

実効グループ ID 

情報ラベル 

プロセス ID 

プロセス認可上限 

ネットワークセッション ID 

有効な特権セット 

追加グループ ID 

プロセスの属性フラグ 

監査 ID 

 

監査情報 (プロセスの事前選択マスク、監査端末 ID、監査セッション ID) 

 

TSIX ライブラリを使用すると、着信メッセージのセキュリティ属性も取得できます。分散型ネットワークでは、異なるトラステッドネットワーキングプロトコルを実行する複数のホストの種類を任意に組み合わせることができるため、すべてのプロトコルがすべてのセキュリティ属性をサポートするわけではありません。Trusted Solaris 7 以外のホストの種類との間で送受信されるメッセージには、上記のセキュリティ属性がほとんどありません。

たとえば、監査 ID、監査情報、追加グループ ID の属性は、TSIX または MSIX プロトコルを使用しているホストとの間でしか送受信ができません。パケットの送信元が Solaris 7 ホストの場合は、パケットが Trusted Solaris 7 ホストに届いた時点で、Solaris 7 のセキュリティ属性は存在しません。


注 -

TSIX ライブラリは、Trusted Solaris 7 用に作成されているどのようなアプリケーションにでも使用できます。TSIX ライブラリを使用するには、TSIX プロトコルは必要ありません。


種類の異なるホストから Trusted Solaris 7 ホストに届くメッセージには、ネットワークデータベースファイルの設定に基づいて、デフォルトのセキュリティ属性が割り当てられます。TSIX ライブラリコールによって着信メッセージから取得されるセキュリティ属性は、それらがメッセージとともに届かなかった場合、ネットワークデータベースファイルから取得されます。ホストの種類とそれらがサポートするセキュリティ属性、およびネットワークデータベースファイルのデフォルトの詳細は、Trusted Solaris 管理者用マニュアルセットを参照してください。

ネットワーク上で送信されるデータの機密ラベルは、送信元、送信先、および転送先ワークステーションの認可範囲でなければなりません。この制限を無効にする特権はありません。

特権の必要な処理

着信メッセージから取得されるセキュリティ属性の読み取りに、特権は必要ありません。以下の節では、発信メッセージに使用される特権について説明します。

情報ラベルの浮上

メッセージの情報ラベルは、データを読み取るプロセスの有効セットに net_nofloat 特権がないかぎり、読み取りプロセスの情報ラベルと結合されて浮上します。

同じ機密ラベルで応答する

サーバープロセスは、その認可上限より優位でないあらゆる機密ラベルで、マルチレベルポート上のメッセージを受信できます。しかし、サーバー応答は、サーバープロセスの有効セットに net_reply_equal 特権がないかぎり、サーバープロセスの機密ラベルで行われます。net_reply_equal 特権がある場合は、応答は最後に受信したメッセージの機密ラベルで送信されます。シングルレベルポートとマルチレベルポートの詳細は、第 11 章「プロセス間通信」を参照してください。


注 -

受信プロセスが要求プロセスとは異なる機密ラベルまたは情報ラベルで応答する必要がある場合、net_reply_equal 特権を無効にしてください。 net_reply_equal を無効にすべき状況の例として、「TCP/IP サーバー」を参照してください。


機密ラベルの変更

シングルレベルのクライアントに応答するには、その子プロセスの機密ラベルを要求クライアントの機密ラベルと同等になるように変更するため、サーバープロセスの有効セットに proc_set_sl 特権が必要です。

セキュリティ属性情報の変更

発信メッセージまたは発信メッセージの通信終端のユーザー ID、グループ ID、機密ラベル、情報ラベル、プロセス認可上限、特権セキュリティ属性を変更するには、プロセスの有効セットに適切なネットワーク特権が必要です。

機密ラベル

送信プロセスは、有効セットに net_downgrade_sl 特権があれば、メッセージまたは通信終端の機密ラベルを、オブジェクトの既存の機密ラベルよりも優位でない新しい機密ラベルに設定できます。送信プロセスは、有効セットに net_upgrade_sl 特権があれば、メッセージまたは通信終端の機密ラベルを、オブジェクトの既存の機密ラベルより優位な新しい機密ラベルに設定できます。

情報ラベル

送信プロセスは、有効セットに net_downgrade_il 特権があれば、通信終端の情報ラベルを、オブジェクトの既存の情報ラベルよりも優位でない新しい情報ラベルに設定できます。

送信プロセスは、有効セットに net_upgrade_il 特権があれば、通信終端の情報ラベルを、オブジェクトの既存の情報ラベルより優位な新しい情報ラベルに設定できます。

システムにより、機密ラベルは必ず情報ラベルよりも優位になります。この制限を無効にする特権はありません。

プロセス認可上限

メッセージとともに送信される認可上限を変更するには、送信プロセスの有効セットに net_setclr 特権が必要です。

システムにより、認可上限は必ず機密ラベルよりも優位になります。この制限を無効にする特権はありません。

ユーザー ID とグループ ID

ユーザー ID やグループ ID を変更するには、送信プロセスの有効セットに net_setid 特権が必要です。

特権

メッセージとともに特権が送信されるように指定するには、送信プロセスの有効セットに net_setpriv 特権が必要です。指定される特権は、送信プロセスの許可セット内に存在していなければなりません。

データ型、ヘッダーファイル、およびライブラリ

この章で説明しているプログラミングインタフェースを使用するには、次のヘッダーファイルが必要です。

#include <tsix/t6attrs.h>

この章の例は、次のライブラリを使用してコンパイルしています。

-lsocket -lt6 -ltsol

属性の構造

t6attr_t データ構造体は、セキュリティ属性の全セットを保持できます。

属性の列挙

t6attr_id_t 構造体は、全セキュリティ属性値のセットを示す列挙型の定数を含み (保持し) ます。t6attr_t 型の変数は、これらの定数を使用して初期化します。ほとんどの定数は、次に示すように固定バイトサイズです。しかし、T6_GROUPS は、その値の実際のサイズを示す可変サイズです。

列挙型の定数 

内容 

データ型 

バイトサイズ 

T6_SL

機密ラベル 

bslabel_t 

36 

T6_SESSION_ID

ネットワークセッション ID 

sid_t 

T6_CLEARANCE

認可上限 

bclear_t 

36 

T6_IL

情報ラベル 

bilabel_t 

68 

T6_PRIVILEGES

有効な特権 

priv_set_t 

16 

T6_AUDIT_ID

監査 ID 

au_id_t 

T6_PID

プロセス ID 

pid_t 

T6_AUDIT_INFO

その他の監査情報 

auditinfo_t 

24 

T6_UID

実効ユーザー ID 

uid_t 

T6_GID

実効グループ ID 

gid_t 

T6_GROUPS

追加グループ ID 

gid_t 

可変 

T6_PROC_ATTR

プロセスの属性フラグ 

pattr_t 

属性マスク

t6mask_t データ構造は、現在の処理対象のセキュリティ属性セットを示します。t6mask_t 型の変数を初期化するには、次に示す列挙型の値を割り当てます。

T6M_SL

機密ラベル 

T6M_SESSION_ID

ネットワークセッション ID 

T6M_CLEARANCE

認可上限 

T6M_IL

情報ラベル 

T6M_PRIVILEGES

有効な特権セット 

T6M_AUDIT_ID

監査 ID 

T6M_PID

プロセス ID 

T6M_AUDIT_INFO

端末 ID と事前選択マスク 

T6M_UID

実効ユーザー ID 

T6M_GID

実効グループ ID 

T6M_GROUPS

追加グループ ID 

T6M_NO_ATTRS

属性なし 

T6M_ALL_ATTRS

すべての属性 

プログラミングインタフェース宣言

これらのネットワークライブラリルーチンは、Trusted Solaris 7 ホストとの間で送受信されるメッセージのセキュリティ属性を処理します。

属性マスクの取得

これらのルーチンは、システムによりサポートされるセキュリティ属性の属性マスク、属性構造に割り当てられる領域の属性、属性構造内の属性を作成します。マスク変数に t6mask_t 列挙型値を割り当てる代わりに、これらのルーチンを使用できます。

t6mask_t				t6supported_attrs(void);
 t6mask_t				t6allocated_attrs(t6attr_t t6ctl);
 t6mask_t				t6present_attrs(t6attr_t t6ctl);

領域の割り当てと解放

t6alloc_blk(3N) ルーチンは、new_attrs で指定されているセキュリティ属性に割り当てられた十分な領域を使用して、セキュリティ属性構造を作成します。 t6free_blk(3N) ルーチンは、セキュリティ属性構造 t6ctl に割り当てられた領域を解放します。詳細は、t6alloc_blk(3N) のマニュアルページを参照してください。

t6attr_t			t6alloc_blk(				t6mask_t *new_attrs);
 void 			t6free_blk(				t6attr_t t6ctl);

データの送受信

t6sendto(3N) ルーチンは、メッセージとともにセキュリティ属性を送信します。t6recvfrom(3N) ルーチンは、メッセージとそのセキュリティ属性を受信します。t6new_attr(3N)有効な場合、t6recvfrom(3N) は、new_attrs 内の属性が変更されているときだけセキュリティ属性を受信します。詳細は、t6sendto(3N)t6recvfrom(3N)t6new_attr(3N) のマニュアルページを参照してください。


注 -

これらのルーチンは、ソケット固有のものです。トランスポートレイヤーインタフェース (TLI) では、t6recvfrom(3N)t6new_attr(3N) の代わりに t6last_attr(3N) を、t6sendto(3N) の代わりに t6set_endpt_default(3N) を使用してください。


int 			t6sendto(				int sock,
 							const char *msg,
 							int len,
 							int flags,
 							const struct sockaddr *to,
 							int tolen,
 							const t6attr_t *attr_ptr);

 int 			t6recvfrom(				int sock,
 							char *buf,
 							int len,
 							int flags,
 							struct sockaddr *from,
 							int *fromlen,
 							t6attr_t *attr_ptr,
 							t6mask_t *new_attrs);

 int			t6new_attr(				int sock, t6cmd_t cmd);

セキュリティ属性の取得と設定

t6get_attr(3N) ルーチンは、attr_type 内の属性をセキュリティ属性構造 t6ctl から取得します。戻り値は、「属性の列挙」で説明しているように、正しい型に変換する必要があります。

t6set_attr(3N) ルーチンは、セキュリティ属性構造 t6ctl 内の attr に指定された値を使用して、attr_type 内の属性を設定します。

詳細は、t6get_attr(3N) のマニュアルページを参照してください。

void * 			t6get_attr(				t6attr_id_t attr_type,
 							const t6attr_t t6ctl);

 int 			t6set_attr(				t6attr_id_t attr_type,
 							const void *attr,
 							t6attr_t *t6ctl);

セキュリティ属性の確認

t6peek_attr(3N) ルーチンは、受信されるデータの次のバイトの attr_ptr 内のセキュリティ属性を確認します。t6last_attr(3N) ルーチンは、受信されたデータの最後のバイトのセキュリティ属性を確認します。詳細は、t6peek_attr(3N) のマニュアルページを参照してください。

int 			t6peek_attr(				int sock,
 							t6attr_t attr_ptr,
 							t6mask_t *new_attrs);

 int		 	t6last_attr(				int sock,
 							t6attr_t attr_ptr,
 							t6mask_t *new_attrs);

1 つのセキュリティ属性のサイズの取得

t6size_attr(3N) ルーチンは、セキュリティ属性構造 t6ctlattr_type で指定されたセキュリティ属性の値のサイズをバイト単位で取得します。t6size_attr(3N) のマニュアルページを参照してください。

size_t 			t6size_attr(				t6attr_id_t attr_type,
 							const t6attr_t t6ctl);

セキュリティ属性のコピーと複製

これらのルーチンは、attr_src をコピーします。詳細は、t6copy_blk(3N)t6dup_blk(3N) のマニュアルページを参照してください。

void 			t6copy_blk(				const t6attr_t attr_src,
 							t6attr_t attr_dest);

 t6attr_t 			t6dup_blk(				const t6attr_t attr_src);

セキュリティ属性の比較

このルーチンは、1 つのセキュリティ属性を別のセキュリティ属性と比較します。詳細は、t6comp_blk(3N) のマニュアルページを参照してください。

int			t6cmp_blk(				t6attr_t t6ctl1,
 							t6attr_t t6ctl2);

セキュリティ属性のクリア

このルーチンは、maskt6ctl に基づいて指定された属性をクリアします。詳細は、t6clear_blk(3N) のマニュアルページを参照してください。

void 				t6clear_blk(							t6mask_t mask, t6attr_t t6ctl);

終端属性の取得と設定

t6set_endpt_default(3N) ルーチンは、mask で示された attr 内のセキュリティ属性値を、通信終端に設定します。t6set_endpt_mask(3N) ルーチンは、終端 mask だけを設定します。

t6get_endpt_default(3N) ルーチンは、mask で示された attr 内のセキュリティ属性値を、通信終端から取得します。t6get_endpt_mask(3N) ルーチンは、終端 mask だけを取得します。

詳細は、t6get_endpt_mask(3N) のマニュアルページを参照してください。

int			t6get_endpt_default(						int sock,
 									t6mask_t *mask,
 									t6attr_t attr);

 int 			t6set_endpt_mask(						int sock,
 									t6mask_t mask);

 int 			t6set_endpt_default(						int sock,
 									t6mask_t mask,
 									const t6attr_t attr_ptr);

 int 			t6get_endpt_mask(						int sock,
 									t6mask_t *mask);

拡張セキュリティオペレーションの有効化と無効化

このルーチンは、ほかのベンダーとの互換性のために、拡張セキュリティオペレーションを有効または無効にします。このオペレーションは、デフォルトでは有効です。無効にされる場合、通信がシステムの必須アクセス制御および任意アクセス制御のもとにあるかぎり、メッセージは送受信できます。詳細は、t6ext_attr(3N) のマニュアルページを参照してください。

int				t6ext_attr(										int fd, t6cmd_t cmd);

セキュリティ属性の取得と設定

これらの例は、送信データのセキュリティ属性を指定するためにセキュリティ属性構造とマスクをどのように設定するかを示しています。最初の例は、メッセージに新しいセキュリティ属性を設定し、2 番目の例は通信終端に新しいセキュリティ属性を設定します。

メッセージのセキュリティ属性

この例では、次の手順によって、msg とともに送信する機密ラベルと認可上限の新しい属性値を設定します。

msg を送信するプロセスは Confidential であるため、認可上限と機密ラベルを変更するために、有効セットに net_setclrnet_upgrade_sl 特権が必要です。新しい機密ラベルと認可上限は、送信プロセスから受け取った msg の機密ラベルと認可上限を無効にします。コード内のコメントは、第 3 章「特権」で説明している特権ブラケットが必要な位置を示します。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	int				retval, sock, error;
 	t6attr_t				sendattrs
 	t6mask_t				sendmask;
 	char				*msg = "Hello World!";
 	bslabel_t				senslabel;
 	bclear_t				clearance;

/* 機密ラベルとプロセスの認可上限のセキュリティ属性フィールドを */
/* 使用してマスクを初期化する */
 	sendmask = T6M_SL | T6M_CLEARANCE;

/* マスクを使用して 2 つのセキュリティ属性構造体に */
/* 必要なだけの領域を割り当てる */
 	sendattrs = t6alloc_blk(sendmask);

/* 機密ラベルと認可上限を Top Secret に初期化する */
 	stobsl("TOP SECRET", &senslabel, NEW_LABEL, &error);
 	stobclear("TOP SECRET", &clearance, NEW_LABEL, &error);

/* メッセージと一緒に送られるセキュリティ属性フィールドの属性値を */
/* 設定する */
 	retval = t6set_attr(T6_SL, &senslabel, sendattrs);
 	printf("Retval1 = %d¥n", retval);
 	retval = t6set_attr(T6_CLEARANCE, &clearance, sendattrs);
 	printf("Retval2 = %d¥n", retval);

/* ソケット通信を設定する */
/* ... */

/* 変更されたセキュリティ属性をメッセージと一緒に送る */
/* 有効セット内で net_setclr と net_upgrade_sl をオン (有効) にする */
 	retval = t6sendto(sock, msg, sizeof(msg), 0, 0, 0, &sendattrs);
/* net_setclr と net_upgrade_sl をオフ (無効) にする */
 	printf("Retval3 = %d¥n bytes", retval);
 }

printf 文によって、次のように出力されます。

Retval1 = 0

Retval2 = 0

Retval3 = 4 bytes

通信終端のセキュリティ属性

この例の最初の部分は、sendattrs とともに異なるマスク (endptmask) を使用し、sendattrs に指定された機密ラベルのセキュリティ属性だけを通信終端に設定します。これにより、t6sendto(3N) ルーチン以外の伝送方法を使用して、または機密ラベルを指定しない属性セットを持つ t6sendto(3N) ルーチンを使用して、特権を持つプロセスが通信終端にメッセージを送信する場合に、機密ラベルが通信終端から取得されます。通信終端のセキュリティ属性を設定するプロセスは Secret で動作しているため、有効セットに net_upgrade_sl 特権が必要です。コード内のコメントは、第 3 章「特権」で説明している特権ブラケットが必要な位置を示します。

次の文は、通信終端のマスクを sendmask に変更し、終端マスクを取得して getmask に入れ、認可上限を保持するために getattrs を割り当て、通信終端のデフォルトからバイナリ認可上限を取得して getattrs に格納します。

通信終端のセキュリティ属性は、送信プロセスから取得される属性を無効にします。メッセージのセキュリティ属性は、通信終端から取得される属性を無効にします。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {	t6mask_t 			sendmask, endptmask, getmask;
 	int 			fd, sock, retval;
 	t6attr_t 			sendattrs, getattrs;

 	sendmask = T6M_SL | T6M_CLEARANCE; sendattrs = t6alloc_blk(sendmask);

/* 機密ラベルを使用してマスクを初期化する */
 	endptmask = T6M_SL;

/* マスクにより示される属性を sendattrs に設定する */
/* 有効セット内で net_upgrade_sl をオン (有効) にする */
 	retval = t6set_endpt_default(sock, endptmask, sendattrs);
/* net_upgrade_sl をオフ (無効) にする */
/* 終端マスクを他のマスクに変更する */
 	retval = t6set_endpt_mask(sock, sendmask);

/* 現在の終端マスクを得る */
 	retval = t6get_endpt_mask(sock, &getmask);

/* 終端のデフォルトの認可上限を得る */
 	getmask = T6M_CLEARANCE;
 	getattrs = t6alloc_blk(getmask);
 	retval = t6get_endpt_default(fd, &getmask, getattrs);
 }

セキュリティ属性の受信と取得

この例は、メッセージをセキュリティ属性とともに受信し、セキュリティ属性情報を取得します。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	char 			buf[512];
 	int 			retval, len = sizeof(buf), sock;
 	t6mask_t 			recvmask;
 	t6attr_t 			recvattrs;
 	bslabel_t 			*senslabel;
 	bclear_t 			*clearance;

/* すべてのセキュリティ属性フィールドを使用してマスクを初期化する */
 	recvmask = T6M_ALL_ATTRS;
 	recvattrs = t6alloc_blk(recvmask);

/* ソケット通信を設定するコード */
/* ... */

/* メッセージ上のセキュリティ属性を受ける */
 	retval = t6recvfrom(sock, buf, len, 0, 0, 0, recvattrs, 0);

/* セキュリティ属性値を取り出す */
 	senslabel = (bslabel_t *)t6get_attr(T6_SL, recvattrs);
 	clearance = (bclear_t *)t6get_attr(T6_CLEARANCE, recvattrs);
 }

次の例は、属性を指定せずに newmask を作成し、値 T6_ON を使用して t6new_attr(3N) ルーチンを呼び出し、newmask を使用して t6recvfrom(3N) ルーチンを呼び出します。この組み合わせは、1 つ以上のセキュリティ属性が最後に受信したメッセージのセキュリティ属性セットと異なる場合だけ、メッセージとともにセキュリティ属性を取得するように t6recvfrom(3N) ルーチンに、指示します。t6recvfrom(3N) コールは、変更されたセキュリティ属性だけでなく、要求されるセキュリティ属性のすべてのセットを返します。セキュリティ属性に変更がある場合には newmask の値が 0 以外になるため、この値をチェックすることによりいつ新しいセキュリティ属性を検索すべきか確認できます。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	char 			buf[512];
 	int 			retval, len = sizeof(buf), sock;
 	t6mask_t 			newmask;
 	t6attr_t 			recvattrs;

/* ソケット通信を設定するコード */
/* ... */

/* 機密ラベルの変更を探すマスクを作成する */
 	newmask = T6M_NO_ATTRS;

/* 新しい属性を有効にして機密ラベルを検査する */
 	retval = t6new_attr(sock, T6_ON) > 0;
 	retval = t6recvfrom(sock, buf, len, 0, 0, 0, recvattrs, &newmask);

 	if(newmask > 0)
 		{/* プロセスのセキュリティ属性情報 */}
 }

属性の確認

読み取られるデータの次のバイトまたは読み取ったデータの最後のバイトのセキュリティ属性を取得できます。この例は、機密ラベルマスクを使用して、データの次のバイトの機密ラベルを確認し、データの最後のバイトの機密ラベルを調べます。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	char			buf[512]
 	int 			retval, sock;
 	int			len = sizeof(buf);
 	t6mask_t 			recvmask;
 	t6attr_t 			recvattrs;

 	recvmask = T6M_SL;
 	recvattrs = t6alloc_blk(recvmask);

/* ソケット通信を設定するコード */
/* ... */

/* データの次のバイトの機密ラベルを先読みする */
 	 retval = t6peek_attr(sock, recvattrs, &recvmask);

/* データの最後のバイトの機密ラベルを調べる */
 	 retval = t6last_attr(sock, recvattrs, &recvmask);
 }

属性サイズの取得

t6size_attr(3N) の戻り値は、呼び出しが成功した場合には指定された属性のバイトサイズを含み、失敗した場合は -1 を含みます。この例は、sendattrs 内の認可上限属性のサイズを取得します。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	size_t			size;
 	t6attr_t			sendattrs;

 	size = t6size_attr(T6_CLEARANCE, sendattrs);
 	printf("Clearance size = %d¥n", size);
 }

printf(1) 文によって、次のように認可上限の固定サイズが出力されます。

Clearance size = 36

属性構造のコピーと複製

TSIX ライブラリには、属性構造のコピーと複製を行うルーチンがあります。それらのルーチンは、異なるパラメータリストを使用して同じ作業を行うのでアプリケーションの要件を満たす方を使用してください。この例は、sendattrs 内のセキュリティ属性を recvattrs にコピーする 2 つの方法を示しています。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	size_t			size;
 	t6attr_t			sendattrs, recvattrs;
 	t6mask_t			sendmask, recvmask;

 	recvmask = T6M_SL;
 	recvattrs = t6alloc_blk(recvmask);
 	sendmask = T6M_IL;
 	sendattrs = t6alloc_blk(sendmask);

/* sendattrs の属性を recvattrs にコピーする */
 	t6copy_blk(sendattrs, recvattrs);

/* sendattrs の属性を recvattrs に複製する */
 	recvattrs = t6dup_blk(sendattrs);
 }

属性構造の比較

この例は、sendattrsrecvattrs と同じであるか比較します。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	int		retval;
 	t6attr_t			sendattrs, recvattrs;
 	t6mask_t			sendmask, recvmask;

 	recvmask = T6M_SL;
 	recvattrs = t6alloc_blk(recvmask);
 	sendmask = T6M_IL;
 	sendattrs = t6alloc_blk(sendmask);

 	retval = t6cmp_blk(sendattrs, recvattrs);
 	printf("Does sendattrs = recvattrs? %d¥n", retval);
 }

printf 文によって、次のように出力されます。0 は 2 つの構造が同じであることを示し、0 以外の値は異なることを示します。

Does sendattrs = recvattrs? 5

属性構造のクリア

この例は、recvattrs からセッション ID 属性の値をクリアします。領域はまだ属性構造に割り当てられていますが、属性値は NULL です。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	t6attr_t			 recvattrs;
 	t6mask_t			 recvmask, clrmask;

 	recvmask = T6M_ALL_ATTRS; recvattrs = t6alloc_blk(recvmask);
 	clrmask = T6M_SESSION_ID;
 	t6clear_blk(clrmask, recvattrs);
 }

属性マスクの作成

この例は、マスク構造のインスタンス化、必要な列挙型フィールドの論理和の計算に加え、属性マスク作成の 3 つの方法を示しています。

#include <tsix/t6attrs.h>
 #include <tsol/label.h>

 main()
 {
 	t6mask_t			suppmask, allocmask, presentmask,
 	t6mask_t 			getmask, recvmask;
 	t6attr_t			attrs, getattrs, recvattrs;

 	recvmask = T6M_ALL_ATTRS; recvattrs = t6alloc_blk(recvmask);
 	getmask = T6M_CLEARANCE; getattrs = t6alloc_blk(getmask);

/* システムがサポートする属性のマスクを得る */
 	suppmask = t6supported_attrs();

/* rcvattrs(T6M_ALL_ATTRS) により割り当てられる領域用の
/* マスクを得る */
 	allocmask = t6allocated_attrs(rcvattrs);

/* getattrs 内の属性のマスクを得る */
 	presentmask = t6present_attrs(getattrs);
 }

領域の解放

プログラムの最後に、t6attr_t 型の変数に割り当てられた領域をすべて解放します。

t6free_blk(sendattrs);
 t6free_blk(recvattrs);
 t6free_blk(getattrs)
 t6free_blk(attrs);

クライアントサーバーアプリケーション

この節では、ネットワーク上でデータとセキュリティ属性情報を転送するために Berkeley ソケットと TSIX ライブラリを使用した短いクライアントサーバーアプリケーションを示します。通信経路は、インターネットドメイン (TCP/IP) を使用する接続型です。サーバーは、複数の機密レベルで今後のミーティングについての情報を提供する並行プロセスです。このサービスをクライアントが受けるには、サーバーに接続し、指定された機密レベルの情報を要求します。

TCP/IP サーバー

サーバープロセスは、net_mac_read 特権を使用してマルチレベルポートに結合し、複数の機密レベルでシングルレベルクライアントに対応します。マルチレベルポートとシングルレベルポートの詳細は、第 11 章「プロセス間通信」を参照してください。

この msg_array 構造は、Confidential 、Secret 、Top Secret 、および NULL のミーティング情報を含みます。情報ラベル文字列は、サーバーがメッセージを送信する場合に使用する情報ラベルを示します。送信メッセージの情報ラベル属性を指定する場合、サーバープロセスは t6sendto(3N) ルーチンを使用します。サーバープロセスの情報ラベルは送信メッセージの情報ラベルと異なる可能性があるため、サーバープロセスは有効セットに net_upgrade_ilnet_downgrade_il 特権を必要とします。シングルレベルクライアントに応答するには、その子プロセスの機密ラベルをクライアントと同じレベルに変更するため、サーバープロセスの有効セットに proc_set_sl 特権が必要です。

#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <string.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>

 #include <tsol/label.h>
 #include <tsix/t6attrs.h>

 struct msg {
 	char *sl;
 	bslabel_t *bsl;
 	char *msg;
 	char *il;
 	bilabel_t *bil;
 } msg_array[] = {
 	"CONFIDENTIAL", 0, "Staff Meeting at 1:00 pm, Rm 200", "CONFIDENTIAL", 0,
 	"SECRET", 0, "Manager Meeting at 10:00 am, Rm 303", "SECRET", 0,
 	"TOP SECRET", 0, "Exective Meeting at 3:00 pm, Rm 902", "TOP SECRET", 0,
 	0, 0, 0, 0, 0
 };

主プログラムのこの最初の部分は、子プロセスがその機密ラベルを要求クライアントの機密ラベルに設定できるように、プロセス認可上限を ADMIN_HIGH に設定します。この作業には、proc_setclr 特権が必要です。

コード内のコメントは、第 3 章「特権」で説明している特権ブラケットが必要な位置を示しています。特権ブラケットにより、要求クライアントの機密ラベルと情報ラベルではなく、msg_array データで指定された機密ラベルと情報ラベルでサーバーがクライアントに応答できるように、net_reply_equal 特権は無効にする必要があります。コードコメントは、この例を動作させるため、net_reply_equal 特権を無効にすべき位置を示しています。

main(int argc, char **argv)
 {
 	int fd, newfd, chpid, index, error;
 	struct sockaddr_in serv_addr;
 	bclear_t clearance;

 	if (argc != 2) {
 		printf("Usage: %s host¥n", argv[0]);
 		exit(1);
 	}
 	printf("PID = %ld¥n", getpid());

 	/* プロセスの認可上限を ADMIN_HIGH に設定する */
 	/* 有効セット内で proc_setclr 特権をオン (有効) にする */

 	bclearhigh(&clearance);
 	if (setclearance(&clearance) != 0) {
 		perror("setclearance");
 		exit(1);
 	}
 	/* proc_setclr 特権をオフ (無効) にする */

主プログラムの次のセグメントは、msg_array 内のデータから、バイナリの機密ラベルと情報ラベルを作成します。これらのバイナリラベルは、後に TSIX ライブラリルーチンとともに使用されます。

	/* 実行時の効率を良くするためバイナリラベルを得る */

 	index = 0;
 	while (msg_array[index].sl != NULL) {
 		if ((msg_array[index].bsl =
 			(bslabel_t *) malloc(sizeof (bslabel_t))) == NULL) {
 			printf("No memory");
 			exit (1);
 		}
 		if (stobsl(msg_array[index].sl, msg_array[index].bsl,
 			NEW_LABEL, &error) != 1) {
 			printf("converting SL %s failed¥n",
 			msg_array[index].sl);
 			exit(1);
 		}
 		if ((msg_array[index].bil =
 			(bilabel_t *) malloc(sizeof (bilabel_t))) == NULL) {
 			printf("No memory");
 			exit (1);
 		}
 		if (stobil(msg_array[index].il, msg_array[index].bil,
 			NEW_LABEL, &error) != 1) {
 			printf("converting IL %s failed¥n",
 			msg_array[index].il);
 			exit(1);
 		}
 		index++;
 	}

主プログラムの次のセグメントは、ソケットを作成して名前に結合し、クライアント要求を待機することによって、終端通信を設定します。コード内のコメントは、第 3 章「特権」で説明している特権ブラケットが必要な位置を示します。

	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 		perror("socket");
 		exit(1);
 	}
 	memset(&serv_addr, 0, sizeof (serv_addr));
 	serv_addr.sin_family = AF_INET;
 	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 	serv_addr.sin_port = htons(10000);

/* 有効セット内で net_mac_read をオン (有効) にする */
 	if (bind(fd, (struct sockaddr *) &serv_addr,
 		sizeof (serv_addr)) < 0) {
 		perror("bind");
 		exit(1);
 	}
/* net_mac_read をオフ (無効) にする */

 	listen(fd, 5);

while ループは、各クライアント要求を処理するために、ソケットでクライアント接続を受け付け、プロセスを作成します。作成されたプロセスは、着信メッセージとその機密ラベルを受信し、プロセス CMW ラベルの機密ラベル部を着信機密ラベルに設定し、送信サーバー応答の情報ラベルを設定する構造を用意します。作成されたプロセスはまた、着信メッセージの機密ラベルを受信するために十分な領域の handle_in を割り当て、発信メッセージとともに機密ラベルを送信するために十分な領域の handle_out を割り当て、t6recvfrom(3N) ルーチンを使用してメッセージとセキュリティ属性情報を受信します。

	while (1) {
 		if ((newfd = accept(fd, NULL, 0)) < 0) {
 			perror("accept");
 			exit(1);
 		}
 		printf("Request Received¥n");
 		if ((chpid = fork()) < 0) {
 			perror("fork");
 			exit(1);
 		} else if (chpid == 0) {        /* 子プロセス */
 			t6attr_t handle_in;
 			t6attr_t handle_out;
 			t6mask_t mask_in = T6M_SL;
 			t6mask_t mask_out = T6M_IL;
 			bslabel_t *bsl;
 			bclabel_t bcmwlabel;
 			char buf[256];
 			int index, buflen = 256;
 			t6mask_t new_mask = T6M_NO_ATTRS;
 			char *string = (char *) 0;
 			char any;
 			close(fd);
 			printf("child PID = %ld¥n", getpid());

/* クライアント要求を処理する */
 			if ((handle_in = t6alloc_blk(mask_in)) == NULL) {
 				printf("t6attr_alloc: no memory");
 				exit(1);
 			}
 			if ((handle_out = t6alloc_blk(mask_out)) == NULL) {
 				printf("t6attr_alloc: no memory");
 				exit(1);
 			}
 			if (t6recvfrom(newfd, buf, buflen, 0, 0, 0,
 				handle_in, &new_mask) < 0) {
 				perror("t6recvfrom");
 				exit(1);
 			}

主プログラムの次のセグメントは、受信した機密ラベルを抽出し、プロセスの機密ラベルをクライアントの機密ラベルに設定します。コード内のコメントは、第 3 章「特権」で説明している特権ブラケットが必要な位置を示します。

	/* 機密ラベルを得る */
 			if ((bsl = (bslabel_t *) t6get_attr(T6_SL,
 				handle_in)) == NULL) {
 				printf("t6get_attr: no SL available");
 				exit(1);
 			}
 			if (bsltos(bsl, &string, 0, LONG_WORDS) < 0) {
 				perror("bsltos");
 				exit(1);
 			}
 			printf("Requestor's SL = %s¥n", string);

 	/* 子プロセスの機密ラベルをクライアントの機密ラベルに設定する */
 			if (getcmwplabel(&bcmwlabel) != 0) {
 				perror("getcmwplabel");
 				exit(1);
 			}
 			setcsl(&bcmwlabel, bsl);

 	/* 有効セット内で proc_set_sl をオン (有効) にする */
 			if (setcmwplabel(&bcmwlabel, SETCL_SL) < 0) {
 				perror("setcmwplabel");
 				exit (1);
 			}
 	/* proc_set_sl をオフ (無効) にする */

主プログラムのこの最後のセグメントは、着信クライアント要求の機密ラベルに基づいて、正しい情報ラベルと対応するミーティング情報を msg_array から見つけ、この情報ラベルを発信サーバー応答に入れます。情報ラベルが handle_out に格納され、t6sendto(3N) ルーチンが正しいミーティング情報と情報ラベルをパラメータに設定し呼び出されます。最後に、t6free_blk(3N) ルーチンが呼び出され、実行時に handle_inhandle_out に割り当てられた記憶領域を解放します。

				index = 0;
 				while (msg_array[index].sl != NULL) {
 					if (blequal(msg_array[index].bsl, bsl)) {
 						printf("Server's IL = %s¥n", msg_array[index].il);
 						if (t6set_attr(T6_IL,
 							(const void *) msg_array[index].bil,
 							handle_out) < 0) {
 							printf("t6set_attr: IL not allocated");
 							exit(1);
 						}
 						print_t6attr_t(handle_out);
 #if 0
 printf("press any key to continue¥n"); scanf("%c", &any);
 #endif
/* 有効セット内で net_replay_equal をオン (有効) にする */
 						if (t6sendto(newfd, msg_array[index].msg, strlen(
 							msg_array[index].msg), 0, 0, 0,
 							handle_out)< 0) {
 #if 0
 						if (sendto(newfd, msg_array[index].msg,
 							strlen(msg_array[index].msg), 0, 0, 0)< 0) {
 #endif
 							perror("t6sendto");
 							exit(1);
 						}
/* net_reply_equal をオフ (無効) にする */
 						break;
 					}
 					index++;
 				} /* end while */
 				if (msg_array[index].sl == NULL) {
 					printf("No Matching Msg Found¥n");
 				}
 				t6free_blk(handle_in);
 				t6free_blk(handle_out);
 				close(newfd);
 				printf("child: exiting¥n");
 				exit(0);
 			} else
 				close(newfd);
 		} /* end while */
 	} /* end main */

TCP/IP クライアント

サービスを要求する場合、クライアントプログラムは、サーバーに接続して要求を送信し、ミーティングメッセージを待ちます。メッセージの受信前に接続が閉じられる場合、その機密ラベルではミーティングがないため、クライアントは終了します。メッセージが受信されると、クライアントは t6recvfrom(3N) を使用してメッセージと情報ラベルを取得します。情報を処理するコードは、この例には示されていません。

プログラムのこの最初の部分は、クライアント要求とサーバー応答のデータ構造を設定します。

#include <stdio.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <string.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <tsol/label.h>
 #include <tsix/t6attrs.h>

 char *clnt_req = "Request Meeting Info";

 main(int argc, char **argv)
 {
 	int sock, retval;
 	char buf[256];
 	int buflen = 256;
 	int num;
 	struct sockaddr_in serv_addr;
 	struct hostent *hostent;
 	bilabel_t *bil;
 	t6mask_t new_mask, il_mask = T6M_IL;
 	t6attr_t handle;
 	char    *string = (char *)0;

主プログラムの次のセグメントは、コマンド行の argcargv 入力を処理し、サーバーのホスト名とポート番号を取得し、接続を確立します。

	if (argc != 2) {
 		printf("Usage: %s host¥n", argv[0]);
 		exit (1);
 	}
 	if ((hostent = gethostbyname(argv[1])) == NULL) {
 		perror("gethostbyname");
 		exit(1);
 	}

 	memset((void *) &serv_addr, 0, sizeof (serv_addr));
 	serv_addr.sin_family = AF_INET;
 	serv_addr.sin_port = htons(10000);
 	memcpy((void *) &serv_addr.sin_addr,
 		(void *) hostent->h_addr_list[0], hostent->h_length);

 	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 		perror("socket");
 		exit(1);
 	}
 	if (connect(sock, (struct sockaddr *)&serv_addr,
 		sizeof (serv_addr)) < 0) {
 		perror("connect");
 		exit(1);
 	}
 	printf("Connected¥n");
 	if ((handle = t6alloc_blk(il_mask)) == NULL) {
 		printf("t6attr_alloc: no memory");
 		exit(1);
 	}

主プログラムの次のセグメントは、要求をサーバーに送信します。この要求は、クライアントプロセスが動作している機密ラベルで送信されます。サーバーは、この要求を処理するとき、要求が作成された機密ラベルのミーティング情報のみを返送します。t6recvfrom(3N) ルーチンは、ミーティング情報を受信します。t6get_attr(3N) ルーチンは、サーバープロセスが応答に付けた情報ラベルを取得します。

/* サーバーに要求を送る */
 	write(sock, clnt_req, strlen(clnt_req));

 	if ((num = t6recvfrom(sock, buf, buflen, 0, 0, 0, handle,
 		&new_mask)) < 0) {
 		perror("t6recvfrom");
 		exit (1);
 	} else if (num == 0) {
 		printf("Connection closed, nothing matches.¥n");
 		exit(0);
 	} else
 		printf("Received Reply¥n");

/* msg に付けられた情報ラベルを取得する */
 	if ((bil = (bilabel_t *) t6get_attr(T6_IL,
 		handle)) == NULL) {
 		printf("t6get_attr: no IL available");
 		exit(0);
 	}

 	retval = biltos(bil, &string, 0, LONG_WORDS);
 	printf("Retval = %d, Information label = %s¥n", retval, string);
 	printf("Message = %s¥n", buf);
 }

プログラムの実行

サーバープロセスが開始し、クライアント要求を待ちます。

phoenix% serverProgram phoenix

PID = 655

クライアントプロセスが Confidential で開始すると、クライアント側の printf 文によって次のように出力されます。マルチレベル接続であるため、サーバーの機密ラベルは問われません。

phoenix% clientProgram phoenix

Received Reply

Information label = CONFIDENTIAL

Message = Staff Meeting at 1:00 pm, Rm 200

クライアント要求に応答した後、サーバープロセスによって次のように出力されます。

Request Received

child PID = 657

Requestor's SL = C

Server's IL = Confidential

Attributes List (alloc_mask = 0x00000040, attr_mask = 0x00000040):

Information Label = CONFIDENTIAL

child: exiting