2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 /* Modified from the kernel GSSAPI code for RPC-over-TLS. */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include "opt_kern_tls.h"
37 #include <sys/param.h>
38 #include <sys/capsicum.h>
40 #include <sys/filedesc.h>
41 #include <sys/kernel.h>
43 #include <sys/malloc.h>
45 #include <sys/mutex.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>
55 #include <rpc/rpc_com.h>
56 #include <rpc/rpcsec_tls.h>
60 #include <vm/vm_param.h>
68 static struct syscall_helper_data rpctls_syscalls[] = {
69 SYSCALL_INIT_HELPER(rpctls_syscall),
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;
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);
94 error = syscall_helper_register(rpctls_syscalls, SY_THR_STATIC_KLD);
96 printf("rpctls_init: cannot register syscall\n");
99 mtx_init(&rpctls_connect_lock, "rpctls_connect_lock", NULL,
101 mtx_init(&rpctls_server_lock, "rpctls_server_lock", NULL,
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);
110 sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
112 struct sockaddr_un sun;
113 struct netconfig *nconf;
117 char path[MAXPATHLEN];
118 int fd = -1, error, try_count;
119 CLIENT *cl, *oldcl, *concl;
121 struct timeval timeo;
126 error = priv_check(td, PRIV_NFS_DAEMON);
131 case RPCTLS_SYSC_CLSETPATH:
132 error = copyinstr(uap->path, path, sizeof(path), NULL);
136 if (rpctls_getinfo(&maxlen, false, false))
140 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) ||
146 sun.sun_family = AF_LOCAL;
147 strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
148 sun.sun_len = SUN_LEN(&sun);
150 nconf = getnetconfigent("local");
151 cl = clnt_reconnect_create(nconf,
152 (struct sockaddr *)&sun, RPCTLSCD, RPCTLSCDVERS,
153 RPC_MAXDATASIZE, RPC_MAXDATASIZE);
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.
169 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count);
172 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo);
177 mtx_lock(&rpctls_connect_lock);
178 oldcl = rpctls_connect_handle;
179 rpctls_connect_handle = cl;
180 mtx_unlock(&rpctls_connect_lock);
187 case RPCTLS_SYSC_SRVSETPATH:
188 error = copyinstr(uap->path, path, sizeof(path), NULL);
192 if (rpctls_getinfo(&maxlen, false, false))
196 if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) ||
202 sun.sun_family = AF_LOCAL;
203 strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
204 sun.sun_len = SUN_LEN(&sun);
206 nconf = getnetconfigent("local");
207 cl = clnt_reconnect_create(nconf,
208 (struct sockaddr *)&sun, RPCTLSSD, RPCTLSSDVERS,
209 RPC_MAXDATASIZE, RPC_MAXDATASIZE);
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.
222 CLNT_CONTROL(cl, CLSET_RETRIES, &try_count);
225 CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo);
230 mtx_lock(&rpctls_server_lock);
231 oldcl = rpctls_server_handle;
232 rpctls_server_handle = cl;
233 mtx_unlock(&rpctls_server_lock);
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);
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);
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);
270 error = falloc(td, &fp, &fd, 0);
273 * Set ssl refno so that clnt_vc_destroy() will
274 * not close the socket and will leave that for
279 ssl[2] = RPCTLS_REFNO_HANDSHAKE;
280 CLNT_CONTROL(concl, CLSET_TLS, ssl);
281 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so,
283 fdrop(fp, td); /* Drop fp reference. */
284 td->td_retval[0] = fd;
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);
297 error = falloc(td, &fp, &fd, 0);
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).
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,
310 fdrop(fp, td); /* Drop fp reference. */
311 td->td_retval[0] = fd;
324 * Acquire the rpctls_connect_handle and return it with a reference count,
325 * if it is available.
328 rpctls_connect_client(void)
332 mtx_lock(&rpctls_connect_lock);
333 cl = rpctls_connect_handle;
336 mtx_unlock(&rpctls_connect_lock);
341 * Acquire the rpctls_server_handle and return it with a reference count,
342 * if it is available.
345 rpctls_server_client(void)
349 mtx_lock(&rpctls_server_lock);
350 cl = rpctls_server_handle;
353 mtx_unlock(&rpctls_server_lock);
357 /* Do an upcall for a new socket connect using TLS. */
359 rpctls_connect(CLIENT *newclient, struct socket *so, uint64_t *sslp,
362 struct rpctlscd_connect_res res;
363 struct rpc_callextra ext;
364 struct timeval utimeout;
368 static bool rpctls_connect_busy = false;
370 cl = rpctls_connect_client();
372 return (RPC_AUTHERROR);
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)
384 if (stat != RPC_SUCCESS)
385 return (RPC_SYSTEMERROR);
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,
392 rpctls_connect_busy = true;
393 rpctls_connect_so = so;
394 rpctls_connect_cl = newclient;
395 mtx_unlock(&rpctls_connect_lock);
397 /* Temporarily block reception during the handshake upcall. */
399 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val);
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) {
410 } else if (stat == RPC_TIMEDOUT) {
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.
417 soshutdown(so, SHUT_RD);
421 /* Unblock reception. */
423 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val);
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);
436 /* Do an upcall to handle an non-application data record using TLS. */
438 rpctls_cl_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl,
441 struct rpctlscd_handlerecord_arg arg;
442 struct rpctlscd_handlerecord_res res;
446 cl = rpctls_connect_client();
448 *reterr = RPCTLSERR_NOSSL;
449 return (RPC_SUCCESS);
452 /* Do the handlerecord upcall. */
456 stat = rpctlscd_handlerecord_1(&arg, &res, cl);
458 if (stat == RPC_SUCCESS)
459 *reterr = res.reterr;
464 rpctls_srv_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl,
467 struct rpctlssd_handlerecord_arg arg;
468 struct rpctlssd_handlerecord_res res;
472 cl = rpctls_server_client();
474 *reterr = RPCTLSERR_NOSSL;
475 return (RPC_SUCCESS);
478 /* Do the handlerecord upcall. */
482 stat = rpctlssd_handlerecord_1(&arg, &res, cl);
484 if (stat == RPC_SUCCESS)
485 *reterr = res.reterr;
489 /* Do an upcall to shut down a socket using TLS. */
491 rpctls_cl_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl,
494 struct rpctlscd_disconnect_arg arg;
495 struct rpctlscd_disconnect_res res;
499 cl = rpctls_connect_client();
501 *reterr = RPCTLSERR_NOSSL;
502 return (RPC_SUCCESS);
505 /* Do the disconnect upcall. */
509 stat = rpctlscd_disconnect_1(&arg, &res, cl);
511 if (stat == RPC_SUCCESS)
512 *reterr = res.reterr;
517 rpctls_srv_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl,
520 struct rpctlssd_disconnect_arg arg;
521 struct rpctlssd_disconnect_res res;
525 cl = rpctls_server_client();
527 *reterr = RPCTLSERR_NOSSL;
528 return (RPC_SUCCESS);
531 /* Do the disconnect upcall. */
535 stat = rpctlssd_disconnect_1(&arg, &res, cl);
537 if (stat == RPC_SUCCESS)
538 *reterr = res.reterr;
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)
549 struct rpctlssd_connect_res res;
553 static bool rpctls_server_busy = false;
555 cl = rpctls_server_client();
557 return (RPC_SYSTEMERROR);
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,
564 rpctls_server_busy = true;
565 rpctls_server_so = so;
566 rpctls_server_xprt = xprt;
567 mtx_unlock(&rpctls_server_lock);
569 /* Do the server upcall. */
570 stat = rpctlssd_connect_1(NULL, &res, cl);
571 if (stat == RPC_SUCCESS) {
576 if ((*flags & (RPCTLS_FLAGS_CERTUSER |
577 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
578 *ngrps = res.gid.gid_len;
580 *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t));
581 gidv = res.gid.gid_val;
582 for (i = 0; i < *ngrps; i++)
585 } else if (stat == RPC_TIMEDOUT) {
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.
592 soshutdown(so, SHUT_RD);
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);
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.
613 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg)
628 /* Initialize reply. */
629 rqst->rq_verf = rpctls_null_verf;
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);
637 if (rqst->rq_proc != NULLPROC)
638 return (AUTH_REJECTEDCRED);
642 if (rpctls_getinfo(&maxlen, false, true))
646 return (AUTH_REJECTEDCRED);
649 * Disable reception for the krpc so that the TLS handshake can
650 * be done on the socket in the rpctlssd daemon.
652 xprt = rqst->rq_xprt;
653 sx_xlock(&xprt->xp_lock);
654 xprt->xp_dontrcv = TRUE;
655 sx_xunlock(&xprt->xp_lock);
658 * Send the reply to the NULL RPC with AUTH_TLS, which is the
659 * STARTTLS command for Sun RPC.
661 call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL);
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);
670 /* Do an upcall to do the TLS handshake. */
671 stat = rpctls_server(xprt, xprt->xp_socket, &flags,
672 ssl, &uid, &ngrps, &gidp);
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;
686 xprt->xp_gidp = gidp;
689 sx_xunlock(&xprt->xp_lock);
690 xprt_active(xprt); /* Harmless if already active. */
692 return (RPCSEC_GSS_NODISPATCH);
696 * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen.
699 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run)
706 if (PMAP_HAS_DMAP == 0 || !mb_use_ext_pgs)
708 siz = sizeof(enable);
709 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable",
710 &enable, &siz, NULL, 0, NULL, 0);
713 siz = sizeof(maxlen);
714 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen",
715 &maxlen, &siz, NULL, 0, NULL, 0);
718 if (rpctlscd_run && rpctls_connect_handle == NULL)
720 if (rpctlssd_run && rpctls_server_handle == NULL)