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