From owner-svn-src-projects@freebsd.org Sun Jan 26 19:37:48 2020 Return-Path: Delivered-To: svn-src-projects@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id BC4EE1F9192 for ; Sun, 26 Jan 2020 19:37:48 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 485NSr54rLz4Qh9; Sun, 26 Jan 2020 19:37:48 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8AAD026073; Sun, 26 Jan 2020 19:37:48 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 00QJbmS3091908; Sun, 26 Jan 2020 19:37:48 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 00QJbl6n091901; Sun, 26 Jan 2020 19:37:47 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <202001261937.00QJbl6n091901@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Sun, 26 Jan 2020 19:37:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r357157 - in projects/nfs-over-tls/usr.sbin: . rpctlscd rpctlssd X-SVN-Group: projects X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: in projects/nfs-over-tls/usr.sbin: . rpctlscd rpctlssd X-SVN-Commit-Revision: 357157 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Jan 2020 19:37:48 -0000 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 + +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 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 +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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 + * Developed with Red Inc: Alfred Perlstein + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 + +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 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 +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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@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 + * Developed with Red Inc: Alfred Perlstein + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 ] [-d] " + "[-l ] [-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 ] [-d] " + "[-l ] [-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); +} +