xref: /freebsd/sys/rpc/rpcsec_tls/rpctls_impl.c (revision 06c3fb27)
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