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>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libnsl/rpc/svc_generic.c
          +++ new/usr/src/lib/libnsl/rpc/svc_generic.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
       23 + * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  23   24   * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25   25   */
  26   26  
  27   27  /*      Copyright (c) 1988 AT&T */
  28   28  /*      All Rights Reserved   */
  29   29  
  30   30  /*
  31   31   * svc_generic.c, Server side for RPC.
  32   32   *
  33   33   */
  34   34  
↓ open down ↓ 45 lines elided ↑ open up ↑
  80   80   */
  81   81  
  82   82  /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
  83   83  
  84   84  SVCXPRT_LIST *_svc_xprtlist = NULL;
  85   85  extern mutex_t xprtlist_lock;
  86   86  
  87   87  static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
  88   88      const struct t_bind *, uint_t, uint_t, boolean_t);
  89   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 +
  90   94  boolean_t
  91   95  is_multilevel(rpcprog_t prognum)
  92   96  {
  93   97          /* This is a list of identified multilevel service provider */
  94   98          if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
  95   99              (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
  96  100              (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
  97  101              (prognum == SM_PROG))
  98  102                  return (B_TRUE);
  99  103  
↓ open down ↓ 69 lines elided ↑ open up ↑
 169  173          /*
 170  174           * In case of num == 0; the error messages are generated by the
 171  175           * underlying layers; and hence not needed here.
 172  176           */
 173  177          return (num);
 174  178  }
 175  179  
 176  180  /*
 177  181   * The high level interface to svc_tli_create().
 178  182   * It tries to create a server for "nconf" and registers the service
 179      - * with the rpcbind. It calls svc_tli_create();
      183 + * with the rpcbind.
 180  184   */
 181  185  SVCXPRT *
 182  186  svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
 183      -                        const rpcvers_t versnum, const struct netconfig *nconf)
      187 +    const rpcvers_t versnum, const struct netconfig *nconf)
 184  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 +{
 185  228          SVCXPRT *xprt;
 186  229          boolean_t anon_mlp = B_FALSE;
 187  230  
 188  231          if (nconf == NULL) {
 189  232                  (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
 190  233                      "structure for prog %d vers %d", prognum, versnum);
 191  234                  return (NULL);
 192  235          }
 193  236  
 194  237          /* Some programs need to allocate MLP for multilevel services */
 195  238          if (is_system_labeled() && is_multilevel(prognum))
 196  239                  anon_mlp = B_TRUE;
 197      -        xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);
      240 +        xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
      241 +            anon_mlp);
 198  242          if (xprt == NULL)
 199  243                  return (NULL);
 200  244  
 201  245          (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
 202  246          if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
 203  247                  (void) syslog(LOG_ERR,
 204  248                      "svc_tp_create: Could not register prog %d vers %d on %s",
 205  249                      prognum, versnum, nconf->nc_netid);
 206  250                  SVC_DESTROY(xprt);
 207  251                  return (NULL);
↓ open down ↓ 109 lines elided ↑ open up ↑
 317  361           * In any case, try to get its bound info in tres
 318  362           */
 319  363  /* LINTED pointer alignment */
 320  364          tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
 321  365          if (tres == NULL) {
 322  366                  (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
 323  367                  goto freedata;
 324  368          }
 325  369  
 326  370          switch (state) {
 327      -                bool_t tcp, exclbind;
 328  371          case T_UNBND:
 329  372                  /* If this is a labeled system, then ask for an MLP */
 330  373                  if (is_system_labeled() &&
 331  374                      (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
 332  375                      strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
 333  376                          (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 334  377                              SO_RECVUCRED, 1);
 335  378                          if (mlp_flag)
 336  379                                  (void) __rpc_tli_set_options(fd, SOL_SOCKET,
 337  380                                      SO_ANON_MLP, 1);
 338  381                  }
 339  382  
 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  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);
 366  392                          if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
 367  393                                  char errorstr[100];
 368  394  
 369  395                                  __tli_sys_strerror(errorstr, sizeof (errorstr),
 370  396                                      t_errno, errno);
 371  397                                  (void) syslog(LOG_ERR,
 372  398                                      "svc_tli_create: could not bind: %s",
 373  399                                      errorstr);
 374  400                                  goto freedata;
 375  401                          }
↓ open down ↓ 20 lines elided ↑ open up ↑
 396  422                          if (t_bind(fd, tres, tres) == -1) {
 397  423                                  char errorstr[100];
 398  424  
 399  425                                  __tli_sys_strerror(errorstr, sizeof (errorstr),
 400  426                                      t_errno, errno);
 401  427                                  (void) syslog(LOG_ERR,
 402  428                                      "svc_tli_create: could not bind: %s",
 403  429                                      errorstr);
 404  430                                  goto freedata;
 405  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 +                        }
 406  473                  }
 407  474  
 408  475                  /* Enable options of returning the ip's for udp */
 409  476                  if (nconf) {
 410  477                          int ret = 0;
 411  478                          if (strcmp(nconf->nc_netid, "udp6") == 0) {
 412  479                                  ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
 413  480                                      IPV6_RECVPKTINFO, 1);
 414  481                                  if (ret < 0) {
 415  482                                          char errorstr[100];
↓ open down ↓ 157 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX