Commit 74aaf96f authored by Chuck Lever's avatar Chuck Lever
Browse files

SUNRPC: Teach server to recognize RPC_AUTH_TLS



Initial support for the RPC_AUTH_TLS authentication flavor enables
NFSD to eventually accept an RPC_AUTH_TLS probe from clients. This
patch simply prevents NFSD from rejecting these probes completely.

In the meantime, graft this support in now so that RPC_AUTH_TLS
support keeps up with generic code and API changes in the RPC
server.

Down the road, server-side transport implementations will populate
xpo_start_tls when they can support RPC-with-TLS. For example, TCP
will eventually populate it, but RDMA won't.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 37902c63
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ struct svc_xprt_ops {
	void		(*xpo_free)(struct svc_xprt *);
	void		(*xpo_secure_port)(struct svc_rqst *rqstp);
	void		(*xpo_kill_temp_xprt)(struct svc_xprt *);
	void		(*xpo_start_tls)(struct svc_xprt *);
};

struct svc_xprt_class {
+2 −0
Original line number Diff line number Diff line
@@ -31,10 +31,12 @@
 */
extern struct auth_ops svcauth_null;
extern struct auth_ops svcauth_unix;
extern struct auth_ops svcauth_tls;

static struct auth_ops __rcu *authtab[RPC_AUTH_MAXFLAVOR] = {
	[RPC_AUTH_NULL] = (struct auth_ops __force __rcu *)&svcauth_null,
	[RPC_AUTH_UNIX] = (struct auth_ops __force __rcu *)&svcauth_unix,
	[RPC_AUTH_TLS]  = (struct auth_ops __force __rcu *)&svcauth_tls,
};

static struct auth_ops *
+60 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct unix_domain {

extern struct auth_ops svcauth_null;
extern struct auth_ops svcauth_unix;
extern struct auth_ops svcauth_tls;

static void svcauth_unix_domain_release_rcu(struct rcu_head *head)
{
@@ -788,6 +789,65 @@ struct auth_ops svcauth_null = {
};


static int
svcauth_tls_accept(struct svc_rqst *rqstp)
{
	struct svc_cred	*cred = &rqstp->rq_cred;
	struct kvec *argv = rqstp->rq_arg.head;
	struct kvec *resv = rqstp->rq_res.head;

	if (argv->iov_len < XDR_UNIT * 3)
		return SVC_GARBAGE;

	/* Call's cred length */
	if (svc_getu32(argv) != xdr_zero) {
		rqstp->rq_auth_stat = rpc_autherr_badcred;
		return SVC_DENIED;
	}

	/* Call's verifier flavor and its length */
	if (svc_getu32(argv) != rpc_auth_null ||
	    svc_getu32(argv) != xdr_zero) {
		rqstp->rq_auth_stat = rpc_autherr_badverf;
		return SVC_DENIED;
	}

	/* AUTH_TLS is not valid on non-NULL procedures */
	if (rqstp->rq_proc != 0) {
		rqstp->rq_auth_stat = rpc_autherr_badcred;
		return SVC_DENIED;
	}

	/* Mapping to nobody uid/gid is required */
	cred->cr_uid = INVALID_UID;
	cred->cr_gid = INVALID_GID;
	cred->cr_group_info = groups_alloc(0);
	if (cred->cr_group_info == NULL)
		return SVC_CLOSE; /* kmalloc failure - client must retry */

	/* Reply's verifier */
	svc_putnl(resv, RPC_AUTH_NULL);
	if (rqstp->rq_xprt->xpt_ops->xpo_start_tls) {
		svc_putnl(resv, 8);
		memcpy(resv->iov_base + resv->iov_len, "STARTTLS", 8);
		resv->iov_len += 8;
	} else
		svc_putnl(resv, 0);

	rqstp->rq_cred.cr_flavor = RPC_AUTH_TLS;
	return SVC_OK;
}

struct auth_ops svcauth_tls = {
	.name		= "tls",
	.owner		= THIS_MODULE,
	.flavour	= RPC_AUTH_TLS,
	.accept 	= svcauth_tls_accept,
	.release	= svcauth_null_release,
	.set_client	= svcauth_unix_set_client,
};


static int
svcauth_unix_accept(struct svc_rqst *rqstp)
{