Print this page
    
OS-2837 lx brand only works with shared IP stacks
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
          +++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  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   23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2014, Joyent, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * Main door handler functions used by ipmgmtd to process the different door
  28   29   * call requests, issued by the library libipadm.so.
  29   30   */
  30   31  
  31   32  #include <alloca.h>
  32   33  #include <pwd.h>
  33   34  #include <auth_attr.h>
  34   35  #include <secdb.h>
  35   36  #include <stdlib.h>
  36   37  #include <stdio.h>
  37   38  #include <string.h>
  38   39  #include <strings.h>
  39   40  #include <errno.h>
  40   41  #include <assert.h>
  41   42  #include <libnvpair.h>
  42   43  #include "ipmgmt_impl.h"
  43   44  
  44   45  /* Handler declaration for each door command */
  45   46  typedef void ipmgmt_door_handler_t(void *argp);
  46   47  
  47   48  static ipmgmt_door_handler_t    ipmgmt_getaddr_handler,
  48   49                                  ipmgmt_getprop_handler,
  49   50                                  ipmgmt_getif_handler,
  50   51                                  ipmgmt_initif_handler,
  51   52                                  ipmgmt_aobjop_handler,
  52   53                                  ipmgmt_resetaddr_handler,
  53   54                                  ipmgmt_setif_handler,
  54   55                                  ipmgmt_resetif_handler,
  55   56                                  ipmgmt_resetprop_handler,
  56   57                                  ipmgmt_setaddr_handler,
  57   58                                  ipmgmt_setprop_handler;
  58   59  
  59   60  typedef struct ipmgmt_door_info_s {
  60   61          uint_t                  idi_cmd;
  61   62          boolean_t               idi_set;
  62   63          ipmgmt_door_handler_t   *idi_handler;
  63   64  } ipmgmt_door_info_t;
  64   65  
  65   66  /* maps door commands to door handler functions */
  66   67  static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
  67   68          { IPMGMT_CMD_SETPROP,           B_TRUE,  ipmgmt_setprop_handler },
  68   69          { IPMGMT_CMD_SETIF,             B_TRUE,  ipmgmt_setif_handler },
  69   70          { IPMGMT_CMD_SETADDR,           B_TRUE,  ipmgmt_setaddr_handler },
  70   71          { IPMGMT_CMD_GETPROP,           B_FALSE, ipmgmt_getprop_handler },
  71   72          { IPMGMT_CMD_GETIF,             B_FALSE, ipmgmt_getif_handler },
  72   73          { IPMGMT_CMD_GETADDR,           B_FALSE, ipmgmt_getaddr_handler },
  73   74          { IPMGMT_CMD_RESETIF,           B_TRUE,  ipmgmt_resetif_handler },
  74   75          { IPMGMT_CMD_RESETADDR,         B_TRUE,  ipmgmt_resetaddr_handler },
  75   76          { IPMGMT_CMD_RESETPROP,         B_TRUE,  ipmgmt_resetprop_handler },
  76   77          { IPMGMT_CMD_INITIF,            B_TRUE,  ipmgmt_initif_handler },
  77   78          { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE,  ipmgmt_aobjop_handler },
  78   79          { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE,  ipmgmt_aobjop_handler },
  79   80          { IPMGMT_CMD_ADDROBJ_ADD,       B_TRUE,  ipmgmt_aobjop_handler },
  80   81          { IPMGMT_CMD_AOBJNAME2ADDROBJ,  B_FALSE, ipmgmt_aobjop_handler },
  81   82          { IPMGMT_CMD_LIF2ADDROBJ,       B_FALSE, ipmgmt_aobjop_handler },
  82   83          { 0, 0, NULL },
  83   84  };
  84   85  
  85   86  /*
  86   87   * The main server procedure function that gets invoked for any of the incoming
  87   88   * door commands. Inside this function we identify the incoming command and
  88   89   * invoke the right door handler function.
  89   90   */
  90   91  /* ARGSUSED */
  91   92  void
  92   93  ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
  93   94      uint_t n_desc)
  94   95  {
  95   96          ipmgmt_door_info_t      *infop = NULL;
  96   97          ipmgmt_retval_t         retval;
  97   98          int                     i;
  98   99          uint_t                  err;
  99  100          ucred_t                 *cred = NULL;
 100  101  
 101  102          for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
 102  103                  if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
 103  104                      ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
 104  105                          infop = &i_ipmgmt_door_info_tbl[i];
  
    | 
      ↓ open down ↓ | 
    71 lines elided | 
    
      ↑ open up ↑ | 
  
 105  106                          break;
 106  107                  }
 107  108          }
 108  109  
 109  110          if (infop == NULL) {
 110  111                  ipmgmt_log(LOG_ERR, "Invalid door command specified");
 111  112                  err = EINVAL;
 112  113                  goto fail;
 113  114          }
 114  115  
 115      -        /* check for solaris.network.interface.config authorization */
      116 +        /*
      117 +         * if not root, check for solaris.network.interface.config authorization
      118 +         */
 116  119          if (infop->idi_set) {
 117  120                  uid_t           uid;
 118  121                  struct passwd   pwd;
 119  122                  char            buf[1024];
 120  123  
 121  124                  if (door_ucred(&cred) != 0) {
 122  125                          err = errno;
 123  126                          ipmgmt_log(LOG_ERR, "Could not get user credentials.");
 124  127                          goto fail;
 125  128                  }
 126  129                  uid = ucred_getruid(cred);
      130 +                ucred_free(cred);
 127  131                  if ((int)uid < 0) {
 128  132                          err = errno;
 129  133                          ipmgmt_log(LOG_ERR, "Could not get user id.");
 130  134                          goto fail;
 131  135                  }
 132      -                if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
 133      -                    NULL) {
 134      -                        err = errno;
 135      -                        ipmgmt_log(LOG_ERR, "Could not get password entry.");
 136      -                        goto fail;
      136 +
      137 +                /*
      138 +                 * Branded zones may have different auth, but root always
      139 +                 * allowed.
      140 +                 */
      141 +                if (uid != 0) {
      142 +                        if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
      143 +                                err = errno;
      144 +                                ipmgmt_log(LOG_ERR,
      145 +                                    "Could not get password entry.");
      146 +                                goto fail;
      147 +                        }
      148 +                        if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
      149 +                            pwd.pw_name) != 1) {
      150 +                                err = EPERM;
      151 +                                ipmgmt_log(LOG_ERR,
      152 +                                    "Not authorized for operation.");
      153 +                                goto fail;
      154 +                        }
 137  155                  }
 138      -                if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
 139      -                    pwd.pw_name) != 1) {
 140      -                        err = EPERM;
 141      -                        ipmgmt_log(LOG_ERR, "Not authorized for operation.");
 142      -                        goto fail;
 143      -                }
 144      -                ucred_free(cred);
 145  156          }
 146  157  
 147  158          /* individual handlers take care of calling door_return */
 148  159          infop->idi_handler((void *)argp);
 149  160          return;
 150  161  fail:
 151  162          ucred_free(cred);
 152  163          retval.ir_err = err;
 153  164          (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
 154  165  }
 155  166  
 156  167  /*
 157  168   * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
 158  169   * property value for the given property.
 159  170   */
 160  171  static void
 161  172  ipmgmt_getprop_handler(void *argp)
 162  173  {
 163  174          ipmgmt_prop_arg_t       *pargp = argp;
 164  175          ipmgmt_getprop_rval_t   rval, *rvalp = &rval;
 165  176  
 166  177          assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
 167  178  
 168  179          rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
 169  180          if (rvalp->ir_err == 0)
 170  181                  (void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
 171  182                      sizeof (rvalp->ir_pval));
 172  183          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 173  184  }
 174  185  
 175  186  /*
 176  187   * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
 177  188   * for the given property in the DB.
 178  189   */
 179  190  static void
 180  191  ipmgmt_setprop_handler(void *argp)
 181  192  {
 182  193          ipmgmt_prop_arg_t       *pargp = argp;
 183  194          ipmgmt_retval_t         rval;
 184  195          ipadm_dbwrite_cbarg_t   cb;
 185  196          nvlist_t                *nvl = NULL;
 186  197          int                     err;
 187  198  
 188  199          assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
 189  200  
 190  201          if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
 191  202                  goto fail;
 192  203          if (pargp->ia_module[0] != '\0' &&
 193  204              (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
 194  205              pargp->ia_module)) != 0) {
 195  206                  goto fail;
 196  207          }
 197  208          if (pargp->ia_ifname[0] != '\0' &&
 198  209              (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
 199  210              pargp->ia_ifname)) != 0)
 200  211                  goto fail;
 201  212          if (pargp->ia_aobjname[0] != '\0' &&
 202  213              (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
 203  214              pargp->ia_aobjname)) != 0)
 204  215                  goto fail;
 205  216          if ((err = nvlist_add_string(nvl, pargp->ia_pname,
 206  217              pargp->ia_pval)) != 0)
 207  218                  goto fail;
 208  219  
 209  220          cb.dbw_nvl = nvl;
 210  221          cb.dbw_flags = pargp->ia_flags;
 211  222          err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
 212  223  fail:
 213  224          nvlist_free(nvl);
 214  225          rval.ir_err = err;
 215  226          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 216  227  }
 217  228  
 218  229  /*
 219  230   * Helper function for ipmgmt_setaddr_handler().
 220  231   * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
 221  232   */
 222  233  static int
 223  234  i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
 224  235  {
 225  236          char                    *aobjname = NULL, *ifname = NULL;
 226  237          int32_t                 lnum;
 227  238          nvlist_t                *nvladdr;
 228  239          struct sockaddr_storage addr;
 229  240          uint_t                  n;
 230  241          sa_family_t             af = AF_UNSPEC;
 231  242          ipadm_addr_type_t       addrtype = IPADM_ADDR_NONE;
 232  243          int                     err = 0;
 233  244  
 234  245          /*
 235  246           * Retrieve all the information needed to build '*nodep' from
 236  247           * nvlist_t nvl.
 237  248           */
 238  249          if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 239  250              &aobjname)) != 0 ||
 240  251              (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
 241  252              (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
 242  253                  return (err);
 243  254          }
 244  255          if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
 245  256                  af = AF_INET;
 246  257                  addrtype = IPADM_ADDR_STATIC;
 247  258          } else if (nvlist_exists(nvl, IPADM_NVP_DHCP)) {
 248  259                  af = AF_INET;
 249  260                  addrtype = IPADM_ADDR_DHCP;
 250  261          } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
 251  262                  af = AF_INET6;
 252  263                  addrtype = IPADM_ADDR_STATIC;
 253  264          } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
 254  265                  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
 255  266                  uint8_t *addr6;
 256  267                  uint32_t plen;
 257  268  
 258  269                  af = AF_INET6;
 259  270                  addrtype = IPADM_ADDR_IPV6_ADDRCONF;
 260  271                  if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
 261  272                      &plen) != 0)
 262  273                          return (EINVAL);
 263  274                  if (plen != 0) {
 264  275                          if (nvlist_lookup_uint8_array(nvladdr,
 265  276                              IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
 266  277                                  return (EINVAL);
 267  278                          bcopy(addr6, &sin6->sin6_addr, n);
 268  279                  } else {
 269  280                          bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
 270  281                  }
 271  282          }
 272  283  
 273  284          /*
 274  285           * populate the `*nodep' with retrieved values.
 275  286           */
 276  287          (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
 277  288          (void) strlcpy(nodep->am_aobjname, aobjname,
 278  289              sizeof (nodep->am_aobjname));
 279  290          nodep->am_lnum = lnum;
 280  291          nodep->am_family = af;
 281  292          nodep->am_atype = addrtype;
 282  293          if (addrtype == IPADM_ADDR_IPV6_ADDRCONF) {
 283  294                  nodep->am_linklocal = B_TRUE;
 284  295                  nodep->am_ifid = addr;
 285  296          }
 286  297          nodep->am_next = NULL;
 287  298  
 288  299          /*
 289  300           * Do not store logical interface number in persistent store as it
 290  301           * takes different value on reboot. So remove it from `nvl'.
 291  302           */
 292  303          if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
 293  304                  (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
 294  305  
 295  306          return (0);
 296  307  }
 297  308  
 298  309  /*
 299  310   * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
 300  311   * node to the list `aobjmap' and then persists the address information in the
 301  312   * DB.
 302  313   */
 303  314  static void
 304  315  ipmgmt_setaddr_handler(void *argp)
 305  316  {
 306  317          ipmgmt_setaddr_arg_t    *sargp = argp;
 307  318          ipmgmt_retval_t         rval;
 308  319          ipmgmt_aobjmap_t        node;
 309  320          nvlist_t                *nvl = NULL;
 310  321          char                    *nvlbuf;
 311  322          size_t                  nvlsize = sargp->ia_nvlsize;
 312  323          uint32_t                flags = sargp->ia_flags;
 313  324          int                     err = 0;
 314  325  
 315  326          nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
 316  327          if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
 317  328                  goto ret;
 318  329          if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
 319  330                  if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
 320  331                          goto ret;
 321  332                  if (flags & IPMGMT_INIT)
 322  333                          node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
 323  334                  else
 324  335                          node.am_flags = flags;
 325  336                  if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
 326  337                          goto ret;
 327  338          }
 328  339          if (flags & IPMGMT_PERSIST) {
 329  340                  ipadm_dbwrite_cbarg_t   cb;
 330  341  
 331  342                  cb.dbw_nvl = nvl;
 332  343                  cb.dbw_flags = 0;
 333  344                  err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
 334  345          }
 335  346  ret:
 336  347          nvlist_free(nvl);
 337  348          rval.ir_err = err;
 338  349          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 339  350  }
 340  351  
 341  352  /*
 342  353   * Handles the door commands that modify the `aobjmap' structure.
 343  354   *
 344  355   * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
 345  356   *      after ensuring that the namespace is not taken. If required, also
 346  357   *      generates an `aobjname' for address object for the library to use.
 347  358   * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
 348  359   * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
 349  360   *      associated with that logical interface.
 350  361   * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
 351  362   *      interface associated with that address object.
 352  363   */
 353  364  static void
 354  365  ipmgmt_aobjop_handler(void *argp)
 355  366  {
 356  367          ipmgmt_aobjop_arg_t     *largp = argp;
 357  368          ipmgmt_retval_t         rval;
 358  369          ipmgmt_aobjop_rval_t    aobjrval;
 359  370          void                    *rvalp;
 360  371          size_t                  rsize;
 361  372          ipmgmt_aobjmap_t        node;
 362  373          int                     err = 0;
 363  374          char                    *ifname = largp->ia_ifname;
 364  375          char                    *aobjname = largp->ia_aobjname;
 365  376          int32_t                 lnum = largp->ia_lnum;
 366  377          sa_family_t             af = largp->ia_family;
 367  378          ipadm_addr_type_t       atype = largp->ia_atype;
 368  379          ipmgmt_aobjmap_t        *head;
 369  380  
 370  381          switch (largp->ia_cmd) {
 371  382          case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
 372  383                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 373  384                  rvalp = &aobjrval;
 374  385                  bzero(&node, sizeof (node));
 375  386                  (void) strlcpy(node.am_aobjname, aobjname,
 376  387                      sizeof (node.am_aobjname));
 377  388                  (void) strlcpy(node.am_ifname, ifname,
 378  389                      sizeof (node.am_ifname));
 379  390                  node.am_family = af;
 380  391                  node.am_atype = atype;
 381  392                  /* no logical number is associated with this addrobj yet */
 382  393                  node.am_lnum = -1;
 383  394                  /* The address object is not persisted yet. */
 384  395                  node.am_flags = IPMGMT_ACTIVE;
 385  396                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
 386  397                  if (err == 0) {
 387  398                          (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
 388  399                              sizeof (aobjrval.ir_aobjname));
 389  400                  }
 390  401                  break;
 391  402          case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
 392  403                  rsize = sizeof (ipmgmt_retval_t);
 393  404                  rvalp = &rval;
 394  405                  bzero(&node, sizeof (node));
 395  406                  (void) strlcpy(node.am_aobjname, aobjname,
 396  407                      sizeof (node.am_aobjname));
 397  408                  (void) strlcpy(node.am_ifname, ifname,
 398  409                      sizeof (node.am_ifname));
 399  410                  node.am_family = af;
 400  411                  node.am_lnum = lnum;
 401  412                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
 402  413                  break;
 403  414          case IPMGMT_CMD_ADDROBJ_ADD:
 404  415                  rsize = sizeof (ipmgmt_retval_t);
 405  416                  rvalp = &rval;
 406  417                  if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
 407  418                      af == AF_UNSPEC) {
 408  419                          err = EINVAL;
 409  420                          break;
 410  421                  }
 411  422                  bzero(&node, sizeof (node));
 412  423                  (void) strlcpy(node.am_aobjname, aobjname,
 413  424                      sizeof (node.am_aobjname));
 414  425                  (void) strlcpy(node.am_ifname, ifname,
 415  426                      sizeof (node.am_ifname));
 416  427                  node.am_atype = atype;
 417  428                  node.am_lnum = lnum;
 418  429                  node.am_family = af;
 419  430                  /* The address object is not persisted. */
 420  431                  node.am_flags = IPMGMT_ACTIVE;
 421  432                  err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
 422  433                  break;
 423  434          case IPMGMT_CMD_AOBJNAME2ADDROBJ:
 424  435                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 425  436                  rvalp = &aobjrval;
 426  437                  bzero(&aobjrval, sizeof (aobjrval));
 427  438                  if (aobjname[0] == '\0') {
 428  439                          err = EINVAL;
 429  440                          break;
 430  441                  }
 431  442                  (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
 432  443                  head = aobjmap.aobjmap_head;
 433  444                  for (; head; head = head->am_next) {
 434  445                          if (strcmp(head->am_aobjname, aobjname) != 0)
 435  446                                  continue;
 436  447                          /*
 437  448                           * For an auto-configured interface, return
 438  449                           * the lifnum that has the link-local on it.
 439  450                           * Other logical interfaces were created for
 440  451                           * prefixes and dhcpv6 addresses and do not
 441  452                           * have am_ifid set.
 442  453                           */
 443  454                          if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
 444  455                              head->am_linklocal) {
 445  456                                  break;
 446  457                          }
 447  458                  }
 448  459                  if (head == NULL) {
 449  460                          err = ENOENT;
 450  461                          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 451  462                          break;
 452  463                  }
 453  464                  (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
 454  465                      sizeof (aobjrval.ir_ifname));
 455  466                  aobjrval.ir_lnum = head->am_lnum;
 456  467                  aobjrval.ir_family = head->am_family;
 457  468                  aobjrval.ir_flags = head->am_flags;
 458  469                  aobjrval.ir_atype = head->am_atype;
 459  470                  if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF &&
 460  471                      head->am_linklocal)
 461  472                          aobjrval.ir_ifid = head->am_ifid;
 462  473                  (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 463  474                  break;
 464  475          case IPMGMT_CMD_LIF2ADDROBJ:
 465  476                  rsize = sizeof (ipmgmt_aobjop_rval_t);
 466  477                  rvalp = &aobjrval;
 467  478                  bzero(&aobjrval, sizeof (aobjrval));
 468  479                  if (ifname[0] == '\0') {
 469  480                          err = EINVAL;
 470  481                          break;
 471  482                  }
 472  483                  (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
 473  484                  head = aobjmap.aobjmap_head;
 474  485                  for (; head; head = head->am_next) {
 475  486                          if (strcmp(head->am_ifname, ifname) == 0 &&
 476  487                              head->am_lnum == lnum &&
 477  488                              head->am_family == af) {
 478  489                                  break;
 479  490                          }
 480  491                  }
 481  492                  if (head == NULL) {
 482  493                          err = ENOENT;
 483  494                          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 484  495                          break;
 485  496                  }
 486  497                  (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
 487  498                      sizeof (aobjrval.ir_aobjname));
 488  499                  aobjrval.ir_atype = head->am_atype;
 489  500                  aobjrval.ir_flags = head->am_flags;
 490  501                  (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 491  502                  break;
 492  503          default:
 493  504                  rsize = sizeof (ipmgmt_retval_t);
 494  505                  rvalp = &rval;
 495  506                  err = EINVAL;
 496  507          }
 497  508          ((ipmgmt_retval_t *)rvalp)->ir_err = err;
 498  509          (void) door_return((char *)rvalp, rsize, NULL, 0);
 499  510  }
 500  511  
 501  512  /*
 502  513   * Given an interface name and family, deletes all the address objects
 503  514   * associated with it.
 504  515   */
 505  516  void
 506  517  i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
 507  518  {
 508  519          ipmgmt_aobjmap_t        *head, *next, *prev;
 509  520          ipadm_db_op_t           db_op;
 510  521  
 511  522          prev = NULL;
 512  523  
 513  524          (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
 514  525          head = aobjmap.aobjmap_head;
 515  526          for (; head; head = next) {
 516  527                  next = head->am_next;
 517  528                  if (strcmp(head->am_ifname, ifname) != 0 ||
 518  529                      head->am_family != af) {
 519  530                          prev = head;
 520  531                          continue;
 521  532                  }
 522  533  
 523  534                  if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
 524  535                      flags == IPMGMT_ACTIVE) {
 525  536                          /*
 526  537                           * If the addres is present in both active and
 527  538                           * persistent store, and if we are performing
 528  539                           * a temporary delete, we update the node to
 529  540                           * indicate that the address is only present in
 530  541                           * persistent store and we proceed. Otherwise
 531  542                           * we always delete the node from aobjmap.
 532  543                           */
 533  544                          head->am_flags &= ~IPMGMT_ACTIVE;
 534  545                          head->am_lnum = -1;
 535  546                          db_op = IPADM_DB_WRITE;
 536  547                  } else {
 537  548                          db_op = IPADM_DB_DELETE;
 538  549                          if (prev == NULL)
 539  550                                  aobjmap.aobjmap_head = next;
 540  551                          else
 541  552                                  prev->am_next = next;
 542  553                  }
 543  554                  (void) ipmgmt_persist_aobjmap(head, db_op);
 544  555                  if (db_op == IPADM_DB_DELETE)
 545  556                          free(head);
 546  557          }
 547  558          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
 548  559  }
 549  560  
 550  561  /*
 551  562   * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
 552  563   * information in the DB.
 553  564   */
 554  565  static void
 555  566  ipmgmt_setif_handler(void *argp)
 556  567  {
 557  568          ipmgmt_retval_t         rval;
 558  569  
 559  570          rval.ir_err = ipmgmt_persist_if(argp);
 560  571          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 561  572  }
 562  573  
 563  574  /*
 564  575   * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
 565  576   * deletes all the persisted interface configuration. It also deletes, from
 566  577   * `aobjmap', all the address objects configured on the given interface.
 567  578   */
 568  579  static void
 569  580  ipmgmt_resetif_handler(void *argp)
 570  581  {
 571  582          ipmgmt_if_arg_t         *rargp = argp;
 572  583          ipmgmt_retval_t         rval;
 573  584          ipmgmt_if_cbarg_t       cbarg;
 574  585          uint32_t                flags = rargp->ia_flags;
 575  586          int                     err = 0;
 576  587  
 577  588          cbarg.cb_family = rargp->ia_family;
 578  589          cbarg.cb_ifname = rargp->ia_ifname;
 579  590          if (flags & IPMGMT_PERSIST)
 580  591                  err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
 581  592                      IPADM_DB_DELETE);
 582  593  
 583  594          if (flags & IPMGMT_ACTIVE)
 584  595                  i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
 585  596                      flags);
 586  597  
 587  598          rval.ir_err = err;
 588  599          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 589  600  }
 590  601  
 591  602  /*
 592  603   * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
 593  604   * deletes all the persisted addrobj configuration. It also deletes the
 594  605   * corresponding node, from `aobjmap'.
 595  606   */
 596  607  static void
 597  608  ipmgmt_resetaddr_handler(void *argp)
 598  609  {
 599  610          ipmgmt_addr_arg_t       *rargp = argp;
 600  611          ipmgmt_retval_t         rval;
 601  612          ipmgmt_aobjmap_t        node;
 602  613          uint32_t                flags = rargp->ia_flags;
 603  614          int                     err = 0;
 604  615          ipmgmt_resetaddr_cbarg_t cbarg;
 605  616  
 606  617          cbarg.cb_aobjname = rargp->ia_aobjname;
 607  618  
 608  619          if (flags & IPMGMT_PERSIST)
 609  620                  err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
 610  621                      IPADM_DB_DELETE);
 611  622  
 612  623          if (flags & IPMGMT_ACTIVE) {
 613  624                  bzero(&node, sizeof (node));
 614  625                  (void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
 615  626                      sizeof (node.am_aobjname));
 616  627  
 617  628                  /*
 618  629                   * am_lnum is used only for IPv6 autoconf case, since there
 619  630                   * can be multiple nodes with the same aobjname.
 620  631                   */
 621  632                  node.am_lnum = rargp->ia_lnum;
 622  633                  node.am_flags = flags;
 623  634                  (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
 624  635          }
 625  636  
 626  637          rval.ir_err = err;
 627  638          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 628  639  }
 629  640  
 630  641  /*
 631  642   * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
 632  643   * address for a given `gargp->ia_aobjname'. If it is not defined then it
 633  644   * retrieves all the addresses configured on `gargp->ia_ifname'. The
 634  645   * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
 635  646   * handler through library.
 636  647   */
 637  648  static void
 638  649  ipmgmt_getaddr_handler(void *argp)
 639  650  {
 640  651          size_t                  buflen, onvlsize;
 641  652          char                    *buf, *onvlbuf;
 642  653          ipmgmt_getaddr_arg_t    *gargp = argp;
 643  654          ipmgmt_getaddr_cbarg_t  cbarg;
 644  655          ipmgmt_get_rval_t       rval, *rvalp = &rval;
 645  656          int                     err = 0;
 646  657  
 647  658          cbarg.cb_ifname = gargp->ia_ifname;
 648  659          cbarg.cb_aobjname = gargp->ia_aobjname;
 649  660          cbarg.cb_ocnt = 0;
 650  661          if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
 651  662                  goto fail;
 652  663          err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
 653  664          if (err == ENOENT && cbarg.cb_ocnt > 0) {
 654  665                  /*
 655  666                   * If there is atleast one entry in the nvlist,
 656  667                   * do not return error.
 657  668                   */
 658  669                  err = 0;
 659  670          }
 660  671          if (err != 0)
 661  672                  goto fail;
 662  673  
 663  674          if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
 664  675              NV_ENCODE_NATIVE)) != 0) {
 665  676                  goto fail;
 666  677          }
 667  678          buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
 668  679          /*
 669  680           * We cannot use malloc() here because door_return never returns, and
 670  681           * memory allocated by malloc() would get leaked. Use alloca() instead.
 671  682           */
 672  683          buf = alloca(buflen);
 673  684          onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
 674  685          if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
 675  686              NV_ENCODE_NATIVE, 0)) != 0) {
 676  687                  goto fail;
 677  688          }
 678  689          nvlist_free(cbarg.cb_onvl);
 679  690          rvalp = (ipmgmt_get_rval_t *)(void *)buf;
 680  691          rvalp->ir_err = 0;
 681  692          rvalp->ir_nvlsize = onvlsize;
 682  693  
 683  694          (void) door_return(buf, buflen, NULL, 0);
 684  695          return;
 685  696  fail:
 686  697          nvlist_free(cbarg.cb_onvl);
 687  698          rvalp->ir_err = err;
 688  699          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 689  700  }
 690  701  
 691  702  /*
 692  703   * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
 693  704   * from the DB.
 694  705   */
 695  706  static void
 696  707  ipmgmt_resetprop_handler(void *argp)
 697  708  {
 698  709          ipmgmt_prop_arg_t       *pargp = argp;
 699  710          ipmgmt_retval_t         rval;
 700  711  
 701  712          assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
 702  713  
 703  714          rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
 704  715              IPADM_DB_DELETE);
 705  716          (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 706  717  }
 707  718  
 708  719  /*
 709  720   * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
 710  721   * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
 711  722   */
 712  723  static void
 713  724  ipmgmt_getif_handler(void *argp)
 714  725  {
 715  726          ipmgmt_getif_arg_t      *getif = argp;
 716  727          ipmgmt_getif_rval_t     *rvalp;
 717  728          ipmgmt_retval_t         rval;
 718  729          ipmgmt_getif_cbarg_t    cbarg;
 719  730          ipadm_if_info_t         *ifp, *rifp, *curifp;
 720  731          int                     i, err = 0, count = 0;
 721  732          size_t                  rbufsize;
 722  733  
 723  734          assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
 724  735  
 725  736          bzero(&cbarg, sizeof (cbarg));
 726  737          cbarg.cb_ifname = getif->ia_ifname;
 727  738          err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
 728  739          if (err == ENOENT && cbarg.cb_ifinfo) {
 729  740                  /*
 730  741                   * If there is atleast one entry in the nvlist,
 731  742                   * do not return error.
 732  743                   */
 733  744                  err = 0;
 734  745          }
 735  746          if (err != 0) {
 736  747                  rval.ir_err = err;
 737  748                  (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 738  749                  return;
 739  750          }
 740  751  
 741  752          /* allocate sufficient buffer to return the interface info */
 742  753          for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
 743  754                  ++count;
 744  755          rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
 745  756          rvalp = alloca(rbufsize);
 746  757          bzero(rvalp, rbufsize);
 747  758  
 748  759          rvalp->ir_ifcnt = count;
 749  760          rifp = rvalp->ir_ifinfo;
 750  761          ifp = cbarg.cb_ifinfo;
 751  762  
 752  763          /*
 753  764           * copy the interface info to buffer allocated on stack. The reason
 754  765           * we do this is to avoid memory leak, as door_return() would never
 755  766           * return
 756  767           */
 757  768          for (i = 0; i < count; i++) {
 758  769                  rifp = rvalp->ir_ifinfo + i;
 759  770                  (void) bcopy(ifp, rifp, sizeof (*rifp));
 760  771                  rifp->ifi_next = NULL;
 761  772                  curifp = ifp->ifi_next;
 762  773                  free(ifp);
 763  774                  ifp = curifp;
 764  775          }
 765  776          rvalp->ir_err = err;
 766  777          (void) door_return((char *)rvalp, rbufsize, NULL, 0);
 767  778  }
 768  779  
 769  780  /*
 770  781   * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
 771  782   * interface configuration (interface properties and addresses), for all those
 772  783   * interfaces that need to be initialized.
 773  784   */
 774  785  static void
 775  786  ipmgmt_initif_handler(void *argp)
 776  787  {
 777  788          ipmgmt_initif_arg_t     *initif = argp;
 778  789          size_t                  buflen, nvlsize;
 779  790          char                    *buf = NULL, *onvlbuf, *invlbuf;
 780  791          ipmgmt_get_rval_t       rval, *rvalp = &rval;
 781  792          ipmgmt_initif_cbarg_t   cbarg;
 782  793          int                     err;
 783  794  
 784  795          assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
 785  796  
 786  797          bzero(&cbarg, sizeof (cbarg));
 787  798          invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
 788  799          nvlsize = initif->ia_nvlsize;
 789  800          err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
 790  801          if (err != 0)
 791  802                  goto fail;
 792  803  
 793  804          cbarg.cb_family = initif->ia_family;
 794  805          if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
 795  806                  goto fail;
 796  807  
 797  808          err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
 798  809          if (err == ENOENT && cbarg.cb_ocnt > 0) {
 799  810                  /*
 800  811                   * If there is atleast one entry in the nvlist,
 801  812                   * do not return error.
 802  813                   */
 803  814                  err = 0;
 804  815          }
 805  816          if (err != 0)
 806  817                  goto fail;
 807  818  
 808  819          if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
 809  820                  goto fail;
 810  821          buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
 811  822          /*
 812  823           * We cannot use malloc() here because door_return never returns, and
 813  824           * memory allocated by malloc() would get leaked. Use alloca() instead.
 814  825           */
 815  826          buf = alloca(buflen);
 816  827          onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
 817  828          if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
 818  829              NV_ENCODE_NATIVE, 0)) != 0) {
 819  830                  goto fail;
 820  831          }
 821  832          nvlist_free(cbarg.cb_invl);
 822  833          nvlist_free(cbarg.cb_onvl);
 823  834          rvalp = (ipmgmt_get_rval_t *)(void *)buf;
 824  835          rvalp->ir_err = 0;
 825  836          rvalp->ir_nvlsize = nvlsize;
 826  837  
 827  838          (void) door_return(buf, buflen, NULL, 0);
 828  839          return;
 829  840  fail:
 830  841          nvlist_free(cbarg.cb_invl);
 831  842          nvlist_free(cbarg.cb_onvl);
 832  843          rvalp->ir_err = err;
 833  844          (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
 834  845  }
 835  846  
 836  847  int
 837  848  ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
 838  849  {
 839  850          ipadm_dbwrite_cbarg_t   cb;
 840  851          uint32_t                flags = sargp->ia_flags;
 841  852          nvlist_t                *nvl = NULL;
 842  853          int                     err = 0;
 843  854          char                    strval[IPMGMT_STRSIZE];
 844  855  
 845  856          if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
 846  857              sargp->ia_ifname[0] == '\0') {
 847  858                  err = EINVAL;
 848  859                  goto ret;
 849  860          }
 850  861          if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
 851  862                  goto ret;
 852  863          if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
 853  864              sargp->ia_ifname)) != 0)
 854  865                  goto ret;
 855  866          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
 856  867          if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
 857  868                  goto ret;
 858  869          cb.dbw_nvl = nvl;
 859  870          cb.dbw_flags = 0;
 860  871          err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
 861  872  ret:
 862  873          nvlist_free(nvl);
 863  874          return (err);
 864  875  }
  
    | 
      ↓ open down ↓ | 
    710 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX