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