Commit 00ef0ed7 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[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.
parent 624361e4
...@@ -389,5 +389,6 @@ struct svc_program nlmsvc_program = { ...@@ -389,5 +389,6 @@ struct svc_program nlmsvc_program = {
.pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */
.pg_vers = nlmsvc_version, /* version table */ .pg_vers = nlmsvc_version, /* version table */
.pg_name = "lockd", /* service name */ .pg_name = "lockd", /* service name */
.pg_class = "nfsd", /* share authentication with nfsd */
.pg_stats = &nlmsvc_stats, /* stats table */ .pg_stats = &nlmsvc_stats, /* stats table */
}; };
...@@ -32,18 +32,12 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp) ...@@ -32,18 +32,12 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp)
fh.fh_export = NULL; fh.fh_export = NULL;
exp_readlock(); 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) { if (!nfserr) {
dget(filp->f_dentry); dget(filp->f_dentry);
mntget(filp->f_vfsmnt); mntget(filp->f_vfsmnt);
} }
fh_put(&fh); fh_put(&fh);
if (rqstp->rq_client)
auth_domain_put(rqstp->rq_client);
rqstp->rq_client = NULL; rqstp->rq_client = NULL;
exp_readunlock(); exp_readunlock();
/* nlm and nfsd don't share error codes. /* nlm and nfsd don't share error codes.
......
...@@ -103,6 +103,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -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; int data_left = fh->fh_size/4;
error = nfserr_stale; error = nfserr_stale;
if (rqstp->rq_client == NULL)
goto out;
if (rqstp->rq_vers > 2) if (rqstp->rq_vers > 2)
error = nfserr_badhandle; error = nfserr_badhandle;
if (rqstp->rq_vers == 4 && fh->fh_size == 0) if (rqstp->rq_vers == 4 && fh->fh_size == 0)
......
...@@ -206,10 +206,6 @@ nfsd(struct svc_rqst *rqstp) ...@@ -206,10 +206,6 @@ nfsd(struct svc_rqst *rqstp)
/* Lock the export hash tables for reading. */ /* Lock the export hash tables for reading. */
exp_readlock(); 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. */ /* Process request with signals blocked. */
spin_lock_irq(&current->sig->siglock); spin_lock_irq(&current->sig->siglock);
siginitsetinv(&current->blocked, ALLOWED_SIGS); siginitsetinv(&current->blocked, ALLOWED_SIGS);
...@@ -219,10 +215,6 @@ nfsd(struct svc_rqst *rqstp) ...@@ -219,10 +215,6 @@ nfsd(struct svc_rqst *rqstp)
svc_process(serv, rqstp); svc_process(serv, rqstp);
/* Unlock export hash tables */ /* Unlock export hash tables */
if (rqstp->rq_client) {
auth_domain_put(rqstp->rq_client);
rqstp->rq_client = NULL;
}
exp_readunlock(); exp_readunlock();
update_thread_usage(atomic_read(&nfsd_busy)); update_thread_usage(atomic_read(&nfsd_busy));
atomic_dec(&nfsd_busy); atomic_dec(&nfsd_busy);
...@@ -369,5 +361,6 @@ struct svc_program nfsd_program = { ...@@ -369,5 +361,6 @@ struct svc_program nfsd_program = {
.pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
.pg_vers = nfsd_version, /* version table */ .pg_vers = nfsd_version, /* version table */
.pg_name = "nfsd", /* program name */ .pg_name = "nfsd", /* program name */
.pg_class = "nfsd", /* authentication class */
.pg_stats = &nfsd_svcstats, /* version table */ .pg_stats = &nfsd_svcstats, /* version table */
}; };
...@@ -154,7 +154,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -154,7 +154,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
struct dentry *mounts = dget(dentry); struct dentry *mounts = dget(dentry);
while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)) 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)) { if (exp2 && EX_CROSSMNT(exp2)) {
/* successfully crossed mount point */ /* successfully crossed mount point */
exp = exp2; exp = exp2;
......
...@@ -142,6 +142,7 @@ struct svc_program { ...@@ -142,6 +142,7 @@ struct svc_program {
unsigned int pg_nvers; /* number of versions */ unsigned int pg_nvers; /* number of versions */
struct svc_version ** pg_vers; /* version array */ struct svc_version ** pg_vers; /* version array */
char * pg_name; /* service name */ char * pg_name; /* service name */
char * pg_class; /* class name: services sharing authentication */
struct svc_stat * pg_stats; /* rpc statistics */ struct svc_stat * pg_stats; /* rpc statistics */
}; };
......
...@@ -201,6 +201,8 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc) ...@@ -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 *argp = &rqstp->rq_argbuf;
struct svc_buf *resp = &rqstp->rq_resbuf; struct svc_buf *resp = &rqstp->rq_resbuf;
int rv=0;
struct ip_map key, *ipm;
if ((argp->len -= 3) < 0) { if ((argp->len -= 3) < 0) {
return SVC_GARBAGE; return SVC_GARBAGE;
...@@ -224,12 +226,45 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc) ...@@ -224,12 +226,45 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
/* Put NULL verifier */ /* Put NULL verifier */
svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, RPC_AUTH_NULL);
svc_putu32(resp, 0); 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 static int
svcauth_null_release(struct svc_rqst *rqstp) 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 */ return 0; /* don't drop */
} }
...@@ -250,6 +285,8 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc) ...@@ -250,6 +285,8 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
struct svc_cred *cred = &rqstp->rq_cred; struct svc_cred *cred = &rqstp->rq_cred;
u32 *bufp = argp->buf, slen, i; u32 *bufp = argp->buf, slen, i;
int len = argp->len; int len = argp->len;
int rv=0;
struct ip_map key, *ipm;
if ((len -= 3) < 0) if ((len -= 3) < 0)
return SVC_GARBAGE; return SVC_GARBAGE;
...@@ -285,7 +322,34 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc) ...@@ -285,7 +322,34 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
svc_putu32(resp, RPC_AUTH_NULL); svc_putu32(resp, RPC_AUTH_NULL);
svc_putu32(resp, 0); 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: badcred:
*authp = rpc_autherr_badcred; *authp = rpc_autherr_badcred;
...@@ -297,6 +361,10 @@ svcauth_unix_release(struct svc_rqst *rqstp) ...@@ -297,6 +361,10 @@ svcauth_unix_release(struct svc_rqst *rqstp)
{ {
/* Verifier (such as it is) is already in place. /* 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; return 0;
} }
......
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