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	"tsol_tndb_parser.c	7.24	01/09/05 SMI; TSOL 2.x"
2645916cd2Sjpk  *
2745916cd2Sjpk  * These functions parse entries in the "tnzonecfg" (zone configuration) file.
2845916cd2Sjpk  * Each entry in this file has five fields, separated by a colon.  These fields
2945916cd2Sjpk  * are:
3045916cd2Sjpk  *
3145916cd2Sjpk  *	zone name : label : flags : zone-specific MLPs : global MLPs
3245916cd2Sjpk  *
3345916cd2Sjpk  * The fourth and fifth fields contain subfields consisting of MLP entries
3445916cd2Sjpk  * separated by semicolons.  The MLP entries are of the form:
3545916cd2Sjpk  *
3645916cd2Sjpk  *	port[-port]/protocol
3745916cd2Sjpk  *
3845916cd2Sjpk  * In order to help preserve sanity, we do not allow more than four unescaped
3945916cd2Sjpk  * colons in a line, nor any unescaped ';' characters in the non-MLP fields.
4045916cd2Sjpk  * Such things are indicative of typing errors, not intentional configuration.
4145916cd2Sjpk  */
4245916cd2Sjpk 
4345916cd2Sjpk #include <ctype.h>
4445916cd2Sjpk #include <stdlib.h>
4545916cd2Sjpk #include <stddef.h>
4645916cd2Sjpk #include <string.h>
4745916cd2Sjpk #include <strings.h>
4845916cd2Sjpk #include <libtsnet.h>
4945916cd2Sjpk #include <tsol/label.h>
5045916cd2Sjpk #include <sys/types.h>
5145916cd2Sjpk #include <sys/socket.h>
5245916cd2Sjpk #include <netinet/in.h>
5345916cd2Sjpk #include <nss.h>
5445916cd2Sjpk #include <errno.h>
5545916cd2Sjpk #include <secdb.h>
5645916cd2Sjpk 
5745916cd2Sjpk /*
5845916cd2Sjpk  * Parse an MLP specification in port1-port2/proto or port/proto form.
5945916cd2Sjpk  */
6045916cd2Sjpk static int
str_to_mlp(char * mlp_str,tsol_mlp_t * zone_mlp)6145916cd2Sjpk str_to_mlp(char *mlp_str, tsol_mlp_t *zone_mlp)
6245916cd2Sjpk {
6345916cd2Sjpk 	char *fieldp;
6445916cd2Sjpk 	char *lasts, *cp;
6545916cd2Sjpk 	int i;
6645916cd2Sjpk 	ulong_t ulv;
6745916cd2Sjpk 	struct protoent proto;
6845916cd2Sjpk 	char gbuf[1024];
6945916cd2Sjpk 
7045916cd2Sjpk 	(void) memset(zone_mlp, 0, sizeof (tsol_mlp_t));
7145916cd2Sjpk 
7245916cd2Sjpk 	fieldp = strtok_r(mlp_str, KV_DELIMITER, &lasts);
7345916cd2Sjpk 	if (fieldp == NULL)
7445916cd2Sjpk 		return (-1);
7545916cd2Sjpk 
7645916cd2Sjpk 	errno = 0;
7745916cd2Sjpk 	for (i = 0; fieldp != NULL && i < NMLP_MAX; i++) {
7845916cd2Sjpk 		ulv = strtoul(fieldp, &cp, 0);
7945916cd2Sjpk 		zone_mlp[i].mlp_port = (uint16_t)ulv;
8045916cd2Sjpk 		zone_mlp[i].mlp_port_upper = 0;
8145916cd2Sjpk 		if (errno != 0 || ulv > 65535)
8245916cd2Sjpk 			return (-1);
8345916cd2Sjpk 		if (*cp == '-') {
8445916cd2Sjpk 			ulv = strtol(cp + 1, &cp, 0);
8545916cd2Sjpk 			zone_mlp[i].mlp_port_upper = (uint16_t)ulv;
8645916cd2Sjpk 			if (errno != 0 || ulv > 65535)
8745916cd2Sjpk 				return (-1);
8845916cd2Sjpk 		}
8945916cd2Sjpk 		if (*cp != '/')
9045916cd2Sjpk 			return (-1);
9145916cd2Sjpk 		fieldp = cp + 1;
9245916cd2Sjpk 		ulv = strtol(fieldp, &cp, 0);
9345916cd2Sjpk 		if (errno == 0 && ulv <= 255 && *cp == '\0')
9445916cd2Sjpk 			zone_mlp->mlp_ipp = (uint8_t)ulv;
9545916cd2Sjpk 		else if (getprotobyname_r(fieldp, &proto, gbuf,
9645916cd2Sjpk 		    sizeof (gbuf)) != NULL)
9745916cd2Sjpk 			zone_mlp->mlp_ipp = proto.p_proto;
9845916cd2Sjpk 		else
9945916cd2Sjpk 			return (-1);
10045916cd2Sjpk 		fieldp = strtok_r(NULL, KV_DELIMITER, &lasts);
10145916cd2Sjpk 	}
10245916cd2Sjpk 	return (0);
10345916cd2Sjpk }
10445916cd2Sjpk 
10545916cd2Sjpk static boolean_t
parse_mlp_list(tsol_mlp_t ** list,char * str,int * errp,char ** errstrp)10645916cd2Sjpk parse_mlp_list(tsol_mlp_t **list, char *str, int *errp, char **errstrp)
10745916cd2Sjpk {
10845916cd2Sjpk 	int mmax;
10945916cd2Sjpk 	tsol_mlp_t *mlp;
11045916cd2Sjpk 	char *tokp, *finally;
11145916cd2Sjpk 	int mc;
11245916cd2Sjpk 
11345916cd2Sjpk 	mmax = 0;
11445916cd2Sjpk 	if ((mlp = *list) != NULL) {
11545916cd2Sjpk 		while (!TSOL_MLP_END(mlp)) {
11645916cd2Sjpk 			mmax++;
11745916cd2Sjpk 			mlp++;
11845916cd2Sjpk 		}
11945916cd2Sjpk 		mmax++;
12045916cd2Sjpk 	}
12145916cd2Sjpk 	mlp = *list;
12245916cd2Sjpk 	tokp = strtok_r(str, KV_DELIMITER, &finally);
12345916cd2Sjpk 	for (mc = 0; tokp != NULL; mc++) {
12445916cd2Sjpk 		if (mc >= mmax) {
12545916cd2Sjpk 			mmax += 8;
12645916cd2Sjpk 			mlp = realloc(mlp, mmax * sizeof (*mlp));
12745916cd2Sjpk 			if (mlp == NULL) {
12845916cd2Sjpk 				*errp = LTSNET_SYSERR;
12945916cd2Sjpk 				*errstrp = tokp;
13045916cd2Sjpk 				return (B_FALSE);
13145916cd2Sjpk 			}
13245916cd2Sjpk 			*list = mlp;
13345916cd2Sjpk 		}
13445916cd2Sjpk 		if (str_to_mlp(tokp, mlp + mc) == -1) {
13545916cd2Sjpk 			*errp = LTSNET_ILL_MLP;
13645916cd2Sjpk 			*errstrp = tokp;
13745916cd2Sjpk 			return (B_FALSE);
13845916cd2Sjpk 		}
13945916cd2Sjpk 		tokp = strtok_r(NULL, KV_DELIMITER, &finally);
14045916cd2Sjpk 	}
14145916cd2Sjpk 	if (mc >= mmax) {
14245916cd2Sjpk 		mlp = realloc(mlp, (mmax + 1) * sizeof (*mlp));
14345916cd2Sjpk 		if (mlp == NULL) {
14445916cd2Sjpk 			*errp = LTSNET_SYSERR;
14545916cd2Sjpk 			*errstrp = finally;
14645916cd2Sjpk 			return (B_FALSE);
14745916cd2Sjpk 		}
14845916cd2Sjpk 		*list = mlp;
14945916cd2Sjpk 	}
15045916cd2Sjpk 	(void) memset(mlp + mc, 0, sizeof (*mlp));
15145916cd2Sjpk 	return (B_TRUE);
15245916cd2Sjpk }
15345916cd2Sjpk 
15445916cd2Sjpk tsol_zcent_t *
tsol_sgetzcent(const char * instr,int * errp,char ** errstrp)15545916cd2Sjpk tsol_sgetzcent(const char *instr, int *errp, char **errstrp)
15645916cd2Sjpk {
15745916cd2Sjpk 	int err;
158*7b0bedd4SRic Aleshire 	m_label_t *slp;
15945916cd2Sjpk 	char *errstr;
16045916cd2Sjpk 	tsol_zcent_t *zc;
16145916cd2Sjpk 	const char *nextf;
16245916cd2Sjpk 	char *cp;
16345916cd2Sjpk 	char fieldbuf[1024];
16445916cd2Sjpk 
16545916cd2Sjpk 	/*
16645916cd2Sjpk 	 * The user can specify NULL pointers for these.  Make sure that we
16745916cd2Sjpk 	 * don't have to deal with checking for NULL everywhere by just
16845916cd2Sjpk 	 * pointing to our own variables if the user gives NULL.
16945916cd2Sjpk 	 */
17045916cd2Sjpk 	if (errp == NULL)
17145916cd2Sjpk 		errp = &err;
17245916cd2Sjpk 	if (errstrp == NULL)
17345916cd2Sjpk 		errstrp = &errstr;
17445916cd2Sjpk 
17545916cd2Sjpk 	/* The default, unless we find a more specific error locus. */
17645916cd2Sjpk 	*errstrp = (char *)instr;
17745916cd2Sjpk 
17845916cd2Sjpk 	if ((zc = calloc(1, sizeof (*zc))) == NULL) {
17945916cd2Sjpk 		*errp = LTSNET_SYSERR;
18045916cd2Sjpk 		return (NULL);
18145916cd2Sjpk 	}
18245916cd2Sjpk 
18345916cd2Sjpk 	/* First, parse off the zone name. */
18445916cd2Sjpk 	instr = parse_entry(zc->zc_name, sizeof (zc->zc_name), instr, "#;:\n");
18545916cd2Sjpk 	if (zc->zc_name[0] == '\0') {
18645916cd2Sjpk 		*errstrp = (char *)instr;
18745916cd2Sjpk 		if (*instr == '\0' || *instr == '#' || *instr == '\n')
18845916cd2Sjpk 			*errp = LTSNET_EMPTY;
18945916cd2Sjpk 		else if (*instr == ':')
19045916cd2Sjpk 			*errp = LTSNET_NO_NAME;
19145916cd2Sjpk 		else
19245916cd2Sjpk 			*errp = LTSNET_ILL_NAME;
19345916cd2Sjpk 		goto err_ret;
19445916cd2Sjpk 	}
19545916cd2Sjpk 	if (*instr != ':') {
19645916cd2Sjpk 		*errstrp = (char *)instr;
19745916cd2Sjpk 		if (*instr == '=' || *instr == ';')
19845916cd2Sjpk 			*errp = LTSNET_ILL_NAME;
19945916cd2Sjpk 		else
20045916cd2Sjpk 			*errp = LTSNET_ILL_ENTRY;
20145916cd2Sjpk 		goto err_ret;
20245916cd2Sjpk 	}
20345916cd2Sjpk 	instr++;
20445916cd2Sjpk 
20545916cd2Sjpk 	/* Field two: parse off the label. */
20645916cd2Sjpk 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#;:\n");
20745916cd2Sjpk 	if (*nextf != ':') {
20845916cd2Sjpk 		*errstrp = (char *)nextf;
20945916cd2Sjpk 		*errp = LTSNET_ILL_ENTRY;
21045916cd2Sjpk 		goto err_ret;
21145916cd2Sjpk 	}
21245916cd2Sjpk 	if (fieldbuf[0] == '\0') {
21345916cd2Sjpk 		*errstrp = (char *)instr;
21445916cd2Sjpk 		*errp = LTSNET_NO_LABEL;
21545916cd2Sjpk 		goto err_ret;
21645916cd2Sjpk 	}
217*7b0bedd4SRic Aleshire 
218*7b0bedd4SRic Aleshire 	slp = &zc->zc_label;
219*7b0bedd4SRic Aleshire 	if (str_to_label(fieldbuf, &slp, MAC_LABEL, L_NO_CORRECTION, NULL)
220*7b0bedd4SRic Aleshire 	    != 0) {
22145916cd2Sjpk 		*errstrp = (char *)instr;
22245916cd2Sjpk 		*errp = LTSNET_ILL_LABEL;
22345916cd2Sjpk 		goto err_ret;
22445916cd2Sjpk 	}
22545916cd2Sjpk 	instr = nextf + 1;
22645916cd2Sjpk 
2277e6639c2Skp 	/* The kernel will apply the system doi to the zone label later */
2287e6639c2Skp 	zc->zc_doi = 0;
22945916cd2Sjpk 
23045916cd2Sjpk 	/* Field three: get match flag */
23145916cd2Sjpk 	errno = 0;
23245916cd2Sjpk 	zc->zc_match = (uchar_t)strtol(instr, &cp, 0);
23345916cd2Sjpk 	if (errno != 0 || (*cp != ':' && *cp != '\0')) {
23445916cd2Sjpk 		*errp = LTSNET_ILL_FLAG;
23545916cd2Sjpk 		*errstrp = (char *)instr;
23645916cd2Sjpk 		goto err_ret;
23745916cd2Sjpk 	}
23845916cd2Sjpk 	if (*cp != ':') {
23945916cd2Sjpk 		*errp = LTSNET_ILL_VALDELIM;
24045916cd2Sjpk 		*errstrp = cp;
24145916cd2Sjpk 		goto err_ret;
24245916cd2Sjpk 	}
24345916cd2Sjpk 	instr = cp + 1;
24445916cd2Sjpk 
24545916cd2Sjpk 	/* Field four: get zone-specific MLP list. */
24645916cd2Sjpk 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
24745916cd2Sjpk 	if (*nextf != ':') {
24845916cd2Sjpk 		*errstrp = (char *)nextf;
24945916cd2Sjpk 		*errp = LTSNET_ILL_ENTRY;
25045916cd2Sjpk 		goto err_ret;
25145916cd2Sjpk 	}
25245916cd2Sjpk 	if (!parse_mlp_list(&zc->zc_private_mlp, fieldbuf, errp, errstrp)) {
25345916cd2Sjpk 		*errstrp = (char *)instr + (*errstrp - fieldbuf);
25445916cd2Sjpk 		goto err_ret;
25545916cd2Sjpk 	}
25645916cd2Sjpk 	instr = nextf + 1;
25745916cd2Sjpk 
25845916cd2Sjpk 	/* Field five: get global MLP list. */
25945916cd2Sjpk 	nextf = parse_entry(fieldbuf, sizeof (fieldbuf), instr, "#:\n");
26045916cd2Sjpk 	if (*nextf != '\0' && *nextf != '#' && !isspace(*nextf)) {
26145916cd2Sjpk 		*errstrp = (char *)nextf;
26245916cd2Sjpk 		*errp = LTSNET_ILL_ENTRY;
26345916cd2Sjpk 		goto err_ret;
26445916cd2Sjpk 	}
26545916cd2Sjpk 	if (!parse_mlp_list(&zc->zc_shared_mlp, fieldbuf, errp, errstrp)) {
26645916cd2Sjpk 		*errstrp = (char *)instr + (*errstrp - fieldbuf);
26745916cd2Sjpk 		goto err_ret;
26845916cd2Sjpk 	}
26945916cd2Sjpk 
27045916cd2Sjpk 	return (zc);
27145916cd2Sjpk 
27245916cd2Sjpk err_ret:
27345916cd2Sjpk 	err = errno;
27445916cd2Sjpk 	tsol_freezcent(zc);
27545916cd2Sjpk 	errno = err;
27645916cd2Sjpk 	return (NULL);
27745916cd2Sjpk }
27845916cd2Sjpk 
27945916cd2Sjpk void
tsol_freezcent(tsol_zcent_t * zc)28045916cd2Sjpk tsol_freezcent(tsol_zcent_t *zc)
28145916cd2Sjpk {
28245916cd2Sjpk 	if (zc != NULL) {
28345916cd2Sjpk 		free(zc->zc_private_mlp);
28445916cd2Sjpk 		free(zc->zc_shared_mlp);
28545916cd2Sjpk 		free(zc);
28645916cd2Sjpk 	}
28745916cd2Sjpk }
288