1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* Modified from the kernel GSSAPI code for RPC-over-TLS. */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include "opt_kern_tls.h" 36 37 #include <sys/param.h> 38 #include <sys/capsicum.h> 39 #include <sys/file.h> 40 #include <sys/filedesc.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/mbuf.h> 45 #include <sys/mutex.h> 46 #include <sys/priv.h> 47 #include <sys/proc.h> 48 #include <sys/socketvar.h> 49 #include <sys/syscall.h> 50 #include <sys/syscallsubr.h> 51 #include <sys/sysent.h> 52 #include <sys/sysproto.h> 53 54 #include <rpc/rpc.h> 55 #include <rpc/rpc_com.h> 56 #include <rpc/rpcsec_tls.h> 57 58 #include <vm/vm.h> 59 #include <vm/pmap.h> 60 #include <vm/vm_param.h> 61 62 #include "rpctlscd.h" 63 #include "rpctlssd.h" 64 65 /* 66 * Syscall hooks 67 */ 68 static struct syscall_helper_data rpctls_syscalls[] = { 69 SYSCALL_INIT_HELPER(rpctls_syscall), 70 SYSCALL_INIT_LAST 71 }; 72 73 static CLIENT *rpctls_connect_handle; 74 static struct mtx rpctls_connect_lock; 75 static struct socket *rpctls_connect_so = NULL; 76 static CLIENT *rpctls_connect_cl = NULL; 77 static CLIENT *rpctls_server_handle; 78 static struct mtx rpctls_server_lock; 79 static struct socket *rpctls_server_so = NULL; 80 static SVCXPRT *rpctls_server_xprt = NULL; 81 static struct opaque_auth rpctls_null_verf; 82 83 static CLIENT *rpctls_connect_client(void); 84 static CLIENT *rpctls_server_client(void); 85 static enum clnt_stat rpctls_server(SVCXPRT *xprt, struct socket *so, 86 uint32_t *flags, uint64_t *sslp, 87 uid_t *uid, int *ngrps, gid_t **gids); 88 89 int 90 rpctls_init(void) 91 { 92 int error; 93 94 error = syscall_helper_register(rpctls_syscalls, SY_THR_STATIC_KLD); 95 if (error != 0) { 96 printf("rpctls_init: cannot register syscall\n"); 97 return (error); 98 } 99 mtx_init(&rpctls_connect_lock, "rpctls_connect_lock", NULL, 100 MTX_DEF); 101 mtx_init(&rpctls_server_lock, "rpctls_server_lock", NULL, 102 MTX_DEF); 103 rpctls_null_verf.oa_flavor = AUTH_NULL; 104 rpctls_null_verf.oa_base = RPCTLS_START_STRING; 105 rpctls_null_verf.oa_length = strlen(RPCTLS_START_STRING); 106 return (0); 107 } 108 109 int 110 sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap) 111 { 112 struct sockaddr_un sun; 113 struct netconfig *nconf; 114 struct file *fp; 115 struct socket *so; 116 SVCXPRT *xprt; 117 char path[MAXPATHLEN]; 118 int fd = -1, error, try_count; 119 CLIENT *cl, *oldcl, *concl; 120 uint64_t ssl[3]; 121 struct timeval timeo; 122 #ifdef KERN_TLS 123 u_int maxlen; 124 #endif 125 126 error = priv_check(td, PRIV_NFS_DAEMON); 127 if (error != 0) 128 return (error); 129 130 switch (uap->op) { 131 case RPCTLS_SYSC_CLSETPATH: 132 error = copyinstr(uap->path, path, sizeof(path), NULL); 133 if (error == 0) { 134 error = ENXIO; 135 #ifdef KERN_TLS 136 if (rpctls_getinfo(&maxlen, false, false)) 137 error = 0; 138 #endif 139 } 140 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) || 141 strlen(path) == 0)) 142 error = EINVAL; 143 144 cl = NULL; 145 if (error == 0) { 146 sun.sun_family = AF_LOCAL; 147 strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 148 sun.sun_len = SUN_LEN(&sun); 149 150 nconf = getnetconfigent("local"); 151 cl = clnt_reconnect_create(nconf, 152 (struct sockaddr *)&sun, RPCTLSCD, RPCTLSCDVERS, 153 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 154 /* 155 * The number of retries defaults to INT_MAX, which 156 * effectively means an infinite, uninterruptable loop. 157 * Set the try_count to 1 so that no retries of the 158 * RPC occur. Since it is an upcall to a local daemon, 159 * requests should not be lost and doing one of these 160 * RPCs multiple times is not correct. 161 * If the server is not working correctly, the 162 * daemon can get stuck in SSL_connect() trying 163 * to read data from the socket during the upcall. 164 * Set a timeout (currently 15sec) and assume the 165 * daemon is hung when the timeout occurs. 166 */ 167 if (cl != NULL) { 168 try_count = 1; 169 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count); 170 timeo.tv_sec = 15; 171 timeo.tv_usec = 0; 172 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo); 173 } else 174 error = EINVAL; 175 } 176 177 mtx_lock(&rpctls_connect_lock); 178 oldcl = rpctls_connect_handle; 179 rpctls_connect_handle = cl; 180 mtx_unlock(&rpctls_connect_lock); 181 182 if (oldcl != NULL) { 183 CLNT_CLOSE(oldcl); 184 CLNT_RELEASE(oldcl); 185 } 186 break; 187 case RPCTLS_SYSC_SRVSETPATH: 188 error = copyinstr(uap->path, path, sizeof(path), NULL); 189 if (error == 0) { 190 error = ENXIO; 191 #ifdef KERN_TLS 192 if (rpctls_getinfo(&maxlen, false, false)) 193 error = 0; 194 #endif 195 } 196 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) || 197 strlen(path) == 0)) 198 error = EINVAL; 199 200 cl = NULL; 201 if (error == 0) { 202 sun.sun_family = AF_LOCAL; 203 strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 204 sun.sun_len = SUN_LEN(&sun); 205 206 nconf = getnetconfigent("local"); 207 cl = clnt_reconnect_create(nconf, 208 (struct sockaddr *)&sun, RPCTLSSD, RPCTLSSDVERS, 209 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 210 /* 211 * The number of retries defaults to INT_MAX, which 212 * effectively means an infinite, uninterruptable loop. 213 * Set the try_count to 1 so that no retries of the 214 * RPC occur. Since it is an upcall to a local daemon, 215 * requests should not be lost and doing one of these 216 * RPCs multiple times is not correct. 217 * Set a timeout (currently 15sec) and assume that 218 * the daemon is hung if a timeout occurs. 219 */ 220 if (cl != NULL) { 221 try_count = 1; 222 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count); 223 timeo.tv_sec = 15; 224 timeo.tv_usec = 0; 225 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo); 226 } else 227 error = EINVAL; 228 } 229 230 mtx_lock(&rpctls_server_lock); 231 oldcl = rpctls_server_handle; 232 rpctls_server_handle = cl; 233 mtx_unlock(&rpctls_server_lock); 234 235 if (oldcl != NULL) { 236 CLNT_CLOSE(oldcl); 237 CLNT_RELEASE(oldcl); 238 } 239 break; 240 case RPCTLS_SYSC_CLSHUTDOWN: 241 mtx_lock(&rpctls_connect_lock); 242 oldcl = rpctls_connect_handle; 243 rpctls_connect_handle = NULL; 244 mtx_unlock(&rpctls_connect_lock); 245 246 if (oldcl != NULL) { 247 CLNT_CLOSE(oldcl); 248 CLNT_RELEASE(oldcl); 249 } 250 break; 251 case RPCTLS_SYSC_SRVSHUTDOWN: 252 mtx_lock(&rpctls_server_lock); 253 oldcl = rpctls_server_handle; 254 rpctls_server_handle = NULL; 255 mtx_unlock(&rpctls_server_lock); 256 257 if (oldcl != NULL) { 258 CLNT_CLOSE(oldcl); 259 CLNT_RELEASE(oldcl); 260 } 261 break; 262 case RPCTLS_SYSC_CLSOCKET: 263 mtx_lock(&rpctls_connect_lock); 264 so = rpctls_connect_so; 265 rpctls_connect_so = NULL; 266 concl = rpctls_connect_cl; 267 rpctls_connect_cl = NULL; 268 mtx_unlock(&rpctls_connect_lock); 269 if (so != NULL) { 270 error = falloc(td, &fp, &fd, 0); 271 if (error == 0) { 272 /* 273 * Set ssl refno so that clnt_vc_destroy() will 274 * not close the socket and will leave that for 275 * the daemon to do. 276 */ 277 soref(so); 278 ssl[0] = ssl[1] = 0; 279 ssl[2] = RPCTLS_REFNO_HANDSHAKE; 280 CLNT_CONTROL(concl, CLSET_TLS, ssl); 281 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, 282 &socketops); 283 fdrop(fp, td); /* Drop fp reference. */ 284 td->td_retval[0] = fd; 285 } 286 } else 287 error = EPERM; 288 break; 289 case RPCTLS_SYSC_SRVSOCKET: 290 mtx_lock(&rpctls_server_lock); 291 so = rpctls_server_so; 292 rpctls_server_so = NULL; 293 xprt = rpctls_server_xprt; 294 rpctls_server_xprt = NULL; 295 mtx_unlock(&rpctls_server_lock); 296 if (so != NULL) { 297 error = falloc(td, &fp, &fd, 0); 298 if (error == 0) { 299 /* 300 * Once this file descriptor is associated 301 * with the socket, it cannot be closed by 302 * the server side krpc code (svc_vc.c). 303 */ 304 soref(so); 305 sx_xlock(&xprt->xp_lock); 306 xprt->xp_tls = RPCTLS_FLAGS_HANDSHFAIL; 307 sx_xunlock(&xprt->xp_lock); 308 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, 309 &socketops); 310 fdrop(fp, td); /* Drop fp reference. */ 311 td->td_retval[0] = fd; 312 } 313 } else 314 error = EPERM; 315 break; 316 default: 317 error = EINVAL; 318 } 319 320 return (error); 321 } 322 323 /* 324 * Acquire the rpctls_connect_handle and return it with a reference count, 325 * if it is available. 326 */ 327 static CLIENT * 328 rpctls_connect_client(void) 329 { 330 CLIENT *cl; 331 332 mtx_lock(&rpctls_connect_lock); 333 cl = rpctls_connect_handle; 334 if (cl != NULL) 335 CLNT_ACQUIRE(cl); 336 mtx_unlock(&rpctls_connect_lock); 337 return (cl); 338 } 339 340 /* 341 * Acquire the rpctls_server_handle and return it with a reference count, 342 * if it is available. 343 */ 344 static CLIENT * 345 rpctls_server_client(void) 346 { 347 CLIENT *cl; 348 349 mtx_lock(&rpctls_server_lock); 350 cl = rpctls_server_handle; 351 if (cl != NULL) 352 CLNT_ACQUIRE(cl); 353 mtx_unlock(&rpctls_server_lock); 354 return (cl); 355 } 356 357 /* Do an upcall for a new socket connect using TLS. */ 358 enum clnt_stat 359 rpctls_connect(CLIENT *newclient, struct socket *so, uint64_t *sslp, 360 uint32_t *reterr) 361 { 362 struct rpctlscd_connect_res res; 363 struct rpc_callextra ext; 364 struct timeval utimeout; 365 enum clnt_stat stat; 366 CLIENT *cl; 367 int val; 368 static bool rpctls_connect_busy = false; 369 370 cl = rpctls_connect_client(); 371 if (cl == NULL) 372 return (RPC_AUTHERROR); 373 374 /* First, do the AUTH_TLS NULL RPC. */ 375 memset(&ext, 0, sizeof(ext)); 376 utimeout.tv_sec = 30; 377 utimeout.tv_usec = 0; 378 ext.rc_auth = authtls_create(); 379 stat = clnt_call_private(newclient, &ext, NULLPROC, (xdrproc_t)xdr_void, 380 NULL, (xdrproc_t)xdr_void, NULL, utimeout); 381 AUTH_DESTROY(ext.rc_auth); 382 if (stat == RPC_AUTHERROR) 383 return (stat); 384 if (stat != RPC_SUCCESS) 385 return (RPC_SYSTEMERROR); 386 387 /* Serialize the connect upcalls. */ 388 mtx_lock(&rpctls_connect_lock); 389 while (rpctls_connect_busy) 390 msleep(&rpctls_connect_busy, &rpctls_connect_lock, PVFS, 391 "rtlscn", 0); 392 rpctls_connect_busy = true; 393 rpctls_connect_so = so; 394 rpctls_connect_cl = newclient; 395 mtx_unlock(&rpctls_connect_lock); 396 397 /* Temporarily block reception during the handshake upcall. */ 398 val = 1; 399 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val); 400 401 /* Do the connect handshake upcall. */ 402 stat = rpctlscd_connect_1(NULL, &res, cl); 403 if (stat == RPC_SUCCESS) { 404 *reterr = res.reterr; 405 if (res.reterr == 0) { 406 *sslp++ = res.sec; 407 *sslp++ = res.usec; 408 *sslp = res.ssl; 409 } 410 } else if (stat == RPC_TIMEDOUT) { 411 /* 412 * Do a shutdown on the socket, since the daemon is probably 413 * stuck in SSL_connect() trying to read the socket. 414 * Do not soclose() the socket, since the daemon will close() 415 * the socket after SSL_connect() returns an error. 416 */ 417 soshutdown(so, SHUT_RD); 418 } 419 CLNT_RELEASE(cl); 420 421 /* Unblock reception. */ 422 val = 0; 423 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val); 424 425 /* Once the upcall is done, the daemon is done with the fp and so. */ 426 mtx_lock(&rpctls_connect_lock); 427 rpctls_connect_so = NULL; 428 rpctls_connect_cl = NULL; 429 rpctls_connect_busy = false; 430 wakeup(&rpctls_connect_busy); 431 mtx_unlock(&rpctls_connect_lock); 432 433 return (stat); 434 } 435 436 /* Do an upcall to handle an non-application data record using TLS. */ 437 enum clnt_stat 438 rpctls_cl_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl, 439 uint32_t *reterr) 440 { 441 struct rpctlscd_handlerecord_arg arg; 442 struct rpctlscd_handlerecord_res res; 443 enum clnt_stat stat; 444 CLIENT *cl; 445 446 cl = rpctls_connect_client(); 447 if (cl == NULL) { 448 *reterr = RPCTLSERR_NOSSL; 449 return (RPC_SUCCESS); 450 } 451 452 /* Do the handlerecord upcall. */ 453 arg.sec = sec; 454 arg.usec = usec; 455 arg.ssl = ssl; 456 stat = rpctlscd_handlerecord_1(&arg, &res, cl); 457 CLNT_RELEASE(cl); 458 if (stat == RPC_SUCCESS) 459 *reterr = res.reterr; 460 return (stat); 461 } 462 463 enum clnt_stat 464 rpctls_srv_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl, 465 uint32_t *reterr) 466 { 467 struct rpctlssd_handlerecord_arg arg; 468 struct rpctlssd_handlerecord_res res; 469 enum clnt_stat stat; 470 CLIENT *cl; 471 472 cl = rpctls_server_client(); 473 if (cl == NULL) { 474 *reterr = RPCTLSERR_NOSSL; 475 return (RPC_SUCCESS); 476 } 477 478 /* Do the handlerecord upcall. */ 479 arg.sec = sec; 480 arg.usec = usec; 481 arg.ssl = ssl; 482 stat = rpctlssd_handlerecord_1(&arg, &res, cl); 483 CLNT_RELEASE(cl); 484 if (stat == RPC_SUCCESS) 485 *reterr = res.reterr; 486 return (stat); 487 } 488 489 /* Do an upcall to shut down a socket using TLS. */ 490 enum clnt_stat 491 rpctls_cl_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl, 492 uint32_t *reterr) 493 { 494 struct rpctlscd_disconnect_arg arg; 495 struct rpctlscd_disconnect_res res; 496 enum clnt_stat stat; 497 CLIENT *cl; 498 499 cl = rpctls_connect_client(); 500 if (cl == NULL) { 501 *reterr = RPCTLSERR_NOSSL; 502 return (RPC_SUCCESS); 503 } 504 505 /* Do the disconnect upcall. */ 506 arg.sec = sec; 507 arg.usec = usec; 508 arg.ssl = ssl; 509 stat = rpctlscd_disconnect_1(&arg, &res, cl); 510 CLNT_RELEASE(cl); 511 if (stat == RPC_SUCCESS) 512 *reterr = res.reterr; 513 return (stat); 514 } 515 516 enum clnt_stat 517 rpctls_srv_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl, 518 uint32_t *reterr) 519 { 520 struct rpctlssd_disconnect_arg arg; 521 struct rpctlssd_disconnect_res res; 522 enum clnt_stat stat; 523 CLIENT *cl; 524 525 cl = rpctls_server_client(); 526 if (cl == NULL) { 527 *reterr = RPCTLSERR_NOSSL; 528 return (RPC_SUCCESS); 529 } 530 531 /* Do the disconnect upcall. */ 532 arg.sec = sec; 533 arg.usec = usec; 534 arg.ssl = ssl; 535 stat = rpctlssd_disconnect_1(&arg, &res, cl); 536 CLNT_RELEASE(cl); 537 if (stat == RPC_SUCCESS) 538 *reterr = res.reterr; 539 return (stat); 540 } 541 542 /* Do an upcall for a new server socket using TLS. */ 543 static enum clnt_stat 544 rpctls_server(SVCXPRT *xprt, struct socket *so, uint32_t *flags, uint64_t *sslp, 545 uid_t *uid, int *ngrps, gid_t **gids) 546 { 547 enum clnt_stat stat; 548 CLIENT *cl; 549 struct rpctlssd_connect_res res; 550 gid_t *gidp; 551 uint32_t *gidv; 552 int i; 553 static bool rpctls_server_busy = false; 554 555 cl = rpctls_server_client(); 556 if (cl == NULL) 557 return (RPC_SYSTEMERROR); 558 559 /* Serialize the server upcalls. */ 560 mtx_lock(&rpctls_server_lock); 561 while (rpctls_server_busy) 562 msleep(&rpctls_server_busy, &rpctls_server_lock, PVFS, 563 "rtlssn", 0); 564 rpctls_server_busy = true; 565 rpctls_server_so = so; 566 rpctls_server_xprt = xprt; 567 mtx_unlock(&rpctls_server_lock); 568 569 /* Do the server upcall. */ 570 stat = rpctlssd_connect_1(NULL, &res, cl); 571 if (stat == RPC_SUCCESS) { 572 *flags = res.flags; 573 *sslp++ = res.sec; 574 *sslp++ = res.usec; 575 *sslp = res.ssl; 576 if ((*flags & (RPCTLS_FLAGS_CERTUSER | 577 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) { 578 *ngrps = res.gid.gid_len; 579 *uid = res.uid; 580 *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t)); 581 gidv = res.gid.gid_val; 582 for (i = 0; i < *ngrps; i++) 583 *gidp++ = *gidv++; 584 } 585 } else if (stat == RPC_TIMEDOUT) { 586 /* 587 * Do a shutdown on the socket, since the daemon is probably 588 * stuck in SSL_accept() trying to read the socket. 589 * Do not soclose() the socket, since the daemon will close() 590 * the socket after SSL_accept() returns an error. 591 */ 592 soshutdown(so, SHUT_RD); 593 } 594 CLNT_RELEASE(cl); 595 596 /* Once the upcall is done, the daemon is done with the fp and so. */ 597 mtx_lock(&rpctls_server_lock); 598 rpctls_server_so = NULL; 599 rpctls_server_xprt = NULL; 600 rpctls_server_busy = false; 601 wakeup(&rpctls_server_busy); 602 mtx_unlock(&rpctls_server_lock); 603 604 return (stat); 605 } 606 607 /* 608 * Handle the NULL RPC with authentication flavor of AUTH_TLS. 609 * This is a STARTTLS command, so do the upcall to the rpctlssd daemon, 610 * which will do the TLS handshake. 611 */ 612 enum auth_stat 613 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg) 614 615 { 616 bool_t call_stat; 617 enum clnt_stat stat; 618 SVCXPRT *xprt; 619 uint32_t flags; 620 uint64_t ssl[3]; 621 int ngrps; 622 uid_t uid; 623 gid_t *gidp; 624 #ifdef KERN_TLS 625 u_int maxlen; 626 #endif 627 628 /* Initialize reply. */ 629 rqst->rq_verf = rpctls_null_verf; 630 631 /* Check client credentials. */ 632 if (rqst->rq_cred.oa_length != 0 || 633 msg->rm_call.cb_verf.oa_length != 0 || 634 msg->rm_call.cb_verf.oa_flavor != AUTH_NULL) 635 return (AUTH_BADCRED); 636 637 if (rqst->rq_proc != NULLPROC) 638 return (AUTH_REJECTEDCRED); 639 640 call_stat = FALSE; 641 #ifdef KERN_TLS 642 if (rpctls_getinfo(&maxlen, false, true)) 643 call_stat = TRUE; 644 #endif 645 if (!call_stat) 646 return (AUTH_REJECTEDCRED); 647 648 /* 649 * Disable reception for the krpc so that the TLS handshake can 650 * be done on the socket in the rpctlssd daemon. 651 */ 652 xprt = rqst->rq_xprt; 653 sx_xlock(&xprt->xp_lock); 654 xprt->xp_dontrcv = TRUE; 655 sx_xunlock(&xprt->xp_lock); 656 657 /* 658 * Send the reply to the NULL RPC with AUTH_TLS, which is the 659 * STARTTLS command for Sun RPC. 660 */ 661 call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL); 662 if (!call_stat) { 663 sx_xlock(&xprt->xp_lock); 664 xprt->xp_dontrcv = FALSE; 665 sx_xunlock(&xprt->xp_lock); 666 xprt_active(xprt); /* Harmless if already active. */ 667 return (AUTH_REJECTEDCRED); 668 } 669 670 /* Do an upcall to do the TLS handshake. */ 671 stat = rpctls_server(xprt, xprt->xp_socket, &flags, 672 ssl, &uid, &ngrps, &gidp); 673 674 /* Re-enable reception on the socket within the krpc. */ 675 sx_xlock(&xprt->xp_lock); 676 xprt->xp_dontrcv = FALSE; 677 if (stat == RPC_SUCCESS) { 678 xprt->xp_tls = flags; 679 xprt->xp_sslsec = ssl[0]; 680 xprt->xp_sslusec = ssl[1]; 681 xprt->xp_sslrefno = ssl[2]; 682 if ((flags & (RPCTLS_FLAGS_CERTUSER | 683 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) { 684 xprt->xp_ngrps = ngrps; 685 xprt->xp_uid = uid; 686 xprt->xp_gidp = gidp; 687 } 688 } 689 sx_xunlock(&xprt->xp_lock); 690 xprt_active(xprt); /* Harmless if already active. */ 691 692 return (RPCSEC_GSS_NODISPATCH); 693 } 694 695 /* 696 * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen. 697 */ 698 bool 699 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run) 700 { 701 u_int maxlen; 702 bool enable; 703 int error; 704 size_t siz; 705 706 if (PMAP_HAS_DMAP == 0 || !mb_use_ext_pgs) 707 return (false); 708 siz = sizeof(enable); 709 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable", 710 &enable, &siz, NULL, 0, NULL, 0); 711 if (error != 0) 712 return (false); 713 siz = sizeof(maxlen); 714 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen", 715 &maxlen, &siz, NULL, 0, NULL, 0); 716 if (error != 0) 717 return (false); 718 if (rpctlscd_run && rpctls_connect_handle == NULL) 719 return (false); 720 if (rpctlssd_run && rpctls_server_handle == NULL) 721 return (false); 722 *maxlenp = maxlen; 723 return (enable); 724 } 725 726