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