]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] kNFSd: Tidy up the rpc authentication interface.
authorNeil Brown <neilb@cse.unsw.edu.au>
Fri, 11 Oct 2002 12:39:15 +0000 (05:39 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 11 Oct 2002 12:39:15 +0000 (05:39 -0700)
Define auth_ops that contains a method for authenticating a request and a
method for authorising a reply.  Call both methods as appropriate.

Also discard rq_verfed and cr_flavour, neither ever used.
And discard rq_auth as it isn't needed.

fs/nfsd/nfssvc.c
include/linux/sunrpc/svc.h
include/linux/sunrpc/svcauth.h
net/sunrpc/svc.c
net/sunrpc/svcauth.c
net/sunrpc/svcsock.c

index 2d53b16ace71a54cf0ced6092cd86abf6f9bfcdd..6fb1615279c218df9fa4ed47707afb3aa450a07d 100644 (file)
@@ -173,8 +173,6 @@ nfsd(struct svc_rqst *rqstp)
        current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
        nfsdstats.th_cnt++;
-       /* Let svc_process check client's authentication. */
-       rqstp->rq_auth = 1;
 
        lockd_up();                             /* start lockd */
 
index e1ed17ddc419c4aeae6db6eb4a1d7634edf26117..e4a2bdc0b87cbbf4e24fed5c245d52e6efa62ad3 100644 (file)
@@ -98,6 +98,7 @@ struct svc_rqst {
 
        struct svc_serv *       rq_server;      /* RPC service definition */
        struct svc_procedure *  rq_procinfo;    /* procedure info */
+       struct auth_ops *       rq_authop;      /* authentication flavour */
        struct svc_cred         rq_cred;        /* auth info */
        struct sk_buff *        rq_skbuff;      /* fast recv inet buffer */
        struct svc_buf          rq_defbuf;      /* default buffer */
@@ -108,10 +109,10 @@ struct svc_rqst {
        u32                     rq_vers;        /* program version */
        u32                     rq_proc;        /* procedure number */
        u32                     rq_prot;        /* IP protocol */
-       unsigned short          rq_verfed  : 1, /* reply has verifier */
+       unsigned short
                                rq_userset : 1, /* auth->setuser OK */
-                               rq_secure  : 1, /* secure port */
-                               rq_auth    : 1; /* check client */
+                               rq_secure  : 1; /* secure port */
+
 
        void *                  rq_argp;        /* decoded arguments */
        void *                  rq_resp;        /* xdr'd results */
@@ -128,7 +129,7 @@ struct svc_rqst {
                                                 * to report (real or virtual)
                                                 */
 
-       wait_queue_head_t       rq_wait;        /* synchronozation */
+       wait_queue_head_t       rq_wait;        /* synchronization */
 };
 
 /*
index 83aa079fe2f3958484d351398005230054fd0dcf..0852b50ff63d1ac5240aa51bb816f910a1e470ba 100644 (file)
 #include <linux/sunrpc/msg_prot.h>
 
 struct svc_cred {
-       rpc_authflavor_t        cr_flavor;
        uid_t                   cr_uid;
        gid_t                   cr_gid;
        gid_t                   cr_groups[NGROUPS];
 };
 
 struct svc_rqst;               /* forward decl */
-
-void   svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-int    svc_auth_register(rpc_authflavor_t flavor,
-                               void (*)(struct svc_rqst *,u32 *,u32 *));
-void   svc_auth_unregister(rpc_authflavor_t flavor);
-
-#if 0
 /*
- * Decoded AUTH_UNIX data. This is different from what's in the RPC lib.
+ * Each authentication flavour registers an auth_ops
+ * structure.
+ * name is simply the name.
+ * flavour gives the auth flavour. It determines where the flavour is registered
+ * accept() is given a request and should verify it.
+ *   It should inspect the authenticator and verifier, and possibly the data.
+ *    If there is a problem with the authentication *authp should be set.
+ *    The return value of accept() can indicate:
+ *      OK - authorised. client and credential are set in rqstp.
+ *           reqbuf points to arguments
+ *           resbuf points to good place for results.  verfier
+ *             is (probably) already in place.  Certainly space is
+ *            reserved for it.
+ *      DROP - simply drop the request. It may have been deferred
+ *      GARBAGE - rpc garbage_args error
+ *      SYSERR - rpc system_err error
+ *      DENIED - authp holds reason for denial.
+ *
+ *   accept is passed the proc number so that it can accept NULL rpc requests
+ *   even if it cannot authenticate the client (as is sometimes appropriate).
+ *
+ * release() is given a request after the procedure has been run.
+ *  It should sign/encrypt the results if needed
+ * It should return:
+ *    OK - the resbuf is ready to be sent
+ *    DROP - the reply should be quitely dropped
+ *    DENIED - authp holds a reason for MSG_DENIED
+ *    SYSERR - rpc system_err
  */
-#define NGRPS          16
-struct authunix_parms {
-       u32             aup_stamp;
-       u32             aup_uid;
-       u32             aup_gid;
-       u32             aup_len;
-       u32             aup_gids[NGRPS];
+struct auth_ops {
+       char *  name;
+       int     flavour;
+       int     (*accept)(struct svc_rqst *rq, u32 *authp, int proc);
+       int     (*release)(struct svc_rqst *rq);
 };
+extern struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR];
+
+#define        SVC_GARBAGE     1
+#define        SVC_SYSERR      2
+#define        SVC_VALID       3
+#define        SVC_NEGATIVE    4
+#define        SVC_OK          5
+#define        SVC_DROP        6
+#define        SVC_DENIED      7
+#define        SVC_PENDING     8
+
 
-struct svc_authops *   auth_getops(rpc_authflavor_t flavor);
-#endif
+extern int     svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc);
+extern int     svc_authorise(struct svc_rqst *rqstp);
+extern int     svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
+extern void    svc_auth_unregister(rpc_authflavor_t flavor);
 
 
 #endif /* __KERNEL__ */
index d3acb5c21001232d6f1148bc95652da1fc9c089e..c831adc8b6ec4c4e825fc6ed9100151193b25596 100644 (file)
@@ -262,18 +262,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
        argp->buf += 5;
        argp->len -= 5;
 
-       /* Used by nfsd to only allow the NULL procedure for amd. */
-       if (rqstp->rq_auth && !rqstp->rq_client && proc) {
-               auth_stat = rpc_autherr_badcred;
-               goto err_bad_auth;
-       }
-
        /*
         * Decode auth data, and add verifier to reply buffer.
         * We do this before anything else in order to get a decent
         * auth verifier.
         */
-       svc_authenticate(rqstp, &rpc_stat, &auth_stat);
+       if (svc_authenticate(rqstp, &rpc_stat, &auth_stat, proc))
+               /* drop the request, it has probably been deferred */
+               goto dropit;
 
        if (rpc_stat != rpc_success)
                goto err_garbage;
@@ -347,10 +343,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
 
        if (procp->pc_encode == NULL)
                goto dropit;
-sendit:
+
+ sendit:
+       if (svc_authorise(rqstp))
+               goto dropit;
        return svc_send(rqstp);
 
-dropit:
+ dropit:
+       svc_authorise(rqstp);   /* doesn't hurt to call this twice */
        dprintk("svc: svc_process dropit\n");
        svc_drop(rqstp);
        return 0;
index 8313d0de5d77a405cb8f8a2b0799cceca047d8de..d0ecfb73a09a5802b1417e18f008609b19b77545 100644 (file)
 
 #define RPCDBG_FACILITY        RPCDBG_AUTH
 
-/*
- * Type of authenticator function
- */
-typedef void   (*auth_fn_t)(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-
 /*
  * Builtin auth flavors
  */
-static void    svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-static void    svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
+static int     svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc);
+static int     svcauth_null_release(struct svc_rqst *rqstp);
+static int     svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc);
+static int     svcauth_unix_release(struct svc_rqst *rqstp);
+
+struct auth_ops svcauth_null = {
+       .name           = "null",
+       .flavour        = RPC_AUTH_NULL,
+       .accept         = svcauth_null_accept,
+       .release        = svcauth_null_release,
+};
+
+struct auth_ops svcauth_unix = {
+       .name           = "unix",
+       .flavour        = RPC_AUTH_UNIX,
+       .accept         = svcauth_unix_accept,
+       .release        = svcauth_unix_release,
+};
 
 /*
  * Table of authenticators
  */
-static auth_fn_t       authtab[RPC_AUTH_MAXFLAVOR] = {
-       svcauth_null,
-       svcauth_unix,
-       NULL,
+static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
+       [0] = &svcauth_null,
+       [1] = &svcauth_unix,
 };
 
-void
-svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
+int
+svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc)
 {
        rpc_authflavor_t        flavor;
-       auth_fn_t               func;
+       struct auth_ops         *aops;
 
        *statp = rpc_success;
        *authp = rpc_auth_ok;
@@ -52,21 +62,53 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
        flavor = ntohl(flavor);
 
        dprintk("svc: svc_authenticate (%d)\n", flavor);
-       if (flavor >= RPC_AUTH_MAXFLAVOR || !(func = authtab[flavor])) {
+       if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])) {
                *authp = rpc_autherr_badcred;
-               return;
+               return 0;
+       }
+
+       rqstp->rq_authop = aops;
+       switch (aops->accept(rqstp, authp, proc)) {
+       case SVC_OK:
+               return 0;
+       case SVC_GARBAGE:
+               *statp = rpc_garbage_args;
+               return 0;
+       case SVC_SYSERR:
+               *statp = rpc_system_err;
+               return 0;
+       case SVC_DENIED:
+               return 0;
+       case SVC_DROP:
+               break;
        }
