The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/rpcsec_tls/rpctls_impl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 963dc20b2cbfd1c01ac42d10f727f95c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.