Commit 778be232 authored by Andy Adamson's avatar Andy Adamson Committed by Trond Myklebust

NFS do not find client in NFSv4 pg_authenticate

The information required to find the nfs_client cooresponding to the incoming
back channel request is contained in the NFS layer. Perform minimal checking
in the RPC layer pg_authenticate method, and push more detailed checking into
the NFS layer where the nfs_client can be found.
Signed-off-by: default avatarAndy Adamson <andros@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 80c30e8d
...@@ -134,33 +134,6 @@ nfs4_callback_up(struct svc_serv *serv) ...@@ -134,33 +134,6 @@ nfs4_callback_up(struct svc_serv *serv)
} }
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
/*
* * CB_SEQUENCE operations will fail until the callback sessionid is set.
* */
int nfs4_set_callback_sessionid(struct nfs_client *clp)
{
struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv;
struct nfs4_sessionid *bc_sid;
if (!serv->sv_bc_xprt)
return -EINVAL;
/* on success freed in xprt_free */
bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL);
if (!bc_sid)
return -ENOMEM;
memcpy(bc_sid->data, &clp->cl_session->sess_id.data,
NFS4_MAX_SESSIONID_LEN);
spin_lock_bh(&serv->sv_cb_lock);
serv->sv_bc_xprt->xpt_bc_sid = bc_sid;
spin_unlock_bh(&serv->sv_cb_lock);
dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__,
((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1],
((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3],
serv->sv_bc_xprt);
return 0;
}
/* /*
* The callback service for NFSv4.1 callbacks * The callback service for NFSv4.1 callbacks
*/ */
...@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, ...@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
struct nfs_callback_data *cb_info) struct nfs_callback_data *cb_info)
{ {
} }
int nfs4_set_callback_sessionid(struct nfs_client *clp)
{
return 0;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
/* /*
...@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion) ...@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion)
mutex_unlock(&nfs_callback_mutex); mutex_unlock(&nfs_callback_mutex);
} }
static int check_gss_callback_principal(struct nfs_client *clp, /* Boolean check of RPC_AUTH_GSS principal */
struct svc_rqst *rqstp) int
check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
{ {
struct rpc_clnt *r = clp->cl_rpcclient; struct rpc_clnt *r = clp->cl_rpcclient;
char *p = svc_gss_principal(rqstp); char *p = svc_gss_principal(rqstp);
if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
return 1;
/* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
if (clp->cl_minorversion != 0) if (clp->cl_minorversion != 0)
return SVC_DROP; return 0;
/* /*
* It might just be a normal user principal, in which case * It might just be a normal user principal, in which case
* userspace won't bother to tell us the name at all. * userspace won't bother to tell us the name at all.
*/ */
if (p == NULL) if (p == NULL)
return SVC_DENIED; return 0;
/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
if (memcmp(p, "nfs@", 4) != 0) if (memcmp(p, "nfs@", 4) != 0)
return SVC_DENIED; return 0;
p += 4; p += 4;
if (strcmp(p, r->cl_server) != 0) if (strcmp(p, r->cl_server) != 0)
return SVC_DENIED; return 0;
return SVC_OK; return 1;
} }
/* pg_authenticate method helper */ /*
static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp) * pg_authenticate method for nfsv4 callback threads.
{ *
struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp); * The authflavor has been negotiated, so an incorrect flavor is a server
int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0; * bug. Drop packets with incorrect authflavor.
*
dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc); * All other checking done after NFS decoding where the nfs_client can be
if (svc_is_backchannel(rqstp)) * found in nfs4_callback_compound
/* Sessionid (usually) set after CB_NULL ping */ */
return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid,
is_cb_compound);
else
/* No callback identifier in pg_authenticate */
return nfs4_find_client_no_ident(svc_addr(rqstp));
}
/* pg_authenticate method for nfsv4 callback threads. */
static int nfs_callback_authenticate(struct svc_rqst *rqstp) static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{ {
struct nfs_client *clp;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
int ret = SVC_OK;
/* Don't talk to strangers */
clp = nfs_cb_find_client(rqstp);
if (clp == NULL)
return SVC_DROP;
dprintk("%s: %s NFSv4 callback!\n", __func__,
svc_print_addr(rqstp, buf, sizeof(buf)));
switch (rqstp->rq_authop->flavour) { switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL: case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL) if (rqstp->rq_proc != CB_NULL)
ret = SVC_DENIED; return SVC_DROP;
break; break;
case RPC_AUTH_UNIX: case RPC_AUTH_GSS:
break; /* No RPC_AUTH_GSS support yet in NFSv4.1 */
case RPC_AUTH_GSS: if (svc_is_backchannel(rqstp))
ret = check_gss_callback_principal(clp, rqstp); return SVC_DROP;
break;
default:
ret = SVC_DENIED;
} }
nfs_put_client(clp); return SVC_OK;
return ret;
} }
/* /*
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#ifndef __LINUX_FS_NFS_CALLBACK_H #ifndef __LINUX_FS_NFS_CALLBACK_H
#define __LINUX_FS_NFS_CALLBACK_H #define __LINUX_FS_NFS_CALLBACK_H
#include <linux/sunrpc/svc.h>
#define NFS4_CALLBACK 0x40000000 #define NFS4_CALLBACK 0x40000000
#define NFS4_CALLBACK_XDRSIZE 2048 #define NFS4_CALLBACK_XDRSIZE 2048
...@@ -37,7 +38,6 @@ enum nfs4_callback_opnum { ...@@ -37,7 +38,6 @@ enum nfs4_callback_opnum {
struct cb_process_state { struct cb_process_state {
__be32 drc_status; __be32 drc_status;
struct nfs_client *clp; struct nfs_client *clp;
struct nfs4_sessionid *svc_sid; /* v4.1 callback service sessionid */
}; };
struct cb_compound_hdr_arg { struct cb_compound_hdr_arg {
...@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall( ...@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall(
extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
extern void nfs4_cb_take_slot(struct nfs_client *clp); extern void nfs4_cb_take_slot(struct nfs_client *clp);
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
struct cb_getattrres *res, struct cb_getattrres *res,
struct cb_process_state *cps); struct cb_process_state *cps);
......
...@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, ...@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
{ {
struct nfs_client *clp; struct nfs_client *clp;
int i; int i;
__be32 status; __be32 status = htonl(NFS4ERR_BADSESSION);
cps->clp = NULL; cps->clp = NULL;
status = htonl(NFS4ERR_BADSESSION); clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
/* Incoming session must match the callback session */
if (memcmp(&args->csa_sessionid, cps->svc_sid, NFS4_MAX_SESSIONID_LEN))
goto out;
clp = nfs4_find_client_sessionid(args->csa_addr,
&args->csa_sessionid, 1);
if (clp == NULL) if (clp == NULL)
goto out; goto out;
......
...@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r ...@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
if (hdr_arg.minorversion == 0) { if (hdr_arg.minorversion == 0) {
cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
if (!cps.clp) if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
return rpc_drop_reply; return rpc_drop_reply;
} else }
cps.svc_sid = bc_xprt_sid(rqstp);
hdr_res.taglen = hdr_arg.taglen; hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag; hdr_res.tag = hdr_arg.tag;
......
...@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident) ...@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident)
* For CB_COMPOUND calls, find a client by IP address, protocol version, * For CB_COMPOUND calls, find a client by IP address, protocol version,
* minorversion, and sessionID * minorversion, and sessionID
* *
* CREATE_SESSION triggers a CB_NULL ping from servers. The callback service
* sessionid can only be set after the CREATE_SESSION return, so a CB_NULL
* can arrive before the callback sessionid is set. For CB_NULL calls,
* find a client by IP address protocol version, and minorversion.
*
* Returns NULL if no such client * Returns NULL if no such client
*/ */
struct nfs_client * struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr, nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound) struct nfs4_sessionid *sid)
{ {
struct nfs_client *clp; struct nfs_client *clp;
...@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, ...@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
if (!nfs4_has_session(clp)) if (!nfs4_has_session(clp))
continue; continue;
/* Match sessionid unless cb_null call*/ /* Match sessionid*/
if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data, if (memcmp(clp->cl_session->sess_id.data,
sid->data, NFS4_MAX_SESSIONID_LEN) != 0)) sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
continue; continue;
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
...@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, ...@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs_client * struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr, nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound) struct nfs4_sessionid *sid)
{ {
return NULL; return NULL;
} }
......
...@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *); ...@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *); extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
extern struct nfs_client *nfs4_find_client_ident(int); extern struct nfs_client *nfs4_find_client_ident(int);
extern struct nfs_client * extern struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *, nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
int);
extern struct nfs_server *nfs_create_server( extern struct nfs_server *nfs_create_server(
const struct nfs_parsed_mount_data *, const struct nfs_parsed_mount_data *,
struct nfs_fh *); struct nfs_fh *);
......
...@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
status = nfs4_proc_create_session(clp); status = nfs4_proc_create_session(clp);
if (status != 0) if (status != 0)
goto out; goto out;
status = nfs4_set_callback_sessionid(clp);
if (status != 0) {
printk(KERN_WARNING "Sessionid not set. No callback service\n");
nfs_callback_down(1);
status = 0;
}
nfs41_setup_state_renewal(clp); nfs41_setup_state_renewal(clp);
nfs_mark_client_ready(clp, NFS_CS_READY); nfs_mark_client_ready(clp, NFS_CS_READY);
out: out:
......
...@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) ...@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
return 1; return 1;
return 0; return 0;
} }
static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
{
if (svc_is_backchannel(rqstp))
return (struct nfs4_sessionid *)
rqstp->rq_server->sv_bc_xprt->xpt_bc_sid;
return NULL;
}
#else /* CONFIG_NFS_V4_1 */ #else /* CONFIG_NFS_V4_1 */
static inline int xprt_setup_backchannel(struct rpc_xprt *xprt, static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
unsigned int min_reqs) unsigned int min_reqs)
...@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) ...@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
return 0; return 0;
} }
static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
{
return NULL;
}
static inline void xprt_free_bc_request(struct rpc_rqst *req) static inline void xprt_free_bc_request(struct rpc_rqst *req)
{ {
} }
......
...@@ -77,7 +77,6 @@ struct svc_xprt { ...@@ -77,7 +77,6 @@ struct svc_xprt {
size_t xpt_remotelen; /* length of address */ size_t xpt_remotelen; /* length of address */
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */ struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
struct list_head xpt_users; /* callbacks on free */ struct list_head xpt_users; /* callbacks on free */
void *xpt_bc_sid; /* back channel session ID */
struct net *xpt_net; struct net *xpt_net;
struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */ struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
......
...@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv, ...@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
*/ */
static void svc_bc_sock_free(struct svc_xprt *xprt) static void svc_bc_sock_free(struct svc_xprt *xprt)
{ {
if (xprt) { if (xprt)
kfree(xprt->xpt_bc_sid);
kfree(container_of(xprt, struct svc_sock, sk_xprt)); kfree(container_of(xprt, struct svc_sock, sk_xprt));
}
} }
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
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