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
|