+       return 1; /* drop the request */
+}
+
+/* A reqeust, which was authenticated, has now executed.
+ * Time to finalise the the credentials and verifier
+ * and release and resources
+ */
+int svc_authorise(struct svc_rqst *rqstp)
+{
+       struct auth_ops *aops = rqstp->rq_authop;
+       int rv = 0;
 
-       rqstp->rq_cred.cr_flavor = flavor;
-       func(rqstp, statp, authp);
+       rqstp->rq_authop = NULL;
+       
+       if (aops) 
+               rv = aops->release(rqstp);
+
+       /* FIXME should I count and release authops */
+       return rv;
 }
 
 int
-svc_auth_register(rpc_authflavor_t flavor, auth_fn_t func)
+svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
 {
        if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor])
                return -EINVAL;
-       authtab[flavor] = func;
+       authtab[flavor] = aops;
        return 0;
 }
 
@@ -77,25 +119,24 @@ svc_auth_unregister(rpc_authflavor_t flavor)
                authtab[flavor] = NULL;
 }
 
-static void
-svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
+static int
+svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
 {
        struct svc_buf  *argp = &rqstp->rq_argbuf;
        struct svc_buf  *resp = &rqstp->rq_resbuf;
 
        if ((argp->len -= 3) < 0) {
-               *statp = rpc_garbage_args;
-               return;
+               return SVC_GARBAGE;
        }
        if (*(argp->buf)++ != 0) {      /* we already skipped the flavor */
                dprintk("svc: bad null cred\n");
                *authp = rpc_autherr_badcred;
-               return;
+               return SVC_DENIED;
        }
        if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) {
                dprintk("svc: bad null verf\n");
                *authp = rpc_autherr_badverf;
-               return;
+               return SVC_DENIED;
        }
 
        /* Signal that mapping to nobody uid/gid is required */
