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 /* 22*7b0bedd4SRic Aleshire * Copyright 2010 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 /* 2945916cd2Sjpk * Miscellaneous user interfaces to trusted label functions. 3045916cd2Sjpk */ 3145916cd2Sjpk 3245916cd2Sjpk 3345916cd2Sjpk #include <ctype.h> 3445916cd2Sjpk #include <stdio.h> 3545916cd2Sjpk #include <stdlib.h> 3645916cd2Sjpk #include <strings.h> 3745916cd2Sjpk #include <errno.h> 3845916cd2Sjpk #include <libintl.h> 3945916cd2Sjpk #include <libtsnet.h> 4045916cd2Sjpk #include <tsol/label.h> 4145916cd2Sjpk 4245916cd2Sjpk #include <net/route.h> 4345916cd2Sjpk 4445916cd2Sjpk #define MAX_ATTR_LEN 1024 4545916cd2Sjpk 4645916cd2Sjpk /* 4745916cd2Sjpk * Parse off an entry from a line. Entry is stored in 'outbuf'. Returned 4845916cd2Sjpk * value is a pointer to the first unprocessed input character from 'instr'. 4945916cd2Sjpk */ 5045916cd2Sjpk const char * 5145916cd2Sjpk parse_entry(char *outbuf, size_t outlen, const char *instr, 5245916cd2Sjpk const char *delimit) 5345916cd2Sjpk { 5445916cd2Sjpk boolean_t escape_state = B_FALSE; 5545916cd2Sjpk boolean_t any_white; 5645916cd2Sjpk char chr; 5745916cd2Sjpk 5845916cd2Sjpk any_white = strchr(delimit, '\n') != NULL; 5945916cd2Sjpk 6045916cd2Sjpk /* 6145916cd2Sjpk * User may specify outlen as 0 to skip over a field without storing 6245916cd2Sjpk * it anywhere. Otherwise, we need at least one byte for the 6345916cd2Sjpk * terminating NUL plus one byte to store another byte from instr. 6445916cd2Sjpk */ 6545916cd2Sjpk while (outlen != 1 && (chr = *instr++) != '\0') { 6645916cd2Sjpk if (!escape_state) { 6745916cd2Sjpk if (chr == '\\') { 6845916cd2Sjpk escape_state = B_TRUE; 6945916cd2Sjpk continue; 7045916cd2Sjpk } 7145916cd2Sjpk if (strchr(delimit, chr) != NULL) 7245916cd2Sjpk break; 7345916cd2Sjpk if (any_white && isspace(chr)) 7445916cd2Sjpk break; 7545916cd2Sjpk } 7645916cd2Sjpk escape_state = B_FALSE; 7745916cd2Sjpk if (outlen > 0) { 7845916cd2Sjpk *outbuf++ = chr; 7945916cd2Sjpk outlen--; 8045916cd2Sjpk } 8145916cd2Sjpk } 8245916cd2Sjpk if (outlen != 1) 8345916cd2Sjpk instr--; 8445916cd2Sjpk if (escape_state) 8545916cd2Sjpk instr--; 8645916cd2Sjpk if (outlen > 0) 8745916cd2Sjpk *outbuf = '\0'; 8845916cd2Sjpk return (instr); 8945916cd2Sjpk } 9045916cd2Sjpk 91*7b0bedd4SRic Aleshire char * 92*7b0bedd4SRic Aleshire sl_to_str(const m_label_t *sl) 9345916cd2Sjpk { 94*7b0bedd4SRic Aleshire char *sl_str = NULL; 95*7b0bedd4SRic Aleshire static char unknown_str[] = "UNKNOWN"; 9645916cd2Sjpk 9745916cd2Sjpk if (sl == NULL) 98*7b0bedd4SRic Aleshire return (strdup(unknown_str)); 9945916cd2Sjpk 100*7b0bedd4SRic Aleshire if ((label_to_str(sl, &sl_str, M_LABEL, DEF_NAMES) != 0) && 101*7b0bedd4SRic Aleshire (label_to_str(sl, &sl_str, M_INTERNAL, DEF_NAMES) != 0)) 102*7b0bedd4SRic Aleshire return (strdup(unknown_str)); 103*7b0bedd4SRic Aleshire 10445916cd2Sjpk return (sl_str); 10545916cd2Sjpk } 10645916cd2Sjpk 10745916cd2Sjpk static const char *rtsa_keywords[] = { 10845916cd2Sjpk #define SAK_MINSL 0 10945916cd2Sjpk "min_sl", 11045916cd2Sjpk #define SAK_MAXSL 1 11145916cd2Sjpk "max_sl", 11245916cd2Sjpk #define SAK_DOI 2 11345916cd2Sjpk "doi", 11445916cd2Sjpk #define SAK_CIPSO 3 11545916cd2Sjpk "cipso", 116e34b0294Swy83408 #define SAK_SL 4 117e34b0294Swy83408 "sl", 118e34b0294Swy83408 #define SAK_INVAL 5 11945916cd2Sjpk NULL 12045916cd2Sjpk }; 12145916cd2Sjpk 12245916cd2Sjpk const char * 12345916cd2Sjpk rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len) 12445916cd2Sjpk { 12545916cd2Sjpk size_t slen; 12645916cd2Sjpk uint32_t mask, i; 127*7b0bedd4SRic Aleshire char *sl_str = NULL; 12845916cd2Sjpk 12945916cd2Sjpk slen = 0; 13045916cd2Sjpk *line = '\0'; 13145916cd2Sjpk mask = rtsa->rtsa_mask; 13245916cd2Sjpk 13345916cd2Sjpk for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) { 13445916cd2Sjpk if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO))) 13545916cd2Sjpk continue; 13645916cd2Sjpk if (!(i & mask)) 13745916cd2Sjpk continue; 13845916cd2Sjpk if (slen != 0) 13945916cd2Sjpk line[slen++] = ','; 14045916cd2Sjpk switch (i & mask) { 14145916cd2Sjpk case RTSA_MINSL: 142e34b0294Swy83408 if ((mask & RTSA_MAXSL) && 143e34b0294Swy83408 blequal(&rtsa->rtsa_slrange.lower_bound, 144e34b0294Swy83408 &rtsa->rtsa_slrange.upper_bound)) { 145*7b0bedd4SRic Aleshire 146*7b0bedd4SRic Aleshire sl_str = 147*7b0bedd4SRic Aleshire sl_to_str(&rtsa->rtsa_slrange.lower_bound); 148e34b0294Swy83408 slen += snprintf(line + slen, len - slen, 149*7b0bedd4SRic Aleshire "sl=%s", sl_str); 150*7b0bedd4SRic Aleshire free(sl_str); 151*7b0bedd4SRic Aleshire sl_str = NULL; 152e34b0294Swy83408 mask ^= RTSA_MAXSL; 153e34b0294Swy83408 break; 154e34b0294Swy83408 } 155*7b0bedd4SRic Aleshire sl_str = sl_to_str(&rtsa->rtsa_slrange.lower_bound); 15645916cd2Sjpk slen += snprintf(line + slen, len - slen, "min_sl=%s", 157*7b0bedd4SRic Aleshire sl_str); 158*7b0bedd4SRic Aleshire free(sl_str); 159*7b0bedd4SRic Aleshire sl_str = NULL; 16045916cd2Sjpk break; 16145916cd2Sjpk case RTSA_MAXSL: 162*7b0bedd4SRic Aleshire sl_str = sl_to_str(&rtsa->rtsa_slrange.upper_bound); 16345916cd2Sjpk slen += snprintf(line + slen, len - slen, "max_sl=%s", 164*7b0bedd4SRic Aleshire sl_str); 165*7b0bedd4SRic Aleshire free(sl_str); 166*7b0bedd4SRic Aleshire sl_str = NULL; 16745916cd2Sjpk break; 16845916cd2Sjpk case RTSA_DOI: 16945916cd2Sjpk slen += snprintf(line + slen, len - slen, "doi=%d", 17045916cd2Sjpk rtsa->rtsa_doi); 17145916cd2Sjpk break; 17245916cd2Sjpk case RTSA_CIPSO: 17345916cd2Sjpk slen += snprintf(line + slen, len - slen, "cipso"); 17445916cd2Sjpk break; 17545916cd2Sjpk } 17645916cd2Sjpk } 17745916cd2Sjpk 17845916cd2Sjpk return (line); 17945916cd2Sjpk } 18045916cd2Sjpk 18145916cd2Sjpk boolean_t 18245916cd2Sjpk rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp) 18345916cd2Sjpk { 18445916cd2Sjpk const char *valptr, *nxtopt; 18545916cd2Sjpk uint32_t mask = 0, doi; 18645916cd2Sjpk int key; 187*7b0bedd4SRic Aleshire m_label_t *min_sl = NULL, *max_sl = NULL; 18845916cd2Sjpk char attrbuf[MAX_ATTR_LEN]; 18945916cd2Sjpk const char **keyword; 19045916cd2Sjpk int err; 19145916cd2Sjpk char *errstr, *cp; 19245916cd2Sjpk 19345916cd2Sjpk if (errp == NULL) 19445916cd2Sjpk errp = &err; 19545916cd2Sjpk if (errstrp == NULL) 19645916cd2Sjpk errstrp = &errstr; 19745916cd2Sjpk 19845916cd2Sjpk *errstrp = (char *)options; 19945916cd2Sjpk 20045916cd2Sjpk while (*options != '\0') { 20145916cd2Sjpk valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",="); 20245916cd2Sjpk 20345916cd2Sjpk if (attrbuf[0] == '\0') { 20445916cd2Sjpk *errstrp = (char *)options; 20545916cd2Sjpk *errp = LTSNET_ILL_ENTRY; 206*7b0bedd4SRic Aleshire goto out_err; 20745916cd2Sjpk } 20845916cd2Sjpk for (keyword = rtsa_keywords; *keyword != NULL; keyword++) 20945916cd2Sjpk if (strcmp(*keyword, attrbuf) == 0) 21045916cd2Sjpk break; 21145916cd2Sjpk if ((key = keyword - rtsa_keywords) == SAK_INVAL) { 21245916cd2Sjpk *errstrp = (char *)options; 21345916cd2Sjpk *errp = LTSNET_ILL_KEY; 214*7b0bedd4SRic Aleshire goto out_err; 21545916cd2Sjpk } 21645916cd2Sjpk if ((key == SAK_CIPSO && *valptr == '=') || 21745916cd2Sjpk (key != SAK_CIPSO && *valptr != '=')) { 21845916cd2Sjpk *errstrp = (char *)valptr; 21945916cd2Sjpk *errp = LTSNET_ILL_VALDELIM; 220*7b0bedd4SRic Aleshire goto out_err; 22145916cd2Sjpk } 22245916cd2Sjpk 22345916cd2Sjpk nxtopt = valptr; 22445916cd2Sjpk if (*valptr == '=') { 22545916cd2Sjpk valptr++; 22645916cd2Sjpk nxtopt = parse_entry(attrbuf, sizeof (attrbuf), 22745916cd2Sjpk valptr, ",="); 22845916cd2Sjpk if (*nxtopt == '=') { 22945916cd2Sjpk *errstrp = (char *)nxtopt; 23045916cd2Sjpk *errp = LTSNET_ILL_KEYDELIM; 231*7b0bedd4SRic Aleshire goto out_err; 23245916cd2Sjpk } 23345916cd2Sjpk } 23445916cd2Sjpk if (*nxtopt == ',') 23545916cd2Sjpk nxtopt++; 23645916cd2Sjpk 23745916cd2Sjpk switch (key) { 23845916cd2Sjpk case SAK_MINSL: 23945916cd2Sjpk if (mask & RTSA_MINSL) { 24045916cd2Sjpk *errstrp = (char *)options; 24145916cd2Sjpk *errp = LTSNET_DUP_KEY; 242*7b0bedd4SRic Aleshire goto out_err; 24345916cd2Sjpk } 244*7b0bedd4SRic Aleshire m_label_free(min_sl); /* in case of duplicate */ 245*7b0bedd4SRic Aleshire min_sl = NULL; 246*7b0bedd4SRic Aleshire if (str_to_label(attrbuf, &min_sl, MAC_LABEL, 247*7b0bedd4SRic Aleshire L_NO_CORRECTION, NULL) != 0) { 24845916cd2Sjpk *errstrp = (char *)valptr; 24945916cd2Sjpk *errp = LTSNET_ILL_LOWERBOUND; 250*7b0bedd4SRic Aleshire goto out_err; 25145916cd2Sjpk } 25245916cd2Sjpk mask |= RTSA_MINSL; 25345916cd2Sjpk break; 25445916cd2Sjpk 25545916cd2Sjpk case SAK_MAXSL: 25645916cd2Sjpk if (mask & RTSA_MAXSL) { 25745916cd2Sjpk *errstrp = (char *)options; 25845916cd2Sjpk *errp = LTSNET_DUP_KEY; 259*7b0bedd4SRic Aleshire goto out_err; 26045916cd2Sjpk } 261*7b0bedd4SRic Aleshire m_label_free(max_sl); /* in case of duplicate */ 262*7b0bedd4SRic Aleshire max_sl = NULL; 263*7b0bedd4SRic Aleshire if (str_to_label(attrbuf, &max_sl, MAC_LABEL, 264*7b0bedd4SRic Aleshire L_NO_CORRECTION, NULL) != 0) { 26545916cd2Sjpk *errstrp = (char *)valptr; 26645916cd2Sjpk *errp = LTSNET_ILL_UPPERBOUND; 267*7b0bedd4SRic Aleshire goto out_err; 26845916cd2Sjpk } 26945916cd2Sjpk mask |= RTSA_MAXSL; 27045916cd2Sjpk break; 27145916cd2Sjpk 272e34b0294Swy83408 case SAK_SL: 273e34b0294Swy83408 if (mask & (RTSA_MAXSL|RTSA_MINSL)) { 274e34b0294Swy83408 *errstrp = (char *)options; 275e34b0294Swy83408 *errp = LTSNET_DUP_KEY; 276*7b0bedd4SRic Aleshire goto out_err; 277e34b0294Swy83408 } 278*7b0bedd4SRic Aleshire m_label_free(min_sl); /* in case of duplicate */ 279*7b0bedd4SRic Aleshire min_sl = NULL; 280*7b0bedd4SRic Aleshire if (str_to_label(attrbuf, &min_sl, MAC_LABEL, 281*7b0bedd4SRic Aleshire L_NO_CORRECTION, NULL) != 0) { 282e34b0294Swy83408 *errstrp = (char *)valptr; 283e34b0294Swy83408 *errp = LTSNET_ILL_LABEL; 284*7b0bedd4SRic Aleshire goto out_err; 285e34b0294Swy83408 } 286*7b0bedd4SRic Aleshire *max_sl = *min_sl; 287e34b0294Swy83408 mask |= (RTSA_MINSL | RTSA_MAXSL); 288e34b0294Swy83408 break; 289e34b0294Swy83408 29045916cd2Sjpk case SAK_DOI: 29145916cd2Sjpk if (mask & RTSA_DOI) { 29245916cd2Sjpk *errstrp = (char *)options; 29345916cd2Sjpk *errp = LTSNET_DUP_KEY; 294*7b0bedd4SRic Aleshire goto out_err; 29545916cd2Sjpk } 29645916cd2Sjpk errno = 0; 29745916cd2Sjpk doi = strtoul(attrbuf, &cp, 0); 29845916cd2Sjpk if (doi == 0 || errno != 0 || *cp != '\0') { 29945916cd2Sjpk *errstrp = (char *)valptr; 30045916cd2Sjpk *errp = LTSNET_ILL_DOI; 301*7b0bedd4SRic Aleshire goto out_err; 30245916cd2Sjpk } 30345916cd2Sjpk mask |= RTSA_DOI; 30445916cd2Sjpk break; 30545916cd2Sjpk 30645916cd2Sjpk case SAK_CIPSO: 30745916cd2Sjpk if (mask & RTSA_CIPSO) { 30845916cd2Sjpk *errstrp = (char *)options; 30945916cd2Sjpk *errp = LTSNET_DUP_KEY; 310*7b0bedd4SRic Aleshire goto out_err; 31145916cd2Sjpk } 31245916cd2Sjpk mask |= RTSA_CIPSO; 31345916cd2Sjpk break; 31445916cd2Sjpk } 31545916cd2Sjpk 31645916cd2Sjpk options = nxtopt; 31745916cd2Sjpk } 31845916cd2Sjpk 31945916cd2Sjpk /* Defaults to CIPSO if not specified */ 32045916cd2Sjpk mask |= RTSA_CIPSO; 32145916cd2Sjpk 32245916cd2Sjpk /* If RTSA_CIPSO is specified, RTSA_DOI must be specified */ 32345916cd2Sjpk if (!(mask & RTSA_DOI)) { 32445916cd2Sjpk *errp = LTSNET_NO_DOI; 325*7b0bedd4SRic Aleshire goto out_err; 32645916cd2Sjpk } 32745916cd2Sjpk 32845916cd2Sjpk /* SL range must be specified */ 32945916cd2Sjpk if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) { 33045916cd2Sjpk *errp = LTSNET_NO_RANGE; 331*7b0bedd4SRic Aleshire goto out_err; 33245916cd2Sjpk } 33345916cd2Sjpk if (!(mask & RTSA_MINSL)) { 33445916cd2Sjpk *errp = LTSNET_NO_LOWERBOUND; 335*7b0bedd4SRic Aleshire goto out_err; 33645916cd2Sjpk } 33745916cd2Sjpk if (!(mask & RTSA_MAXSL)) { 33845916cd2Sjpk *errp = LTSNET_NO_UPPERBOUND; 339*7b0bedd4SRic Aleshire goto out_err; 34045916cd2Sjpk } 34145916cd2Sjpk 34245916cd2Sjpk /* SL range must have upper bound dominating lower bound */ 343*7b0bedd4SRic Aleshire if (!bldominates(max_sl, min_sl)) { 34445916cd2Sjpk *errp = LTSNET_ILL_RANGE; 345*7b0bedd4SRic Aleshire goto out_err; 34645916cd2Sjpk } 34745916cd2Sjpk 34845916cd2Sjpk if (mask & RTSA_MINSL) 349*7b0bedd4SRic Aleshire sp->rtsa_slrange.lower_bound = *min_sl; 35045916cd2Sjpk if (mask & RTSA_MAXSL) 351*7b0bedd4SRic Aleshire sp->rtsa_slrange.upper_bound = *max_sl; 35245916cd2Sjpk if (mask & RTSA_DOI) 35345916cd2Sjpk sp->rtsa_doi = doi; 35445916cd2Sjpk sp->rtsa_mask = mask; 35545916cd2Sjpk 356*7b0bedd4SRic Aleshire m_label_free(min_sl); 357*7b0bedd4SRic Aleshire m_label_free(max_sl); 358*7b0bedd4SRic Aleshire 35945916cd2Sjpk return (B_TRUE); 360*7b0bedd4SRic Aleshire 361*7b0bedd4SRic Aleshire out_err: 362*7b0bedd4SRic Aleshire m_label_free(min_sl); 363*7b0bedd4SRic Aleshire m_label_free(max_sl); 364*7b0bedd4SRic Aleshire 365*7b0bedd4SRic Aleshire return (B_FALSE); 36645916cd2Sjpk } 36745916cd2Sjpk 36845916cd2Sjpk /* Keep in sync with libtsnet.h */ 36945916cd2Sjpk static const char *tsol_errlist[] = { 37045916cd2Sjpk "No error", 37145916cd2Sjpk "System error", 37245916cd2Sjpk "Empty string or end of list", 37345916cd2Sjpk "Entry is malformed", 37445916cd2Sjpk "Missing name", 37545916cd2Sjpk "Missing attributes", 37645916cd2Sjpk "Illegal name", 37745916cd2Sjpk "Illegal keyword delimiter", 37845916cd2Sjpk "Unknown keyword", 37945916cd2Sjpk "Duplicate keyword", 38045916cd2Sjpk "Illegal value delimiter", 38145916cd2Sjpk "Missing host type", 38245916cd2Sjpk "Illegal host type", 38345916cd2Sjpk "Missing label", 38445916cd2Sjpk "Illegal label", 38545916cd2Sjpk "Missing label range", 38645916cd2Sjpk "Illegal label range", 38745916cd2Sjpk "No lower bound in range", 38845916cd2Sjpk "Illegal lower bound in range", 38945916cd2Sjpk "No upper bound in range", 39045916cd2Sjpk "Illegal upper bound in range", 39145916cd2Sjpk "Missing DOI", 39245916cd2Sjpk "Illegal DOI", 39345916cd2Sjpk "Too many entries in set", 39445916cd2Sjpk "Missing address/network", 39545916cd2Sjpk "Illegal address/network", 39645916cd2Sjpk "Illegal flag", 39745916cd2Sjpk "Illegal MLP specification", 39845916cd2Sjpk "Unacceptable keyword for type" 39945916cd2Sjpk }; 40045916cd2Sjpk static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist); 40145916cd2Sjpk 40245916cd2Sjpk const char * 40345916cd2Sjpk tsol_strerror(int libtserr, int errnoval) 40445916cd2Sjpk { 40545916cd2Sjpk if (libtserr == LTSNET_SYSERR) 40645916cd2Sjpk return (strerror(errnoval)); 40745916cd2Sjpk if (libtserr >= 0 && libtserr < tsol_nerr) 40845916cd2Sjpk return (gettext(tsol_errlist[libtserr])); 40945916cd2Sjpk return (gettext("Unknown error")); 41045916cd2Sjpk } 411