xref: /onnv-gate/usr/src/cmd/tsol/tnctl/tnctl.c (revision 4746:0bc0c48f4304)
1*4746Srica /*
2*4746Srica  * CDDL HEADER START
3*4746Srica  *
4*4746Srica  * The contents of this file are subject to the terms of the
5*4746Srica  * Common Development and Distribution License (the "License").
6*4746Srica  * You may not use this file except in compliance with the License.
7*4746Srica  *
8*4746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4746Srica  * or http://www.opensolaris.org/os/licensing.
10*4746Srica  * See the License for the specific language governing permissions
11*4746Srica  * and limitations under the License.
12*4746Srica  *
13*4746Srica  * When distributing Covered Code, include this CDDL HEADER in each
14*4746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4746Srica  * If applicable, add the following below this CDDL HEADER, with the
16*4746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
17*4746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4746Srica  *
19*4746Srica  * CDDL HEADER END
20*4746Srica  */
21*4746Srica 
22*4746Srica /*
23*4746Srica  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*4746Srica  * Use is subject to license terms.
25*4746Srica  */
26*4746Srica 
27*4746Srica #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*4746Srica 
29*4746Srica /*
30*4746Srica  * tnctl.c -
31*4746Srica  *          Trusted Network control utility
32*4746Srica  */
33*4746Srica #include <stdio.h>
34*4746Srica #include <stdlib.h>
35*4746Srica #include <stddef.h>
36*4746Srica #include <unistd.h>
37*4746Srica #include <string.h>
38*4746Srica #include <errno.h>
39*4746Srica #include <locale.h>
40*4746Srica #include <fcntl.h>
41*4746Srica #include <sys/types.h>
42*4746Srica #include <sys/param.h>
43*4746Srica #include <sys/socket.h>
44*4746Srica #include <netinet/in.h>
45*4746Srica #include <arpa/inet.h>
46*4746Srica #include <netdb.h>
47*4746Srica #include <libtsnet.h>
48*4746Srica #include <zone.h>
49*4746Srica #include <nss_dbdefs.h>
50*4746Srica 
51*4746Srica static void process_rh(const char *);
52*4746Srica static void process_rhl(const char *);
53*4746Srica static void process_mlp(const char *);
54*4746Srica static void process_tp(const char *);
55*4746Srica static void process_tpl(const char *);
56*4746Srica static void process_tnzone(const char *);
57*4746Srica static void usage(void);
58*4746Srica 
59*4746Srica static boolean_t verbose_mode;
60*4746Srica static boolean_t delete_mode;
61*4746Srica static boolean_t flush_mode;
62*4746Srica 
63*4746Srica int
64*4746Srica main(int argc, char **argv)
65*4746Srica {
66*4746Srica 	extern char *optarg;
67*4746Srica 	int chr;
68*4746Srica 
69*4746Srica 	/* Don't do anything if labeling is not active. */
70*4746Srica 	if (!is_system_labeled())
71*4746Srica 		return (0);
72*4746Srica 
73*4746Srica 	/* set the locale for only the messages system (all else is clean) */
74*4746Srica 	(void) setlocale(LC_ALL, "");
75*4746Srica #ifndef TEXT_DOMAIN		/* Should be defined by cc -D */
76*4746Srica #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
77*4746Srica #endif
78*4746Srica 
79*4746Srica 	(void) textdomain(TEXT_DOMAIN);
80*4746Srica 
81*4746Srica 	while ((chr = getopt(argc, argv, "dfh:H:m:t:T:vz:")) != EOF) {
82*4746Srica 		switch (chr) {
83*4746Srica 		case 'd':
84*4746Srica 			delete_mode = B_TRUE;
85*4746Srica 			break;
86*4746Srica 		case 'f':
87*4746Srica 			flush_mode = B_TRUE;
88*4746Srica 			break;
89*4746Srica 		case 'h':
90*4746Srica 			process_rh(optarg);
91*4746Srica 			break;
92*4746Srica 		case 'H':
93*4746Srica 			process_rhl(optarg);
94*4746Srica 			break;
95*4746Srica 		case 'm':
96*4746Srica 			process_mlp(optarg);
97*4746Srica 			break;
98*4746Srica 		case 't':
99*4746Srica 			process_tp(optarg);
100*4746Srica 			break;
101*4746Srica 		case 'T':
102*4746Srica 			process_tpl(optarg);
103*4746Srica 			break;
104*4746Srica 		case 'v':
105*4746Srica 			verbose_mode = B_TRUE;
106*4746Srica 			break;
107*4746Srica 		case 'z':
108*4746Srica 			process_tnzone(optarg);
109*4746Srica 			break;
110*4746Srica 		case '?':
111*4746Srica 			usage();
112*4746Srica 		}
113*4746Srica 	}
114*4746Srica 	return (0);
115*4746Srica }
116*4746Srica 
117*4746Srica static void
118*4746Srica print_error(int linenum, int err, const char *errstr)
119*4746Srica {
120*4746Srica 	if (linenum > 0)
121*4746Srica 		(void) fprintf(stderr, gettext("line %1$d: %2$s:\n"), linenum,
122*4746Srica 		    tsol_strerror(err, errno));
123*4746Srica 	else
124*4746Srica 		(void) fprintf(stderr, gettext("tnctl: parsing error: %s\n"),
125*4746Srica 		    tsol_strerror(err, errno));
126*4746Srica 	(void) fprintf(stderr, "%.32s\n", errstr);
127*4746Srica }
128*4746Srica 
129*4746Srica /*
130*4746Srica  * Load remote host entries from the designated file.
131*4746Srica  */
132*4746Srica static void
133*4746Srica process_rhl(const char *file)
134*4746Srica {
135*4746Srica 	boolean_t	success = B_FALSE;
136*4746Srica 	tsol_rhent_t	*rhentp = NULL;
137*4746Srica 	FILE		*fp;
138*4746Srica 
139*4746Srica 	if ((fp = fopen(file, "r")) == NULL) {
140*4746Srica 		(void) fprintf(stderr,
141*4746Srica 		    gettext("tnctl: failed to open %1$s: %2$s\n"),
142*4746Srica 		    file, strerror(errno));
143*4746Srica 		exit(1);
144*4746Srica 	}
145*4746Srica 
146*4746Srica 	tsol_setrhent(1);
147*4746Srica 	while (rhentp = tsol_fgetrhent(fp)) {
148*4746Srica 		/* First time through the loop, flush it all */
149*4746Srica 		if (!success && flush_mode)
150*4746Srica 			(void) tnrh(TNDB_FLUSH, NULL);
151*4746Srica 		success = B_TRUE;
152*4746Srica 
153*4746Srica 		if (verbose_mode)
154*4746Srica 			(void) printf("loading rh entry...\n");
155*4746Srica 
156*4746Srica 		if (tnrh(TNDB_LOAD, rhentp) != 0) {
157*4746Srica 			(void) fclose(fp);
158*4746Srica 			if (errno == EFAULT)
159*4746Srica 				perror("tnrh");
160*4746Srica 			else
161*4746Srica 				(void) fprintf(stderr,
162*4746Srica 				    gettext("tnctl: load of remote-host entry "
163*4746Srica 				    "%1$s into kernel cache failed: %2$s\n"),
164*4746Srica 				    rhentp->rh_template, strerror(errno));
165*4746Srica 			tsol_endrhent();
166*4746Srica 			exit(1);
167*4746Srica 		}
168*4746Srica 		tsol_freerhent(rhentp);
169*4746Srica 	}
170*4746Srica 	if (!success) {
171*4746Srica 		(void) fprintf(stderr,
172*4746Srica 		    gettext("tnctl: No valid tnrhdb entries found in %s\n"),
173*4746Srica 		    file);
174*4746Srica 	}
175*4746Srica 	(void) fclose(fp);
176*4746Srica 	tsol_endrhent();
177*4746Srica }
178*4746Srica 
179*4746Srica /*
180*4746Srica  * The argument can be either a host name, an address
181*4746Srica  * in tnrhdb address format, or a complete tnrhdb entry.
182*4746Srica  */
183*4746Srica static void
184*4746Srica process_rh(const char *hostname)
185*4746Srica {
186*4746Srica 	tsol_rhstr_t rhstr;
187*4746Srica 	tsol_rhent_t rhent;
188*4746Srica 	tsol_rhent_t *rhentp;
189*4746Srica 	int err;
190*4746Srica 	int alen;
191*4746Srica 	char *errstr;
192*4746Srica 	/* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
193*4746Srica 	char abuf[INET6_ADDRSTRLEN+5];
194*4746Srica 	const char *cp;
195*4746Srica 	char *cp1;
196*4746Srica 	char *cp2;
197*4746Srica 	void *aptr;
198*4746Srica 	char buf[NSS_BUFLEN_TSOL_RH];
199*4746Srica 	struct in6_addr ipv6addr;
200*4746Srica 
201*4746Srica 	/* was a template name provided on the command line? */
202*4746Srica 	if ((cp = strrchr(hostname, ':')) != NULL && cp != hostname &&
203*4746Srica 	    cp[-1] != '\\') {
204*4746Srica 		/* use common tnrhdb line conversion function */
205*4746Srica 		(void) str_to_rhstr(hostname, strlen(hostname), &rhstr, buf,
206*4746Srica 		    sizeof (buf));
207*4746Srica 		rhentp = rhstr_to_ent(&rhstr, &err, &errstr);
208*4746Srica 		if (rhentp == NULL) {
209*4746Srica 			print_error(0, err, errstr);
210*4746Srica 			exit(1);
211*4746Srica 		}
212*4746Srica 	} else {
213*4746Srica 		char *hostname_p;
214*4746Srica 		char *prefix_p;
215*4746Srica 		struct hostent *hp;
216*4746Srica 
217*4746Srica 		/* Check for a subnet prefix length */
218*4746Srica 		if ((prefix_p = strchr(hostname, '/')) != NULL) {
219*4746Srica 			cp1 = prefix_p + 1;
220*4746Srica 			errno = 0;
221*4746Srica 			rhent.rh_prefix = strtol(cp1, &cp2, 0);
222*4746Srica 			if (*cp2 != '\0' || errno != 0 || rhent.rh_prefix < 0) {
223*4746Srica 				(void) fprintf(stderr, gettext("tnct: invalid "
224*4746Srica 				    "prefix length: %s\n"), cp);
225*4746Srica 				exit(2);
226*4746Srica 			}
227*4746Srica 		} else {
228*4746Srica 			rhent.rh_prefix = -1;
229*4746Srica 		}
230*4746Srica 
231*4746Srica 		/* Strip any backslashes from numeric address */
232*4746Srica 		hostname_p = malloc(strlen(hostname)+1);
233*4746Srica 		if (hostname_p == NULL) {
234*4746Srica 			perror("tnctl");
235*4746Srica 			exit(2);
236*4746Srica 		}
237*4746Srica 		cp1 = hostname_p;
238*4746Srica 		while (*hostname != '\0' && *hostname != '/') {
239*4746Srica 			*cp1 = *hostname++;
240*4746Srica 			if (*cp1 != '\\')
241*4746Srica 				cp1++;
242*4746Srica 		}
243*4746Srica 		*cp1 = '\0';
244*4746Srica 
245*4746Srica 		/* Convert address or hostname to binary af_inet6 format */
246*4746Srica 		hp = getipnodebyname(hostname_p, AF_INET6,
247*4746Srica 		    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &err);
248*4746Srica 		if (hp == NULL) {
249*4746Srica 			(void) fprintf(stderr, gettext("tnctl: unknown host "
250*4746Srica 			    "or invalid literal address: %s\n"), hostname_p);
251*4746Srica 			if (err == TRY_AGAIN)
252*4746Srica 				(void) fprintf(stderr,
253*4746Srica 				    gettext("\t(try again later)\n"));
254*4746Srica 			exit(2);
255*4746Srica 		}
256*4746Srica 		free(hostname_p);
257*4746Srica 		(void) memcpy(&ipv6addr, hp->h_addr, hp->h_length);
258*4746Srica 
259*4746Srica 		/* if ipv4 address, convert to af_inet format */
260*4746Srica 		if (IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
261*4746Srica 			rhent.rh_address.ta_family = AF_INET;
262*4746Srica 			IN6_V4MAPPED_TO_INADDR(&ipv6addr,
263*4746Srica 			    &rhent.rh_address.ta_addr_v4);
264*4746Srica 			if (rhent.rh_prefix == -1)
265*4746Srica 				rhent.rh_prefix = 32;
266*4746Srica 		} else {
267*4746Srica 			rhent.rh_address.ta_family = AF_INET6;
268*4746Srica 			rhent.rh_address.ta_addr_v6 = ipv6addr;
269*4746Srica 			if (rhent.rh_prefix == -1)
270*4746Srica 				rhent.rh_prefix = 128;
271*4746Srica 		}
272*4746Srica 		rhent.rh_template[0] = '\0';
273*4746Srica 		rhentp = &rhent;
274*4746Srica 	}
275*4746Srica 
276*4746Srica 	/* produce ascii format of address and prefix length */
277*4746Srica 	if (rhentp->rh_address.ta_family == AF_INET6) {
278*4746Srica 		aptr = &(rhentp->rh_address.ta_addr_v6);
279*4746Srica 		alen = sizeof (ipv6addr);
280*4746Srica 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
281*4746Srica 		    sizeof (abuf));
282*4746Srica 		if (rhentp->rh_prefix != 128) {
283*4746Srica 			cp1 = abuf + strlen(abuf);
284*4746Srica 			(void) sprintf(cp1, "/%d", rhentp->rh_prefix);
285*4746Srica 		}
286*4746Srica 	} else {
287*4746Srica 		aptr = &(rhentp->rh_address.ta_addr_v4);
288*4746Srica 		alen = sizeof (rhent.rh_address.ta_addr_v4);
289*4746Srica 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
290*4746Srica 		    sizeof (abuf));
291*4746Srica 		if (rhentp->rh_prefix != 32) {
292*4746Srica 			cp1 = abuf + strlen(abuf);
293*4746Srica 			(void) sprintf(cp1, "/%d", rhentp->rh_prefix);
294*4746Srica 		}
295*4746Srica 	}
296*4746Srica 
297*4746Srica 	/*
298*4746Srica 	 * look up the entry from ldap or tnrhdb if this is a load
299*4746Srica 	 * request and a template name was not provided.
300*4746Srica 	 */
301*4746Srica 	if (!delete_mode &&
302*4746Srica 	    rhentp->rh_template[0] == '\0' &&
303*4746Srica 	    (rhentp = tsol_getrhbyaddr(abuf, alen,
304*4746Srica 	    rhent.rh_address.ta_family)) == NULL) {
305*4746Srica 		(void) fprintf(stderr,
306*4746Srica 		    gettext("tnctl: database lookup failed for %s\n"),
307*4746Srica 		    abuf);
308*4746Srica 		exit(1);
309*4746Srica 	}
310*4746Srica 
311*4746Srica 	if (verbose_mode)
312*4746Srica 		(void) printf("%s rh entry %s\n", delete_mode ? "deleting" :
313*4746Srica 		    "loading", abuf);
314*4746Srica 
315*4746Srica 	/* update the tnrhdb entry in the kernel */
316*4746Srica 	if (tnrh(delete_mode ? TNDB_DELETE : TNDB_LOAD, rhentp) != 0) {
317*4746Srica 		if (errno == EFAULT)
318*4746Srica 			perror("tnrh");
319*4746Srica 		else if (errno == ENOENT)
320*4746Srica 			(void) fprintf(stderr,
321*4746Srica 			    gettext("tnctl: %1$s of remote-host kernel cache "
322*4746Srica 			    "entry %2$s failed: no such entry\n"),
323*4746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
324*4746Srica 			    abuf);
325*4746Srica 		else
326*4746Srica 			(void) fprintf(stderr,
327*4746Srica 			    gettext("tnctl: %1$s of remote-host kernel cache "
328*4746Srica 			    "entry %2$s failed: %3$s\n"),
329*4746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
330*4746Srica 			    abuf, strerror(errno));
331*4746Srica 		exit(1);
332*4746Srica 	}
333*4746Srica 	if (rhentp != &rhent)
334*4746Srica 		tsol_freerhent(rhentp);
335*4746Srica }
336*4746Srica 
337*4746Srica static void
338*4746Srica handle_mlps(zoneid_t zoneid, tsol_mlp_t *mlp, int flags, int cmd)
339*4746Srica {
340*4746Srica 	tsol_mlpent_t tsme;
341*4746Srica 
342*4746Srica 	tsme.tsme_zoneid = zoneid;
343*4746Srica 	tsme.tsme_flags = flags;
344*4746Srica 	while (!TSOL_MLP_END(mlp)) {
345*4746Srica 		tsme.tsme_mlp = *mlp;
346*4746Srica 		if (tnmlp(cmd, &tsme) != 0) {
347*4746Srica 			/*
348*4746Srica 			 * Usage of ?: here is ugly, but helps with
349*4746Srica 			 * localization.
350*4746Srica 			 */
351*4746Srica 			(void) fprintf(stderr,
352*4746Srica 			    flags & TSOL_MEF_SHARED ?
353*4746Srica 			    gettext("tnctl: cannot set "
354*4746Srica 			    "shared MLP on %1$d-%2$d/%3$d: %4$s\n") :
355*4746Srica 			    gettext("tnctl: cannot set "
356*4746Srica 			    "zone-specific MLP on %1$d-%2$d/%3$d: %4$s\n"),
357*4746Srica 			    mlp->mlp_port, mlp->mlp_port_upper, mlp->mlp_ipp,
358*4746Srica 			    strerror(errno));
359*4746Srica 			exit(1);
360*4746Srica 		}
361*4746Srica 		mlp++;
362*4746Srica 	}
363*4746Srica }
364*4746Srica 
365*4746Srica /*
366*4746Srica  * This reads the configuration for the global zone out of tnzonecfg
367*4746Srica  * and sets it in the kernel.  The non-global zones are configured
368*4746Srica  * by zoneadmd.
369*4746Srica  */
370*4746Srica static void
371*4746Srica process_tnzone(const char *file)
372*4746Srica {
373*4746Srica 	tsol_zcent_t *zc;
374*4746Srica 	tsol_mlpent_t tsme;
375*4746Srica 	int err;
376*4746Srica 	char *errstr;
377*4746Srica 	FILE *fp;
378*4746Srica 	char line[2048], *cp;
379*4746Srica 	int linenum, errors;
380*4746Srica 
381*4746Srica 	if ((fp = fopen(file, "r")) == NULL) {
382*4746Srica 		(void) fprintf(stderr,
383*4746Srica 		    gettext("tnctl: failed to open %s: %s\n"), file,
384*4746Srica 		    strerror(errno));
385*4746Srica 		exit(1);
386*4746Srica 	}
387*4746Srica 
388*4746Srica 	linenum = errors = 0;
389*4746Srica 	zc = NULL;
390*4746Srica 	while (fgets(line, sizeof (line), fp) != NULL) {
391*4746Srica 		if ((cp = strchr(line, '\n')) != NULL)
392*4746Srica 			*cp = '\0';
393*4746Srica 
394*4746Srica 		linenum++;
395*4746Srica 		if ((zc = tsol_sgetzcent(line, &err, &errstr)) == NULL) {
396*4746Srica 			if (err == LTSNET_EMPTY)
397*4746Srica 				continue;
398*4746Srica 			if (errors == 0) {
399*4746Srica 				int errtmp = errno;
400*4746Srica 
401*4746Srica 				(void) fprintf(stderr, gettext("tnctl: errors "
402*4746Srica 				    "parsing %s:\n"), file);
403*4746Srica 				errno = errtmp;
404*4746Srica 			}
405*4746Srica 			print_error(linenum, err, errstr);
406*4746Srica 			errors++;
407*4746Srica 			continue;
408*4746Srica 		}
409*4746Srica 
410*4746Srica 		if (strcasecmp(zc->zc_name, "global") == 0)
411*4746Srica 			break;
412*4746Srica 		tsol_freezcent(zc);
413*4746Srica 	}
414*4746Srica 	(void) fclose(fp);
415*4746Srica 
416*4746Srica 	if (zc == NULL) {
417*4746Srica 		(void) fprintf(stderr,
418*4746Srica 		    gettext("tnctl: cannot find global zone in %s\n"), file);
419*4746Srica 		exit(1);
420*4746Srica 	}
421*4746Srica 
422*4746Srica 	tsme.tsme_zoneid = GLOBAL_ZONEID;
423*4746Srica 	tsme.tsme_flags = 0;
424*4746Srica 	if (flush_mode)
425*4746Srica 		(void) tnmlp(TNDB_FLUSH, &tsme);
426*4746Srica 
427*4746Srica 	handle_mlps(GLOBAL_ZONEID, zc->zc_private_mlp, 0, TNDB_LOAD);
428*4746Srica 	handle_mlps(GLOBAL_ZONEID, zc->zc_shared_mlp, TSOL_MEF_SHARED,
429*4746Srica 	    TNDB_LOAD);
430*4746Srica 
431*4746Srica 	tsol_freezcent(zc);
432*4746Srica }
433*4746Srica 
434*4746Srica static void
435*4746Srica process_tpl(const char *file)
436*4746Srica {
437*4746Srica 	FILE		*fp;
438*4746Srica 	boolean_t	success = B_FALSE;
439*4746Srica 	tsol_tpent_t	*tpentp;
440*4746Srica 
441*4746Srica 	if ((fp = fopen(file, "r")) == NULL) {
442*4746Srica 		(void) fprintf(stderr,
443*4746Srica 		    gettext("tnctl: failed to open %s: %s\n"), file,
444*4746Srica 		    strerror(errno));
445*4746Srica 		exit(1);
446*4746Srica 	}
447*4746Srica 
448*4746Srica 	tsol_settpent(1);
449*4746Srica 	while (tpentp = tsol_fgettpent(fp)) {
450*4746Srica 		/* First time through the loop, flush it all */
451*4746Srica 		if (!success && flush_mode)
452*4746Srica 			(void) tnrhtp(TNDB_FLUSH, NULL);
453*4746Srica 
454*4746Srica 		success = B_TRUE;
455*4746Srica 
456*4746Srica 		if (verbose_mode)
457*4746Srica 			(void) printf("tnctl: loading rhtp entry ...\n");
458*4746Srica 
459*4746Srica 		if (tnrhtp(TNDB_LOAD, tpentp) != 0) {
460*4746Srica 			(void) fclose(fp);
461*4746Srica 			if (errno == EFAULT)
462*4746Srica 				perror("tnrhtp");
463*4746Srica 			else
464*4746Srica 				(void) fprintf(stderr, gettext("tnctl: load "
465*4746Srica 				    "of remote-host template %1$s into kernel "
466*4746Srica 				    "cache failed: %2$s\n"), tpentp->name,
467*4746Srica 				    strerror(errno));
468*4746Srica 			tsol_endtpent();
469*4746Srica 			exit(1);
470*4746Srica 		}
471*4746Srica 		tsol_freetpent(tpentp);
472*4746Srica 	}
473*4746Srica 	if (!success) {
474*4746Srica 		(void) fprintf(stderr,
475*4746Srica 		    gettext("tnctl: No valid tnrhtp entries found in %s\n"),
476*4746Srica 		    file);
477*4746Srica 	}
478*4746Srica 	(void) fclose(fp);
479*4746Srica 	tsol_endtpent();
480*4746Srica }
481*4746Srica 
482*4746Srica static void
483*4746Srica process_tp(const char *template)
484*4746Srica {
485*4746Srica 	tsol_tpstr_t tpstr;
486*4746Srica 	tsol_tpent_t tpent;
487*4746Srica 	tsol_tpent_t *tpentp;
488*4746Srica 	int err;
489*4746Srica 	char *errstr;
490*4746Srica 	char buf[NSS_BUFLEN_TSOL_TP];
491*4746Srica 
492*4746Srica 	if (strchr(template, ':') != NULL) {
493*4746Srica 		(void) str_to_tpstr(template, strlen(template), &tpstr, buf,
494*4746Srica 		    sizeof (buf));
495*4746Srica 		tpentp = tpstr_to_ent(&tpstr, &err, &errstr);
496*4746Srica 		if (tpentp == NULL) {
497*4746Srica 			print_error(0, err, errstr);
498*4746Srica 			exit(1);
499*4746Srica 		}
500*4746Srica 	} else if (delete_mode) {
501*4746Srica 		(void) memset(&tpent, 0, sizeof (tpent));
502*4746Srica 		tpentp = &tpent;
503*4746Srica 		(void) strlcpy(tpentp->name, template, sizeof (tpentp->name));
504*4746Srica 	} else if ((tpentp = tsol_gettpbyname(template)) == NULL) {
505*4746Srica 		(void) fprintf(stderr,
506*4746Srica 		    gettext("tnctl: template %s not found\n"), template);
507*4746Srica 		exit(1);
508*4746Srica 	}
509*4746Srica 
510*4746Srica 	if (verbose_mode)
511*4746Srica 		(void) printf("%s rhtp entry ...\n", delete_mode ? "deleting" :
512*4746Srica 		    "loading");
513*4746Srica 
514*4746Srica 	if (tnrhtp(delete_mode ? TNDB_DELETE : TNDB_LOAD, tpentp) != 0) {
515*4746Srica 		if (errno == EFAULT)
516*4746Srica 			perror("tnrhtp");
517*4746Srica 		else if (errno == ENOENT)
518*4746Srica 			(void) fprintf(stderr,
519*4746Srica 			    gettext("tnctl: %1$s of remote-host template "
520*4746Srica 			    "kernel cache entry %2$s failed: no such "
521*4746Srica 			    "entry\n"),
522*4746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
523*4746Srica 			    tpentp->name);
524*4746Srica 		else
525*4746Srica 			(void) fprintf(stderr,
526*4746Srica 			    gettext("tnctl: %1$s of remote-host template "
527*4746Srica 			    "kernel cache entry %2$s failed: %3$s\n"),
528*4746Srica 			    delete_mode ? gettext("delete") : gettext("load"),
529*4746Srica 			    tpentp->name, strerror(errno));
530*4746Srica 		exit(1);
531*4746Srica 	}
532*4746Srica 	if (tpentp != &tpent)
533*4746Srica 		tsol_freetpent(tpentp);
534*4746Srica }
535*4746Srica 
536*4746Srica static void
537*4746Srica process_mlp(const char *str)
538*4746Srica {
539*4746Srica 	const char *cp;
540*4746Srica 	char zonename[ZONENAME_MAX];
541*4746Srica 	zoneid_t zoneid;
542*4746Srica 	tsol_zcent_t *zc;
543*4746Srica 	int err;
544*4746Srica 	char *errstr;
545*4746Srica 	char *sbuf;
546*4746Srica 
547*4746Srica 	if ((cp = strchr(str, ':')) == NULL) {
548*4746Srica 		if (!delete_mode) {
549*4746Srica 			(void) fprintf(stderr,
550*4746Srica 			    gettext("tnctl: need MLP list to insert\n"));
551*4746Srica 			exit(2);
552*4746Srica 		}
553*4746Srica 		(void) strlcpy(zonename, str, sizeof (zonename));
554*4746Srica 	} else if (cp - str >= ZONENAME_MAX) {
555*4746Srica 		(void) fprintf(stderr, gettext("tnctl: illegal zone name\n"));
556*4746Srica 		exit(2);
557*4746Srica 	} else {
558*4746Srica 		(void) memcpy(zonename, str, cp - str);
559*4746Srica 		zonename[cp - str] = '\0';
560*4746Srica 		str = cp + 1;
561*4746Srica 	}
562*4746Srica 
563*4746Srica 	if ((zoneid = getzoneidbyname(zonename)) == -1) {
564*4746Srica 		(void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"),
565*4746Srica 		    zonename);
566*4746Srica 		exit(1);
567*4746Srica 	}
568*4746Srica 
569*4746Srica 	sbuf = malloc(strlen(zonename) + sizeof (":ADMIN_LOW:0:") +
570*4746Srica 	    strlen(str));
571*4746Srica 	if (sbuf == NULL) {
572*4746Srica 		perror("malloc");
573*4746Srica 		exit(1);
574*4746Srica 	}
575*4746Srica 	/* LINTED: sprintf is known not to be unbounded here */
576*4746Srica 	(void) sprintf(sbuf, "%s:ADMIN_LOW:0:%s", zonename, str);
577*4746Srica 	if ((zc = tsol_sgetzcent(sbuf, &err, &errstr)) == NULL) {
578*4746Srica 		(void) fprintf(stderr,
579*4746Srica 		    gettext("tnctl: unable to parse MLPs\n"));
580*4746Srica 		exit(1);
581*4746Srica 	}
582*4746Srica 	handle_mlps(zoneid, zc->zc_private_mlp, 0,
583*4746Srica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
584*4746Srica 	handle_mlps(zoneid, zc->zc_shared_mlp, TSOL_MEF_SHARED,
585*4746Srica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
586*4746Srica 	tsol_freezcent(zc);
587*4746Srica }
588*4746Srica 
589*4746Srica static void
590*4746Srica usage(void)
591*4746Srica {
592*4746Srica 	(void) fprintf(stderr, gettext("usage: tnctl [-dfv] "
593*4746Srica 	    "[-h host[/prefix][:tmpl]] [-m zone:priv:share]\n\t"
594*4746Srica 	    "[-t tmpl[:key=val[;key=val]]] [-[HTz] file]\n"));
595*4746Srica 
596*4746Srica 	exit(1);
597*4746Srica }
598