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
rpctls_vnetinit(const void * unused __unused)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
rpctls_cleanup(void * unused __unused)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
rpctls_init(void)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
sys_rpctls_syscall(struct thread * td,struct rpctls_syscall_args * uap)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 *
rpctls_connect_client(void)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 *
rpctls_server_client(int procpos)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
rpctls_connect(CLIENT * newclient,char * certname,struct socket * so,uint64_t * sslp,uint32_t * reterr)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
rpctls_cl_handlerecord(uint64_t sec,uint64_t usec,uint64_t ssl,uint32_t * reterr)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
rpctls_srv_handlerecord(uint64_t sec,uint64_t usec,uint64_t ssl,int procpos,uint32_t * reterr)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
rpctls_cl_disconnect(uint64_t sec,uint64_t usec,uint64_t ssl,uint32_t * reterr)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
rpctls_srv_disconnect(uint64_t sec,uint64_t usec,uint64_t ssl,int procpos,uint32_t * reterr)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
rpctls_server(SVCXPRT * xprt,struct socket * so,uint32_t * flags,uint64_t * sslp,uid_t * uid,int * ngrps,gid_t ** gids,int * procposp)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
_svcauth_rpcsec_tls(struct svc_req * rqst,struct rpc_msg * msg)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
rpctls_getinfo(u_int * maxlenp,bool rpctlscd_run,bool rpctlssd_run)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