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