AUTH_SYS タイプより厳しいセキュリティレベルが要求されるプログラムでは、AUTH_DES タイプの認証を使用します。AUTH_SYS タイプは AUTH_DES タイプに簡単に変更できます。たとえば、authsys_create_default() を使用する代わりに、プログラムから authsys_create() を呼び出し、RPC 認証ハンドルを変更して目的のユーザ ID とホスト名を設定することができます。
AUTH_DES タイプの認証を使用するには、サーバ側とクライアント側の両方のホストで、keyserv() デーモンと NIS また NIS+ ネームサービスが実行されている必要があります。また、両方のホスト上のユーザに対してネットワーク管理者が割り当てたパブリックキー / シークレットのキーペアが、publickey() のデータベースに入っていなければなりません。ユーザは keylogin() のコマンドを実行して自分のシークレットキーを暗号化しておく必要があります (通常は、ログインパスワードとセキュア RPC パスワードが同一の場合には、これを login() で行います)。
AUTH_DES タイプの認証を使用するには、クライアントが認証ハンドルを正しく設定しなければなりません。その例を次に示します。
cl->cl_auth = authdes_seccreate(servername, 60, server, (char *)NULL);
最初の引数は、サーバプロセスのネットワーク名か、サーバプロセスの所有者のネット名です。サーバプロセスは通常 root プロセスで、次の関数呼び出しでネット名を得ることができます。
char servername[MAXNETNAMELEN]; host2netname(servername, server, (char *)NULL);
servername は受信文字列へのポインタで、server はサーバプロセスが実行されているホスト名です。サーバプロセスがスーパーユーザ以外のユーザから起動されている場合は、次のように user2netname() を呼び出します。
char servername[MAXNETNAMELEN]; user2netname(servername, serveruid(), (char *)NULL);
serveruid() はサーバプロセスのユーザ id です。どちらの関数も最後の引数は、サーバを含むドメイン名です。NULL を指定すると、ローカルドメイン名が使用されます。
authdes_seccreate() の第 2 引数では、このクライアントの資格の存在時間 (ウィンドウとも呼ばれる) を指定します。この例では 60 秒が指定されているので、この資格はクライアント側が RPC 呼び出しを行なってから、60 秒間で失われます。プログラムから再びこの資格を使用しようとしても、サーバ側の RPC サブシステムは、資格がすでに失われていることを知って、資格を失ったクライアントからの要求に答えません。また資格の存在時間中に別のプログラムがその資格を再使用しようとしても拒否されます。サーバ側の RPC サブシステムが最近作成された資格を保存していて、重複して使用できないようにするためです。
authdes_seccreate() の第 3 引数は、クロックを同期させる timehost 名です。AUTH_DES タイプの認証を使用するには、サーバとクライアントの時間が一致していなければなりません。この例では、サーバに同期させています。(char *)NULL と指定すると同期しません。この指定は、クライアントとサーバがすでに同期していることが確実な場合にだけ行なってください。
authdes_seccreate() の第 4 引数は、タイムスタンプとデータとを暗号化するための DES 暗号化キーへのポインタです。この例のように (char *)NULL と指定した場合は、ランダムキーが選択されます。このキーは、認証ハンドルの ah_key フィールドに入っています。
サーバ側はクライアント側より簡単です。例 4-27のサーバを AUTH_DES タイプの認証を使用するように変更したものを、例 4-28に示します。
#include <rpc/rpc.h>
...
...
nuser(rqstp, transp)
struct svc_req *rqstp;
SVCXPRT *transp;
{
struct authdes_cred *des_cred;
uid_t uid;
gid_t gid;
int gidlen;
gid_t gidlist[10];
/* NULLPROC の場合は認証データなし */
if (rqstp->rq_proc == NULLPROC) {
/* 元のプログラムと同じ */
}
/* ここで uid を取得 */
switch(rqstp->rq_cred.oa_flavor) {
case AUTH_DES:
des_cred = (struct authdes_cred *) rqstp->rq_clntcred;
if (! netname2user( des_cred->adc_fullname.name, &uid,
&gid, &gidlen, gidlist)) {
fprintf(stderr, "unknown user: %s¥n",
des_cred->adc_fullname.name);
svcerr_systemerr(transp);
return;
}
break;
default:
svcerr_weakauth(transp);
return;
}
/* 以降は元のプログラムと同じ */
netname2user() ルーチンは、ネットワーク名 (またはユーザの netname) をローカルシステム ID に変換することに注意してください。このルーチンはグループ ID も返します (この例では使用していません)。