この節では、RPC ライブラリルーチンによってセキュリティ属性がどのように送受信されるかを示す簡単なクライアントサーバーアプリケーションを示します。コマンド行引数には、サーバー名とユーザー ID を指定します。サーバープロセスは、クライアントが送信するユーザー ID を取得し、その入力を 2 倍にした結果をクライアントに送信します。このプログラムを実行するには、「ヘッダーファイルとライブラリ」に示されているライブラリを使用してコンパイルしてください。
このアプリケーション例をコンパイルするには、次のヘッダーファイル rpc_test.h が必要です。
#include <rpc/rpc.h> #include <rpc/types.h> #define RPC_TEST_PROG ((u_long)1234567890) #define RPC_TEST_VERS ((u_long)1) #define RPC_TEST_DOUBLE1 ((u_long)1) #define RPC_TEST_EXIT1 ((u_long)2)
クライアントプログラムのこの部分は、コマンド行入力を受け入れて、クライアントハンドルを作成します。
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <netdb.h>
#include <tsix/t6attrs.h>
#include "rpc_test.h"
extern int
main(int argc, char *argv[])
{
struct timeval time_out;
CLIENT *handlep;
enum clnt_stat stat;
int input, output;
uid_t uid;
if (argc < 2 || argc > 3) {
fprintf(stderr,
"Usage: simple_rpc_clnt_test HOSTNAME [UID]¥n");
exit(1);
}
handlep = clnt_create(argv[1], RPC_TEST_PROG,
RPC_TEST_VERS, "udp");
if (handlep == (CLIENT *) NULL) {
fprintf(stderr, "Couldn't create client%s.¥n",
clnt_spcreateerror(""));
exit(1);
}
クライアントプログラムのこの部分は、コマンド行から入力されるユーザー ID に割り当てられる領域を指すようにクライアントハンドルを設定し、ユーザー ID 値を設定し、その値をサーバープロセスに送信し、サーバー応答を待機します。クライアントは、サーバー応答を出力して終了します。
クライアントプログラムは、変更された発信ユーザー ID を送信するために有効セットに net_setid 特権を必要とします。コード内のコメントは、特権のブラケットが必要な位置を示します。
if (argc == 3) {
handlep->cl_tsol_outgoing_attrsp = t6alloc_blk(T6M_UID);
if (handlep->cl_tsol_outgoing_attrsp == NULL) {
fprintf(stderr, "Can't create attr buffer¥n");
exit(1);
}
printf ("Sending UID %s¥n", argv[2]);
uid = atoi(argv[2]);
if (t6set_attr(T6_UID, &uid,
handlep->cl_tsol_outgoing_attrsp) != 0) {
fprintf(stderr, "Error returned by t6set_attr.¥n");
exit(1);
}
}
time_out.tv_sec = 30;
time_out.tv_usec = 0;
input = 3;
/* 有効セット内で net_uid をオン (有効) にする */
stat = clnt_call( handlep, RPC_TEST_DOUBLE1, xdr_int,
(caddr_t) &input, xdr_int, (caddr_t) &output, time_out);
if (stat != RPC_SUCCESS) {
fprintf(stderr, "Call failed. %s.¥n",
clnt_sperror(handlep, ""));
exit(1);
}
/* net_uid をオフ (無効) にする */
printf("Response received: %d¥n", output);
(void) clnt_destroy(handlep);
return (0);
}
サーバープログラムは、すべてのセキュリティ属性に割り当てられた領域を指すようにサーバーハンドルを設定します。
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <tsix/t6attrs.h>
#include "rpc_test.h"
static void proc_1(struct svc_req *rqstp, SVCXPRT *transp);
extern int
main(int argc, char *argv[])
{
SVCXPRT *handlep;
struct netconfig *netconfigp;
netconfigp = getnetconfigent("udp");
if (netconfigp == NULL) {
fprintf(stderr, "Cannot find netconfig entry for udp.¥n");
exit(1);
}
handlep = svc_tp_create(proc_1, RPC_TEST_PROG,
RPC_TEST_VERS, netconfigp);
if (handlep == NULL) {
fprintf(stderr, "Cannot create service.¥n");
exit(1);
}
freenetconfigent(netconfigp);
handlep->xp_tsol_incoming_attrsp = t6alloc_blk(T6M_ALL_ATTRS);
if (handlep->xp_tsol_incoming_attrsp == NULL) {
fprintf(stderr, "Can't create attr buffer¥n");
exit(1);
}
svc_run();
return (0);
}
遠隔手続きは、コマンド行引数からユーザー ID を受け取り、その入力を 2 倍にした結果をクライアントに送信し、応答を出力して終了します。
static void
proc_1(struct svc_req *rqstp, SVCXPRT *handlep)
{
int input;
int result;
uid_t *uidp;
switch(rqstp->rq_proc) {
case NULLPROC:
svc_sendreply(handlep, xdr_void, NULL);
break;
case RPC_TEST_DOUBLE1:
if (!svc_getargs(handlep, xdr_int, (caddr_t) &input)) {
fprintf(stderr, "Error from svc_getargs¥n");
svcerr_systemerr(handlep);
}
uidp = (uid_t *) t6get_attr(T6_UID,
handlep->xp_tsol_incoming_attrsp);
if (uidp == NULL)
fprintf(stderr, "Error from t6get_attr.¥n");
else printf("Client's UID is %d¥n", *uidp);
result = 2 * input;
if (!svc_sendreply(handlep, xdr_int, (caddr_t) &result)) {
fprintf(stderr, "Error from sendreply¥n");
svcerr_systemerr(handlep);
}
svc_freeargs(handlep, xdr_int, (caddr_t) &input);
break;
default:
fprintf(stderr, "Call to unexpected procedure number %d¥n",
rqstp->rq_proc);
svcerr_noproc(handlep);
break;
}
}
クライアントプロセスは、サーバーホスト名とユーザー ID を入力パラメータとして受け取り、指定されたユーザー ID を送信中であることを出力します。
%owl phoenix
%phoenix owl 2570
Sending UID 2570
サーバーは、ユーザー ID を取得し、それを次のように出力します。
Client's UID is 2570
クライアントプロセスは、サーバー応答を出力して終了します。
Response received: 6
%phoenix