xref: /titanic_54/usr/src/cmd/tsol/tnctl/tnctl.c (revision 1f041b1785d05ef9863b007d3807833c3609391d)
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 /*
23f875b4ebSrica  * Copyright 2007 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);
58*1f041b17Ston 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 /*
131*1f041b17Ston  * Produce ascii format of address and prefix length
132*1f041b17Ston  */
133*1f041b17Ston static void
134*1f041b17Ston translate_inet_addr(tsol_rhent_t *rhentp, int *alen, char abuf[], int abuflen)
135*1f041b17Ston {
136*1f041b17Ston 	void *aptr;
137*1f041b17Ston 	tsol_rhent_t rhent;
138*1f041b17Ston 	struct in6_addr ipv6addr;
139*1f041b17Ston 	char tmpbuf[20];
140*1f041b17Ston 
141*1f041b17Ston 	(void) snprintf(tmpbuf, sizeof (tmpbuf), "/%d", rhentp->rh_prefix);
142*1f041b17Ston 
143*1f041b17Ston 	if (rhentp->rh_address.ta_family == AF_INET6) {
144*1f041b17Ston 		aptr = &(rhentp->rh_address.ta_addr_v6);
145*1f041b17Ston 		*alen = sizeof (ipv6addr);
146*1f041b17Ston 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
147*1f041b17Ston 		    abuflen);
148*1f041b17Ston 		if (rhentp->rh_prefix != 128) {
149*1f041b17Ston 			if (strlcat(abuf, tmpbuf, abuflen) >= abuflen)
150*1f041b17Ston 				(void) fprintf(stderr, gettext(
151*1f041b17Ston 				    "tnctl: buffer overflow detected: %s\n"),
152*1f041b17Ston 				    abuf);
153*1f041b17Ston 		}
154*1f041b17Ston 	} else {
155*1f041b17Ston 		aptr = &(rhentp->rh_address.ta_addr_v4);
156*1f041b17Ston 		*alen = sizeof (rhent.rh_address.ta_addr_v4);
157*1f041b17Ston 		(void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
158*1f041b17Ston 		    abuflen);
159*1f041b17Ston 		if (rhentp->rh_prefix != 32) {
160*1f041b17Ston 			if (strlcat(abuf, tmpbuf, abuflen) >= abuflen)
161*1f041b17Ston 				(void) fprintf(stderr, gettext(
162*1f041b17Ston 				    "tnctl: buffer overflow detected: %s\n"),
163*1f041b17Ston 				    abuf);
164*1f041b17Ston 		}
165*1f041b17Ston 	}
166*1f041b17Ston }
167*1f041b17Ston 
168*1f041b17Ston /*
169f875b4ebSrica  * Load remote host entries from the designated file.
170f875b4ebSrica  */
171f875b4ebSrica static void
172f875b4ebSrica process_rhl(const char *file)
173f875b4ebSrica {
174f875b4ebSrica 	boolean_t	success = B_FALSE;
175f875b4ebSrica 	tsol_rhent_t	*rhentp = NULL;
176f875b4ebSrica 	FILE		*fp;
177*1f041b17Ston 	int alen;
178*1f041b17Ston 	/* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
179*1f041b17Ston 	char abuf[INET6_ADDRSTRLEN+5];
180f875b4ebSrica 
181f875b4ebSrica 	if ((fp = fopen(file, "r")) == NULL) {
182f875b4ebSrica 		(void) fprintf(stderr,
183f875b4ebSrica 		    gettext("tnctl: failed to open %1$s: %2$s\n"),
184f875b4ebSrica 		    file, strerror(errno));
185f875b4ebSrica 		exit(1);
186f875b4ebSrica 	}
187f875b4ebSrica 
188f875b4ebSrica 	tsol_setrhent(1);
189f875b4ebSrica 	while (rhentp = tsol_fgetrhent(fp)) {
190f875b4ebSrica 		/* First time through the loop, flush it all */
191f875b4ebSrica 		if (!success && flush_mode)
192f875b4ebSrica 			(void) tnrh(TNDB_FLUSH, NULL);
193f875b4ebSrica 		success = B_TRUE;
194f875b4ebSrica 
195f875b4ebSrica 		if (verbose_mode)
196f875b4ebSrica 			(void) printf("loading rh entry...\n");
197f875b4ebSrica 
198f875b4ebSrica 		if (tnrh(TNDB_LOAD, rhentp) != 0) {
199f875b4ebSrica 			(void) fclose(fp);
200f875b4ebSrica 			if (errno == EFAULT)
201f875b4ebSrica 				perror("tnrh");
202f875b4ebSrica 			else
203*1f041b17Ston 				translate_inet_addr(rhentp, &alen, abuf,
204*1f041b17Ston 				    sizeof (abuf));
205f875b4ebSrica 				(void) fprintf(stderr,
206f875b4ebSrica 				    gettext("tnctl: load of remote-host entry "
207f875b4ebSrica 				    "%1$s into kernel cache failed: %2$s\n"),
208*1f041b17Ston 				    abuf, strerror(errno));
209f875b4ebSrica 			tsol_endrhent();
210f875b4ebSrica 			exit(1);
211f875b4ebSrica 		}
212f875b4ebSrica 		tsol_freerhent(rhentp);
213f875b4ebSrica 	}
214f875b4ebSrica 	if (!success) {
215f875b4ebSrica 		(void) fprintf(stderr,
216f875b4ebSrica 		    gettext("tnctl: No valid tnrhdb entries found in %s\n"),
217f875b4ebSrica 		    file);
218f875b4ebSrica 	}
219f875b4ebSrica 	(void) fclose(fp);
220f875b4ebSrica 	tsol_endrhent();
221f875b4ebSrica }
222f875b4ebSrica 
223f875b4ebSrica /*
224f875b4ebSrica  * The argument can be either a host name, an address
225f875b4ebSrica  * in tnrhdb address format, or a complete tnrhdb entry.
226f875b4ebSrica  */
227f875b4ebSrica static void
228f875b4ebSrica process_rh(const char *hostname)
229f875b4ebSrica {
230f875b4ebSrica 	tsol_rhstr_t rhstr;
231f875b4ebSrica 	tsol_rhent_t rhent;
232f875b4ebSrica 	tsol_rhent_t *rhentp;
233f875b4ebSrica 	int err;
234f875b4ebSrica 	int alen;
235f875b4ebSrica 	char *errstr;
236f875b4ebSrica 	/* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
237f875b4ebSrica 	char abuf[INET6_ADDRSTRLEN+5];
238f875b4ebSrica 	const char *cp;
239f875b4ebSrica 	char *cp1;
240f875b4ebSrica 	char *cp2;
241f875b4ebSrica 	void *aptr;
242f875b4ebSrica 	char buf[NSS_BUFLEN_TSOL_RH];
243f875b4ebSrica 	struct in6_addr ipv6addr;
244f875b4ebSrica 
245f875b4ebSrica 	/* was a template name provided on the command line? */
246f875b4ebSrica 	if ((cp = strrchr(hostname, ':')) != NULL && cp != hostname &&
247f875b4ebSrica 	    cp[-1] != '\\') {
248f875b4ebSrica 		/* use common tnrhdb line conversion function */
249f875b4ebSrica 		(void) str_to_rhstr(hostname, strlen(hostname), &rhstr, buf,
250f875b4ebSrica 		    sizeof (buf));
251f875b4ebSrica 		rhentp = rhstr_to_ent(&rhstr, &err, &errstr);
252f875b4ebSrica 		if (rhentp == NULL) {
253f875b4ebSrica 			print_error(0, err, errstr);
254f875b4ebSrica 			exit(1);
255f875b4ebSrica 		}
256f875b4ebSrica 	} else {
257f875b4ebSrica 		char *hostname_p;
258f875b4ebSrica 		char *prefix_p;
259f875b4ebSrica 		struct hostent *hp;
260f875b4ebSrica 
261f875b4ebSrica 		/* Check for a subnet prefix length */
262f875b4ebSrica 		if ((prefix_p = strchr(hostname, '/')) != NULL) {
263f875b4ebSrica 			cp1 = prefix_p + 1;
264f875b4ebSrica 			errno = 0;
265f875b4ebSrica 			rhent.rh_prefix = strtol(cp1, &cp2, 0);
266f875b4ebSrica 			if (*cp2 != '\0' || errno != 0 || rhent.rh_prefix < 0) {
267f875b4ebSrica 				(void) fprintf(stderr, gettext("tnct: invalid "
268f875b4ebSrica 				    "prefix length: %s\n"), cp);
269f875b4ebSrica 				exit(2);
270f875b4ebSrica 			}
271f875b4ebSrica 		} else {
272f875b4ebSrica 			rhent.rh_prefix = -1;
273f875b4ebSrica 		}
274f875b4ebSrica 
275f875b4ebSrica 		/* Strip any backslashes from numeric address */
276f875b4ebSrica 		hostname_p = malloc(strlen(hostname)+1);
277f875b4ebSrica 		if (hostname_p == NULL) {
278f875b4ebSrica 			perror("tnctl");
279f875b4ebSrica 			exit(2);
280f875b4ebSrica 		}
281f875b4ebSrica 		cp1 = hostname_p;
282f875b4ebSrica 		while (*hostname != '\0' && *hostname != '/') {
283f875b4ebSrica 			*cp1 = *hostname++;
284f875b4ebSrica 			if (*cp1 != '\\')
285f875b4ebSrica 				cp1++;
286f875b4ebSrica 		}
287f875b4ebSrica 		*cp1 = '\0';
288f875b4ebSrica 
289f875b4ebSrica 		/* Convert address or hostname to binary af_inet6 format */
290f875b4ebSrica 		hp = getipnodebyname(hostname_p, AF_INET6,
291f875b4ebSrica 		    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &err);
292f875b4ebSrica 		if (hp == NULL) {
293f875b4ebSrica 			(void) fprintf(stderr, gettext("tnctl: unknown host "
294f875b4ebSrica 			    "or invalid literal address: %s\n"), hostname_p);
295f875b4ebSrica 			if (err == TRY_AGAIN)
296f875b4ebSrica 				(void) fprintf(stderr,
297f875b4ebSrica 				    gettext("\t(try again later)\n"));
298f875b4ebSrica 			exit(2);
299f875b4ebSrica 		}
300f875b4ebSrica 		free(hostname_p);
301f875b4ebSrica 		(void) memcpy(&ipv6addr, hp->h_addr, hp->h_length);
302f875b4ebSrica 
303f875b4ebSrica 		/* if ipv4 address, convert to af_inet format */
304f875b4ebSrica 		if (IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
305f875b4ebSrica 			rhent.rh_address.ta_family = AF_INET;
306f875b4ebSrica 			IN6_V4MAPPED_TO_INADDR(&ipv6addr,
307f875b4ebSrica 			    &rhent.rh_address.ta_addr_v4);
308f875b4ebSrica 			if (rhent.rh_prefix == -1)
309f875b4ebSrica 				rhent.rh_prefix = 32;
310f875b4ebSrica 		} else {
311f875b4ebSrica 			rhent.rh_address.ta_family = AF_INET6;
312f875b4ebSrica 			rhent.rh_address.ta_addr_v6 = ipv6addr;
313f875b4ebSrica 			if (rhent.rh_prefix == -1)
314f875b4ebSrica 				rhent.rh_prefix = 128;
315f875b4ebSrica 		}
316f875b4ebSrica 		rhent.rh_template[0] = '\0';
317f875b4ebSrica 		rhentp = &rhent;
318f875b4ebSrica 	}
319f875b4ebSrica 
320f875b4ebSrica 	/* produce ascii format of address and prefix length */
321*1f041b17Ston 	translate_inet_addr(rhentp, &alen, abuf, sizeof (abuf));
322f875b4ebSrica 
323f875b4ebSrica 	/*
324f875b4ebSrica 	 * look up the entry from ldap or tnrhdb if this is a load
325f875b4ebSrica 	 * request and a template name was not provided.
326f875b4ebSrica 	 */
327f875b4ebSrica 	if (!delete_mode &&
328f875b4ebSrica 	    rhentp->rh_template[0] == '\0' &&
329f875b4ebSrica 	    (rhentp = tsol_getrhbyaddr(abuf, alen,
330f875b4ebSrica 	    rhent.rh_address.ta_family)) == NULL) {
331f875b4ebSrica 		(void) fprintf(stderr,
332f875b4ebSrica 		    gettext("tnctl: database lookup failed for %s\n"),
333f875b4ebSrica 		    abuf);
334f875b4ebSrica 		exit(1);
335f875b4ebSrica 	}
336f875b4ebSrica 
337f875b4ebSrica 	if (verbose_mode)
338f875b4ebSrica 		(void) printf("%s rh entry %s\n", delete_mode ? "deleting" :
339f875b4ebSrica 		    "loading", abuf);
340f875b4ebSrica 
341f875b4ebSrica 	/* update the tnrhdb entry in the kernel */
342f875b4ebSrica 	if (tnrh(delete_mode ? TNDB_DELETE : TNDB_LOAD, rhentp) != 0) {
343f875b4ebSrica 		if (errno == EFAULT)
344f875b4ebSrica 			perror("tnrh");
345f875b4ebSrica 		else if (errno == ENOENT)
346f875b4ebSrica 			(void) fprintf(stderr,
347f875b4ebSrica 			    gettext("tnctl: %1$s of remote-host kernel cache "
348f875b4ebSrica 			    "entry %2$s failed: no such entry\n"),
349f875b4ebSrica 			    delete_mode ? gettext("delete") : gettext("load"),
350f875b4ebSrica 			    abuf);
351f875b4ebSrica 		else
352f875b4ebSrica 			(void) fprintf(stderr,
353f875b4ebSrica 			    gettext("tnctl: %1$s of remote-host kernel cache "
354f875b4ebSrica 			    "entry %2$s failed: %3$s\n"),
355f875b4ebSrica 			    delete_mode ? gettext("delete") : gettext("load"),
356f875b4ebSrica 			    abuf, strerror(errno));
357f875b4ebSrica 		exit(1);
358f875b4ebSrica 	}
359f875b4ebSrica 	if (rhentp != &rhent)
360f875b4ebSrica 		tsol_freerhent(rhentp);
361f875b4ebSrica }
362f875b4ebSrica 
363f875b4ebSrica static void
364f875b4ebSrica handle_mlps(zoneid_t zoneid, tsol_mlp_t *mlp, int flags, int cmd)
365f875b4ebSrica {
366f875b4ebSrica 	tsol_mlpent_t tsme;
367f875b4ebSrica 
368f875b4ebSrica 	tsme.tsme_zoneid = zoneid;
369f875b4ebSrica 	tsme.tsme_flags = flags;
370f875b4ebSrica 	while (!TSOL_MLP_END(mlp)) {
371f875b4ebSrica 		tsme.tsme_mlp = *mlp;
372f875b4ebSrica 		if (tnmlp(cmd, &tsme) != 0) {
373f875b4ebSrica 			/*
374f875b4ebSrica 			 * Usage of ?: here is ugly, but helps with
375f875b4ebSrica 			 * localization.
376f875b4ebSrica 			 */
377f875b4ebSrica 			(void) fprintf(stderr,
378f875b4ebSrica 			    flags & TSOL_MEF_SHARED ?
379f875b4ebSrica 			    gettext("tnctl: cannot set "
380f875b4ebSrica 			    "shared MLP on %1$d-%2$d/%3$d: %4$s\n") :
381f875b4ebSrica 			    gettext("tnctl: cannot set "
382f875b4ebSrica 			    "zone-specific MLP on %1$d-%2$d/%3$d: %4$s\n"),
383f875b4ebSrica 			    mlp->mlp_port, mlp->mlp_port_upper, mlp->mlp_ipp,
384f875b4ebSrica 			    strerror(errno));
385f875b4ebSrica 			exit(1);
386f875b4ebSrica 		}
387f875b4ebSrica 		mlp++;
388f875b4ebSrica 	}
389f875b4ebSrica }
390f875b4ebSrica 
391f875b4ebSrica /*
392f875b4ebSrica  * This reads the configuration for the global zone out of tnzonecfg
393f875b4ebSrica  * and sets it in the kernel.  The non-global zones are configured
394f875b4ebSrica  * by zoneadmd.
395f875b4ebSrica  */
396f875b4ebSrica static void
397f875b4ebSrica process_tnzone(const char *file)
398f875b4ebSrica {
399f875b4ebSrica 	tsol_zcent_t *zc;
400f875b4ebSrica 	tsol_mlpent_t tsme;
401f875b4ebSrica 	int err;
402f875b4ebSrica 	char *errstr;
403f875b4ebSrica 	FILE *fp;
404f875b4ebSrica 	char line[2048], *cp;
405f875b4ebSrica 	int linenum, errors;
406f875b4ebSrica 
407f875b4ebSrica 	if ((fp = fopen(file, "r")) == NULL) {
408f875b4ebSrica 		(void) fprintf(stderr,
409f875b4ebSrica 		    gettext("tnctl: failed to open %s: %s\n"), file,
410f875b4ebSrica 		    strerror(errno));
411f875b4ebSrica 		exit(1);
412f875b4ebSrica 	}
413f875b4ebSrica 
414f875b4ebSrica 	linenum = errors = 0;
415f875b4ebSrica 	zc = NULL;
416f875b4ebSrica 	while (fgets(line, sizeof (line), fp) != NULL) {
417f875b4ebSrica 		if ((cp = strchr(line, '\n')) != NULL)
418f875b4ebSrica 			*cp = '\0';
419f875b4ebSrica 
420f875b4ebSrica 		linenum++;
421f875b4ebSrica 		if ((zc = tsol_sgetzcent(line, &err, &errstr)) == NULL) {
422f875b4ebSrica 			if (err == LTSNET_EMPTY)
423f875b4ebSrica 				continue;
424f875b4ebSrica 			if (errors == 0) {
425f875b4ebSrica 				int errtmp = errno;
426f875b4ebSrica 
427f875b4ebSrica 				(void) fprintf(stderr, gettext("tnctl: errors "
428f875b4ebSrica 				    "parsing %s:\n"), file);
429f875b4ebSrica 				errno = errtmp;
430f875b4ebSrica 			}
431f875b4ebSrica 			print_error(linenum, err, errstr);
432f875b4ebSrica 			errors++;
433f875b4ebSrica 			continue;
434f875b4ebSrica 		}
435f875b4ebSrica 
436f875b4ebSrica 		if (strcasecmp(zc->zc_name, "global") == 0)
437f875b4ebSrica 			break;
438f875b4ebSrica 		tsol_freezcent(zc);
439f875b4ebSrica 	}
440f875b4ebSrica 	(void) fclose(fp);
441f875b4ebSrica 
442f875b4ebSrica 	if (zc == NULL) {
443f875b4ebSrica 		(void) fprintf(stderr,
444f875b4ebSrica 		    gettext("tnctl: cannot find global zone in %s\n"), file);
445f875b4ebSrica 		exit(1);
446f875b4ebSrica 	}
447f875b4ebSrica 
448f875b4ebSrica 	tsme.tsme_zoneid = GLOBAL_ZONEID;
449f875b4ebSrica 	tsme.tsme_flags = 0;
450f875b4ebSrica 	if (flush_mode)
451f875b4ebSrica 		(void) tnmlp(TNDB_FLUSH, &tsme);
452f875b4ebSrica 
453f875b4ebSrica 	handle_mlps(GLOBAL_ZONEID, zc->zc_private_mlp, 0, TNDB_LOAD);
454f875b4ebSrica 	handle_mlps(GLOBAL_ZONEID, zc->zc_shared_mlp, TSOL_MEF_SHARED,
455f875b4ebSrica 	    TNDB_LOAD);
456f875b4ebSrica 
457f875b4ebSrica 	tsol_freezcent(zc);
458f875b4ebSrica }
459f875b4ebSrica 
460f875b4ebSrica static void
461f875b4ebSrica process_tpl(const char *file)
462f875b4ebSrica {
463f875b4ebSrica 	FILE		*fp;
464f875b4ebSrica 	boolean_t	success = B_FALSE;
465f875b4ebSrica 	tsol_tpent_t	*tpentp;
466f875b4ebSrica 
467f875b4ebSrica 	if ((fp = fopen(file, "r")) == NULL) {
468f875b4ebSrica 		(void) fprintf(stderr,
469f875b4ebSrica 		    gettext("tnctl: failed to open %s: %s\n"), file,
470f875b4ebSrica 		    strerror(errno));
471f875b4ebSrica 		exit(1);
472f875b4ebSrica 	}
473f875b4ebSrica 
474f875b4ebSrica 	tsol_settpent(1);
475f875b4ebSrica 	while (tpentp = tsol_fgettpent(fp)) {
476f875b4ebSrica 		/* First time through the loop, flush it all */
477f875b4ebSrica 		if (!success && flush_mode)
478f875b4ebSrica 			(void) tnrhtp(TNDB_FLUSH, NULL);
479f875b4ebSrica 
480f875b4ebSrica 		success = B_TRUE;
481f875b4ebSrica 
482f875b4ebSrica 		if (verbose_mode)
483f875b4ebSrica 			(void) printf("tnctl: loading rhtp entry ...\n");
484f875b4ebSrica 
485f875b4ebSrica 		if (tnrhtp(TNDB_LOAD, tpentp) != 0) {
486f875b4ebSrica 			(void) fclose(fp);
487f875b4ebSrica 			if (errno == EFAULT)
488f875b4ebSrica 				perror("tnrhtp");
489f875b4ebSrica 			else
490f875b4ebSrica 				(void) fprintf(stderr, gettext("tnctl: load "
491f875b4ebSrica 				    "of remote-host template %1$s into kernel "
492f875b4ebSrica 				    "cache failed: %2$s\n"), tpentp->name,
493f875b4ebSrica 				    strerror(errno));
494f875b4ebSrica 			tsol_endtpent();
495f875b4ebSrica 			exit(1);
496f875b4ebSrica 		}
497f875b4ebSrica 		tsol_freetpent(tpentp);
498f875b4ebSrica 	}
499f875b4ebSrica 	if (!success) {
500f875b4ebSrica 		(void) fprintf(stderr,
501f875b4ebSrica 		    gettext("tnctl: No valid tnrhtp entries found in %s\n"),
502f875b4ebSrica 		    file);
503f875b4ebSrica 	}
504f875b4ebSrica 	(void) fclose(fp);
505f875b4ebSrica 	tsol_endtpent();
506f875b4ebSrica }
507f875b4ebSrica 
508f875b4ebSrica static void
509f875b4ebSrica process_tp(const char *template)
510f875b4ebSrica {
511f875b4ebSrica 	tsol_tpstr_t tpstr;
512f875b4ebSrica 	tsol_tpent_t tpent;
513f875b4ebSrica 	tsol_tpent_t *tpentp;
514f875b4ebSrica 	int err;
515f875b4ebSrica 	char *errstr;
516f875b4ebSrica 	char buf[NSS_BUFLEN_TSOL_TP];
517f875b4ebSrica 
518f875b4ebSrica 	if (strchr(template, ':') != NULL) {
519f875b4ebSrica 		(void) str_to_tpstr(template, strlen(template), &tpstr, buf,
520f875b4ebSrica 		    sizeof (buf));
521f875b4ebSrica 		tpentp = tpstr_to_ent(&tpstr, &err, &errstr);
522f875b4ebSrica 		if (tpentp == NULL) {
523f875b4ebSrica 			print_error(0, err, errstr);
524f875b4ebSrica 			exit(1);
525f875b4ebSrica 		}
526f875b4ebSrica 	} else if (delete_mode) {
527f875b4ebSrica 		(void) memset(&tpent, 0, sizeof (tpent));
528f875b4ebSrica 		tpentp = &tpent;
529f875b4ebSrica 		(void) strlcpy(tpentp->name, template, sizeof (tpentp->name));
530f875b4ebSrica 	} else if ((tpentp = tsol_gettpbyname(template)) == NULL) {
531f875b4ebSrica 		(void) fprintf(stderr,
532f875b4ebSrica 		    gettext("tnctl: template %s not found\n"), template);
533f875b4ebSrica 		exit(1);
534f875b4ebSrica 	}
535f875b4ebSrica 
536f875b4ebSrica 	if (verbose_mode)
537f875b4ebSrica 		(void) printf("%s rhtp entry ...\n", delete_mode ? "deleting" :
538f875b4ebSrica 		    "loading");
539f875b4ebSrica 
540f875b4ebSrica 	if (tnrhtp(delete_mode ? TNDB_DELETE : TNDB_LOAD, tpentp) != 0) {
541f875b4ebSrica 		if (errno == EFAULT)
542f875b4ebSrica 			perror("tnrhtp");
543f875b4ebSrica 		else if (errno == ENOENT)
544f875b4ebSrica 			(void) fprintf(stderr,
545f875b4ebSrica 			    gettext("tnctl: %1$s of remote-host template "
546f875b4ebSrica 			    "kernel cache entry %2$s failed: no such "
547f875b4ebSrica 			    "entry\n"),
548f875b4ebSrica 			    delete_mode ? gettext("delete") : gettext("load"),
549f875b4ebSrica 			    tpentp->name);
550f875b4ebSrica 		else
551f875b4ebSrica 			(void) fprintf(stderr,
552f875b4ebSrica 			    gettext("tnctl: %1$s of remote-host template "
553f875b4ebSrica 			    "kernel cache entry %2$s failed: %3$s\n"),
554f875b4ebSrica 			    delete_mode ? gettext("delete") : gettext("load"),
555f875b4ebSrica 			    tpentp->name, strerror(errno));
556f875b4ebSrica 		exit(1);
557f875b4ebSrica 	}
558f875b4ebSrica 	if (tpentp != &tpent)
559f875b4ebSrica 		tsol_freetpent(tpentp);
560f875b4ebSrica }
561f875b4ebSrica 
562f875b4ebSrica static void
563f875b4ebSrica process_mlp(const char *str)
564f875b4ebSrica {
565f875b4ebSrica 	const char *cp;
566f875b4ebSrica 	char zonename[ZONENAME_MAX];
567f875b4ebSrica 	zoneid_t zoneid;
568f875b4ebSrica 	tsol_zcent_t *zc;
569f875b4ebSrica 	int err;
570f875b4ebSrica 	char *errstr;
571f875b4ebSrica 	char *sbuf;
572f875b4ebSrica 
573f875b4ebSrica 	if ((cp = strchr(str, ':')) == NULL) {
574f875b4ebSrica 		if (!delete_mode) {
575f875b4ebSrica 			(void) fprintf(stderr,
576f875b4ebSrica 			    gettext("tnctl: need MLP list to insert\n"));
577f875b4ebSrica 			exit(2);
578f875b4ebSrica 		}
579f875b4ebSrica 		(void) strlcpy(zonename, str, sizeof (zonename));
580f875b4ebSrica 	} else if (cp - str >= ZONENAME_MAX) {
581f875b4ebSrica 		(void) fprintf(stderr, gettext("tnctl: illegal zone name\n"));
582f875b4ebSrica 		exit(2);
583f875b4ebSrica 	} else {
584f875b4ebSrica 		(void) memcpy(zonename, str, cp - str);
585f875b4ebSrica 		zonename[cp - str] = '\0';
586f875b4ebSrica 		str = cp + 1;
587f875b4ebSrica 	}
588f875b4ebSrica 
589f875b4ebSrica 	if ((zoneid = getzoneidbyname(zonename)) == -1) {
590f875b4ebSrica 		(void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"),
591f875b4ebSrica 		    zonename);
592f875b4ebSrica 		exit(1);
593f875b4ebSrica 	}
594f875b4ebSrica 
595f875b4ebSrica 	sbuf = malloc(strlen(zonename) + sizeof (":ADMIN_LOW:0:") +
596f875b4ebSrica 	    strlen(str));
597f875b4ebSrica 	if (sbuf == NULL) {
598f875b4ebSrica 		perror("malloc");
599f875b4ebSrica 		exit(1);
600f875b4ebSrica 	}
601f875b4ebSrica 	/* LINTED: sprintf is known not to be unbounded here */
602f875b4ebSrica 	(void) sprintf(sbuf, "%s:ADMIN_LOW:0:%s", zonename, str);
603f875b4ebSrica 	if ((zc = tsol_sgetzcent(sbuf, &err, &errstr)) == NULL) {
604f875b4ebSrica 		(void) fprintf(stderr,
605f875b4ebSrica 		    gettext("tnctl: unable to parse MLPs\n"));
606f875b4ebSrica 		exit(1);
607f875b4ebSrica 	}
608f875b4ebSrica 	handle_mlps(zoneid, zc->zc_private_mlp, 0,
609f875b4ebSrica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
610f875b4ebSrica 	handle_mlps(zoneid, zc->zc_shared_mlp, TSOL_MEF_SHARED,
611f875b4ebSrica 	    delete_mode ? TNDB_DELETE : TNDB_LOAD);
612f875b4ebSrica 	tsol_freezcent(zc);
613f875b4ebSrica }
614f875b4ebSrica 
615f875b4ebSrica static void
616f875b4ebSrica usage(void)
617f875b4ebSrica {
618f875b4ebSrica 	(void) fprintf(stderr, gettext("usage: tnctl [-dfv] "
619f875b4ebSrica 	    "[-h host[/prefix][:tmpl]] [-m zone:priv:share]\n\t"
620f875b4ebSrica 	    "[-t tmpl[:key=val[;key=val]]] [-[HTz] file]\n"));
621f875b4ebSrica 
622f875b4ebSrica 	exit(1);
623f875b4ebSrica }
624