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)
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 */
......
......@@ -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 */
};
/*
......
......@@ -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__ */
......
......@@ -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;
......
......@@ -19,31 +19,41 @@
#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_cred.cr_flavor = flavor;
func(rqstp, statp, authp);
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_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;
}
......@@ -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);
......
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