]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpcsec_tls/rpctls_impl.c
Add a new "tlscertname" NFS mount option.
[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, 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. */
443 enum clnt_stat
444 rpctls_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
469 enum clnt_stat
470 rpctls_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. */
496 enum clnt_stat
497 rpctls_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
522 enum clnt_stat
523 rpctls_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. */
549 static enum clnt_stat
550 rpctls_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         stat = rpctlssd_connect_1(NULL, &res, cl);
577         if (stat == RPC_SUCCESS) {
578                 *flags = res.flags;
579                 *sslp++ = res.sec;
580                 *sslp++ = res.usec;
581                 *sslp = res.ssl;
582                 if ((*flags & (RPCTLS_FLAGS_CERTUSER |
583                     RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
584                         *ngrps = res.gid.gid_len;
585                         *uid = res.uid;
586                         *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t));
587                         gidv = res.gid.gid_val;
588                         for (i = 0; i < *ngrps; i++)
589                                 *gidp++ = *gidv++;
590                 }
591         } else if (stat == RPC_TIMEDOUT) {
592                 /*
593                  * Do a shutdown on the socket, since the daemon is probably
594                  * stuck in SSL_accept() trying to read the socket.
595                  * Do not soclose() the socket, since the daemon will close()
596                  * the socket after SSL_accept() returns an error.
597                  */
598                 soshutdown(so, SHUT_RD);
599         }
600         CLNT_RELEASE(cl);
601
602         /* Once the upcall is done, the daemon is done with the fp and so. */
603         mtx_lock(&rpctls_server_lock);
604         rpctls_server_so = NULL;
605         rpctls_server_xprt = NULL;
606         rpctls_server_busy = false;
607         wakeup(&rpctls_server_busy);
608         mtx_unlock(&rpctls_server_lock);
609
610         return (stat);
611 }
612
613 /*
614  * Handle the NULL RPC with authentication flavor of AUTH_TLS.
615  * This is a STARTTLS command, so do the upcall to the rpctlssd daemon,
616  * which will do the TLS handshake.
617  */
618 enum auth_stat
619 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg)
620
621 {
622         bool_t call_stat;
623         enum clnt_stat stat;
624         SVCXPRT *xprt;
625         uint32_t flags;
626         uint64_t ssl[3];
627         int ngrps;
628         uid_t uid;
629         gid_t *gidp;
630 #ifdef KERN_TLS
631         u_int maxlen;
632 #endif
633         
634         /* Initialize reply. */
635         rqst->rq_verf = rpctls_null_verf;
636
637         /* Check client credentials. */
638         if (rqst->rq_cred.oa_length != 0 ||
639             msg->rm_call.cb_verf.oa_length != 0 ||
640             msg->rm_call.cb_verf.oa_flavor != AUTH_NULL)
641                 return (AUTH_BADCRED);
642         
643         if (rqst->rq_proc != NULLPROC)
644                 return (AUTH_REJECTEDCRED);
645
646         call_stat = FALSE;
647 #ifdef KERN_TLS
648         if (rpctls_getinfo(&maxlen, false, true))
649                 call_stat = TRUE;
650 #endif
651         if (!call_stat)
652                 return (AUTH_REJECTEDCRED);
653
654         /*
655          * Disable reception for the krpc so that the TLS handshake can
656          * be done on the socket in the rpctlssd daemon.
657          */
658         xprt = rqst->rq_xprt;
659         sx_xlock(&xprt->xp_lock);
660         xprt->xp_dontrcv = TRUE;
661         sx_xunlock(&xprt->xp_lock);
662
663         /*
664          * Send the reply to the NULL RPC with AUTH_TLS, which is the
665          * STARTTLS command for Sun RPC.
666          */
667         call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL);
668         if (!call_stat) {
669                 sx_xlock(&xprt->xp_lock);
670                 xprt->xp_dontrcv = FALSE;
671                 sx_xunlock(&xprt->xp_lock);
672                 xprt_active(xprt);      /* Harmless if already active. */
673                 return (AUTH_REJECTEDCRED);
674         }
675
676         /* Do an upcall to do the TLS handshake. */
677         stat = rpctls_server(xprt, xprt->xp_socket, &flags,
678             ssl, &uid, &ngrps, &gidp);
679
680         /* Re-enable reception on the socket within the krpc. */
681         sx_xlock(&xprt->xp_lock);
682         xprt->xp_dontrcv = FALSE;
683         if (stat == RPC_SUCCESS) {
684                 xprt->xp_tls = flags;
685                 xprt->xp_sslsec = ssl[0];
686                 xprt->xp_sslusec = ssl[1];
687                 xprt->xp_sslrefno = ssl[2];
688                 if ((flags & (RPCTLS_FLAGS_CERTUSER |
689                     RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
690                         xprt->xp_ngrps = ngrps;
691                         xprt->xp_uid = uid;
692                         xprt->xp_gidp = gidp;
693                 }
694         }
695         sx_xunlock(&xprt->xp_lock);
696         xprt_active(xprt);              /* Harmless if already active. */
697
698         return (RPCSEC_GSS_NODISPATCH);
699 }
700
701 /*
702  * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen.
703  */
704 bool
705 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run)
706 {
707         u_int maxlen;
708         bool enable;
709         int error;
710         size_t siz;
711
712         if (PMAP_HAS_DMAP == 0 || !mb_use_ext_pgs)
713                 return (false);
714         siz = sizeof(enable);
715         error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable",
716             &enable, &siz, NULL, 0, NULL, 0);
717         if (error != 0)
718                 return (false);
719         siz = sizeof(maxlen);
720         error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen",
721             &maxlen, &siz, NULL, 0, NULL, 0);
722         if (error != 0)
723                 return (false);
724         if (rpctlscd_run && rpctls_connect_handle == NULL)
725                 return (false);
726         if (rpctlssd_run && rpctls_server_handle == NULL)
727                 return (false);
728         *maxlenp = maxlen;
729         return (enable);
730 }
731