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 * 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 #include "opt_kern_tls.h" 34 35 #include <sys/param.h> 36 #include <sys/capsicum.h> 37 #include <sys/file.h> 38 #include <sys/filedesc.h> 39 #include <sys/jail.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mbuf.h> 44 #include <sys/mutex.h> 45 #include <sys/priv.h> 46 #include <sys/proc.h> 47 #include <sys/socketvar.h> 48 #include <sys/syscall.h> 49 #include <sys/syscallsubr.h> 50 #include <sys/sysent.h> 51 #include <sys/sysproto.h> 52 53 #include <net/vnet.h> 54 55 #include <rpc/rpc.h> 56 #include <rpc/rpc_com.h> 57 #include <rpc/rpcsec_tls.h> 58 59 #include <vm/vm.h> 60 #include <vm/pmap.h> 61 #include <vm/vm_param.h> 62 63 #include "rpctlscd.h" 64 #include "rpctlssd.h" 65 66 /* 67 * Syscall hooks 68 */ 69 static struct syscall_helper_data rpctls_syscalls[] = { 70 SYSCALL_INIT_HELPER(rpctls_syscall), 71 SYSCALL_INIT_LAST 72 }; 73 74 static CLIENT *rpctls_connect_handle; 75 static struct mtx rpctls_connect_lock; 76 static struct socket *rpctls_connect_so = NULL; 77 static CLIENT *rpctls_connect_cl = NULL; 78 static struct mtx rpctls_server_lock; 79 static struct opaque_auth rpctls_null_verf; 80 81 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_success); 82 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_failed); 83 84 KRPC_VNET_DEFINE_STATIC(CLIENT **, rpctls_server_handle); 85 KRPC_VNET_DEFINE_STATIC(struct socket *, rpctls_server_so) = NULL; 86 KRPC_VNET_DEFINE_STATIC(SVCXPRT *, rpctls_server_xprt) = NULL; 87 KRPC_VNET_DEFINE_STATIC(bool, rpctls_srv_newdaemon) = false; 88 KRPC_VNET_DEFINE_STATIC(int, rpctls_srv_prevproc) = 0; 89 KRPC_VNET_DEFINE_STATIC(bool *, rpctls_server_busy); 90 91 static CLIENT *rpctls_connect_client(void); 92 static CLIENT *rpctls_server_client(int procpos); 93 static enum clnt_stat rpctls_server(SVCXPRT *xprt, struct socket *so, 94 uint32_t *flags, uint64_t *sslp, 95 uid_t *uid, int *ngrps, gid_t **gids, 96 int *procposp); 97 98 static void 99 rpctls_vnetinit(const void *unused __unused) 100 { 101 int i; 102 103 KRPC_VNET(rpctls_server_handle) = malloc(sizeof(CLIENT *) * 104 RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO); 105 KRPC_VNET(rpctls_server_busy) = malloc(sizeof(bool) * 106 RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO); 107 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) 108 KRPC_VNET(rpctls_server_busy)[i] = false; 109 } 110 VNET_SYSINIT(rpctls_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, 111 rpctls_vnetinit, NULL); 112 113 static void 114 rpctls_cleanup(void *unused __unused) 115 { 116 117 free(KRPC_VNET(rpctls_server_handle), M_RPC); 118 free(KRPC_VNET(rpctls_server_busy), M_RPC); 119 } 120 VNET_SYSUNINIT(rpctls_cleanup, SI_SUB_VNET_DONE, SI_ORDER_ANY, 121 rpctls_cleanup, NULL); 122 123 int 124 rpctls_init(void) 125 { 126 int error; 127 128 error = syscall_helper_register(rpctls_syscalls, SY_THR_STATIC_KLD); 129 if (error != 0) { 130 printf("rpctls_init: cannot register syscall\n"); 131 return (error); 132 } 133 mtx_init(&rpctls_connect_lock, "rpctls_connect_lock", NULL, 134 MTX_DEF); 135 mtx_init(&rpctls_server_lock, "rpctls_server_lock", NULL, 136 MTX_DEF); 137 rpctls_null_verf.oa_flavor = AUTH_NULL; 138 rpctls_null_verf.oa_base = RPCTLS_START_STRING; 139 rpctls_null_verf.oa_length = strlen(RPCTLS_START_STRING); 140 return (0); 141 } 142 143 int 144 sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap) 145 { 146 struct sockaddr_un sun; 147 struct netconfig *nconf; 148 struct file *fp; 149 struct socket *so; 150 SVCXPRT *xprt; 151 char path[MAXPATHLEN]; 152 int fd = -1, error, i, try_count; 153 CLIENT *cl, *oldcl[RPCTLS_SRV_MAXNPROCS], *concl; 154 uint64_t ssl[3]; 155 struct timeval timeo; 156 #ifdef KERN_TLS 157 u_int maxlen; 158 #endif 159 160 error = priv_check(td, PRIV_NFS_DAEMON); 161 if (error != 0) 162 return (error); 163 164 KRPC_CURVNET_SET(KRPC_TD_TO_VNET(td)); 165 switch (uap->op) { 166 case RPCTLS_SYSC_SRVSTARTUP: 167 if (jailed(curthread->td_ucred) && 168 !prison_check_nfsd(curthread->td_ucred)) 169 error = EPERM; 170 if (error == 0) { 171 /* Get rid of all old CLIENTs. */ 172 mtx_lock(&rpctls_server_lock); 173 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 174 oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; 175 KRPC_VNET(rpctls_server_handle)[i] = NULL; 176 KRPC_VNET(rpctls_server_busy)[i] = false; 177 } 178 KRPC_VNET(rpctls_srv_newdaemon) = true; 179 KRPC_VNET(rpctls_srv_prevproc) = 0; 180 mtx_unlock(&rpctls_server_lock); 181 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 182 if (oldcl[i] != NULL) { 183 CLNT_CLOSE(oldcl[i]); 184 CLNT_RELEASE(oldcl[i]); 185 } 186 } 187 } 188 break; 189 case RPCTLS_SYSC_CLSETPATH: 190 if (jailed(curthread->td_ucred)) 191 error = EPERM; 192 if (error == 0) 193 error = copyinstr(uap->path, path, sizeof(path), NULL); 194 if (error == 0) { 195 error = ENXIO; 196 #ifdef KERN_TLS 197 if (rpctls_getinfo(&maxlen, false, false)) 198 error = 0; 199 #endif 200 } 201 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) || 202 strlen(path) == 0)) 203 error = EINVAL; 204 205 cl = NULL; 206 if (error == 0) { 207 sun.sun_family = AF_LOCAL; 208 strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 209 sun.sun_len = SUN_LEN(&sun); 210 211 nconf = getnetconfigent("local"); 212 cl = clnt_reconnect_create(nconf, 213 (struct sockaddr *)&sun, RPCTLSCD, RPCTLSCDVERS, 214 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 215 /* 216 * The number of retries defaults to INT_MAX, which 217 * effectively means an infinite, uninterruptable loop. 218 * Set the try_count to 1 so that no retries of the 219 * RPC occur. Since it is an upcall to a local daemon, 220 * requests should not be lost and doing one of these 221 * RPCs multiple times is not correct. 222 * If the server is not working correctly, the 223 * daemon can get stuck in SSL_connect() trying 224 * to read data from the socket during the upcall. 225 * Set a timeout (currently 15sec) and assume the 226 * daemon is hung when the timeout occurs. 227 */ 228 if (cl != NULL) { 229 try_count = 1; 230 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count); 231 timeo.tv_sec = 15; 232 timeo.tv_usec = 0; 233 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo); 234 } else 235 error = EINVAL; 236 } 237 238 mtx_lock(&rpctls_connect_lock); 239 oldcl[0] = rpctls_connect_handle; 240 rpctls_connect_handle = cl; 241 mtx_unlock(&rpctls_connect_lock); 242 243 if (oldcl[0] != NULL) { 244 CLNT_CLOSE(oldcl[0]); 245 CLNT_RELEASE(oldcl[0]); 246 } 247 break; 248 case RPCTLS_SYSC_SRVSETPATH: 249 if (jailed(curthread->td_ucred) && 250 !prison_check_nfsd(curthread->td_ucred)) 251 error = EPERM; 252 if (error == 0) 253 error = copyinstr(uap->path, path, sizeof(path), NULL); 254 if (error == 0) { 255 error = ENXIO; 256 #ifdef KERN_TLS 257 if (rpctls_getinfo(&maxlen, false, false)) 258 error = 0; 259 #endif 260 } 261 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) || 262 strlen(path) == 0)) 263 error = EINVAL; 264 265 cl = NULL; 266 if (error == 0) { 267 sun.sun_family = AF_LOCAL; 268 strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 269 sun.sun_len = SUN_LEN(&sun); 270 271 nconf = getnetconfigent("local"); 272 cl = clnt_reconnect_create(nconf, 273 (struct sockaddr *)&sun, RPCTLSSD, RPCTLSSDVERS, 274 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 275 /* 276 * The number of retries defaults to INT_MAX, which 277 * effectively means an infinite, uninterruptable loop. 278 * Set the try_count to 1 so that no retries of the 279 * RPC occur. Since it is an upcall to a local daemon, 280 * requests should not be lost and doing one of these 281 * RPCs multiple times is not correct. 282 * Set a timeout (currently 15sec) and assume that 283 * the daemon is hung if a timeout occurs. 284 */ 285 if (cl != NULL) { 286 try_count = 1; 287 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count); 288 timeo.tv_sec = 15; 289 timeo.tv_usec = 0; 290 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo); 291 } else 292 error = EINVAL; 293 } 294 295 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) 296 oldcl[i] = NULL; 297 mtx_lock(&rpctls_server_lock); 298 if (KRPC_VNET(rpctls_srv_newdaemon)) { 299 /* 300 * For a new daemon, the rpctls_srv_handles have 301 * already been cleaned up by RPCTLS_SYSC_SRVSTARTUP. 302 * Scan for an available array entry to use. 303 */ 304 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 305 if (KRPC_VNET(rpctls_server_handle)[i] == NULL) 306 break; 307 } 308 if (i == RPCTLS_SRV_MAXNPROCS && error == 0) 309 error = ENXIO; 310 } else { 311 /* For an old daemon, clear out old CLIENTs. */ 312 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 313 oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; 314 KRPC_VNET(rpctls_server_handle)[i] = NULL; 315 KRPC_VNET(rpctls_server_busy)[i] = false; 316 } 317 i = 0; /* Set to use rpctls_server_handle[0]. */ 318 } 319 if (error == 0) 320 KRPC_VNET(rpctls_server_handle)[i] = cl; 321 mtx_unlock(&rpctls_server_lock); 322 323 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 324 if (oldcl[i] != NULL) { 325 CLNT_CLOSE(oldcl[i]); 326 CLNT_RELEASE(oldcl[i]); 327 } 328 } 329 break; 330 case RPCTLS_SYSC_CLSHUTDOWN: 331 mtx_lock(&rpctls_connect_lock); 332 oldcl[0] = rpctls_connect_handle; 333 rpctls_connect_handle = NULL; 334 mtx_unlock(&rpctls_connect_lock); 335 336 if (oldcl[0] != NULL) { 337 CLNT_CLOSE(oldcl[0]); 338 CLNT_RELEASE(oldcl[0]); 339 } 340 break; 341 case RPCTLS_SYSC_SRVSHUTDOWN: 342 mtx_lock(&rpctls_server_lock); 343 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 344 oldcl[i] = KRPC_VNET(rpctls_server_handle)[i]; 345 KRPC_VNET(rpctls_server_handle)[i] = NULL; 346 } 347 KRPC_VNET(rpctls_srv_newdaemon) = false; 348 mtx_unlock(&rpctls_server_lock); 349 350 for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) { 351 if (oldcl[i] != NULL) { 352 CLNT_CLOSE(oldcl[i]); 353 CLNT_RELEASE(oldcl[i]); 354 } 355 } 356 break; 357 case RPCTLS_SYSC_CLSOCKET: 358 mtx_lock(&rpctls_connect_lock); 359 so = rpctls_connect_so; 360 rpctls_connect_so = NULL; 361 concl = rpctls_connect_cl; 362 rpctls_connect_cl = NULL; 363 mtx_unlock(&rpctls_connect_lock); 364 if (so != NULL) { 365 error = falloc(td, &fp, &fd, 0); 366 if (error == 0) { 367 /* 368 * Set ssl refno so that clnt_vc_destroy() will 369 * not close the socket and will leave that for 370 * the daemon to do. 371 */ 372 soref(so); 373 ssl[0] = ssl[1] = 0; 374 ssl[2] = RPCTLS_REFNO_HANDSHAKE; 375 CLNT_CONTROL(concl, CLSET_TLS, ssl); 376 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, 377 &socketops); 378 fdrop(fp, td); /* Drop fp reference. */ 379 td->td_retval[0] = fd; 380 } 381 } else 382 error = EPERM; 383 break; 384 case RPCTLS_SYSC_SRVSOCKET: 385 mtx_lock(&rpctls_server_lock); 386 so = KRPC_VNET(rpctls_server_so); 387 KRPC_VNET(rpctls_server_so) = NULL; 388 xprt = KRPC_VNET(rpctls_server_xprt); 389 KRPC_VNET(rpctls_server_xprt) = NULL; 390 mtx_unlock(&rpctls_server_lock); 391 if (so != NULL) { 392 error = falloc(td, &fp, &fd, 0); 393 if (error == 0) { 394 /* 395 * Once this file descriptor is associated 396 * with the socket, it cannot be closed by 397 * the server side krpc code (svc_vc.c). 398 */ 399 soref(so); 400 sx_xlock(&xprt->xp_lock); 401 xprt->xp_tls = RPCTLS_FLAGS_HANDSHFAIL; 402 sx_xunlock(&xprt->xp_lock); 403 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, 404 &socketops); 405 fdrop(fp, td); /* Drop fp reference. */ 406 td->td_retval[0] = fd; 407 } 408 } else 409 error = EPERM; 410 break; 411 default: 412 error = EINVAL; 413 } 414 KRPC_CURVNET_RESTORE(); 415 416 return (error); 417 } 418 419 /* 420 * Acquire the rpctls_connect_handle and return it with a reference count, 421 * if it is available. 422 */ 423 static CLIENT * 424 rpctls_connect_client(void) 425 { 426 CLIENT *cl; 427 428 mtx_lock(&rpctls_connect_lock); 429 cl = rpctls_connect_handle; 430 if (cl != NULL) 431 CLNT_ACQUIRE(cl); 432 mtx_unlock(&rpctls_connect_lock); 433 return (cl); 434 } 435 436 /* 437 * Acquire the rpctls_server_handle and return it with a reference count, 438 * if it is available. 439 */ 440 static CLIENT * 441 rpctls_server_client(int procpos) 442 { 443 CLIENT *cl; 444 445 KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); 446 mtx_lock(&rpctls_server_lock); 447 cl = KRPC_VNET(rpctls_server_handle)[procpos]; 448 if (cl != NULL) 449 CLNT_ACQUIRE(cl); 450 mtx_unlock(&rpctls_server_lock); 451 KRPC_CURVNET_RESTORE(); 452 return (cl); 453 } 454 455 /* Do an upcall for a new socket connect using TLS. */ 456 enum clnt_stat 457 rpctls_connect(CLIENT *newclient, char *certname, struct socket *so, 458 uint64_t *sslp, uint32_t *reterr) 459 { 460 struct rpctlscd_connect_arg arg; 461 struct rpctlscd_connect_res res; 462 struct rpc_callextra ext; 463 struct timeval utimeout; 464 enum clnt_stat stat; 465 CLIENT *cl; 466 int val; 467 static bool rpctls_connect_busy = false; 468 469 cl = rpctls_connect_client(); 470 if (cl == NULL) 471 return (RPC_AUTHERROR); 472 473 /* First, do the AUTH_TLS NULL RPC. */ 474 memset(&ext, 0, sizeof(ext)); 475 utimeout.tv_sec = 30; 476 utimeout.tv_usec = 0; 477 ext.rc_auth = authtls_create(); 478 stat = clnt_call_private(newclient, &ext, NULLPROC, (xdrproc_t)xdr_void, 479 NULL, (xdrproc_t)xdr_void, NULL, utimeout); 480 AUTH_DESTROY(ext.rc_auth); 481 if (stat == RPC_AUTHERROR) 482 return (stat); 483 if (stat != RPC_SUCCESS) 484 return (RPC_SYSTEMERROR); 485 486 /* Serialize the connect upcalls. */ 487 mtx_lock(&rpctls_connect_lock); 488 while (rpctls_connect_busy) 489 msleep(&rpctls_connect_busy, &rpctls_connect_lock, PVFS, 490 "rtlscn", 0); 491 rpctls_connect_busy = true; 492 rpctls_connect_so = so; 493 rpctls_connect_cl = newclient; 494 mtx_unlock(&rpctls_connect_lock); 495 496 /* Temporarily block reception during the handshake upcall. */ 497 val = 1; 498 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val); 499 500 /* Do the connect handshake upcall. */ 501 if (certname != NULL) { 502 arg.certname.certname_len = strlen(certname); 503 arg.certname.certname_val = certname; 504 } else 505 arg.certname.certname_len = 0; 506 stat = rpctlscd_connect_1(&arg, &res, cl); 507 if (stat == RPC_SUCCESS) { 508 *reterr = res.reterr; 509 if (res.reterr == 0) { 510 *sslp++ = res.sec; 511 *sslp++ = res.usec; 512 *sslp = res.ssl; 513 } 514 } else if (stat == RPC_TIMEDOUT) { 515 /* 516 * Do a shutdown on the socket, since the daemon is probably 517 * stuck in SSL_connect() trying to read the socket. 518 * Do not soclose() the socket, since the daemon will close() 519 * the socket after SSL_connect() returns an error. 520 */ 521 soshutdown(so, SHUT_RD); 522 } 523 CLNT_RELEASE(cl); 524 525 /* Unblock reception. */ 526 val = 0; 527 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val); 528 529 /* Once the upcall is done, the daemon is done with the fp and so. */ 530 mtx_lock(&rpctls_connect_lock); 531 rpctls_connect_so = NULL; 532 rpctls_connect_cl = NULL; 533 rpctls_connect_busy = false; 534 wakeup(&rpctls_connect_busy); 535 mtx_unlock(&rpctls_connect_lock); 536 537 return (stat); 538 } 539 540 /* Do an upcall to handle an non-application data record using TLS. */ 541 enum clnt_stat 542 rpctls_cl_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl, 543 uint32_t *reterr) 544 { 545 struct rpctlscd_handlerecord_arg arg; 546 struct rpctlscd_handlerecord_res res; 547 enum clnt_stat stat; 548 CLIENT *cl; 549 550 cl = rpctls_connect_client(); 551 if (cl == NULL) { 552 *reterr = RPCTLSERR_NOSSL; 553 return (RPC_SUCCESS); 554 } 555 556 /* Do the handlerecord upcall. */ 557 arg.sec = sec; 558 arg.usec = usec; 559 arg.ssl = ssl; 560 stat = rpctlscd_handlerecord_1(&arg, &res, cl); 561 CLNT_RELEASE(cl); 562 if (stat == RPC_SUCCESS) 563 *reterr = res.reterr; 564 return (stat); 565 } 566 567 enum clnt_stat 568 rpctls_srv_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl, int procpos, 569 uint32_t *reterr) 570 { 571 struct rpctlssd_handlerecord_arg arg; 572 struct rpctlssd_handlerecord_res res; 573 enum clnt_stat stat; 574 CLIENT *cl; 575 576 cl = rpctls_server_client(procpos); 577 if (cl == NULL) { 578 *reterr = RPCTLSERR_NOSSL; 579 return (RPC_SUCCESS); 580 } 581 582 /* Do the handlerecord upcall. */ 583 arg.sec = sec; 584 arg.usec = usec; 585 arg.ssl = ssl; 586 stat = rpctlssd_handlerecord_1(&arg, &res, cl); 587 CLNT_RELEASE(cl); 588 if (stat == RPC_SUCCESS) 589 *reterr = res.reterr; 590 return (stat); 591 } 592 593 /* Do an upcall to shut down a socket using TLS. */ 594 enum clnt_stat 595 rpctls_cl_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl, 596 uint32_t *reterr) 597 { 598 struct rpctlscd_disconnect_arg arg; 599 struct rpctlscd_disconnect_res res; 600 enum clnt_stat stat; 601 CLIENT *cl; 602 603 cl = rpctls_connect_client(); 604 if (cl == NULL) { 605 *reterr = RPCTLSERR_NOSSL; 606 return (RPC_SUCCESS); 607 } 608 609 /* Do the disconnect upcall. */ 610 arg.sec = sec; 611 arg.usec = usec; 612 arg.ssl = ssl; 613 stat = rpctlscd_disconnect_1(&arg, &res, cl); 614 CLNT_RELEASE(cl); 615 if (stat == RPC_SUCCESS) 616 *reterr = res.reterr; 617 return (stat); 618 } 619 620 enum clnt_stat 621 rpctls_srv_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl, int procpos, 622 uint32_t *reterr) 623 { 624 struct rpctlssd_disconnect_arg arg; 625 struct rpctlssd_disconnect_res res; 626 enum clnt_stat stat; 627 CLIENT *cl; 628 629 cl = rpctls_server_client(procpos); 630 if (cl == NULL) { 631 *reterr = RPCTLSERR_NOSSL; 632 return (RPC_SUCCESS); 633 } 634 635 /* Do the disconnect upcall. */ 636 arg.sec = sec; 637 arg.usec = usec; 638 arg.ssl = ssl; 639 stat = rpctlssd_disconnect_1(&arg, &res, cl); 640 CLNT_RELEASE(cl); 641 if (stat == RPC_SUCCESS) 642 *reterr = res.reterr; 643 return (stat); 644 } 645 646 /* Do an upcall for a new server socket using TLS. */ 647 static enum clnt_stat 648 rpctls_server(SVCXPRT *xprt, struct socket *so, uint32_t *flags, uint64_t *sslp, 649 uid_t *uid, int *ngrps, gid_t **gids, int *procposp) 650 { 651 enum clnt_stat stat; 652 CLIENT *cl; 653 struct rpctlssd_connect_res res; 654 gid_t *gidp; 655 uint32_t *gidv; 656 int i, procpos; 657 658 KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); 659 cl = NULL; 660 procpos = -1; 661 mtx_lock(&rpctls_server_lock); 662 for (i = (KRPC_VNET(rpctls_srv_prevproc) + 1) % RPCTLS_SRV_MAXNPROCS; 663 i != KRPC_VNET(rpctls_srv_prevproc); 664 i = (i + 1) % RPCTLS_SRV_MAXNPROCS) { 665 if (KRPC_VNET(rpctls_server_handle)[i] != NULL) 666 break; 667 } 668 if (i == KRPC_VNET(rpctls_srv_prevproc)) { 669 if (KRPC_VNET(rpctls_server_handle)[i] != NULL) 670 procpos = i; 671 } else 672 KRPC_VNET(rpctls_srv_prevproc) = procpos = i; 673 mtx_unlock(&rpctls_server_lock); 674 if (procpos >= 0) 675 cl = rpctls_server_client(procpos); 676 if (cl == NULL) { 677 KRPC_CURVNET_RESTORE(); 678 return (RPC_SYSTEMERROR); 679 } 680 681 /* Serialize the server upcalls. */ 682 mtx_lock(&rpctls_server_lock); 683 while (KRPC_VNET(rpctls_server_busy)[procpos]) 684 msleep(&KRPC_VNET(rpctls_server_busy)[procpos], 685 &rpctls_server_lock, PVFS, "rtlssn", 0); 686 KRPC_VNET(rpctls_server_busy)[procpos] = true; 687 KRPC_VNET(rpctls_server_so) = so; 688 KRPC_VNET(rpctls_server_xprt) = xprt; 689 mtx_unlock(&rpctls_server_lock); 690 691 /* Do the server upcall. */ 692 res.gid.gid_val = NULL; 693 stat = rpctlssd_connect_1(NULL, &res, cl); 694 if (stat == RPC_SUCCESS) { 695 *flags = res.flags; 696 *sslp++ = res.sec; 697 *sslp++ = res.usec; 698 *sslp = res.ssl; 699 *procposp = procpos; 700 if ((*flags & (RPCTLS_FLAGS_CERTUSER | 701 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) { 702 *ngrps = res.gid.gid_len; 703 *uid = res.uid; 704 *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t)); 705 gidv = res.gid.gid_val; 706 for (i = 0; i < *ngrps; i++) 707 *gidp++ = *gidv++; 708 } 709 } else if (stat == RPC_TIMEDOUT) { 710 /* 711 * Do a shutdown on the socket, since the daemon is probably 712 * stuck in SSL_accept() trying to read the socket. 713 * Do not soclose() the socket, since the daemon will close() 714 * the socket after SSL_accept() returns an error. 715 */ 716 soshutdown(so, SHUT_RD); 717 } 718 CLNT_RELEASE(cl); 719 mem_free(res.gid.gid_val, 0); 720 721 /* Once the upcall is done, the daemon is done with the fp and so. */ 722 mtx_lock(&rpctls_server_lock); 723 KRPC_VNET(rpctls_server_so) = NULL; 724 KRPC_VNET(rpctls_server_xprt) = NULL; 725 KRPC_VNET(rpctls_server_busy)[procpos] = false; 726 wakeup(&KRPC_VNET(rpctls_server_busy)[procpos]); 727 mtx_unlock(&rpctls_server_lock); 728 KRPC_CURVNET_RESTORE(); 729 730 return (stat); 731 } 732 733 /* 734 * Handle the NULL RPC with authentication flavor of AUTH_TLS. 735 * This is a STARTTLS command, so do the upcall to the rpctlssd daemon, 736 * which will do the TLS handshake. 737 */ 738 enum auth_stat 739 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg) 740 741 { 742 bool_t call_stat; 743 enum clnt_stat stat; 744 SVCXPRT *xprt; 745 uint32_t flags; 746 uint64_t ssl[3]; 747 int ngrps, procpos; 748 uid_t uid; 749 gid_t *gidp; 750 #ifdef KERN_TLS 751 u_int maxlen; 752 #endif 753 754 KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); 755 KRPC_VNET(svc_vc_tls_handshake_failed)++; 756 /* Initialize reply. */ 757 rqst->rq_verf = rpctls_null_verf; 758 759 /* Check client credentials. */ 760 if (rqst->rq_cred.oa_length != 0 || 761 msg->rm_call.cb_verf.oa_length != 0 || 762 msg->rm_call.cb_verf.oa_flavor != AUTH_NULL) { 763 KRPC_CURVNET_RESTORE(); 764 return (AUTH_BADCRED); 765 } 766 767 if (rqst->rq_proc != NULLPROC) { 768 KRPC_CURVNET_RESTORE(); 769 return (AUTH_REJECTEDCRED); 770 } 771 772 call_stat = FALSE; 773 #ifdef KERN_TLS 774 if (rpctls_getinfo(&maxlen, false, true)) 775 call_stat = TRUE; 776 #endif 777 if (!call_stat) { 778 KRPC_CURVNET_RESTORE(); 779 return (AUTH_REJECTEDCRED); 780 } 781 782 /* 783 * Disable reception for the krpc so that the TLS handshake can 784 * be done on the socket in the rpctlssd daemon. 785 */ 786 xprt = rqst->rq_xprt; 787 sx_xlock(&xprt->xp_lock); 788 xprt->xp_dontrcv = TRUE; 789 sx_xunlock(&xprt->xp_lock); 790 791 /* 792 * Send the reply to the NULL RPC with AUTH_TLS, which is the 793 * STARTTLS command for Sun RPC. 794 */ 795 call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL); 796 if (!call_stat) { 797 sx_xlock(&xprt->xp_lock); 798 xprt->xp_dontrcv = FALSE; 799 sx_xunlock(&xprt->xp_lock); 800 xprt_active(xprt); /* Harmless if already active. */ 801 KRPC_CURVNET_RESTORE(); 802 return (AUTH_REJECTEDCRED); 803 } 804 805 /* Do an upcall to do the TLS handshake. */ 806 stat = rpctls_server(xprt, xprt->xp_socket, &flags, 807 ssl, &uid, &ngrps, &gidp, &procpos); 808 809 /* Re-enable reception on the socket within the krpc. */ 810 sx_xlock(&xprt->xp_lock); 811 xprt->xp_dontrcv = FALSE; 812 if (stat == RPC_SUCCESS) { 813 xprt->xp_tls = flags; 814 xprt->xp_sslsec = ssl[0]; 815 xprt->xp_sslusec = ssl[1]; 816 xprt->xp_sslrefno = ssl[2]; 817 xprt->xp_sslproc = procpos; 818 if ((flags & (RPCTLS_FLAGS_CERTUSER | 819 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) { 820 xprt->xp_ngrps = ngrps; 821 xprt->xp_uid = uid; 822 xprt->xp_gidp = gidp; 823 } 824 KRPC_VNET(svc_vc_tls_handshake_failed)--; 825 KRPC_VNET(svc_vc_tls_handshake_success)++; 826 } 827 sx_xunlock(&xprt->xp_lock); 828 xprt_active(xprt); /* Harmless if already active. */ 829 KRPC_CURVNET_RESTORE(); 830 831 return (RPCSEC_GSS_NODISPATCH); 832 } 833 834 /* 835 * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen. 836 */ 837 bool 838 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run) 839 { 840 u_int maxlen; 841 bool enable; 842 int error; 843 size_t siz; 844 845 if (!mb_use_ext_pgs) 846 return (false); 847 siz = sizeof(enable); 848 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable", 849 &enable, &siz, NULL, 0, NULL, 0); 850 if (error != 0) 851 return (false); 852 siz = sizeof(maxlen); 853 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen", 854 &maxlen, &siz, NULL, 0, NULL, 0); 855 if (error != 0) 856 return (false); 857 if (rpctlscd_run && rpctls_connect_handle == NULL) 858 return (false); 859 KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread)); 860 if (rpctlssd_run && KRPC_VNET(rpctls_server_handle)[0] == NULL) { 861 KRPC_CURVNET_RESTORE(); 862 return (false); 863 } 864 KRPC_CURVNET_RESTORE(); 865 *maxlenp = maxlen; 866 return (enable); 867 } 868 869