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