svn commit: r357157 - in projects/nfs-over-tls/usr.sbin: . rpctlscd rpctlssd

Rick Macklem rmacklem at FreeBSD.org
Sun Jan 26 19:37:48 UTC 2020


Author: rmacklem
Date: Sun Jan 26 19:37:46 2020
New Revision: 357157
URL: https://svnweb.freebsd.org/changeset/base/357157

Log:
  Add the rpctlscd and rpctlssd daemons to usr.sbin.
  
  These daemons do the client side (rpctlscd) and server side (rpctlssd) of
  the TLS handshake for the kernel RPC-over-TLS.
  They really need a review by someone who actually understands the OpenSSL
  API.
  Currently rpctlscd has 478 bytes in the recieve socket queue when
  SSL_connect() returns. SSL_read() knows how to skip over this, but for
  kernel socket use, the code just currently does a recv() to get it
  and throw it away.
  How to do this properly needs to be figured out.
  
  After the handshake, the code just currently does unencrypted RPCs
  in the kernel. Encryption can't be done until the kernel TLS knows
  how to do receive.
  
  Also, they currently (mis)use the gssd_syscall(), since it was easier
  for testing than adding a new syscall.
  Adding a new syscall will be done before this project is ready for head.

Added:
  projects/nfs-over-tls/usr.sbin/rpctlscd/
  projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile   (contents, props changed)
  projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8   (contents, props changed)
  projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c   (contents, props changed)
  projects/nfs-over-tls/usr.sbin/rpctlssd/
  projects/nfs-over-tls/usr.sbin/rpctlssd/Makefile   (contents, props changed)
  projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8   (contents, props changed)
  projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.c   (contents, props changed)
Modified:
  projects/nfs-over-tls/usr.sbin/Makefile

Modified: projects/nfs-over-tls/usr.sbin/Makefile
==============================================================================
--- projects/nfs-over-tls/usr.sbin/Makefile	Sun Jan 26 19:16:36 2020	(r357156)
+++ projects/nfs-over-tls/usr.sbin/Makefile	Sun Jan 26 19:37:46 2020	(r357157)
@@ -72,6 +72,8 @@ SUBDIR=	adduser \
 	rarpd \
 	rmt \
 	rpcbind \
+	rpctlscd \
+	rpctlssd \
 	rpc.lockd \
 	rpc.statd \
 	rpc.umntall \

