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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * From	"tsol_tndb_parser.c	7.24	01/09/05 SMI; TSOL 2.x"
26  *
27  * These functions parse entries in the "tnzonecfg" (zone configuration) file.
28  * Each entry in this file has five fields, separated by a colon.  These fields
29  * are:
30  *
31  *	zone name : label : flags : zone-specific MLPs : global MLPs
32  *
33  * The fourth and fifth fields contain subfields consisting of MLP entries
34  * separated by semicolons.  The MLP entries are of the form:
35  *
36  *	port[-port]/protocol
37  *
38  * In order to help preserve sanity, we do not allow more than four unescaped
39  * colons in a line, nor any unescaped ';' characters in the non-MLP fields.
40  * Such things are indicative of typing errors, not intentional configuration.
41  */
42 
43 #include <ctype.h>
44 #include <stdlib.h>
45 #include <stddef.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <libtsnet.h>
49 #include <tsol/label.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <nss.h>
54 #include <errno.h>
55 #include <secdb.h>
56 
57 /*
58  * Parse an MLP specification in port1-port2/proto or port/proto form.
59  */
60 static int
str_to_mlp(char * mlp_str,tsol_mlp_t * zone_mlp)61 str_to_mlp(char *mlp_str, tsol_mlp_t *zone_mlp)
62 {
63 	char *fieldp;
64 	char *lasts, *cp;
65 	int i;
66 	ulong_t ulv;
67 	struct protoent proto;
68 	char gbuf[1024];
69 
70 	(void) memset(zone_mlp, 0, sizeof (tsol_mlp_t));
71 
72 	fieldp = strtok_r(mlp_str, KV_DELIMITER, &lasts);
73 	if (fieldp == NULL)
74 		return (-1);
75 
76 	errno = 0;
77 	for (i = 0; fieldp != NULL && i < NMLP_MAX; i++) {
78 		ulv = strtoul(fieldp, &cp, 0);
79 		zone_mlp[i].mlp_port = (uint16_t)ulv;
80 		zone_mlp[i].mlp_port_upper = 0;
81 		if (errno != 0 || ulv > 65535)
82 			return (-1);
83 		if (*cp == '-') {
84 			ulv = strtol(cp + 1, &cp, 0);
85 			zone_mlp[i].mlp_port_upper = (uint16_t)ulv;
86 			if (errno != 0 || ulv > 65535)
87 				return (-1);
88 		}
89 		if (*cp != '/')
90 			return (-1);
91 		fieldp = cp + 1;
92 		ulv = strtol(fieldp, &cp, 0);
93 		if (errno == 0 && ulv <= 255 && *cp == '\0')
94 			zone_mlp->mlp_ipp = (uint8_t)ulv;
95 		else if (getprotobyname_r(fieldp, &proto, gbuf,
96 		    sizeof (gbuf)) != NULL)
97 			zone_mlp->mlp_ipp = proto.p_proto;
98 		else
99 			return (-1);
100 		fieldp = strtok_r(NULL, KV_DELIMITER, &lasts);
101 	}
102 	return (0);
103 }
104 
105 static boolean_t
parse_mlp_list(tsol_mlp_t ** list,char * str,int * errp,char ** errstrp)106 parse_mlp_list(tsol_mlp_t **list, char *str, int *errp, char **errstrp)
107 {
108 	int mmax;
109 	tsol_mlp_t *mlp;
110 	char *tokp, *finally;
111 	int mc;
112 
113 	mmax = 0;
114 	if ((mlp = *list) != NULL) {
115 		while (!TSOL_MLP_END(mlp)) {
116 			mmax++;
117 			mlp++;
118 		}
119 		mmax++;
120 	}
121 	mlp = *list;
122 	tokp = strtok_r(str, KV_DELIMITER, &finally);
123 	for (mc = 0; tokp != NULL; mc++) {
124 		if (mc >= mmax) {
125 			mmax += 8;
126 			mlp = realloc(mlp, mmax * sizeof (*mlp));
127 			if (mlp == NULL) {
128 				*errp = LTSNET_SYSERR;
129 				*errstrp = tokp;
130 				return (B_FALSE);
131 			}
132 			*list = mlp;
133 		}
134 		if (str_to_mlp(tokp, mlp + mc) == -1) {
135 			*errp = LTSNET_ILL_MLP;
136 			*errstrp = tokp;
137 			return (B_FALSE);
138 		}
139 		tokp = strtok_r(NULL, KV_DELIMITER, &finally);
140 	}
141 	if (mc >= mmax) {
142 		mlp = realloc(mlp, (mmax + 1) * sizeof (*mlp));
143 		if (mlp == NULL) {
144 			*errp = LTSNET_SYSERR;
145 			*errstrp = finally;
146 			return (B_FALSE);
147 		}
148 		*list = mlp;
149 	}
150 	(void) memset(mlp + mc, 0, sizeof (*mlp));
151 	return (B_TRUE);
152 }
153 
154 tsol_zcent_t *
tsol_sgetzcent(const char * instr,int * errp,char ** errstrp)155 tsol_sgetzcent(const char *instr, int *errp, char **errstrp)
156 {
157 	int err;
158 	m_label_t *slp;
159 	char *errstr;
160 	tsol_zcent_t *zc;
161 	const char *nextf;
162 	char *cp;
163 	char fieldbuf[1024];
164 
165 	/*
166 	 * The user can specify NULL pointers for these.  Make sure that we
167 	 * don't have to deal with checking for NULL everywhere by just
168 	 * pointing to our own variables if the user gives NULL.
169 	 */
170 	if (errp == NULL)
171 		errp = &err;
172 	if (errstrp == NULL)
173 		errstrp = &errstr;
174 
175 	/* The default, unless we find a more specific error locus. */
176 	*errstrp = (char *)instr;
177 
178 	if ((zc = calloc(1, sizeof (*zc))) == NULL) {
179 		*errp = LTSNET_SYSERR;
180 		return (NULL);
181 	}
182 
183 	/* First, parse off the zone name. */
184 	instr = parse_entry(zc->zc_name, sizeof (zc->zc_name), instr, "#;:\n");
185 	if (zc->zc_name[0] == '\0') {
186 		*errstrp = (char *)instr;
187 		if (*instr == '\0' || *instr == '#' || *instr == '\n')
188 			*errp = LTSNET_EMPTY;
189 		else if (*instr == ':')
190 			*errp = LTSNET_NO_NAME;
191 		else
192 			*errp = LTSNET_ILL_NAME;
193 		goto err_ret;
194 	}
195 	if (*instr != ':') {
196 		*errstrp = (char *)instr;
197 		if (*instr == '=' || *instr == ';')
198 			*errp = LTSNET_ILL_NAME;
199 		else
200 			*errp = LTSNET_ILL_ENTRY;
201 		goto err_ret;
202 	}
203 	instr++;
204 
205 	/* Field two: parse off the label. */
206 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#;:\n");
207 	if (*nextf != ':') {
208 		*errstrp = (char *)nextf;
209 		*errp = LTSNET_ILL_ENTRY;
210 		goto err_ret;
211 	}
212 	if (fieldbuf[0] == '\0') {
213 		*errstrp = (char *)instr;
214 		*errp = LTSNET_NO_LABEL;
215 		goto err_ret;
216 	}
217 
218 	slp = &zc->zc_label;
219 	if (str_to_label(fieldbuf, &slp, MAC_LABEL, L_NO_CORRECTION, NULL)
220 	    != 0) {
221 		*errstrp = (char *)instr;
222 		*errp = LTSNET_ILL_LABEL;
223 		goto err_ret;
224 	}
225 	instr = nextf + 1;
226 
227 	/* The kernel will apply the system doi to the zone label later */
228 	zc->zc_doi = 0;
229 
230 	/* Field three: get match flag */
231 	errno = 0;
232 	zc->zc_match = (uchar_t)strtol(instr, &cp, 0);
233 	if (errno != 0 || (*cp != ':' && *cp != '\0')) {
234 		*errp = LTSNET_ILL_FLAG;
235 		*errstrp = (char *)instr;
236 		goto err_ret;
237 	}
238 	if (*cp != ':') {
239 		*errp = LTSNET_ILL_VALDELIM;
240 		*errstrp = cp;
241 		goto err_ret;
242 	}
243 	instr = cp + 1;
244 
245 	/* Field four: get zone-specific MLP list. */
246 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
247 	if (*nextf != ':') {
248 		*errstrp = (char *)nextf;
249 		*errp = LTSNET_ILL_ENTRY;
250 		goto err_ret;
251 	}
252 	if (!parse_mlp_list(&zc->zc_private_mlp, fieldbuf, errp, errstrp)) {
253 		*errstrp = (char *)instr + (*errstrp - fieldbuf);
254 		goto err_ret;
255 	}
256 	instr = nextf + 1;
257 
258 	/* Field five: get global MLP list. */
259 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
260 	if (*nextf != '\0' && *nextf != '#' && !isspace(*nextf)) {
261 		*errstrp = (char *)nextf;
262 		*errp = LTSNET_ILL_ENTRY;
263 		goto err_ret;
264 	}
265 	if (!parse_mlp_list(&zc->zc_shared_mlp, fieldbuf, errp, errstrp)) {
266 		*errstrp = (char *)instr + (*errstrp - fieldbuf);
267 		goto err_ret;
268 	}
269 
270 	return (zc);
271 
272 err_ret:
273 	err = errno;
274 	tsol_freezcent(zc);
275 	errno = err;
276 	return (NULL);
277 }
278 
279 void
tsol_freezcent(tsol_zcent_t * zc)280 tsol_freezcent(tsol_zcent_t *zc)
281 {
282 	if (zc != NULL) {
283 		free(zc->zc_private_mlp);
284 		free(zc->zc_shared_mlp);
285 		free(zc);
286 	}
287 }
288