4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * Trusted Network control utility
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
47 #include <nss_dbdefs.h>
49 static void process_rh(const char *);
50 static void process_rhl(const char *);
51 static void process_mlp(const char *);
52 static void process_tp(const char *);
53 static void process_tpl(const char *);
54 static void process_tnzone(const char *);
55 static void usage(void);
56 static void translate_inet_addr(tsol_rhent_t
*, int *, char [], int);
58 static boolean_t verbose_mode
;
59 static boolean_t delete_mode
;
60 static boolean_t flush_mode
;
63 main(int argc
, char **argv
)
68 /* Don't do anything if labeling is not active. */
69 if (!is_system_labeled())
72 /* set the locale for only the messages system (all else is clean) */
73 (void) setlocale(LC_ALL
, "");
74 #ifndef TEXT_DOMAIN /* Should be defined by cc -D */
75 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
78 (void) textdomain(TEXT_DOMAIN
);
80 while ((chr
= getopt(argc
, argv
, "dfh:H:m:t:T:vz:")) != EOF
) {
104 verbose_mode
= B_TRUE
;
107 process_tnzone(optarg
);
117 print_error(int linenum
, int err
, const char *errstr
)
120 (void) fprintf(stderr
, gettext("line %1$d: %2$s:\n"), linenum
,
121 tsol_strerror(err
, errno
));
123 (void) fprintf(stderr
, gettext("tnctl: parsing error: %s\n"),
124 tsol_strerror(err
, errno
));
125 (void) fprintf(stderr
, "%.32s\n", errstr
);
129 * Produce ascii format of address and prefix length
132 translate_inet_addr(tsol_rhent_t
*rhentp
, int *alen
, char abuf
[], int abuflen
)
136 struct in6_addr ipv6addr
;
139 (void) snprintf(tmpbuf
, sizeof (tmpbuf
), "/%d", rhentp
->rh_prefix
);
141 if (rhentp
->rh_address
.ta_family
== AF_INET6
) {
142 aptr
= &(rhentp
->rh_address
.ta_addr_v6
);
143 (void) inet_ntop(rhentp
->rh_address
.ta_family
, aptr
, abuf
,
145 if (rhentp
->rh_prefix
!= 128) {
146 if (strlcat(abuf
, tmpbuf
, abuflen
) >= abuflen
)
147 (void) fprintf(stderr
, gettext(
148 "tnctl: buffer overflow detected: %s\n"),
151 *alen
= strlen(abuf
);
153 aptr
= &(rhentp
->rh_address
.ta_addr_v4
);
154 (void) inet_ntop(rhentp
->rh_address
.ta_family
, aptr
, abuf
,
156 if (rhentp
->rh_prefix
!= 32) {
157 if (strlcat(abuf
, tmpbuf
, abuflen
) >= abuflen
)
158 (void) fprintf(stderr
, gettext(
159 "tnctl: buffer overflow detected: %s\n"),
162 *alen
= strlen(abuf
);
167 * Load remote host entries from the designated file.
170 process_rhl(const char *file
)
172 boolean_t error
= B_FALSE
;
173 boolean_t success
= B_FALSE
;
174 tsol_rhent_t
*rhentp
= NULL
;
177 /* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
178 char abuf
[INET6_ADDRSTRLEN
+5];
180 if ((fp
= fopen(file
, "r")) == NULL
) {
181 (void) fprintf(stderr
,
182 gettext("tnctl: failed to open %1$s: %2$s\n"),
183 file
, strerror(errno
));
188 while (rhentp
= tsol_fgetrhent(fp
, &error
)) {
189 /* First time through the loop, flush it all */
190 if (!success
&& flush_mode
)
191 (void) tnrh(TNDB_FLUSH
, NULL
);
195 (void) printf("loading rh entry...\n");
197 if (tnrh(TNDB_LOAD
, rhentp
) != 0) {
199 if (errno
== EFAULT
) {
202 translate_inet_addr(rhentp
, &alen
, abuf
,
204 (void) fprintf(stderr
,
205 gettext("tnctl: load of remote-host entry "
206 "%1$s into kernel cache failed: %2$s\n"),
207 abuf
, strerror(errno
));
212 tsol_freerhent(rhentp
);
215 (void) fprintf(stderr
,
216 gettext("tnctl: No valid tnrhdb entries found in %s\n"),
227 * The argument can be either a host name, an address
228 * in tnrhdb address format, or a complete tnrhdb entry.
231 process_rh(const char *hostname
)
235 tsol_rhent_t
*rhentp
;
239 /* abuf holds: <numeric-ip-addr>'/'<prefix-length>'\0' */
240 char abuf
[INET6_ADDRSTRLEN
+5];
245 char buf
[NSS_BUFLEN_TSOL_RH
];
246 struct in6_addr ipv6addr
;
248 /* was a template name provided on the command line? */
249 if ((cp
= strrchr(hostname
, ':')) != NULL
&& cp
!= hostname
&&
251 /* use common tnrhdb line conversion function */
252 (void) str_to_rhstr(hostname
, strlen(hostname
), &rhstr
, buf
,
254 rhentp
= rhstr_to_ent(&rhstr
, &err
, &errstr
);
255 if (rhentp
== NULL
) {
256 print_error(0, err
, errstr
);
264 /* Check for a subnet prefix length */
265 if ((prefix_p
= strchr(hostname
, '/')) != NULL
) {
268 rhent
.rh_prefix
= strtol(cp1
, &cp2
, 0);
269 if (*cp2
!= '\0' || errno
!= 0 || rhent
.rh_prefix
< 0) {
270 (void) fprintf(stderr
, gettext("tnct: invalid "
271 "prefix length: %s\n"), cp
);
275 rhent
.rh_prefix
= -1;
278 /* Strip any backslashes from numeric address */
279 hostname_p
= malloc(strlen(hostname
)+1);
280 if (hostname_p
== NULL
) {
285 while (*hostname
!= '\0' && *hostname
!= '/') {
292 /* Convert address or hostname to binary af_inet6 format */
293 hp
= getipnodebyname(hostname_p
, AF_INET6
,
294 AI_ALL
| AI_ADDRCONFIG
| AI_V4MAPPED
, &err
);
296 (void) fprintf(stderr
, gettext("tnctl: unknown host "
297 "or invalid literal address: %s\n"), hostname_p
);
298 if (err
== TRY_AGAIN
)
299 (void) fprintf(stderr
,
300 gettext("\t(try again later)\n"));
304 (void) memcpy(&ipv6addr
, hp
->h_addr
, hp
->h_length
);
306 /* if ipv4 address, convert to af_inet format */
307 if (IN6_IS_ADDR_V4MAPPED(&ipv6addr
)) {
308 rhent
.rh_address
.ta_family
= AF_INET
;
309 IN6_V4MAPPED_TO_INADDR(&ipv6addr
,
310 &rhent
.rh_address
.ta_addr_v4
);
311 if (rhent
.rh_prefix
== -1)
312 rhent
.rh_prefix
= 32;
314 rhent
.rh_address
.ta_family
= AF_INET6
;
315 rhent
.rh_address
.ta_addr_v6
= ipv6addr
;
316 if (rhent
.rh_prefix
== -1)
317 rhent
.rh_prefix
= 128;
319 rhent
.rh_template
[0] = '\0';
323 /* produce ascii format of address and prefix length */
324 translate_inet_addr(rhentp
, &alen
, abuf
, sizeof (abuf
));
327 * look up the entry from ldap or tnrhdb if this is a load
328 * request and a template name was not provided.
331 rhentp
->rh_template
[0] == '\0' &&
332 (rhentp
= tsol_getrhbyaddr(abuf
, alen
+1,
333 rhent
.rh_address
.ta_family
)) == NULL
) {
334 (void) fprintf(stderr
,
335 gettext("tnctl: database lookup failed for %s\n"),
341 (void) printf("%s rh entry %s\n", delete_mode
? "deleting" :
344 /* update the tnrhdb entry in the kernel */
345 if (tnrh(delete_mode
? TNDB_DELETE
: TNDB_LOAD
, rhentp
) != 0) {
348 else if (errno
== ENOENT
)
349 (void) fprintf(stderr
,
350 gettext("tnctl: %1$s of remote-host kernel cache "
351 "entry %2$s failed: no such entry\n"),
352 delete_mode
? gettext("delete") : gettext("load"),
355 (void) fprintf(stderr
,
356 gettext("tnctl: %1$s of remote-host kernel cache "
357 "entry %2$s failed: %3$s\n"),
358 delete_mode
? gettext("delete") : gettext("load"),
359 abuf
, strerror(errno
));
362 if (rhentp
!= &rhent
)
363 tsol_freerhent(rhentp
);
367 handle_mlps(zoneid_t zoneid
, tsol_mlp_t
*mlp
, int flags
, int cmd
)
371 tsme
.tsme_zoneid
= zoneid
;
372 tsme
.tsme_flags
= flags
;
373 while (!TSOL_MLP_END(mlp
)) {
374 tsme
.tsme_mlp
= *mlp
;
375 if (tnmlp(cmd
, &tsme
) != 0) {
377 * Usage of ?: here is ugly, but helps with
380 (void) fprintf(stderr
,
381 flags
& TSOL_MEF_SHARED
?
382 gettext("tnctl: cannot set "
383 "shared MLP on %1$d-%2$d/%3$d: %4$s\n") :
384 gettext("tnctl: cannot set "
385 "zone-specific MLP on %1$d-%2$d/%3$d: %4$s\n"),
386 mlp
->mlp_port
, mlp
->mlp_port_upper
, mlp
->mlp_ipp
,
395 * This reads the configuration for the global zone out of tnzonecfg
396 * and sets it in the kernel. The non-global zones are configured
400 process_tnzone(const char *file
)
407 char line
[2048], *cp
;
410 if ((fp
= fopen(file
, "r")) == NULL
) {
411 (void) fprintf(stderr
,
412 gettext("tnctl: failed to open %s: %s\n"), file
,
417 linenum
= errors
= 0;
419 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
420 if ((cp
= strchr(line
, '\n')) != NULL
)
424 if ((zc
= tsol_sgetzcent(line
, &err
, &errstr
)) == NULL
) {
425 if (err
== LTSNET_EMPTY
)
430 (void) fprintf(stderr
, gettext("tnctl: errors "
431 "parsing %s:\n"), file
);
434 print_error(linenum
, err
, errstr
);
439 if (strcasecmp(zc
->zc_name
, "global") == 0)
446 (void) fprintf(stderr
,
447 gettext("tnctl: cannot find global zone in %s\n"), file
);
451 tsme
.tsme_zoneid
= GLOBAL_ZONEID
;
454 (void) tnmlp(TNDB_FLUSH
, &tsme
);
456 handle_mlps(GLOBAL_ZONEID
, zc
->zc_private_mlp
, 0, TNDB_LOAD
);
457 handle_mlps(GLOBAL_ZONEID
, zc
->zc_shared_mlp
, TSOL_MEF_SHARED
,
464 process_tpl(const char *file
)
467 boolean_t error
= B_FALSE
;
468 boolean_t success
= B_FALSE
;
469 tsol_tpent_t
*tpentp
;
471 if ((fp
= fopen(file
, "r")) == NULL
) {
472 (void) fprintf(stderr
,
473 gettext("tnctl: failed to open %s: %s\n"), file
,
479 while (tpentp
= tsol_fgettpent(fp
, &error
)) {
480 /* First time through the loop, flush it all */
481 if (!success
&& flush_mode
)
482 (void) tnrhtp(TNDB_FLUSH
, NULL
);
487 (void) printf("tnctl: loading rhtp entry ...\n");
489 if (tnrhtp(TNDB_LOAD
, tpentp
) != 0) {
494 (void) fprintf(stderr
, gettext("tnctl: load "
495 "of remote-host template %1$s into kernel "
496 "cache failed: %2$s\n"), tpentp
->name
,
501 tsol_freetpent(tpentp
);
504 (void) fprintf(stderr
,
505 gettext("tnctl: No valid tnrhtp entries found in %s\n"),
516 process_tp(const char *template)
520 tsol_tpent_t
*tpentp
;
523 char buf
[NSS_BUFLEN_TSOL_TP
];
525 if (strchr(template, ':') != NULL
) {
526 (void) str_to_tpstr(template, strlen(template), &tpstr
, buf
,
528 tpentp
= tpstr_to_ent(&tpstr
, &err
, &errstr
);
529 if (tpentp
== NULL
) {
530 print_error(0, err
, errstr
);
533 } else if (delete_mode
) {
534 (void) memset(&tpent
, 0, sizeof (tpent
));
536 (void) strlcpy(tpentp
->name
, template, sizeof (tpentp
->name
));
537 } else if ((tpentp
= tsol_gettpbyname(template)) == NULL
) {
538 (void) fprintf(stderr
,
539 gettext("tnctl: template %s not found\n"), template);
544 (void) printf("%s rhtp entry ...\n", delete_mode
? "deleting" :
547 if (tnrhtp(delete_mode
? TNDB_DELETE
: TNDB_LOAD
, tpentp
) != 0) {
550 else if (errno
== ENOENT
)
551 (void) fprintf(stderr
,
552 gettext("tnctl: %1$s of remote-host template "
553 "kernel cache entry %2$s failed: no such "
555 delete_mode
? gettext("delete") : gettext("load"),
558 (void) fprintf(stderr
,
559 gettext("tnctl: %1$s of remote-host template "
560 "kernel cache entry %2$s failed: %3$s\n"),
561 delete_mode
? gettext("delete") : gettext("load"),
562 tpentp
->name
, strerror(errno
));
565 if (tpentp
!= &tpent
)
566 tsol_freetpent(tpentp
);
570 process_mlp(const char *str
)
573 char zonename
[ZONENAME_MAX
];
580 if ((cp
= strchr(str
, ':')) == NULL
) {
582 (void) fprintf(stderr
,
583 gettext("tnctl: need MLP list to insert\n"));
586 (void) strlcpy(zonename
, str
, sizeof (zonename
));
587 } else if (cp
- str
>= ZONENAME_MAX
) {
588 (void) fprintf(stderr
, gettext("tnctl: illegal zone name\n"));
591 (void) memcpy(zonename
, str
, cp
- str
);
592 zonename
[cp
- str
] = '\0';
596 if ((zoneid
= getzoneidbyname(zonename
)) == -1) {
597 (void) fprintf(stderr
, gettext("tninfo: zone '%s' unknown\n"),
602 sbuf
= malloc(strlen(zonename
) + sizeof (":ADMIN_LOW:0:") +
608 /* LINTED: sprintf is known not to be unbounded here */
609 (void) sprintf(sbuf
, "%s:ADMIN_LOW:0:%s", zonename
, str
);
610 if ((zc
= tsol_sgetzcent(sbuf
, &err
, &errstr
)) == NULL
) {
611 (void) fprintf(stderr
,
612 gettext("tnctl: unable to parse MLPs\n"));
615 handle_mlps(zoneid
, zc
->zc_private_mlp
, 0,
616 delete_mode
? TNDB_DELETE
: TNDB_LOAD
);
617 handle_mlps(zoneid
, zc
->zc_shared_mlp
, TSOL_MEF_SHARED
,
618 delete_mode
? TNDB_DELETE
: TNDB_LOAD
);
625 (void) fprintf(stderr
, gettext("usage: tnctl [-dfv] "
626 "[-h host[/prefix][:tmpl]] [-m zone:priv:share]\n\t"
627 "[-t tmpl[:key=val[;key=val]]] [-[HTz] file]\n"));