diff options
| author | Neil Brown <neilb@cse.unsw.edu.au> | 2002-10-11 05:39:30 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-10-11 05:39:30 -0700 |
| commit | 00ef0ed798300f080b767bddea0ef143e5aa9419 (patch) | |
| tree | a9ffc62b678e3fedd9d644503071169ee89804d3 | |
| parent | 624361e43a7f518101fe4b5277aa1ad7a1fe6028 (diff) | |
[PATCH] kNFSd: Move auth domain lookup into svcauth
Instead of doing the lookup from ipaddr to domain inside
the nfs server, (and also when lockd calls into nfsd) it is
now done at the rpc authentication level which is a more
sensible place for it.
Note that both AUTH_UNIX and AUTH_NULL do the same lookup.
So that the rpc layer knows that nfsd and lockd both uses the
name space of domains (while other hypothetical services may
not) we introduce a 'class' for each service which svc_auth combines
with the IP address when doing a lookup.
| -rw-r--r-- | fs/lockd/svc.c | 1 | ||||
| -rw-r--r-- | fs/nfsd/lockd.c | 8 | ||||
| -rw-r--r-- | fs/nfsd/nfsfh.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 9 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc.h | 1 | ||||
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 72 |
7 files changed, 77 insertions, 18 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index cfef0f0feff8..1f515cfb294b 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -389,5 +389,6 @@ struct svc_program nlmsvc_program = { .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ .pg_vers = nlmsvc_version, /* version table */ .pg_name = "lockd", /* service name */ + .pg_class = "nfsd", /* share authentication with nfsd */ .pg_stats = &nlmsvc_stats, /* stats table */ }; diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index a3f9df90d9f2..5da1ed2e8ccd 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -32,18 +32,12 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp) fh.fh_export = NULL; exp_readlock(); - rqstp->rq_client = exp_getclient(&rqstp->rq_addr); - if (rqstp->rq_client == NULL) - nfserr = nfserr_stale; - else - nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp); + nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp); if (!nfserr) { dget(filp->f_dentry); mntget(filp->f_vfsmnt); } fh_put(&fh); - if (rqstp->rq_client) - auth_domain_put(rqstp->rq_client); rqstp->rq_client = NULL; exp_readunlock(); /* nlm and nfsd don't share error codes. diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 70d84e36fadc..d3f021582efd 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -103,6 +103,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) int data_left = fh->fh_size/4; error = nfserr_stale; + if (rqstp->rq_client == NULL) + goto out; if (rqstp->rq_vers > 2) error = nfserr_badhandle; if (rqstp->rq_vers == 4 && fh->fh_size == 0) diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 65f455e529ba..1044a94d69ae 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -206,10 +206,6 @@ nfsd(struct svc_rqst *rqstp) /* Lock the export hash tables for reading. */ exp_readlock(); - /* Validate the client's address. This will also defeat - * port probes on port 2049 by unauthorized clients. - */ - rqstp->rq_client = exp_getclient(&rqstp->rq_addr); /* Process request with signals blocked. */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked, ALLOWED_SIGS); @@ -219,10 +215,6 @@ nfsd(struct svc_rqst *rqstp) svc_process(serv, rqstp); /* Unlock export hash tables */ - if (rqstp->rq_client) { - auth_domain_put(rqstp->rq_client); - rqstp->rq_client = NULL; - } exp_readunlock(); update_thread_usage(atomic_read(&nfsd_busy)); atomic_dec(&nfsd_busy); @@ -369,5 +361,6 @@ struct svc_program nfsd_program = { .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ .pg_vers = nfsd_version, /* version table */ .pg_name = "nfsd", /* program name */ + .pg_class = "nfsd", /* authentication class */ .pg_stats = &nfsd_svcstats, /* version table */ }; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 61c7bd03d3f0..7069a472a095 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -154,7 +154,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, struct dentry *mounts = dget(dentry); while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)) ; - exp2 = exp_get_by_name(rqstp->rq_client, mnt, mounts); + exp2 = exp_get_by_name(exp->ex_client, mnt, mounts); if (exp2 && EX_CROSSMNT(exp2)) { /* successfully crossed mount point */ exp = exp2; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 57c5a49d2b0a..95e6b8d20fd1 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -142,6 +142,7 @@ struct svc_program { unsigned int pg_nvers; /* number of versions */ struct svc_version ** pg_vers; /* version array */ char * pg_name; /* service name */ + char * pg_class; /* class name: services sharing authentication */ struct svc_stat * pg_stats; /* rpc statistics */ }; diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index c5e7e20c44c4..ce13795dcbcb 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -201,6 +201,8 @@ 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; + int rv=0; + struct ip_map key, *ipm; if ((argp->len -= 3) < 0) { return SVC_GARBAGE; @@ -224,12 +226,45 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc) /* Put NULL verifier */ svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, 0); - return SVC_OK; + + key.m_class = rqstp->rq_server->sv_program->pg_class; + key.m_addr = rqstp->rq_addr.sin_addr; + + ipm = ip_map_lookup(&key, 0); + + rqstp->rq_client = NULL; + + if (ipm) + switch (cache_check(&ip_map_cache, &ipm->h)) { + case -EAGAIN: + rv = SVC_DROP; + break; + case -ENOENT: + rv = SVC_OK; /* rq_client is NULL */ + break; + case 0: + rqstp->rq_client = &ipm->m_client->h; + cache_get(&rqstp->rq_client->h); + ip_map_put(&ipm->h, &ip_map_cache); + rv = SVC_OK; + break; + default: BUG(); + } + else rv = SVC_DROP; + + if (rqstp->rq_client == NULL && proc != 0) + *authp = rpc_autherr_badcred; + + return rv; } static int svcauth_null_release(struct svc_rqst *rqstp) { + if (rqstp->rq_client) + auth_domain_put(rqstp->rq_client); + rqstp->rq_client = NULL; + return 0; /* don't drop */ } @@ -250,6 +285,8 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc) struct svc_cred *cred = &rqstp->rq_cred; u32 *bufp = argp->buf, slen, i; int len = argp->len; + int rv=0; + struct ip_map key, *ipm; if ((len -= 3) < 0) return SVC_GARBAGE; @@ -285,7 +322,34 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc) svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, 0); - return SVC_OK; + key.m_class = rqstp->rq_server->sv_program->pg_class; + key.m_addr = rqstp->rq_addr.sin_addr; + + ipm = ip_map_lookup(&key, 0); + + rqstp->rq_client = NULL; + + if (ipm) + switch (cache_check(&ip_map_cache, &ipm->h)) { + case -EAGAIN: + rv = SVC_DROP; + break; + case -ENOENT: + rv = SVC_OK; /* rq_client is NULL */ + break; + case 0: + rqstp->rq_client = &ipm->m_client->h; + cache_get(&rqstp->rq_client->h); + ip_map_put(&ipm->h, &ip_map_cache); + rv = SVC_OK; + break; + default: BUG(); + } + else rv = SVC_DROP; + + if (rqstp->rq_client == NULL && proc != 0) + goto badcred; + return rv; badcred: *authp = rpc_autherr_badcred; @@ -297,6 +361,10 @@ svcauth_unix_release(struct svc_rqst *rqstp) { /* Verifier (such as it is) is already in place. */ + if (rqstp->rq_client) + auth_domain_put(rqstp->rq_client); + rqstp->rq_client = NULL; + return 0; } |
