From: NeilBrown <neilb@cse.unsw.edu.au>

svcauth_null_accept() and svcauth_unix_accept() are currently hard-wired to
check the source ip address on an incoming request against the export table,
which make sense for nfsd but not necessarily for other rpc-based services.

So instead we have the accept() method call a program-specific
pg_authenticate() method.  We also move the call to this method into
svc_process instead of calling it from the flavor-specific accept() routines.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/lockd/svc.c                    |   15 +++++++++++++++
 25-akpm/fs/nfsd/nfssvc.c                  |    2 ++
 25-akpm/include/linux/sunrpc/svc.h        |    1 +
 25-akpm/net/sunrpc/auth_gss/svcauth_gss.c |    9 ++-------
 25-akpm/net/sunrpc/svc.c                  |   12 +++++++++++-
 25-akpm/net/sunrpc/svcauth_unix.c         |   18 ++----------------
 6 files changed, 33 insertions(+), 24 deletions(-)

diff -puN fs/lockd/svc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method fs/lockd/svc.c
--- 25/fs/lockd/svc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/fs/lockd/svc.c	2005-02-07 19:19:08.000000000 -0800
@@ -403,6 +403,20 @@ static int param_set_##name(const char *
 	return 0;							\
 }
 
+static int lockd_authenticate(struct svc_rqst *rqstp)
+{
+	rqstp->rq_client = NULL;
+	switch (rqstp->rq_authop->flavour) {
+		case RPC_AUTH_NULL:
+		case RPC_AUTH_UNIX:
+			if (rqstp->rq_proc == 0)
+				return SVC_OK;
+			return svc_set_client(rqstp);
+	}
+	return SVC_DENIED;
+}
+
+
 param_set_min_max(port, int, simple_strtol, 0, 65535)
 param_set_min_max(grace_period, unsigned long, simple_strtoul,
 		  nlm_grace_period_min, nlm_grace_period_max)
@@ -483,4 +497,5 @@ static struct svc_program	nlmsvc_program
 	.pg_name		= "lockd",		/* service name */
 	.pg_class		= "nfsd",		/* share authentication with nfsd */
 	.pg_stats		= &nlmsvc_stats,	/* stats table */
+	.pg_authenticate = &lockd_authenticate	/* export authentication */
 };
diff -puN fs/nfsd/nfssvc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method fs/nfsd/nfssvc.c
--- 25/fs/nfsd/nfssvc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/fs/nfsd/nfssvc.c	2005-02-07 19:19:08.000000000 -0800
@@ -378,4 +378,6 @@ struct svc_program		nfsd_program = {
 	.pg_name		= "nfsd",		/* program name */
 	.pg_class		= "nfsd",		/* authentication class */
 	.pg_stats		= &nfsd_svcstats,	/* version table */
+	.pg_authenticate	= &svc_set_client,	/* export authentication */
+
 };
diff -puN include/linux/sunrpc/svc.h~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method include/linux/sunrpc/svc.h
--- 25/include/linux/sunrpc/svc.h~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/include/linux/sunrpc/svc.h	2005-02-07 19:19:08.000000000 -0800
@@ -253,6 +253,7 @@ struct svc_program {
 	struct svc_stat *	pg_stats;	/* rpc statistics */
 	/* Override authentication. NULL means use default */
 	int			(*pg_authenticate_obsolete)(struct svc_rqst *, u32 *);
+	int			(*pg_authenticate)(struct svc_rqst *);
 };
 
 /*
diff -puN net/sunrpc/auth_gss/svcauth_gss.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method net/sunrpc/auth_gss/svcauth_gss.c
--- 25/net/sunrpc/auth_gss/svcauth_gss.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/svcauth_gss.c	2005-02-07 19:19:08.000000000 -0800
@@ -906,11 +906,6 @@ svcauth_gss_accept(struct svc_rqst *rqst
 		svc_putu32(resv, rpc_success);
 		goto complete;
 	case RPC_GSS_PROC_DATA:
-		*authp = rpc_autherr_badcred;
-		rqstp->rq_client =
-			find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
-		if (rqstp->rq_client == NULL)
-			goto auth_err;
 		*authp = rpcsec_gsserr_ctxproblem;
 		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
 			goto auth_err;
@@ -924,8 +919,6 @@ svcauth_gss_accept(struct svc_rqst *rqst
 			if (unwrap_integ_data(&rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
 				goto auth_err;
-			svcdata->rsci = rsci;
-			cache_get(&rsci->h);
 			/* placeholders for length and seq. number: */
 			svcdata->body_start = resv->iov_base + resv->iov_len;
 			svc_putu32(resv, 0);
