2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A *
2N/A * From "misc.c 5.15 00/05/31 SMI; TSOL 2.x"
2N/A */
2N/A
2N/A/*
2N/A * Miscellaneous user interfaces to trusted label functions.
2N/A */
2N/A
2N/A
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <errno.h>
2N/A#include <libintl.h>
2N/A#include <libtsnet.h>
2N/A#include <tsol/label.h>
2N/A
2N/A#include <net/route.h>
2N/A
2N/A#define MAX_ATTR_LEN 1024
2N/A
2N/A/*
2N/A * Parse off an entry from a line. Entry is stored in 'outbuf'. Returned
2N/A * value is a pointer to the first unprocessed input character from 'instr'.
2N/A */
2N/Aconst char *
2N/Aparse_entry(char *outbuf, size_t outlen, const char *instr,
2N/A const char *delimit)
2N/A{
2N/A boolean_t escape_state = B_FALSE;
2N/A boolean_t any_white;
2N/A char chr;
2N/A
2N/A any_white = strchr(delimit, '\n') != NULL;
2N/A
2N/A /*
2N/A * User may specify outlen as 0 to skip over a field without storing
2N/A * it anywhere. Otherwise, we need at least one byte for the
2N/A * terminating NUL plus one byte to store another byte from instr.
2N/A */
2N/A while (outlen != 1 && (chr = *instr++) != '\0') {
2N/A if (!escape_state) {
2N/A if (chr == '\\') {
2N/A escape_state = B_TRUE;
2N/A continue;
2N/A }
2N/A if (strchr(delimit, chr) != NULL)
2N/A break;
2N/A if (any_white && isspace(chr))
2N/A break;
2N/A }
2N/A escape_state = B_FALSE;
2N/A if (outlen > 0) {
2N/A *outbuf++ = chr;
2N/A outlen--;
2N/A }
2N/A }
2N/A if (outlen != 1)
2N/A instr--;
2N/A if (escape_state)
2N/A instr--;
2N/A if (outlen > 0)
2N/A *outbuf = '\0';
2N/A return (instr);
2N/A}
2N/A
2N/Achar *
2N/Asl_to_str(const m_label_t *sl)
2N/A{
2N/A char *sl_str = NULL;
2N/A static char unknown_str[] = "UNKNOWN";
2N/A
2N/A if (sl == NULL)
2N/A return (strdup(unknown_str));
2N/A
2N/A if ((label_to_str(sl, &sl_str, M_LABEL, DEF_NAMES) != 0) &&
2N/A (label_to_str(sl, &sl_str, M_INTERNAL, DEF_NAMES) != 0))
2N/A return (strdup(unknown_str));
2N/A
2N/A return (sl_str);
2N/A}
2N/A
2N/Astatic const char *rtsa_keywords[] = {
2N/A#define SAK_MINSL 0
2N/A "min_sl",
2N/A#define SAK_MAXSL 1
2N/A "max_sl",
2N/A#define SAK_DOI 2
2N/A "doi",
2N/A#define SAK_CIPSO 3
2N/A "cipso",
2N/A#define SAK_SL 4
2N/A "sl",
2N/A#define SAK_INVAL 5
2N/A NULL
2N/A};
2N/A
2N/Aconst char *
2N/Artsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
2N/A{
2N/A size_t slen;
2N/A uint32_t mask, i;
2N/A char *sl_str = NULL;
2N/A
2N/A slen = 0;
2N/A *line = '\0';
2N/A mask = rtsa->rtsa_mask;
2N/A
2N/A for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
2N/A if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
2N/A continue;
2N/A if (!(i & mask))
2N/A continue;
2N/A if (slen != 0)
2N/A line[slen++] = ',';
2N/A switch (i & mask) {
2N/A case RTSA_MINSL:
2N/A if ((mask & RTSA_MAXSL) &&
2N/A blequal(&rtsa->rtsa_slrange.lower_bound,
2N/A &rtsa->rtsa_slrange.upper_bound)) {
2N/A
2N/A sl_str =
2N/A sl_to_str(&rtsa->rtsa_slrange.lower_bound);
2N/A slen += snprintf(line + slen, len - slen,
2N/A "sl=%s", sl_str);
2N/A free(sl_str);
2N/A sl_str = NULL;
2N/A mask ^= RTSA_MAXSL;
2N/A break;
2N/A }
2N/A sl_str = sl_to_str(&rtsa->rtsa_slrange.lower_bound);
2N/A slen += snprintf(line + slen, len - slen, "min_sl=%s",
2N/A sl_str);
2N/A free(sl_str);
2N/A sl_str = NULL;
2N/A break;
2N/A case RTSA_MAXSL:
2N/A sl_str = sl_to_str(&rtsa->rtsa_slrange.upper_bound);
2N/A slen += snprintf(line + slen, len - slen, "max_sl=%s",
2N/A sl_str);
2N/A free(sl_str);
2N/A sl_str = NULL;
2N/A break;
2N/A case RTSA_DOI:
2N/A slen += snprintf(line + slen, len - slen, "doi=%d",
2N/A rtsa->rtsa_doi);
2N/A break;
2N/A case RTSA_CIPSO:
2N/A slen += snprintf(line + slen, len - slen, "cipso");
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (line);
2N/A}
2N/A
2N/Aboolean_t
2N/Artsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
2N/A{
2N/A const char *valptr, *nxtopt;
2N/A uint32_t mask = 0, doi;
2N/A int key;
2N/A m_label_t *min_sl = NULL, *max_sl = NULL;
2N/A char attrbuf[MAX_ATTR_LEN];
2N/A const char **keyword;
2N/A int err;
2N/A char *errstr, *cp;
2N/A
2N/A if (errp == NULL)
2N/A errp = &err;
2N/A if (errstrp == NULL)
2N/A errstrp = &errstr;
2N/A
2N/A *errstrp = (char *)options;
2N/A
2N/A while (*options != '\0') {
2N/A valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
2N/A
2N/A if (attrbuf[0] == '\0') {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_ILL_ENTRY;
2N/A goto out_err;
2N/A }
2N/A for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
2N/A if (strcmp(*keyword, attrbuf) == 0)
2N/A break;
2N/A if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_ILL_KEY;
2N/A goto out_err;
2N/A }
2N/A if ((key == SAK_CIPSO && *valptr == '=') ||
2N/A (key != SAK_CIPSO && *valptr != '=')) {
2N/A *errstrp = (char *)valptr;
2N/A *errp = LTSNET_ILL_VALDELIM;
2N/A goto out_err;
2N/A }
2N/A
2N/A nxtopt = valptr;
2N/A if (*valptr == '=') {
2N/A valptr++;
2N/A nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
2N/A valptr, ",=");
2N/A if (*nxtopt == '=') {
2N/A *errstrp = (char *)nxtopt;
2N/A *errp = LTSNET_ILL_KEYDELIM;
2N/A goto out_err;
2N/A }
2N/A }
2N/A if (*nxtopt == ',')
2N/A nxtopt++;
2N/A
2N/A switch (key) {
2N/A case SAK_MINSL:
2N/A if (mask & RTSA_MINSL) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_DUP_KEY;
2N/A goto out_err;
2N/A }
2N/A m_label_free(min_sl); /* in case of duplicate */
2N/A min_sl = NULL;
2N/A if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
2N/A L_NO_CORRECTION, NULL) != 0) {
2N/A *errstrp = (char *)valptr;
2N/A *errp = LTSNET_ILL_LOWERBOUND;
2N/A goto out_err;
2N/A }
2N/A mask |= RTSA_MINSL;
2N/A break;
2N/A
2N/A case SAK_MAXSL:
2N/A if (mask & RTSA_MAXSL) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_DUP_KEY;
2N/A goto out_err;
2N/A }
2N/A m_label_free(max_sl); /* in case of duplicate */
2N/A max_sl = NULL;
2N/A if (str_to_label(attrbuf, &max_sl, MAC_LABEL,
2N/A L_NO_CORRECTION, NULL) != 0) {
2N/A *errstrp = (char *)valptr;
2N/A *errp = LTSNET_ILL_UPPERBOUND;
2N/A goto out_err;
2N/A }
2N/A mask |= RTSA_MAXSL;
2N/A break;
2N/A
2N/A case SAK_SL:
2N/A if (mask & (RTSA_MAXSL|RTSA_MINSL)) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_DUP_KEY;
2N/A goto out_err;
2N/A }
2N/A m_label_free(min_sl); /* in case of duplicate */
2N/A min_sl = NULL;
2N/A if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
2N/A L_NO_CORRECTION, NULL) != 0) {
2N/A *errstrp = (char *)valptr;
2N/A *errp = LTSNET_ILL_LABEL;
2N/A goto out_err;
2N/A }
2N/A *max_sl = *min_sl;
2N/A mask |= (RTSA_MINSL | RTSA_MAXSL);
2N/A break;
2N/A
2N/A case SAK_DOI:
2N/A if (mask & RTSA_DOI) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_DUP_KEY;
2N/A goto out_err;
2N/A }
2N/A errno = 0;
2N/A doi = strtoul(attrbuf, &cp, 0);
2N/A if (doi == 0 || errno != 0 || *cp != '\0') {
2N/A *errstrp = (char *)valptr;
2N/A *errp = LTSNET_ILL_DOI;
2N/A goto out_err;
2N/A }
2N/A mask |= RTSA_DOI;
2N/A break;
2N/A
2N/A case SAK_CIPSO:
2N/A if (mask & RTSA_CIPSO) {
2N/A *errstrp = (char *)options;
2N/A *errp = LTSNET_DUP_KEY;
2N/A goto out_err;
2N/A }
2N/A mask |= RTSA_CIPSO;
2N/A break;
2N/A }
2N/A
2N/A options = nxtopt;
2N/A }
2N/A
2N/A /* Defaults to CIPSO if not specified */
2N/A mask |= RTSA_CIPSO;
2N/A
2N/A /* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
2N/A if (!(mask & RTSA_DOI)) {
2N/A *errp = LTSNET_NO_DOI;
2N/A goto out_err;
2N/A }
2N/A
2N/A /* SL range must be specified */
2N/A if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
2N/A *errp = LTSNET_NO_RANGE;
2N/A goto out_err;
2N/A }
2N/A if (!(mask & RTSA_MINSL)) {
2N/A *errp = LTSNET_NO_LOWERBOUND;
2N/A goto out_err;
2N/A }
2N/A if (!(mask & RTSA_MAXSL)) {
2N/A *errp = LTSNET_NO_UPPERBOUND;
2N/A goto out_err;
2N/A }
2N/A
2N/A /* SL range must have upper bound dominating lower bound */
2N/A if (!bldominates(max_sl, min_sl)) {
2N/A *errp = LTSNET_ILL_RANGE;
2N/A goto out_err;
2N/A }
2N/A
2N/A if (mask & RTSA_MINSL)
2N/A sp->rtsa_slrange.lower_bound = *min_sl;
2N/A if (mask & RTSA_MAXSL)
2N/A sp->rtsa_slrange.upper_bound = *max_sl;
2N/A if (mask & RTSA_DOI)
2N/A sp->rtsa_doi = doi;
2N/A sp->rtsa_mask = mask;
2N/A
2N/A m_label_free(min_sl);
2N/A m_label_free(max_sl);
2N/A
2N/A return (B_TRUE);
2N/A
2N/Aout_err:
2N/A m_label_free(min_sl);
2N/A m_label_free(max_sl);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/* Keep in sync with libtsnet.h */
2N/Astatic const char *tsol_errlist[] = {
2N/A "No error",
2N/A "System error",
2N/A "Empty string or end of list",
2N/A "Entry is malformed",
2N/A "Missing name",
2N/A "Missing attributes",
2N/A "Illegal name",
2N/A "Illegal keyword delimiter",
2N/A "Unknown keyword",
2N/A "Duplicate keyword",
2N/A "Illegal value delimiter",
2N/A "Missing host type",
2N/A "Illegal host type",
2N/A "Missing label",
2N/A "Illegal label",
2N/A "Missing label range",
2N/A "Illegal label range",
2N/A "No lower bound in range",
2N/A "Illegal lower bound in range",
2N/A "No upper bound in range",
2N/A "Illegal upper bound in range",
2N/A "Missing DOI",
2N/A "Illegal DOI",
2N/A "Too many entries in set",
2N/A "Missing address/network",
2N/A "Illegal address/network",
2N/A "Illegal flag",
2N/A "Illegal MLP specification",
2N/A "Unacceptable keyword for type"
2N/A};
2N/Astatic const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
2N/A
2N/Aconst char *
2N/Atsol_strerror(int libtserr, int errnoval)
2N/A{
2N/A if (libtserr == LTSNET_SYSERR)
2N/A return (strerror(errnoval));
2N/A if (libtserr >= 0 && libtserr < tsol_nerr)
2N/A return (gettext(tsol_errlist[libtserr]));
2N/A return (gettext("Unknown error"));
2N/A}