@@ -104,13 +145,19 @@ svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
        rqstp->rq_cred.cr_groups[0] = NOGROUP;
 
        /* Put NULL verifier */
-       rqstp->rq_verfed = 1;
        svc_putu32(resp, RPC_AUTH_NULL);
        svc_putu32(resp, 0);
+       return SVC_OK;
+}
+
+static int
+svcauth_null_release(struct svc_rqst *rqstp)
+{
+       return 0; /* don't drop */
 }
 
-static void
-svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
+static int
+svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
 {
        struct svc_buf  *argp = &rqstp->rq_argbuf;
        struct svc_buf  *resp = &rqstp->rq_resbuf;
@@ -118,14 +165,12 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
        u32             *bufp = argp->buf, slen, i;
        int             len   = argp->len;
 
-       if ((len -= 3) < 0) {
-               *statp = rpc_garbage_args;
-               return;
-       }
+       if ((len -= 3) < 0)
+               return SVC_GARBAGE;
 
        bufp++;                                 /* length */
        bufp++;                                 /* time stamp */
-       slen = (ntohl(*bufp++) + 3) >> 2;       /* machname length */
+       slen = XDR_QUADLEN(ntohl(*bufp++));     /* machname length */
        if (slen > 64 || (len -= slen + 3) < 0)
                goto badcred;
        bufp += slen;                           /* skip machname */
@@ -144,19 +189,27 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
 
        if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) {
                *authp = rpc_autherr_badverf;
-               return;
+               return SVC_DENIED;
        }
 
        argp->buf = bufp;
        argp->len = len;
 
        /* Put NULL verifier */
-       rqstp->rq_verfed = 1;
        svc_putu32(resp, RPC_AUTH_NULL);
        svc_putu32(resp, 0);
 
-       return;
+       return SVC_OK;
 
 badcred:
        *authp = rpc_autherr_badcred;
+       return SVC_DENIED;
+}
+
+static int
+svcauth_unix_release(struct svc_rqst *rqstp)
+{
+       /* Verifier (such as it is) is already in place.
+        */
+       return 0;
 }
index 2f37164216d4059a03fef08d7612c6bd3a671fea..6319f64da31fecaca57357cbe1586ea557bae189 100644 (file)
@@ -1089,7 +1089,6 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 
        rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
        rqstp->rq_userset = 0;
-       rqstp->rq_verfed  = 0;
 
        svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid);
        svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid);