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