aboutsummaryrefslogtreecommitdiff
path: root/sys/rpc/svc_auth.c
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2020-08-22 03:57:55 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2020-08-22 03:57:55 +0000
commitab0c29af0512df1e40c30f1b361da7803594336e (patch)
treea4a060373915aec885ec1f16a58946209c74bf01 /sys/rpc/svc_auth.c
parent530134d2918e3f8d53cf51b89c0f4c5fd032c88b (diff)
downloadsrc-ab0c29af0512df1e40c30f1b361da7803594336e.tar.gz
src-ab0c29af0512df1e40c30f1b361da7803594336e.zip
Add TLS support to the kernel RPC.
An internet draft titled "Towards Remote Procedure Call Encryption By Default" describes how TLS is to be used for Sun RPC, with NFS as an intended use case. This patch adds client and server support for this to the kernel RPC, using KERN_TLS and upcalls to daemons for the handshake, peer reset and other non-application data record cases. The upcalls to the daemons use three fields to uniquely identify the TCP connection. They are the time.tv_sec, time.tv_usec of the connection establshment, plus a 64bit sequence number. The time fields avoid problems with re-use of the sequence number after a daemon restart. For the server side, once a Null RPC with AUTH_TLS is received, kernel reception on the socket is blocked and an upcall to the rpctlssd(8) daemon is done to perform the TLS handshake. Upon completion, the completion status of the handshake is stored in xp_tls as flag bits and the reply to the Null RPC is sent. For the client, if CLSET_TLS has been set, a new TCP connection will send the Null RPC with AUTH_TLS to initiate the handshake. The client kernel RPC code will then block kernel I/O on the socket and do an upcall to the rpctlscd(8) daemon to perform the handshake. If the upcall is successful, ct_rcvstate will be maintained to indicate if/when an upcall is being done. If non-application data records are received, the code does an upcall to the appropriate daemon, which will do a SSL_read() of 0 length to handle the record(s). When the socket is being shut down, upcalls are done to the daemons, so that they can perform SSL_shutdown() calls to perform the "peer reset". The rpctlssd(8) and rpctlscd(8) daemons require a patched version of the openssl library and, as such, will not be committed to head at this time. Although the changes done by this patch are fairly numerous, there should be no semantics change to the kernel RPC at this time. A future commit to the NFS code will optionally enable use of TLS for NFS.
Notes
Notes: svn path=/head/; revision=364475
Diffstat (limited to 'sys/rpc/svc_auth.c')
-rw-r--r--sys/rpc/svc_auth.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/sys/rpc/svc_auth.c b/sys/rpc/svc_auth.c
index 5dbc64b74769..0c5a68688d48 100644
--- a/sys/rpc/svc_auth.c
+++ b/sys/rpc/svc_auth.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ucred.h>
#include <rpc/rpc.h>
+#include <rpc/rpcsec_tls.h>
static enum auth_stat (*_svcauth_rpcsec_gss)(struct svc_req *,
struct rpc_msg *) = NULL;
@@ -94,16 +95,25 @@ _authenticate(struct svc_req *rqst, struct rpc_msg *msg)
dummy = _svcauth_null(rqst, msg);
return (dummy);
case AUTH_SYS:
+ if ((rqst->rq_xprt->xp_tls & RPCTLS_FLAGS_DISABLED) != 0)
+ return (AUTH_REJECTEDCRED);
dummy = _svcauth_unix(rqst, msg);
return (dummy);
case AUTH_SHORT:
+ if ((rqst->rq_xprt->xp_tls & RPCTLS_FLAGS_DISABLED) != 0)
+ return (AUTH_REJECTEDCRED);
dummy = _svcauth_short(rqst, msg);
return (dummy);
case RPCSEC_GSS:
+ if ((rqst->rq_xprt->xp_tls & RPCTLS_FLAGS_DISABLED) != 0)
+ return (AUTH_REJECTEDCRED);
if (!_svcauth_rpcsec_gss)
return (AUTH_REJECTEDCRED);
dummy = _svcauth_rpcsec_gss(rqst, msg);
return (dummy);
+ case AUTH_TLS:
+ dummy = _svcauth_rpcsec_tls(rqst, msg);
+ return (dummy);
default:
break;
}
@@ -169,11 +179,30 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
struct ucred *cr = NULL;
int flavor;
struct xucred *xcr;
+ SVCXPRT *xprt = rqst->rq_xprt;
flavor = rqst->rq_cred.oa_flavor;
if (flavorp)
*flavorp = flavor;
+ /*
+ * If there are credentials acquired via a TLS
+ * certificate for this TCP connection, use those
+ * instead of what is in the RPC header.
+ */
+ if ((xprt->xp_tls & (RPCTLS_FLAGS_CERTUSER |
+ RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER &&
+ flavor == AUTH_UNIX) {
+ cr = crget();
+ cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xprt->xp_uid;
+ crsetgroups(cr, xprt->xp_ngrps, xprt->xp_gidp);
+ cr->cr_rgid = cr->cr_svgid = xprt->xp_gidp[0];
+ cr->cr_prison = &prison0;
+ prison_hold(cr->cr_prison);
+ *crp = cr;
+ return (TRUE);
+ }
+
switch (flavor) {
case AUTH_UNIX:
xcr = (struct xucred *) rqst->rq_clntcred;