この節では、ネットワーク上でデータとセキュリティ属性情報を転送するために 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);
}