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 = {
.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 */
};
......@@ -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.
......
......@@ -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)
......
......@@ -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(&current->sig->siglock);
siginitsetinv(&current->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 */
};
......@@ -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;
......
......@@ -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 */
};
......
......@@ -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;
}
......
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