Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+29 −80
Original line number Original line Diff line number Diff line
@@ -134,33 +134,6 @@ out_err:
}
}


#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,
		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)
	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)
{
	struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp);
	int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0;

	dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc);
	if (svc_is_backchannel(rqstp))
		/* 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. */
/*
 * pg_authenticate method for nfsv4 callback threads.
 *
 * The authflavor has been negotiated, so an incorrect flavor is a server
 * bug. Drop packets with incorrect authflavor.
 *
 * All other checking done after NFS decoding where the nfs_client can be
 * found in nfs4_callback_compound
 */
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;
		case RPC_AUTH_UNIX:
		break;
		break;
	case RPC_AUTH_GSS:
	case RPC_AUTH_GSS:
			ret = check_gss_callback_principal(clp, rqstp);
		/* No RPC_AUTH_GSS support yet in NFSv4.1 */
			break;
		 if (svc_is_backchannel(rqstp))
		default:
			return SVC_DROP;
			ret = SVC_DENIED;
	}
	}
	nfs_put_client(clp);
	return SVC_OK;
	return ret;
}
}


/*
/*
+2 −2
Original line number Original line Diff line number Diff line
@@ -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 {
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(
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);
+2 −8
Original line number Original line Diff line number Diff line
@@ -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;


+2 −3
Original line number Original line Diff line number Diff line
@@ -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;
+5 −10
Original line number Original line Diff line number Diff line
@@ -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,
		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,


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;
}
}
Loading