svn commit: r365866 - in projects/nfs-over-tls/usr.sbin: rpc.tlsclntd rpc.tlsservd
Rick Macklem
rmacklem at FreeBSD.org
Fri Sep 18 01:11:12 UTC 2020
Author: rmacklem
Date: Fri Sep 18 01:11:11 2020
New Revision: 365866
URL: https://svnweb.freebsd.org/changeset/base/365866
Log:
Factor out several functions from the daemons and put them in common files
shared by both daemons.
Added:
projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.c (contents, props changed)
projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.h (contents, props changed)
Modified:
projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/Makefile
projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/rpc.tlsclntd.c
projects/nfs-over-tls/usr.sbin/rpc.tlsservd/Makefile
projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlsservd.c
Modified: projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/Makefile
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/Makefile Fri Sep 18 00:02:58 2020 (r365865)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/Makefile Fri Sep 18 01:11:11 2020 (r365866)
@@ -4,9 +4,9 @@
PROG= rpc.tlsclntd
MAN= rpc.tlsclntd.8
-SRCS= rpc.tlsclntd.c rpctlscd.h rpctlscd_svc.c rpctlscd_xdr.c
+SRCS= rpc.tlsclntd.c rpc.tlscommon.c rpctlscd.h rpctlscd_svc.c rpctlscd_xdr.c
-CFLAGS+= -I.
+CFLAGS+= -I. -I${SRCTOP}/usr.sbin/rpc.tlsservd
CFLAGS+= -I/usr/ktls/include
LDFLAGS+= -L/usr/ktls/lib
@@ -27,6 +27,6 @@ rpctlscd_xdr.c: ${RPCSRC} rpctlscd.h
rpctlscd.h: ${RPCSRC}
${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
-.PATH: ${SRCTOP}/sys/rpc/rpcsec_tls
+.PATH: ${SRCTOP}/sys/rpc/rpcsec_tls ${SRCTOP}/usr.sbin/rpc.tlsservd
.include <bsd.prog.mk>
Modified: projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/rpc.tlsclntd.c
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/rpc.tlsclntd.c Fri Sep 18 00:02:58 2020 (r365865)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsclntd/rpc.tlsclntd.c Fri Sep 18 01:11:11 2020 (r365866)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <openssl/x509v3.h>
#include "rpctlscd.h"
+#include "rpc.tlscommon.h"
#ifndef _PATH_RPCTLSCDSOCK
#define _PATH_RPCTLSCDSOCK "/var/run/rpc.tlsclntd.sock"
@@ -77,52 +78,27 @@ __FBSDID("$FreeBSD$");
#define _PREFERRED_CIPHERS "AES128-GCM-SHA256"
#endif
-/*
- * How long to delay a reload of the CRL when there are RPC request(s)
- * to process, in usec. Must be less than 1second.
- */
-#define RELOADDELAY 250000
+/* Global variables also used by rpc.tlscommon.c. */
+int rpctls_debug_level;
+bool rpctls_verbose;
+SSL_CTX *rpctls_ctx = NULL;
+const char *rpctls_verify_cafile = NULL;
+const char *rpctls_verify_capath = NULL;
+const char *rpctls_crlfile = NULL;
+bool rpctls_gothup = false;
+struct ssl_list rpctls_ssllist;
+
static struct pidfh *rpctls_pfh = NULL;
-static int rpctls_debug_level;
-static bool rpctls_verbose;
-static SSL_CTX *rpctls_ctx = NULL;
-static const char *rpctls_verify_cafile = NULL;
-static const char *rpctls_verify_capath = NULL;
-static const char *rpctls_crlfile = NULL;
static const char *rpctls_certdir = _PATH_CERTANDKEY;
static uint64_t rpctls_ssl_refno = 0;
static uint64_t rpctls_ssl_sec = 0;
static uint64_t rpctls_ssl_usec = 0;
-static bool rpctls_gothup = false;
-/*
- * A linked list of all current "SSL *"s and socket "fd"s
- * for kernel RPC TLS connections is maintained.
- * The "refno" field is a unique 64bit value used to
- * identify which entry a kernel RPC upcall refers to.
- */
-LIST_HEAD(ssl_list, ssl_entry);
-struct ssl_entry {
- LIST_ENTRY(ssl_entry) next;
- uint64_t refno;
- int s;
- bool shutoff;
- SSL *ssl;
- X509 *cert;
-};
-static struct ssl_list rpctls_ssllist;
-
static void rpctlscd_terminate(int);
static SSL_CTX *rpctls_setupcl_ssl(bool cert);
static SSL *rpctls_connect(SSL_CTX *ctx, int s, X509 **certp);
-static int rpctls_gethost(int s, struct sockaddr *sad,
- char *hostip, size_t hostlen);
-static int rpctls_checkhost(struct sockaddr *sad, X509 *cert);
-static int rpctls_loadcrlfile(SSL_CTX *ctx);
static void rpctls_huphandler(int sig __unused);
-static void rpctls_checkcrl(void);
-static void rpctlscd_verbose_out(const char *fmt, ...);
extern void rpctlscd_1(struct svc_req *rqstp, SVCXPRT *transp);
@@ -146,16 +122,12 @@ main(int argc, char **argv)
* TLS handshake.
*/
struct sockaddr_un sun;
- int ch, fd, oldmask, ret;
+ int ch, fd, oldmask;
SVCXPRT *xprt;
bool cert;
struct timeval tm;
struct timezone tz;
pid_t otherpid;
- fd_set readfds;
- uint64_t curtime, nexttime;
- struct timespec tp;
- sigset_t sighup_mask;
/* Check that another rpctlscd isn't already running. */
rpctls_pfh = pidfile_open(_PATH_RPCTLSCDPID, 0600, &otherpid);
@@ -305,61 +277,8 @@ main(int argc, char **argv)
rpctls_syscall(RPCTLS_SYSC_CLSETPATH, _PATH_RPCTLSCDSOCK);
- /* Expand svc_run() here so that we can call rpctls_loadcrlfile(). */
- curtime = nexttime = 0;
- sigemptyset(&sighup_mask);
- sigaddset(&sighup_mask, SIGHUP);
- for (;;) {
- clock_gettime(CLOCK_MONOTONIC, &tp);
- curtime = tp.tv_sec;
- curtime = curtime * 1000000 + tp.tv_nsec / 1000;
- sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
- if (rpctls_gothup && curtime >= nexttime) {
- rpctls_gothup = false;
- sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
- ret = rpctls_loadcrlfile(rpctls_ctx);
- if (ret != 0)
- rpctls_checkcrl();
- else
- rpctlscd_verbose_out("rpc.tlsclntd: Can't "
- "reload CRLfile\n");
- clock_gettime(CLOCK_MONOTONIC, &tp);
- nexttime = tp.tv_sec;
- nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 +
- RELOADDELAY;
- } else
- sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
+ rpctls_svc_run();
- /*
- * If a reload is pending, poll for received request(s),
- * otherwise set a RELOADDELAY timeout, since a SIGHUP
- * could be processed between the got_sighup test and
- * the select() system call.
- */
- tm.tv_sec = 0;
- if (rpctls_gothup)
- tm.tv_usec = 0;
- else
- tm.tv_usec = RELOADDELAY;
- readfds = svc_fdset;
- switch (select(svc_maxfd + 1, &readfds, NULL, NULL, &tm)) {
- case -1:
- if (errno == EINTR) {
- /* Allow a reload now. */
- nexttime = 0;
- continue;
- }
- syslog(LOG_ERR, "rpc.tlsservd died: select: %m");
- exit(1);
- case 0:
- /* Allow a reload now. */
- nexttime = 0;
- continue;
- default:
- svc_getreqset(&readfds);
- }
- }
-
rpctls_syscall(RPCTLS_SYSC_CLSHUTDOWN, "");
SSL_CTX_free(rpctls_ctx);
@@ -367,26 +286,11 @@ main(int argc, char **argv)
return (0);
}
-static void
-rpctlscd_verbose_out(const char *fmt, ...)
-{
- va_list ap;
-
- if (rpctls_verbose) {
- 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");
+ rpctls_verbose_out("rpctlscd_null: done\n");
return (TRUE);
}
@@ -402,10 +306,10 @@ rpctlscd_connect_1_svc(void *argp,
struct ssl_entry *newslp;
X509 *cert;
- rpctlscd_verbose_out("rpctlsd_connect: started\n");
+ rpctls_verbose_out("rpctlsd_connect: started\n");
/* Get the socket fd from the kernel. */
s = rpctls_syscall(RPCTLS_SYSC_CLSOCKET, "");
-rpctlscd_verbose_out("rpctlsd_connect s=%d\n", s);
+rpctls_verbose_out("rpctlsd_connect s=%d\n", s);
if (s < 0) {
result->reterr = RPCTLSERR_NOSOCKET;
return (TRUE);
@@ -414,7 +318,7 @@ rpctlscd_verbose_out("rpctlsd_connect s=%d\n", s);
/* Do a TLS connect handshake. */
ssl = rpctls_connect(rpctls_ctx, s, &cert);
if (ssl == NULL) {
- rpctlscd_verbose_out("rpctlsd_connect: can't do TLS "
+ rpctls_verbose_out("rpctlsd_connect: can't do TLS "
"handshake\n");
result->reterr = RPCTLSERR_NOSSL;
} else {
@@ -455,7 +359,7 @@ rpctlscd_handlerecord_1_svc(struct rpctlscd_handlereco
int ret;
char junk;
-rpctlscd_verbose_out("handlerec sslref=%jx\n", (uintmax_t)slp->refno);
+rpctls_verbose_out("handlerec sslref=%jx\n", (uintmax_t)slp->refno);
slp = NULL;
if (argp->sec == rpctls_ssl_sec && argp->usec ==
rpctls_ssl_usec) {
@@ -466,7 +370,7 @@ rpctlscd_verbose_out("handlerec sslref=%jx\n", (uintma
}
if (slp != NULL) {
- rpctlscd_verbose_out("rpctlscd_handlerecord fd=%d\n",
+ rpctls_verbose_out("rpctlscd_handlerecord fd=%d\n",
slp->s);
/*
* An SSL_read() of 0 bytes should fail, but it should
@@ -476,7 +380,7 @@ rpctlscd_verbose_out("handlerec sslref=%jx\n", (uintma
if (ret <= 0) {
/* Check to see if this was a close alert. */
ret = SSL_get_shutdown(slp->ssl);
-rpctlscd_verbose_out("get_shutdown2=%d\n", ret);
+rpctls_verbose_out("get_shutdown2=%d\n", ret);
if ((ret & (SSL_SENT_SHUTDOWN |
SSL_RECEIVED_SHUTDOWN)) == SSL_RECEIVED_SHUTDOWN)
SSL_shutdown(slp->ssl);
@@ -499,7 +403,7 @@ rpctlscd_disconnect_1_svc(struct rpctlscd_disconnect_a
struct ssl_entry *slp;
int ret;
-rpctlscd_verbose_out("disconnect refno=%jx\n", (uintmax_t)slp->refno);
+rpctls_verbose_out("disconnect refno=%jx\n", (uintmax_t)slp->refno);
slp = NULL;
if (argp->sec == rpctls_ssl_sec && argp->usec ==
rpctls_ssl_usec) {
@@ -510,12 +414,12 @@ rpctlscd_verbose_out("disconnect refno=%jx\n", (uintma
}
if (slp != NULL) {
- rpctlscd_verbose_out("rpctlscd_disconnect: fd=%d closed\n",
+ rpctls_verbose_out("rpctlscd_disconnect: fd=%d closed\n",
slp->s);
LIST_REMOVE(slp, next);
if (!slp->shutoff) {
ret = SSL_get_shutdown(slp->ssl);
-rpctlscd_verbose_out("get_shutdown0=%d\n", ret);
+rpctls_verbose_out("get_shutdown0=%d\n", ret);
/*
* Do an SSL_shutdown() unless a close alert has
* already been sent.
@@ -571,7 +475,7 @@ rpctls_setupcl_ssl(bool cert)
ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: SSL_CTX_new "
+ rpctls_verbose_out("rpctls_setupcl_ssl: SSL_CTX_new "
"failed\n");
return (NULL);
}
@@ -583,7 +487,7 @@ rpctls_setupcl_ssl(bool cert)
*/
ret = SSL_CTX_set_cipher_list(ctx, _PREFERRED_CIPHERS);
if (ret == 0) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: "
+ rpctls_verbose_out("rpctls_setupcl_ssl: "
"SSL_CTX_set_cipher_list failed to set any ciphers\n");
SSL_CTX_free(ctx);
return (NULL);
@@ -604,7 +508,7 @@ rpctls_setupcl_ssl(bool cert)
ret = SSL_CTX_use_certificate_file(ctx, path,
SSL_FILETYPE_PEM);
if (ret != 1) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: can't use "
+ rpctls_verbose_out("rpctls_setupcl_ssl: can't use "
"certificate file path=%s ret=%d\n", path, ret);
SSL_CTX_free(ctx);
return (NULL);
@@ -616,7 +520,7 @@ rpctls_setupcl_ssl(bool cert)
ret = SSL_CTX_use_PrivateKey_file(ctx, path,
SSL_FILETYPE_PEM);
if (ret != 1) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: Can't use "
+ rpctls_verbose_out("rpctls_setupcl_ssl: Can't use "
"private key path=%s ret=%d\n", path, ret);
SSL_CTX_free(ctx);
return (NULL);
@@ -626,7 +530,7 @@ rpctls_setupcl_ssl(bool cert)
if (rpctls_crlfile != NULL) {
ret = rpctls_loadcrlfile(ctx);
if (ret == 0) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: "
+ rpctls_verbose_out("rpctls_setupcl_ssl: "
"Load CRLfile failed\n");
SSL_CTX_free(ctx);
return (NULL);
@@ -645,7 +549,7 @@ rpctls_setupcl_ssl(bool cert)
rpctls_verify_cafile, rpctls_verify_capath);
#endif
if (ret == 0) {
- rpctlscd_verbose_out("rpctls_setupcl_ssl: "
+ rpctls_verbose_out("rpctls_setupcl_ssl: "
"Can't load verify locations\n");
SSL_CTX_free(ctx);
return (NULL);
@@ -685,21 +589,21 @@ rpctls_connect(SSL_CTX *ctx, int s, X509 **certp)
*certp = NULL;
ssl = SSL_new(ctx);
if (ssl == NULL) {
- rpctlscd_verbose_out("rpctls_connect: "
+ rpctls_verbose_out("rpctls_connect: "
"SSL_new failed\n");
return (NULL);
}
if (SSL_set_fd(ssl, s) != 1) {
- rpctlscd_verbose_out("rpctls_connect: "
+ rpctls_verbose_out("rpctls_connect: "
"SSL_set_fd failed\n");
SSL_free(ssl);
return (NULL);
}
-rpctlscd_verbose_out("at SSL_connect\n");
+rpctls_verbose_out("at SSL_connect\n");
ret = SSL_connect(ssl);
-rpctlscd_verbose_out("aft SSL_connect ret=%d\n", ret);
+rpctls_verbose_out("aft SSL_connect ret=%d\n", ret);
if (ret != 1) {
- rpctlscd_verbose_out("rpctls_connect: "
+ rpctls_verbose_out("rpctls_connect: "
"SSL_connect failed %d\n",
ret);
SSL_free(ssl);
@@ -708,7 +612,7 @@ rpctlscd_verbose_out("aft SSL_connect ret=%d\n", ret);
cert = SSL_get_peer_certificate(ssl);
if (cert == NULL) {
- rpctlscd_verbose_out("rpctls_connect: get peer"
+ rpctls_verbose_out("rpctls_connect: get peer"
" certificate failed\n");
SSL_free(ssl);
return (NULL);
@@ -719,7 +623,7 @@ rpctlscd_verbose_out("aft SSL_connect ret=%d\n", ret);
ret = SSL_get_verify_result(ssl);
if (ret == X509_V_OK && (rpctls_verify_cafile != NULL ||
rpctls_verify_capath != NULL) && (gethostret == 0 ||
- rpctls_checkhost(sad, cert) != 1))
+ rpctls_checkhost(sad, cert, X509_CHECK_FLAG_NO_WILDCARDS) != 1))
ret = X509_V_ERR_HOSTNAME_MISMATCH;
if (ret != X509_V_OK && (rpctls_verify_cafile != NULL ||
rpctls_verify_capath != NULL)) {
@@ -748,10 +652,10 @@ rpctlscd_verbose_out("aft SSL_connect ret=%d\n", ret);
/* Check to see if ktls is enabled on the connection. */
ret = BIO_get_ktls_send(SSL_get_wbio(ssl));
- rpctlscd_verbose_out("rpctls_connect: BIO_get_ktls_send=%d\n", ret);
+ rpctls_verbose_out("rpctls_connect: BIO_get_ktls_send=%d\n", ret);
if (ret != 0) {
ret = BIO_get_ktls_recv(SSL_get_rbio(ssl));
- rpctlscd_verbose_out("rpctls_connect: BIO_get_ktls_recv=%d\n",
+ rpctls_verbose_out("rpctls_connect: BIO_get_ktls_recv=%d\n",
ret);
}
if (ret == 0) {
@@ -772,142 +676,9 @@ rpctlscd_verbose_out("aft SSL_connect ret=%d\n", ret);
return (ssl);
}
-/*
- * Get the server's IP address.
- */
-static int
-rpctls_gethost(int s, struct sockaddr *sad, char *hostip, size_t hostlen)
-{
- socklen_t slen;
- int ret;
-
- slen = sizeof(struct sockaddr_storage);
- if (getpeername(s, sad, &slen) < 0)
- return (0);
- ret = 0;
- if (getnameinfo((const struct sockaddr *)sad,
- sad->sa_len, hostip, hostlen,
- NULL, 0, NI_NUMERICHOST) == 0) {
- rpctlscd_verbose_out("rpctls_gethost: %s\n",
- hostip);
- ret = 1;
- }
- return (ret);
-}
-
-/*
- * Check a server IP address against any host address in the
- * certificate. Basically getnameinfo(3) and
- * X509_check_host().
- */
-static int
-rpctls_checkhost(struct sockaddr *sad, X509 *cert)
-{
- char hostnam[NI_MAXHOST];
- int ret;
-
- if (getnameinfo((const struct sockaddr *)sad,
- sad->sa_len, hostnam, sizeof(hostnam),
- NULL, 0, NI_NAMEREQD) != 0)
- return (0);
- rpctlscd_verbose_out("rpctls_checkhost: DNS %s\n",
- hostnam);
- ret = X509_check_host(cert, hostnam, strlen(hostnam),
- X509_CHECK_FLAG_NO_WILDCARDS, NULL);
- return (ret);
-}
-
-/*
- * (re)load the CRLfile into the certificate verification store.
- */
-static int
-rpctls_loadcrlfile(SSL_CTX *ctx)
-{
- X509_STORE *certstore;
- X509_LOOKUP *certlookup;
- int ret;
-
- if ((rpctls_verify_cafile != NULL ||
- rpctls_verify_capath != NULL) &&
- rpctls_crlfile != NULL) {
- certstore = SSL_CTX_get_cert_store(ctx);
- certlookup = X509_STORE_add_lookup(
- certstore, X509_LOOKUP_file());
- ret = 0;
- if (certlookup != NULL)
- ret = X509_load_crl_file(certlookup,
- rpctls_crlfile, X509_FILETYPE_PEM);
- if (ret != 0)
- ret = X509_STORE_set_flags(certstore,
- X509_V_FLAG_CRL_CHECK |
- X509_V_FLAG_CRL_CHECK_ALL);
- if (ret == 0) {
- rpctlscd_verbose_out(
- "rpctls_loadcrlfile: Can't"
- " load CRLfile=%s\n",
- rpctls_crlfile);
- return (ret);
- }
- }
- return (1);
-}
-
static void
rpctls_huphandler(int sig __unused)
{
rpctls_gothup = true;
-}
-
-/*
- * Read the CRL file and check for any extant connections
- * that might now be revoked.
- */
-static void
-rpctls_checkcrl(void)
-{
- struct ssl_entry *slp;
- BIO *infile;
- X509_CRL *crl;
- X509_REVOKED *revoked;
- int ret;
-
- if (rpctls_crlfile == NULL || (rpctls_verify_cafile == NULL &&
- rpctls_verify_capath == NULL))
- return;
- infile = BIO_new(BIO_s_file());
- if (infile == NULL) {
- rpctlscd_verbose_out("rpctls_checkcrl: Cannot BIO_new\n");
- return;
- }
- ret = BIO_read_filename(infile, rpctls_crlfile);
- if (ret != 1) {
- rpctlscd_verbose_out("rpctls_checkcrl: Cannot read CRL file\n");
- BIO_free(infile);
- return;
- }
-
- for (crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, "");
- crl != NULL; crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, "")) {
- LIST_FOREACH(slp, &rpctls_ssllist, next) {
- if (slp->cert != NULL) {
- ret = X509_CRL_get0_by_cert(crl, &revoked,
- slp->cert);
-rpctlscd_verbose_out("get0_by_cert=%d\n", ret);
- /*
- * Do a shutdown on the socket, so that it
- * can no longer be used. The kernel RPC
- * code will notice the socket is disabled
- * and will do a disconnect upcall, which will
- * close the socket.
- */
- if (ret == 1) {
- shutdown(slp->s, SHUT_WR);
- slp->shutoff = true;
- }
- }
- }
- X509_CRL_free(crl);
- }
- BIO_free(infile);
}
Modified: projects/nfs-over-tls/usr.sbin/rpc.tlsservd/Makefile
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpc.tlsservd/Makefile Fri Sep 18 00:02:58 2020 (r365865)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsservd/Makefile Fri Sep 18 01:11:11 2020 (r365866)
@@ -4,7 +4,7 @@
PROG= rpc.tlsservd
MAN= rpc.tlsservd.8
-SRCS= rpc.tlsservd.c rpctlssd.h rpctlssd_svc.c rpctlssd_xdr.c
+SRCS= rpc.tlsservd.c rpc.tlscommon.c rpctlssd.h rpctlssd_svc.c rpctlssd_xdr.c
CFLAGS+= -I.
Added: projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.c Fri Sep 18 01:11:11 2020 (r365866)
@@ -0,0 +1,305 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Rick Macklem
+ *
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <netdb.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+
+#include <openssl/opensslconf.h>
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "rpctlssd.h"
+#include "rpc.tlscommon.h"
+
+/* Global variables defined in the daemons. */
+extern bool rpctls_gothup;
+extern bool rpctls_verbose;
+extern int rpctls_debug_level;
+extern SSL_CTX *rpctls_ctx;
+extern const char *rpctls_verify_cafile;
+extern const char *rpctls_verify_capath;
+extern const char *rpctls_crlfile;
+extern struct ssl_list rpctls_ssllist;
+
+/*
+ * How long to delay a reload of the CRL when there are RPC request(s)
+ * to process, in usec. Must be less than 1second.
+ */
+#define RELOADDELAY 250000
+
+void
+rpctls_svc_run(void)
+{
+ int ret;
+ struct timeval tv;
+ fd_set readfds;
+ uint64_t curtime, nexttime;
+ struct timespec tp;
+ sigset_t sighup_mask;
+
+ /* Expand svc_run() here so that we can call rpctls_loadcrlfile(). */
+ curtime = nexttime = 0;
+ sigemptyset(&sighup_mask);
+ sigaddset(&sighup_mask, SIGHUP);
+ for (;;) {
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ curtime = tp.tv_sec;
+ curtime = curtime * 1000000 + tp.tv_nsec / 1000;
+ sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
+ if (rpctls_gothup && curtime >= nexttime) {
+ rpctls_gothup = false;
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
+ ret = rpctls_loadcrlfile(rpctls_ctx);
+ if (ret != 0)
+ rpctls_checkcrl();
+ else
+ rpctls_verbose_out("rpc.tlsservd: Can't "
+ "reload CRLfile\n");
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ nexttime = tp.tv_sec;
+ nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 +
+ RELOADDELAY;
+ } else
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
+
+ /*
+ * If a reload is pending, poll for received request(s),
+ * otherwise set a RELOADDELAY timeout, since a SIGHUP
+ * could be processed between the got_sighup test and
+ * the select() system call.
+ */
+ tv.tv_sec = 0;
+ if (rpctls_gothup)
+ tv.tv_usec = 0;
+ else
+ tv.tv_usec = RELOADDELAY;
+ readfds = svc_fdset;
+ switch (select(svc_maxfd + 1, &readfds, NULL, NULL, &tv)) {
+ case -1:
+ if (errno == EINTR) {
+ /* Allow a reload now. */
+ nexttime = 0;
+ continue;
+ }
+ syslog(LOG_ERR, "rpc.tls daemon died: select: %m");
+ exit(1);
+ case 0:
+ /* Allow a reload now. */
+ nexttime = 0;
+ continue;
+ default:
+ svc_getreqset(&readfds);
+ }
+ }
+}
+
+/*
+ * (re)load the CRLfile into the certificate verification store.
+ */
+int
+rpctls_loadcrlfile(SSL_CTX *ctx)
+{
+ X509_STORE *certstore;
+ X509_LOOKUP *certlookup;
+ int ret;
+
+ if ((rpctls_verify_cafile != NULL ||
+ rpctls_verify_capath != NULL) &&
+ rpctls_crlfile != NULL) {
+ certstore = SSL_CTX_get_cert_store(ctx);
+ certlookup = X509_STORE_add_lookup(
+ certstore, X509_LOOKUP_file());
+ ret = 0;
+ if (certlookup != NULL)
+ ret = X509_load_crl_file(certlookup,
+ rpctls_crlfile, X509_FILETYPE_PEM);
+ if (ret != 0)
+ ret = X509_STORE_set_flags(certstore,
+ X509_V_FLAG_CRL_CHECK |
+ X509_V_FLAG_CRL_CHECK_ALL);
+ if (ret == 0) {
+ rpctls_verbose_out(
+ "rpctls_loadcrlfile: Can't"
+ " load CRLfile=%s\n",
+ rpctls_crlfile);
+ return (ret);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Read the CRL file and check for any extant connections
+ * that might now be revoked.
+ */
+void
+rpctls_checkcrl(void)
+{
+ struct ssl_entry *slp;
+ BIO *infile;
+ X509_CRL *crl;
+ X509_REVOKED *revoked;
+ char *cp, *cp2;
+ int ret;
+
+ if (rpctls_crlfile == NULL || (rpctls_verify_cafile == NULL &&
+ rpctls_verify_capath == NULL))
+ return;
+ infile = BIO_new(BIO_s_file());
+ if (infile == NULL) {
+ rpctls_verbose_out("rpctls_checkcrl: Cannot BIO_new\n");
+ return;
+ }
+ ret = BIO_read_filename(infile, rpctls_crlfile);
+ if (ret != 1) {
+ rpctls_verbose_out("rpctls_checkcrl: Cannot read CRL file\n");
+ BIO_free(infile);
+ return;
+ }
+
+ for (crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, "");
+ crl != NULL; crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, "")) {
+ LIST_FOREACH(slp, &rpctls_ssllist, next) {
+ if (slp->cert != NULL) {
+ ret = X509_CRL_get0_by_cert(crl, &revoked,
+ slp->cert);
+rpctls_verbose_out("get0_by_cert=%d\n", ret);
+ /*
+ * Do a shutdown on the socket, so that it
+ * can no longer be used. The kernel RPC
+ * code will notice the socket is disabled
+ * and will do a disconnect upcall, which will
+ * close the socket.
+ */
+ if (ret == 1) {
+ cp2 = X509_NAME_oneline(
+ X509_get_subject_name(slp->cert),
+ NULL, 0);
+ cp = X509_NAME_oneline(
+ X509_get_issuer_name(slp->cert),
+ NULL, 0);
+ if (rpctls_debug_level == 0)
+ syslog(LOG_INFO | LOG_DAEMON,
+ "rpctls_daemon: Certificate"
+ " Revoked "
+ "issuerName=%s "
+ "subjectName=%s: "
+ "TCP connection closed",
+ cp, cp2);
+ else
+ fprintf(stderr,
+ "rpctls_daemon: Certificate"
+ " Revoked "
+ "issuerName=%s "
+ "subjectName=%s: "
+ "TCP connection closed",
+ cp, cp2);
+ shutdown(slp->s, SHUT_WR);
+ slp->shutoff = true;
+ }
+ }
+ }
+ X509_CRL_free(crl);
+ }
+ BIO_free(infile);
+}
+
+void
+rpctls_verbose_out(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (rpctls_verbose) {
+ va_start(ap, fmt);
+ if (rpctls_debug_level == 0)
+ vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap);
+ else
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+}
+
+/*
+ * Check a IP address against any host address in the
+ * certificate. Basically getnameinfo(3) and
+ * X509_check_host().
+ */
+int
+rpctls_checkhost(struct sockaddr *sad, X509 *cert, unsigned int wildcard)
+{
+ char hostnam[NI_MAXHOST];
+ int ret;
+
+ if (getnameinfo((const struct sockaddr *)sad,
+ sad->sa_len, hostnam, sizeof(hostnam),
+ NULL, 0, NI_NAMEREQD) != 0)
+ return (0);
+ rpctls_verbose_out("rpctls_checkhost: DNS %s\n",
+ hostnam);
+ ret = X509_check_host(cert, hostnam, strlen(hostnam),
+ wildcard, NULL);
+ return (ret);
+}
+
+/*
+ * Get the peer's IP address.
+ */
+int
+rpctls_gethost(int s, struct sockaddr *sad, char *hostip, size_t hostlen)
+{
+ socklen_t slen;
+ int ret;
+
+ slen = sizeof(struct sockaddr_storage);
+ if (getpeername(s, sad, &slen) < 0)
+ return (0);
+ ret = 0;
+ if (getnameinfo((const struct sockaddr *)sad,
+ sad->sa_len, hostip, hostlen,
+ NULL, 0, NI_NUMERICHOST) == 0) {
+ rpctls_verbose_out("rpctls_gethost: %s\n",
+ hostip);
+ ret = 1;
+ }
+ return (ret);
+}
Added: projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlscommon.h Fri Sep 18 01:11:11 2020 (r365866)
@@ -0,0 +1,56 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Rick Macklem
+ *
+ * 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$
+ */
+
+/*
+ * Functions in rpc.tlscommon.c used by both rpc.tlsservd.c and rpc.tlsclntd.c.
+ */
+int rpctls_gethost(int s, struct sockaddr *sad,
+ char *hostip, size_t hostlen);
+int rpctls_checkhost(struct sockaddr *sad, X509 *cert,
+ unsigned int wildcard);
+int rpctls_loadcrlfile(SSL_CTX *ctx);
+void rpctls_checkcrl(void);
+void rpctls_verbose_out(const char *fmt, ...);
+void rpctls_svc_run(void);
+
+/*
+ * A linked list of all current "SSL *"s and socket "fd"s
+ * for kernel RPC TLS connections is maintained.
+ * The "refno" field is a unique 64bit value used to
+ * identify which entry a kernel RPC upcall refers to.
+ */
+LIST_HEAD(ssl_list, ssl_entry);
+struct ssl_entry {
+ LIST_ENTRY(ssl_entry) next;
+ uint64_t refno;
+ int s;
+ bool shutoff;
+ SSL *ssl;
+ X509 *cert;
+};
Modified: projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlsservd.c
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlsservd.c Fri Sep 18 00:02:58 2020 (r365865)
+++ projects/nfs-over-tls/usr.sbin/rpc.tlsservd/rpc.tlsservd.c Fri Sep 18 01:11:11 2020 (r365866)
@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <openssl/x509v3.h>
#include "rpctlssd.h"
+#include "rpc.tlscommon.h"
#ifndef _PATH_RPCTLSSDSOCK
#define _PATH_RPCTLSSDSOCK "/var/run/rpc.tlsservd.sock"
@@ -78,63 +79,37 @@ __FBSDID("$FreeBSD$");
#define _PREFERRED_CIPHERS "AES128-GCM-SHA256"
#endif
-/*
- * How long to delay a reload of the CRL when there are RPC request(s)
- * to process, in usec. Must be less than 1second.
- */
-#define RELOADDELAY 250000
+/* Global variables also used by rpc.tlscommon.c. */
+int rpctls_debug_level;
+bool rpctls_verbose;
+SSL_CTX *rpctls_ctx = NULL;
+const char *rpctls_verify_cafile = NULL;
+const char *rpctls_verify_capath = NULL;
+const char *rpctls_crlfile = NULL;
+bool rpctls_gothup = false;
+struct ssl_list rpctls_ssllist;
static struct pidfh *rpctls_pfh = NULL;
-static int rpctls_debug_level;
-static bool rpctls_verbose;
-static SSL_CTX *rpctls_ctx = NULL;
static bool rpctls_do_mutual = false;
-static const char *rpctls_verify_cafile = NULL;
-static const char *rpctls_verify_capath = NULL;
-static const char *rpctls_crlfile = NULL;
static const char *rpctls_certdir = _PATH_CERTANDKEY;
static bool rpctls_comparehost = false;
static unsigned int rpctls_wildcard = X509_CHECK_FLAG_NO_WILDCARDS;
static uint64_t rpctls_ssl_refno = 0;
static uint64_t rpctls_ssl_sec = 0;
static uint64_t rpctls_ssl_usec = 0;
-static bool rpctls_gothup = false;
static bool rpctls_cnuser = false;
static char *rpctls_dnsname;
static const char *rpctls_cnuseroid = "1.3.6.1.4.1.2238.1.1.1";
-/*
- * A linked list of all current "SSL *"s and socket "fd"s
- * for kernel RPC TLS connections is maintained.
- * The "refno" field is a unique 64bit value used to
- * identify which entry a kernel RPC upcall refers to.
- */
-LIST_HEAD(ssl_list, ssl_entry);
-struct ssl_entry {
- LIST_ENTRY(ssl_entry) next;
- uint64_t refno;
- int s;
- bool shutoff;
- SSL *ssl;
- X509 *cert;
-};
-static struct ssl_list rpctls_ssllist;
-
static void rpctlssd_terminate(int);
static SSL_CTX *rpctls_setup_ssl(const char *certdir);
static SSL *rpctls_server(SSL_CTX *ctx, int s,
uint32_t *flags, uint32_t *uidp,
int *ngrps, uint32_t *gidp, X509 **certp);
-static int rpctls_gethost(int s, struct sockaddr *sad,
- char *hostip, size_t hostlen);
-static int rpctls_checkhost(struct sockaddr *sad, X509 *cert);
-static int rpctls_loadcrlfile(SSL_CTX *ctx);
static int rpctls_cnname(X509 *cert, uint32_t *uidp,
int *ngrps, uint32_t *gidp);
static char *rpctls_getdnsname(char *dnsname);
static void rpctls_huphandler(int sig __unused);
-static void rpctls_checkcrl(void);
-static void rpctlssd_verbose_out(const char *fmt, ...);
extern void rpctlssd_1(struct svc_req *rqstp, SVCXPRT *transp);
@@ -163,16 +138,12 @@ main(int argc, char **argv)
* TLS handshake.
*/
struct sockaddr_un sun;
- int ch, debug, fd, oldmask, ret;
+ int ch, debug, fd, oldmask;
SVCXPRT *xprt;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list