1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * tnchkdb.c - Trusted network database checking utility 31 */ 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <errno.h> 35 #include <locale.h> 36 #include <malloc.h> 37 #include <string.h> 38 #include <libtsnet.h> 39 #include <netinet/in.h> 40 #include <nss_dbdefs.h> 41 42 static void usage(void); 43 static void check_tnrhtp(const char *); 44 static void check_tnrhdb(const char *); 45 static void check_tnzonecfg(const char *); 46 47 static boolean_t tnrhtp_bad; 48 static int exitval; 49 50 struct tsol_name_list { 51 struct tsol_name_list *next; 52 int linenum; 53 char name[TNTNAMSIZ]; 54 }; 55 56 struct tsol_addr_list { 57 struct tsol_addr_list *next; 58 int linenum; 59 int prefix_len; 60 in6_addr_t addr; 61 }; 62 63 static struct tsol_name_list *tp_list_head; 64 static struct tsol_addr_list *rh_list_head; 65 static struct tsol_name_list *zc_list_head; 66 67 typedef struct mlp_info_list_s { 68 struct mlp_info_list_s *next; 69 int linenum; 70 tsol_mlp_t mlp; 71 char name[TNTNAMSIZ]; 72 } mlp_info_list_t; 73 74 static mlp_info_list_t *global_mlps; 75 76 static void 77 add_name(struct tsol_name_list **head, const char *name, int linenum) 78 { 79 int err; 80 struct tsol_name_list *entry; 81 82 entry = malloc(sizeof (struct tsol_name_list)); 83 if (entry == NULL) { 84 err = errno; 85 86 (void) fprintf(stderr, 87 gettext("tnchkdb: allocating name list: %s\n"), 88 strerror(err)); 89 exit(1); 90 } 91 (void) strlcpy(entry->name, name, sizeof (entry->name)); 92 entry->next = *head; 93 entry->linenum = linenum; 94 *head = entry; 95 } 96 97 static struct tsol_name_list * 98 find_name(struct tsol_name_list *head, const char *name) 99 { 100 struct tsol_name_list *entry; 101 102 for (entry = head; entry != NULL; entry = entry->next) 103 if (strcmp(entry->name, name) == 0) 104 break; 105 return (entry); 106 } 107 108 static void 109 add_addr(struct tsol_addr_list **head, int prefix_len, in6_addr_t addr, 110 int linenum) 111 { 112 int err; 113 struct tsol_addr_list *entry; 114 115 entry = malloc(sizeof (struct tsol_addr_list)); 116 if (entry == NULL) { 117 err = errno; 118 119 (void) fprintf(stderr, 120 gettext("tnchkdb: allocating addr list: %s\n"), 121 strerror(err)); 122 exit(2); 123 } 124 entry->prefix_len = prefix_len; 125 entry->addr = addr; 126 entry->next = *head; 127 entry->linenum = linenum; 128 *head = entry; 129 } 130 131 static struct tsol_addr_list * 132 find_addr(struct tsol_addr_list *head, int prefix_len, in6_addr_t addr) 133 { 134 struct tsol_addr_list *entry; 135 136 for (entry = head; entry != NULL; entry = entry->next) 137 if (entry->prefix_len == prefix_len && 138 IN6_ARE_ADDR_EQUAL(&entry->addr, &addr)) 139 break; 140 return (entry); 141 } 142 143 static void 144 add_template(const char *name, int linenum) 145 { 146 add_name(&tp_list_head, name, linenum); 147 } 148 149 static struct tsol_name_list * 150 find_template(const char *name) 151 { 152 return (find_name(tp_list_head, name)); 153 } 154 155 static void 156 add_host(int prefix_len, in6_addr_t addr, int linenum) 157 { 158 add_addr(&rh_list_head, prefix_len, addr, linenum); 159 } 160 161 static struct tsol_addr_list * 162 find_host(int prefix_len, in6_addr_t addr) 163 { 164 return (find_addr(rh_list_head, prefix_len, addr)); 165 } 166 167 static void 168 add_zone(const char *name, int linenum) 169 { 170 add_name(&zc_list_head, name, linenum); 171 } 172 173 static struct tsol_name_list * 174 find_zone(const char *name) 175 { 176 return (find_name(zc_list_head, name)); 177 } 178 179 int 180 main(int argc, char **argv) 181 { 182 const char *tnrhdb_file = TNRHDB_PATH; 183 const char *tnrhtp_file = TNRHTP_PATH; 184 const char *tnzonecfg_file = TNZONECFG_PATH; 185 int chr; 186 187 /* set the locale for only the messages system (all else is clean) */ 188 (void) setlocale(LC_ALL, ""); 189 #ifndef TEXT_DOMAIN /* Should be defined by cc -D */ 190 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 191 #endif 192 (void) textdomain(TEXT_DOMAIN); 193 194 while ((chr = getopt(argc, argv, "h:t:z:")) != EOF) { 195 switch (chr) { 196 case 'h': 197 tnrhdb_file = optarg; 198 break; 199 case 't': 200 tnrhtp_file = optarg; 201 break; 202 case 'z': 203 tnzonecfg_file = optarg; 204 break; 205 default: 206 usage(); 207 } 208 } 209 210 check_tnrhtp(tnrhtp_file); 211 check_tnrhdb(tnrhdb_file); 212 check_tnzonecfg(tnzonecfg_file); 213 214 return (exitval); 215 } 216 217 static void 218 usage(void) 219 { 220 (void) fprintf(stderr, gettext( 221 "usage: tnchkdb [-h path] [-t path] [-z path]\n")); 222 exit(2); 223 } 224 225 static void 226 print_error(int linenum, int err, const char *errstr) 227 { 228 (void) fprintf(stderr, gettext("line %1$d: %2$s: %.32s\n"), linenum, 229 tsol_strerror(err, errno), errstr); 230 } 231 232 static void 233 cipso_representable(const bslabel_t *lab, int linenum, const char *template, 234 const char *name) 235 { 236 const _blevel_impl_t *blab = (const _blevel_impl_t *)lab; 237 int lclass; 238 uint32_t c8; 239 240 if (!bltype(lab, SUN_SL_ID)) { 241 (void) fprintf(stderr, gettext("tnchkdb: " 242 "%1$s type %2$d is invalid for cipso labels: " 243 "line %3$d entry %4$s\n"), name, GETBLTYPE(lab), linenum, 244 template); 245 exitval = 1; 246 } 247 lclass = LCLASS(blab); 248 if (lclass & 0xff00) { 249 (void) fprintf(stderr, gettext("tnchkdb: " 250 "%1$s classification %2$x is invalid for cipso labels: " 251 "line %3$d entry %4$s\n"), name, lclass, linenum, 252 template); 253 exitval = 1; 254 } 255 c8 = blab->compartments.c8; 256 #ifdef _BIG_ENDIAN 257 if (c8 & 0x0000ffff) { 258 #else 259 if (c8 & 0xffff0000) { 260 #endif 261 (void) fprintf(stderr, gettext("tnchkdb: %1$s " 262 "compartments 241-256 must be zero for cipso labels: " 263 "line %2$d entry %3$s\n"), name, linenum, template); 264 exitval = 1; 265 } 266 } 267 268 static void 269 check_tnrhtp(const char *file) 270 { 271 tsol_tpent_t *tpentp; 272 tsol_tpstr_t tpstr; 273 int err; 274 char *errstr; 275 FILE *fp; 276 blevel_t *l1, *l2; 277 char line[2048], *cp; 278 int linenum = 0; 279 struct tsol_name_list *tnl; 280 char buf[NSS_BUFLEN_TSOL_TP]; 281 uint32_t initial_doi = 0; 282 boolean_t multiple_doi_found = B_FALSE; 283 boolean_t doi_zero_found = B_FALSE; 284 285 (void) printf(gettext("checking %s ...\n"), file); 286 287 if ((fp = fopen(file, "r")) == NULL) { 288 err = errno; 289 (void) fprintf(stderr, 290 gettext("tnchkdb: cannot open %1$s: %2$s\n"), file, 291 strerror(err)); 292 exitval = 2; 293 tnrhtp_bad = B_TRUE; 294 return; 295 } 296 297 while (fgets(line, sizeof (line), fp) != NULL) { 298 linenum++; 299 if (line[0] == '#') 300 continue; 301 if ((cp = strchr(line, '\n')) != NULL) 302 *cp = '\0'; 303 (void) str_to_tpstr(line, strlen(line), &tpstr, buf, 304 sizeof (buf)); 305 tpentp = tpstr_to_ent(&tpstr, &err, &errstr); 306 if (tpentp == NULL) { 307 if (err == LTSNET_EMPTY) 308 continue; 309 print_error(linenum, err, errstr); 310 exitval = 1; 311 /* 312 * Flag is set *only* for parsing errors, which result 313 * in omitting the entry from tsol_name_list. 314 */ 315 tnrhtp_bad = B_TRUE; 316 continue; 317 } 318 319 switch (tpentp->host_type) { 320 case UNLABELED: 321 /* 322 * check doi 323 */ 324 if (initial_doi == 0) 325 initial_doi = tpentp->tp_cipso_doi_unl; 326 if (tpentp->tp_cipso_doi_unl != initial_doi) 327 multiple_doi_found = B_TRUE; 328 if (tpentp->tp_cipso_doi_unl == 0) 329 doi_zero_found = B_TRUE; 330 331 cipso_representable(&tpentp->tp_def_label, linenum, 332 tpentp->name, TP_DEFLABEL); 333 334 /* 335 * check max_sl dominates min_sl 336 */ 337 l1 = &tpentp->tp_gw_sl_range.lower_bound; 338 l2 = &tpentp->tp_gw_sl_range.upper_bound; 339 if (!bldominates(l2, l1)) { 340 (void) fprintf(stderr, 341 gettext("tnchkdb: max_sl does not " 342 "dominate min_sl: line %$1d entry %2$s\n"), 343 linenum, tpentp->name); 344 exitval = 1; 345 } 346 347 cipso_representable(l1, linenum, tpentp->name, 348 TP_MINLABEL); 349 l1 = (blevel_t *)&tpentp->tp_gw_sl_set[0]; 350 l2 = (blevel_t *)&tpentp->tp_gw_sl_set[NSLS_MAX]; 351 for (; l1 < l2; l1++) { 352 if (bisinvalid(l1)) 353 break; 354 cipso_representable(l1, linenum, tpentp->name, 355 TP_SET); 356 } 357 break; 358 359 case SUN_CIPSO: 360 /* 361 * check max_sl dominates min_sl 362 */ 363 l1 = &tpentp->tp_sl_range_cipso.lower_bound; 364 l2 = &tpentp->tp_sl_range_cipso.upper_bound; 365 if (!bldominates(l2, l1)) { 366 (void) fprintf(stderr, 367 gettext("tnchkdb: max_sl does not " 368 "dominate min_sl: line %$1d entry %2$s\n"), 369 linenum, tpentp->name); 370 exitval = 1; 371 } 372 373 cipso_representable(l1, linenum, tpentp->name, 374 TP_MINLABEL); 375 376 l1 = (blevel_t *)&tpentp->tp_sl_set_cipso[0]; 377 l2 = (blevel_t *)&tpentp->tp_sl_set_cipso[NSLS_MAX]; 378 for (; l1 < l2; l1++) { 379 if (bisinvalid(l1)) 380 break; 381 cipso_representable(l1, linenum, tpentp->name, 382 TP_SET); 383 } 384 385 /* 386 * check doi 387 */ 388 if (initial_doi == 0) 389 initial_doi = tpentp->tp_cipso_doi_cipso; 390 if (tpentp->tp_cipso_doi_cipso != initial_doi) 391 multiple_doi_found = B_TRUE; 392 if (tpentp->tp_cipso_doi_cipso == 0) 393 doi_zero_found = B_TRUE; 394 break; 395 396 default: 397 (void) fprintf(stderr, gettext("tnchkdb: unknown host " 398 "type %$1d: line %2$d entry %3$s\n"), 399 tpentp->host_type, linenum, tpentp->name); 400 exitval = 1; 401 } /* switch */ 402 403 /* 404 * check if a duplicated entry 405 */ 406 if ((tnl = find_template(tpentp->name)) != NULL) { 407 (void) fprintf(stderr, gettext("tnchkdb: duplicated " 408 "entry: %1$s at lines %2$d and %3$d\n"), 409 tpentp->name, tnl->linenum, linenum); 410 exitval = 1; 411 } else { 412 add_template(tpentp->name, linenum); 413 } 414 tsol_freetpent(tpentp); 415 } 416 if (multiple_doi_found == B_TRUE) { 417 (void) fprintf(stderr, 418 gettext("tnchkdb: Warning: tnrhtp entries do not all " 419 "contain the same DOI value\n")); 420 } 421 if (doi_zero_found == B_TRUE) { 422 (void) fprintf(stderr, 423 gettext("tnchkdb: Warning: DOI=0 found in some " 424 "tnrhtp entries\n")); 425 } 426 (void) fclose(fp); 427 } 428 429 static void 430 check_tnrhdb(const char *file) 431 { 432 tsol_rhent_t *rhentp; 433 tsol_rhstr_t rhstr; 434 int err; 435 char *errstr; 436 FILE *fp; 437 char line[2048], *cp; 438 int linenum; 439 in6_addr_t addr; 440 struct tsol_addr_list *tal; 441 char buf[NSS_BUFLEN_TSOL_RH]; 442 443 (void) printf(gettext("checking %s ...\n"), file); 444 445 if ((fp = fopen(file, "r")) == NULL) { 446 err = errno; 447 (void) fprintf(stderr, 448 gettext("tnchkdb: failed to open %s: %s\n"), file, 449 strerror(err)); 450 exitval = 2; 451 return; 452 } 453 454 /* 455 * check that all templates used in tnrhdb file are defined by tnrhtp 456 */ 457 linenum = 0; 458 while (fgets(line, sizeof (line), fp) != NULL) { 459 linenum++; 460 if (line[0] == '#') 461 continue; 462 if ((cp = strchr(line, '\n')) != NULL) 463 *cp = '\0'; 464 (void) str_to_rhstr(line, strlen(line), &rhstr, buf, 465 sizeof (buf)); 466 rhentp = rhstr_to_ent(&rhstr, &err, &errstr); 467 if (rhentp == NULL) { 468 if (err == LTSNET_EMPTY) 469 continue; 470 print_error(linenum, err, errstr); 471 exitval = 1; 472 continue; 473 } 474 475 if (rhentp->rh_address.ta_family == AF_INET) { 476 IN6_INADDR_TO_V4MAPPED(&rhentp->rh_address.ta_addr_v4, 477 &addr); 478 } else { 479 addr = rhentp->rh_address.ta_addr_v6; 480 } 481 if ((tal = find_host(rhentp->rh_prefix, addr)) != NULL) { 482 (void) fprintf(stderr, 483 gettext("tnchkdb: duplicate entry: lines %1$d and " 484 "%2$d\n"), tal->linenum, linenum); 485 exitval = 1; 486 } else { 487 add_host(rhentp->rh_prefix, addr, linenum); 488 } 489 490 if (!tnrhtp_bad && find_template(rhentp->rh_template) == NULL) { 491 (void) fprintf(stderr, 492 gettext("tnchkdb: unknown template name: %1$s at " 493 "line %2$d\n"), rhentp->rh_template, linenum); 494 exitval = 1; 495 } 496 497 tsol_freerhent(rhentp); 498 } 499 (void) fclose(fp); 500 } 501 502 static void 503 check_mlp_conflicts(tsol_mlp_t *mlps, boolean_t isglobal, const char *name, 504 int linenum) 505 { 506 tsol_mlp_t *mlpptr, *mlp2; 507 mlp_info_list_t *mil; 508 509 for (mlpptr = mlps; !TSOL_MLP_END(mlpptr); mlpptr++) { 510 if (mlpptr->mlp_port_upper == 0) 511 mlpptr->mlp_port_upper = mlpptr->mlp_port; 512 513 /* First, validate against self for duplicates */ 514 for (mlp2 = mlps; mlp2 < mlpptr; mlp2++) { 515 if (mlp2->mlp_ipp == mlpptr->mlp_ipp && 516 !(mlp2->mlp_port_upper < mlpptr->mlp_port || 517 mlp2->mlp_port > mlpptr->mlp_port_upper)) 518 break; 519 } 520 521 if (mlp2 < mlpptr) { 522 (void) fprintf(stderr, gettext("tnchkdb: self-overlap " 523 "of %1$s MLP protocol %2$d port %3$d-%4$d with " 524 "%5$d-%6$d: zone %7$s line %8$d\n"), 525 gettext(isglobal ? "global" : "zone-specific"), 526 mlpptr->mlp_ipp, mlpptr->mlp_port, 527 mlpptr->mlp_port_upper, mlp2->mlp_port, 528 mlp2->mlp_port_upper, name, linenum); 529 exitval = 1; 530 } 531 532 if (isglobal) { 533 /* Next, validate against list for duplicates */ 534 for (mil = global_mlps; mil != NULL; mil = mil->next) { 535 if (strcmp(mil->name, name) == 0) 536 continue; 537 if (mil->mlp.mlp_ipp == mlpptr->mlp_ipp && 538 !(mil->mlp.mlp_port_upper < 539 mlpptr->mlp_port || 540 mil->mlp.mlp_port > 541 mlpptr->mlp_port_upper)) 542 break; 543 } 544 545 if (mil != NULL) { 546 (void) fprintf(stderr, gettext("tnchkdb: " 547 "overlap of global MLP protocol %2$d port " 548 "%3$d-%4$d with zone %$5s %6$d-%7$d: zone " 549 "%8$s lines %9$d and %10$d\n"), 550 mlpptr->mlp_ipp, mlpptr->mlp_port, 551 mlpptr->mlp_port_upper, mil->name, 552 mil->mlp.mlp_port, mil->mlp.mlp_port_upper, 553 name, mil->linenum, linenum); 554 exitval = 1; 555 } 556 557 /* Now throw into list */ 558 if ((mil = malloc(sizeof (*mil))) == NULL) { 559 (void) fprintf(stderr, gettext("tnchkdb: " 560 "malloc error: %s\n"), strerror(errno)); 561 exit(2); 562 } 563 (void) strlcpy(mil->name, name, sizeof (mil->name)); 564 mil->linenum = linenum; 565 mil->mlp = *mlpptr; 566 mil->next = global_mlps; 567 global_mlps = mil; 568 } 569 } 570 } 571 572 static void 573 check_tnzonecfg(const char *file) 574 { 575 tsol_zcent_t *zc; 576 int err; 577 char *errstr; 578 FILE *fp; 579 char line[2048], *cp; 580 int linenum; 581 boolean_t saw_global; 582 struct tsol_name_list *tnl; 583 584 (void) printf(gettext("checking %s ...\n"), file); 585 586 if ((fp = fopen(file, "r")) == NULL) { 587 err = errno; 588 (void) fprintf(stderr, 589 gettext("tnchkdb: failed to open %s: %s\n"), file, 590 strerror(err)); 591 exitval = 2; 592 return; 593 } 594 595 saw_global = B_FALSE; 596 linenum = 0; 597 while (fgets(line, sizeof (line), fp) != NULL) { 598 if ((cp = strchr(line, '\n')) != NULL) 599 *cp = '\0'; 600 601 linenum++; 602 if ((zc = tsol_sgetzcent(line, &err, &errstr)) == NULL) { 603 if (err == LTSNET_EMPTY) 604 continue; 605 print_error(linenum, err, errstr); 606 exitval = 1; 607 continue; 608 } 609 610 cipso_representable(&zc->zc_label, linenum, zc->zc_name, 611 "label"); 612 613 if (strcmp(zc->zc_name, "global") == 0) 614 saw_global = B_TRUE; 615 616 if ((tnl = find_zone(zc->zc_name)) != NULL) { 617 (void) fprintf(stderr, 618 gettext("tnchkdb: duplicate zones: %1$s at lines " 619 "%2$d and %3$d\n"), zc->zc_name, tnl->linenum, 620 linenum); 621 exitval = 1; 622 } else { 623 add_zone(zc->zc_name, linenum); 624 } 625 626 if (zc->zc_private_mlp != NULL) 627 check_mlp_conflicts(zc->zc_private_mlp, B_FALSE, 628 zc->zc_name, linenum); 629 if (zc->zc_shared_mlp != NULL) 630 check_mlp_conflicts(zc->zc_shared_mlp, B_TRUE, 631 zc->zc_name, linenum); 632 633 tsol_freezcent(zc); 634 } 635 (void) fclose(fp); 636 637 if (!saw_global) { 638 (void) fprintf(stderr, gettext("tnchkdb: missing required " 639 "entry for global zone in %s\n"), file); 640 exitval = 1; 641 } 642 } 643