Print this page
8330 Add svc_tp_create_addr to libnsl
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*

  23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T */
  28 /*      All Rights Reserved   */
  29 
  30 /*
  31  * svc_generic.c, Server side for RPC.
  32  *
  33  */
  34 
  35 #include "mt.h"
  36 #include <stdlib.h>
  37 #include <sys/socket.h>
  38 #include <netinet/in.h>
  39 #include <netinet/tcp.h>
  40 #include <netinet/udp.h>
  41 #include <inttypes.h>
  42 #include "rpc_mt.h"
  43 #include <stdio.h>
  44 #include <rpc/rpc.h>


  70 extern bool_t __rpc_try_doors(const char *, bool_t *);
  71 
  72 /*
  73  * The highest level interface for server creation.
  74  * It tries for all the nettokens in that particular class of token
  75  * and returns the number of handles it can create and/or find.
  76  *
  77  * It creates a link list of all the handles it could create.
  78  * If svc_create() is called multiple times, it uses the handle
  79  * created earlier instead of creating a new handle every time.
  80  */
  81 
  82 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
  83 
  84 SVCXPRT_LIST *_svc_xprtlist = NULL;
  85 extern mutex_t xprtlist_lock;
  86 
  87 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
  88     const struct t_bind *, uint_t, uint_t, boolean_t);
  89 




  90 boolean_t
  91 is_multilevel(rpcprog_t prognum)
  92 {
  93         /* This is a list of identified multilevel service provider */
  94         if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
  95             (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
  96             (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
  97             (prognum == SM_PROG))
  98                 return (B_TRUE);
  99 
 100         return (B_FALSE);
 101 }
 102 
 103 void
 104 __svc_free_xprtlist(void)
 105 {
 106         __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
 107 }
 108 
 109 int


 159                                     &xprtlist_lock)) {
 160                                         (void) syslog(LOG_ERR,
 161                                             "svc_create: no memory");
 162                                         return (0);
 163                                 }
 164                                 num++;
 165                         }
 166                 }
 167         }
 168         __rpc_endconf(handle);
 169         /*
 170          * In case of num == 0; the error messages are generated by the
 171          * underlying layers; and hence not needed here.
 172          */
 173         return (num);
 174 }
 175 
 176 /*
 177  * The high level interface to svc_tli_create().
 178  * It tries to create a server for "nconf" and registers the service
 179  * with the rpcbind. It calls svc_tli_create();
 180  */
 181 SVCXPRT *
 182 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
 183                         const rpcvers_t versnum, const struct netconfig *nconf)
 184 {







































 185         SVCXPRT *xprt;
 186         boolean_t anon_mlp = B_FALSE;
 187 
 188         if (nconf == NULL) {
 189                 (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
 190                     "structure for prog %d vers %d", prognum, versnum);
 191                 return (NULL);
 192         }
 193 
 194         /* Some programs need to allocate MLP for multilevel services */
 195         if (is_system_labeled() && is_multilevel(prognum))
 196                 anon_mlp = B_TRUE;
 197         xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);

 198         if (xprt == NULL)
 199                 return (NULL);
 200 
 201         (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
 202         if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
 203                 (void) syslog(LOG_ERR,
 204                     "svc_tp_create: Could not register prog %d vers %d on %s",
 205                     prognum, versnum, nconf->nc_netid);
 206                 SVC_DESTROY(xprt);
 207                 return (NULL);
 208         }
 209         return (xprt);
 210 }
 211 
 212 SVCXPRT *
 213 svc_tli_create(const int fd, const struct netconfig *nconf,
 214     const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
 215 {
 216         return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
 217 }


 307                                             "svc_tli_create: "
 308                                             "IP_RECVDSTADDR(1): %s", errorstr);
 309                                         return (NULL);
 310                                 }
 311                         }
 312                 }
 313         }
 314 
 315         /*
 316          * If the fd is unbound, try to bind it.
 317          * In any case, try to get its bound info in tres
 318          */
 319 /* LINTED pointer alignment */
 320         tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
 321         if (tres == NULL) {
 322                 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
 323                 goto freedata;
 324         }
 325 
 326         switch (state) {
 327                 bool_t tcp, exclbind;
 328         case T_UNBND:
 329                 /* If this is a labeled system, then ask for an MLP */
 330                 if (is_system_labeled() &&
 331                     (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
 332                     strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
 333                         (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 334                             SO_RECVUCRED, 1);
 335                         if (mlp_flag)
 336                                 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 337                                     SO_ANON_MLP, 1);
 338                 }
 339 

 340                 /*
 341                  * SO_EXCLBIND has the following properties
 342                  *    - an fd bound to port P via IPv4 will prevent an IPv6
 343                  *    bind to port P (and vice versa)
 344                  *    - an fd bound to a wildcard IP address for port P will
 345                  *    prevent a more specific IP address bind to port P
 346                  *    (see {tcp,udp}.c for details)
 347                  *
 348                  * We use the latter property to prevent hijacking of RPC
 349                  * services that reside at non-privileged ports.
 350                  */
 351                 tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0;
 352                 if (nconf &&
 353                     (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) &&
 354                     rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) {
 355                         if (exclbind) {
 356                                 if (__rpc_tli_set_options(fd, SOL_SOCKET,
 357                                     SO_EXCLBIND, 1) < 0) {
 358                                         syslog(LOG_ERR,
 359                             "svc_tli_create: can't set EXCLBIND [netid='%s']",
 360                                             nconf->nc_netid);
 361                                         goto freedata;
 362                                 }
 363                         }
 364                 }
 365                 if (bindaddr) {
 366                         if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
 367                                 char errorstr[100];
 368 
 369                                 __tli_sys_strerror(errorstr, sizeof (errorstr),
 370                                     t_errno, errno);
 371                                 (void) syslog(LOG_ERR,
 372                                     "svc_tli_create: could not bind: %s",
 373                                     errorstr);
 374                                 goto freedata;
 375                         }
 376                         /*
 377                          * Should compare the addresses only if addr.len
 378                          * was non-zero
 379                          */
 380                         if (bindaddr->addr.len &&
 381                             (memcmp(bindaddr->addr.buf, tres->addr.buf,
 382                             (int)tres->addr.len) != 0)) {
 383                                 (void) syslog(LOG_ERR, "svc_tli_create: could "
 384                                     "not bind to requested address: address "
 385                                     "mismatch");
 386                                 goto freedata;
 387                         }
 388                 } else {
 389                         if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
 390                             == FALSE) {
 391                                 syslog(LOG_ERR,
 392                                     "svc_tli_create: can't get listen backlog");
 393                                 goto freedata;
 394                         }
 395                         tres->addr.len = 0;
 396                         if (t_bind(fd, tres, tres) == -1) {
 397                                 char errorstr[100];
 398 
 399                                 __tli_sys_strerror(errorstr, sizeof (errorstr),
 400                                     t_errno, errno);
 401                                 (void) syslog(LOG_ERR,
 402                                     "svc_tli_create: could not bind: %s",
 403                                     errorstr);
 404                                 goto freedata;
 405                         }









































 406                 }
 407 
 408                 /* Enable options of returning the ip's for udp */
 409                 if (nconf) {
 410                         int ret = 0;
 411                         if (strcmp(nconf->nc_netid, "udp6") == 0) {
 412                                 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
 413                                     IPV6_RECVPKTINFO, 1);
 414                                 if (ret < 0) {
 415                                         char errorstr[100];
 416 
 417                                         __tli_sys_strerror(errorstr,
 418                                             sizeof (errorstr), t_errno, errno);
 419                                         (void) syslog(LOG_ERR,
 420                                             "svc_tli_create: "
 421                                             "IPV6_RECVPKTINFO(2): %s",
 422                                             errorstr);
 423                                         goto freedata;
 424                                 }
 425                         } else if (strcmp(nconf->nc_netid, "udp") == 0) {




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.

  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T */
  28 /*      All Rights Reserved   */
  29 
  30 /*
  31  * svc_generic.c, Server side for RPC.
  32  *
  33  */
  34 
  35 #include "mt.h"
  36 #include <stdlib.h>
  37 #include <sys/socket.h>
  38 #include <netinet/in.h>
  39 #include <netinet/tcp.h>
  40 #include <netinet/udp.h>
  41 #include <inttypes.h>
  42 #include "rpc_mt.h"
  43 #include <stdio.h>
  44 #include <rpc/rpc.h>


  70 extern bool_t __rpc_try_doors(const char *, bool_t *);
  71 
  72 /*
  73  * The highest level interface for server creation.
  74  * It tries for all the nettokens in that particular class of token
  75  * and returns the number of handles it can create and/or find.
  76  *
  77  * It creates a link list of all the handles it could create.
  78  * If svc_create() is called multiple times, it uses the handle
  79  * created earlier instead of creating a new handle every time.
  80  */
  81 
  82 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
  83 
  84 SVCXPRT_LIST *_svc_xprtlist = NULL;
  85 extern mutex_t xprtlist_lock;
  86 
  87 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
  88     const struct t_bind *, uint_t, uint_t, boolean_t);
  89 
  90 static SVCXPRT *svc_tp_create_bind(void (*dispatch)(),
  91     const rpcprog_t, const rpcvers_t,
  92     const struct netconfig *, const struct t_bind *);
  93 
  94 boolean_t
  95 is_multilevel(rpcprog_t prognum)
  96 {
  97         /* This is a list of identified multilevel service provider */
  98         if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
  99             (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
 100             (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
 101             (prognum == SM_PROG))
 102                 return (B_TRUE);
 103 
 104         return (B_FALSE);
 105 }
 106 
 107 void
 108 __svc_free_xprtlist(void)
 109 {
 110         __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
 111 }
 112 
 113 int


 163                                     &xprtlist_lock)) {
 164                                         (void) syslog(LOG_ERR,
 165                                             "svc_create: no memory");
 166                                         return (0);
 167                                 }
 168                                 num++;
 169                         }
 170                 }
 171         }
 172         __rpc_endconf(handle);
 173         /*
 174          * In case of num == 0; the error messages are generated by the
 175          * underlying layers; and hence not needed here.
 176          */
 177         return (num);
 178 }
 179 
 180 /*
 181  * The high level interface to svc_tli_create().
 182  * It tries to create a server for "nconf" and registers the service
 183  * with the rpcbind.
 184  */
 185 SVCXPRT *
 186 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
 187     const rpcvers_t versnum, const struct netconfig *nconf)
 188 {
 189         return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL));
 190 }
 191 
 192 /*
 193  * svc_tp_create_addr()
 194  * Variant of svc_tp_create() that allows specifying just the
 195  * the binding address, for convenience.
 196  */
 197 SVCXPRT *
 198 svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum,
 199     const rpcvers_t versnum, const struct netconfig *nconf,
 200     const struct netbuf *addr)
 201 {
 202         struct t_bind bind;
 203         struct t_bind *bindp = NULL;
 204 
 205         if (addr != NULL) {
 206 
 207                 bind.addr = *addr;
 208                 if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) {
 209                         syslog(LOG_ERR,
 210                             "svc_tp_create: can't get listen backlog");
 211                         return (NULL);
 212                 }
 213                 bindp = &bind;
 214         }
 215 
 216         /*
 217          * When bindp == NULL, this is the same as svc_tp_create().
 218          */
 219         return (svc_tp_create_bind(dispatch, prognum, versnum,
 220             nconf, bindp));
 221 }
 222 
 223 static SVCXPRT *
 224 svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum,
 225     const rpcvers_t versnum, const struct netconfig *nconf,
 226     const struct t_bind *bindaddr)
 227 {
 228         SVCXPRT *xprt;
 229         boolean_t anon_mlp = B_FALSE;
 230 
 231         if (nconf == NULL) {
 232                 (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
 233                     "structure for prog %d vers %d", prognum, versnum);
 234                 return (NULL);
 235         }
 236 
 237         /* Some programs need to allocate MLP for multilevel services */
 238         if (is_system_labeled() && is_multilevel(prognum))
 239                 anon_mlp = B_TRUE;
 240         xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
 241             anon_mlp);
 242         if (xprt == NULL)
 243                 return (NULL);
 244 
 245         (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
 246         if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
 247                 (void) syslog(LOG_ERR,
 248                     "svc_tp_create: Could not register prog %d vers %d on %s",
 249                     prognum, versnum, nconf->nc_netid);
 250                 SVC_DESTROY(xprt);
 251                 return (NULL);
 252         }
 253         return (xprt);
 254 }
 255 
 256 SVCXPRT *
 257 svc_tli_create(const int fd, const struct netconfig *nconf,
 258     const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
 259 {
 260         return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
 261 }


 351                                             "svc_tli_create: "
 352                                             "IP_RECVDSTADDR(1): %s", errorstr);
 353                                         return (NULL);
 354                                 }
 355                         }
 356                 }
 357         }
 358 
 359         /*
 360          * If the fd is unbound, try to bind it.
 361          * In any case, try to get its bound info in tres
 362          */
 363 /* LINTED pointer alignment */
 364         tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
 365         if (tres == NULL) {
 366                 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
 367                 goto freedata;
 368         }
 369 
 370         switch (state) {

 371         case T_UNBND:
 372                 /* If this is a labeled system, then ask for an MLP */
 373                 if (is_system_labeled() &&
 374                     (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
 375                     strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
 376                         (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 377                             SO_RECVUCRED, 1);
 378                         if (mlp_flag)
 379                                 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 380                                     SO_ANON_MLP, 1);
 381                 }
 382 
 383                 if (bindaddr) {
 384                         /*
 385                          * Services that specify a bind address typically
 386                          * use a fixed service (IP port) so we need to set
 387                          * SO_REUSEADDR to prevent bind errors on restart.






 388                          */
 389                         if (bindaddr->addr.len != 0)
 390                                 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 391                                     SO_REUSEADDR, 1);












 392                         if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
 393                                 char errorstr[100];
 394 
 395                                 __tli_sys_strerror(errorstr, sizeof (errorstr),
 396                                     t_errno, errno);
 397                                 (void) syslog(LOG_ERR,
 398                                     "svc_tli_create: could not bind: %s",
 399                                     errorstr);
 400                                 goto freedata;
 401                         }
 402                         /*
 403                          * Should compare the addresses only if addr.len
 404                          * was non-zero
 405                          */
 406                         if (bindaddr->addr.len &&
 407                             (memcmp(bindaddr->addr.buf, tres->addr.buf,
 408                             (int)tres->addr.len) != 0)) {
 409                                 (void) syslog(LOG_ERR, "svc_tli_create: could "
 410                                     "not bind to requested address: address "
 411                                     "mismatch");
 412                                 goto freedata;
 413                         }
 414                 } else {
 415                         if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
 416                             == FALSE) {
 417                                 syslog(LOG_ERR,
 418                                     "svc_tli_create: can't get listen backlog");
 419                                 goto freedata;
 420                         }
 421                         tres->addr.len = 0;
 422                         if (t_bind(fd, tres, tres) == -1) {
 423                                 char errorstr[100];
 424 
 425                                 __tli_sys_strerror(errorstr, sizeof (errorstr),
 426                                     t_errno, errno);
 427                                 (void) syslog(LOG_ERR,
 428                                     "svc_tli_create: could not bind: %s",
 429                                     errorstr);
 430                                 goto freedata;
 431                         }
 432                 }
 433 
 434                 /*
 435                  * If requested, set SO_EXCLBIND on each binding.
 436                  *
 437                  * SO_EXCLBIND has the following properties
 438                  *    - an fd bound to port P via IPv4 will prevent an IPv6
 439                  *    bind to port P (and vice versa)
 440                  *    - an fd bound to a wildcard IP address for port P will
 441                  *    prevent a more specific IP address bind to port P
 442                  *    (see {tcp,udp}.c for details)
 443                  *
 444                  * We use the latter property to prevent hijacking of RPC
 445                  * services that reside at non-privileged ports.
 446                  *
 447                  * When the bind address is not specified, each bind gets a
 448                  * new port number, and (for IP transports) we should set
 449                  * the exclusive flag after every IP bind.  That's the
 450                  * strcmp nc_proto part of the expression below.
 451                  *
 452                  * When the bind address IS specified, we need to set the
 453                  * exclusive flag only after we've bound both IPv6+IPv4,
 454                  * or the IPv4 bind will fail.  Setting the exclusive flag
 455                  * after the "tcp" or "udp" transport bind does that.
 456                  * That's the strcmp nc_netid part below.
 457                  */
 458                 if (nconf != NULL && ((bindaddr == NULL &&
 459                     (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
 460                     strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
 461                     (strcmp(nconf->nc_netid, "tcp") == 0 ||
 462                     strcmp(nconf->nc_netid, "udp") == 0))) {
 463                         bool_t exclbind = FALSE;
 464                         (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind);
 465                         if (exclbind &&
 466                             __rpc_tli_set_options(fd, SOL_SOCKET,
 467                             SO_EXCLBIND, 1) < 0) {
 468                                 syslog(LOG_ERR,
 469                             "svc_tli_create: can't set EXCLBIND [netid='%s']",
 470                                     nconf->nc_netid);
 471                                 goto freedata;
 472                         }
 473                 }
 474 
 475                 /* Enable options of returning the ip's for udp */
 476                 if (nconf) {
 477                         int ret = 0;
 478                         if (strcmp(nconf->nc_netid, "udp6") == 0) {
 479                                 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
 480                                     IPV6_RECVPKTINFO, 1);
 481                                 if (ret < 0) {
 482                                         char errorstr[100];
 483 
 484                                         __tli_sys_strerror(errorstr,
 485                                             sizeof (errorstr), t_errno, errno);
 486                                         (void) syslog(LOG_ERR,
 487                                             "svc_tli_create: "
 488                                             "IPV6_RECVPKTINFO(2): %s",
 489                                             errorstr);
 490                                         goto freedata;
 491                                 }
 492                         } else if (strcmp(nconf->nc_netid, "udp") == 0) {