xref: /onnv-gate/usr/src/lib/libtsnet/common/misc.c (revision 11561:e0d5740d4722)
11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
211676Sjpk /*
22*11561SRic.Aleshire@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
231676Sjpk  * Use is subject to license terms.
241676Sjpk  *
251676Sjpk  * From "misc.c	5.15	00/05/31 SMI; TSOL 2.x"
261676Sjpk  */
271676Sjpk 
281676Sjpk /*
291676Sjpk  *	Miscellaneous user interfaces to trusted label functions.
301676Sjpk  */
311676Sjpk 
321676Sjpk 
331676Sjpk #include <ctype.h>
341676Sjpk #include <stdio.h>
351676Sjpk #include <stdlib.h>
361676Sjpk #include <strings.h>
371676Sjpk #include <errno.h>
381676Sjpk #include <libintl.h>
391676Sjpk #include <libtsnet.h>
401676Sjpk #include <tsol/label.h>
411676Sjpk 
421676Sjpk #include <net/route.h>
431676Sjpk 
441676Sjpk #define	MAX_ATTR_LEN	1024
451676Sjpk 
461676Sjpk /*
471676Sjpk  * Parse off an entry from a line.  Entry is stored in 'outbuf'.  Returned
481676Sjpk  * value is a pointer to the first unprocessed input character from 'instr'.
491676Sjpk  */
501676Sjpk const char *
parse_entry(char * outbuf,size_t outlen,const char * instr,const char * delimit)511676Sjpk parse_entry(char *outbuf, size_t outlen, const char *instr,
521676Sjpk     const char *delimit)
531676Sjpk {
541676Sjpk 	boolean_t escape_state = B_FALSE;
551676Sjpk 	boolean_t any_white;
561676Sjpk 	char chr;
571676Sjpk 
581676Sjpk 	any_white = strchr(delimit, '\n') != NULL;
591676Sjpk 
601676Sjpk 	/*
611676Sjpk 	 * User may specify outlen as 0 to skip over a field without storing
621676Sjpk 	 * it anywhere.  Otherwise, we need at least one byte for the
631676Sjpk 	 * terminating NUL plus one byte to store another byte from instr.
641676Sjpk 	 */
651676Sjpk 	while (outlen != 1 && (chr = *instr++) != '\0') {
661676Sjpk 		if (!escape_state) {
671676Sjpk 			if (chr == '\\') {
681676Sjpk 				escape_state = B_TRUE;
691676Sjpk 				continue;
701676Sjpk 			}
711676Sjpk 			if (strchr(delimit, chr) != NULL)
721676Sjpk 				break;
731676Sjpk 			if (any_white && isspace(chr))
741676Sjpk 				break;
751676Sjpk 		}
761676Sjpk 		escape_state = B_FALSE;
771676Sjpk 		if (outlen > 0) {
781676Sjpk 			*outbuf++ = chr;
791676Sjpk 			outlen--;
801676Sjpk 		}
811676Sjpk 	}
821676Sjpk 	if (outlen != 1)
831676Sjpk 		instr--;
841676Sjpk 	if (escape_state)
851676Sjpk 		instr--;
861676Sjpk 	if (outlen > 0)
871676Sjpk 		*outbuf = '\0';
881676Sjpk 	return (instr);
891676Sjpk }
901676Sjpk 
91*11561SRic.Aleshire@Sun.COM char *
sl_to_str(const m_label_t * sl)92*11561SRic.Aleshire@Sun.COM sl_to_str(const m_label_t *sl)
931676Sjpk {
94*11561SRic.Aleshire@Sun.COM 	char *sl_str = NULL;
95*11561SRic.Aleshire@Sun.COM 	static char unknown_str[] = "UNKNOWN";
961676Sjpk 
971676Sjpk 	if (sl == NULL)
98*11561SRic.Aleshire@Sun.COM 		return (strdup(unknown_str));
991676Sjpk 
100*11561SRic.Aleshire@Sun.COM 	if ((label_to_str(sl, &sl_str, M_LABEL, DEF_NAMES) != 0) &&
101*11561SRic.Aleshire@Sun.COM 	    (label_to_str(sl, &sl_str, M_INTERNAL, DEF_NAMES) != 0))
102*11561SRic.Aleshire@Sun.COM 		return (strdup(unknown_str));
103*11561SRic.Aleshire@Sun.COM 
1041676Sjpk 	return (sl_str);
1051676Sjpk }
1061676Sjpk 
1071676Sjpk static const char *rtsa_keywords[] = {
1081676Sjpk #define	SAK_MINSL	0
1091676Sjpk 	"min_sl",
1101676Sjpk #define	SAK_MAXSL	1
1111676Sjpk 	"max_sl",
1121676Sjpk #define	SAK_DOI		2
1131676Sjpk 	"doi",
1141676Sjpk #define	SAK_CIPSO	3
1151676Sjpk 	"cipso",
1162304Swy83408 #define	SAK_SL		4
1172304Swy83408 	"sl",
1182304Swy83408 #define	SAK_INVAL	5
1191676Sjpk 	NULL
1201676Sjpk };
1211676Sjpk 
1221676Sjpk const char *
rtsa_to_str(const struct rtsa_s * rtsa,char * line,size_t len)1231676Sjpk rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
1241676Sjpk {
1251676Sjpk 	size_t slen;
1261676Sjpk 	uint32_t mask, i;
127*11561SRic.Aleshire@Sun.COM 	char *sl_str = NULL;
1281676Sjpk 
1291676Sjpk 	slen = 0;
1301676Sjpk 	*line = '\0';
1311676Sjpk 	mask = rtsa->rtsa_mask;
1321676Sjpk 
1331676Sjpk 	for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
1341676Sjpk 		if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
1351676Sjpk 			continue;
1361676Sjpk 		if (!(i & mask))
1371676Sjpk 			continue;
1381676Sjpk 		if (slen != 0)
1391676Sjpk 			line[slen++] = ',';
1401676Sjpk 		switch (i & mask) {
1411676Sjpk 		case RTSA_MINSL:
1422304Swy83408 			if ((mask & RTSA_MAXSL) &&
1432304Swy83408 			    blequal(&rtsa->rtsa_slrange.lower_bound,
1442304Swy83408 			    &rtsa->rtsa_slrange.upper_bound)) {
145*11561SRic.Aleshire@Sun.COM 
146*11561SRic.Aleshire@Sun.COM 				sl_str =
147*11561SRic.Aleshire@Sun.COM 				    sl_to_str(&rtsa->rtsa_slrange.lower_bound);
1482304Swy83408 				slen += snprintf(line + slen, len - slen,
149*11561SRic.Aleshire@Sun.COM 				    "sl=%s", sl_str);
150*11561SRic.Aleshire@Sun.COM 				free(sl_str);
151*11561SRic.Aleshire@Sun.COM 				sl_str = NULL;
1522304Swy83408 				mask ^= RTSA_MAXSL;
1532304Swy83408 				break;
1542304Swy83408 			}
155*11561SRic.Aleshire@Sun.COM 			sl_str = sl_to_str(&rtsa->rtsa_slrange.lower_bound);
1561676Sjpk 			slen += snprintf(line + slen, len - slen, "min_sl=%s",
157*11561SRic.Aleshire@Sun.COM 			    sl_str);
158*11561SRic.Aleshire@Sun.COM 			free(sl_str);
159*11561SRic.Aleshire@Sun.COM 			sl_str = NULL;
1601676Sjpk 			break;
1611676Sjpk 		case RTSA_MAXSL:
162*11561SRic.Aleshire@Sun.COM 			sl_str = sl_to_str(&rtsa->rtsa_slrange.upper_bound);
1631676Sjpk 			slen += snprintf(line + slen, len - slen, "max_sl=%s",
164*11561SRic.Aleshire@Sun.COM 			    sl_str);
165*11561SRic.Aleshire@Sun.COM 			free(sl_str);
166*11561SRic.Aleshire@Sun.COM 			sl_str = NULL;
1671676Sjpk 			break;
1681676Sjpk 		case RTSA_DOI:
1691676Sjpk 			slen += snprintf(line + slen, len - slen, "doi=%d",
1701676Sjpk 			    rtsa->rtsa_doi);
1711676Sjpk 			break;
1721676Sjpk 		case RTSA_CIPSO:
1731676Sjpk 			slen += snprintf(line + slen, len - slen, "cipso");
1741676Sjpk 			break;
1751676Sjpk 		}
1761676Sjpk 	}
1771676Sjpk 
1781676Sjpk 	return (line);
1791676Sjpk }
1801676Sjpk 
1811676Sjpk boolean_t
rtsa_keyword(const char * options,struct rtsa_s * sp,int * errp,char ** errstrp)1821676Sjpk rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
1831676Sjpk {
1841676Sjpk 	const char *valptr, *nxtopt;
1851676Sjpk 	uint32_t mask = 0, doi;
1861676Sjpk 	int key;
187*11561SRic.Aleshire@Sun.COM 	m_label_t *min_sl = NULL, *max_sl = NULL;
1881676Sjpk 	char attrbuf[MAX_ATTR_LEN];
1891676Sjpk 	const char **keyword;
1901676Sjpk 	int err;
1911676Sjpk 	char *errstr, *cp;
1921676Sjpk 
1931676Sjpk 	if (errp == NULL)
1941676Sjpk 		errp = &err;
1951676Sjpk 	if (errstrp == NULL)
1961676Sjpk 		errstrp = &errstr;
1971676Sjpk 
1981676Sjpk 	*errstrp = (char *)options;
1991676Sjpk 
2001676Sjpk 	while (*options != '\0') {
2011676Sjpk 		valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
2021676Sjpk 
2031676Sjpk 		if (attrbuf[0] == '\0') {
2041676Sjpk 			*errstrp = (char *)options;
2051676Sjpk 			*errp = LTSNET_ILL_ENTRY;
206*11561SRic.Aleshire@Sun.COM 			goto out_err;
2071676Sjpk 		}
2081676Sjpk 		for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
2091676Sjpk 			if (strcmp(*keyword, attrbuf) == 0)
2101676Sjpk 				break;
2111676Sjpk 		if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
2121676Sjpk 			*errstrp = (char *)options;
2131676Sjpk 			*errp = LTSNET_ILL_KEY;
214*11561SRic.Aleshire@Sun.COM 			goto out_err;
2151676Sjpk 		}
2161676Sjpk 		if ((key == SAK_CIPSO && *valptr == '=') ||
2171676Sjpk 		    (key != SAK_CIPSO && *valptr != '=')) {
2181676Sjpk 			*errstrp = (char *)valptr;
2191676Sjpk 			*errp = LTSNET_ILL_VALDELIM;
220*11561SRic.Aleshire@Sun.COM 			goto out_err;
2211676Sjpk 		}
2221676Sjpk 
2231676Sjpk 		nxtopt = valptr;
2241676Sjpk 		if (*valptr == '=') {
2251676Sjpk 			valptr++;
2261676Sjpk 			nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
2271676Sjpk 			    valptr, ",=");
2281676Sjpk 			if (*nxtopt == '=') {
2291676Sjpk 				*errstrp = (char *)nxtopt;
2301676Sjpk 				*errp = LTSNET_ILL_KEYDELIM;
231*11561SRic.Aleshire@Sun.COM 				goto out_err;
2321676Sjpk 			}
2331676Sjpk 		}
2341676Sjpk 		if (*nxtopt == ',')
2351676Sjpk 			nxtopt++;
2361676Sjpk 
2371676Sjpk 		switch (key) {
2381676Sjpk 		case SAK_MINSL:
2391676Sjpk 			if (mask & RTSA_MINSL) {
2401676Sjpk 				*errstrp = (char *)options;
2411676Sjpk 				*errp = LTSNET_DUP_KEY;
242*11561SRic.Aleshire@Sun.COM 				goto out_err;
2431676Sjpk 			}
244*11561SRic.Aleshire@Sun.COM 			m_label_free(min_sl);		/* in case of duplicate */
245*11561SRic.Aleshire@Sun.COM 			min_sl = NULL;
246*11561SRic.Aleshire@Sun.COM 			if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
247*11561SRic.Aleshire@Sun.COM 			    L_NO_CORRECTION, NULL) != 0) {
2481676Sjpk 				*errstrp = (char *)valptr;
2491676Sjpk 				*errp = LTSNET_ILL_LOWERBOUND;
250*11561SRic.Aleshire@Sun.COM 				goto out_err;
2511676Sjpk 			}
2521676Sjpk 			mask |= RTSA_MINSL;
2531676Sjpk 			break;
2541676Sjpk 
2551676Sjpk 		case SAK_MAXSL:
2561676Sjpk 			if (mask & RTSA_MAXSL) {
2571676Sjpk 				*errstrp = (char *)options;
2581676Sjpk 				*errp = LTSNET_DUP_KEY;
259*11561SRic.Aleshire@Sun.COM 				goto out_err;
2601676Sjpk 			}
261*11561SRic.Aleshire@Sun.COM 			m_label_free(max_sl);		/* in case of duplicate */
262*11561SRic.Aleshire@Sun.COM 			max_sl = NULL;
263*11561SRic.Aleshire@Sun.COM 			if (str_to_label(attrbuf, &max_sl, MAC_LABEL,
264*11561SRic.Aleshire@Sun.COM 			    L_NO_CORRECTION, NULL) != 0) {
2651676Sjpk 				*errstrp = (char *)valptr;
2661676Sjpk 				*errp = LTSNET_ILL_UPPERBOUND;
267*11561SRic.Aleshire@Sun.COM 				goto out_err;
2681676Sjpk 			}
2691676Sjpk 			mask |= RTSA_MAXSL;
2701676Sjpk 			break;
2711676Sjpk 
2722304Swy83408 		case SAK_SL:
2732304Swy83408 			if (mask & (RTSA_MAXSL|RTSA_MINSL)) {
2742304Swy83408 				*errstrp = (char *)options;
2752304Swy83408 				*errp = LTSNET_DUP_KEY;
276*11561SRic.Aleshire@Sun.COM 				goto out_err;
2772304Swy83408 			}
278*11561SRic.Aleshire@Sun.COM 			m_label_free(min_sl);		/* in case of duplicate */
279*11561SRic.Aleshire@Sun.COM 			min_sl = NULL;
280*11561SRic.Aleshire@Sun.COM 			if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
281*11561SRic.Aleshire@Sun.COM 			    L_NO_CORRECTION, NULL) != 0) {
2822304Swy83408 				*errstrp = (char *)valptr;
2832304Swy83408 				*errp = LTSNET_ILL_LABEL;
284*11561SRic.Aleshire@Sun.COM 				goto out_err;
2852304Swy83408 			}
286*11561SRic.Aleshire@Sun.COM 			*max_sl = *min_sl;
2872304Swy83408 			mask |= (RTSA_MINSL | RTSA_MAXSL);
2882304Swy83408 			break;
2892304Swy83408 
2901676Sjpk 		case SAK_DOI:
2911676Sjpk 			if (mask & RTSA_DOI) {
2921676Sjpk 				*errstrp = (char *)options;
2931676Sjpk 				*errp = LTSNET_DUP_KEY;
294*11561SRic.Aleshire@Sun.COM 				goto out_err;
2951676Sjpk 			}
2961676Sjpk 			errno = 0;
2971676Sjpk 			doi = strtoul(attrbuf, &cp, 0);
2981676Sjpk 			if (doi == 0 || errno != 0 || *cp != '\0') {
2991676Sjpk 				*errstrp = (char *)valptr;
3001676Sjpk 				*errp = LTSNET_ILL_DOI;
301*11561SRic.Aleshire@Sun.COM 				goto out_err;
3021676Sjpk 			}
3031676Sjpk 			mask |= RTSA_DOI;
3041676Sjpk 			break;
3051676Sjpk 
3061676Sjpk 		case SAK_CIPSO:
3071676Sjpk 			if (mask & RTSA_CIPSO) {
3081676Sjpk 				*errstrp = (char *)options;
3091676Sjpk 				*errp = LTSNET_DUP_KEY;
310*11561SRic.Aleshire@Sun.COM 				goto out_err;
3111676Sjpk 			}
3121676Sjpk 			mask |= RTSA_CIPSO;
3131676Sjpk 			break;
3141676Sjpk 		}
3151676Sjpk 
3161676Sjpk 		options = nxtopt;
3171676Sjpk 	}
3181676Sjpk 
3191676Sjpk 	/* Defaults to CIPSO if not specified */
3201676Sjpk 	mask |= RTSA_CIPSO;
3211676Sjpk 
3221676Sjpk 	/* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
3231676Sjpk 	if (!(mask & RTSA_DOI)) {
3241676Sjpk 		*errp = LTSNET_NO_DOI;
325*11561SRic.Aleshire@Sun.COM 		goto out_err;
3261676Sjpk 	}
3271676Sjpk 
3281676Sjpk 	/* SL range must be specified */
3291676Sjpk 	if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
3301676Sjpk 		*errp = LTSNET_NO_RANGE;
331*11561SRic.Aleshire@Sun.COM 		goto out_err;
3321676Sjpk 	}
3331676Sjpk 	if (!(mask & RTSA_MINSL)) {
3341676Sjpk 		*errp = LTSNET_NO_LOWERBOUND;
335*11561SRic.Aleshire@Sun.COM 		goto out_err;
3361676Sjpk 	}
3371676Sjpk 	if (!(mask & RTSA_MAXSL)) {
3381676Sjpk 		*errp = LTSNET_NO_UPPERBOUND;
339*11561SRic.Aleshire@Sun.COM 		goto out_err;
3401676Sjpk 	}
3411676Sjpk 
3421676Sjpk 	/* SL range must have upper bound dominating lower bound */
343*11561SRic.Aleshire@Sun.COM 	if (!bldominates(max_sl, min_sl)) {
3441676Sjpk 		*errp = LTSNET_ILL_RANGE;
345*11561SRic.Aleshire@Sun.COM 		goto out_err;
3461676Sjpk 	}
3471676Sjpk 
3481676Sjpk 	if (mask & RTSA_MINSL)
349*11561SRic.Aleshire@Sun.COM 		sp->rtsa_slrange.lower_bound = *min_sl;
3501676Sjpk 	if (mask & RTSA_MAXSL)
351*11561SRic.Aleshire@Sun.COM 		sp->rtsa_slrange.upper_bound = *max_sl;
3521676Sjpk 	if (mask & RTSA_DOI)
3531676Sjpk 		sp->rtsa_doi = doi;
3541676Sjpk 	sp->rtsa_mask = mask;
3551676Sjpk 
356*11561SRic.Aleshire@Sun.COM 	m_label_free(min_sl);
357*11561SRic.Aleshire@Sun.COM 	m_label_free(max_sl);
358*11561SRic.Aleshire@Sun.COM 
3591676Sjpk 	return (B_TRUE);
360*11561SRic.Aleshire@Sun.COM 
361*11561SRic.Aleshire@Sun.COM out_err:
362*11561SRic.Aleshire@Sun.COM 	m_label_free(min_sl);
363*11561SRic.Aleshire@Sun.COM 	m_label_free(max_sl);
364*11561SRic.Aleshire@Sun.COM 
365*11561SRic.Aleshire@Sun.COM 	return (B_FALSE);
3661676Sjpk }
3671676Sjpk 
3681676Sjpk /* Keep in sync with libtsnet.h */
3691676Sjpk static const char *tsol_errlist[] = {
3701676Sjpk 	"No error",
3711676Sjpk 	"System error",
3721676Sjpk 	"Empty string or end of list",
3731676Sjpk 	"Entry is malformed",
3741676Sjpk 	"Missing name",
3751676Sjpk 	"Missing attributes",
3761676Sjpk 	"Illegal name",
3771676Sjpk 	"Illegal keyword delimiter",
3781676Sjpk 	"Unknown keyword",
3791676Sjpk 	"Duplicate keyword",
3801676Sjpk 	"Illegal value delimiter",
3811676Sjpk 	"Missing host type",
3821676Sjpk 	"Illegal host type",
3831676Sjpk 	"Missing label",
3841676Sjpk 	"Illegal label",
3851676Sjpk 	"Missing label range",
3861676Sjpk 	"Illegal label range",
3871676Sjpk 	"No lower bound in range",
3881676Sjpk 	"Illegal lower bound in range",
3891676Sjpk 	"No upper bound in range",
3901676Sjpk 	"Illegal upper bound in range",
3911676Sjpk 	"Missing DOI",
3921676Sjpk 	"Illegal DOI",
3931676Sjpk 	"Too many entries in set",
3941676Sjpk 	"Missing address/network",
3951676Sjpk 	"Illegal address/network",
3961676Sjpk 	"Illegal flag",
3971676Sjpk 	"Illegal MLP specification",
3981676Sjpk 	"Unacceptable keyword for type"
3991676Sjpk };
4001676Sjpk static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
4011676Sjpk 
4021676Sjpk const char *
tsol_strerror(int libtserr,int errnoval)4031676Sjpk tsol_strerror(int libtserr, int errnoval)
4041676Sjpk {
4051676Sjpk 	if (libtserr == LTSNET_SYSERR)
4061676Sjpk 		return (strerror(errnoval));
4071676Sjpk 	if (libtserr >= 0 && libtserr < tsol_nerr)
4081676Sjpk 		return (gettext(tsol_errlist[libtserr]));
4091676Sjpk 	return (gettext("Unknown error"));
4101676Sjpk }
411