summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2002-10-11 05:39:15 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-10-11 05:39:15 -0700
commit7b1c5134432d8d9eff53094ce27bd153e401dbfd (patch)
treeacfff167ad52c7ba05c64500532982003e8cea4e
parentbc9ff117c1bc6a879fced39d09fae033d21b7d67 (diff)
[PATCH] kNFSd: Tidy up the rpc authentication interface.
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.
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--include/linux/sunrpc/svc.h9
-rw-r--r--include/linux/sunrpc/svcauth.h66
-rw-r--r--net/sunrpc/svc.c18
-rw-r--r--net/sunrpc/svcauth.c127
-rw-r--r--net/sunrpc/svcsock.c1
6 files changed, 152 insertions, 71 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 2d53b16ace71..6fb1615279c2 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -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 */
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index e1ed17ddc419..e4a2bdc0b87c 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -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 */
};
/*
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 83aa079fe2f3..0852b50ff63d 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -14,34 +14,64 @@
#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__ */
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index d3acb5c21001..c831adc8b6ec 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -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;
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 8313d0de5d77..d0ecfb73a09a 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -20,30 +20,40 @@
#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;
}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 2f37164216d4..6319f64da31f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -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);