xref: /illumos-gate/usr/src/lib/libtsnet/common/misc.c (revision 876de206688d9fe008ad80c116a23a56701579d1)
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 "misc.c	5.15	00/05/31 SMI; TSOL 2.x"
26  */
27 
28 /*
29  *	Miscellaneous user interfaces to trusted label functions.
30  */
31 
32 
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <libintl.h>
39 #include <libtsnet.h>
40 #include <tsol/label.h>
41 
42 #include <net/route.h>
43 
44 #define	MAX_ATTR_LEN	1024
45 
46 /*
47  * Parse off an entry from a line.  Entry is stored in 'outbuf'.  Returned
48  * value is a pointer to the first unprocessed input character from 'instr'.
49  */
50 const char *
51 parse_entry(char *outbuf, size_t outlen, const char *instr,
52     const char *delimit)
53 {
54 	boolean_t escape_state = B_FALSE;
55 	boolean_t any_white;
56 	char chr;
57 
58 	any_white = strchr(delimit, '\n') != NULL;
59 
60 	/*
61 	 * User may specify outlen as 0 to skip over a field without storing
62 	 * it anywhere.  Otherwise, we need at least one byte for the
63 	 * terminating NUL plus one byte to store another byte from instr.
64 	 */
65 	while (outlen != 1 && (chr = *instr++) != '\0') {
66 		if (!escape_state) {
67 			if (chr == '\\') {
68 				escape_state = B_TRUE;
69 				continue;
70 			}
71 			if (strchr(delimit, chr) != NULL)
72 				break;
73 			if (any_white && isspace(chr))
74 				break;
75 		}
76 		escape_state = B_FALSE;
77 		if (outlen > 0) {
78 			*outbuf++ = chr;
79 			outlen--;
80 		}
81 	}
82 	if (outlen != 1)
83 		instr--;
84 	if (escape_state)
85 		instr--;
86 	if (outlen > 0)
87 		*outbuf = '\0';
88 	return (instr);
89 }
90 
91 char *
92 sl_to_str(const m_label_t *sl)
93 {
94 	char *sl_str = NULL;
95 	static char unknown_str[] = "UNKNOWN";
96 
97 	if (sl == NULL)
98 		return (strdup(unknown_str));
99 
100 	if ((label_to_str(sl, &sl_str, M_LABEL, DEF_NAMES) != 0) &&
101 	    (label_to_str(sl, &sl_str, M_INTERNAL, DEF_NAMES) != 0))
102 		return (strdup(unknown_str));
103 
104 	return (sl_str);
105 }
106 
107 static const char *rtsa_keywords[] = {
108 #define	SAK_MINSL	0
109 	"min_sl",
110 #define	SAK_MAXSL	1
111 	"max_sl",
112 #define	SAK_DOI		2
113 	"doi",
114 #define	SAK_CIPSO	3
115 	"cipso",
116 #define	SAK_SL		4
117 	"sl",
118 #define	SAK_INVAL	5
119 	NULL
120 };
121 
122 const char *
123 rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
124 {
125 	size_t slen;
126 	uint32_t mask, i;
127 	char *sl_str = NULL;
128 
129 	slen = 0;
130 	*line = '\0';
131 	mask = rtsa->rtsa_mask;
132 
133 	for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
134 		if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
135 			continue;
136 		if (!(i & mask))
137 			continue;
138 		if (slen != 0)
139 			line[slen++] = ',';
140 		switch (i & mask) {
141 		case RTSA_MINSL:
142 			if ((mask & RTSA_MAXSL) &&
143 			    blequal(&rtsa->rtsa_slrange.lower_bound,
144 			    &rtsa->rtsa_slrange.upper_bound)) {
145 
146 				sl_str =
147 				    sl_to_str(&rtsa->rtsa_slrange.lower_bound);
148 				slen += snprintf(line + slen, len - slen,
149 				    "sl=%s", sl_str);
150 				free(sl_str);
151 				sl_str = NULL;
152 				mask ^= RTSA_MAXSL;
153 				break;
154 			}
155 			sl_str = sl_to_str(&rtsa->rtsa_slrange.lower_bound);
156 			slen += snprintf(line + slen, len - slen, "min_sl=%s",
157 			    sl_str);
158 			free(sl_str);
159 			sl_str = NULL;
160 			break;
161 		case RTSA_MAXSL:
162 			sl_str = sl_to_str(&rtsa->rtsa_slrange.upper_bound);
163 			slen += snprintf(line + slen, len - slen, "max_sl=%s",
164 			    sl_str);
165 			free(sl_str);
166 			sl_str = NULL;
167 			break;
168 		case RTSA_DOI:
169 			slen += snprintf(line + slen, len - slen, "doi=%d",
170 			    rtsa->rtsa_doi);
171 			break;
172 		case RTSA_CIPSO:
173 			slen += snprintf(line + slen, len - slen, "cipso");
174 			break;
175 		}
176 	}
177 
178 	return (line);
179 }
180 
181 boolean_t
182 rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
183 {
184 	const char *valptr, *nxtopt;
185 	uint32_t mask = 0, doi;
186 	int key;
187 	m_label_t *min_sl = NULL, *max_sl = NULL;
188 	char attrbuf[MAX_ATTR_LEN];
189 	const char **keyword;
190 	int err;
191 	char *errstr, *cp;
192 
193 	if (errp == NULL)
194 		errp = &err;
195 	if (errstrp == NULL)
196 		errstrp = &errstr;
197 
198 	*errstrp = (char *)options;
199 
200 	while (*options != '\0') {
201 		valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
202 
203 		if (attrbuf[0] == '\0') {
204 			*errstrp = (char *)options;
205 			*errp = LTSNET_ILL_ENTRY;
206 			goto out_err;
207 		}
208 		for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
209 			if (strcmp(*keyword, attrbuf) == 0)
210 				break;
211 		if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
212 			*errstrp = (char *)options;
213 			*errp = LTSNET_ILL_KEY;
214 			goto out_err;
215 		}
216 		if ((key == SAK_CIPSO && *valptr == '=') ||
217 		    (key != SAK_CIPSO && *valptr != '=')) {
218 			*errstrp = (char *)valptr;
219 			*errp = LTSNET_ILL_VALDELIM;
220 			goto out_err;
221 		}
222 
223 		nxtopt = valptr;
224 		if (*valptr == '=') {
225 			valptr++;
226 			nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
227 			    valptr, ",=");
228 			if (*nxtopt == '=') {
229 				*errstrp = (char *)nxtopt;
230 				*errp = LTSNET_ILL_KEYDELIM;
231 				goto out_err;
232 			}
233 		}
234 		if (*nxtopt == ',')
235 			nxtopt++;
236 
237 		switch (key) {
238 		case SAK_MINSL:
239 			if (mask & RTSA_MINSL) {
240 				*errstrp = (char *)options;
241 				*errp = LTSNET_DUP_KEY;
242 				goto out_err;
243 			}
244 			m_label_free(min_sl);		/* in case of duplicate */
245 			min_sl = NULL;
246 			if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
247 			    L_NO_CORRECTION, NULL) != 0) {
248 				*errstrp = (char *)valptr;
249 				*errp = LTSNET_ILL_LOWERBOUND;
250 				goto out_err;
251 			}
252 			mask |= RTSA_MINSL;
253 			break;
254 
255 		case SAK_MAXSL:
256 			if (mask & RTSA_MAXSL) {
257 				*errstrp = (char *)options;
258 				*errp = LTSNET_DUP_KEY;
259 				goto out_err;
260 			}
261 			m_label_free(max_sl);		/* in case of duplicate */
262 			max_sl = NULL;
263 			if (str_to_label(attrbuf, &max_sl, MAC_LABEL,
264 			    L_NO_CORRECTION, NULL) != 0) {
265 				*errstrp = (char *)valptr;
266 				*errp = LTSNET_ILL_UPPERBOUND;
267 				goto out_err;
268 			}
269 			mask |= RTSA_MAXSL;
270 			break;
271 
272 		case SAK_SL:
273 			if (mask & (RTSA_MAXSL|RTSA_MINSL)) {
274 				*errstrp = (char *)options;
275 				*errp = LTSNET_DUP_KEY;
276 				goto out_err;
277 			}
278 			m_label_free(min_sl);		/* in case of duplicate */
279 			min_sl = NULL;
280 			if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
281 			    L_NO_CORRECTION, NULL) != 0) {
282 				*errstrp = (char *)valptr;
283 				*errp = LTSNET_ILL_LABEL;
284 				goto out_err;
285 			}
286 			*max_sl = *min_sl;
287 			mask |= (RTSA_MINSL | RTSA_MAXSL);
288 			break;
289 
290 		case SAK_DOI:
291 			if (mask & RTSA_DOI) {
292 				*errstrp = (char *)options;
293 				*errp = LTSNET_DUP_KEY;
294 				goto out_err;
295 			}
296 			errno = 0;
297 			doi = strtoul(attrbuf, &cp, 0);
298 			if (doi == 0 || errno != 0 || *cp != '\0') {
299 				*errstrp = (char *)valptr;
300 				*errp = LTSNET_ILL_DOI;
301 				goto out_err;
302 			}
303 			mask |= RTSA_DOI;
304 			break;
305 
306 		case SAK_CIPSO:
307 			if (mask & RTSA_CIPSO) {
308 				*errstrp = (char *)options;
309 				*errp = LTSNET_DUP_KEY;
310 				goto out_err;
311 			}
312 			mask |= RTSA_CIPSO;
313 			break;
314 		}
315 
316 		options = nxtopt;
317 	}
318 
319 	/* Defaults to CIPSO if not specified */
320 	mask |= RTSA_CIPSO;
321 
322 	/* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
323 	if (!(mask & RTSA_DOI)) {
324 		*errp = LTSNET_NO_DOI;
325 		goto out_err;
326 	}
327 
328 	/* SL range must be specified */
329 	if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
330 		*errp = LTSNET_NO_RANGE;
331 		goto out_err;
332 	}
333 	if (!(mask & RTSA_MINSL)) {
334 		*errp = LTSNET_NO_LOWERBOUND;
335 		goto out_err;
336 	}
337 	if (!(mask & RTSA_MAXSL)) {
338 		*errp = LTSNET_NO_UPPERBOUND;
339 		goto out_err;
340 	}
341 
342 	/* SL range must have upper bound dominating lower bound */
343 	if (!bldominates(max_sl, min_sl)) {
344 		*errp = LTSNET_ILL_RANGE;
345 		goto out_err;
346 	}
347 
348 	if (mask & RTSA_MINSL)
349 		sp->rtsa_slrange.lower_bound = *min_sl;
350 	if (mask & RTSA_MAXSL)
351 		sp->rtsa_slrange.upper_bound = *max_sl;
352 	if (mask & RTSA_DOI)
353 		sp->rtsa_doi = doi;
354 	sp->rtsa_mask = mask;
355 
356 	m_label_free(min_sl);
357 	m_label_free(max_sl);
358 
359 	return (B_TRUE);
360 
361 out_err:
362 	m_label_free(min_sl);
363 	m_label_free(max_sl);
364 
365 	return (B_FALSE);
366 }
367 
368 /* Keep in sync with libtsnet.h */
369 static const char *tsol_errlist[] = {
370 	"No error",
371 	"System error",
372 	"Empty string or end of list",
373 	"Entry is malformed",
374 	"Missing name",
375 	"Missing attributes",
376 	"Illegal name",
377 	"Illegal keyword delimiter",
378 	"Unknown keyword",
379 	"Duplicate keyword",
380 	"Illegal value delimiter",
381 	"Missing host type",
382 	"Illegal host type",
383 	"Missing label",
384 	"Illegal label",
385 	"Missing label range",
386 	"Illegal label range",
387 	"No lower bound in range",
388 	"Illegal lower bound in range",
389 	"No upper bound in range",
390 	"Illegal upper bound in range",
391 	"Missing DOI",
392 	"Illegal DOI",
393 	"Too many entries in set",
394 	"Missing address/network",
395 	"Illegal address/network",
396 	"Illegal flag",
397 	"Illegal MLP specification",
398 	"Unacceptable keyword for type"
399 };
400 static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
401 
402 const char *
403 tsol_strerror(int libtserr, int errnoval)
404 {
405 	if (libtserr == LTSNET_SYSERR)
406 		return (strerror(errnoval));
407 	if (libtserr >= 0 && libtserr < tsol_nerr)
408 		return (gettext(tsol_errlist[libtserr]));
409 	return (gettext("Unknown error"));
410 }
411