1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 5 * Authors: Doug Rabson <dfr@rabson.org> 6 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 7 * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * Extensively modified from /usr/src/usr.sbin/gssd.c r344402 for 33 * the server side of kernel RPC-over-TLS by Rick Macklem. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/linker.h> 38 #include <sys/module.h> 39 #include <sys/queue.h> 40 #include <sys/sysctl.h> 41 #include <sys/syslog.h> 42 #include <assert.h> 43 #include <err.h> 44 #include <getopt.h> 45 #include <libutil.h> 46 #include <netdb.h> 47 #include <pthread.h> 48 #include <pwd.h> 49 #include <stdbool.h> 50 #include <unistd.h> 51 52 #include <rpc/rpc.h> 53 #include <rpc/rpc_com.h> 54 #include <rpc/rpcsec_tls.h> 55 56 #include <openssl/opensslconf.h> 57 #include <openssl/bio.h> 58 #include <openssl/ssl.h> 59 #include <openssl/err.h> 60 #include <openssl/x509v3.h> 61 62 #include "rpctlssd.h" 63 #include "rpc.tlscommon.h" 64 65 #ifndef _PATH_CERTANDKEY 66 #define _PATH_CERTANDKEY "/etc/rpc.tlsservd/" 67 #endif 68 #ifndef _PATH_RPCTLSSDPID 69 #define _PATH_RPCTLSSDPID "/var/run/rpc.tlsservd.pid" 70 #endif 71 #ifndef _PREFERRED_CIPHERS 72 #define _PREFERRED_CIPHERS "AES128-GCM-SHA256" 73 #endif 74 75 /* Global variables also used by rpc.tlscommon.c. */ 76 int rpctls_debug_level; 77 bool rpctls_verbose; 78 SSL_CTX *rpctls_ctx = NULL; 79 const char *rpctls_verify_cafile = NULL; 80 const char *rpctls_verify_capath = NULL; 81 char *rpctls_crlfile = NULL; 82 bool rpctls_gothup = false; 83 84 static SVCXPRT *xprt; 85 static pthread_key_t xidkey; 86 struct ssl_list rpctls_ssllist; 87 static pthread_rwlock_t rpctls_rwlock; 88 static u_int rpctls_nthreads = 0; 89 static pthread_mutex_t rpctls_mtx; 90 static pthread_cond_t rpctls_cv; 91 92 static struct pidfh *rpctls_pfh = NULL; 93 static bool rpctls_do_mutual = false; 94 static const char *rpctls_certdir = _PATH_CERTANDKEY; 95 static bool rpctls_comparehost = false; 96 static unsigned int rpctls_wildcard = X509_CHECK_FLAG_NO_WILDCARDS; 97 static bool rpctls_cnuser = false; 98 static char *rpctls_dnsname; 99 static const char *rpctls_cnuseroid = "1.3.6.1.4.1.2238.1.1.1"; 100 static const char *rpctls_ciphers = NULL; 101 static int rpctls_mintls = TLS1_3_VERSION; 102 static u_int rpctls_maxthreads; 103 104 static void rpctls_cleanup_term(int sig); 105 static SSL_CTX *rpctls_setup_ssl(const char *certdir); 106 static SSL *rpctls_server(SSL_CTX *ctx, int s, 107 uint32_t *flags, uint32_t *uidp, 108 int *ngrps, uint32_t *gidp, X509 **certp); 109 static int rpctls_cnname(X509 *cert, uint32_t *uidp, 110 int *ngrps, uint32_t *gidp); 111 static char *rpctls_getdnsname(char *dnsname); 112 static void rpctls_huphandler(int sig __unused); 113 114 extern void rpctlssd_2(struct svc_req *rqstp, SVCXPRT *transp); 115 116 static void *dummy_thread(void *v __unused) { return (NULL); } 117 118 static struct option longopts[] = { 119 { "allowtls1_2", no_argument, NULL, '2' }, 120 { "ciphers", required_argument, NULL, 'C' }, 121 { "certdir", required_argument, NULL, 'D' }, 122 { "debuglevel", no_argument, NULL, 'd' }, 123 { "checkhost", no_argument, NULL, 'h' }, 124 { "verifylocs", required_argument, NULL, 'l' }, 125 { "mutualverf", no_argument, NULL, 'm' }, 126 { "maxthreads", required_argument, NULL, 'N' }, 127 { "domain", required_argument, NULL, 'n' }, 128 { "verifydir", required_argument, NULL, 'p' }, 129 { "crl", required_argument, NULL, 'r' }, 130 { "certuser", no_argument, NULL, 'u' }, 131 { "verbose", no_argument, NULL, 'v' }, 132 { "multiwild", no_argument, NULL, 'W' }, 133 { "singlewild", no_argument, NULL, 'w' }, 134 { NULL, 0, NULL, 0 } 135 }; 136 137 int 138 main(int argc, char **argv) 139 { 140 int ch; 141 char hostname[MAXHOSTNAMELEN + 2]; 142 pid_t otherpid; 143 pthread_t tid; 144 bool tls_enable; 145 size_t tls_enable_len; 146 u_int ncpu; 147 148 /* Check that another rpctlssd isn't already running. */ 149 rpctls_pfh = pidfile_open(_PATH_RPCTLSSDPID, 0600, &otherpid); 150 if (rpctls_pfh == NULL) { 151 if (errno == EEXIST) 152 errx(1, "rpctlssd already running, pid: %d.", otherpid); 153 warn("cannot open or create pidfile"); 154 } 155 156 /* Check to see that the ktls is enabled. */ 157 tls_enable_len = sizeof(tls_enable); 158 if (sysctlbyname("kern.ipc.tls.enable", &tls_enable, &tls_enable_len, 159 NULL, 0) != 0 || !tls_enable) 160 errx(1, "Kernel TLS not enabled"); 161 162 /* Set the dns name for the server. */ 163 rpctls_dnsname = rpctls_getdnsname(hostname); 164 if (rpctls_dnsname == NULL) { 165 strcpy(hostname, "@default.domain"); 166 rpctls_dnsname = hostname; 167 } 168 169 rpctls_verbose = false; 170 ncpu = (u_int)sysconf(_SC_NPROCESSORS_ONLN); 171 #ifdef notnow 172 rpctls_maxthreads = ncpu > 1 ? ncpu / 2 : 1; 173 #else 174 /* XXX For now, until fixed properly!! */ 175 rpctls_maxthreads = 1; 176 #endif 177 178 while ((ch = getopt_long(argc, argv, "2C:D:dhl:N:n:mp:r:uvWw", longopts, 179 NULL)) != -1) { 180 switch (ch) { 181 case '2': 182 rpctls_mintls = TLS1_2_VERSION; 183 break; 184 case 'C': 185 rpctls_ciphers = optarg; 186 break; 187 case 'D': 188 rpctls_certdir = optarg; 189 break; 190 case 'd': 191 rpctls_debug_level++; 192 break; 193 case 'h': 194 rpctls_comparehost = true; 195 break; 196 case 'l': 197 rpctls_verify_cafile = optarg; 198 break; 199 case 'm': 200 rpctls_do_mutual = true; 201 break; 202 case 'N': 203 rpctls_maxthreads = atoi(optarg); 204 if (rpctls_maxthreads < 1 || rpctls_maxthreads > ncpu) 205 errx(1, "maximum threads must be between 1 and " 206 "number of CPUs (%d)", ncpu); 207 /* XXX For now, until fixed properly!! */ 208 rpctls_maxthreads = 1; 209 break; 210 case 'n': 211 hostname[0] = '@'; 212 strlcpy(&hostname[1], optarg, MAXHOSTNAMELEN + 1); 213 rpctls_dnsname = hostname; 214 break; 215 case 'p': 216 rpctls_verify_capath = optarg; 217 break; 218 case 'r': 219 rpctls_crlfile = optarg; 220 break; 221 case 'u': 222 rpctls_cnuser = true; 223 break; 224 case 'v': 225 rpctls_verbose = true; 226 break; 227 case 'W': 228 if (rpctls_wildcard != X509_CHECK_FLAG_NO_WILDCARDS) 229 errx(1, "options -w and -W are mutually " 230 "exclusive"); 231 rpctls_wildcard = X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; 232 break; 233 case 'w': 234 if (rpctls_wildcard != X509_CHECK_FLAG_NO_WILDCARDS) 235 errx(1, "options -w and -W are mutually " 236 "exclusive"); 237 rpctls_wildcard = 0; 238 break; 239 default: 240 fprintf(stderr, "usage: %s " 241 "[-2/--allowtls1_2] " 242 "[-C/--ciphers available_ciphers] " 243 "[-D/--certdir certdir] [-d/--debuglevel] " 244 "[-h/--checkhost] " 245 "[-l/--verifylocs CAfile] [-m/--mutualverf] " 246 "[-n/--domain domain_name] " 247 "[-p/--verifydir CApath] [-r/--crl CRLfile] " 248 "[-u/--certuser] [-v/--verbose] [-W/--multiwild] " 249 "[-w/--singlewild]\n", argv[0]); 250 exit(1); 251 } 252 } 253 if (rpctls_do_mutual && rpctls_verify_cafile == NULL && 254 rpctls_verify_capath == NULL) 255 errx(1, "-m requires the -l <CAfile> and/or " 256 "-p <CApath> options"); 257 if (rpctls_comparehost && (!rpctls_do_mutual || 258 (rpctls_verify_cafile == NULL && rpctls_verify_capath == NULL))) 259 errx(1, "-h requires the -m plus the " 260 "-l <CAfile> and/or -p <CApath> options"); 261 if (!rpctls_comparehost && rpctls_wildcard != 262 X509_CHECK_FLAG_NO_WILDCARDS) 263 errx(1, "The -w or -W options require the -h option"); 264 if (rpctls_cnuser && (!rpctls_do_mutual || 265 (rpctls_verify_cafile == NULL && rpctls_verify_capath == NULL))) 266 errx(1, "-u requires the -m plus the " 267 "-l <CAfile> and/or -p <CApath> options"); 268 269 if (modfind("krpc") < 0) { 270 /* Not present in kernel, try loading it */ 271 if (kldload("krpc") < 0 || modfind("krpc") < 0) 272 errx(1, "Kernel RPC is not available"); 273 } 274 signal(SIGPIPE, SIG_IGN); 275 signal(SIGHUP, rpctls_huphandler); 276 signal(SIGTERM, rpctls_cleanup_term); 277 278 if (rpctls_debug_level == 0 && daemon(0, 0) != 0) 279 err(1, "Can't daemonize"); 280 pidfile_write(rpctls_pfh); 281 282 /* 283 * XXX: Push libc internal state into threaded mode before creating 284 * the threaded svc_nl xprt. 285 */ 286 (void)pthread_create(&tid, NULL, dummy_thread, NULL); 287 (void)pthread_join(tid, NULL); 288 if ((xprt = svc_nl_create("tlsserv")) == NULL) { 289 if (rpctls_debug_level == 0) { 290 syslog(LOG_ERR, 291 "Can't create transport for local rpctlssd socket"); 292 exit(1); 293 } 294 err(1, "Can't create transport for local rpctlssd socket"); 295 } 296 if (!SVC_CONTROL(xprt, SVCNL_GET_XIDKEY, &xidkey)) 297 err(1, "Failed to obtain pthread key for xid from svc_nl"); 298 if (!svc_reg(xprt, RPCTLSSD, RPCTLSSDVERS, rpctlssd_2, NULL)) { 299 if (rpctls_debug_level == 0) { 300 syslog(LOG_ERR, 301 "Can't register service for local rpctlssd socket"); 302 exit(1); 303 } 304 err(1, "Can't register service for local rpctlssd socket"); 305 } 306 307 rpctls_ctx = rpctls_setup_ssl(rpctls_certdir); 308 if (rpctls_ctx == NULL) { 309 if (rpctls_debug_level == 0) { 310 syslog(LOG_ERR, "Can't create SSL context"); 311 exit(1); 312 } 313 err(1, "Can't create SSL context"); 314 } 315 rpctls_gothup = false; 316 pthread_rwlock_init(&rpctls_rwlock, NULL); 317 pthread_mutex_init(&rpctls_mtx, NULL); 318 pthread_cond_init(&rpctls_cv, NULL); 319 LIST_INIT(&rpctls_ssllist); 320 321 rpctls_svc_run(); 322 323 SSL_CTX_free(rpctls_ctx); 324 return (0); 325 } 326 327 bool_t 328 rpctlssd_null_2_svc(__unused void *argp, __unused void *result, 329 __unused struct svc_req *rqstp) 330 { 331 332 rpctls_verbose_out("rpctlssd_null_svc: done\n"); 333 return (TRUE); 334 } 335 336 /* 337 * To parallelize SSL handshakes we will launch a thread per handshake. Thread 338 * creation/destruction shall be order(s) of magnitude cheaper than a crypto 339 * handshake, so we are not keeping a pool of workers here. 340 * 341 * Marrying rpc(3) and pthread(3): 342 * 343 * Normally the rpcgen(1) generated rpctlssd_V() calls rpctlssd_connect_V_svc(), 344 * and the latter processes the RPC all the way to the end and returns a TRUE 345 * value and populates the result. The generated code immediately calls 346 * svc_sendreply() transmitting the result back. 347 * 348 * We will make a private copy of arguments and return FALSE. Then it is our 349 * obligation to call svc_sendreply() once we do the work in the thread. 350 */ 351 352 static void * rpctlssd_connect_thread(void *); 353 struct rpctlssd_connect_thread_ctx { 354 struct rpctlssd_connect_arg arg; 355 uint32_t xid; 356 }; 357 358 bool_t 359 rpctlssd_connect_2_svc(struct rpctlssd_connect_arg *argp, 360 struct rpctlssd_connect_res *result __unused, struct svc_req *rqstp) 361 { 362 struct rpctlssd_connect_thread_ctx *ctx; 363 pthread_t tid; 364 365 assert(rqstp->rq_xprt == xprt); 366 367 ctx = malloc(sizeof(*ctx)); 368 memcpy(&ctx->arg, argp, sizeof(ctx->arg)); 369 ctx->xid = *(uint32_t *)pthread_getspecific(xidkey); 370 371 pthread_mutex_lock(&rpctls_mtx); 372 while (rpctls_nthreads >= rpctls_maxthreads) 373 pthread_cond_wait(&rpctls_cv, &rpctls_mtx); 374 rpctls_nthreads++; 375 pthread_mutex_unlock(&rpctls_mtx); 376 377 rpctls_verbose_out("rpctlsd_connect_svc: xid %u thread %u\n", 378 ctx->xid, rpctls_nthreads); 379 380 if (pthread_create(&tid, NULL, rpctlssd_connect_thread, ctx) != 0) 381 warn("failed to start handshake thread"); 382 383 /* Intentionally, so that RPC generated code doesn't try to reply. */ 384 return (FALSE); 385 } 386 387 static void * 388 rpctlssd_connect_thread(void *v) 389 { 390 struct rpctlssd_connect_thread_ctx *ctx = v; 391 struct rpctlssd_connect_res result; 392 uint64_t socookie; 393 int ngrps, s; 394 SSL *ssl; 395 uint32_t flags; 396 struct ssl_entry *newslp; 397 uint32_t xid, uid; 398 uint32_t *gidp; 399 X509 *cert; 400 401 socookie = ctx->arg.socookie; 402 xid = ctx->xid; 403 free(ctx); 404 ctx = NULL; 405 pthread_detach(pthread_self()); 406 407 if (pthread_setspecific(xidkey, &xid) != 0) { 408 rpctls_verbose_out("rpctlssd_connect_svc: pthread_setspecific " 409 "failed\n"); 410 goto out; 411 } 412 413 /* Get the socket fd from the kernel. */ 414 s = rpctls_syscall(socookie); 415 if (s < 0) { 416 rpctls_verbose_out("rpctlssd_connect_svc: rpctls_syscall " 417 "accept failed\n"); 418 goto out; 419 } 420 421 /* Do the server side of a TLS handshake. */ 422 gidp = calloc(NGROUPS, sizeof(*gidp)); 423 ssl = rpctls_server(rpctls_ctx, s, &flags, &uid, &ngrps, gidp, &cert); 424 if (ssl == NULL) { 425 free(gidp); 426 rpctls_verbose_out("rpctlssd_connect_svc: ssl " 427 "accept failed\n"); 428 /* 429 * For RPC-over-TLS, this upcall is expected 430 * to close off the socket upon handshake failure. 431 */ 432 close(s); 433 goto out; 434 } else { 435 rpctls_verbose_out("rpctlssd_connect_svc: " 436 "succeeded flags=0x%x\n", flags); 437 if ((flags & RPCTLS_FLAGS_CERTUSER) != 0) 438 result = (struct rpctlssd_connect_res){ 439 .flags = flags, 440 .uid = uid, 441 .gid.gid_len = ngrps, 442 .gid.gid_val = gidp, 443 }; 444 else 445 result = (struct rpctlssd_connect_res){ 446 .flags = flags, 447 .uid = 0, 448 .gid.gid_len = 0, 449 .gid.gid_val = gidp, 450 }; 451 } 452 453 /* Maintain list of all current SSL *'s */ 454 newslp = malloc(sizeof(*newslp)); 455 newslp->ssl = ssl; 456 newslp->s = s; 457 newslp->shutoff = false; 458 newslp->cookie = socookie; 459 newslp->cert = cert; 460 pthread_rwlock_wrlock(&rpctls_rwlock); 461 LIST_INSERT_HEAD(&rpctls_ssllist, newslp, next); 462 pthread_rwlock_unlock(&rpctls_rwlock); 463 464 if (!svc_sendreply(xprt, (xdrproc_t)xdr_rpctlssd_connect_res, &result)) 465 svcerr_systemerr(xprt); 466 467 free(result.gid.gid_val); 468 rpctls_verbose_out("rpctlsd_connect_svc: xid %u: thread finished\n", 469 xid); 470 471 out: 472 pthread_mutex_lock(&rpctls_mtx); 473 if (rpctls_nthreads-- >= rpctls_maxthreads) { 474 pthread_mutex_unlock(&rpctls_mtx); 475 pthread_cond_signal(&rpctls_cv); 476 } else 477 pthread_mutex_unlock(&rpctls_mtx); 478 return (NULL); 479 } 480 481 bool_t 482 rpctlssd_handlerecord_2_svc(struct rpctlssd_handlerecord_arg *argp, 483 struct rpctlssd_handlerecord_res *result, __unused struct svc_req *rqstp) 484 { 485 struct ssl_entry *slp; 486 int ret; 487 char junk; 488 489 pthread_rwlock_rdlock(&rpctls_rwlock); 490 LIST_FOREACH(slp, &rpctls_ssllist, next) 491 if (slp->cookie == argp->socookie) 492 break; 493 pthread_rwlock_unlock(&rpctls_rwlock); 494 495 if (slp != NULL) { 496 rpctls_verbose_out("rpctlssd_handlerecord fd=%d\n", 497 slp->s); 498 /* 499 * An SSL_read() of 0 bytes should fail, but it should 500 * handle the non-application data record before doing so. 501 */ 502 ret = SSL_read(slp->ssl, &junk, 0); 503 if (ret <= 0) { 504 /* Check to see if this was a close alert. */ 505 ret = SSL_get_shutdown(slp->ssl); 506 if ((ret & (SSL_SENT_SHUTDOWN | 507 SSL_RECEIVED_SHUTDOWN)) == SSL_RECEIVED_SHUTDOWN) 508 SSL_shutdown(slp->ssl); 509 } else { 510 if (rpctls_debug_level == 0) 511 syslog(LOG_ERR, "SSL_read returned %d", ret); 512 else 513 fprintf(stderr, "SSL_read returned %d\n", ret); 514 } 515 result->reterr = RPCTLSERR_OK; 516 } else 517 result->reterr = RPCTLSERR_NOSSL; 518 return (TRUE); 519 } 520 521 bool_t 522 rpctlssd_disconnect_2_svc(struct rpctlssd_disconnect_arg *argp, 523 struct rpctlssd_disconnect_res *result, __unused struct svc_req *rqstp) 524 { 525 struct ssl_entry *slp; 526 int ret; 527 528 pthread_rwlock_wrlock(&rpctls_rwlock); 529 LIST_FOREACH(slp, &rpctls_ssllist, next) 530 if (slp->cookie == argp->socookie) { 531 LIST_REMOVE(slp, next); 532 break; 533 } 534 pthread_rwlock_unlock(&rpctls_rwlock); 535 536 if (slp != NULL) { 537 rpctls_verbose_out("rpctlssd_disconnect fd=%d closed\n", 538 slp->s); 539 if (!slp->shutoff) { 540 ret = SSL_get_shutdown(slp->ssl); 541 /* 542 * Do an SSL_shutdown() unless a close alert has 543 * already been sent. 544 */ 545 if ((ret & SSL_SENT_SHUTDOWN) == 0) 546 SSL_shutdown(slp->ssl); 547 } 548 SSL_free(slp->ssl); 549 if (slp->cert != NULL) 550 X509_free(slp->cert); 551 /* 552 * For RPC-over-TLS, this upcall is expected 553 * to close off the socket. 554 */ 555 if (!slp->shutoff) 556 shutdown(slp->s, SHUT_WR); 557 close(slp->s); 558 free(slp); 559 result->reterr = RPCTLSERR_OK; 560 } else 561 result->reterr = RPCTLSERR_NOCLOSE; 562 return (TRUE); 563 } 564 565 int 566 rpctlssd_2_freeresult(__unused SVCXPRT *transp, xdrproc_t xdr_result __unused, 567 caddr_t result __unused) 568 { 569 return (TRUE); 570 } 571 572 /* 573 * cleanup_term() called via SIGTERM (or SIGCHLD if a child dies). 574 */ 575 static void 576 rpctls_cleanup_term(int sig __unused) 577 { 578 struct ssl_entry *slp; 579 580 LIST_FOREACH(slp, &rpctls_ssllist, next) 581 shutdown(slp->s, SHUT_RD); 582 SSL_CTX_free(rpctls_ctx); 583 EVP_cleanup(); 584 pidfile_remove(rpctls_pfh); 585 586 exit(0); 587 } 588 589 /* Allow the handshake to proceed. */ 590 static int 591 rpctls_verify_callback(__unused int preverify_ok, 592 __unused X509_STORE_CTX *x509_ctx) 593 { 594 595 return (1); 596 } 597 598 static SSL_CTX * 599 rpctls_setup_ssl(const char *certdir) 600 { 601 SSL_CTX *ctx; 602 char path[PATH_MAX]; 603 size_t len, rlen; 604 int ret; 605 606 ctx = SSL_CTX_new(TLS_server_method()); 607 if (ctx == NULL) { 608 rpctls_verbose_out("rpctls_setup_ssl: SSL_CTX_new failed\n"); 609 return (NULL); 610 } 611 612 if (rpctls_ciphers != NULL) { 613 /* 614 * Set available ciphers, since KERN_TLS only supports a 615 * few of them. Normally, not doing this should be ok, 616 * since the library defaults will work. 617 */ 618 ret = SSL_CTX_set_ciphersuites(ctx, rpctls_ciphers); 619 if (ret == 0) { 620 rpctls_verbose_out("rpctls_setup_ssl: " 621 "SSL_CTX_set_ciphersuites failed: %s\n", 622 rpctls_ciphers); 623 SSL_CTX_free(ctx); 624 return (NULL); 625 } 626 } 627 628 ret = SSL_CTX_set_min_proto_version(ctx, rpctls_mintls); 629 if (ret == 0) { 630 rpctls_verbose_out("rpctls_setup_ssl: " 631 "SSL_CTX_set_min_proto_version failed\n"); 632 SSL_CTX_free(ctx); 633 return (NULL); 634 } 635 ret = SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); 636 if (ret == 0) { 637 rpctls_verbose_out("rpctls_setup_ssl: " 638 "SSL_CTX_set_max_proto_version failed\n"); 639 SSL_CTX_free(ctx); 640 return (NULL); 641 } 642 643 /* Get the cert.pem and certkey.pem files from the directory certdir. */ 644 len = strlcpy(path, certdir, sizeof(path)); 645 rlen = sizeof(path) - len; 646 if (strlcpy(&path[len], "cert.pem", rlen) != 8) { 647 SSL_CTX_free(ctx); 648 return (NULL); 649 } 650 ret = SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM); 651 if (ret != 1) { 652 rpctls_verbose_out("rpctls_setup_ssl: can't use certificate " 653 "file path=%s ret=%d\n", path, ret); 654 SSL_CTX_free(ctx); 655 return (NULL); 656 } 657 if (strlcpy(&path[len], "certkey.pem", rlen) != 11) { 658 SSL_CTX_free(ctx); 659 return (NULL); 660 } 661 ret = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM); 662 if (ret != 1) { 663 rpctls_verbose_out("rpctls_setup_ssl: Can't use private " 664 "key path=%s ret=%d\n", path, ret); 665 SSL_CTX_free(ctx); 666 return (NULL); 667 } 668 669 /* Set Mutual authentication, as required. */ 670 if (rpctls_do_mutual) { 671 if (rpctls_verify_cafile != NULL || 672 rpctls_verify_capath != NULL) { 673 if (rpctls_crlfile != NULL) { 674 ret = rpctls_loadcrlfile(ctx); 675 if (ret == 0) { 676 rpctls_verbose_out("rpctls_setup_ssl:" 677 " Load CRLfile failed\n"); 678 SSL_CTX_free(ctx); 679 return (NULL); 680 } 681 } 682 #if OPENSSL_VERSION_NUMBER >= 0x30000000 683 ret = 1; 684 if (rpctls_verify_cafile != NULL) 685 ret = SSL_CTX_load_verify_file(ctx, 686 rpctls_verify_cafile); 687 if (ret != 0 && rpctls_verify_capath != NULL) 688 ret = SSL_CTX_load_verify_dir(ctx, 689 rpctls_verify_capath); 690 #else 691 ret = SSL_CTX_load_verify_locations(ctx, 692 rpctls_verify_cafile, rpctls_verify_capath); 693 #endif 694 if (ret == 0) { 695 rpctls_verbose_out("rpctls_setup_ssl: " 696 "Can't load verify locations\n"); 697 SSL_CTX_free(ctx); 698 return (NULL); 699 } 700 if (rpctls_verify_cafile != NULL) 701 SSL_CTX_set_client_CA_list(ctx, 702 SSL_load_client_CA_file( 703 rpctls_verify_cafile)); 704 } 705 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 706 rpctls_verify_callback); 707 } 708 #ifdef SSL_OP_ENABLE_KTLS 709 SSL_CTX_set_options(ctx, SSL_OP_ENABLE_KTLS); 710 #endif 711 #ifdef SSL_MODE_NO_KTLS_TX 712 SSL_CTX_clear_mode(ctx, SSL_MODE_NO_KTLS_TX | SSL_MODE_NO_KTLS_RX); 713 #endif 714 return (ctx); 715 } 716 717 static SSL * 718 rpctls_server(SSL_CTX *ctx, int s, uint32_t *flags, uint32_t *uidp, 719 int *ngrps, uint32_t *gidp, X509 **certp) 720 { 721 SSL *ssl; 722 X509 *cert; 723 struct sockaddr *sad; 724 struct sockaddr_storage ad; 725 char hostnam[NI_MAXHOST]; 726 int gethostret, ret; 727 char *cp, *cp2; 728 long verfret; 729 730 *flags = 0; 731 *certp = NULL; 732 sad = (struct sockaddr *)&ad; 733 ssl = SSL_new(ctx); 734 if (ssl == NULL) { 735 rpctls_verbose_out("rpctls_server: SSL_new failed\n"); 736 return (NULL); 737 } 738 if (SSL_set_fd(ssl, s) != 1) { 739 rpctls_verbose_out("rpctls_server: SSL_set_fd failed\n"); 740 SSL_free(ssl); 741 return (NULL); 742 } 743 ret = SSL_accept(ssl); 744 if (ret != 1) { 745 rpctls_verbose_out("rpctls_server: SSL_accept " 746 "failed ret=%d\n", ret); 747 SSL_free(ssl); 748 return (NULL); 749 } 750 *flags |= RPCTLS_FLAGS_HANDSHAKE; 751 if (rpctls_verbose) { 752 gethostret = rpctls_gethost(s, sad, hostnam, sizeof(hostnam)); 753 if (gethostret == 0) 754 hostnam[0] = '\0'; 755 rpctls_verbose_out("rpctls_server: SSL handshake ok for host %s" 756 " <%s %s>\n", hostnam, SSL_get_version(ssl), 757 SSL_get_cipher(ssl)); 758 } 759 if (rpctls_do_mutual) { 760 #if OPENSSL_VERSION_NUMBER >= 0x30000000 761 cert = SSL_get1_peer_certificate(ssl); 762 #else 763 cert = SSL_get_peer_certificate(ssl); 764 #endif 765 if (cert != NULL) { 766 if (!rpctls_verbose) { 767 gethostret = rpctls_gethost(s, sad, hostnam, 768 sizeof(hostnam)); 769 if (gethostret == 0) 770 hostnam[0] = '\0'; 771 } 772 cp2 = X509_NAME_oneline( 773 X509_get_subject_name(cert), NULL, 0); 774 *flags |= RPCTLS_FLAGS_GOTCERT; 775 verfret = SSL_get_verify_result(ssl); 776 if (verfret != X509_V_OK) { 777 cp = X509_NAME_oneline( 778 X509_get_issuer_name(cert), NULL, 0); 779 if (rpctls_debug_level == 0) 780 syslog(LOG_INFO | LOG_DAEMON, 781 "rpctls_server: client IP %s " 782 "issuerName=%s subjectName=%s" 783 " verify failed %s\n", hostnam, 784 cp, cp2, 785 X509_verify_cert_error_string( 786 verfret)); 787 else 788 fprintf(stderr, 789 "rpctls_server: client IP %s " 790 "issuerName=%s subjectName=%s" 791 " verify failed %s\n", hostnam, 792 cp, cp2, 793 X509_verify_cert_error_string( 794 verfret)); 795 } 796 if (verfret == 797 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || 798 verfret == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) 799 *flags |= RPCTLS_FLAGS_SELFSIGNED; 800 else if (verfret == X509_V_OK) { 801 if (rpctls_comparehost) { 802 ret = 0; 803 if (gethostret != 0) 804 ret = rpctls_checkhost(sad, 805 cert, rpctls_wildcard); 806 if (ret != 1) { 807 *flags |= 808 RPCTLS_FLAGS_DISABLED; 809 rpctls_verbose_out( 810 "rpctls_server: " 811 "checkhost " 812 "failed\n"); 813 } 814 } 815 if (rpctls_cnuser) { 816 ret = rpctls_cnname(cert, uidp, 817 ngrps, gidp); 818 if (ret != 0) 819 *flags |= RPCTLS_FLAGS_CERTUSER; 820 } 821 *flags |= RPCTLS_FLAGS_VERIFIED; 822 *certp = cert; 823 cert = NULL; 824 } 825 if (cert != NULL) 826 X509_free(cert); 827 } else 828 rpctls_verbose_out("rpctls_server: " 829 "No peer certificate\n"); 830 } 831 832 /* Check to see that ktls is working for the connection. */ 833 ret = BIO_get_ktls_send(SSL_get_wbio(ssl)); 834 rpctls_verbose_out("rpctls_server: BIO_get_ktls_send=%d\n", ret); 835 if (ret != 0) { 836 ret = BIO_get_ktls_recv(SSL_get_rbio(ssl)); 837 rpctls_verbose_out("rpctls_server: BIO_get_ktls_recv=%d\n", 838 ret); 839 } 840 if (ret == 0) { 841 if (rpctls_debug_level == 0) 842 syslog(LOG_ERR, "ktls not working"); 843 else 844 fprintf(stderr, "ktls not working\n"); 845 /* 846 * The handshake has completed, so all that can be 847 * done is disable the connection. 848 */ 849 *flags |= RPCTLS_FLAGS_DISABLED; 850 } 851 852 return (ssl); 853 } 854 855 /* 856 * Acquire the dnsname for this server. 857 */ 858 static char * 859 rpctls_getdnsname(char *hostname) 860 { 861 char *cp, *dnsname; 862 struct addrinfo *aip, hints; 863 int error; 864 865 dnsname = NULL; 866 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 867 if ((cp = strchr(hostname, '.')) != NULL && 868 *(cp + 1) != '\0') { 869 *cp = '@'; 870 dnsname = cp; 871 } else { 872 memset((void *)&hints, 0, sizeof (hints)); 873 hints.ai_flags = AI_CANONNAME; 874 error = getaddrinfo(hostname, NULL, &hints, &aip); 875 if (error == 0) { 876 if (aip->ai_canonname != NULL && 877 (cp = strchr(aip->ai_canonname, '.')) != 878 NULL && *(cp + 1) != '\0') { 879 hostname[0] = '@'; 880 strlcpy(&hostname[1], cp + 1, 881 MAXHOSTNAMELEN + 1); 882 dnsname = hostname; 883 } 884 freeaddrinfo(aip); 885 } 886 } 887 } 888 return (dnsname); 889 } 890 891 /* 892 * Check for an otherName component of subjectAltName where the OID 893 * matches and the "domain" matches that of this server. 894 * If found, map "user" to a <uid, gidlist> for it. 895 */ 896 static int 897 rpctls_cnname(X509 *cert, uint32_t *uidp, int *ngrps, uint32_t *gidp) 898 { 899 char *cp, usern[1024 + 1]; 900 struct passwd *pwd; 901 gid_t gids[NGROUPS]; 902 int i, j; 903 GENERAL_NAMES *genlist; 904 GENERAL_NAME *genname; 905 OTHERNAME *val; 906 size_t slen; 907 908 /* First, find the otherName in the subjectAltName. */ 909 genlist = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 910 if (genlist == NULL) 911 return (0); 912 cp = NULL; 913 for (i = 0; i < sk_GENERAL_NAME_num(genlist); i++) { 914 genname = sk_GENERAL_NAME_value(genlist, i); 915 if (genname->type != GEN_OTHERNAME) 916 continue; 917 val = genname->d.otherName; 918 919 /* Check to see that it is the correct OID. */ 920 slen = i2t_ASN1_OBJECT(usern, sizeof(usern), val->type_id); 921 if (slen != strlen(rpctls_cnuseroid) || memcmp(usern, 922 rpctls_cnuseroid, slen) != 0) 923 continue; 924 925 /* Sanity check the otherName. */ 926 if (val->value->type != V_ASN1_UTF8STRING || 927 val->value->value.utf8string->length < 3 || 928 (size_t)val->value->value.utf8string->length > sizeof(usern) 929 - 1) { 930 rpctls_verbose_out("rpctls_cnname: invalid cnuser " 931 "type=%d\n", val->value->type); 932 continue; 933 } 934 935 /* Look for a "user" in the otherName */ 936 memcpy(usern, val->value->value.utf8string->data, 937 val->value->value.utf8string->length); 938 usern[val->value->value.utf8string->length] = '\0'; 939 940 /* Now, look for the @dnsname suffix in the commonName. */ 941 cp = strcasestr(usern, rpctls_dnsname); 942 if (cp == NULL) 943 continue; 944 if (*(cp + strlen(rpctls_dnsname)) != '\0') { 945 cp = NULL; 946 continue; 947 } 948 *cp = '\0'; 949 break; 950 } 951 if (cp == NULL) 952 return (0); 953 954 /* See if the "user" is in the passwd database. */ 955 pwd = getpwnam(usern); 956 if (pwd == NULL) 957 return (0); 958 *uidp = pwd->pw_uid; 959 *ngrps = NGROUPS; 960 if (getgrouplist(pwd->pw_name, pwd->pw_gid, gids, ngrps) < 0) 961 return (0); 962 rpctls_verbose_out("mapped user=%s ngrps=%d uid=%d\n", pwd->pw_name, 963 *ngrps, pwd->pw_uid); 964 for (j = 0; j < *ngrps; j++) 965 gidp[j] = gids[j]; 966 return (1); 967 } 968 969 static void 970 rpctls_huphandler(int sig __unused) 971 { 972 973 rpctls_gothup = true; 974 } 975