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