xref: /onnv-gate/usr/src/cmd/tsol/tnctl/tnctl.c (revision 6509:66665723ee6a)
14746Srica /*
24746Srica  * CDDL HEADER START
34746Srica  *
44746Srica  * The contents of this file are subject to the terms of the
54746Srica  * Common Development and Distribution License (the "License").
64746Srica  * You may not use this file except in compliance with the License.
74746Srica  *
84746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94746Srica  * or http://www.opensolaris.org/os/licensing.
104746Srica  * See the License for the specific language governing permissions
114746Srica  * and limitations under the License.
124746Srica  *
134746Srica  * When distributing Covered Code, include this CDDL HEADER in each
144746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154746Srica  * If applicable, add the following below this CDDL HEADER, with the
164746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
174746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
184746Srica  *
194746Srica  * CDDL HEADER END
204746Srica  */
214746Srica 
224746Srica /*
23*6509Ston  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
244746Srica  * Use is subject to license terms.
254746Srica  */
264746Srica 
274746Srica #pragma ident	"%Z%%M%	%I%	%E% SMI"
284746Srica 
294746Srica /*
304746Srica  * tnctl.c -
314746Srica  *          Trusted Network control utility
324746Srica  */
334746Srica #include <stdio.h>
344746Srica #include <stdlib.h>
354746Srica #include <stddef.h>
364746Srica #include <unistd.h>
374746Srica #include <string.h>
384746Srica #include <errno.h>
394746Srica #include <locale.h>
404746Srica #include <fcntl.h>
414746Srica #include <sys/types.h>
424746Srica #include <sys/param.h>
434746Srica #include <sys/socket.h>
444746Srica #include <netinet/in.h>
454746Srica #include <arpa/inet.h>
464746Srica #include <netdb.h>
474746Srica #include <libtsnet.h>
484746Srica #include <zone.h>
494746Srica #include <nss_dbdefs.h>
504746Srica 
514746Srica static void process_rh(const char *);
524746Srica static void process_rhl(const char *);
534746Srica static void process_mlp(const char *);
544746Srica static void process_tp(const char *);
554746Srica static void process_tpl(const char *);
564746Srica static void process_tnzone(const char *);
574746Srica static void usage(void);
585250Ston static void translate_inet_addr(tsol_rhent_t *, int *, char [], int);
594746Srica 
604746Srica static boolean_t verbose_mode;
614746Srica static boolean_t delete_mode;
624746Srica static boolean_t flush_mode;
634746Srica 
644746Srica int
654746Srica main(int argc, char **argv)
664746Srica {
674746Srica 	extern char *optarg;
684746Srica 	int chr;
694746Srica 
704746Srica 	/* Don't do anything if labeling is not active. */
714746Srica 	if (!is_system_labeled())
724746Srica 		return (0);
734746Srica 
744746Srica 	/* set the locale for only the messages system (all else is clean) */
754746Srica 	(void) setlocale(LC_ALL, "");
764746Srica #ifndef TEXT_DOMAIN		/* Should be defined by cc -D */
774746Srica #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
784746Srica #endif
794746Srica 
804746Srica 	(void) textdomain(TEXT_DOMAIN);
814746Srica 
824746Srica 	while ((chr = getopt(argc, argv, "dfh:H:m:t:T:vz:")) != EOF) {
834746Srica 		switch (chr) {
844746Srica 		case 'd':
854746Srica 			delete_mode = B_TRUE;
864746Srica 			break;
874746Srica 		case 'f':
884746Srica 			flush_mode = B_TRUE;
894746Srica 			break;
904746Srica 		case 'h':
914746Srica 			process_rh(optarg);
924746Srica 			break;
934746Srica 		case 'H':
944746Srica 			process_rhl(optarg);
954746Srica 			break;
964746Srica 		case 'm':
974746Srica 			process_mlp(optarg);
984746Srica 			break;
994746Srica 		case 't':
1004746Srica 			process_tp(optarg);
1014746Srica 			break;
1024746Srica 		case 'T':
1034746Srica 			process_tpl(optarg);
1044746Srica 			break;
1054746Srica 		case 'v':
1064746Srica 			verbose_mode = B_TRUE;
1074746Srica 			break;
1084746Srica 		case 'z':
1094746Srica 			process_tnzone(optarg);
1104746Srica 			break;
1114746Srica 		case '?':
1124746Srica 			usage();
1134746Srica 		}
1144746Srica 	}
1154746Srica 	return (0);
1164746Srica }
1174746Srica 
1184746Srica static void
1194746Srica print_error(int linenum, int err, const char *errstr)
1204746Srica {
1214746Srica 	if (linenum > 0)
1224746Srica 		(void) fprintf(stderr, gettext("line %1$d: %2$s:\n"), linenum,
1234746Srica 		    tsol_strerror(err, errno));
1244746Srica 	else
1254746Srica 		(void) fprintf(stderr, gettext("tnctl: parsing error: %s\n"),
1264746Srica 		    tsol_strerror(err, errno));
1274746Srica 	(void) fprintf(stderr, "%.32s\n", errstr);
1284746Srica }
1294746Srica 
1304746Srica /*
1315250Ston  * Produce ascii format of address and prefix length
1325250Ston  */
1335250Ston static void
1345250Ston translate_inet_addr(tsol_rhent_t *rhentp, int *alen, char abuf[], int abuflen)
1355250Ston {
1365250Ston 	void *aptr;
1375250Ston 	tsol_rhent_t rhent;
1385250Ston 	struct in6_addr ipv6addr;
1395250Ston 	char tmpbuf[20];
1405250Ston 
1415250Ston 	(void) snprintf(tmpbuf, sizeof (tmpbuf), "/%d", rhentp->rh_prefix);
1425250Ston 
1435250Ston 	if (rhentp->rh_address.ta_family == AF_INET6) {
1445250Ston 		aptr = &(rhentp->rh_address.ta_addr_v6);
1455250Ston 		*alen = sizeof (ipv6addr);
1465250Ston 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
1475250Ston 		    abuflen);
1485250Ston 		if (rhentp->rh_prefix != 128) {
1495250Ston 			if (strlcat(abuf, tmpbuf, abuflen) >= abuflen)
1505250Ston 				(void) fprintf(stderr, gettext(
1515250Ston 				    "tnctl: buffer overflow detected: %s\n"),
1525250Ston 				    abuf);
1535250Ston 		}
1545250Ston 	} else {
1555250Ston 		aptr = &(rhentp->rh_address.ta_addr_v4);
1565250Ston 		*alen = sizeof (rhent.rh_address.ta_addr_v4);
1575250Ston 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
1585250Ston 		    abuflen);
1595250Ston 		if (rhentp->rh_prefix != 32) {
1605250Ston 			if (strlcat(abuf, tmpbuf, abuflen) >= abuflen)
1615250Ston 				(void) fprintf(stderr, gettext(
1625250Ston 				    "tnctl: buffer overflow detected: %s\n"),
1635250Ston 				    abuf);
1645250Ston 		}
1655250Ston 	}
1665250Ston }
1675250Ston 
1685250Ston /*
1694746Srica  * Load remote host entries from the designated file.
1704746Srica  */
1714746Srica static void
1724746Srica process_rhl(const char *file)
1734746Srica {
174*6509Ston 	boolean_t	error = B_FALSE;
1754746Srica 	boolean_t	success = B_FALSE;
1764746Srica 	tsol_rhent_t	*rhentp = NULL;
1774746Srica 	FILE		*fp;
1785250Ston 	int alen;
1795250Ston 	/* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
1805250Ston 	char abuf[INET6_ADDRSTRLEN+5];
1814746Srica 
1824746Srica 	if ((fp = fopen(file, "r")) == NULL) {
1834746Srica 		(void) fprintf(stderr,
1844746Srica 		    gettext("tnctl: failed to open %1$s: %2$s\n"),
1854746Srica 		    file, strerror(errno));
1864746Srica 		exit(1);
1874746Srica 	}
1884746Srica 
1894746Srica 	tsol_setrhent(1);
190*6509Ston 	while (rhentp = tsol_fgetrhent(fp, &error)) {
1914746Srica 		/* First time through the loop, flush it all */
1924746Srica 		if (!success && flush_mode)
1934746Srica 			(void) tnrh(TNDB_FLUSH, NULL);
1944746Srica 		success = B_TRUE;
1954746Srica 
1964746Srica 		if (verbose_mode)
1974746Srica 			(void) printf("loading rh entry...\n");
1984746Srica 
1994746Srica 		if (tnrh(TNDB_LOAD, rhentp) != 0) {
2004746Srica 			(void) fclose(fp);
2014746Srica 			if (errno == EFAULT)
2024746Srica 				perror("tnrh");
2034746Srica 			else
2045250Ston 				translate_inet_addr(rhentp, &alen, abuf,
2055250Ston 				    sizeof (abuf));
2064746Srica 				(void) fprintf(stderr,
2074746Srica 				    gettext("tnctl: load of remote-host entry "
2084746Srica 				    "%1$s into kernel cache failed: %2$s\n"),
2095250Ston 				    abuf, strerror(errno));
2104746Srica 			tsol_endrhent();
2114746Srica 			exit(1);
2124746Srica 		}
2134746Srica 		tsol_freerhent(rhentp);
2144746Srica 	}
2154746Srica 	if (!success) {
2164746Srica 		(void) fprintf(stderr,
2174746Srica 		    gettext("tnctl: No valid tnrhdb entries found in %s\n"),
2184746Srica 		    file);
2194746Srica 	}
2204746Srica 	(void) fclose(fp);
2214746Srica 	tsol_endrhent();
222*6509Ston 
223*6509Ston 	if (error)
224*6509Ston 		exit(1);
2254746Srica }
2264746Srica 
2274746Srica /*
2284746Srica  * The argument can be either a host name, an address
2294746Srica  * in tnrhdb address format, or a complete tnrhdb entry.
2304746Srica  */
2314746Srica static void
2324746Srica process_rh(const char *hostname)
2334746Srica {
2344746Srica 	tsol_rhstr_t rhstr;
2354746Srica 	tsol_rhent_t rhent;
2364746Srica 	tsol_rhent_t *rhentp;
2374746Srica 	int err;
2384746Srica 	int alen;
2394746Srica 	char *errstr;
2404746Srica 	/* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
2414746Srica 	char abuf[INET6_ADDRSTRLEN+5];
2424746Srica 	const char *cp;
2434746Srica 	char *cp1;
2444746Srica 	char *cp2;
2454746Srica 	void *aptr;
2464746Srica 	char buf[NSS_BUFLEN_TSOL_RH];
2474746Srica 	struct in6_addr ipv6addr;
2484746Srica 
2494746Srica 	/* was a template name provided on the command line? */
2504746Srica 	if ((cp = strrchr(hostname, ':')) != NULL && cp != hostname &&
2514746Srica 	    cp[-1] != '\\') {
2524746Srica 		/* use common tnrhdb line conversion function */
2534746Srica 		(void) str_to_rhstr(hostname, strlen(hostname), &rhstr, buf,
2544746Srica 		    sizeof (buf));
2554746Srica 		rhentp = rhstr_to_ent(&rhstr, &err, &errstr);
2564746Srica 		if (rhentp == NULL) {
2574746Srica 			print_error(0, err, errstr);
2584746Srica 			exit(1);
2594746Srica 		}
2604746Srica 	} else {
2614746Srica 		char *hostname_p;
2624746Srica 		char *prefix_p;
2634746Srica 		struct hostent *hp;
2644746Srica 
2654746Srica 		/* Check for a subnet prefix length */
2664746Srica 		if ((prefix_p = strchr(hostname, '/')) != NULL) {
2674746Srica 			cp1 = prefix_p + 1;
2684746Srica 			errno = 0;
2694746Srica 			rhent.rh_prefix = strtol(cp1, &cp2, 0);
2704746Srica 			if (*cp2 != '\0' || errno != 0 || rhent.rh_prefix < 0) {
2714746Srica 				(void) fprintf(stderr, gettext("tnct: invalid "
2724746Srica 				    "prefix length: %s\n"), cp);
2734746Srica 				exit(2);
2744746Srica 			}
2754746Srica 		} else {
2764746Srica 			rhent.rh_prefix = -1;
2774746Srica 		}
2784746Srica 
2794746Srica 		/* Strip any backslashes from numeric address */
2804746Srica 		hostname_p = malloc(strlen(hostname)+1);
2814746Srica 		if (hostname_p == NULL) {
2824746Srica 			perror("tnctl");
2834746Srica 			exit(2);
2844746Srica 		}
2854746Srica 		cp1 = hostname_p;
2864746Srica 		while (*hostname != '\0' && *hostname != '/') {
2874746Srica 			*cp1 = *hostname++;
2884746Srica 			if (*cp1 != '\\')
2894746Srica 				cp1++;
2904746Srica 		}
2914746Srica 		*cp1 = '\0';
2924746Srica 
2934746Srica 		/* Convert address or hostname to binary af_inet6 format */
2944746Srica 		hp = getipnodebyname(hostname_p, AF_INET6,
2954746Srica 		    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &err);
2964746Srica 		if (hp == NULL) {
2974746Srica 			(void) fprintf(stderr, gettext("tnctl: unknown host "
2984746Srica 			    "or invalid literal address: %s\n"), hostname_p);
2994746Srica 			if (err == TRY_AGAIN)
3004746Srica 				(void) fprintf(stderr,
3014746Srica 				    gettext("\t(try again later)\n"));
3024746Srica 			exit(2);
3034746Srica 		}
3044746Srica 		free(hostname_p);
3054746Srica 		(void) memcpy(&ipv6addr, hp->h_addr, hp->h_length);
3064746Srica 
3074746Srica 		/* if ipv4 address, convert to af_inet format */
3084746Srica 		if (IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
3094746Srica 			rhent.rh_address.ta_family = AF_INET;
3104746Srica 			IN6_V4MAPPED_TO_INADDR(&ipv6addr,
3114746Srica 			    &rhent.rh_address.ta_addr_v4);
3124746Srica 			if (rhent.rh_prefix == -1)
3134746Srica 				rhent.rh_prefix = 32;
3144746Srica 		} else {
3154746Srica 			rhent.rh_address.ta_family = AF_INET6;
3164746Srica 			rhent.rh_address.ta_addr_v6 = ipv6addr;
3174746Srica 			if (rhent.rh_prefix == -1)
3184746Srica 				rhent.rh_prefix = 128;
3194746Srica 		}
3204746Srica 		rhent.rh_template[0] = '\0';
3214746Srica 		rhentp = &rhent;
3224746Srica 	}
3234746Srica 
3244746Srica 	/* produce ascii format of address and prefix length */
3255250Ston 	translate_inet_addr(rhentp, &alen, abuf, sizeof (abuf));
3264746Srica 
3274746Srica 	/*
3284746Srica 	 * look up the entry from ldap or tnrhdb if this is a load
3294746Srica 	 * request and a template name was not provided.
3304746Srica 	 */
3314746Srica 	if (!delete_mode &&
3324746Srica 	    rhentp->rh_template[0] == '\0' &&
3334746Srica 	    (rhentp = tsol_getrhbyaddr(abuf, alen,
3344746Srica 	    rhent.rh_address.ta_family)) == NULL) {
3354746Srica 		(void) fprintf(stderr,
3364746Srica 		    gettext("tnctl: database lookup failed for %s\n"),
3374746Srica 		    abuf);
3384746Srica 		exit(1);
3394746Srica 	}
3404746Srica 
3414746Srica 	if (verbose_mode)
3424746Srica 		(void) printf("%s rh entry %s\n", delete_mode ? "deleting" :
3434746Srica 		    "loading", abuf);
3444746Srica 
3454746Srica 	/* update the tnrhdb entry in the kernel */
3464746Srica 	if (tnrh(delete_mode ? TNDB_DELETE : TNDB_LOAD, rhentp) != 0) {
3474746Srica 		if (errno == EFAULT)
3484746Srica 			perror("tnrh");
3494746Srica 		else if (errno == ENOENT)
3504746Srica 			(void) fprintf(stderr,
3514746Srica 			    gettext("tnctl: %1$s of remote-host kernel cache "
3524746Srica 			    "entry %2$s failed: no such entry\n"),
3534746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
3544746Srica 			    abuf);
3554746Srica 		else
3564746Srica 			(void) fprintf(stderr,
3574746Srica 			    gettext("tnctl: %1$s of remote-host kernel cache "
3584746Srica 			    "entry %2$s failed: %3$s\n"),
3594746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
3604746Srica 			    abuf, strerror(errno));
3614746Srica 		exit(1);
3624746Srica 	}
3634746Srica 	if (rhentp != &rhent)
3644746Srica 		tsol_freerhent(rhentp);
3654746Srica }
3664746Srica 
3674746Srica static void
3684746Srica handle_mlps(zoneid_t zoneid, tsol_mlp_t *mlp, int flags, int cmd)
3694746Srica {
3704746Srica 	tsol_mlpent_t tsme;
3714746Srica 
3724746Srica 	tsme.tsme_zoneid = zoneid;
3734746Srica 	tsme.tsme_flags = flags;
3744746Srica 	while (!TSOL_MLP_END(mlp)) {
3754746Srica 		tsme.tsme_mlp = *mlp;
3764746Srica 		if (tnmlp(cmd, &tsme) != 0) {
3774746Srica 			/*
3784746Srica 			 * Usage of ?: here is ugly, but helps with
3794746Srica 			 * localization.
3804746Srica 			 */
3814746Srica 			(void) fprintf(stderr,
3824746Srica 			    flags & TSOL_MEF_SHARED ?
3834746Srica 			    gettext("tnctl: cannot set "
3844746Srica 			    "shared MLP on %1$d-%2$d/%3$d: %4$s\n") :
3854746Srica 			    gettext("tnctl: cannot set "
3864746Srica 			    "zone-specific MLP on %1$d-%2$d/%3$d: %4$s\n"),
3874746Srica 			    mlp->mlp_port, mlp->mlp_port_upper, mlp->mlp_ipp,
3884746Srica 			    strerror(errno));
3894746Srica 			exit(1);
3904746Srica 		}
3914746Srica 		mlp++;
3924746Srica 	}
3934746Srica }
3944746Srica 
3954746Srica /*
3964746Srica  * This reads the configuration for the global zone out of tnzonecfg
3974746Srica  * and sets it in the kernel.  The non-global zones are configured
3984746Srica  * by zoneadmd.
3994746Srica  */
4004746Srica static void
4014746Srica process_tnzone(const char *file)
4024746Srica {
4034746Srica 	tsol_zcent_t *zc;
4044746Srica 	tsol_mlpent_t tsme;
4054746Srica 	int err;
4064746Srica 	char *errstr;
4074746Srica 	FILE *fp;
4084746Srica 	char line[2048], *cp;
4094746Srica 	int linenum, errors;
4104746Srica 
4114746Srica 	if ((fp = fopen(file, "r")) == NULL) {
4124746Srica 		(void) fprintf(stderr,
4134746Srica 		    gettext("tnctl: failed to open %s: %s\n"), file,
4144746Srica 		    strerror(errno));
4154746Srica 		exit(1);
4164746Srica 	}
4174746Srica 
4184746Srica 	linenum = errors = 0;
4194746Srica 	zc = NULL;
4204746Srica 	while (fgets(line, sizeof (line), fp) != NULL) {
4214746Srica 		if ((cp = strchr(line, '\n')) != NULL)
4224746Srica 			*cp = '\0';
4234746Srica 
4244746Srica 		linenum++;
4254746Srica 		if ((zc = tsol_sgetzcent(line, &err, &errstr)) == NULL) {
4264746Srica 			if (err == LTSNET_EMPTY)
4274746Srica 				continue;
4284746Srica 			if (errors == 0) {
4294746Srica 				int errtmp = errno;
4304746Srica 
4314746Srica 				(void) fprintf(stderr, gettext("tnctl: errors "
4324746Srica 				    "parsing %s:\n"), file);
4334746Srica 				errno = errtmp;
4344746Srica 			}
4354746Srica 			print_error(linenum, err, errstr);
4364746Srica 			errors++;
4374746Srica 			continue;
4384746Srica 		}
4394746Srica 
4404746Srica 		if (strcasecmp(zc->zc_name, "global") == 0)
4414746Srica 			break;
4424746Srica 		tsol_freezcent(zc);
4434746Srica 	}
4444746Srica 	(void) fclose(fp);
4454746Srica 
4464746Srica 	if (zc == NULL) {
4474746Srica 		(void) fprintf(stderr,
4484746Srica 		    gettext("tnctl: cannot find global zone in %s\n"), file);
4494746Srica 		exit(1);
4504746Srica 	}
4514746Srica 
4524746Srica 	tsme.tsme_zoneid = GLOBAL_ZONEID;
4534746Srica 	tsme.tsme_flags = 0;
4544746Srica 	if (flush_mode)
4554746Srica 		(void) tnmlp(TNDB_FLUSH, &tsme);
4564746Srica 
4574746Srica 	handle_mlps(GLOBAL_ZONEID, zc->zc_private_mlp, 0, TNDB_LOAD);
4584746Srica 	handle_mlps(GLOBAL_ZONEID, zc->zc_shared_mlp, TSOL_MEF_SHARED,
4594746Srica 	    TNDB_LOAD);
4604746Srica 
4614746Srica 	tsol_freezcent(zc);
4624746Srica }
4634746Srica 
4644746Srica static void
4654746Srica process_tpl(const char *file)
4664746Srica {
4674746Srica 	FILE		*fp;
468*6509Ston 	boolean_t	error = B_FALSE;
4694746Srica 	boolean_t	success = B_FALSE;
4704746Srica 	tsol_tpent_t	*tpentp;
4714746Srica 
4724746Srica 	if ((fp = fopen(file, "r")) == NULL) {
4734746Srica 		(void) fprintf(stderr,
4744746Srica 		    gettext("tnctl: failed to open %s: %s\n"), file,
4754746Srica 		    strerror(errno));
4764746Srica 		exit(1);
4774746Srica 	}
4784746Srica 
4794746Srica 	tsol_settpent(1);
480*6509Ston 	while (tpentp = tsol_fgettpent(fp, &error)) {
4814746Srica 		/* First time through the loop, flush it all */
4824746Srica 		if (!success && flush_mode)
4834746Srica 			(void) tnrhtp(TNDB_FLUSH, NULL);
4844746Srica 
4854746Srica 		success = B_TRUE;
4864746Srica 
4874746Srica 		if (verbose_mode)
4884746Srica 			(void) printf("tnctl: loading rhtp entry ...\n");
4894746Srica 
4904746Srica 		if (tnrhtp(TNDB_LOAD, tpentp) != 0) {
4914746Srica 			(void) fclose(fp);
4924746Srica 			if (errno == EFAULT)
4934746Srica 				perror("tnrhtp");
4944746Srica 			else
4954746Srica 				(void) fprintf(stderr, gettext("tnctl: load "
4964746Srica 				    "of remote-host template %1$s into kernel "
4974746Srica 				    "cache failed: %2$s\n"), tpentp->name,
4984746Srica 				    strerror(errno));
4994746Srica 			tsol_endtpent();
5004746Srica 			exit(1);
5014746Srica 		}
5024746Srica 		tsol_freetpent(tpentp);
5034746Srica 	}
5044746Srica 	if (!success) {
5054746Srica 		(void) fprintf(stderr,
5064746Srica 		    gettext("tnctl: No valid tnrhtp entries found in %s\n"),
5074746Srica 		    file);
5084746Srica 	}
5094746Srica 	(void) fclose(fp);
5104746Srica 	tsol_endtpent();
511*6509Ston 
512*6509Ston 	if (error)
513*6509Ston 		exit(1);
5144746Srica }
5154746Srica 
5164746Srica static void
5174746Srica process_tp(const char *template)
5184746Srica {
5194746Srica 	tsol_tpstr_t tpstr;
5204746Srica 	tsol_tpent_t tpent;
5214746Srica 	tsol_tpent_t *tpentp;
5224746Srica 	int err;
5234746Srica 	char *errstr;
5244746Srica 	char buf[NSS_BUFLEN_TSOL_TP];
5254746Srica 
5264746Srica 	if (strchr(template, ':') != NULL) {
5274746Srica 		(void) str_to_tpstr(template, strlen(template), &tpstr, buf,
5284746Srica 		    sizeof (buf));
5294746Srica 		tpentp = tpstr_to_ent(&tpstr, &err, &errstr);
5304746Srica 		if (tpentp == NULL) {
5314746Srica 			print_error(0, err, errstr);
5324746Srica 			exit(1);
5334746Srica 		}
5344746Srica 	} else if (delete_mode) {
5354746Srica 		(void) memset(&tpent, 0, sizeof (tpent));
5364746Srica 		tpentp = &tpent;
5374746Srica 		(void) strlcpy(tpentp->name, template, sizeof (tpentp->name));
5384746Srica 	} else if ((tpentp = tsol_gettpbyname(template)) == NULL) {
5394746Srica 		(void) fprintf(stderr,
5404746Srica 		    gettext("tnctl: template %s not found\n"), template);
5414746Srica 		exit(1);
5424746Srica 	}
5434746Srica 
5444746Srica 	if (verbose_mode)
5454746Srica 		(void) printf("%s rhtp entry ...\n", delete_mode ? "deleting" :
5464746Srica 		    "loading");
5474746Srica 
5484746Srica 	if (tnrhtp(delete_mode ? TNDB_DELETE : TNDB_LOAD, tpentp) != 0) {
5494746Srica 		if (errno == EFAULT)
5504746Srica 			perror("tnrhtp");
5514746Srica 		else if (errno == ENOENT)
5524746Srica 			(void) fprintf(stderr,
5534746Srica 			    gettext("tnctl: %1$s of remote-host template "
5544746Srica 			    "kernel cache entry %2$s failed: no such "
5554746Srica 			    "entry\n"),
5564746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
5574746Srica 			    tpentp->name);
5584746Srica 		else
5594746Srica 			(void) fprintf(stderr,
5604746Srica 			    gettext("tnctl: %1$s of remote-host template "
5614746Srica 			    "kernel cache entry %2$s failed: %3$s\n"),
5624746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
5634746Srica 			    tpentp->name, strerror(errno));
5644746Srica 		exit(1);
5654746Srica 	}
5664746Srica 	if (tpentp != &tpent)
5674746Srica 		tsol_freetpent(tpentp);
5684746Srica }
5694746Srica 
5704746Srica static void
5714746Srica process_mlp(const char *str)
5724746Srica {
5734746Srica 	const char *cp;
5744746Srica 	char zonename[ZONENAME_MAX];
5754746Srica 	zoneid_t zoneid;
5764746Srica 	tsol_zcent_t *zc;
5774746Srica 	int err;
5784746Srica 	char *errstr;
5794746Srica 	char *sbuf;
5804746Srica 
5814746Srica 	if ((cp = strchr(str, ':')) == NULL) {
5824746Srica 		if (!delete_mode) {
5834746Srica 			(void) fprintf(stderr,
5844746Srica 			    gettext("tnctl: need MLP list to insert\n"));
5854746Srica 			exit(2);
5864746Srica 		}
5874746Srica 		(void) strlcpy(zonename, str, sizeof (zonename));
5884746Srica 	} else if (cp - str >= ZONENAME_MAX) {
5894746Srica 		(void) fprintf(stderr, gettext("tnctl: illegal zone name\n"));
5904746Srica 		exit(2);
5914746Srica 	} else {
5924746Srica 		(void) memcpy(zonename, str, cp - str);
5934746Srica 		zonename[cp - str] = '\0';
5944746Srica 		str = cp + 1;
5954746Srica 	}
5964746Srica 
5974746Srica 	if ((zoneid = getzoneidbyname(zonename)) == -1) {
5984746Srica 		(void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"),
5994746Srica 		    zonename);
6004746Srica 		exit(1);
6014746Srica 	}
6024746Srica 
6034746Srica 	sbuf = malloc(strlen(zonename) + sizeof (":ADMIN_LOW:0:") +
6044746Srica 	    strlen(str));
6054746Srica 	if (sbuf == NULL) {
6064746Srica 		perror("malloc");
6074746Srica 		exit(1);
6084746Srica 	}
6094746Srica 	/* LINTED: sprintf is known not to be unbounded here */
6104746Srica 	(void) sprintf(sbuf, "%s:ADMIN_LOW:0:%s", zonename, str);
6114746Srica 	if ((zc = tsol_sgetzcent(sbuf, &err, &errstr)) == NULL) {
6124746Srica 		(void) fprintf(stderr,
6134746Srica 		    gettext("tnctl: unable to parse MLPs\n"));
6144746Srica 		exit(1);
6154746Srica 	}
6164746Srica 	handle_mlps(zoneid, zc->zc_private_mlp, 0,
6174746Srica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
6184746Srica 	handle_mlps(zoneid, zc->zc_shared_mlp, TSOL_MEF_SHARED,
6194746Srica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
6204746Srica 	tsol_freezcent(zc);
6214746Srica }
6224746Srica 
6234746Srica static void
6244746Srica usage(void)
6254746Srica {
6264746Srica 	(void) fprintf(stderr, gettext("usage: tnctl [-dfv] "
6274746Srica 	    "[-h host[/prefix][:tmpl]] [-m zone:priv:share]\n\t"
6284746Srica 	    "[-t tmpl[:key=val[;key=val]]] [-[HTz] file]\n"));
6294746Srica 
6304746Srica 	exit(1);
6314746Srica }
632