@@ -936,6 +929,8 @@ svcauth_gss_accept(struct svc_rqst *rqst
 		default:
 			goto auth_err;
 		}
+		svcdata->rsci = rsci;
+		cache_get(&rsci->h);
 		ret = SVC_OK;
 		goto out;
 	}
diff -puN net/sunrpc/svcauth_unix.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method net/sunrpc/svcauth_unix.c
--- 25/net/sunrpc/svcauth_unix.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/net/sunrpc/svcauth_unix.c	2005-02-07 19:19:08.000000000 -0800
@@ -368,7 +368,6 @@ svcauth_null_accept(struct svc_rqst *rqs
 	struct kvec	*argv = &rqstp->rq_arg.head[0];
 	struct kvec	*resv = &rqstp->rq_res.head[0];
 	struct svc_cred	*cred = &rqstp->rq_cred;
-	int		rv=0;
 
 	cred->cr_group_info = NULL;
 	rqstp->rq_client = NULL;
@@ -394,19 +393,11 @@ svcauth_null_accept(struct svc_rqst *rqs
 	if (cred->cr_group_info == NULL)
 		return SVC_DROP; /* kmalloc failure - client must retry */
 
-	rv = svcauth_unix_set_client(rqstp);
-	if (rv == SVC_DENIED)
-		goto badcred;
-
 	/* Put NULL verifier */
 	svc_putu32(resv, RPC_AUTH_NULL);
 	svc_putu32(resv, 0);
 
-	return rv;
-
-badcred:
-	*authp = rpc_autherr_badcred;
-	return SVC_DENIED;
+	return SVC_OK;
 }
 
 static int
@@ -441,7 +432,6 @@ svcauth_unix_accept(struct svc_rqst *rqs
 	struct svc_cred	*cred = &rqstp->rq_cred;
 	u32		slen, i;
 	int		len   = argv->iov_len;
-	int		rv=0;
 
 	cred->cr_group_info = NULL;
 	rqstp->rq_client = NULL;
@@ -473,15 +463,11 @@ svcauth_unix_accept(struct svc_rqst *rqs
 		return SVC_DENIED;
 	}
 
-	rv = svcauth_unix_set_client(rqstp);
-	if (rv == SVC_DENIED)
-		goto badcred;
-
 	/* Put NULL verifier */
 	svc_putu32(resv, RPC_AUTH_NULL);
 	svc_putu32(resv, 0);
 
-	return rv;
+	return SVC_OK;
 
 badcred:
 	*authp = rpc_autherr_badcred;
diff -puN net/sunrpc/svc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method net/sunrpc/svc.c
--- 25/net/sunrpc/svc.c~nfsd--svcrpc-move-export-table-checks-to-a-per-program-pg_add_client-method	2005-02-07 19:19:08.000000000 -0800
+++ 25-akpm/net/sunrpc/svc.c	2005-02-07 19:19:08.000000000 -0800
@@ -264,6 +264,7 @@ svc_process(struct svc_serv *serv, struc
 	u32			dir, prog, vers, proc,
 				auth_stat, rpc_stat;
 	int			auth_res;
+	u32			*accept_statp;
 
 	rpc_stat = rpc_success;
 
@@ -299,6 +300,9 @@ svc_process(struct svc_serv *serv, struc
 	if (vers != 2)		/* RPC version number */
 		goto err_bad_rpc;
 
+	/* Save position in case we later decide to reject: */
+	accept_statp = resv->iov_base + resv->iov_len;
+
 	svc_putu32(resv, xdr_zero);		/* ACCEPT */
 
 	rqstp->rq_prog = prog = ntohl(svc_getu32(argv));	/* program number */
@@ -315,6 +319,11 @@ svc_process(struct svc_serv *serv, struc
 		auth_res = progp->pg_authenticate_obsolete(rqstp, &auth_stat);
 	else
 		auth_res = svc_authenticate(rqstp, &auth_stat);
+	/* Also give the program a chance to reject this call: */
+	if (auth_res == SVC_OK) {
+		auth_stat = rpc_autherr_badcred;
+		auth_res = progp->pg_authenticate(rqstp);
+	}
 	switch (auth_res) {
 	case SVC_OK:
 		break;
@@ -437,7 +446,8 @@ err_bad_rpc:
 err_bad_auth:
 	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
 	serv->sv_stats->rpcbadauth++;
-	resv->iov_len -= 4;
+	/* Restore write pointer to location of accept status: */
+	xdr_ressize_check(rqstp, accept_statp);
 	svc_putu32(resv, xdr_one);	/* REJECT */
 	svc_putu32(resv, xdr_one);	/* AUTH_ERROR */
 	svc_putu32(resv, auth_stat);	/* status */
_