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