SUNRPC: Add RPC client support for the RPC_AUTH_TLS auth flavor
authorChuck Lever <chuck.lever@oracle.com>
Wed, 7 Jun 2023 13:58:04 +0000 (09:58 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 19 Jun 2023 16:18:36 +0000 (12:18 -0400)
The new authentication flavor is used only to discover peer support
for RPC-over-TLS.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/auth.h
net/sunrpc/Makefile
net/sunrpc/auth.c
net/sunrpc/auth_tls.c [new file with mode: 0644]
net/sunrpc/clnt.c

index 3e6ce288a7fc0159bddf1ee69131e8392c631f8b..61e58327b1aa5627220f6a574b298b8802ada5b3 100644 (file)
@@ -120,6 +120,7 @@ struct rpc_authops {
                                                struct rpcsec_gss_info *);
        int                     (*key_timeout)(struct rpc_auth *,
                                                struct rpc_cred *);
+       int                     (*ping)(struct rpc_clnt *clnt);
 };
 
 struct rpc_credops {
@@ -144,6 +145,7 @@ struct rpc_credops {
 
 extern const struct rpc_authops        authunix_ops;
 extern const struct rpc_authops        authnull_ops;
+extern const struct rpc_authops        authtls_ops;
 
 int __init             rpc_init_authunix(void);
 int __init             rpcauth_init_module(void);
index 1c8de397d6adcebd955f46691f2e7fa7cccb39ed..f89c10fe7e6acc71d47273200d85425a2891a08a 100644 (file)
@@ -9,7 +9,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
 obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
 
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
-           auth.o auth_null.o auth_unix.o \
+           auth.o auth_null.o auth_tls.o auth_unix.o \
            svc.o svcsock.o svcauth.o svcauth_unix.o \
            addr.o rpcb_clnt.o timer.o xdr.o \
            sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \
index fb75a883503f7e65279fb4a4ff9324be3747562f..2f16f9d179662442b94bb729f772fdb1b39c2a39 100644 (file)
@@ -32,7 +32,7 @@ static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;
 static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
        [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops,
        [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops,
-       NULL,                   /* others can be loadable modules */
+       [RPC_AUTH_TLS]  = (const struct rpc_authops __force __rcu *)&authtls_ops,
 };
 
 static LIST_HEAD(cred_unused);
diff --git a/net/sunrpc/auth_tls.c b/net/sunrpc/auth_tls.c
new file mode 100644 (file)
index 0000000..de7678f
--- /dev/null
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, 2022 Oracle.  All rights reserved.
+ *
+ * The AUTH_TLS credential is used only to probe a remote peer
+ * for RPC-over-TLS support.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/sunrpc/clnt.h>
+
+static const char *starttls_token = "STARTTLS";
+static const size_t starttls_len = 8;
+
+static struct rpc_auth tls_auth;
+static struct rpc_cred tls_cred;
+
+static void tls_encode_probe(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+                            const void *obj)
+{
+}
+
+static int tls_decode_probe(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+                           void *obj)
+{
+       return 0;
+}
+
+static const struct rpc_procinfo rpcproc_tls_probe = {
+       .p_encode       = tls_encode_probe,
+       .p_decode       = tls_decode_probe,
+};
+
+static void rpc_tls_probe_call_prepare(struct rpc_task *task, void *data)
+{
+       task->tk_flags &= ~RPC_TASK_NO_RETRANS_TIMEOUT;
+       rpc_call_start(task);
+}
+
+static void rpc_tls_probe_call_done(struct rpc_task *task, void *data)
+{
+}
+
+static const struct rpc_call_ops rpc_tls_probe_ops = {
+       .rpc_call_prepare       = rpc_tls_probe_call_prepare,
+       .rpc_call_done          = rpc_tls_probe_call_done,
+};
+
+static int tls_probe(struct rpc_clnt *clnt)
+{
+       struct rpc_message msg = {
+               .rpc_proc       = &rpcproc_tls_probe,
+       };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_client     = clnt,
+               .rpc_message    = &msg,
+               .rpc_op_cred    = &tls_cred,
+               .callback_ops   = &rpc_tls_probe_ops,
+               .flags          = RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
+       };
+       struct rpc_task *task;
+       int status;
+
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       status = task->tk_status;
+       rpc_put_task(task);
+       return status;
+}
+
+static struct rpc_auth *tls_create(const struct rpc_auth_create_args *args,
+                                  struct rpc_clnt *clnt)
+{
+       refcount_inc(&tls_auth.au_count);
+       return &tls_auth;
+}
+
+static void tls_destroy(struct rpc_auth *auth)
+{
+}
+
+static struct rpc_cred *tls_lookup_cred(struct rpc_auth *auth,
+                                       struct auth_cred *acred, int flags)
+{
+       return get_rpccred(&tls_cred);
+}
+
+static void tls_destroy_cred(struct rpc_cred *cred)
+{
+}
+
+static int tls_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags)
+{
+       return 1;
+}
+
+static int tls_marshal(struct rpc_task *task, struct xdr_stream *xdr)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, 4 * XDR_UNIT);
+       if (!p)
+               return -EMSGSIZE;
+       /* Credential */
+       *p++ = rpc_auth_tls;
+       *p++ = xdr_zero;
+       /* Verifier */
+       *p++ = rpc_auth_null;
+       *p   = xdr_zero;
+       return 0;
+}
+
+static int tls_refresh(struct rpc_task *task)
+{
+       set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
+       return 0;
+}
+
+static int tls_validate(struct rpc_task *task, struct xdr_stream *xdr)
+{
+       __be32 *p;
+       void *str;
+
+       p = xdr_inline_decode(xdr, XDR_UNIT);
+       if (!p)
+               return -EIO;
+       if (*p != rpc_auth_null)
+               return -EIO;
+       if (xdr_stream_decode_opaque_inline(xdr, &str, starttls_len) != starttls_len)
+               return -EIO;
+       if (memcmp(str, starttls_token, starttls_len))
+               return -EIO;
+       return 0;
+}
+
+const struct rpc_authops authtls_ops = {
+       .owner          = THIS_MODULE,
+       .au_flavor      = RPC_AUTH_TLS,
+       .au_name        = "NULL",
+       .create         = tls_create,
+       .destroy        = tls_destroy,
+       .lookup_cred    = tls_lookup_cred,
+       .ping           = tls_probe,
+};
+
+static struct rpc_auth tls_auth = {
+       .au_cslack      = NUL_CALLSLACK,
+       .au_rslack      = NUL_REPLYSLACK,
+       .au_verfsize    = NUL_REPLYSLACK,
+       .au_ralign      = NUL_REPLYSLACK,
+       .au_ops         = &authtls_ops,
+       .au_flavor      = RPC_AUTH_TLS,
+       .au_count       = REFCOUNT_INIT(1),
+};
+
+static const struct rpc_credops tls_credops = {
+       .cr_name        = "AUTH_TLS",
+       .crdestroy      = tls_destroy_cred,
+       .crmatch        = tls_match,
+       .crmarshal      = tls_marshal,
+       .crwrap_req     = rpcauth_wrap_req_encode,
+       .crrefresh      = tls_refresh,
+       .crvalidate     = tls_validate,
+       .crunwrap_resp  = rpcauth_unwrap_resp_decode,
+};
+
+static struct rpc_cred tls_cred = {
+       .cr_lru         = LIST_HEAD_INIT(tls_cred.cr_lru),
+       .cr_auth        = &tls_auth,
+       .cr_ops         = &tls_credops,
+       .cr_count       = REFCOUNT_INIT(2),
+       .cr_flags       = 1UL << RPCAUTH_CRED_UPTODATE,
+};
index ba34cfcf459a2354b685bdcaca5b1641216e370f..640c76ab2f1af58f9f5785702a31de3cdd90b9f8 100644 (file)
@@ -2833,6 +2833,9 @@ static int rpc_ping(struct rpc_clnt *clnt)
        struct rpc_task *task;
        int status;
 
+       if (clnt->cl_auth->au_ops->ping)
+               return clnt->cl_auth->au_ops->ping(clnt);
+
        task = rpc_call_null_helper(clnt, NULL, NULL, 0, NULL, NULL);
        if (IS_ERR(task))
                return PTR_ERR(task);