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