服务器端的 UNIX 认证

本例演示了如何在服务器端使用 UNIX 授权。

以下是传递到服务器上的服务分派例程的请求句柄的结构定义:

/*
 * An RPC Service request
 */
struct svc_req {
    u_long    rq_prog;          /*  service program number     */
    u_long    rq_vers;          /*  service protocol vers num  */
    u_long    rq_proc;          /*  required procedure number   */
   struct opaque_auth rq_cred;  /*  raw credentials from wire  */
   caddr_t   rq_clntcred;       /*  credentials (read only)    */
};
除了认证凭证的样式或类型模板以外, rq_cred 例程是不透明的。

/*
 * Authentication info. Mostly opaque to the programmer.
 */
struct opaque_auth {
    enum_t  oa_flavor;  /*  style of credentials  */
    caddr_t oa_base;    /*  address of more auth stuff  */
    u_int   oa_length;  /*  not to exceed MAX_AUTH_BYTES */
};
在将请求传递到服务分派例程之前, RPC 保证:
  • 请求的 rq_cred 字段采用可接受的格式。 因此,服务实现者可以检查请求的 rq_cred.oa_flavor 以确定调用者使用的认证样式。 如果认证样式不是 RPC 包支持的样式之一,那么服务实现者也可能希望检查其他 rq_cred 字段。
  • 请求的 rq_clntcred 字段为空或指向与受支持的认证凭证样式对应的格式正确的结构。 当前可以将 rq_clntcred 字段设置为指向用于 UNIX 样式认证的 authunix_parms 结构的指针。 如果 rq_clntcred 为空,那么服务实现者可以检查 rq_cred 凭证的其他不透明字段以获取 RPC 包可能未知的任何新类型的认证。
以下示例在服务器端使用 UNIX 认证。 此处扩展了远程用户服务示例,以便计算除用户标识 (UID) 16 以外的所有用户的结果:

nuser(rqstp, transp)
    struct svc_req *rqstp;
    SVCXPRT *transp;
{
    struct authunix_parms *unix_cred;
    int uid;
    unsigned long nusers;

    /*
     * we don't care about authentication for null proc
     */
    if (rqstp->rq_proc == NULLPROC) {
        if (!svc_sendreply(transp, xdr_void, 0)) {
            fprintf(stderr, "can't reply to RPC call\n");
            return (1);
         }
         return;
    }
    /*
     * now get the uid
     */
    switch (rqstp->rq_cred.oa_flavor) {
    case AUTH_UNIX:
        unix_cred = 
            (struct authunix_parms *)rqstp->rq_clntcred;
        uid = unix_cred->aup_uid;
        break;
    case AUTH_NULL:
    default:
        svcerr_weakauth(transp);
        return;
    }

    switch (rqstp->rq_proc) {
    case RUSERSPROC_NUM:
        /*
         * make sure caller is allowed to call this proc
         */
        if (uid == 16) {
            svcerr_systemerr(transp);
            return;
        }
        /*
         * Code here to compute the number of users
         * and assign it to the variable nusers 
         */
        if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
            fprintf(stderr, "can't reply to RPC call\n");
            return (1);
        }
        return;
    default:
        svcerr_noproc(transp);
        return;
    }
}