トラステッドセキュリティ情報交換 (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 を変更するには、送信プロセスの有効セットに net_setid 特権が必要です。
メッセージとともに特権が送信されるように指定するには、送信プロセスの有効セットに net_setpriv 特権が必要です。指定される特権は、送信プロセスの許可セット内に存在していなければなりません。
この章で説明しているプログラミングインタフェースを使用するには、次のヘッダーファイルが必要です。
#include <tsix/t6attrs.h>
この章の例は、次のライブラリを使用してコンパイルしています。
-lsocket -lt6 -ltsol
t6attr_t データ構造体は、セキュリティ属性の全セットを保持できます。
t6attr_id_t 構造体は、全セキュリティ属性値のセットを示す列挙型の定数を含み (保持し) ます。t6attr_t 型の変数は、これらの定数を使用して初期化します。ほとんどの定数は、次に示すように固定バイトサイズです。しかし、T6_GROUPS は、その値の実際のサイズを示す可変サイズです。
t6set_attr(3N) ルーチンは、次に示す適切な型にキャストされるべき任意の型のパラメータを受け入れます。
t6get_attr(3N) ルーチンは、次に示す適切な型に変換されるべき任意の型の変数を返します。
列挙型の定数 |
内容 |
データ型 |
バイトサイズ |
T6_SL |
機密ラベル |
bslabel_t |
36 |
T6_SESSION_ID |
ネットワークセッション ID |
sid_t |
4 |
T6_CLEARANCE |
認可上限 |
bclear_t |
36 |
T6_IL |
情報ラベル |
bilabel_t |
68 |
T6_PRIVILEGES |
有効な特権 |
priv_set_t |
16 |
T6_AUDIT_ID |
監査 ID |
au_id_t |
4 |
T6_PID |
プロセス ID |
pid_t |
4 |
T6_AUDIT_INFO |
その他の監査情報 |
auditinfo_t |
24 |
T6_UID |
実効ユーザー ID |
uid_t |
4 |
T6_GID |
実効グループ ID |
gid_t |
4 |
T6_GROUPS |
追加グループ ID |
gid_t |
可変 |
T6_PROC_ATTR |
プロセスの属性フラグ |
pattr_t |
4 |
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);
t6size_attr(3N) ルーチンは、セキュリティ属性構造 t6ctl の attr_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);
このルーチンは、mask に t6ctl に基づいて指定された属性をクリアします。詳細は、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 とともに送信する機密ラベルと認可上限の新しい属性値を設定します。
定義済みの機密ラベルと認可上限だけを使用して、マスク (sendmask) を定義する
sendmask を使用してセキュリティ属性構造 sendattrs を割り当て、属性構造がこれら 2 つの属性だけの領域を含むようにする
sendattrs 内の機密ラベルと認可上限に、Top Secret の属性値を設定する
通信終端との通信を設定する
msg をセキュリティ属性とともに通信終端へ送信する
msg を送信するプロセスは Confidential であるため、認可上限と機密ラベルを変更するために、有効セットに net_setclr と net_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); }
この例は、sendattrs が recvattrs と同じであるか比較します。
#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) を使用する接続型です。サーバーは、複数の機密レベルで今後のミーティングについての情報を提供する並行プロセスです。このサービスをクライアントが受けるには、サーバーに接続し、指定された機密レベルの情報を要求します。
サーバープロセスは、net_mac_read 特権を使用してマルチレベルポートに結合し、複数の機密レベルでシングルレベルクライアントに対応します。マルチレベルポートとシングルレベルポートの詳細は、第 11 章「プロセス間通信」を参照してください。
この msg_array 構造は、Confidential 、Secret 、Top Secret 、および NULL のミーティング情報を含みます。情報ラベル文字列は、サーバーがメッセージを送信する場合に使用する情報ラベルを示します。送信メッセージの情報ラベル属性を指定する場合、サーバープロセスは t6sendto(3N) ルーチンを使用します。サーバープロセスの情報ラベルは送信メッセージの情報ラベルと異なる可能性があるため、サーバープロセスは有効セットに net_upgrade_il と net_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_in と handle_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 */
サービスを要求する場合、クライアントプログラムは、サーバーに接続して要求を送信し、ミーティングメッセージを待ちます。メッセージの受信前に接続が閉じられる場合、その機密ラベルではミーティングがないため、クライアントは終了します。メッセージが受信されると、クライアントは 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;
主プログラムの次のセグメントは、コマンド行の argc と argv 入力を処理し、サーバーのホスト名とポート番号を取得し、接続を確立します。
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