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