1 /*
   2  * CDDL HEADER START
   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) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Nexenta Systems, Inc.
  25  * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  26  */
  27 
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <errno.h>
  32 #include <fcntl.h>
  33 #include <unistd.h>
  34 #include <stropts.h>
  35 #include <sys/sockio.h>
  36 #include <sys/types.h>
  37 #include <sys/stat.h>
  38 #include <sys/socket.h>
  39 #include <net/route.h>
  40 #include <netinet/in.h>
  41 #include <inet/ip.h>
  42 #include <arpa/inet.h>
  43 #include <libintl.h>
  44 #include <libdlpi.h>
  45 #include <libinetutil.h>
  46 #include <libdladm.h>
  47 #include <libdllink.h>
  48 #include <libdliptun.h>
  49 #include <strings.h>
  50 #include <zone.h>
  51 #include <ctype.h>
  52 #include <limits.h>
  53 #include <assert.h>
  54 #include <netdb.h>
  55 #include <pwd.h>
  56 #include <auth_attr.h>
  57 #include <secdb.h>
  58 #include <nss_dbdefs.h>
  59 #include "libipadm_impl.h"
  60 
  61 /* error codes and text description */
  62 static struct ipadm_error_info {
  63         ipadm_status_t  error_code;
  64         const char      *error_desc;
  65 } ipadm_errors[] = {
  66         { IPADM_SUCCESS,        "Operation succeeded" },
  67         { IPADM_FAILURE,        "Operation failed" },
  68         { IPADM_EAUTH,          "Insufficient user authorizations" },
  69         { IPADM_EPERM,          "Permission denied" },
  70         { IPADM_NO_BUFS,        "No buffer space available" },
  71         { IPADM_NO_MEMORY,      "Insufficient memory" },
  72         { IPADM_BAD_ADDR,       "Invalid address" },
  73         { IPADM_BAD_PROTOCOL,   "Incorrect protocol family for operation" },
  74         { IPADM_DAD_FOUND,      "Duplicate address detected" },
  75         { IPADM_EXISTS,         "Already exists" },
  76         { IPADM_IF_EXISTS,      "Interface already exists" },
  77         { IPADM_ADDROBJ_EXISTS, "Address object already exists" },
  78         { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
  79         { IPADM_ENXIO,          "Interface does not exist" },
  80         { IPADM_GRP_NOTEMPTY,   "IPMP group is not empty" },
  81         { IPADM_INVALID_ARG,    "Invalid argument provided" },
  82         { IPADM_INVALID_NAME,   "Invalid name" },
  83         { IPADM_DLPI_FAILURE,   "Could not open DLPI link" },
  84         { IPADM_DLADM_FAILURE,  "Datalink does not exist" },
  85         { IPADM_PROP_UNKNOWN,   "Unknown property" },
  86         { IPADM_ERANGE,         "Value is outside the allowed range" },
  87         { IPADM_ESRCH,          "Value does not exist" },
  88         { IPADM_EOVERFLOW,      "Number of values exceeds the allowed limit" },
  89         { IPADM_NOTFOUND,       "Object not found" },
  90         { IPADM_IF_INUSE,       "Interface already in use" },
  91         { IPADM_ADDR_INUSE,     "Address already in use" },
  92         { IPADM_BAD_HOSTNAME,   "Hostname maps to multiple IP addresses" },
  93         { IPADM_ADDR_NOTAVAIL,  "Can't assign requested address" },
  94         { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
  95         { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
  96         { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
  97         { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" },
  98         { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
  99         { IPADM_TEMPORARY_OBJ,  "Persistent operation on temporary object" },
 100         { IPADM_IPC_ERROR,      "Could not communicate with ipmgmtd" },
 101         { IPADM_NOTSUP,         "Operation not supported" },
 102         { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
 103         { IPADM_EBADE,          "Invalid data exchange with daemon" },
 104         { IPADM_GZ_PERM,        "Operation not permitted on from-gz interface"}
 105 };
 106 
 107 #define IPADM_NUM_ERRORS        (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
 108 
 109 ipadm_status_t
 110 ipadm_errno2status(int error)
 111 {
 112         switch (error) {
 113         case 0:
 114                 return (IPADM_SUCCESS);
 115         case ENXIO:
 116                 return (IPADM_ENXIO);
 117         case ENOMEM:
 118                 return (IPADM_NO_MEMORY);
 119         case ENOBUFS:
 120                 return (IPADM_NO_BUFS);
 121         case EINVAL:
 122                 return (IPADM_INVALID_ARG);
 123         case EBUSY:
 124                 return (IPADM_IF_INUSE);
 125         case EEXIST:
 126                 return (IPADM_EXISTS);
 127         case EADDRNOTAVAIL:
 128                 return (IPADM_ADDR_NOTAVAIL);
 129         case EADDRINUSE:
 130                 return (IPADM_ADDR_INUSE);
 131         case ENOENT:
 132                 return (IPADM_NOTFOUND);
 133         case ERANGE:
 134                 return (IPADM_ERANGE);
 135         case EPERM:
 136                 return (IPADM_EPERM);
 137         case ENOTSUP:
 138         case EOPNOTSUPP:
 139                 return (IPADM_NOTSUP);
 140         case EBADF:
 141                 return (IPADM_IPC_ERROR);
 142         case EBADE:
 143                 return (IPADM_EBADE);
 144         case ESRCH:
 145                 return (IPADM_ESRCH);
 146         case EOVERFLOW:
 147                 return (IPADM_EOVERFLOW);
 148         default:
 149                 return (IPADM_FAILURE);
 150         }
 151 }
 152 
 153 /*
 154  * Returns a message string for the given libipadm error status.
 155  */
 156 const char *
 157 ipadm_status2str(ipadm_status_t status)
 158 {
 159         int     i;
 160 
 161         for (i = 0; i < IPADM_NUM_ERRORS; i++) {
 162                 if (status == ipadm_errors[i].error_code)
 163                         return (dgettext(TEXT_DOMAIN,
 164                             ipadm_errors[i].error_desc));
 165         }
 166 
 167         return (dgettext(TEXT_DOMAIN, "<unknown error>"));
 168 }
 169 
 170 /*
 171  * Opens a handle to libipadm.
 172  * Possible values for flags:
 173  *  IPH_VRRP:   Used by VRRP daemon to set the socket option SO_VRRP.
 174  *  IPH_LEGACY: This is used whenever an application needs to provide a
 175  *              logical interface name while creating or deleting
 176  *              interfaces and static addresses.
 177  *  IPH_INIT:   Used by ipadm_init_prop(), to initialize protocol properties
 178  *              on reboot.
 179  */
 180 ipadm_status_t
 181 ipadm_open(ipadm_handle_t *handle, uint32_t flags)
 182 {
 183         ipadm_handle_t  iph;
 184         ipadm_status_t  status = IPADM_SUCCESS;
 185         zoneid_t        zoneid;
 186         ushort_t        zflags;
 187         int             on = B_TRUE;
 188 
 189         if (handle == NULL)
 190                 return (IPADM_INVALID_ARG);
 191         *handle = NULL;
 192 
 193         if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
 194                 return (IPADM_INVALID_ARG);
 195 
 196         if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
 197                 return (IPADM_NO_MEMORY);
 198         iph->iph_sock = -1;
 199         iph->iph_sock6 = -1;
 200         iph->iph_door_fd = -1;
 201         iph->iph_rtsock = -1;
 202         iph->iph_flags = flags;
 203         (void) pthread_mutex_init(&iph->iph_lock, NULL);
 204 
 205         if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
 206             (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 207                 goto errnofail;
 208         }
 209 
 210         /*
 211          * We open a handle to libdladm here, to facilitate some daemons (like
 212          * nwamd) which opens handle to libipadm before devfsadmd installs the
 213          * right device permissions into the kernel and requires "all"
 214          * privileges to open DLD_CONTROL_DEV.
 215          *
 216          * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
 217          * and dladm_open() will fail. So, we avoid this by not calling
 218          * dladm_open() for such zones.
 219          */
 220         zoneid = getzoneid();
 221         iph->iph_zoneid = zoneid;
 222         if (zoneid != GLOBAL_ZONEID) {
 223                 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
 224                     sizeof (zflags)) < 0) {
 225                         goto errnofail;
 226                 }
 227         }
 228         if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
 229                 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
 230                         ipadm_close(iph);
 231                         return (IPADM_DLADM_FAILURE);
 232                 }
 233                 if (zoneid != GLOBAL_ZONEID) {
 234                         iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
 235                         /*
 236                          * Failure to open rtsock is ignored as this is
 237                          * only used in non-global zones to initialize
 238                          * routing socket information.
 239                          */
 240                 }
 241         } else {
 242                 assert(zoneid != GLOBAL_ZONEID);
 243                 iph->iph_dlh = NULL;
 244         }
 245         if (flags & IPH_VRRP) {
 246                 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
 247                     sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
 248                     SO_VRRP, &on, sizeof (on)) < 0) {
 249                         goto errnofail;
 250                 }
 251         }
 252         *handle = iph;
 253         return (status);
 254 
 255 errnofail:
 256         status = ipadm_errno2status(errno);
 257         ipadm_close(iph);
 258         return (status);
 259 }
 260 
 261 /*
 262  * Closes and frees the libipadm handle.
 263  */
 264 void
 265 ipadm_close(ipadm_handle_t iph)
 266 {
 267         if (iph == NULL)
 268                 return;
 269         if (iph->iph_sock != -1)
 270                 (void) close(iph->iph_sock);
 271         if (iph->iph_sock6 != -1)
 272                 (void) close(iph->iph_sock6);
 273         if (iph->iph_rtsock != -1)
 274                 (void) close(iph->iph_rtsock);
 275         if (iph->iph_door_fd != -1)
 276                 (void) close(iph->iph_door_fd);
 277         dladm_close(iph->iph_dlh);
 278         (void) pthread_mutex_destroy(&iph->iph_lock);
 279         free(iph);
 280 }
 281 
 282 /*
 283  * Checks if the caller has the authorization to configure network
 284  * interfaces.
 285  */
 286 boolean_t
 287 ipadm_check_auth(void)
 288 {
 289         struct passwd   pwd;
 290         char            buf[NSS_BUFLEN_PASSWD];
 291 
 292         /* get the password entry for the given user ID */
 293         if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
 294                 return (B_FALSE);
 295 
 296         /* check for presence of given authorization */
 297         return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
 298 }
 299 
 300 /*
 301  * Stores the index value of the interface in `ifname' for the address
 302  * family `af' into the buffer pointed to by `index'.
 303  */
 304 static ipadm_status_t
 305 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
 306     int *index)
 307 {
 308         struct lifreq   lifr;
 309         int             sock;
 310 
 311         bzero(&lifr, sizeof (lifr));
 312         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 313         if (af == AF_INET)
 314                 sock = iph->iph_sock;
 315         else
 316                 sock = iph->iph_sock6;
 317 
 318         if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
 319                 return (ipadm_errno2status(errno));
 320         *index = lifr.lifr_index;
 321 
 322         return (IPADM_SUCCESS);
 323 }
 324 
 325 /*
 326  * Maximum amount of time (in milliseconds) to wait for Duplicate Address
 327  * Detection to complete in the kernel.
 328  */
 329 #define DAD_WAIT_TIME           1000
 330 
 331 /*
 332  * Any time that flags are changed on an interface where either the new or the
 333  * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
 334  * announce the new address added and its flag status.
 335  * We wait here for that message and look for IFF_UP.
 336  * If something's amiss with the kernel, though, we don't wait forever.
 337  * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
 338  * it in the routing socket messages.)
 339  */
 340 static ipadm_status_t
 341 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
 342     int rtsock)
 343 {
 344         struct pollfd   fds[1];
 345         union {
 346                 struct if_msghdr ifm;
 347                 char buf[1024];
 348         } msg;
 349         int             index;
 350         ipadm_status_t  retv;
 351         uint64_t        flags;
 352         hrtime_t        starttime, now;
 353 
 354         fds[0].fd = rtsock;
 355         fds[0].events = POLLIN;
 356         fds[0].revents = 0;
 357 
 358         retv = i_ipadm_get_index(handle, lifname, af, &index);
 359         if (retv != IPADM_SUCCESS)
 360                 return (retv);
 361 
 362         starttime = gethrtime();
 363         for (;;) {
 364                 now = gethrtime();
 365                 now = (now - starttime) / 1000000;
 366                 if (now >= DAD_WAIT_TIME)
 367                         break;
 368                 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
 369                         break;
 370                 if (read(rtsock, &msg, sizeof (msg)) <= 0)
 371                         break;
 372                 if (msg.ifm.ifm_type != RTM_NEWADDR)
 373                         continue;
 374                 /* Note that ifm_index is just 16 bits */
 375                 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
 376                         return (IPADM_SUCCESS);
 377         }
 378 
 379         retv = i_ipadm_get_flags(handle, lifname, af, &flags);
 380         if (retv != IPADM_SUCCESS)
 381                 return (retv);
 382         if (flags & IFF_DUPLICATE)
 383                 return (IPADM_DAD_FOUND);
 384 
 385         return (IPADM_SUCCESS);
 386 }
 387 
 388 /*
 389  * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
 390  * interface in `lifname'.
 391  *
 392  * If the new flags value will transition the interface from "down" to "up"
 393  * then duplicate address detection is performed by the kernel.  This routine
 394  * waits to get the outcome of that test.
 395  */
 396 ipadm_status_t
 397 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
 398     uint64_t on_flags, uint64_t off_flags)
 399 {
 400         struct lifreq   lifr;
 401         uint64_t        oflags;
 402         ipadm_status_t  ret;
 403         int             rtsock = -1;
 404         int             sock, err;
 405 
 406         ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
 407         if (ret != IPADM_SUCCESS)
 408                 return (ret);
 409 
 410         sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
 411 
 412         /*
 413          * Any time flags are changed on an interface that has IFF_UP set,
 414          * we get a routing socket message.  We care about the status,
 415          * though, only when the new flags are marked "up."
 416          */
 417         if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
 418                 rtsock = socket(PF_ROUTE, SOCK_RAW, af);
 419 
 420         oflags |= on_flags;
 421         oflags &= ~off_flags;
 422         bzero(&lifr, sizeof (lifr));
 423         (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
 424         lifr.lifr_flags = oflags;
 425         if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 426                 err = errno;
 427                 if (rtsock != -1)
 428                         (void) close(rtsock);
 429                 return (ipadm_errno2status(err));
 430         }
 431         if (rtsock == -1) {
 432                 return (IPADM_SUCCESS);
 433         } else {
 434                 /* Wait for DAD to complete. */
 435                 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
 436                 (void) close(rtsock);
 437                 return (ret);
 438         }
 439 }
 440 
 441 /*
 442  * Returns the flags value for the logical interface in `lifname'
 443  * in the buffer pointed to by `flags'.
 444  */
 445 ipadm_status_t
 446 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
 447     uint64_t *flags)
 448 {
 449         struct lifreq   lifr;
 450         int             sock;
 451 
 452         bzero(&lifr, sizeof (lifr));
 453         (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
 454         if (af == AF_INET)
 455                 sock = iph->iph_sock;
 456         else
 457                 sock = iph->iph_sock6;
 458 
 459         if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
 460                 return (ipadm_errno2status(errno));
 461         }
 462         *flags = lifr.lifr_flags;
 463 
 464         return (IPADM_SUCCESS);
 465 }
 466 
 467 /*
 468  * Determines whether or not an interface name represents a loopback
 469  * interface, before the interface has been plumbed.
 470  * It is assumed that the interface name in `ifname' is of correct format
 471  * as verified by ifparse_ifspec().
 472  *
 473  * Returns: B_TRUE if loopback, B_FALSE if not.
 474  */
 475 boolean_t
 476 i_ipadm_is_loopback(const char *ifname)
 477 {
 478         int len = strlen(LOOPBACK_IF);
 479 
 480         return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
 481             (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
 482 }
 483 
 484 /*
 485  * Determines whether or not an interface name represents a vni
 486  * interface, before the interface has been plumbed.
 487  * It is assumed that the interface name in `ifname' is of correct format
 488  * as verified by ifparse_ifspec().
 489  *
 490  * Returns: B_TRUE if vni, B_FALSE if not.
 491  */
 492 boolean_t
 493 i_ipadm_is_vni(const char *ifname)
 494 {
 495         ifspec_t        ifsp;
 496 
 497         return (ifparse_ifspec(ifname, &ifsp) &&
 498             strcmp(ifsp.ifsp_devnm, "vni") == 0);
 499 }
 500 
 501 /*
 502  * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
 503  */
 504 boolean_t
 505 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
 506 {
 507         dladm_status_t          dlstatus;
 508         datalink_class_t        class;
 509         iptun_params_t          params;
 510         datalink_id_t           linkid;
 511 
 512         if (iph->iph_dlh == NULL) {
 513                 assert(iph->iph_zoneid != GLOBAL_ZONEID);
 514                 return (B_FALSE);
 515         }
 516         dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
 517             &class, NULL);
 518         if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
 519                 params.iptun_param_linkid = linkid;
 520                 dlstatus = dladm_iptun_getparams(iph->iph_dlh, &params,
 521                     DLADM_OPT_ACTIVE);
 522                 if (dlstatus == DLADM_STATUS_OK &&
 523                     params.iptun_param_type == IPTUN_TYPE_6TO4) {
 524                         return (B_TRUE);
 525                 }
 526         }
 527         return (B_FALSE);
 528 }
 529 
 530 /*
 531  * For a given interface name, ipadm_if_enabled() checks if v4
 532  * or v6 or both IP interfaces exist in the active configuration.
 533  */
 534 boolean_t
 535 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
 536 {
 537         struct lifreq   lifr;
 538         int             s4 = iph->iph_sock;
 539         int             s6 = iph->iph_sock6;
 540 
 541         bzero(&lifr, sizeof (lifr));
 542         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
 543         switch (af) {
 544         case AF_INET:
 545                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 546                         return (B_TRUE);
 547                 break;
 548         case AF_INET6:
 549                 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
 550                         return (B_TRUE);
 551                 break;
 552         case AF_UNSPEC:
 553                 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
 554                     ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
 555                         return (B_TRUE);
 556                 }
 557         }
 558         return (B_FALSE);
 559 }
 560 
 561 /*
 562  * Apply the interface property by retrieving information from nvl.
 563  */
 564 static ipadm_status_t
 565 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
 566 {
 567         nvpair_t        *nvp;
 568         char            *name, *pname = NULL;
 569         char            *protostr = NULL, *ifname = NULL, *pval = NULL;
 570         uint_t          proto;
 571         int             err = 0;
 572 
 573         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 574             nvp = nvlist_next_nvpair(nvl, nvp)) {
 575                 name = nvpair_name(nvp);
 576                 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
 577                         if ((err = nvpair_value_string(nvp, &ifname)) != 0)
 578                                 break;
 579                 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
 580                         if ((err = nvpair_value_string(nvp, &protostr)) != 0)
 581                                 break;
 582                 } else {
 583                         assert(!IPADM_PRIV_NVP(name));
 584                         pname = name;
 585                         if ((err = nvpair_value_string(nvp, &pval)) != 0)
 586                                 break;
 587                 }
 588         }
 589         if (err != 0)
 590                 return (ipadm_errno2status(err));
 591         proto = ipadm_str2proto(protostr);
 592         return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
 593             IPADM_OPT_ACTIVE));
 594 }
 595 
 596 /*
 597  * Instantiate the address object or set the address object property by
 598  * retrieving the configuration from the nvlist `nvl'.
 599  */
 600 ipadm_status_t
 601 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
 602 {
 603         nvpair_t        *nvp;
 604         char            *name;
 605         char            *aobjname = NULL, *pval = NULL, *ifname = NULL;
 606         sa_family_t     af = AF_UNSPEC;
 607         ipadm_addr_type_t atype = IPADM_ADDR_NONE;
 608         int             err = 0;
 609         ipadm_status_t  status = IPADM_SUCCESS;
 610 
 611         for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
 612             nvp = nvlist_next_nvpair(nvl, nvp)) {
 613                 name = nvpair_name(nvp);
 614                 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
 615                         if ((err = nvpair_value_string(nvp, &ifname)) != 0)
 616                                 break;
 617                 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
 618                         if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
 619                                 break;
 620                 } else if (i_ipadm_name2atype(name, &af, &atype)) {
 621                         break;
 622                 } else {
 623                         assert(!IPADM_PRIV_NVP(name));
 624                         err = nvpair_value_string(nvp, &pval);
 625                         break;
 626                 }
 627         }
 628         if (err != 0)
 629                 return (ipadm_errno2status(err));
 630 
 631         switch (atype) {
 632         case IPADM_ADDR_STATIC:
 633                 status = i_ipadm_enable_static(iph, ifname, nvl, af);
 634                 break;
 635         case IPADM_ADDR_DHCP:
 636                 status = i_ipadm_enable_dhcp(iph, ifname, nvl);
 637                 if (status == IPADM_DHCP_IPC_TIMEOUT)
 638                         status = IPADM_SUCCESS;
 639                 break;
 640         case IPADM_ADDR_IPV6_ADDRCONF:
 641                 status = i_ipadm_enable_addrconf(iph, ifname, nvl);
 642                 break;
 643         case IPADM_ADDR_NONE:
 644                 status = ipadm_set_addrprop(iph, name, pval, aobjname,
 645                     IPADM_OPT_ACTIVE);
 646                 break;
 647         }
 648 
 649         return (status);
 650 }
 651 
 652 /*
 653  * Instantiate the interface object by retrieving the configuration from
 654  * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
 655  * (interface properties and address objects on that interface) for the
 656  * given `ifname'.
 657  */
 658 ipadm_status_t
 659 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
 660 {
 661         nvlist_t        *nvl = NULL;
 662         nvpair_t        *nvp;
 663         ipadm_status_t  status = IPADM_ENXIO;
 664         ipadm_status_t  ret_status = IPADM_SUCCESS;
 665         char            newifname[LIFNAMSIZ];
 666         char            *aobjstr;
 667         uint16_t        *afs;
 668         char            *gifname;
 669         uint_t          nelem = 0;
 670         boolean_t       init_from_gz = B_FALSE;
 671         boolean_t       move_to_group = B_FALSE;
 672 
 673         (void) strlcpy(newifname, ifname, sizeof (newifname));
 674 
 675         /*
 676          * First go through the ifnvl nvlist looking for nested nvlist
 677          * containing interface class and address families.
 678          */
 679         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 680             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 681                 char *icstr;
 682                 char **mifnames;
 683                 uint32_t ipadm_flags = IPADM_OPT_ACTIVE;
 684 
 685                 if (nvpair_value_nvlist(nvp, &nvl) != 0 ||
 686                     nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 687                     &afs, &nelem) != 0)
 688                         continue;
 689 
 690                 /* Check if this is IPMP group interface */
 691                 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS,
 692                     &icstr) == 0 && atoi(icstr) == IPADM_IF_CLASS_IPMP)
 693                         ipadm_flags |= IPADM_OPT_IPMP;
 694 
 695                 /* Create interfaces for address families specified */
 696                 while (nelem-- > 0) {
 697                         uint16_t af = afs[nelem];
 698 
 699                         assert(af == AF_INET || af == AF_INET6);
 700 
 701                         status = i_ipadm_plumb_if(iph, newifname, af,
 702                             ipadm_flags);
 703                         if (status == IPADM_IF_EXISTS)
 704                                 status = IPADM_SUCCESS;
 705                         if (status != IPADM_SUCCESS)
 706                                 return (status);
 707                 }
 708                 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME,
 709                     &gifname) == 0) {
 710                         /*
 711                          * IPMP underlying interface. Move to the
 712                          * specified IPMP group.
 713                          */
 714                         move_to_group = B_TRUE;
 715                 } else if ((ipadm_flags & IPADM_OPT_IPMP) &&
 716                     nvlist_lookup_string_array(nvl, IPADM_NVP_MIFNAMES,
 717                     &mifnames, &nelem) == 0) {
 718                         /* Non-empty IPMP group interface */
 719                         while (nelem-- > 0) {
 720                                 (void) ipadm_add_ipmp_member(iph, newifname,
 721                                     mifnames[nelem], IPADM_OPT_ACTIVE);
 722                         }
 723                 }
 724                 if (iph->iph_zoneid != GLOBAL_ZONEID)
 725                         init_from_gz = B_TRUE;
 726         }
 727 
 728         if (status != IPADM_SUCCESS)
 729                 return (status);
 730 
 731         /*
 732          * Go through the ifnvl nvlist again, applying persistent configuration.
 733          */
 734         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
 735             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
 736                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
 737                         continue;
 738                 if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
 739                     &aobjstr) == 0) {
 740                         /*
 741                          * For addresses, we need to relocate addrprops from the
 742                          * nvlist `ifnvl'.
 743                          */
 744                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
 745                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
 746                             nvlist_exists(nvl, IPADM_NVP_DHCP)) {
 747                                 status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
 748                                     nvl, aobjstr);
 749 
 750                                 if (status != IPADM_SUCCESS)
 751                                         continue;
 752                         }
 753                         status = i_ipadm_init_addrobj(iph, nvl);
 754 
 755                         /*
 756                          * If this address is in use on some other interface,
 757                          * we want to record an error to be returned as
 758                          * a soft error and continue processing the rest of
 759                          * the addresses.
 760                          */
 761                         if (status == IPADM_ADDR_NOTAVAIL) {
 762                                 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
 763                                 status = IPADM_SUCCESS;
 764                         }
 765                 } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) {
 766                         status = i_ipadm_init_ifprop(iph, nvl);
 767                 }
 768                 if (status != IPADM_SUCCESS)
 769                         return (status);
 770         }
 771         if (move_to_group) {
 772                 (void) ipadm_add_ipmp_member(iph, gifname, newifname,
 773                     IPADM_OPT_ACTIVE);
 774         }
 775         if (init_from_gz)
 776                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
 777         return (ret_status);
 778 }
 779 
 780 /*
 781  * Retrieves the persistent configuration for the given interface(s) in `ifs'
 782  * by contacting the daemon and dumps the information in `allifs'.
 783  */
 784 ipadm_status_t
 785 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
 786 {
 787         nvlist_t                *nvl = NULL;
 788         size_t                  nvlsize, bufsize;
 789         ipmgmt_initif_arg_t     *iargp;
 790         char                    *buf = NULL, *nvlbuf = NULL;
 791         ipmgmt_get_rval_t       *rvalp = NULL;
 792         int                     err;
 793         ipadm_status_t          status = IPADM_SUCCESS;
 794 
 795         if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
 796                 return (ipadm_errno2status(err));
 797 
 798         err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
 799         if (err != 0) {
 800                 status = ipadm_errno2status(err);
 801                 goto done;
 802         }
 803         bufsize = sizeof (*iargp) + nvlsize;
 804         if ((buf = malloc(bufsize)) == NULL) {
 805                 status = ipadm_errno2status(errno);
 806                 goto done;
 807         }
 808 
 809         /* populate the door_call argument structure */
 810         iargp = (void *)buf;
 811         iargp->ia_cmd = IPMGMT_CMD_INITIF;
 812         iargp->ia_flags = 0;
 813         iargp->ia_family = AF_UNSPEC;
 814         iargp->ia_nvlsize = nvlsize;
 815         (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
 816 
 817         if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
 818                 status = ipadm_errno2status(errno);
 819                 goto done;
 820         }
 821         if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
 822             sizeof (*rvalp), B_TRUE)) != 0) {
 823                 status = ipadm_errno2status(err);
 824                 goto done;
 825         }
 826 
 827         /*
 828          * Daemon reply pointed to by rvalp contains ipmgmt_get_rval_t structure
 829          * followed by a list of packed nvlists, each of which represents
 830          * configuration information for the given interface(s).
 831          */
 832         err = nvlist_unpack((char *)rvalp + sizeof (ipmgmt_get_rval_t),
 833             rvalp->ir_nvlsize, allifs, NV_ENCODE_NATIVE);
 834         if (err != 0)
 835                 status = ipadm_errno2status(err);
 836 done:
 837         nvlist_free(nvl);
 838         free(buf);
 839         free(nvlbuf);
 840         free(rvalp);
 841         return (status);
 842 }
 843 
 844 /*
 845  * Returns B_FALSE if
 846  * (1) `ifname' is NULL or has no string or has a string of invalid length
 847  * (2) ifname is a logical interface and IPH_LEGACY is not set, or
 848  */
 849 boolean_t
 850 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
 851 {
 852         ifspec_t ifsp;
 853 
 854         if (ifname == NULL || ifname[0] == '\0' ||
 855             !ifparse_ifspec(ifname, &ifsp))
 856                 return (B_FALSE);
 857         if (ifsp.ifsp_lunvalid)
 858                 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
 859         return (B_TRUE);
 860 }
 861 
 862 /*
 863  * Wrapper for sending a non-transparent I_STR ioctl().
 864  * Returns: Result from ioctl().
 865  */
 866 int
 867 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
 868 {
 869         struct strioctl ioc;
 870 
 871         (void) memset(&ioc, 0, sizeof (ioc));
 872         ioc.ic_cmd = cmd;
 873         ioc.ic_timout = 0;
 874         ioc.ic_len = buflen;
 875         ioc.ic_dp = buf;
 876 
 877         return (ioctl(s, I_STR, (char *)&ioc));
 878 }
 879 
 880 /*
 881  * Make a door call to the server and checks if the door call succeeded or not.
 882  * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
 883  * variable size and door will allocate buffer using mmap(). In such cases
 884  * we re-allocate the required memory,n assign it to `rbufp', copy the data to
 885  * `rbufp' and then call munmap() (see below).
 886  *
 887  * It also checks to see if the server side procedure ran successfully by
 888  * checking for ir_err. Therefore, for some callers who just care about the
 889  * return status can set `rbufp' to NULL and set `rsize' to 0.
 890  */
 891 int
 892 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
 893     size_t rsize, boolean_t is_varsize)
 894 {
 895         door_arg_t      darg;
 896         int             err;
 897         ipmgmt_retval_t rval, *rvalp;
 898         boolean_t       reopen = B_FALSE;
 899 
 900         if (rbufp == NULL) {
 901                 rvalp = &rval;
 902                 rbufp = (void **)&rvalp;
 903                 rsize = sizeof (rval);
 904         }
 905 
 906         darg.data_ptr = arg;
 907         darg.data_size = asize;
 908         darg.desc_ptr = NULL;
 909         darg.desc_num = 0;
 910         darg.rbuf = *rbufp;
 911         darg.rsize = rsize;
 912 
 913 reopen:
 914         (void) pthread_mutex_lock(&iph->iph_lock);
 915         /* The door descriptor is opened if it isn't already */
 916         if (iph->iph_door_fd == -1) {
 917                 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
 918                         err = errno;
 919                         (void) pthread_mutex_unlock(&iph->iph_lock);
 920                         return (err);
 921                 }
 922         }
 923         (void) pthread_mutex_unlock(&iph->iph_lock);
 924 
 925         if (door_call(iph->iph_door_fd, &darg) == -1) {
 926                 /*
 927                  * Stale door descriptor is possible if ipmgmtd was restarted
 928                  * since last iph_door_fd was opened, so try re-opening door
 929                  * descriptor.
 930                  */
 931                 if (!reopen && errno == EBADF) {
 932                         (void) close(iph->iph_door_fd);
 933                         iph->iph_door_fd = -1;
 934                         reopen = B_TRUE;
 935                         goto reopen;
 936                 }
 937                 return (errno);
 938         }
 939         err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
 940         if (darg.rbuf != *rbufp) {
 941                 /*
 942                  * if the caller is expecting the result to fit in specified
 943                  * buffer then return failure.
 944                  */
 945                 if (!is_varsize)
 946                         err = EBADE;
 947                 /*
 948                  * The size of the buffer `*rbufp' was not big enough
 949                  * and the door itself allocated buffer, for us. We will
 950                  * hit this, on several occasion as for some cases
 951                  * we cannot predict the size of the return structure.
 952                  * Reallocate the buffer `*rbufp' and memcpy() the contents
 953                  * to new buffer.
 954                  */
 955                 if (err == 0) {
 956                         void *newp;
 957 
 958                         /* allocated memory will be freed by the caller */
 959                         if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
 960                                 err = ENOMEM;
 961                         } else {
 962                                 *rbufp = newp;
 963                                 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
 964                         }
 965                 }
 966                 /* munmap() the door buffer */
 967                 (void) munmap(darg.rbuf, darg.rsize);
 968         } else {
 969                 if (darg.rsize != rsize)
 970                         err = EBADE;
 971         }
 972         return (err);
 973 }
 974 
 975 /*
 976  * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
 977  * to do a door_call to ipmgmtd, that should return persistent information
 978  * about interfaces or/and addresses from ipadm DB
 979  */
 980 ipadm_status_t
 981 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg, size_t garg_size,
 982     nvlist_t **onvl)
 983 {
 984         ipmgmt_get_rval_t       *rvalp;
 985         int                     err;
 986         size_t                  nvlsize;
 987         char                    *nvlbuf;
 988 
 989         rvalp = malloc(sizeof (ipmgmt_get_rval_t));
 990         err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
 991             sizeof (*rvalp), B_TRUE);
 992         if (err == 0) {
 993                 nvlsize = rvalp->ir_nvlsize;
 994                 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
 995                 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
 996         }
 997         free(rvalp);
 998 
 999         return (ipadm_errno2status(err));
