SUNRPC: Teach server to recognize RPC_AUTH_TLS
authorChuck Lever <chuck.lever@oracle.com>
Tue, 22 Feb 2022 18:10:52 +0000 (13:10 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 28 Feb 2022 15:26:40 +0000 (10:26 -0500)
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: Chuck Lever <chuck.lever@oracle.com>
include/linux/sunrpc/svc_xprt.h
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c

index 42e113742429b3895a3c465c0e6cd7e66f3b2818..20068ccfd0cc0243967d1cf0a1f0f221c6f3fba6 100644 (file)
@@ -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 {
index 5a8b8e03fdd42b14e38a4fd561f8076589845d15..e72ba2f13f6c6277f7047d43ba5403352573123c 100644 (file)
  */
 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 *
index d7ed7d49115ac607cf4677bdd60bb03dd5b4f9e3..b1efc34db6ed8b20e5076f0115142055b9ce29e9 100644 (file)
@@ -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)
 {