summaryrefslogtreecommitdiff
path: root/usr/src/cmd/tsol/tnctl/tnctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/tsol/tnctl/tnctl.c')
-rw-r--r--usr/src/cmd/tsol/tnctl/tnctl.c597
1 files changed, 597 insertions, 0 deletions
diff --git a/usr/src/cmd/tsol/tnctl/tnctl.c b/usr/src/cmd/tsol/tnctl/tnctl.c
new file mode 100644
index 0000000000..04a44e33cf
--- /dev/null
+++ b/usr/src/cmd/tsol/tnctl/tnctl.c
@@ -0,0 +1,597 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * tnctl.c -
+ * Trusted Network control utility
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <libtsnet.h>
+#include <zone.h>
+#include <nss_dbdefs.h>
+
+static void process_rh(const char *);
+static void process_rhl(const char *);
+static void process_mlp(const char *);
+static void process_tp(const char *);
+static void process_tpl(const char *);
+static void process_tnzone(const char *);
+static void usage(void);
+
+static boolean_t verbose_mode;
+static boolean_t delete_mode;
+static boolean_t flush_mode;
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ int chr;
+
+ /* Don't do anything if labeling is not active. */
+ if (!is_system_labeled())
+ return (0);
+
+ /* set the locale for only the messages system (all else is clean) */
+ (void) setlocale(LC_ALL, "");
+#ifndef TEXT_DOMAIN /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ while ((chr = getopt(argc, argv, "dfh:H:m:t:T:vz:")) != EOF) {
+ switch (chr) {
+ case 'd':
+ delete_mode = B_TRUE;
+ break;
+ case 'f':
+ flush_mode = B_TRUE;
+ break;
+ case 'h':
+ process_rh(optarg);
+ break;
+ case 'H':
+ process_rhl(optarg);
+ break;
+ case 'm':
+ process_mlp(optarg);
+ break;
+ case 't':
+ process_tp(optarg);
+ break;
+ case 'T':
+ process_tpl(optarg);
+ break;
+ case 'v':
+ verbose_mode = B_TRUE;
+ break;
+ case 'z':
+ process_tnzone(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ return (0);
+}
+
+static void
+print_error(int linenum, int err, const char *errstr)
+{
+ if (linenum > 0)
+ (void) fprintf(stderr, gettext("line %1$d: %2$s:\n"), linenum,
+ tsol_strerror(err, errno));
+ else
+ (void) fprintf(stderr, gettext("tnctl: parsing error: %s\n"),
+ tsol_strerror(err, errno));
+ (void) fprintf(stderr, "%.32s\n", errstr);
+}
+
+/*
+ * Load remote host entries from the designated file.
+ */
+static void
+process_rhl(const char *file)
+{
+ boolean_t success = B_FALSE;
+ tsol_rhent_t *rhentp = NULL;
+ FILE *fp;
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: failed to open %1$s: %2$s\n"),
+ file, strerror(errno));
+ exit(1);
+ }
+
+ tsol_setrhent(1);
+ while (rhentp = tsol_fgetrhent(fp)) {
+ /* First time through the loop, flush it all */
+ if (!success && flush_mode)
+ (void) tnrh(TNDB_FLUSH, NULL);
+ success = B_TRUE;
+
+ if (verbose_mode)
+ (void) printf("loading rh entry...\n");
+
+ if (tnrh(TNDB_LOAD, rhentp) != 0) {
+ (void) fclose(fp);
+ if (errno == EFAULT)
+ perror("tnrh");
+ else
+ (void) fprintf(stderr,
+ gettext("tnctl: load of remote-host entry "
+ "%1$s into kernel cache failed: %2$s\n"),
+ rhentp->rh_template, strerror(errno));
+ tsol_endrhent();
+ exit(1);
+ }
+ tsol_freerhent(rhentp);
+ }
+ if (!success) {
+ (void) fprintf(stderr,
+ gettext("tnctl: No valid tnrhdb entries found in %s\n"),
+ file);
+ }
+ (void) fclose(fp);
+ tsol_endrhent();
+}
+
+/*
+ * The argument can be either a host name, an address
+ * in tnrhdb address format, or a complete tnrhdb entry.
+ */
+static void
+process_rh(const char *hostname)
+{
+ tsol_rhstr_t rhstr;
+ tsol_rhent_t rhent;
+ tsol_rhent_t *rhentp;
+ int err;
+ int alen;
+ char *errstr;
+ /* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
+ char abuf[INET6_ADDRSTRLEN+5];
+ const char *cp;
+ char *cp1;
+ char *cp2;
+ void *aptr;
+ char buf[NSS_BUFLEN_TSOL_RH];
+ struct in6_addr ipv6addr;
+
+ /* was a template name provided on the command line? */
+ if ((cp = strrchr(hostname, ':')) != NULL && cp != hostname &&
+ cp[-1] != '\\') {
+ /* use common tnrhdb line conversion function */
+ (void) str_to_rhstr(hostname, strlen(hostname), &rhstr, buf,
+ sizeof (buf));
+ rhentp = rhstr_to_ent(&rhstr, &err, &errstr);
+ if (rhentp == NULL) {
+ print_error(0, err, errstr);
+ exit(1);
+ }
+ } else {
+ char *hostname_p;
+ char *prefix_p;
+ struct hostent *hp;
+
+ /* Check for a subnet prefix length */
+ if ((prefix_p = strchr(hostname, '/')) != NULL) {
+ cp1 = prefix_p + 1;
+ errno = 0;
+ rhent.rh_prefix = strtol(cp1, &cp2, 0);
+ if (*cp2 != '\0' || errno != 0 || rhent.rh_prefix < 0) {
+ (void) fprintf(stderr, gettext("tnct: invalid "
+ "prefix length: %s\n"), cp);
+ exit(2);
+ }
+ } else {
+ rhent.rh_prefix = -1;
+ }
+
+ /* Strip any backslashes from numeric address */
+ hostname_p = malloc(strlen(hostname)+1);
+ if (hostname_p == NULL) {
+ perror("tnctl");
+ exit(2);
+ }
+ cp1 = hostname_p;
+ while (*hostname != '\0' && *hostname != '/') {
+ *cp1 = *hostname++;
+ if (*cp1 != '\\')
+ cp1++;
+ }
+ *cp1 = '\0';
+
+ /* Convert address or hostname to binary af_inet6 format */
+ hp = getipnodebyname(hostname_p, AF_INET6,
+ AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &err);
+ if (hp == NULL) {
+ (void) fprintf(stderr, gettext("tnctl: unknown host "
+ "or invalid literal address: %s\n"), hostname_p);
+ if (err == TRY_AGAIN)
+ (void) fprintf(stderr,
+ gettext("\t(try again later)\n"));
+ exit(2);
+ }
+ free(hostname_p);
+ (void) memcpy(&ipv6addr, hp->h_addr, hp->h_length);
+
+ /* if ipv4 address, convert to af_inet format */
+ if (IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
+ rhent.rh_address.ta_family = AF_INET;
+ IN6_V4MAPPED_TO_INADDR(&ipv6addr,
+ &rhent.rh_address.ta_addr_v4);
+ if (rhent.rh_prefix == -1)
+ rhent.rh_prefix = 32;
+ } else {
+ rhent.rh_address.ta_family = AF_INET6;
+ rhent.rh_address.ta_addr_v6 = ipv6addr;
+ if (rhent.rh_prefix == -1)
+ rhent.rh_prefix = 128;
+ }
+ rhent.rh_template[0] = '\0';
+ rhentp = &rhent;
+ }
+
+ /* produce ascii format of address and prefix length */
+ if (rhentp->rh_address.ta_family == AF_INET6) {
+ aptr = &(rhentp->rh_address.ta_addr_v6);
+ alen = sizeof (ipv6addr);
+ (void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
+ sizeof (abuf));
+ if (rhentp->rh_prefix != 128) {
+ cp1 = abuf + strlen(abuf);
+ (void) sprintf(cp1, "/%d", rhentp->rh_prefix);
+ }
+ } else {
+ aptr = &(rhentp->rh_address.ta_addr_v4);
+ alen = sizeof (rhent.rh_address.ta_addr_v4);
+ (void) inet_ntop(rhentp->rh_address.ta_family, aptr, abuf,
+ sizeof (abuf));
+ if (rhentp->rh_prefix != 32) {
+ cp1 = abuf + strlen(abuf);
+ (void) sprintf(cp1, "/%d", rhentp->rh_prefix);
+ }
+ }
+
+ /*
+ * look up the entry from ldap or tnrhdb if this is a load
+ * request and a template name was not provided.
+ */
+ if (!delete_mode &&
+ rhentp->rh_template[0] == '\0' &&
+ (rhentp = tsol_getrhbyaddr(abuf, alen,
+ rhent.rh_address.ta_family)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: database lookup failed for %s\n"),
+ abuf);
+ exit(1);
+ }
+
+ if (verbose_mode)
+ (void) printf("%s rh entry %s\n", delete_mode ? "deleting" :
+ "loading", abuf);
+
+ /* update the tnrhdb entry in the kernel */
+ if (tnrh(delete_mode ? TNDB_DELETE : TNDB_LOAD, rhentp) != 0) {
+ if (errno == EFAULT)
+ perror("tnrh");
+ else if (errno == ENOENT)
+ (void) fprintf(stderr,
+ gettext("tnctl: %1$s of remote-host kernel cache "
+ "entry %2$s failed: no such entry\n"),
+ delete_mode ? gettext("delete") : gettext("load"),
+ abuf);
+ else
+ (void) fprintf(stderr,
+ gettext("tnctl: %1$s of remote-host kernel cache "
+ "entry %2$s failed: %3$s\n"),
+ delete_mode ? gettext("delete") : gettext("load"),
+ abuf, strerror(errno));
+ exit(1);
+ }
+ if (rhentp != &rhent)
+ tsol_freerhent(rhentp);
+}
+
+static void
+handle_mlps(zoneid_t zoneid, tsol_mlp_t *mlp, int flags, int cmd)
+{
+ tsol_mlpent_t tsme;
+
+ tsme.tsme_zoneid = zoneid;
+ tsme.tsme_flags = flags;
+ while (!TSOL_MLP_END(mlp)) {
+ tsme.tsme_mlp = *mlp;
+ if (tnmlp(cmd, &tsme) != 0) {
+ /*
+ * Usage of ?: here is ugly, but helps with
+ * localization.
+ */
+ (void) fprintf(stderr,
+ flags & TSOL_MEF_SHARED ?
+ gettext("tnctl: cannot set "
+ "shared MLP on %1$d-%2$d/%3$d: %4$s\n") :
+ gettext("tnctl: cannot set "
+ "zone-specific MLP on %1$d-%2$d/%3$d: %4$s\n"),
+ mlp->mlp_port, mlp->mlp_port_upper, mlp->mlp_ipp,
+ strerror(errno));
+ exit(1);
+ }
+ mlp++;
+ }
+}
+
+/*
+ * This reads the configuration for the global zone out of tnzonecfg
+ * and sets it in the kernel. The non-global zones are configured
+ * by zoneadmd.
+ */
+static void
+process_tnzone(const char *file)
+{
+ tsol_zcent_t *zc;
+ tsol_mlpent_t tsme;
+ int err;
+ char *errstr;
+ FILE *fp;
+ char line[2048], *cp;
+ int linenum, errors;
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: failed to open %s: %s\n"), file,
+ strerror(errno));
+ exit(1);
+ }
+
+ linenum = errors = 0;
+ zc = NULL;
+ while (fgets(line, sizeof (line), fp) != NULL) {
+ if ((cp = strchr(line, '\n')) != NULL)
+ *cp = '\0';
+
+ linenum++;
+ if ((zc = tsol_sgetzcent(line, &err, &errstr)) == NULL) {
+ if (err == LTSNET_EMPTY)
+ continue;
+ if (errors == 0) {
+ int errtmp = errno;
+
+ (void) fprintf(stderr, gettext("tnctl: errors "
+ "parsing %s:\n"), file);
+ errno = errtmp;
+ }
+ print_error(linenum, err, errstr);
+ errors++;
+ continue;
+ }
+
+ if (strcasecmp(zc->zc_name, "global") == 0)
+ break;
+ tsol_freezcent(zc);
+ }
+ (void) fclose(fp);
+
+ if (zc == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: cannot find global zone in %s\n"), file);
+ exit(1);
+ }
+
+ tsme.tsme_zoneid = GLOBAL_ZONEID;
+ tsme.tsme_flags = 0;
+ if (flush_mode)
+ (void) tnmlp(TNDB_FLUSH, &tsme);
+
+ handle_mlps(GLOBAL_ZONEID, zc->zc_private_mlp, 0, TNDB_LOAD);
+ handle_mlps(GLOBAL_ZONEID, zc->zc_shared_mlp, TSOL_MEF_SHARED,
+ TNDB_LOAD);
+
+ tsol_freezcent(zc);
+}
+
+static void
+process_tpl(const char *file)
+{
+ FILE *fp;
+ boolean_t success = B_FALSE;
+ tsol_tpent_t *tpentp;
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: failed to open %s: %s\n"), file,
+ strerror(errno));
+ exit(1);
+ }
+
+ tsol_settpent(1);
+ while (tpentp = tsol_fgettpent(fp)) {
+ /* First time through the loop, flush it all */
+ if (!success && flush_mode)
+ (void) tnrhtp(TNDB_FLUSH, NULL);
+
+ success = B_TRUE;
+
+ if (verbose_mode)
+ (void) printf("tnctl: loading rhtp entry ...\n");
+
+ if (tnrhtp(TNDB_LOAD, tpentp) != 0) {
+ (void) fclose(fp);
+ if (errno == EFAULT)
+ perror("tnrhtp");
+ else
+ (void) fprintf(stderr, gettext("tnctl: load "
+ "of remote-host template %1$s into kernel "
+ "cache failed: %2$s\n"), tpentp->name,
+ strerror(errno));
+ tsol_endtpent();
+ exit(1);
+ }
+ tsol_freetpent(tpentp);
+ }
+ if (!success) {
+ (void) fprintf(stderr,
+ gettext("tnctl: No valid tnrhtp entries found in %s\n"),
+ file);
+ }
+ (void) fclose(fp);
+ tsol_endtpent();
+}
+
+static void
+process_tp(const char *template)
+{
+ tsol_tpstr_t tpstr;
+ tsol_tpent_t tpent;
+ tsol_tpent_t *tpentp;
+ int err;
+ char *errstr;
+ char buf[NSS_BUFLEN_TSOL_TP];
+
+ if (strchr(template, ':') != NULL) {
+ (void) str_to_tpstr(template, strlen(template), &tpstr, buf,
+ sizeof (buf));
+ tpentp = tpstr_to_ent(&tpstr, &err, &errstr);
+ if (tpentp == NULL) {
+ print_error(0, err, errstr);
+ exit(1);
+ }
+ } else if (delete_mode) {
+ (void) memset(&tpent, 0, sizeof (tpent));
+ tpentp = &tpent;
+ (void) strlcpy(tpentp->name, template, sizeof (tpentp->name));
+ } else if ((tpentp = tsol_gettpbyname(template)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: template %s not found\n"), template);
+ exit(1);
+ }
+
+ if (verbose_mode)
+ (void) printf("%s rhtp entry ...\n", delete_mode ? "deleting" :
+ "loading");
+
+ if (tnrhtp(delete_mode ? TNDB_DELETE : TNDB_LOAD, tpentp) != 0) {
+ if (errno == EFAULT)
+ perror("tnrhtp");
+ else if (errno == ENOENT)
+ (void) fprintf(stderr,
+ gettext("tnctl: %1$s of remote-host template "
+ "kernel cache entry %2$s failed: no such "
+ "entry\n"),
+ delete_mode ? gettext("delete") : gettext("load"),
+ tpentp->name);
+ else
+ (void) fprintf(stderr,
+ gettext("tnctl: %1$s of remote-host template "
+ "kernel cache entry %2$s failed: %3$s\n"),
+ delete_mode ? gettext("delete") : gettext("load"),
+ tpentp->name, strerror(errno));
+ exit(1);
+ }
+ if (tpentp != &tpent)
+ tsol_freetpent(tpentp);
+}
+
+static void
+process_mlp(const char *str)
+{
+ const char *cp;
+ char zonename[ZONENAME_MAX];
+ zoneid_t zoneid;
+ tsol_zcent_t *zc;
+ int err;
+ char *errstr;
+ char *sbuf;
+
+ if ((cp = strchr(str, ':')) == NULL) {
+ if (!delete_mode) {
+ (void) fprintf(stderr,
+ gettext("tnctl: need MLP list to insert\n"));
+ exit(2);
+ }
+ (void) strlcpy(zonename, str, sizeof (zonename));
+ } else if (cp - str >= ZONENAME_MAX) {
+ (void) fprintf(stderr, gettext("tnctl: illegal zone name\n"));
+ exit(2);
+ } else {
+ (void) memcpy(zonename, str, cp - str);
+ zonename[cp - str] = '\0';
+ str = cp + 1;
+ }
+
+ if ((zoneid = getzoneidbyname(zonename)) == -1) {
+ (void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"),
+ zonename);
+ exit(1);
+ }
+
+ sbuf = malloc(strlen(zonename) + sizeof (":ADMIN_LOW:0:") +
+ strlen(str));
+ if (sbuf == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ /* LINTED: sprintf is known not to be unbounded here */
+ (void) sprintf(sbuf, "%s:ADMIN_LOW:0:%s", zonename, str);
+ if ((zc = tsol_sgetzcent(sbuf, &err, &errstr)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnctl: unable to parse MLPs\n"));
+ exit(1);
+ }
+ handle_mlps(zoneid, zc->zc_private_mlp, 0,
+ delete_mode ? TNDB_DELETE : TNDB_LOAD);
+ handle_mlps(zoneid, zc->zc_shared_mlp, TSOL_MEF_SHARED,
+ delete_mode ? TNDB_DELETE : TNDB_LOAD);
+ tsol_freezcent(zc);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, gettext("usage: tnctl [-dfv] "
+ "[-h host[/prefix][:tmpl]] [-m zone:priv:share]\n\t"
+ "[-t tmpl[:key=val[;key=val]]] [-[HTz] file]\n"));
+
+ exit(1);
+}