From: NeilBrown 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 Signed-off-by: Neil Brown Signed-off-by: Andrew Morton --- 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 */ _