Trusted Extensions ソフトウェアは、次のソケットベースのメカニズムを使用することによって、通信終端間の IPC に対応します。
バークレーソケット
トランスポートレイヤーインタフェース (TLI)
遠隔手続き呼び出し (RPC)
この節では、ソケット通信メカニズムとそれに関連するセキュリティーポリシーについて概説します。セキュリティーポリシーと適用可能な特権については、該当するマニュアルページを参照してください。
これらのメカニズムのほかに、Trusted Extensions はマルチレベルポートにも対応します。「マルチレベルポートについて」を参照してください。
Trusted Extensions ソフトウェアは、単一ポートおよびマルチレベルポートでバークレーソケットおよび TLI を使用することによって、ネットワーク通信に対応します。システムコールの AF_UNIX ファミリは、完全解決のパス名で指定される特別なファイルを使用して、同じラベル付けされたゾーンでプロセス間接続を確立します。システムコールの AF_INET ファミリは、IP アドレスとポート番号を使用して、ネットワークにまたがるプロセス間接続を確立します。
インタフェースの AF_UNIX ファミリでは、UNIX® ドメインソケットである特別な 1 つのファイルに対してサーバーバインドを 1 つだけ確立できます。AF_UNIX ファミリはマルチレベルポートに対応しません。
UNIX ドメインソケット同様に、ドアおよび名前付きパイプは、認識し合う目的で特別なファイルを使用します。
すべての Trusted Extensions IPC メカニズムのデフォルトポリシーは、すべてのメカニズムが 1 つのラベル付けされたゾーン内で機能するように制約されることです。このポリシーの例外は次のとおりです。
大域ゾーン管理者は、ラベルが所有ゾーンより優位であるゾーンに対して名前付きパイプ (FIFO) を使用可能にできます。管理者は、FIFO を含むディレクトリをループバックマウントすることによってこれを行います。
より高いレベルのゾーンで実行されるプロセスは、読み取り専用モードで FIFO を開くことができます。プロセスは下位書き込みのために FIFO を使用できません。
大域ゾーンランデブファイルがラベル付けされたゾーンにループバックマウントされる場合、ラベル付けされたゾーンは大域ゾーンドアサーバーにアクセスできます。
Trusted Extensions ソフトウェアは、labeld および nscd のドアベースサービスをサポートするドアポリシーに従います。デフォルトの zonecfg テンプレートは、大域ゾーンの /var/tsol/doors ディレクトリが、ラベル付けされたゾーンのそれぞれにループバックマウントされることを指定します。
AF_INET ファミリでは、プロセスは、特権または非特権のポート番号に対して単一ラベル接続またはマルチラベル接続を確立できます。特権ポート番号に接続するには、net_priv_addr 特権が必要です。マルチレベルポート接続にするには、net_bindmlp 特権も必要です。
サーバープロセスには、マルチレベルポート接続のために、その実効セットに net_bindmlp 特権が必要です。それに対して単一レベルポート接続を行う場合、サーバープロセスにはソケットに対する必須同等読み取りアクセスが必要であり、クライアントプロセスには必須同等書き込みアクセスが必要です。両方のプロセスには、ファイルに対する必須と任意のアクセスが必要です。ファイルへのアクセスが拒否される場合、アクセスが拒否されるプロセスには、アクセスを得るために、適切なファイル特権がその実効セットに必要です。
次のコーディング例は、接続されたクライアントのラベルをマルチレベルサーバーがどのように取得するかを示します。標準 C ライブラリ関数 getpeerucred() が、接続されたソケットまたは STREAM ピアの資格を取得します。Trusted Extensions において、マルチレベルポートサーバーの待機ソケットが接続要求を受け入れると、通常、最初の引数がクライアントソケットファイル記述子になります。Trusted Extensions アプリケーションは、標準のアプリケーションプログラムとまったく同じに getpeerucred() 関数を使用します。Trusted Extensions には ucred_getlabel() が追加され、ラベルを返します。詳細は、ucred_get(3C) のマニュアルページを参照してください。
/*
* この例は、接続されたクライアントのラベルをマルチレベルサーバーが
* どのように取得するかを示す。
*/
void
remote_client_label(int svr_fd)
{
ucred_t *uc = NULL;
m_label_t *sl;
struct sockaddr_in6 remote_addr;
bzero((void *)&remote_addr, sizeof (struct sockaddr_in6));
while (1) {
int clnt_fd;
clnt_fd = accept(svr_fd, (struct sockaddr *)&remote_addr,
&sizeof (struct sockaddr_in6));
/*
* ソケットからクライアント属性を取得する
*/
if (getpeerucred(clnt_fd, &uc) == -1) {
return;
}
/*
* ucred 構造体から各フィールドを抽出する
*/
sl = ucred_getlabel(uc);
/*
* セキュリティーラベルの使用法
* .....
*/
ucred_free(uc);
close(clnt_fd);
}
}
Trusted Extensions ソフトウェアは、遠隔手続き呼び出し (RPC) に対するマルチレベルポートに対応します。クライアントアプリケーションは、特定サービスが使用可能かどうかの問い合わせをサーバーの PORTMAPPER サービス (ポート 111) に対して送信できます。要求されたサービスがサーバーの PORTMAPPER に登録されている場合、サーバーは匿名ポートを動的に割り当て、そのポートをクライアントに返します。
Solaris Trusted Extensions システムでは、管理者が PORTMAPPER ポートをマルチレベルポートとして構成できるので、複数の単一レベルアプリケーションでこのサービスを使用できます。PORTMAPPER ポートをマルチレベルポートにすると、PORTMAPPER サービスによって割り当てられるすべての匿名ポートもマルチレベルポートになります。これ以外の、匿名のマルチレベルポートを制御するための、プログラム可能なインタフェースも管理インタフェースもありません。
前の節で説明した PORTMAPPER サービスは、UDP を使用して実装されます。TCP と異なり、UDP ソケットは接続指向ではないので、マルチレベルポートでクライアントに応答する場合にどの資格を使用するかに関してあいまいになることがあります。したがって、クライアントの要求ソケットは、サーバーの応答ソケットに明示的に関連付けられなければなりません。これを関連付けるには、SO_RECVUCRED ソケットオプションを使用します。
SO_RECVUCRED が UDP ソケットで設定されると、カーネル UDP モジュールは ucred 構造体のラベルを補助データとしてアプリケーションに渡します。ucred の level と type の値がそれぞれ、SOL_SOCKET と SCM_UCRED です。
アプリケーションは次のいずれかの方法でこの ucred 構造体を処理します。
この ucred 構造体を受信バッファーから送信バッファーにコピーする
受信バッファーを送信バッファーとして再利用し、受信バッファーの ucred 構造体をそのままにする
次のコード抜粋は再利用の場合を示します。
/*
* src で SCM_UCRED を検索し、dest のみのオプションに
* ポインタを指定する。これら 2 つの 'netbuf' 構造体が同じ
* である場合もある。そのため、コードで dest の変更後に
* src を照会するときに注意が必要。
*/
static void
extract_cred(const struct netbuf *src, struct netbuf *dest)
{
char *cp = src->buf;
unsigned int len = src->len;
const struct T_opthdr *opt;
unsigned int olen;
while (len >= sizeof (*opt)) {
/* LINTED: pointer alignment */
opt = (const struct T_opthdr *)cp;
olen = opt->len;
if (olen > len || olen < sizeof (*opt) ||
!IS_P2ALIGNED(olen, sizeof (t_uscalar_t)))
break;
if (opt->level == SOL_SOCKET &&
opt->name == SCM_UCRED) {
dest->buf = cp;
dest->len = olen;
return;
}
cp += olen;
len -= olen;
}
dest->len = 0;
}
次のコード抜粋は、受信バッファーからユーザー資格にアクセスする方法を示します。
void
examine_udp_label()
{
struct msghdr recv_msg;
struct cmsghdr *cmsgp;
char message[MAX_MSGLEN+1];
char inmsg[MAX_MSGLEN+1];
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_RECVUCRED, (void *)&on,
sizeof (int));
[...]
while (1) {
if (recvmsg(sockfd, &recv_msg, 0) < 0) {
(void) fprintf(stderr, "recvmsg_errno: %d\n", errno);
exit(1);
}
/*
* 補助データで ucred を検査する
*/
ucred = NULL;
for (cmsgp = CMSG_FIRSTHDR(&recv_msg); cmsgp;
cmsgp = CMSG_NXTHDR(&recv_msg, cmsgp)) {
if (cmsgp->cmsg_level == SOL_SOCKET &&
cmsgp->cmsg_type == SCM_UCRED) {
ucred = (ucred_t *)CMSG_DATA(cmsgp);
break;
}
if (ucred == NULL) {
(void) sprintf(&message[0],
"No ucred info in ancillary data with UDP");
} else {
/*
* ここで、ucred_getlabel(3C) を使用して、ucred から
* ラベルを抽出することもできる。
*/
}
}
[...]
if (message != NULL)
(void) strlcpy(&inmsg[0], message, MAX_MSGLEN);
/*
* 正しいラベルが含まれるように、受信したメッセージを
* 使用する
*/
iov.iov_len = strlen(inmsg);
ret = sendmsg(sockfd, &recv_msg, 0);
}
}