svn commit: r359618 - projects/nfs-over-tls/usr.sbin/rpctlscd
Rick Macklem
rmacklem at FreeBSD.org
Fri Apr 3 22:21:11 UTC 2020
Author: rmacklem
Date: Fri Apr 3 22:13:53 2020
New Revision: 359618
URL: https://svnweb.freebsd.org/changeset/base/359618
Log:
Update the rpctlscd in several areas.
This patch updates/fixes the rpctlscd in the following areas:
- Fix handling of the CRL file and add code to reload it when a SIGHUP
is posted to the daemon.
- Move the creation of the SSL_CTX * to before the program daemonizes.
This was done so that it can prompt for a passphrase for the case
where the client has a certificate with an encrypted key.
- Fix up options.
- Make the handling of the server hostname in the certificate not
accept a wildcard, as recommended by RFC6125.
Modified:
projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c
Modified: projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c Fri Apr 3 22:06:55 2020 (r359617)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c Fri Apr 3 22:13:53 2020 (r359618)
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <sys/time.h>
#include <err.h>
+#include <libutil.h>
#include <netdb.h>
#include <signal.h>
#include <stdarg.h>
@@ -67,10 +68,14 @@ __FBSDID("$FreeBSD$");
#ifndef _PATH_CERTANDKEY
#define _PATH_CERTANDKEY "/etc/rpctlscd/"
#endif
+#ifndef _PATH_RPCTLSCDPID
+#define _PATH_RPCTLSCDPID "/var/run/rpctlscd.pid"
+#endif
#ifndef _PREFERRED_CIPHERS
#define _PREFERRED_CIPHERS "SHA384:SHA256:!CAMELLIA"
#endif
+static struct pidfh *rpctls_pfh = NULL;
static int rpctls_debug_level;
static bool rpctls_verbose;
static int testnossl;
@@ -79,8 +84,6 @@ 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_verify = false;
-static bool rpctls_comparehost = false;
static uint64_t rpctls_ssl_refno = 0;
static uint64_t rpctls_ssl_sec = 0;
static uint64_t rpctls_ssl_usec = 0;
@@ -104,8 +107,10 @@ 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);
-static int rpctls_checkhost(int s, X509 *cert);
-static int rpctls_loadfiles(SSL_CTX *ctx);
+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);
extern void rpctlscd_1(struct svc_req *rqstp, SVCXPRT *transp);
@@ -125,7 +130,16 @@ main(int argc, char **argv)
bool cert;
struct timeval tm;
struct timezone tz;
+ pid_t otherpid;
+ /* Check that another rpctlscd isn't already running. */
+ rpctls_pfh = pidfile_open(_PATH_RPCTLSCDPID, 0600, &otherpid);
+ if (rpctls_pfh == NULL) {
+ if (errno == EEXIST)
+ errx(1, "rpctlscd already running, pid: %d.", otherpid);
+ warn("cannot open or create pidfile");
+ }
+
/* Get the time when this daemon is started. */
gettimeofday(&tm, &tz);
rpctls_ssl_sec = tm.tv_sec;
@@ -134,7 +148,7 @@ main(int argc, char **argv)
rpctls_verbose = false;
testnossl = 0;
cert = false;
- while ((ch = getopt(argc, argv, "D:dhl:mp:rtVv")) != -1) {
+ while ((ch = getopt(argc, argv, "D:dl:mp:r:tv")) != -1) {
switch (ch) {
case 'D':
rpctls_certdir = optarg;
@@ -142,9 +156,6 @@ main(int argc, char **argv)
case 'd':
rpctls_debug_level++;
break;
- case 'h':
- rpctls_comparehost = true;
- break;
case 'l':
rpctls_verify_cafile = optarg;
break;
@@ -160,22 +171,23 @@ main(int argc, char **argv)
case 't':
testnossl = 1;
break;
- case 'V':
- rpctls_verify = true;
- break;
case 'v':
rpctls_verbose = true;
break;
default:
fprintf(stderr, "usage: %s "
- "[-D certdir] [-d] [-h] "
+ "[-D certdir] [-d] "
"[-l CAfile] [-m] "
"[-p CApath] [-r CRLfile] "
- "[-V] [-v]\n", argv[0]);
+ "[-v]\n", argv[0]);
exit(1);
break;
}
}
+ if (rpctls_crlfile != NULL && rpctls_verify_cafile == NULL &&
+ rpctls_verify_capath == NULL)
+ errx(1, "-r requires the -l <CAfile> and/or "
+ "-p <CApath> options");
if (modfind("krpc") < 0) {
/* Not present in kernel, try loading it */
@@ -183,6 +195,21 @@ main(int argc, char **argv)
errx(1, "Kernel RPC is not available");
}
+ /*
+ * Set up the SSL_CTX *.
+ * Do it now, before daemonizing, in case the private key
+ * is encrypted and requires a passphrase to be entered.
+ */
+ rpctls_ctx = rpctls_setupcl_ssl(cert);
+ 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");
+ }
+ LIST_INIT(&rpctls_ssllist);
+
if (!rpctls_debug_level) {
if (daemon(0, 0) != 0)
err(1, "Can't daemonize");
@@ -194,6 +221,8 @@ main(int argc, char **argv)
signal(SIGPIPE, rpctlscd_terminate);
signal(SIGHUP, rpctls_huphandler);
+ pidfile_write(rpctls_pfh);
+
memset(&sun, 0, sizeof sun);
sun.sun_family = AF_LOCAL;
unlink(_PATH_RPCTLSCDSOCK);
@@ -242,17 +271,6 @@ main(int argc, char **argv)
err(1, "Can't register service for local rpctlscd socket");
}
- /* Set up the OpenSSL TSL stuff. */
- rpctls_ctx = rpctls_setupcl_ssl(cert);
- 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");
- }
- LIST_INIT(&rpctls_ssllist);
-
gssd_syscall(_PATH_RPCTLSCDSOCK);
svc_run();
gssd_syscall("");
@@ -390,6 +408,7 @@ rpctlscd_terminate(int sig __unused)
{
gssd_syscall("");
+ pidfile_remove(rpctls_pfh);
exit(0);
}
@@ -461,10 +480,10 @@ rpctls_setupcl_ssl(bool cert)
}
if (rpctls_verify_cafile != NULL || rpctls_verify_capath != NULL) {
if (rpctls_crlfile != NULL) {
- ret = rpctls_loadfiles(ctx);
+ ret = rpctls_loadcrlfile(ctx);
if (ret == 0) {
- rpctlscd_verbose_out("rpctls_setup_ssl: "
- "Load CAfile, CRLfile failed\n");
+ rpctlscd_verbose_out("rpctls_setupcl_ssl: "
+ "Load CRLfile failed\n");
SSL_CTX_free(ctx);
return (NULL);
}
@@ -503,15 +522,18 @@ rpctls_connect(SSL_CTX *ctx, int s)
{
SSL *ssl;
X509 *cert;
- int ret;
- char *cp;
+ struct sockaddr *sad;
+ struct sockaddr_storage ad;
+ char hostnam[NI_MAXHOST];
+ int gethostret, ret;
+ char *cp, *cp2;
if (rpctls_gothup) {
rpctls_gothup = false;
- ret = rpctls_loadfiles(ctx);
+ ret = rpctls_loadcrlfile(ctx);
if (ret == 0)
rpctlscd_verbose_out("rpctls_connect: Can't "
- "load CAfile, CRLfile\n");
+ "reload CRLfile\n");
}
ssl = SSL_new(ctx);
if (ssl == NULL) {
@@ -542,18 +564,27 @@ rpctls_connect(SSL_CTX *ctx, int s)
SSL_free(ssl);
return (NULL);
}
- cp = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
- rpctlscd_verbose_out("rpctls_connect: cert issuerName=%s\n", cp);
- cp = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
- rpctlscd_verbose_out("rpctls_connect: cert subjectName=%s\n", cp);
+ gethostret = rpctls_gethost(s, sad, hostnam, sizeof(hostnam));
+ if (gethostret == 0)
+ hostnam[0] = '\0';
ret = SSL_get_verify_result(ssl);
- rpctlscd_verbose_out("rpctls_connect: get "
- "verify result=%d\n", ret);
- if (ret == X509_V_OK && rpctls_comparehost &&
- rpctls_checkhost(s, cert) != 1)
+ if (ret == X509_V_OK && (rpctls_verify_cafile != NULL ||
+ rpctls_verify_capath != NULL) && (gethostret == 0 ||
+ rpctls_checkhost(sad, cert) != 1))
ret = X509_V_ERR_HOSTNAME_MISMATCH;
X509_free(cert);
- if (rpctls_verify && ret != X509_V_OK) {
+ if (ret != X509_V_OK && (rpctls_verify_cafile != NULL ||
+ rpctls_verify_capath != NULL)) {
+ if (ret != X509_V_OK) {
+ cp = X509_NAME_oneline(X509_get_issuer_name(cert),
+ NULL, 0);
+ cp2 = X509_NAME_oneline(X509_get_subject_name(cert),
+ NULL, 0);
+ syslog(LOG_INFO | LOG_DAEMON, "rpctls_connect: client"
+ " IP %s issuerName=%s subjectName=%s verify "
+ "failed %s\n", hostnam, cp, cp2,
+ X509_verify_cert_error_string(ret));
+ }
SSL_shutdown(ssl);
SSL_free(ssl);
return (NULL);
@@ -569,81 +600,81 @@ rpctls_connect(SSL_CTX *ctx, int s)
}
/*
- * Check a client IP address against any host address in the
- * certificate. Basically getpeername(2), getnameinfo(3) and
- * X509_check_host().
+ * Get the server's IP address.
*/
static int
-rpctls_checkhost(int s, X509 *cert)
+rpctls_gethost(int s, struct sockaddr *sad, char *hostip, size_t hostlen)
{
- struct sockaddr *sad;
- struct sockaddr_storage ad;
- char hostnam[NI_MAXHOST];
socklen_t slen;
int ret;
- sad = (struct sockaddr *)&ad;
- slen = sizeof(ad);
+ slen = sizeof(struct sockaddr_storage);
if (getpeername(s, sad, &slen) < 0)
return (0);
+ ret = 0;
if (getnameinfo((const struct sockaddr *)sad,
- sad->sa_len, hostnam, sizeof(hostnam),
- NULL, 0, NI_NUMERICHOST) == 0)
- rpctlscd_verbose_out("rpctls_checkhost: %s\n",
- hostnam);
+ 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), 0, NULL);
+ 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);
}
/*
- * Load the CAfile (and optionally CRLfile) into the certificate
- * verification store.
+ * (re)load the CRLfile into the certificate verification store.
*/
static int
-rpctls_loadfiles(SSL_CTX *ctx)
+rpctls_loadcrlfile(SSL_CTX *ctx)
{
X509_STORE *certstore;
X509_LOOKUP *certlookup;
int ret;
- if (rpctls_verify_cafile != NULL ||
- rpctls_verify_capath != NULL) {
- if (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_loadfiles: Can't"
- " load CRLfile=%s\n",
- rpctls_crlfile);
- return (ret);
- }
- }
- ret = SSL_CTX_load_verify_locations(ctx,
- rpctls_verify_cafile, rpctls_verify_capath);
+ 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_loadfiles: "
- "Can't load verify locations\n");
+ rpctlscd_verbose_out(
+ "rpctls_loadcrlfile: Can't"
+ " load CRLfile=%s\n",
+ rpctls_crlfile);
return (ret);
}
- if (rpctls_verify_cafile != NULL)
- SSL_CTX_set_client_CA_list(ctx,
- SSL_load_client_CA_file(
- rpctls_verify_cafile));
}
return (1);
}
More information about the svn-src-projects
mailing list