1000 }
1001 
1002 /*
1003  * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
1004  *                      NULL, empty, or a single space (e.g., as returned by
1005  *                      domainname(1M)/sysinfo).
1006  *
1007  *   input: const char *: the hostname to inspect;
1008  *  output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
1009  *                      criteria above; otherwise, B_FALSE;
1010  */
1011 
1012 boolean_t
1013 ipadm_is_nil_hostname(const char *hostname)
1014 {
1015         return (hostname == NULL || *hostname == '\0' ||
1016             (*hostname == ' ' && hostname[1] == '\0'));
1017 }
1018 
1019 /*
1020  * ipadm_is_valid_hostname(): check whether a string is a valid hostname
1021  *
1022  *   input: const char *: the string to verify as a hostname
1023  *  output: boolean_t: B_TRUE if the string is a valid hostname
1024  *
1025  * Note that we accept host names beginning with a digit, which is not
1026  * strictly legal according to the RFCs but is in common practice, so we
1027  * endeavour to not break what customers are using.
1028  *
1029  * RFC 1035 limits a wire-format domain name to 255 octets. For a printable
1030  * `hostname' as we have, the limit is therefore 253 characters (excluding
1031  * the terminating '\0'--or 254 characters if the last character of
1032  * `hostname' is a '.'.
1033  *
1034  * Excerpt from section 2.3.1., Preferred name syntax:
1035  *
1036  * <domain> ::= <subdomain> | " "
1037  * <subdomain> ::= <label> | <subdomain> "." <label>
1038  * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
1039  * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
1040  * <let-dig-hyp> ::= <let-dig> | "-"
1041  * <let-dig> ::= <letter> | <digit>
1042  */
1043 boolean_t
1044 ipadm_is_valid_hostname(const char *hostname)
1045 {
1046         const size_t MAX_READABLE_NAME_LEN = 253;
1047         char last_char;
1048         size_t has_last_dot, namelen, i;
1049 
1050         if (hostname == NULL)
1051                 return (B_FALSE);
1052 
1053         namelen = strlen(hostname);
1054         if (namelen < 1)
1055                 return (B_FALSE);
1056 
1057         last_char = hostname[namelen - 1];
1058         has_last_dot = last_char == '.';
1059 
1060         if (namelen > MAX_READABLE_NAME_LEN + has_last_dot ||
1061             last_char == '-')
1062                 return (B_FALSE);
1063 
1064         for (i = 0; hostname[i] != '\0'; i++) {
1065                 /*
1066                  * As noted above, this deviates from RFC 1035 in that it
1067                  * allows a leading digit.
1068                  */
1069                 if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
1070                     (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
1071                         continue;
1072 
1073                 return (B_FALSE);
1074         }
1075 
1076         return (B_TRUE);
1077 }