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