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