Commit 7b1c5134 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[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.
parent bc9ff117
...@@ -173,8 +173,6 @@ nfsd(struct svc_rqst *rqstp) ...@@ -173,8 +173,6 @@ nfsd(struct svc_rqst *rqstp)
current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
nfsdstats.th_cnt++; nfsdstats.th_cnt++;
/* Let svc_process check client's authentication. */
rqstp->rq_auth = 1;
lockd_up(); /* start lockd */ lockd_up(); /* start lockd */
......
...@@ -98,6 +98,7 @@ struct svc_rqst { ...@@ -98,6 +98,7 @@ struct svc_rqst {
struct svc_serv * rq_server; /* RPC service definition */ struct svc_serv * rq_server; /* RPC service definition */
struct svc_procedure * rq_procinfo; /* procedure info */ struct svc_procedure * rq_procinfo; /* procedure info */
struct auth_ops * rq_authop; /* authentication flavour */
struct svc_cred rq_cred; /* auth info */ struct svc_cred rq_cred; /* auth info */
struct sk_buff * rq_skbuff; /* fast recv inet buffer */ struct sk_buff * rq_skbuff; /* fast recv inet buffer */
struct svc_buf rq_defbuf; /* default buffer */ struct svc_buf rq_defbuf; /* default buffer */
...@@ -108,10 +109,10 @@ struct svc_rqst { ...@@ -108,10 +109,10 @@ struct svc_rqst {
u32 rq_vers; /* program version */ u32 rq_vers; /* program version */
u32 rq_proc; /* procedure number */ u32 rq_proc; /* procedure number */
u32 rq_prot; /* IP protocol */ u32 rq_prot; /* IP protocol */
unsigned short rq_verfed : 1, /* reply has verifier */ unsigned short
rq_userset : 1, /* auth->setuser OK */ rq_userset : 1, /* auth->setuser OK */
rq_secure : 1, /* secure port */ rq_secure : 1; /* secure port */
rq_auth : 1; /* check client */
void * rq_argp; /* decoded arguments */ void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */ void * rq_resp; /* xdr'd results */
...@@ -128,7 +129,7 @@ struct svc_rqst { ...@@ -128,7 +129,7 @@ struct svc_rqst {
* to report (real or virtual) * to report (real or virtual)
*/ */
wait_queue_head_t rq_wait; /* synchronozation */ wait_queue_head_t rq_wait; /* synchronization */
}; };
/* /*
......
...@@ -14,34 +14,64 @@ ...@@ -14,34 +14,64 @@
#include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/msg_prot.h>
struct svc_cred { struct svc_cred {
rpc_authflavor_t cr_flavor;
uid_t cr_uid; uid_t cr_uid;
gid_t cr_gid; gid_t cr_gid;
gid_t cr_groups[NGROUPS]; gid_t cr_groups[NGROUPS];
}; };
struct svc_rqst; /* forward decl */ 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 auth_ops {
struct authunix_parms { char * name;
u32 aup_stamp; int flavour;
u32 aup_uid; int (*accept)(struct svc_rqst *rq, u32 *authp, int proc);
u32 aup_gid; int (*release)(struct svc_rqst *rq);
u32 aup_len;
u32 aup_gids[NGRPS];
}; };
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); extern int svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc);
#endif 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__ */ #endif /* __KERNEL__ */
......
...@@ -262,18 +262,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) ...@@ -262,18 +262,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
argp->buf += 5; argp->buf += 5;
argp->len -= 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. * Decode auth data, and add verifier to reply buffer.
* We do this before anything else in order to get a decent * We do this before anything else in order to get a decent
* auth verifier. * 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) if (rpc_stat != rpc_success)
goto err_garbage; goto err_garbage;
...@@ -347,10 +343,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) ...@@ -347,10 +343,14 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
if (procp->pc_encode == NULL) if (procp->pc_encode == NULL)
goto dropit; goto dropit;
sendit:
sendit:
if (svc_authorise(rqstp))
goto dropit;
return svc_send(rqstp); return svc_send(rqstp);
dropit: dropit:
svc_authorise(rqstp); /* doesn't hurt to call this twice */
dprintk("svc: svc_process dropit\n"); dprintk("svc: svc_process dropit\n");
svc_drop(rqstp); svc_drop(rqstp);
return 0; return 0;
......
...@@ -19,31 +19,41 @@ ...@@ -19,31 +19,41 @@
#define RPCDBG_FACILITY RPCDBG_AUTH #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 * Builtin auth flavors
*/ */
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);
static void svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp); 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 * Table of authenticators
*/ */
static auth_fn_t authtab[RPC_AUTH_MAXFLAVOR] = { static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
svcauth_null, [0] = &svcauth_null,
svcauth_unix, [1] = &svcauth_unix,
NULL,
}; };
void int
svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp) svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc)
{ {
rpc_authflavor_t flavor; rpc_authflavor_t flavor;
auth_fn_t func; struct auth_ops *aops;
*statp = rpc_success; *statp = rpc_success;
*authp = rpc_auth_ok; *authp = rpc_auth_ok;
...@@ -52,21 +62,53 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp) ...@@ -52,21 +62,53 @@ svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
flavor = ntohl(flavor); flavor = ntohl(flavor);
dprintk("svc: svc_authenticate (%d)\n", 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; *authp = rpc_autherr_badcred;
return; return 0;
} }
rqstp->rq_cred.cr_flavor = flavor; rqstp->rq_authop = aops;
func(rqstp, statp, authp); 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_authop = NULL;
if (aops)
rv = aops->release(rqstp);
/* FIXME should I count and release authops */
return rv;
} }
int 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]) if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor])
return -EINVAL; return -EINVAL;
authtab[flavor] = func; authtab[flavor] = aops;
return 0; return 0;
} }
...@@ -77,25 +119,24 @@ svc_auth_unregister(rpc_authflavor_t flavor) ...@@ -77,25 +119,24 @@ svc_auth_unregister(rpc_authflavor_t flavor)
authtab[flavor] = NULL; authtab[flavor] = NULL;
} }
static void static int
svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp) svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
{ {
struct svc_buf *argp = &rqstp->rq_argbuf; struct svc_buf *argp = &rqstp->rq_argbuf;
struct svc_buf *resp = &rqstp->rq_resbuf; struct svc_buf *resp = &rqstp->rq_resbuf;
if ((argp->len -= 3) < 0) { if ((argp->len -= 3) < 0) {
*statp = rpc_garbage_args; return SVC_GARBAGE;
return;
} }
if (*(argp->buf)++ != 0) { /* we already skipped the flavor */ if (*(argp->buf)++ != 0) { /* we already skipped the flavor */
dprintk("svc: bad null cred\n"); dprintk("svc: bad null cred\n");
*authp = rpc_autherr_badcred; *authp = rpc_autherr_badcred;
return; return SVC_DENIED;
} }
if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) { if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) {
dprintk("svc: bad null verf\n"); dprintk("svc: bad null verf\n");
*authp = rpc_autherr_badverf; *authp = rpc_autherr_badverf;
return; return SVC_DENIED;
} }
/* Signal that mapping to nobody uid/gid is required */ /* Signal that mapping to nobody uid/gid is required */
...@@ -104,13 +145,19 @@ svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp) ...@@ -104,13 +145,19 @@ svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
rqstp->rq_cred.cr_groups[0] = NOGROUP; rqstp->rq_cred.cr_groups[0] = NOGROUP;
/* Put NULL verifier */ /* Put NULL verifier */
rqstp->rq_verfed = 1;
svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, RPC_AUTH_NULL);
svc_putu32(resp, 0); svc_putu32(resp, 0);
return SVC_OK;
}
static int
svcauth_null_release(struct svc_rqst *rqstp)
{
return 0; /* don't drop */
} }
static void static int
svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp) svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
{ {
struct svc_buf *argp = &rqstp->rq_argbuf; struct svc_buf *argp = &rqstp->rq_argbuf;
struct svc_buf *resp = &rqstp->rq_resbuf; struct svc_buf *resp = &rqstp->rq_resbuf;
...@@ -118,14 +165,12 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp) ...@@ -118,14 +165,12 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
u32 *bufp = argp->buf, slen, i; u32 *bufp = argp->buf, slen, i;
int len = argp->len; int len = argp->len;
if ((len -= 3) < 0) { if ((len -= 3) < 0)
*statp = rpc_garbage_args; return SVC_GARBAGE;
return;
}
bufp++; /* length */ bufp++; /* length */
bufp++; /* time stamp */ bufp++; /* time stamp */
slen = (ntohl(*bufp++) + 3) >> 2; /* machname length */ slen = XDR_QUADLEN(ntohl(*bufp++)); /* machname length */
if (slen > 64 || (len -= slen + 3) < 0) if (slen > 64 || (len -= slen + 3) < 0)
goto badcred; goto badcred;
bufp += slen; /* skip machname */ bufp += slen; /* skip machname */
...@@ -144,19 +189,27 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp) ...@@ -144,19 +189,27 @@ svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) { if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) {
*authp = rpc_autherr_badverf; *authp = rpc_autherr_badverf;
return; return SVC_DENIED;
} }
argp->buf = bufp; argp->buf = bufp;
argp->len = len; argp->len = len;
/* Put NULL verifier */ /* Put NULL verifier */
rqstp->rq_verfed = 1;
svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, RPC_AUTH_NULL);
svc_putu32(resp, 0); svc_putu32(resp, 0);
return; return SVC_OK;
badcred: badcred:
*authp = rpc_autherr_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;
} }
...@@ -1089,7 +1089,6 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) ...@@ -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_secure = ntohs(rqstp->rq_addr.sin_port) < 1024;
rqstp->rq_userset = 0; rqstp->rq_userset = 0;
rqstp->rq_verfed = 0;
svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid); svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid);
svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid); svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment