]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpcsec_tls/rpctls_impl.c
Update nvi to 2.2.0
[FreeBSD/FreeBSD.git] / sys / rpc / rpcsec_tls / rpctls_impl.c
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;
78 static struct mtx       rpctls_server_lock;
79 static struct socket    *rpctls_server_so = NULL;
80 static SVCXPRT          *rpctls_server_xprt = NULL;
81 static struct opaque_auth rpctls_null_verf;
82
83 static CLIENT           *rpctls_connect_client(void);
84 static CLIENT           *rpctls_server_client(void);
85 static 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
89 int
90 rpctls_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
109 int
110 sys_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  */
327 static CLIENT *
328 rpctls_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  */
344 static CLIENT *
345 rpctls_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. */
358 enum clnt_stat
359 rpctls_connect(CLIENT *newclient, struct socket *so, uint64_t *sslp,
360     uint32_t *reterr)
361 {
362         struct rpctlscd_connect_res res;
363         struct rpc_callextra ext;
364         struct timeval utimeout;
365         enum clnt_stat stat;
366         CLIENT *cl;
367         int val;
368         static bool rpctls_connect_busy = false;
369
370         cl = rpctls_connect_client();
371         if (cl == NULL)
372                 return (RPC_AUTHERROR);
373
374         /* First, do the AUTH_TLS NULL RPC. */
375         memset(&ext, 0, sizeof(ext));
376         utimeout.tv_sec = 30;
377         utimeout.tv_usec = 0;
378         ext.rc_auth = authtls_create();
379         stat = clnt_call_private(newclient, &ext, NULLPROC, (xdrproc_t)xdr_void,
380             NULL, (xdrproc_t)xdr_void, NULL, utimeout);
381         AUTH_DESTROY(ext.rc_auth);
382         if (stat == RPC_AUTHERROR)
383                 return (stat);
384         if (stat != RPC_SUCCESS)
385                 return (RPC_SYSTEMERROR);
386
387         /* Serialize the connect upcalls. */
388         mtx_lock(&rpctls_connect_lock);
389         while (rpctls_connect_busy)
390                 msleep(&rpctls_connect_busy, &rpctls_connect_lock, PVFS,
391                     "rtlscn", 0);
392         rpctls_connect_busy = true;
393         rpctls_connect_so = so;
394         rpctls_connect_cl = newclient;
395         mtx_unlock(&rpctls_connect_lock);
396
397         /* Temporarily block reception during the handshake upcall. */
398         val = 1;
399         CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val);
400
401         /* Do the connect handshake upcall. */
402         stat = rpctlscd_connect_1(NULL, &res, cl);
403         if (stat == RPC_SUCCESS) {
404                 *reterr = res.reterr;
405                 if (res.reterr == 0) {
406                         *sslp++ = res.sec;
407                         *sslp++ = res.usec;
408                         *sslp = res.ssl;
409                 }
410         } else if (stat == RPC_TIMEDOUT) {
411                 /*
412                  * Do a shutdown on the socket, since the daemon is probably
413                  * stuck in SSL_connect() trying to read the socket.
414                  * Do not soclose() the socket, since the daemon will close()
415                  * the socket after SSL_connect() returns an error.
416                  */
417                 soshutdown(so, SHUT_RD);
418         }
419         CLNT_RELEASE(cl);
420
421         /* Unblock reception. */
422         val = 0;
423         CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &val);
424
425         /* Once the upcall is done, the daemon is done with the fp and so. */
426         mtx_lock(&rpctls_connect_lock);
427         rpctls_connect_so = NULL;
428         rpctls_connect_cl = NULL;
429         rpctls_connect_busy = false;
430         wakeup(&rpctls_connect_busy);
431         mtx_unlock(&rpctls_connect_lock);
432
433         return (stat);
434 }
435
436 /* Do an upcall to handle an non-application data record using TLS. */
437 enum clnt_stat
438 rpctls_cl_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl,
439     uint32_t *reterr)
440 {
441         struct rpctlscd_handlerecord_arg arg;
442         struct rpctlscd_handlerecord_res res;
443         enum clnt_stat stat;
444         CLIENT *cl;
445
446         cl = rpctls_connect_client();
447         if (cl == NULL) {
448                 *reterr = RPCTLSERR_NOSSL;
449                 return (RPC_SUCCESS);
450         }
451
452         /* Do the handlerecord upcall. */
453         arg.sec = sec;
454         arg.usec = usec;
455         arg.ssl = ssl;
456         stat = rpctlscd_handlerecord_1(&arg, &res, cl);
457         CLNT_RELEASE(cl);
458         if (stat == RPC_SUCCESS)
459                 *reterr = res.reterr;
460         return (stat);
461 }
462
463 enum clnt_stat
464 rpctls_srv_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl,
465     uint32_t *reterr)
466 {
467         struct rpctlssd_handlerecord_arg arg;
468         struct rpctlssd_handlerecord_res res;
469         enum clnt_stat stat;
470         CLIENT *cl;
471
472         cl = rpctls_server_client();
473         if (cl == NULL) {
474                 *reterr = RPCTLSERR_NOSSL;
475                 return (RPC_SUCCESS);
476         }
477
478         /* Do the handlerecord upcall. */
479         arg.sec = sec;
480         arg.usec = usec;
481         arg.ssl = ssl;
482         stat = rpctlssd_handlerecord_1(&arg, &res, cl);
483         CLNT_RELEASE(cl);
484         if (stat == RPC_SUCCESS)
485                 *reterr = res.reterr;
486         return (stat);
487 }
488
489 /* Do an upcall to shut down a socket using TLS. */
490 enum clnt_stat
491 rpctls_cl_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl,
492     uint32_t *reterr)
493 {
494         struct rpctlscd_disconnect_arg arg;
495         struct rpctlscd_disconnect_res res;
496         enum clnt_stat stat;
497         CLIENT *cl;
498
499         cl = rpctls_connect_client();
500         if (cl == NULL) {
501                 *reterr = RPCTLSERR_NOSSL;
502                 return (RPC_SUCCESS);
503         }
504
505         /* Do the disconnect upcall. */
506         arg.sec = sec;
507         arg.usec = usec;
508         arg.ssl = ssl;
509         stat = rpctlscd_disconnect_1(&arg, &res, cl);
510         CLNT_RELEASE(cl);
511         if (stat == RPC_SUCCESS)
512                 *reterr = res.reterr;
513         return (stat);
514 }
515
516 enum clnt_stat
517 rpctls_srv_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl,
518     uint32_t *reterr)
519 {
520         struct rpctlssd_disconnect_arg arg;
521         struct rpctlssd_disconnect_res res;
522         enum clnt_stat stat;
523         CLIENT *cl;
524
525         cl = rpctls_server_client();
526         if (cl == NULL) {
527                 *reterr = RPCTLSERR_NOSSL;
528                 return (RPC_SUCCESS);
529         }
530
531         /* Do the disconnect upcall. */
532         arg.sec = sec;
533         arg.usec = usec;
534         arg.ssl = ssl;
535         stat = rpctlssd_disconnect_1(&arg, &res, cl);
536         CLNT_RELEASE(cl);
537         if (stat == RPC_SUCCESS)
538                 *reterr = res.reterr;
539         return (stat);
540 }
541
542 /* Do an upcall for a new server socket using TLS. */
543 static enum clnt_stat
544 rpctls_server(SVCXPRT *xprt, struct socket *so, uint32_t *flags, uint64_t *sslp,
545     uid_t *uid, int *ngrps, gid_t **gids)
546 {
547         enum clnt_stat stat;
548         CLIENT *cl;
549         struct rpctlssd_connect_res res;
550         gid_t *gidp;
551         uint32_t *gidv;
552         int i;
553         static bool rpctls_server_busy = false;
554
555         cl = rpctls_server_client();
556         if (cl == NULL)
557                 return (RPC_SYSTEMERROR);
558
559         /* Serialize the server upcalls. */
560         mtx_lock(&rpctls_server_lock);
561         while (rpctls_server_busy)
562                 msleep(&rpctls_server_busy, &rpctls_server_lock, PVFS,
563                     "rtlssn", 0);
564         rpctls_server_busy = true;
565         rpctls_server_so = so;
566         rpctls_server_xprt = xprt;
567         mtx_unlock(&rpctls_server_lock);
568
569         /* Do the server upcall. */
570         stat = rpctlssd_connect_1(NULL, &res, cl);
571         if (stat == RPC_SUCCESS) {
572                 *flags = res.flags;
573                 *sslp++ = res.sec;
574                 *sslp++ = res.usec;
575                 *sslp = res.ssl;
576                 if ((*flags & (RPCTLS_FLAGS_CERTUSER |
577                     RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
578                         *ngrps = res.gid.gid_len;
579                         *uid = res.uid;
580                         *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t));
581                         gidv = res.gid.gid_val;
582                         for (i = 0; i < *ngrps; i++)
583                                 *gidp++ = *gidv++;
584                 }
585         } else if (stat == RPC_TIMEDOUT) {
586                 /*
587                  * Do a shutdown on the socket, since the daemon is probably
588                  * stuck in SSL_accept() trying to read the socket.
589                  * Do not soclose() the socket, since the daemon will close()
590                  * the socket after SSL_accept() returns an error.
591                  */
592                 soshutdown(so, SHUT_RD);
593         }
594         CLNT_RELEASE(cl);
595
596         /* Once the upcall is done, the daemon is done with the fp and so. */
597         mtx_lock(&rpctls_server_lock);
598         rpctls_server_so = NULL;
599         rpctls_server_xprt = NULL;
600         rpctls_server_busy = false;
601         wakeup(&rpctls_server_busy);
602         mtx_unlock(&rpctls_server_lock);
603
604         return (stat);
605 }
606
607 /*
608  * Handle the NULL RPC with authentication flavor of AUTH_TLS.
609  * This is a STARTTLS command, so do the upcall to the rpctlssd daemon,
610  * which will do the TLS handshake.
611  */
612 enum auth_stat
613 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg)
614
615 {
616         bool_t call_stat;
617         enum clnt_stat stat;
618         SVCXPRT *xprt;
619         uint32_t flags;
620         uint64_t ssl[3];
621         int ngrps;
622         uid_t uid;
623         gid_t *gidp;
624 #ifdef KERN_TLS
625         u_int maxlen;
626 #endif
627         
628         /* Initialize reply. */
629         rqst->rq_verf = rpctls_null_verf;
630
631         /* Check client credentials. */
632         if (rqst->rq_cred.oa_length != 0 ||
633             msg->rm_call.cb_verf.oa_length != 0 ||
634             msg->rm_call.cb_verf.oa_flavor != AUTH_NULL)
635                 return (AUTH_BADCRED);
636         
637         if (rqst->rq_proc != NULLPROC)
638                 return (AUTH_REJECTEDCRED);
639
640         call_stat = FALSE;
641 #ifdef KERN_TLS
642         if (rpctls_getinfo(&maxlen, false, true))
643                 call_stat = TRUE;
644 #endif
645         if (!call_stat)
646                 return (AUTH_REJECTEDCRED);
647
648         /*
649          * Disable reception for the krpc so that the TLS handshake can
650          * be done on the socket in the rpctlssd daemon.
651          */
652         xprt = rqst->rq_xprt;
653         sx_xlock(&xprt->xp_lock);
654         xprt->xp_dontrcv = TRUE;
655         sx_xunlock(&xprt->xp_lock);
656
657         /*
658          * Send the reply to the NULL RPC with AUTH_TLS, which is the
659          * STARTTLS command for Sun RPC.
660          */
661         call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL);
662         if (!call_stat) {
663                 sx_xlock(&xprt->xp_lock);
664                 xprt->xp_dontrcv = FALSE;
665                 sx_xunlock(&xprt->xp_lock);
666                 xprt_active(xprt);      /* Harmless if already active. */
667                 return (AUTH_REJECTEDCRED);
668         }
669
670         /* Do an upcall to do the TLS handshake. */
671         stat = rpctls_server(xprt, xprt->xp_socket, &flags,
672             ssl, &uid, &ngrps, &gidp);
673
674         /* Re-enable reception on the socket within the krpc. */
675         sx_xlock(&xprt->xp_lock);
676         xprt->xp_dontrcv = FALSE;
677         if (stat == RPC_SUCCESS) {
678                 xprt->xp_tls = flags;
679                 xprt->xp_sslsec = ssl[0];
680                 xprt->xp_sslusec = ssl[1];
681                 xprt->xp_sslrefno = ssl[2];
682                 if ((flags & (RPCTLS_FLAGS_CERTUSER |
683                     RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
684                         xprt->xp_ngrps = ngrps;
685                         xprt->xp_uid = uid;
686                         xprt->xp_gidp = gidp;
687                 }
688         }
689         sx_xunlock(&xprt->xp_lock);
690         xprt_active(xprt);              /* Harmless if already active. */
691
692         return (RPCSEC_GSS_NODISPATCH);
693 }
694
695 /*
696  * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen.
697  */
698 bool
699 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run)
700 {
701         u_int maxlen;
702         bool enable;
703         int error;
704         size_t siz;
705
706         if (PMAP_HAS_DMAP == 0 || !mb_use_ext_pgs)
707                 return (false);
708         siz = sizeof(enable);
709         error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable",
710             &enable, &siz, NULL, 0, NULL, 0);
711         if (error != 0)
712                 return (false);
713         siz = sizeof(maxlen);
714         error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen",
715             &maxlen, &siz, NULL, 0, NULL, 0);
716         if (error != 0)
717                 return (false);
718         if (rpctlscd_run && rpctls_connect_handle == NULL)
719                 return (false);
720         if (rpctlssd_run && rpctls_server_handle == NULL)
721                 return (false);
722         *maxlenp = maxlen;
723         return (enable);
724 }
725