xref: /titanic_44/usr/src/lib/libtsnet/common/misc.c (revision e34b029407ed5ec566196ede3f54256d7868dd10)
145916cd2Sjpk /*
245916cd2Sjpk  * CDDL HEADER START
345916cd2Sjpk  *
445916cd2Sjpk  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
745916cd2Sjpk  *
845916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
945916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
1045916cd2Sjpk  * See the License for the specific language governing permissions
1145916cd2Sjpk  * and limitations under the License.
1245916cd2Sjpk  *
1345916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
1445916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1545916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
1645916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
1745916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
1845916cd2Sjpk  *
1945916cd2Sjpk  * CDDL HEADER END
2045916cd2Sjpk  */
2145916cd2Sjpk /*
2245916cd2Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2345916cd2Sjpk  * Use is subject to license terms.
2445916cd2Sjpk  *
2545916cd2Sjpk  * From "misc.c	5.15	00/05/31 SMI; TSOL 2.x"
2645916cd2Sjpk  */
2745916cd2Sjpk 
2845916cd2Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
2945916cd2Sjpk 
3045916cd2Sjpk /*
3145916cd2Sjpk  *	Miscellaneous user interfaces to trusted label functions.
3245916cd2Sjpk  */
3345916cd2Sjpk 
3445916cd2Sjpk 
3545916cd2Sjpk #include <ctype.h>
3645916cd2Sjpk #include <stdio.h>
3745916cd2Sjpk #include <stdlib.h>
3845916cd2Sjpk #include <strings.h>
3945916cd2Sjpk #include <errno.h>
4045916cd2Sjpk #include <libintl.h>
4145916cd2Sjpk #include <libtsnet.h>
4245916cd2Sjpk #include <tsol/label.h>
4345916cd2Sjpk 
4445916cd2Sjpk #include <net/route.h>
4545916cd2Sjpk 
4645916cd2Sjpk #define	MAX_STRING_SIZE 256
4745916cd2Sjpk #define	MAX_ATTR_LEN	1024
4845916cd2Sjpk 
4945916cd2Sjpk /*
5045916cd2Sjpk  * Parse off an entry from a line.  Entry is stored in 'outbuf'.  Returned
5145916cd2Sjpk  * value is a pointer to the first unprocessed input character from 'instr'.
5245916cd2Sjpk  */
5345916cd2Sjpk const char *
5445916cd2Sjpk parse_entry(char *outbuf, size_t outlen, const char *instr,
5545916cd2Sjpk     const char *delimit)
5645916cd2Sjpk {
5745916cd2Sjpk 	boolean_t escape_state = B_FALSE;
5845916cd2Sjpk 	boolean_t any_white;
5945916cd2Sjpk 	char chr;
6045916cd2Sjpk 
6145916cd2Sjpk 	any_white = strchr(delimit, '\n') != NULL;
6245916cd2Sjpk 
6345916cd2Sjpk 	/*
6445916cd2Sjpk 	 * User may specify outlen as 0 to skip over a field without storing
6545916cd2Sjpk 	 * it anywhere.  Otherwise, we need at least one byte for the
6645916cd2Sjpk 	 * terminating NUL plus one byte to store another byte from instr.
6745916cd2Sjpk 	 */
6845916cd2Sjpk 	while (outlen != 1 && (chr = *instr++) != '\0') {
6945916cd2Sjpk 		if (!escape_state) {
7045916cd2Sjpk 			if (chr == '\\') {
7145916cd2Sjpk 				escape_state = B_TRUE;
7245916cd2Sjpk 				continue;
7345916cd2Sjpk 			}
7445916cd2Sjpk 			if (strchr(delimit, chr) != NULL)
7545916cd2Sjpk 				break;
7645916cd2Sjpk 			if (any_white && isspace(chr))
7745916cd2Sjpk 				break;
7845916cd2Sjpk 		}
7945916cd2Sjpk 		escape_state = B_FALSE;
8045916cd2Sjpk 		if (outlen > 0) {
8145916cd2Sjpk 			*outbuf++ = chr;
8245916cd2Sjpk 			outlen--;
8345916cd2Sjpk 		}
8445916cd2Sjpk 	}
8545916cd2Sjpk 	if (outlen != 1)
8645916cd2Sjpk 		instr--;
8745916cd2Sjpk 	if (escape_state)
8845916cd2Sjpk 		instr--;
8945916cd2Sjpk 	if (outlen > 0)
9045916cd2Sjpk 		*outbuf = '\0';
9145916cd2Sjpk 	return (instr);
9245916cd2Sjpk }
9345916cd2Sjpk 
9445916cd2Sjpk const char *
9545916cd2Sjpk sl_to_str(const bslabel_t *sl)
9645916cd2Sjpk {
9745916cd2Sjpk 	const char *sl_str;
9845916cd2Sjpk 	static const char unknown_str[] = "UNKNOWN";
9945916cd2Sjpk 
10045916cd2Sjpk 	if (sl == NULL)
10145916cd2Sjpk 		return (unknown_str);
10245916cd2Sjpk 
10345916cd2Sjpk 	if ((sl_str = sbsltos(sl, MAX_STRING_SIZE)) == NULL &&
10445916cd2Sjpk 	    (sl_str = bsltoh(sl)) == NULL)
10545916cd2Sjpk 		sl_str = unknown_str;
10645916cd2Sjpk 	return (sl_str);
10745916cd2Sjpk }
10845916cd2Sjpk 
10945916cd2Sjpk static const char *rtsa_keywords[] = {
11045916cd2Sjpk #define	SAK_MINSL	0
11145916cd2Sjpk 	"min_sl",
11245916cd2Sjpk #define	SAK_MAXSL	1
11345916cd2Sjpk 	"max_sl",
11445916cd2Sjpk #define	SAK_DOI		2
11545916cd2Sjpk 	"doi",
11645916cd2Sjpk #define	SAK_CIPSO	3
11745916cd2Sjpk 	"cipso",
118*e34b0294Swy83408 #define	SAK_SL		4
119*e34b0294Swy83408 	"sl",
120*e34b0294Swy83408 #define	SAK_INVAL	5
12145916cd2Sjpk 	NULL
12245916cd2Sjpk };
12345916cd2Sjpk 
12445916cd2Sjpk const char *
12545916cd2Sjpk rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
12645916cd2Sjpk {
12745916cd2Sjpk 	size_t slen;
12845916cd2Sjpk 	uint32_t mask, i;
12945916cd2Sjpk 
13045916cd2Sjpk 	slen = 0;
13145916cd2Sjpk 	*line = '\0';
13245916cd2Sjpk 	mask = rtsa->rtsa_mask;
13345916cd2Sjpk 
13445916cd2Sjpk 	for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
13545916cd2Sjpk 		if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
13645916cd2Sjpk 			continue;
13745916cd2Sjpk 		if (!(i & mask))
13845916cd2Sjpk 			continue;
13945916cd2Sjpk 		if (slen != 0)
14045916cd2Sjpk 			line[slen++] = ',';
14145916cd2Sjpk 		switch (i & mask) {
14245916cd2Sjpk 		case RTSA_MINSL:
143*e34b0294Swy83408 			if ((mask & RTSA_MAXSL) &&
144*e34b0294Swy83408 			    blequal(&rtsa->rtsa_slrange.lower_bound,
145*e34b0294Swy83408 			    &rtsa->rtsa_slrange.upper_bound)) {
146*e34b0294Swy83408 				slen += snprintf(line + slen, len - slen,
147*e34b0294Swy83408 				    "sl=%s",
148*e34b0294Swy83408 				    sl_to_str(&rtsa->rtsa_slrange.lower_bound));
149*e34b0294Swy83408 				mask ^= RTSA_MAXSL;
150*e34b0294Swy83408 				break;
151*e34b0294Swy83408 			}
15245916cd2Sjpk 			slen += snprintf(line + slen, len - slen, "min_sl=%s",
15345916cd2Sjpk 			    sl_to_str(&rtsa->rtsa_slrange.lower_bound));
15445916cd2Sjpk 			break;
15545916cd2Sjpk 		case RTSA_MAXSL:
15645916cd2Sjpk 			slen += snprintf(line + slen, len - slen, "max_sl=%s",
15745916cd2Sjpk 			    sl_to_str(&rtsa->rtsa_slrange.upper_bound));
15845916cd2Sjpk 			break;
15945916cd2Sjpk 		case RTSA_DOI:
16045916cd2Sjpk 			slen += snprintf(line + slen, len - slen, "doi=%d",
16145916cd2Sjpk 			    rtsa->rtsa_doi);
16245916cd2Sjpk 			break;
16345916cd2Sjpk 		case RTSA_CIPSO:
16445916cd2Sjpk 			slen += snprintf(line + slen, len - slen, "cipso");
16545916cd2Sjpk 			break;
16645916cd2Sjpk 		}
16745916cd2Sjpk 	}
16845916cd2Sjpk 
16945916cd2Sjpk 	return (line);
17045916cd2Sjpk }
17145916cd2Sjpk 
17245916cd2Sjpk boolean_t
17345916cd2Sjpk rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
17445916cd2Sjpk {
17545916cd2Sjpk 	const char *valptr, *nxtopt;
17645916cd2Sjpk 	uint32_t mask = 0, doi;
17745916cd2Sjpk 	int key;
17845916cd2Sjpk 	bslabel_t min_sl, max_sl;
17945916cd2Sjpk 	char attrbuf[MAX_ATTR_LEN];
18045916cd2Sjpk 	const char **keyword;
18145916cd2Sjpk 	int err;
18245916cd2Sjpk 	char *errstr, *cp;
18345916cd2Sjpk 
18445916cd2Sjpk 	if (errp == NULL)
18545916cd2Sjpk 		errp = &err;
18645916cd2Sjpk 	if (errstrp == NULL)
18745916cd2Sjpk 		errstrp = &errstr;
18845916cd2Sjpk 
18945916cd2Sjpk 	*errstrp = (char *)options;
19045916cd2Sjpk 
19145916cd2Sjpk 	while (*options != '\0') {
19245916cd2Sjpk 		valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
19345916cd2Sjpk 
19445916cd2Sjpk 		if (attrbuf[0] == '\0') {
19545916cd2Sjpk 			*errstrp = (char *)options;
19645916cd2Sjpk 			*errp = LTSNET_ILL_ENTRY;
19745916cd2Sjpk 			return (B_FALSE);
19845916cd2Sjpk 		}
19945916cd2Sjpk 		for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
20045916cd2Sjpk 			if (strcmp(*keyword, attrbuf) == 0)
20145916cd2Sjpk 				break;
20245916cd2Sjpk 		if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
20345916cd2Sjpk 			*errstrp = (char *)options;
20445916cd2Sjpk 			*errp = LTSNET_ILL_KEY;
20545916cd2Sjpk 			return (B_FALSE);
20645916cd2Sjpk 		}
20745916cd2Sjpk 		if ((key == SAK_CIPSO && *valptr == '=') ||
20845916cd2Sjpk 		    (key != SAK_CIPSO && *valptr != '=')) {
20945916cd2Sjpk 			*errstrp = (char *)valptr;
21045916cd2Sjpk 			*errp = LTSNET_ILL_VALDELIM;
21145916cd2Sjpk 			return (B_FALSE);
21245916cd2Sjpk 		}
21345916cd2Sjpk 
21445916cd2Sjpk 		nxtopt = valptr;
21545916cd2Sjpk 		if (*valptr == '=') {
21645916cd2Sjpk 			valptr++;
21745916cd2Sjpk 			nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
21845916cd2Sjpk 			    valptr, ",=");
21945916cd2Sjpk 			if (*nxtopt == '=') {
22045916cd2Sjpk 				*errstrp = (char *)nxtopt;
22145916cd2Sjpk 				*errp = LTSNET_ILL_KEYDELIM;
22245916cd2Sjpk 				return (B_FALSE);
22345916cd2Sjpk 			}
22445916cd2Sjpk 		}
22545916cd2Sjpk 		if (*nxtopt == ',')
22645916cd2Sjpk 			nxtopt++;
22745916cd2Sjpk 
22845916cd2Sjpk 		switch (key) {
22945916cd2Sjpk 		case SAK_MINSL:
23045916cd2Sjpk 			if (mask & RTSA_MINSL) {
23145916cd2Sjpk 				*errstrp = (char *)options;
23245916cd2Sjpk 				*errp = LTSNET_DUP_KEY;
23345916cd2Sjpk 				return (B_FALSE);
23445916cd2Sjpk 			}
23545916cd2Sjpk 			if (stobsl(attrbuf, &min_sl, NO_CORRECTION,
23645916cd2Sjpk 			    &err) != 1) {
23745916cd2Sjpk 				*errstrp = (char *)valptr;
23845916cd2Sjpk 				*errp = LTSNET_ILL_LOWERBOUND;
23945916cd2Sjpk 				return (B_FALSE);
24045916cd2Sjpk 			}
24145916cd2Sjpk 			mask |= RTSA_MINSL;
24245916cd2Sjpk 			break;
24345916cd2Sjpk 
24445916cd2Sjpk 		case SAK_MAXSL:
24545916cd2Sjpk 			if (mask & RTSA_MAXSL) {
24645916cd2Sjpk 				*errstrp = (char *)options;
24745916cd2Sjpk 				*errp = LTSNET_DUP_KEY;
24845916cd2Sjpk 				return (B_FALSE);
24945916cd2Sjpk 			}
25045916cd2Sjpk 			if (stobsl(attrbuf, &max_sl, NO_CORRECTION,
25145916cd2Sjpk 			    &err) != 1) {
25245916cd2Sjpk 				*errstrp = (char *)valptr;
25345916cd2Sjpk 				*errp = LTSNET_ILL_UPPERBOUND;
25445916cd2Sjpk 				return (B_FALSE);
25545916cd2Sjpk 			}
25645916cd2Sjpk 			mask |= RTSA_MAXSL;
25745916cd2Sjpk 			break;
25845916cd2Sjpk 
259*e34b0294Swy83408 		case SAK_SL:
260*e34b0294Swy83408 			if (mask & (RTSA_MAXSL|RTSA_MINSL)) {
261*e34b0294Swy83408 				*errstrp = (char *)options;
262*e34b0294Swy83408 				*errp = LTSNET_DUP_KEY;
263*e34b0294Swy83408 				return (B_FALSE);
264*e34b0294Swy83408 			}
265*e34b0294Swy83408 			if (stobsl(attrbuf, &min_sl, NO_CORRECTION,
266*e34b0294Swy83408 			    &err) != 1) {
267*e34b0294Swy83408 				*errstrp = (char *)valptr;
268*e34b0294Swy83408 				*errp = LTSNET_ILL_LABEL;
269*e34b0294Swy83408 				return (B_FALSE);
270*e34b0294Swy83408 			}
271*e34b0294Swy83408 			bcopy(&min_sl, &max_sl, sizeof (bslabel_t));
272*e34b0294Swy83408 			mask |= (RTSA_MINSL | RTSA_MAXSL);
273*e34b0294Swy83408 			break;
274*e34b0294Swy83408 
27545916cd2Sjpk 		case SAK_DOI:
27645916cd2Sjpk 			if (mask & RTSA_DOI) {
27745916cd2Sjpk 				*errstrp = (char *)options;
27845916cd2Sjpk 				*errp = LTSNET_DUP_KEY;
27945916cd2Sjpk 				return (B_FALSE);
28045916cd2Sjpk 			}
28145916cd2Sjpk 			errno = 0;
28245916cd2Sjpk 			doi = strtoul(attrbuf, &cp, 0);
28345916cd2Sjpk 			if (doi == 0 || errno != 0 || *cp != '\0') {
28445916cd2Sjpk 				*errstrp = (char *)valptr;
28545916cd2Sjpk 				*errp = LTSNET_ILL_DOI;
28645916cd2Sjpk 				return (B_FALSE);
28745916cd2Sjpk 			}
28845916cd2Sjpk 			mask |= RTSA_DOI;
28945916cd2Sjpk 			break;
29045916cd2Sjpk 
29145916cd2Sjpk 		case SAK_CIPSO:
29245916cd2Sjpk 			if (mask & RTSA_CIPSO) {
29345916cd2Sjpk 				*errstrp = (char *)options;
29445916cd2Sjpk 				*errp = LTSNET_DUP_KEY;
29545916cd2Sjpk 				return (B_FALSE);
29645916cd2Sjpk 			}
29745916cd2Sjpk 			mask |= RTSA_CIPSO;
29845916cd2Sjpk 			break;
29945916cd2Sjpk 		}
30045916cd2Sjpk 
30145916cd2Sjpk 		options = nxtopt;
30245916cd2Sjpk 	}
30345916cd2Sjpk 
30445916cd2Sjpk 	/* Defaults to CIPSO if not specified */
30545916cd2Sjpk 	mask |= RTSA_CIPSO;
30645916cd2Sjpk 
30745916cd2Sjpk 	/* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
30845916cd2Sjpk 	if (!(mask & RTSA_DOI)) {
30945916cd2Sjpk 		*errp = LTSNET_NO_DOI;
31045916cd2Sjpk 		return (B_FALSE);
31145916cd2Sjpk 	}
31245916cd2Sjpk 
31345916cd2Sjpk 	/* SL range must be specified */
31445916cd2Sjpk 	if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
31545916cd2Sjpk 		*errp = LTSNET_NO_RANGE;
31645916cd2Sjpk 		return (B_FALSE);
31745916cd2Sjpk 	}
31845916cd2Sjpk 	if (!(mask & RTSA_MINSL)) {
31945916cd2Sjpk 		*errp = LTSNET_NO_LOWERBOUND;
32045916cd2Sjpk 		return (B_FALSE);
32145916cd2Sjpk 	}
32245916cd2Sjpk 	if (!(mask & RTSA_MAXSL)) {
32345916cd2Sjpk 		*errp = LTSNET_NO_UPPERBOUND;
32445916cd2Sjpk 		return (B_FALSE);
32545916cd2Sjpk 	}
32645916cd2Sjpk 
32745916cd2Sjpk 	/* SL range must have upper bound dominating lower bound */
32845916cd2Sjpk 	if (!bldominates(&max_sl, &min_sl)) {
32945916cd2Sjpk 		*errp = LTSNET_ILL_RANGE;
33045916cd2Sjpk 		return (B_FALSE);
33145916cd2Sjpk 	}
33245916cd2Sjpk 
33345916cd2Sjpk 	if (mask & RTSA_MINSL)
33445916cd2Sjpk 		sp->rtsa_slrange.lower_bound = min_sl;
33545916cd2Sjpk 	if (mask & RTSA_MAXSL)
33645916cd2Sjpk 		sp->rtsa_slrange.upper_bound = max_sl;
33745916cd2Sjpk 	if (mask & RTSA_DOI)
33845916cd2Sjpk 		sp->rtsa_doi = doi;
33945916cd2Sjpk 	sp->rtsa_mask = mask;
34045916cd2Sjpk 
34145916cd2Sjpk 	return (B_TRUE);
34245916cd2Sjpk }
34345916cd2Sjpk 
34445916cd2Sjpk /* Keep in sync with libtsnet.h */
34545916cd2Sjpk static const char *tsol_errlist[] = {
34645916cd2Sjpk 	"No error",
34745916cd2Sjpk 	"System error",
34845916cd2Sjpk 	"Empty string or end of list",
34945916cd2Sjpk 	"Entry is malformed",
35045916cd2Sjpk 	"Missing name",
35145916cd2Sjpk 	"Missing attributes",
35245916cd2Sjpk 	"Illegal name",
35345916cd2Sjpk 	"Illegal keyword delimiter",
35445916cd2Sjpk 	"Unknown keyword",
35545916cd2Sjpk 	"Duplicate keyword",
35645916cd2Sjpk 	"Illegal value delimiter",
35745916cd2Sjpk 	"Missing host type",
35845916cd2Sjpk 	"Illegal host type",
35945916cd2Sjpk 	"Missing label",
36045916cd2Sjpk 	"Illegal label",
36145916cd2Sjpk 	"Missing label range",
36245916cd2Sjpk 	"Illegal label range",
36345916cd2Sjpk 	"No lower bound in range",
36445916cd2Sjpk 	"Illegal lower bound in range",
36545916cd2Sjpk 	"No upper bound in range",
36645916cd2Sjpk 	"Illegal upper bound in range",
36745916cd2Sjpk 	"Missing DOI",
36845916cd2Sjpk 	"Illegal DOI",
36945916cd2Sjpk 	"Too many entries in set",
37045916cd2Sjpk 	"Missing address/network",
37145916cd2Sjpk 	"Illegal address/network",
37245916cd2Sjpk 	"Illegal flag",
37345916cd2Sjpk 	"Illegal MLP specification",
37445916cd2Sjpk 	"Unacceptable keyword for type"
37545916cd2Sjpk };
37645916cd2Sjpk static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
37745916cd2Sjpk 
37845916cd2Sjpk const char *
37945916cd2Sjpk tsol_strerror(int libtserr, int errnoval)
38045916cd2Sjpk {
38145916cd2Sjpk 	if (libtserr == LTSNET_SYSERR)
38245916cd2Sjpk 		return (strerror(errnoval));
38345916cd2Sjpk 	if (libtserr >= 0 && libtserr < tsol_nerr)
38445916cd2Sjpk 		return (gettext(tsol_errlist[libtserr]));
38545916cd2Sjpk 	return (gettext("Unknown error"));
38645916cd2Sjpk }
387