xref: /illumos-gate/usr/src/lib/libtsnet/common/misc.c (revision 80ab886d)
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_INVAL	4
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 
128 	slen = 0;
129 	*line = '\0';
130 	mask = rtsa->rtsa_mask;
131 
132 	for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
133 		if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
134 			continue;
135 		if (!(i & mask))
136 			continue;
137 		if (slen != 0)
138 			line[slen++] = ',';
139 		switch (i & mask) {
140 		case RTSA_MINSL:
141 			slen += snprintf(line + slen, len - slen, "min_sl=%s",
142 			    sl_to_str(&rtsa->rtsa_slrange.lower_bound));
143 			break;
144 		case RTSA_MAXSL:
145 			slen += snprintf(line + slen, len - slen, "max_sl=%s",
146 			    sl_to_str(&rtsa->rtsa_slrange.upper_bound));
147 			break;
148 		case RTSA_DOI:
149 			slen += snprintf(line + slen, len - slen, "doi=%d",
150 			    rtsa->rtsa_doi);
151 			break;
152 		case RTSA_CIPSO:
153 			slen += snprintf(line + slen, len - slen, "cipso");
154 			break;
155 		}
156 	}
157 
158 	return (line);
159 }
160 
161 boolean_t
162 rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
163 {
164 	const char *valptr, *nxtopt;
165 	uint32_t mask = 0, doi;
166 	int key;
167 	bslabel_t min_sl, max_sl;
168 	char attrbuf[MAX_ATTR_LEN];
169 	const char **keyword;
170 	int err;
171 	char *errstr, *cp;
172 
173 	if (errp == NULL)
174 		errp = &err;
175 	if (errstrp == NULL)
176 		errstrp = &errstr;
177 
178 	*errstrp = (char *)options;
179 
180 	while (*options != '\0') {
181 		valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
182 
183 		if (attrbuf[0] == '\0') {
184 			*errstrp = (char *)options;
185 			*errp = LTSNET_ILL_ENTRY;
186 			return (B_FALSE);
187 		}
188 		for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
189 			if (strcmp(*keyword, attrbuf) == 0)
190 				break;
191 		if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
192 			*errstrp = (char *)options;
193 			*errp = LTSNET_ILL_KEY;
194 			return (B_FALSE);
195 		}
196 		if ((key == SAK_CIPSO && *valptr == '=') ||
197 		    (key != SAK_CIPSO && *valptr != '=')) {
198 			*errstrp = (char *)valptr;
199 			*errp = LTSNET_ILL_VALDELIM;
200 			return (B_FALSE);
201 		}
202 
203 		nxtopt = valptr;
204 		if (*valptr == '=') {
205 			valptr++;
206 			nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
207 			    valptr, ",=");
208 			if (*nxtopt == '=') {
209 				*errstrp = (char *)nxtopt;
210 				*errp = LTSNET_ILL_KEYDELIM;
211 				return (B_FALSE);
212 			}
213 		}
214 		if (*nxtopt == ',')
215 			nxtopt++;
216 
217 		switch (key) {
218 		case SAK_MINSL:
219 			if (mask & RTSA_MINSL) {
220 				*errstrp = (char *)options;
221 				*errp = LTSNET_DUP_KEY;
222 				return (B_FALSE);
223 			}
224 			if (stobsl(attrbuf, &min_sl, NO_CORRECTION,
225 			    &err) != 1) {
226 				*errstrp = (char *)valptr;
227 				*errp = LTSNET_ILL_LOWERBOUND;
228 				return (B_FALSE);
229 			}
230 			mask |= RTSA_MINSL;
231 			break;
232 
233 		case SAK_MAXSL:
234 			if (mask & RTSA_MAXSL) {
235 				*errstrp = (char *)options;
236 				*errp = LTSNET_DUP_KEY;
237 				return (B_FALSE);
238 			}
239 			if (stobsl(attrbuf, &max_sl, NO_CORRECTION,
240 			    &err) != 1) {
241 				*errstrp = (char *)valptr;
242 				*errp = LTSNET_ILL_UPPERBOUND;
243 				return (B_FALSE);
244 			}
245 			mask |= RTSA_MAXSL;
246 			break;
247 
248 		case SAK_DOI:
249 			if (mask & RTSA_DOI) {
250 				*errstrp = (char *)options;
251 				*errp = LTSNET_DUP_KEY;
252 				return (B_FALSE);
253 			}
254 			errno = 0;
255 			doi = strtoul(attrbuf, &cp, 0);
256 			if (doi == 0 || errno != 0 || *cp != '\0') {
257 				*errstrp = (char *)valptr;
258 				*errp = LTSNET_ILL_DOI;
259 				return (B_FALSE);
260 			}
261 			mask |= RTSA_DOI;
262 			break;
263 
264 		case SAK_CIPSO:
265 			if (mask & RTSA_CIPSO) {
266 				*errstrp = (char *)options;
267 				*errp = LTSNET_DUP_KEY;
268 				return (B_FALSE);
269 			}
270 			mask |= RTSA_CIPSO;
271 			break;
272 		}
273 
274 		options = nxtopt;
275 	}
276 
277 	/* Defaults to CIPSO if not specified */
278 	mask |= RTSA_CIPSO;
279 
280 	/* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
281 	if (!(mask & RTSA_DOI)) {
282 		*errp = LTSNET_NO_DOI;
283 		return (B_FALSE);
284 	}
285 
286 	/* SL range must be specified */
287 	if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
288 		*errp = LTSNET_NO_RANGE;
289 		return (B_FALSE);
290 	}
291 	if (!(mask & RTSA_MINSL)) {
292 		*errp = LTSNET_NO_LOWERBOUND;
293 		return (B_FALSE);
294 	}
295 	if (!(mask & RTSA_MAXSL)) {
296 		*errp = LTSNET_NO_UPPERBOUND;
297 		return (B_FALSE);
298 	}
299 
300 	/* SL range must have upper bound dominating lower bound */
301 	if (!bldominates(&max_sl, &min_sl)) {
302 		*errp = LTSNET_ILL_RANGE;
303 		return (B_FALSE);
304 	}
305 
306 	if (mask & RTSA_MINSL)
307 		sp->rtsa_slrange.lower_bound = min_sl;
308 	if (mask & RTSA_MAXSL)
309 		sp->rtsa_slrange.upper_bound = max_sl;
310 	if (mask & RTSA_DOI)
311 		sp->rtsa_doi = doi;
312 	sp->rtsa_mask = mask;
313 
314 	return (B_TRUE);
315 }
316 
317 /* Keep in sync with libtsnet.h */
318 static const char *tsol_errlist[] = {
319 	"No error",
320 	"System error",
321 	"Empty string or end of list",
322 	"Entry is malformed",
323 	"Missing name",
324 	"Missing attributes",
325 	"Illegal name",
326 	"Illegal keyword delimiter",
327 	"Unknown keyword",
328 	"Duplicate keyword",
329 	"Illegal value delimiter",
330 	"Missing host type",
331 	"Illegal host type",
332 	"Missing label",
333 	"Illegal label",
334 	"Missing label range",
335 	"Illegal label range",
336 	"No lower bound in range",
337 	"Illegal lower bound in range",
338 	"No upper bound in range",
339 	"Illegal upper bound in range",
340 	"Missing DOI",
341 	"Illegal DOI",
342 	"Too many entries in set",
343 	"Missing address/network",
344 	"Illegal address/network",
345 	"Illegal flag",
346 	"Illegal MLP specification",
347 	"Unacceptable keyword for type"
348 };
349 static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
350 
351 const char *
352 tsol_strerror(int libtserr, int errnoval)
353 {
354 	if (libtserr == LTSNET_SYSERR)
355 		return (strerror(errnoval));
356 	if (libtserr >= 0 && libtserr < tsol_nerr)
357 		return (gettext(tsol_errlist[libtserr]));
358 	return (gettext("Unknown error"));
359 }
360