Added: projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+PROG=	rpctlscd
+MAN=	rpctlscd.8
+SRCS=	rpctlscd.c rpctlscd.h rpctlscd_svc.c rpctlscd_xdr.c
+
+CFLAGS+= -I.
+WARNS?= 1
+
+LIBADD=	ssl crypto
+
+CLEANFILES= rpctlscd_svc.c rpctlscd_xdr.c rpctlscd.h
+
+RPCSRC=	/usr/src/sys.dec13-2019/rpc/rpcsec_tls/rpctlscd.x
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -L -C -M
+
+rpctlscd_svc.c: ${RPCSRC} rpctlscd.h
+	${RPCGEN} -m -o ${.TARGET} ${RPCSRC}
+
+rpctlscd_xdr.c: ${RPCSRC} rpctlscd.h
+	${RPCGEN} -c -o ${.TARGET} ${RPCSRC}
+
+rpctlscd.h: ${RPCSRC}
+	${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+.PATH:	${SRCTOP}/sys/rpc/rpcsec_tls
+
+.include <bsd.prog.mk>

Added: projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,72 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr at rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred at FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" Modified from gssd.8 for rpctlscd.8 by Rick Macklem.
+.Dd January 21, 2020
+.Dt RPCTLSCD 8
+.Os
+.Sh NAME
+.Nm rpctlscd
+.Nd "Sun RPC over TLS Client Daemon"
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+program provides support for the client side of the kernel Sun RPC over TLS
+implementation.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Run in debug mode.
+In this mode,
+.Nm
+will not fork when it starts.
+.It Fl v
+Run in verbose mode.
+In this mode,
+.Nm
+will log activity messages to syslog using LOG_INFO | LOG_DAEMON or to
+stderr, if the
+.Fl d
+option has also been specified.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr openssl 3 ,
+.Xr syslog 3 ,
+.Xr mount_nfs 8 ,
+.Xr rpctlssd 8
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 13.0 .

Added: projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,345 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr at rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred at freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Modified from gssd.c for the client side of kernel RPC-over-TLS. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+#include <err.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpcsec_tls.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "rpctlscd.h"
+
+#ifndef _PATH_RPCTLSCDSOCK
+#define _PATH_RPCTLSCDSOCK	"/var/run/rpctlscd.sock"
+#endif
+
+static int	rpctls_debug_level;
+static int	rpctls_verbose;
+static int testnossl;
+static SSL_CTX	*rpctls_ctx = NULL;
+
+static void	rpctlscd_terminate(int);
+static SSL_CTX	*rpctls_setupcl_ssl(char *certpath);
+static SSL	*rpctls_connect(SSL_CTX *ctx, int s);
+
+extern void rpctlscd_1(struct svc_req *rqstp, SVCXPRT *transp);
+extern int gssd_syscall(const char *path);
+
+int
+main(int argc, char **argv)
+{
+	/*
+	 * We provide an RPC service on a local-domain socket. The
+	 * kernel rpctls code will upcall to this daemon to do the initial
+	 * TLS handshake.
+	 */
+	struct sockaddr_un sun;
+	int fd, oldmask, ch;
+	SVCXPRT *xprt;
+	char *certpath;
+
+	rpctls_verbose = 0;
+	testnossl = 0;
+	certpath = NULL;
+	while ((ch = getopt(argc, argv, "c:dtv")) != -1) {
+		switch (ch) {
+		case 'c':
+			certpath = optarg;
+		case 'd':
+			rpctls_debug_level++;
+			break;
+		case 't':
+			testnossl = 1;
+			break;
+		case 'v':
+			rpctls_verbose = 1;
+			break;
+		default:
+			fprintf(stderr, "usage: %s [-d] [-v]\n", argv[0]);
+			exit(1);
+			break;
+		}
+	}
+
+	if (!rpctls_debug_level) {
+		if (daemon(0, 0) != 0)
+			err(1, "Can't daemonize");
+		signal(SIGINT, SIG_IGN);
+		signal(SIGQUIT, SIG_IGN);
+		signal(SIGHUP, SIG_IGN);
+	}
+	signal(SIGTERM, rpctlscd_terminate);
+	signal(SIGPIPE, rpctlscd_terminate);
+
+	memset(&sun, 0, sizeof sun);
+	sun.sun_family = AF_LOCAL;
+	unlink(_PATH_RPCTLSCDSOCK);
+	strcpy(sun.sun_path, _PATH_RPCTLSCDSOCK);
+	sun.sun_len = SUN_LEN(&sun);
+	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (fd < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't create local rpctlscd socket");
+			exit(1);
+		}
+		err(1, "Can't create local rpctlscd socket");
+	}
+	oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
+	if (bind(fd, (struct sockaddr *)&sun, sun.sun_len) < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't bind local rpctlscd socket");
+			exit(1);
+		}
+		err(1, "Can't bind local rpctlscd socket");
+	}
+	umask(oldmask);
+	if (listen(fd, SOMAXCONN) < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't listen on local rpctlscd socket");
+			exit(1);
+		}
+		err(1, "Can't listen on local rpctlscd socket");
+	}
+	xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
+	if (!xprt) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't create transport for local rpctlscd socket");
+			exit(1);
+		}
+		err(1, "Can't create transport for local rpctlscd socket");
+	}
+	if (!svc_reg(xprt, RPCTLSCD, RPCTLSCDVERS, rpctlscd_1, NULL)) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't register service for local rpctlscd socket");
+			exit(1);
+		}
+		err(1, "Can't register service for local rpctlscd socket");
+	}
+
+	/* Set up the OpenSSL TSL stuff. */
+	rpctls_ctx = rpctls_setupcl_ssl(certpath);
+	if (rpctls_ctx == NULL) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't set up TSL context");
+			exit(1);
+		}
+		err(1, "Can't set up TSL context");
+	}
+
+	gssd_syscall(_PATH_RPCTLSCDSOCK);
+	svc_run();
+	gssd_syscall("");
+
+	SSL_CTX_free(rpctls_ctx);
+	EVP_cleanup();
+	return (0);
+}
+
+static void
+rpctlscd_verbose_out(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (rpctls_verbose != 0) {
+		va_start(ap, fmt);
+		if (rpctls_debug_level == 0)
+			vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap);
+		else
+			vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+bool_t
+rpctlscd_null_1_svc(void *argp, void *result, struct svc_req *rqstp)
+{
+
+	rpctlscd_verbose_out("rpctlscd_null: done\n");
+	return (TRUE);
+}
+
+bool_t
+rpctlscd_connect_1_svc(void *argp, void *result, struct svc_req *rqstp)
+{
+	int s;
+	bool_t res;
+	SSL *ssl;
+	char buf[1024];
+	ssize_t siz, ret;
+
+	rpctlscd_verbose_out("rpctlsd_connect: started\n");
+	/* Get the socket fd from the kernel. */
+	s = gssd_syscall("C");
+rpctlscd_verbose_out("rpctlsd_connect s=%d\n", s);
+	if (s < 0)
+		return (FALSE);
+
+	if (testnossl == 0) {
+		/* Do a TLS connect handshake. */
+		ssl = rpctls_connect(rpctls_ctx, s);
+		if (ssl == NULL)
+			rpctlscd_verbose_out("rpctlsd_connect: can't do TLS "
+			    "handshake\n");
+		else {
+			/* Read the 478 bytes of junk off the socket. */
+			siz = 478;
+			ret = 1;
+			while (siz > 0 && ret > 0) {
+				ret = recv(s, &buf[478 - siz], siz, 0);
+				siz -= ret;
+			}
+		}
+	}
+
+	/* Done with socket fd, so let the kernel know. */
+	gssd_syscall("D");
+	if (ssl == NULL)
+		return (FALSE);
+	return (TRUE);
+}
+
+int
+rpctlscd_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
+{
+
+	return (TRUE);
+}
+
+static void
+rpctlscd_terminate(int sig __unused)
+{
+
+	gssd_syscall("");
+	exit(0);
+}
+
+static SSL_CTX *
+rpctls_setupcl_ssl(char *certpath)
+{
+	SSL_CTX *ctx;
+	long flags;
+	int ret;
+
+	OpenSSL_add_all_algorithms();
+
+	ctx = SSL_CTX_new(TLS_client_method());
+	if (ctx == NULL) {
+		rpctlscd_verbose_out("rpctls_setupcl_ssl: SSL_CTX_new "
+		    "failed\n");
+		return (NULL);
+	}
+	SSL_CTX_set_ecdh_auto(ctx, 1);
+
+	/*
+	 * If certpath is set, it refers to the certifcate file to be used
+	 * during an SSL_connect().
+	 */
+	if (certpath != NULL) {
+		ret = SSL_CTX_use_certificate_file(ctx, certpath,
+		    SSL_FILETYPE_PEM);
+		if (ret != 1) {
+			rpctlscd_verbose_out("rpctls_setupcl_ssl: can't use "
+			    "the certificate file %s\n", certpath);
+			SSL_CTX_free(ctx);
+			return (NULL);
+		}
+	}
+
+	/* RPC-over-TLS must use TLSv1.3. */
+	flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
+	    SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
+	SSL_CTX_set_options(ctx, flags);
+	return (ctx);
+}
+
+static SSL *
+rpctls_connect(SSL_CTX *ctx, int s)
+{
+	SSL *ssl;
+	X509 *cert;
+	int ret;
+
+	ssl = SSL_new(ctx);
+	if (ssl == NULL) {
+		rpctlscd_verbose_out("rpctls_connect: SSL_new failed\n");
+		return (NULL);
+	}
+	if (SSL_set_fd(ssl, s) != 1) {
+		rpctlscd_verbose_out("rpctls_connect: SSL_set_fd failed\n");
+		SSL_free(ssl);
+		return (NULL);
+	}
+	ret = SSL_connect(ssl);
+	if (ret != 1) {
+		rpctlscd_verbose_out("rpctls_connect: SSL_connect failed %d\n",
+		    ret);
+		SSL_free(ssl);
+		return (NULL);
+	}
+
+	cert = SSL_get_peer_certificate(ssl);
+	if (cert == NULL) {
+		rpctlscd_verbose_out("rpctls_connect: get peer certificate "
+		    "failed\n");
+		SSL_shutdown(ssl);
+		SSL_free(ssl);
+		return (NULL);
+	}
+	X509_free(cert);
+
+#ifdef notnow
+	ret = BIO_get_ktls_send(SSL_get_wbio(ssl));
+	fprintf(stderr, "ktls_send=%d\n", ret);
+	ret = BIO_get_ktls_recv(SSL_get_rbio(ssl));
+	fprintf(stderr, "ktls_recv=%d\n", ret);
+#endif
+	return (ssl);
+}
+

Added: projects/nfs-over-tls/usr.sbin/rpctlssd/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlssd/Makefile	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+PROG=	rpctlssd
+MAN=	rpctlssd.8
+SRCS=	rpctlssd.c rpctlssd.h rpctlssd_svc.c rpctlssd_xdr.c
+
+CFLAGS+= -I.
+WARNS?= 1
+
+LIBADD=	ssl crypto
+
+CLEANFILES= rpctlssd_svc.c rpctlssd_xdr.c rpctlssd.h
+
+RPCSRC=	/usr/src/sys.dec13-2019/rpc/rpcsec_tls/rpctlssd.x
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -L -C -M
+
+rpctlssd_svc.c: ${RPCSRC} rpctlssd.h
+	${RPCGEN} -m -o ${.TARGET} ${RPCSRC}
+
+rpctlssd_xdr.c: ${RPCSRC} rpctlssd.h
+	${RPCGEN} -c -o ${.TARGET} ${RPCSRC}
+
+rpctlssd.h: ${RPCSRC}
+	${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+.PATH:	${SRCTOP}/sys/rpc/rpcsec_tls
+
+.include <bsd.prog.mk>

Added: projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,76 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr at rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred at FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" Modified from gssd.8 for rpctlssd.8 by Rick Macklem.
+.Dd January 21, 2020
+.Dt RPCTLSSD 8
+.Os
+.Sh NAME
+.Nm rpctlssd
+.Nd "Sun RPC over TLS Server Daemon"
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+program provides support for the server side of the kernel Sun RPC over TLS
+implementation.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Run in debug mode.
+In this mode,
+.Nm
+will not fork when it starts.
+.It Fl v
+Run in verbose mode.
+In this mode,
+.Nm
+will log activity messages to syslog using LOG_INFO | LOG_DAEMON or to
+stderr, if the
+.Fl d
+option has also been specified.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr openssl 3 ,
+.Xr syslog 3 ,
+.Xr mount_nfs 8 ,
+.Xr rpctlscd 8
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+This
+manual page was adapted from a manual page for the gssd daemon written by
+.An Doug Rabson Aq Mt dfr at FreeBSD.org .

Added: projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.c	Sun Jan 26 19:37:46 2020	(r357157)
@@ -0,0 +1,358 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr at rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred at freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Modified from gssd.c for the server side of kernel RPC-over-TLS. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+#include <err.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpcsec_tls.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "rpctlssd.h"
+
+#ifndef _PATH_RPCTLSSDSOCK
+#define _PATH_RPCTLSSDSOCK	"/var/run/rpctlssd.sock"
+#define _PATH_RPCTLSSDS	"S/var/run/rpctlssd.sock"
+#endif
+#ifndef	_PATH_CERTANDKEY
+#define	_PATH_CERTANDKEY	"/etc/rpctlssd/"
+#endif
+
+static int	rpctls_debug_level;
+static int	rpctls_verbose;
+static int	testnossl;
+static SSL_CTX	*rpctls_ctx = NULL;
+static char	*rpctls_cafiles = NULL;
+static char	*rpctls_verify_loc = NULL;
+
+static void	rpctlssd_terminate(int);
+static SSL_CTX	*rpctls_setup_ssl(char *certdir);
+static SSL	*rpctls_server(SSL_CTX *ctx, int s);
+
+extern void rpctlssd_1(struct svc_req *rqstp, SVCXPRT *transp);
+extern int gssd_syscall(const char *path);
+
+int
+main(int argc, char **argv)
+{
+	/*
+	 * We provide an RPC service on a local-domain socket. The
+	 * kernel rpctls code will upcall to this daemon to do the initial
+	 * TLS handshake.
+	 */
+	struct sockaddr_un sun;
+	int fd, oldmask, ch, debug;
+	SVCXPRT *xprt;
+
+	debug = 0;
+	rpctls_verbose = 0;
+	testnossl = 0;
+	while ((ch = getopt(argc, argv, "c:dl:tv")) != -1) {
+		switch (ch) {
+		case 'c':
+			rpctls_cafiles = optarg;
+			break;
+		case 'd':
+			rpctls_debug_level++;
+			break;
+		case 'l':
+			rpctls_verify_loc = optarg;
+			break;
+		case 't':
+			testnossl = 1;
+			break;
+		case 'v':
+			rpctls_verbose = 1;
+			break;
+		default:
+			fprintf(stderr, "usage: %s [-c <cafile>] [-d] "
+			    "[-l <verify locations>] [-v]\n", argv[0]);
+			exit(1);
+			break;
+		}
+	}
+	if ((rpctls_cafiles != NULL && rpctls_verify_loc == NULL) ||
+	    (rpctls_cafiles == NULL && rpctls_verify_loc != NULL)) {
+		fprintf(stderr, "usage: %s [-c <cafile>] [-d] "
+		    "[-l <verify locations>] [-v]\n", argv[0]);
+		exit(1);
+	}
+
+	if (rpctls_debug_level == 0) {
+		if (daemon(0, 0) != 0)
+			err(1, "Can't daemonize");
+		signal(SIGINT, SIG_IGN);
+		signal(SIGQUIT, SIG_IGN);
+		signal(SIGHUP, SIG_IGN);
+	}
+	signal(SIGTERM, rpctlssd_terminate);
+	signal(SIGPIPE, rpctlssd_terminate);
+
+	memset(&sun, 0, sizeof sun);
+	sun.sun_family = AF_LOCAL;
+	unlink(_PATH_RPCTLSSDSOCK);
+	strcpy(sun.sun_path, _PATH_RPCTLSSDSOCK);
+	sun.sun_len = SUN_LEN(&sun);
+	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (fd < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't create local rpctlssd socket");
+			exit(1);
+		}
+		err(1, "Can't create local rpctlssd socket");
+	}
+	oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
+	if (bind(fd, (struct sockaddr *)&sun, sun.sun_len) < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't bind local rpctlssd socket");
+			exit(1);
+		}
+		err(1, "Can't bind local rpctlssd socket");
+	}
+	umask(oldmask);
+	if (listen(fd, SOMAXCONN) < 0) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't listen on local rpctlssd socket");
+			exit(1);
+		}
+		err(1, "Can't listen on local rpctlssd socket");
+	}
+	xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
+	if (!xprt) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't create transport for local rpctlssd socket");
+			exit(1);
+		}
+		err(1, "Can't create transport for local rpctlssd socket");
+	}
+	if (!svc_reg(xprt, RPCTLSSD, RPCTLSSDVERS, rpctlssd_1, NULL)) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR,
+			    "Can't register service for local rpctlssd socket");
+			exit(1);
+		}
+		err(1, "Can't register service for local rpctlssd socket");
+	}
+
+	rpctls_ctx = rpctls_setup_ssl(_PATH_CERTANDKEY);
+	if (rpctls_ctx == NULL) {
+		if (rpctls_debug_level == 0) {
+			syslog(LOG_ERR, "Can't create SSL context");
+			exit(1);
+		}
+		err(1, "Can't create SSL context");
+	}
+
+	gssd_syscall(_PATH_RPCTLSSDS);
+	svc_run();
+	gssd_syscall("S");
+
+	SSL_CTX_free(rpctls_ctx);
+	EVP_cleanup();
+	return (0);
+}
+
+static void
+rpctlssd_verbose_out(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (rpctls_verbose != 0) {
+		va_start(ap, fmt);
+		if (rpctls_debug_level == 0)
+			vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap);
+		else
+			vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+bool_t
+rpctlssd_null_1_svc(void *argp, void *result, struct svc_req *rqstp)
+{
+
+	rpctlssd_verbose_out("rpctlssd_null_svc: done\n");
+	return (TRUE);
+}
+
+bool_t
+rpctlssd_connect_1_svc(void *argp, void *result, struct svc_req *rqstp)
+{
+	int s;
+	SSL *ssl;
+
+	rpctlssd_verbose_out("rpctlsd_connect_svc: started\n");
+	/* Get the socket fd from the kernel. */
+	s = gssd_syscall("E");
+rpctlssd_verbose_out("rpctlsd_connect_svc s=%d\n", s);
+	if (s < 0)
+		return (FALSE);
+
+	if (testnossl == 0) {
+		/* Do the server side of a TLS handshake. */
+		ssl = rpctls_server(rpctls_ctx, s);
+		if (ssl == NULL)
+			rpctlssd_verbose_out("rpctlssd_connect_svc: ssl accept "
+			    "failed\n");
+		else
+			rpctlssd_verbose_out("rpctlssd_connect_svc: "
+			    "succeeded\n");
+	}
+
+	/* Done with socket fd, so let the kernel know. */
+	gssd_syscall("F");
+	if (testnossl == 0 && ssl == NULL)
+		return (FALSE);
+	return (TRUE);
+}
+
+int
+rpctlssd_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
+{
+
+	return (TRUE);
+}
+
+static void
+rpctlssd_terminate(int sig __unused)
+{
+
+	gssd_syscall("S");
+	exit(0);
+}
+
+static SSL_CTX *
+rpctls_setup_ssl(char *certdir)
+{
+	SSL_CTX *ctx;
+	char path[PATH_MAX];
+	size_t len, rlen;
+	int ret;
+
+	OpenSSL_add_all_algorithms();
+
+	ctx = SSL_CTX_new(TLS_server_method());
+	if (ctx == NULL) {
+		rpctlssd_verbose_out("rpctls_setup_ssl: SSL_CTX_new failed\n");
+		return (NULL);
+	}
+	SSL_CTX_set_ecdh_auto(ctx, 1);
+
+	/* Get the cert.pem and key.pem files from the directory certdir. */
+	len = strlcpy(path, certdir, sizeof(path));
+	rlen = sizeof(path) - len;
+	if (strlcpy(&path[len], "cert.pem", rlen) != 8) {
+		SSL_CTX_free(ctx);
+		return (NULL);
+	}
+	ret = SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM);
+	if (ret != 1) {
+		rpctlssd_verbose_out("rpctls_setup_ssl: can't use certificate "
+		    "file path=%s ret=%d\n", path, ret);
+		SSL_CTX_free(ctx);
+		return (NULL);
+	}
+	if (strlcpy(&path[len], "key.pem", rlen) != 7) {
+		SSL_CTX_free(ctx);
+		return (NULL);
+	}
+	ret = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM);
+	if (ret != 1) {
+		rpctlssd_verbose_out("rpctls_setup_ssl: Can't use private "
+		    "key path=%s ret=%d\n", path, ret);
+		SSL_CTX_free(ctx);
+		return (NULL);
+	}
+
+	/* Set Mutual authentication, as required. */
+	if (rpctls_cafiles != NULL && rpctls_verify_loc != NULL) {
+		rpctlssd_verbose_out("rpctls_setup_ssl: set mutual "
+		    "authentication cafiles=%s verf_loc=%s\n", rpctls_cafiles,
+		    rpctls_verify_loc);
+		ret = SSL_CTX_load_verify_locations(ctx, rpctls_verify_loc,
+		    NULL);
+		if (ret != 1) {
+			rpctlssd_verbose_out("rpctls_setup_ssl: Can't load "
+			    "verify locations\n");
+			SSL_CTX_free(ctx);
+			return (NULL);
+		}
+		SSL_CTX_set_client_CA_list(ctx,
+		    SSL_load_client_CA_file(rpctls_cafiles));
+		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER |
+		    SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+	}
+	return (ctx);
+}
+
+static SSL *
+rpctls_server(SSL_CTX *ctx, int s)
+{
+	SSL *ssl;
+	int ret;
+
+	ssl = SSL_new(ctx);
+	if (ssl == NULL) {
+		rpctlssd_verbose_out("rpctls_server: SSL_new failed\n");
+		return (NULL);
+	}
+	if (SSL_set_fd(ssl, s) != 1) {
+		rpctlssd_verbose_out("rpctls_server: SSL_set_fd failed\n");
+		SSL_free(ssl);
+		return (NULL);
+	}
+	ret = SSL_accept(ssl);
+	if (ret != 1) {
+		rpctlssd_verbose_out("rpctls_server: SS_accept failed ret=%d\n",
+		    ret);
+		SSL_free(ssl);
+		return (NULL);
+	}
+	return (ssl);
+}
+


More information about the svn-src-projects mailing list