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  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*
  26  * This file contains routines to read/write formatted entries from/to
  27  * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
  28  * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
  29  * below:
  30  *              name=value[;...]
  31  *
  32  * The 'name' determines how to interpret 'value'. The supported names are:
  33  *
  34  *  IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
  35  *             converted to nvlist, will contain nvpairs for local and remote
  36  *             addresses. These nvpairs are of type DATA_TYPE_STRING
  37  *
  38  *  IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
  39  *             converted to nvlist, will contain nvpairs for local and remote
  40  *             addresses. These nvpairs are of type DATA_TYPE_STRING
  41  *
  42  *  IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
  43  *             info and when converted to nvlist, will contain following nvpairs
  44  *                      interface_id: DATA_TYPE_UINT8_ARRAY
  45  *                      prefixlen: DATA_TYPE_UINT32
  46  *                      stateless: DATA_TYPE_STRING
  47  *                      stateful: DATA_TYPE_STRING
  48  *
  49  *  IPADM_NVP_DHCP - value holds wait time and primary info and when converted
  50  *             to nvlist, will contain following nvpairs
  51  *                      wait:   DATA_TYPE_INT32
  52  *                      primary: DATA_TYPE_BOOLEAN
  53  *
  54  *  default  - value is a single entity and when converted to nvlist, will
  55  *             contain nvpair of type DATA_TYPE_STRING. nvpairs private to
  56  *             ipadm are of this type. Further the property name and property
  57  *             values are stored as nvpairs of this type.
  58  *
  59  * The syntax for each line is described above the respective functions below.
  60  */
  61 
  62 #include <stdlib.h>
  63 #include <strings.h>
  64 #include <errno.h>
  65 #include <ctype.h>
  66 #include <sys/types.h>
  67 #include <sys/stat.h>
  68 #include <sys/dld.h>
  69 #include <fcntl.h>
  70 #include <dirent.h>
  71 #include <unistd.h>
  72 #include <assert.h>
  73 #include <sys/socket.h>
  74 #include <netinet/in.h>
  75 #include <arpa/inet.h>
  76 #include <sys/sockio.h>
  77 #include "libipadm_impl.h"
  78 
  79 #define MAXLINELEN              1024
  80 #define IPADM_NVPAIR_SEP        ";"
  81 #define IPADM_NAME_SEP          ","
  82 
  83 static char ipadm_rootdir[MAXPATHLEN] = "/";
  84 
  85 static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
  86     ipadm_db_op_t);
  87 
  88 /*
  89  * convert nvpair to a "name=value" string for writing to the DB.
  90  */
  91 typedef size_t  ipadm_wfunc_t(nvpair_t *, char *, size_t);
  92 
  93 /*
  94  * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
  95  * nvpair to the nvlist.
  96  */
  97 typedef void  ipadm_rfunc_t(nvlist_t *, char *name, char *value);
  98 
  99 static ipadm_rfunc_t    i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
 100                         i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
 101                         i_ipadm_dhcp_dbline2nvl;
 102 
 103 static ipadm_wfunc_t    i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
 104                         i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
 105                         i_ipadm_dhcp_nvp2dbline;
 106 
 107 /*
 108  * table of function pointers to read/write formatted entries from/to
 109  * ipadm.conf.
 110  */
 111 typedef struct ipadm_conf_ent_s {
 112         const char              *ipent_type_name;
 113         ipadm_wfunc_t           *ipent_wfunc;
 114         ipadm_rfunc_t           *ipent_rfunc;
 115 } ipadm_conf_ent_t;
 116 
 117 static ipadm_conf_ent_t ipadm_conf_ent[] = {
 118         { IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
 119         { IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
 120         { IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
 121             i_ipadm_intfid_dbline2nvl },
 122         { IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
 123         { NULL, i_ipadm_str_nvp2dbline, i_ipadm_str_dbline2nvl }
 124 };
 125 
 126 static ipadm_conf_ent_t *
 127 i_ipadm_find_conf_type(const char *type)
 128 {
 129         int     i;
 130 
 131         for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
 132                 if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
 133                         break;
 134         return (&ipadm_conf_ent[i]);
 135 }
 136 
 137 /*
 138  * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
 139  * the given nvlist `nvl' and adds the strings to `buf'.
 140  */
 141 size_t
 142 i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
 
 598 static void
 599 i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
 600 {
 601         char            *cp;
 602         char            *endp;
 603         long            wait_time;
 604         boolean_t       primary;
 605 
 606         assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
 607         cp = strchr(value, ',');
 608         assert(cp != NULL);
 609         *cp++ = '\0';
 610         errno = 0;
 611         wait_time = strtol(value, &endp, 10);
 612         if (*endp != '\0' || errno != 0)
 613                 return;
 614         primary = (strcmp(cp, "yes") == 0);
 615         (void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
 616 }
 617 
 618 /*
 619  * Parses the buffer, for name-value pairs and creates nvlist. The value
 620  * is always considered to be a string.
 621  */
 622 int
 623 ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
 624 {
 625         char    *nv, *name, *val, *buf, *cp, *sep;
 626         int     err;
 627 
 628         if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
 629                 return (EINVAL);
 630         *ipnvl = NULL;
 631 
 632         /*
 633          * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
 634          */
 635         if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
 636                 return (EINVAL);
 637 
 
 | 
 
 
   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  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 /*
  27  * This file contains routines to read/write formatted entries from/to
  28  * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
  29  * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
  30  * below:
  31  *              name=value[;...]
  32  *
  33  * The 'name' determines how to interpret 'value'. The supported names are:
  34  *
  35  *  IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
  36  *             converted to nvlist, will contain nvpairs for local and remote
  37  *             addresses. These nvpairs are of type DATA_TYPE_STRING
  38  *
  39  *  IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
  40  *             converted to nvlist, will contain nvpairs for local and remote
  41  *             addresses. These nvpairs are of type DATA_TYPE_STRING
  42  *
  43  *  IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
  44  *             info and when converted to nvlist, will contain following nvpairs
  45  *                      interface_id: DATA_TYPE_UINT8_ARRAY
  46  *                      prefixlen: DATA_TYPE_UINT32
  47  *                      stateless: DATA_TYPE_STRING
  48  *                      stateful: DATA_TYPE_STRING
  49  *
  50  *  IPADM_NVP_DHCP - value holds wait time and primary info and when converted
  51  *             to nvlist, will contain following nvpairs
  52  *                      wait:   DATA_TYPE_INT32
  53  *                      primary: DATA_TYPE_BOOLEAN
  54  *
  55  *  IPADM_NVP_FAMILIES - value holds interface families and when converted
  56  *              to nvlist, will be a DATA_TYPE_UINT16_ARRAY
  57  *
  58  *  IPADM_NVP_MIFNAMES - value holds IPMP group members and when converted
  59  *          to nvlist, will be a DATA_TYPE_STRING_ARRAY
  60  *
  61  *  default  - value is a single entity and when converted to nvlist, will
  62  *             contain nvpair of type DATA_TYPE_STRING. nvpairs private to
  63  *             ipadm are of this type. Further the property name and property
  64  *             values are stored as nvpairs of this type.
  65  *
  66  * The syntax for each line is described above the respective functions below.
  67  */
  68 
  69 #include <stdlib.h>
  70 #include <strings.h>
  71 #include <errno.h>
  72 #include <ctype.h>
  73 #include <sys/types.h>
  74 #include <sys/stat.h>
  75 #include <sys/dld.h>
  76 #include <fcntl.h>
  77 #include <dirent.h>
  78 #include <unistd.h>
  79 #include <assert.h>
  80 #include <sys/socket.h>
  81 #include <netinet/in.h>
  82 #include <arpa/inet.h>
  83 #include <sys/sockio.h>
  84 #include <sys/note.h>
  85 #include "libipadm_impl.h"
  86 
  87 #define MAXLINELEN              1024
  88 #define IPADM_NVPAIR_SEP        ";"
  89 #define IPADM_NAME_SEP          ","
  90 
  91 static char ipadm_rootdir[MAXPATHLEN] = "/";
  92 
  93 static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
  94     ipadm_db_op_t);
  95 
  96 /*
  97  * convert nvpair to a "name=value" string for writing to the DB.
  98  */
  99 typedef size_t  ipadm_wfunc_t(nvpair_t *, char *, size_t);
 100 
 101 /*
 102  * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
 103  * nvpair to the nvlist.
 104  */
 105 typedef void  ipadm_rfunc_t(nvlist_t *, char *name, char *value);
 106 
 107 static ipadm_rfunc_t    i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
 108                         i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
 109                         i_ipadm_dhcp_dbline2nvl, i_ipadm_families_dbline2nvl,
 110                         i_ipadm_groupmembers_dbline2nvl;
 111 
 112 static ipadm_wfunc_t    i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
 113                         i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
 114                         i_ipadm_dhcp_nvp2dbline, i_ipadm_families_nvp2dbline,
 115                         i_ipadm_groupmembers_nvp2dbline;
 116 
 117 /*
 118  * table of function pointers to read/write formatted entries from/to
 119  * ipadm.conf.
 120  */
 121 typedef struct ipadm_conf_ent_s {
 122         const char              *ipent_type_name;
 123         ipadm_wfunc_t           *ipent_wfunc;
 124         ipadm_rfunc_t           *ipent_rfunc;
 125 } ipadm_conf_ent_t;
 126 
 127 static ipadm_conf_ent_t ipadm_conf_ent[] = {
 128         { IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
 129         { IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
 130         { IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
 131             i_ipadm_intfid_dbline2nvl },
 132         { IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
 133         { IPADM_NVP_FAMILIES, i_ipadm_families_nvp2dbline,
 134             i_ipadm_families_dbline2nvl },
 135         { IPADM_NVP_MIFNAMES, i_ipadm_groupmembers_nvp2dbline,
 136             i_ipadm_groupmembers_dbline2nvl},
 137         { NULL, i_ipadm_str_nvp2dbline, i_ipadm_str_dbline2nvl }
 138 };
 139 
 140 static ipadm_conf_ent_t *
 141 i_ipadm_find_conf_type(const char *type)
 142 {
 143         int     i;
 144 
 145         for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
 146                 if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
 147                         break;
 148         return (&ipadm_conf_ent[i]);
 149 }
 150 
 151 /*
 152  * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
 153  * the given nvlist `nvl' and adds the strings to `buf'.
 154  */
 155 size_t
 156 i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
 
 612 static void
 613 i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
 614 {
 615         char            *cp;
 616         char            *endp;
 617         long            wait_time;
 618         boolean_t       primary;
 619 
 620         assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
 621         cp = strchr(value, ',');
 622         assert(cp != NULL);
 623         *cp++ = '\0';
 624         errno = 0;
 625         wait_time = strtol(value, &endp, 10);
 626         if (*endp != '\0' || errno != 0)
 627                 return;
 628         primary = (strcmp(cp, "yes") == 0);
 629         (void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
 630 }
 631 
 632 /*
 633  * Input 'nvp': name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
 634  *
 635  *
 636  */
 637 static size_t
 638 i_ipadm_families_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
 639 {
 640         uint_t nelem = 0;
 641         uint16_t *elem;
 642 
 643         assert(nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY);
 644 
 645         if (nvpair_value_uint16_array(nvp,
 646             &elem, &nelem) != 0) {
 647                 buf[0] = '\0';
 648                 return (0);
 649         }
 650 
 651         assert(nelem != 0 || nelem > 2);
 652 
 653         if (nelem == 1) {
 654                 return (snprintf(buf, buflen, "%s=%d",
 655                     nvpair_name(nvp), elem[0]));
 656         } else {
 657                 return (snprintf(buf, buflen, "%s=%d,%d",
 658                     nvpair_name(nvp), elem[0], elem[1]));
 659         }
 660 }
 661 
 662 /*
 663  * name = IPADM_NVP_FAMILIES and value = <FAMILY>[,FAMILY]
 664  *
 665  * output nvp: name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
 666  *
 667  */
 668 static void
 669 i_ipadm_families_dbline2nvl(nvlist_t *nvl, char *name, char *value)
 670 {
 671         _NOTE(ARGUNUSED(name))
 672         uint16_t        families[2];
 673         uint_t  nelem = 0;
 674         char    *val, *lasts;
 675 
 676         if ((val = strtok_r(value,
 677             ",", &lasts)) != NULL) {
 678                 families[0] = atoi(val);
 679                 nelem++;
 680                 if ((val = strtok_r(NULL,
 681                     ",", &lasts)) != NULL) {
 682                         families[1] = atoi(val);
 683                         nelem++;
 684                 }
 685                 (void) nvlist_add_uint16_array(nvl,
 686                     IPADM_NVP_FAMILIES, families, nelem);
 687         }
 688 }
 689 
 690 /*
 691  * input nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
 692  *
 693  *
 694  */
 695 static size_t
 696 i_ipadm_groupmembers_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
 697 {
 698         uint_t nelem = 0;
 699         char **elem;
 700         size_t n;
 701 
 702         assert(nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY);
 703 
 704         if (nvpair_value_string_array(nvp,
 705             &elem, &nelem) != 0) {
 706                 buf[0] = '\0';
 707                 return (0);
 708         }
 709 
 710         assert(nelem != 0);
 711 
 712         n = snprintf(buf, buflen, "%s=", IPADM_NVP_MIFNAMES);
 713         if (n >= buflen)
 714                 return (n);
 715 
 716         while (nelem-- > 0) {
 717                 n = strlcat(buf, elem[nelem], buflen);
 718                 if (nelem > 0)
 719                         n = strlcat(buf, ",", buflen);
 720 
 721                 if (n > buflen)
 722                         return (n);
 723         }
 724 
 725         return (n);
 726 }
 727 
 728 /*
 729  * name = IPADM_NVP_MIFNAMES and value = <if_name>[,if_name]
 730  *
 731  * output nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
 732  */
 733 static void
 734 i_ipadm_groupmembers_dbline2nvl(nvlist_t *nvl, char *name, char *value)
 735 {
 736         char    *members[256];
 737         char    *member;
 738         char    *val, *lasts;
 739         uint_t  m_cnt = 0;
 740 
 741         assert(strcmp(name, IPADM_NVP_MIFNAMES) == 0 && value != NULL);
 742 
 743         if ((val = strtok_r(value, ",", &lasts)) != NULL) {
 744                 if ((member = calloc(1, LIFNAMSIZ)) == NULL)
 745                         return;
 746 
 747                 (void) strlcpy(member, val, LIFNAMSIZ);
 748                 members[m_cnt++] = member;
 749 
 750                 while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
 751                         if ((member = calloc(1, LIFNAMSIZ)) == NULL)
 752                                 goto fail;
 753 
 754                         (void) strlcpy(member, val, LIFNAMSIZ);
 755                         members[m_cnt++] = member;
 756                 }
 757 
 758                 (void) nvlist_add_string_array(nvl, IPADM_NVP_MIFNAMES,
 759                     members, m_cnt);
 760         }
 761 
 762 fail:
 763         while (m_cnt-- > 0) {
 764                 free(members[m_cnt]);
 765         }
 766 }
 767 
 768 /*
 769  * Parses the buffer, for name-value pairs and creates nvlist. The value
 770  * is always considered to be a string.
 771  */
 772 int
 773 ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
 774 {
 775         char    *nv, *name, *val, *buf, *cp, *sep;
 776         int     err;
 777 
 778         if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
 779                 return (EINVAL);
 780         *ipnvl = NULL;
 781 
 782         /*
 783          * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
 784          */
 785         if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
 786                 return (EINVAL);
 787 
 
 |