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 #include <sys/types.h> 28 #include <time.h> 29 #include <unistd.h> 30 #include <stdio.h> 31 #include <sys/fcntl.h> 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include <locale.h> 35 #include <langinfo.h> 36 #include <search.h> 37 #include <tsol/label.h> 38 #include <errno.h> 39 #include <sys/tsol/tndb.h> 40 #include <sys/socket.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 #include <netdb.h> 44 #include <signal.h> 45 #include <sys/signal.h> 46 #include <string.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <stdarg.h> 50 #include <syslog.h> 51 #include <ctype.h> 52 #include <pwd.h> 53 #include <grp.h> 54 #include <door.h> 55 #include <synch.h> 56 #include <sys/tsol/tsyscall.h> 57 #include <nss_dbdefs.h> 58 #include <libtsnet.h> 59 #include <zone.h> 60 61 #include "tnd.h" 62 63 static FILE *tnlog_open(char *); 64 static void usage(); 65 static void parse_opts(int, char **); 66 static int check_debugl(int); 67 static void load_tp(); 68 static void load_tp_entry(); 69 static void tnd_serve(); 70 static void detachfromtty(); 71 static void terminate(); 72 static void noop(); 73 static char *gettime(); 74 static int isnumber(char *); 75 static void poll_now(); 76 static int nss_get_tp(); 77 static int nss_get_rh(); 78 static void timer(); 79 static void load_rh_marked(); 80 static int rhtable_search_and_update(struct tsol_rhent *ent, int duplflag); 81 static int is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt); 82 static int walk_cache_table(in_addr_t newaddr, char *name, 83 int indx, tnd_tnrhdb_t *src); 84 static tnrh_tlb_t *lookup_cache_table(in_addr_t addr); 85 static int update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src); 86 static void update_rh_entry(int op, struct tsol_rhent *rhentp); 87 static int handle_unvisited_nodes(); 88 static in_addr_t rh_index_to_mask(uint_t masklen); 89 static tnrh_tlb_ipv6_t *lookup_cache_table_v6(in6_addr_t addr); 90 static in6_addr_t *rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask); 91 static void load_rh_marked_v6(); 92 static int 93 rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag); 94 static int walk_cache_table_v6(in6_addr_t newaddr, char *name, 95 int indx, tnd_tnrhdb_t *src); 96 static int update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src); 97 static int handle_unvisited_nodes_v6(); 98 99 #ifdef DEBUG 100 static void print_entry(tsol_rhent_t *ent, int af); 101 static void print_tlbt(tnrh_tlb_t *tlbt); 102 static void rhtable_print(); 103 static void cachetable_print(); 104 static void rhtable_walk(void (*action)()); 105 static void cachetable_print_v6(); 106 static void rhtable_print_v6(); 107 static void rhtable_walk_v6(void (*action)()); 108 #endif /* DEBUG */ 109 110 /* 111 * The following constants and structures and the functions 112 * that operate on them are similar to the ip_ire.c and ip6_ire.c 113 * code in the kernel. 114 */ 115 #define TNRH_TABLE_HASH_SIZE 256 116 #define IP_ABITS 32 117 #define IP_MASK_TABLE_SIZE (IP_ABITS + 1) 118 #define RH_HOST_MASK (in_addr_t)0xffffffffU 119 120 #define IPV6_ABITS 128 121 #define IPV6_MASK_TABLE_SIZE (IPV6_ABITS + 1) 122 #define s6_addr8 _S6_un._S6_u8 123 #define s6_addr32 _S6_un._S6_u32 124 125 /* 126 * Exclusive-or the 6 bytes that are likely to contain the MAC 127 * address. Assumes table_size does not exceed 256. 128 * Assumes EUI-64 format for good hashing. 129 */ 130 #define TNRH_ADDR_HASH_V6(addr) \ 131 (((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^ \ 132 (addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^ \ 133 (addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % TNRH_TABLE_HASH_SIZE) 134 135 #define TNRH_ADDR_MASK_HASH_V6(addr, mask) \ 136 ((((addr).s6_addr8[8] & (mask).s6_addr8[8]) ^ \ 137 ((addr).s6_addr8[9] & (mask).s6_addr8[9]) ^ \ 138 ((addr).s6_addr8[10] & (mask).s6_addr8[10]) ^ \ 139 ((addr).s6_addr8[13] & (mask).s6_addr8[13]) ^ \ 140 ((addr).s6_addr8[14] & (mask).s6_addr8[14]) ^ \ 141 ((addr).s6_addr8[15] & (mask).s6_addr8[15])) % TNRH_TABLE_HASH_SIZE) 142 143 /* Mask comparison: is IPv6 addr a, and'ed with mask m, equal to addr b? */ 144 #define V6_MASK_EQ(a, m, b) \ 145 ((((a).s6_addr32[0] & (m).s6_addr32[0]) == (b).s6_addr32[0]) && \ 146 (((a).s6_addr32[1] & (m).s6_addr32[1]) == (b).s6_addr32[1]) && \ 147 (((a).s6_addr32[2] & (m).s6_addr32[2]) == (b).s6_addr32[2]) && \ 148 (((a).s6_addr32[3] & (m).s6_addr32[3]) == (b).s6_addr32[3])) 149 150 151 const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 }; 152 153 /* 154 * This is a table of hash tables to keep 155 * all the name service entries. We don't have 156 * a separate hash bucket structure, instead mantain 157 * a pointer to the hash chain. 158 */ 159 tnd_tnrhdb_t **tnrh_entire_table[IP_MASK_TABLE_SIZE]; 160 tnd_tnrhdb_t **tnrh_entire_table_v6[IPV6_MASK_TABLE_SIZE]; 161 162 /* reader/writer lock for tnrh_entire_table */ 163 rwlock_t entire_rwlp; 164 rwlock_t entire_rwlp_v6; 165 166 167 /* 168 * This is a hash table which keeps fully resolved 169 * tnrhdb entries <IP address, Host type>. We don't have 170 * a separate hash bucket structure, instead 171 * mantain a pointer to the hash chain. 172 */ 173 tnrh_tlb_t *tnrh_cache_table[TNRH_TABLE_HASH_SIZE]; 174 tnrh_tlb_ipv6_t *tnrh_cache_table_v6[TNRH_TABLE_HASH_SIZE]; 175 176 /* reader/writer lock for tnrh_cache_table */ 177 rwlock_t cache_rwlp; 178 rwlock_t cache_rwlp_v6; 179 180 FILE *logf; 181 int debugl = 0; 182 int poll_interval = TND_DEF_POLL_TIME; 183 int delay_poll_flag = 0; 184 185 void *tp_tree; 186 187 #define _SZ_TIME_BUF 100 188 char time_buf[_SZ_TIME_BUF]; 189 190 #define cprint(s, param) { \ 191 register FILE *consl; \ 192 \ 193 if ((consl = fopen("/dev/msglog", "w")) != NULL) { \ 194 setbuf(consl, NULL); \ 195 (void) fprintf(consl, "tnd: "); \ 196 (void) fprintf(consl, s, param); \ 197 (void) fclose(consl); \ 198 } \ 199 } 200 201 #define RHENT_BUF_SIZE 300 202 #define TPENT_BUF_SIZE 2000 203 204 /* 128 privs * (24 bytes + 1 deliminator)= 3200 bytes + 1200 cushion */ 205 #define STRING_PRIVS_SIZE 4800 206 #define ID_ENT_SIZE 500 207 208 int 209 main(int argc, char **argv) 210 { 211 212 213 const ucred_t *uc = NULL; 214 const priv_set_t *pset; 215 struct sigaction act; 216 217 /* set the locale for only the messages system (all else is clean) */ 218 (void) setlocale(LC_ALL, ""); 219 #ifndef TEXT_DOMAIN /* Should be defined by cc -D */ 220 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 221 #endif 222 (void) textdomain(TEXT_DOMAIN); 223 224 if (getzoneid() != GLOBAL_ZONEID) { 225 syslog(LOG_ERR, "can not run tnd from a local zone"); 226 exit(-1); 227 } 228 229 230 if (((uc = ucred_get(getpid())) == NULL) || 231 ((pset = ucred_getprivset(uc, PRIV_EFFECTIVE)) == NULL)) { 232 syslog(LOG_ERR, "don't have privilege set"); 233 exit(-1); 234 } 235 236 if (!priv_ismember(pset, PRIV_SYS_NET_CONFIG)) { 237 syslog(LOG_ERR, "don't have privilege to run tnd"); 238 exit(-1); 239 } 240 241 242 /* parse command line options */ 243 (void) parse_opts(argc, argv); 244 245 /* 246 * Initialize reader/writer locks. To be 247 * used within this process only. 248 */ 249 if ((rwlock_init(&entire_rwlp, USYNC_THREAD, 0) != 0) || 250 (rwlock_init(&entire_rwlp_v6, USYNC_THREAD, 0) != 0) || 251 (rwlock_init(&cache_rwlp, USYNC_THREAD, 0) != 0) || 252 (rwlock_init(&cache_rwlp_v6, USYNC_THREAD, 0) != 0)) { 253 syslog(LOG_ERR, "cannot initialize lock"); 254 exit(-1); 255 } 256 257 /* catch the usual termination signals for graceful exit */ 258 (void) sigset(SIGINT, terminate); 259 (void) sigset(SIGTERM, terminate); 260 (void) sigset(SIGQUIT, terminate); 261 (void) sigset(SIGUSR1, noop); 262 263 act.sa_handler = timer; 264 act.sa_flags = SA_RESTART; 265 (void) sigemptyset(&act.sa_mask); 266 (void) sigaddset(&act.sa_mask, SIGALRM); 267 (void) sigaddset(&act.sa_mask, SIGHUP); 268 (void) sigaction(SIGALRM, &act, NULL); 269 (void) sigaction(SIGHUP, &act, NULL); 270 271 if (debugl == MAX_TND_DEBUG) { 272 (void) fprintf(logf, "%s : ", gettime()); 273 (void) fprintf(logf, gettext("tnd started. pid= %d\n"), 274 getpid()); 275 (void) fprintf(logf, "%s : ", gettime()); 276 (void) fprintf(logf, 277 gettext("max level debugging! not forking\n")); 278 (void) fflush(logf); 279 } else { 280 detachfromtty(); 281 } 282 283 if (!delay_poll_flag) { 284 (void) sigprocmask(SIG_BLOCK, &act.sa_mask, NULL); 285 timer(); 286 (void) sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 287 } 288 289 if (debugl != MAX_TND_DEBUG) { 290 (void) sigsend(P_PID, getppid(), SIGUSR1); 291 } 292 293 (void) tnd_serve(); 294 295 /* NOT REACHED */ 296 return (0); 297 } 298 299 300 /* 301 * Compare addresses after masking off unneeded bits. 302 * We do this to handle addresses where prefix_len is 303 * less than the bit length. 304 */ 305 static int 306 rhaddr_compar_mask(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2, int i) 307 { 308 struct sockaddr_in *saddrp; 309 in_addr_t tmpmask = rh_index_to_mask(i); 310 311 saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4); 312 313 #ifdef DEBUG 314 (void) fprintf(logf, gettext("rhaddr_compar_mask mask = 0x%4x, \ 315 tp1 = 0x%4x, tp2 = 0x%4x\n"), tmpmask, (tp1->sin_addr), 316 (saddrp->sin_addr.s_addr & tmpmask)); 317 (void) fprintf(logf, gettext("rhaddr_compar_mask return = %d\n"), 318 (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask))); 319 #endif 320 return (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask)); 321 } 322 323 324 /* 325 * we use this where exact match is needed. 326 */ 327 static int 328 rhaddr_compar(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2) 329 { 330 struct sockaddr_in *saddrp; 331 332 saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4); 333 334 #ifdef DEBUG 335 (void) fprintf(logf, gettext("\t tp1 saddrp IP : %s %s\n"), 336 inet_ntoa(tp1->sin_addr), inet_ntoa(saddrp->sin_addr)); 337 #endif 338 339 return (tp1->sin_addr.s_addr == saddrp->sin_addr.s_addr); 340 } 341 342 /* 343 * Compare v6 addresses after masking off unneeded bits. 344 * We do this to handle addresses where prefix_len is 345 * less than the bit length. 346 */ 347 static int 348 rhaddr_compar_mask_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2, int i) 349 { 350 struct sockaddr_in6 *saddrp; 351 in6_addr_t tmpmask; 352 353 (void) rh_index_to_mask_v6(i, &tmpmask); 354 saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6); 355 return (V6_MASK_EQ(tp1->sin6_addr, tmpmask, saddrp->sin6_addr)); 356 } 357 358 /* 359 * we use this where v6 exact match is needed. 360 */ 361 static int 362 rhaddr_compar_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2) 363 { 364 struct sockaddr_in6 *saddrp; 365 366 saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6); 367 return (IN6_ARE_ADDR_EQUAL(&tp1->sin6_addr, &saddrp->sin6_addr)); 368 } 369 370 static int 371 get_hashvalue(in_addr_t addr) 372 { 373 unsigned char *bp; 374 375 bp = (unsigned char *) &addr; 376 return ((bp[0] ^ bp[1] ^ bp[2] ^ bp[3]) % TNRH_TABLE_HASH_SIZE); 377 } 378 379 /* 380 * Convert length for a mask to the mask. 381 */ 382 static in_addr_t 383 rh_index_to_mask(uint_t masklen) 384 { 385 if (masklen == 0) 386 return (0); 387 return (htonl(RH_HOST_MASK << (IP_ABITS - masklen))); 388 } 389 390 /* 391 * Convert length for a mask to the mask. 392 * Returns the argument bitmask. 393 */ 394 static in6_addr_t * 395 rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask) 396 { 397 uint32_t *ptr; 398 399 *bitmask = ipv6_all_zeros; 400 401 ptr = (uint32_t *)bitmask; 402 while (masklen > 32) { 403 *ptr++ = 0xffffffffU; 404 masklen -= 32; 405 } 406 *ptr = htonl(0xffffffffU << (32 - masklen)); 407 return (bitmask); 408 } 409 410 411 static void 412 parse_opts(argc, argv) 413 int argc; 414 char **argv; 415 { 416 char *logfile = TNDLOG; 417 extern char *optarg; 418 int c; 419 420 while ((c = getopt(argc, argv, "d:f:p:n")) != EOF) 421 switch (c) { 422 case 'd': 423 if (isnumber(optarg)) { 424 debugl = atoi(optarg); 425 if (check_debugl(debugl) == -1) 426 debugl = 1; /* default to 1 */ 427 } else { 428 usage(); 429 exit(1); 430 } 431 break; 432 case 'f': 433 logfile = optarg; 434 break; 435 case 'p': 436 if (isnumber(optarg)) { 437 poll_interval = atoi(optarg); 438 if (poll_interval == 0) 439 usage(); 440 } else { 441 usage(); 442 } 443 break; 444 case 'n': 445 delay_poll_flag = 1; 446 break; 447 case '?': 448 usage(); 449 } 450 451 logf = tnlog_open(logfile); 452 } 453 454 static int 455 check_debugl(debug_level) 456 int debug_level; 457 { 458 if (debug_level > MAX_TND_DEBUG) { 459 if ((debugl > 0) && (logf != NULL)) { 460 (void) fprintf(logf, "%s : ", gettime()); 461 (void) fprintf(logf, 462 gettext("invalid debug level: %d, not changed!\n"), 463 debug_level); 464 (void) fflush(logf); 465 } 466 cprint("invalid debug level: %d, not changed!\n", 467 debug_level); 468 return (-1); 469 } 470 return (0); 471 } 472 473 static FILE * 474 tnlog_open(logfile) 475 char *logfile; 476 { 477 FILE *fp; 478 479 if ((fp = fopen(logfile, "a")) == NULL) { 480 syslog(LOG_ERR, "unable to open logfile %s", 481 logfile); 482 exit(-1); 483 } 484 (void) fprintf(fp, "%s : ", gettime()); 485 (void) fprintf(fp, gettext("tnd starting\n")); 486 487 return (fp); 488 } 489 490 static void 491 detachfromtty() 492 { 493 pid_t tnd_pid; 494 495 (void) close(0); 496 (void) close(1); 497 (void) close(2); 498 switch (tnd_pid = fork()) { 499 case (pid_t)-1: 500 if (debugl && (logf != NULL)) { 501 (void) fprintf(logf, "%s : ", gettime()); 502 (void) fprintf(logf, 503 gettext("fork() failed: %s\n"), strerror(errno)); 504 (void) fflush(logf); 505 } 506 cprint("fork() failed: %s\n", strerror(errno)); 507 break; 508 case 0: 509 break; 510 default: 511 if (debugl && (logf != NULL)) { 512 (void) fprintf(logf, "%s : ", gettime()); 513 (void) fprintf(logf, 514 gettext("tnd started. pid= %d\n"), tnd_pid); 515 (void) fflush(logf); 516 } 517 /* 518 * Suspend parent till child signals it. We catch the signal 519 * in order to return correct exit value. 520 */ 521 522 (void) pause(); 523 exit(0); 524 } 525 (void) setsid(); 526 (void) open("/dev/null", O_RDWR, 0); 527 (void) dup(0); 528 (void) dup(0); 529 } 530 531 static void 532 usage() 533 { 534 (void) fprintf(stderr, gettext( 535 "Usage:\n\ttnd [-d debug-level][-f debug-file]" 536 "[-p poll-interval]\n")); 537 538 exit(1); 539 } 540 541 static int 542 isnumber(s) 543 char *s; 544 { 545 register int c; 546 547 /* LINTED */ 548 while (c = *s++) 549 if (!isdigit(c)) 550 return (0); 551 return (1); 552 } 553 554 555 /* 556 * match any entry in any tree 557 * used in tree removal 558 */ 559 /* ARGSUSED */ 560 static int 561 any_compar(const void *v1, const void *v2) 562 { 563 return (0); 564 } 565 566 static int 567 tp_compar(const void *v1, const void *v2) 568 { 569 struct tnd_tnrhtp_c *tp1 = (struct tnd_tnrhtp_c *)v1; 570 struct tnd_tnrhtp_c *tp2 = (struct tnd_tnrhtp_c *)v2; 571 return (strcmp(tp1->tp_ent.name, tp2->tp_ent.name)); 572 } 573 574 /* 575 * Build tree of tp entries, tossing duplicates 576 */ 577 static int 578 nss_get_tp() 579 { 580 tsol_tpent_t tp; /* to store result */ 581 tsol_tpent_t *tpp; 582 struct tnd_tnrhtp_c *new, **old; 583 int count = 0; 584 585 tpp = &tp; 586 587 tsol_settpent(1); 588 589 while ((tpp = (tsol_tpent_t *)tsol_gettpent()) != NULL) { 590 if ((new = (struct tnd_tnrhtp_c *) 591 calloc(1, sizeof (struct tnd_tnrhtp_c))) == NULL) 592 continue; 593 (void) memcpy(&new->tp_ent, tpp, sizeof (tp)); 594 old = (struct tnd_tnrhtp_c **)tsearch(new, &tp_tree, tp_compar); 595 if (*old != new) 596 free(new); 597 else 598 count++; 599 } 600 tsol_endtpent(); 601 602 return (count); 603 } 604 605 /* load tp ents into kernel */ 606 static void 607 load_tp() 608 { 609 twalk(tp_tree, load_tp_entry); 610 } 611 612 613 static void 614 /* LINTED */ 615 load_tp_entry(struct tnd_tnrhtp_c **tppp, VISIT visit, int level) 616 { 617 struct tnd_tnrhtp_c *tpp; 618 619 if (!(visit == postorder || visit == leaf)) 620 return; 621 622 tpp = *tppp; 623 if (tnrhtp(TNDB_LOAD, &tpp->tp_ent)) { 624 if (debugl && (logf != NULL)) { 625 (void) fprintf(logf, "%s : ", gettime()); 626 (void) fprintf(logf, gettext("tnrhtp() failed 0: %s\n"), 627 strerror(errno)); 628 (void) fprintf(logf, 629 gettext("load of remote-host template " 630 "%s into kernel cache failed\n"), 631 tpp->tp_ent.name); 632 (void) fflush(logf); 633 } 634 cprint("tnrhtp() failed here 1: %s\n", strerror(errno)); 635 } 636 } 637 638 static void 639 tp_flush_cache() 640 { 641 struct tnd_tnrhtp_c dummy; 642 struct tnd_tnrhtp_c *tp; 643 644 while (tp = tfind(&dummy, tp_tree, any_compar)) { 645 (void) tdelete(tp, &tp_tree, tp_compar); 646 free(tp); 647 } 648 } 649 650 /* 651 * Build/update the table of rh entries from the 652 * name service sources, files, ldap etc. 653 */ 654 static int 655 nss_get_rh() 656 { 657 int found_entry = 0; 658 int count = 0; 659 int newflag = 0; 660 struct tsol_rhent rh; /* to store result */ 661 struct tsol_rhent *rhp; 662 tsol_tpent_t tp; 663 sa_family_t af; 664 int v6cnt = 0; 665 666 rhp = &rh; 667 668 tsol_setrhent(1); 669 while ((rhp = (struct tsol_rhent *) 670 tsol_getrhent()) != NULL) { 671 /* 672 * Check if this is a known template name 673 * Entries with missing template in kernel will be logged 674 * and not added to cache. 675 */ 676 677 (void) fprintf(logf, gettext("getrhent template name: %s\n"), 678 rhp->rh_template); 679 680 (void) strncpy(tp.name, rhp->rh_template, TNTNAMSIZ - 1); 681 if (tnrhtp(TNDB_GET, &tp) != 0) { 682 if (debugl && (logf != NULL)) 683 (void) fprintf(logf, 684 gettext("Unknown template name: %s\n"), 685 rhp->rh_template); 686 cprint(gettext("Unknown template name: %s\n"), 687 rhp->rh_template); 688 continue; 689 } 690 found_entry++; /* found a valid tnrhdb entry */ 691 af = rhp->rh_address.ta_family; 692 693 if (af == AF_INET) { 694 #ifdef DEBUG 695 (void) fprintf(logf, gettext("nss_get_rh() v4\n")); 696 #endif 697 (void) rw_wrlock(&entire_rwlp); 698 (void) rw_wrlock(&cache_rwlp); 699 700 /* 701 * Both cache table and entire table can be modified 702 * by this function. So, get both locks. 703 */ 704 newflag = rhtable_search_and_update(rhp, 1); 705 706 (void) rw_unlock(&cache_rwlp); 707 (void) rw_unlock(&entire_rwlp); 708 } else if (af == AF_INET6) { 709 #ifdef DEBUG 710 (void) fprintf(logf, gettext("nss_get_rh() v6\n")); 711 #endif 712 v6cnt++; 713 (void) rw_wrlock(&entire_rwlp_v6); 714 (void) rw_wrlock(&cache_rwlp_v6); 715 716 /* 717 * Both cache table and entire table can be modified 718 * by this function. So, get both locks. 719 */ 720 newflag = rhtable_search_and_update_v6(rhp, 1); 721 722 (void) rw_unlock(&cache_rwlp_v6); 723 (void) rw_unlock(&entire_rwlp_v6); 724 } 725 if (newflag) 726 count++; 727 } 728 tsol_endrhent(); 729 730 /* 731 * If the first tsol_getrhent() failed, we bail out and 732 * try again at the next poll interval, just in case the 733 * name service was not reachable the first time. 734 */ 735 if (!found_entry) { 736 #ifdef DEBUG 737 if (logf != NULL) 738 (void) fprintf(logf, 739 gettext("Unable to contact ldap server?\n")); 740 #endif 741 return (count); 742 } 743 744 (void) rw_wrlock(&entire_rwlp); 745 (void) rw_wrlock(&cache_rwlp); 746 /* 747 * Handle deletions in the name service entries 748 * Both cache table and entire table can be modified 749 * by this function. So, get both locks. 750 */ 751 count += handle_unvisited_nodes(); 752 753 (void) rw_unlock(&cache_rwlp); 754 (void) rw_unlock(&entire_rwlp); 755 756 if (v6cnt > 0) { 757 (void) rw_wrlock(&entire_rwlp_v6); 758 (void) rw_wrlock(&cache_rwlp_v6); 759 /* 760 * Handle deletions in the name service entries 761 * Both cache table and entire table can be modified 762 * by this function. So, get both locks. 763 */ 764 count += handle_unvisited_nodes_v6(); 765 766 (void) rw_unlock(&cache_rwlp_v6); 767 (void) rw_unlock(&entire_rwlp_v6); 768 } 769 770 return (count); 771 } 772 773 /* 774 * Check if any deletions in the name service tables 775 * affect the cache entries. We need to do this 776 * in order to not flush the entrie kernel tnrhdb 777 * cache every time we poll the name services. 778 */ 779 static int 780 handle_unvisited_nodes() 781 { 782 int i, j, cnt = 0; 783 tnrh_tlb_t *tlbt; 784 tnd_tnrhdb_t *rhent, *prev; 785 786 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) 787 if ((tlbt = tnrh_cache_table[i]) != NULL) 788 do { 789 if (tlbt->src->visited == 0) { 790 /* 791 * Mark for deletion of both our cache 792 * entry and the kernel cache entry. 793 */ 794 tlbt->reload = TNDB_DELETE; 795 cnt++; 796 } 797 798 tlbt = tlbt->next; 799 } while (tlbt != NULL); 800 801 /* 802 * Remove any unvisited nodes. This can 803 * happen if they are not in use by any cache entry. Then, 804 * mark all nodes in entire_table, un-visited, for next iteration. 805 */ 806 807 for (i = 0; i <= IP_ABITS; i++) { 808 if (tnrh_entire_table[i] == NULL) 809 continue; 810 811 for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) { 812 prev = rhent = tnrh_entire_table[i][j]; 813 814 while (rhent != NULL) { 815 if (rhent->visited == 0) { 816 /* 817 * Check if start node 818 */ 819 if (rhent == tnrh_entire_table[i][j]) { 820 prev = tnrh_entire_table[i][j] = 821 rhent->rh_next; 822 } else { 823 /* bypass the deleted node */ 824 prev->rh_next = rhent->rh_next; 825 prev = prev->rh_next; 826 } 827 828 free(rhent); 829 830 if (prev == NULL) 831 break; 832 else { 833 rhent = prev; 834 continue; 835 } 836 } else 837 rhent->visited = 0; 838 839 prev = rhent; 840 rhent = rhent->rh_next; 841 } 842 } 843 } 844 845 return (cnt); 846 } 847 848 /* 849 * Check if any deletions in the name service tables 850 * affect the cache entries. We need to do this 851 * in order to not flush the entrie kernel tnrhdb 852 * cache every time we poll the name services. 853 */ 854 static int 855 handle_unvisited_nodes_v6() 856 { 857 int i, j, cnt = 0; 858 tnrh_tlb_ipv6_t *tlbt; 859 tnd_tnrhdb_t *rhent, *prev; 860 861 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) 862 if ((tlbt = tnrh_cache_table_v6[i]) != NULL) 863 do { 864 if (tlbt->src->visited == 0) { 865 /* 866 * Mark for deletion of both our cache entry 867 * and the kernel cache entry. 868 */ 869 tlbt->reload = TNDB_DELETE; 870 cnt++; 871 } 872 873 tlbt = tlbt->next; 874 } while (tlbt != NULL); 875 876 /* 877 * Remove any unvisited nodes. This can 878 * happen if they are not in use by any cache entry. Then, 879 * mark all nodes in entire_table, un-visited, for next iteration. 880 */ 881 882 for (i = 0; i <= IPV6_ABITS; i++) { 883 if (tnrh_entire_table_v6[i] == NULL) 884 continue; 885 886 for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) { 887 prev = rhent = tnrh_entire_table_v6[i][j]; 888 889 while (rhent != NULL) { 890 if (rhent->visited == 0) { /* delete the node */ 891 /* Check if start node */ 892 if (rhent == tnrh_entire_table_v6[i][j]) { 893 prev = tnrh_entire_table_v6[i][j] = 894 rhent->rh_next; 895 } else { 896 /* bypass the deleted node */ 897 prev->rh_next = rhent->rh_next; 898 prev = prev->rh_next; 899 } 900 901 free(rhent); 902 if (prev == NULL) 903 break; 904 else { 905 rhent = prev; 906 continue; 907 } 908 } else 909 rhent->visited = 0; 910 911 prev = rhent; 912 rhent = rhent->rh_next; 913 } 914 } 915 } 916 917 return (cnt); 918 } 919 920 921 /* 922 * Search the hash chain for the address. If not found, 923 * add the entry to the hash table. If necessary, 924 * construct the hash table. 925 * If the rh entry is in table, we may update its template name 926 */ 927 static int 928 rhtable_search_and_update(struct tsol_rhent *ent, int duplflag) 929 { 930 struct sockaddr_in *saddrp; 931 unsigned char hash; 932 tnd_tnrhdb_t *rhent; 933 int i; 934 int rflag = 1; 935 936 struct tnd_tnrhdb_c *new; 937 938 saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4; 939 hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr); 940 i = ent->rh_prefix; 941 942 #ifdef DEBUG 943 (void) fprintf(logf, gettext("\trhtable_search_and_update IP address:\ 944 %s\n"), inet_ntoa(saddrp->sin_addr)); 945 #endif 946 947 if (tnrh_entire_table[i] == NULL) { 948 if ((tnrh_entire_table[i] = (tnd_tnrhdb_t **)calloc( 949 TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) { 950 return (0); 951 } 952 } 953 954 rhent = tnrh_entire_table[i][hash]; 955 #ifdef DEBUG 956 (void) fprintf(logf, gettext("\tsearch_and_update i = %d hash = %d\n"), 957 i, hash); 958 if (rhent != NULL) { 959 (void) fprintf(logf, gettext("\trhent visited = %d\n"), 960 rhent->visited); 961 print_entry(&rhent->rh_ent, AF_INET); 962 } else { 963 (void) fprintf(logf, gettext("\tsearch_and_update null\n")); 964 } 965 #endif 966 while (rhent != NULL) { 967 if (rhaddr_compar(saddrp, rhent) == 1) { 968 /* Check if this is a duplicate entry */ 969 if ((rhent->visited == 1) && duplflag) 970 return (0); 971 972 if (duplflag) 973 rhent->visited = 1; 974 975 if (strcmp(ent->rh_template, 976 rhent->rh_ent.rh_template) != 0) { 977 /* 978 * Template is changed in the name service. 979 * Use the new template. 980 */ 981 (void) strcpy(rhent->rh_ent.rh_template, 982 ent->rh_template); 983 /* 984 * Check if this modified entry 985 * affects the cache table. 986 */ 987 rflag = update_cache_table(ent, rhent); 988 return (rflag); 989 } else 990 return (0); 991 } 992 rhent = rhent->rh_next; 993 } 994 995 /* Not found. Add the entry */ 996 new = (struct tnd_tnrhdb_c *)calloc(1, 997 sizeof (struct tnd_tnrhdb_c)); 998 if (new == NULL) 999 return (0); 1000 (void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent)); 1001 if (duplflag) 1002 new->visited = 1; /* Mark all new nodes visited */ 1003 1004 /* linked list. Insert in the beginning */ 1005 new->rh_next = tnrh_entire_table[i][hash]; 1006 tnrh_entire_table[i][hash] = new; 1007 #ifdef DEBUG 1008 (void) fprintf(logf, gettext("rhtable added i = %d, hash = %d\n"), 1009 i, hash); 1010 #endif 1011 1012 /* Check if the new entry affects the cache table */ 1013 rflag = update_cache_table(ent, new); 1014 1015 #ifdef DEBUG 1016 (void) fprintf(logf, gettext("search_and_update rflag=%d\n"), rflag); 1017 #endif 1018 return (rflag); 1019 } 1020 1021 /* 1022 * Search the hash chain for the address. If not found, 1023 * add the entry to the hash table. If necessary, 1024 * construct the hash table. 1025 */ 1026 static int 1027 rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag) 1028 { 1029 struct sockaddr_in6 *saddrp; 1030 unsigned char hash; 1031 tnd_tnrhdb_t *rhent; 1032 int i; 1033 int rflag = 1; 1034 1035 struct tnd_tnrhdb_c *new; 1036 in6_addr_t tmpmask6; 1037 1038 saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6; 1039 i = ent->rh_prefix; 1040 (void) rh_index_to_mask_v6(i, &tmpmask6); 1041 hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr, 1042 tmpmask6); 1043 1044 if (tnrh_entire_table_v6[i] == NULL) { 1045 if ((tnrh_entire_table_v6[i] = (tnd_tnrhdb_t **)calloc( 1046 TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) { 1047 return (0); 1048 } 1049 } 1050 1051 rhent = tnrh_entire_table_v6[i][hash]; 1052 while (rhent != NULL) { 1053 if (rhaddr_compar_v6(saddrp, rhent) == 1) { 1054 /* Check if this is a duplicate entry */ 1055 if ((rhent->visited == 1) && duplflag) 1056 return (0); 1057 1058 if (duplflag) 1059 rhent->visited = 1; 1060 1061 if (strcmp(ent->rh_template, 1062 rhent->rh_ent.rh_template) != 0) { 1063 /* 1064 * Template is changed in the name service. 1065 * Use the new template. 1066 */ 1067 (void) strcpy(rhent->rh_ent.rh_template, 1068 ent->rh_template); 1069 /* 1070 * Check if this modified entry 1071 * affects the cache table. 1072 */ 1073 rflag = update_cache_table_v6(ent, rhent); 1074 return (rflag); 1075 } else 1076 return (0); 1077 } 1078 rhent = rhent->rh_next; 1079 } 1080 1081 /* Not found. Add the entry */ 1082 new = (struct tnd_tnrhdb_c *)calloc(1, sizeof (struct tnd_tnrhdb_c)); 1083 if (new == NULL) 1084 return (0); 1085 (void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent)); 1086 if (duplflag) 1087 new->visited = 1; /* Mark all new nodes visited */ 1088 1089 /* linked list. Insert in the beginning */ 1090 new->rh_next = tnrh_entire_table_v6[i][hash]; 1091 tnrh_entire_table_v6[i][hash] = new; 1092 1093 /* Check if the new entry affects the cache table */ 1094 rflag = update_cache_table_v6(ent, new); 1095 1096 return (rflag); 1097 } 1098 1099 /* 1100 * The array element i points to the hash table. 1101 * Search the hash chain for the address. 1102 */ 1103 static struct tnd_tnrhdb_c * 1104 rhtable_lookup(struct sockaddr_in *saddrp, int i) 1105 { 1106 unsigned char hash; 1107 tnd_tnrhdb_t *rhent; 1108 1109 if (tnrh_entire_table[i] == NULL) 1110 return (NULL); 1111 1112 hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr); 1113 rhent = tnrh_entire_table[i][hash]; 1114 1115 #ifdef DEBUG 1116 (void) fprintf(logf, gettext("rhtable_lookup i = %d, hash = %d\n"), 1117 i, hash); 1118 #endif 1119 1120 while (rhent != NULL) { 1121 #ifdef DEBUG 1122 struct sockaddr_in *saddrp2; 1123 saddrp2 = (struct sockaddr_in *)(&rhent->rh_ent.rh_address.ip_addr_v4); 1124 (void) fprintf(logf, gettext("rhtable_lookup addr = %s, tmpl = %s\n"), 1125 inet_ntoa(saddrp2->sin_addr), rhent->rh_ent.rh_template); 1126 #endif 1127 if (rhaddr_compar_mask(saddrp, rhent, i) == 1) 1128 return (rhent); 1129 rhent = rhent->rh_next; 1130 } 1131 1132 #ifdef DEBUG 1133 (void) fprintf(logf, gettext("\trhtable_lookup failed\n")); 1134 #endif 1135 1136 /* Not found */ 1137 return (NULL); 1138 } 1139 1140 /* 1141 * The array element i points to the hash table. 1142 * Search the hash chain for the address. 1143 */ 1144 static struct tnd_tnrhdb_c * 1145 rhtable_lookup_v6(struct sockaddr_in6 *saddrp, in6_addr_t mask, int i) 1146 { 1147 unsigned char hash; 1148 tnd_tnrhdb_t *rhent; 1149 1150 if (tnrh_entire_table_v6[i] == NULL) 1151 return (NULL); 1152 1153 hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr, mask); 1154 rhent = tnrh_entire_table_v6[i][hash]; 1155 1156 while (rhent != NULL) { 1157 if (rhaddr_compar_mask_v6(saddrp, rhent, i) == 1) 1158 return (rhent); 1159 rhent = rhent->rh_next; 1160 } 1161 1162 /* Not found */ 1163 return (NULL); 1164 } 1165 1166 void 1167 add_cache_entry(in_addr_t addr, char *name, int indx, 1168 tnd_tnrhdb_t *src) 1169 { 1170 unsigned char hash; 1171 tnrh_tlb_t *tlbt; 1172 1173 hash = (unsigned char) get_hashvalue(addr); 1174 1175 /* Look if some other thread already added this entry */ 1176 if (lookup_cache_table(addr) != NULL) 1177 return; 1178 #ifdef DEBUG 1179 (void) fprintf(logf, gettext("\tenter add_cache_entry\n")); 1180 #endif 1181 if ((tlbt = (tnrh_tlb_t *)calloc(1, sizeof (tnrh_tlb_t))) == NULL) 1182 return; 1183 tlbt->addr = addr; 1184 (void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1); 1185 tlbt->masklen_used = indx; 1186 tlbt->reload = TNDB_LOAD; 1187 tlbt->src = src; 1188 1189 #ifdef DEBUG 1190 (void) fprintf(logf, gettext("adding cache entry\n")); 1191 print_tlbt(tlbt); 1192 #endif 1193 /* Add to the chain */ 1194 if (tnrh_cache_table[hash] == NULL) { 1195 tnrh_cache_table[hash] = tlbt; 1196 } else { 1197 /* Add in the beginning */ 1198 tlbt->next = tnrh_cache_table[hash]; 1199 tnrh_cache_table[hash] = tlbt; 1200 } 1201 } 1202 1203 static tnrh_tlb_t * 1204 lookup_cache_table(in_addr_t addr) 1205 { 1206 tnrh_tlb_t *tlbt = NULL; 1207 unsigned char hash; 1208 1209 hash = (unsigned char) get_hashvalue(addr); 1210 tlbt = tnrh_cache_table[hash]; 1211 while (tlbt != NULL) { 1212 if (addr == tlbt->addr) 1213 break; 1214 tlbt = tlbt->next; 1215 } 1216 return (tlbt); 1217 } 1218 1219 static void 1220 add_cache_entry_v6(in6_addr_t addr, char *name, int indx, 1221 tnd_tnrhdb_t *src) 1222 { 1223 unsigned char hash; 1224 tnrh_tlb_ipv6_t *tlbt; 1225 1226 hash = (unsigned char) TNRH_ADDR_HASH_V6(addr); 1227 1228 /* Look if some other thread already added this entry */ 1229 if (lookup_cache_table_v6(addr) != NULL) 1230 return; 1231 1232 if ((tlbt = (tnrh_tlb_ipv6_t *)calloc(1, 1233 sizeof (tnrh_tlb_ipv6_t))) == NULL) 1234 return; 1235 (void) memcpy(&tlbt->addr, &addr, sizeof (in6_addr_t)); 1236 (void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1); 1237 tlbt->masklen_used = indx; 1238 tlbt->reload = TNDB_LOAD; 1239 tlbt->src = src; 1240 1241 /* Add to the chain */ 1242 if (tnrh_cache_table_v6[hash] == NULL) { 1243 tnrh_cache_table_v6[hash] = tlbt; 1244 } else { 1245 /* Add in the beginning */ 1246 tlbt->next = tnrh_cache_table_v6[hash]; 1247 tnrh_cache_table_v6[hash] = tlbt; 1248 } 1249 } 1250 1251 static tnrh_tlb_ipv6_t * 1252 lookup_cache_table_v6(in6_addr_t addr) 1253 { 1254 tnrh_tlb_ipv6_t *tlbt = NULL; 1255 unsigned char hash; 1256 1257 hash = (unsigned char) TNRH_ADDR_HASH_V6(addr); 1258 tlbt = tnrh_cache_table_v6[hash]; 1259 while (tlbt != NULL) { 1260 if (IN6_ARE_ADDR_EQUAL(&addr, &tlbt->addr)) 1261 break; 1262 tlbt = tlbt->next; 1263 } 1264 return (tlbt); 1265 } 1266 1267 1268 /* 1269 * Walk the cache table and check if this IP address/address prefix 1270 * will be a better match for an existing entry in the cache. 1271 * will add cache if not already exists 1272 */ 1273 static int 1274 update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src) 1275 { 1276 int i; 1277 char result[TNTNAMSIZ]; 1278 in_addr_t tmpmask; 1279 in_addr_t addr; 1280 struct sockaddr_in *saddrp; 1281 tnrh_tlb_t *tlbt; 1282 struct tnd_tnrhdb_c *rhp; 1283 int rflag = 0; 1284 1285 saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4; 1286 addr = saddrp->sin_addr.s_addr; 1287 1288 (void) rw_rdlock(&cache_rwlp); 1289 tlbt = lookup_cache_table(addr); 1290 (void) rw_unlock(&cache_rwlp); 1291 1292 if (tlbt == NULL) { 1293 (void) rw_rdlock(&entire_rwlp); 1294 for (i = (IP_MASK_TABLE_SIZE - 1); i >= 0; i--) { 1295 #ifdef DEBUG 1296 (void) fprintf(logf, "update_cache_table i = %d\n", i); 1297 #endif 1298 if (tnrh_entire_table[i] == NULL) 1299 continue; 1300 1301 tmpmask = rh_index_to_mask(i); 1302 saddrp->sin_addr.s_addr &= tmpmask; 1303 #ifdef DEBUG 1304 (void) fprintf(logf, 1305 "update_cache_table found i = %d\n", i); 1306 (void) fprintf(logf, "\ti = %d, tmpmask = 0x%4x\n", 1307 i, tmpmask); 1308 #endif 1309 rhp = (struct tnd_tnrhdb_c *)rhtable_lookup(saddrp, i); 1310 if (rhp != NULL) { 1311 (void) strcpy(result, rhp->rh_ent.rh_template); 1312 /* Add this result to the cache also */ 1313 (void) rw_wrlock(&cache_rwlp); 1314 add_cache_entry(addr, result, i, rhp); 1315 rflag++; 1316 (void) rw_unlock(&cache_rwlp); 1317 break; 1318 } else { 1319 #ifdef DEBUG 1320 (void) fprintf(logf, 1321 "rhtable_lookup return null !!"); 1322 #endif 1323 } 1324 } 1325 (void) rw_unlock(&entire_rwlp); 1326 } 1327 1328 rflag += walk_cache_table(addr, ent->rh_template, ent->rh_prefix, src); 1329 return (rflag); 1330 } 1331 1332 /* 1333 * Walk the cache table and check if this IP address/address prefix 1334 * will be a better match for an existing entry in the cache. 1335 */ 1336 static int 1337 update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src) 1338 { 1339 int i; 1340 char result[TNTNAMSIZ]; 1341 in6_addr_t addr; 1342 struct sockaddr_in6 *saddrp; 1343 tnrh_tlb_ipv6_t *tlbt; 1344 struct tnd_tnrhdb_c *rhp; 1345 in6_addr_t tmpmask6; 1346 int rflag = 0; 1347 1348 saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6; 1349 (void) memcpy(&addr, &saddrp->sin6_addr, sizeof (in6_addr_t)); 1350 1351 /* Look in the cache first */ 1352 (void) rw_rdlock(&cache_rwlp); 1353 tlbt = lookup_cache_table_v6(addr); 1354 (void) rw_unlock(&cache_rwlp); 1355 1356 1357 if (tlbt == NULL) { 1358 (void) rw_rdlock(&entire_rwlp_v6); 1359 for (i = (IPV6_MASK_TABLE_SIZE - 1); i >= 0; i--) { 1360 if (tnrh_entire_table_v6[i] == NULL) 1361 continue; 1362 (void) rh_index_to_mask_v6(i, &tmpmask6); 1363 rhp = (struct tnd_tnrhdb_c *) 1364 rhtable_lookup_v6(saddrp, tmpmask6, i); 1365 if (rhp != NULL) { 1366 (void) strcpy(result, rhp->rh_ent.rh_template); 1367 /* Add this result to the cache also */ 1368 (void) rw_wrlock(&cache_rwlp_v6); 1369 add_cache_entry_v6(addr, result, i, rhp); 1370 rflag++; 1371 (void) rw_unlock(&cache_rwlp_v6); 1372 break; 1373 } 1374 } 1375 (void) rw_unlock(&entire_rwlp_v6); 1376 } 1377 1378 rflag += walk_cache_table_v6(addr, ent->rh_template, 1379 ent->rh_prefix, src); 1380 return (rflag); 1381 } 1382 1383 1384 /* 1385 * Check if this prefix addr will be a better match 1386 * for an existing entry. 1387 */ 1388 static int 1389 is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt) 1390 { 1391 if (tlbt->masklen_used <= indx) { 1392 in_addr_t tmpmask = rh_index_to_mask(indx); 1393 1394 if ((newaddr) == (tlbt->addr & tmpmask)) 1395 return (1); 1396 } 1397 1398 return (0); 1399 } 1400 1401 /* 1402 * Walk the cache table and update entries if needed. 1403 * Mark entries for reload to kernel, if somehow their 1404 * template changed. 1405 * why is_better_match() is called??? 1406 */ 1407 static int 1408 walk_cache_table(in_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src) 1409 { 1410 int i; 1411 tnrh_tlb_t *tlbt; 1412 int rflag = 0; 1413 1414 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1415 tlbt = tnrh_cache_table[i]; 1416 1417 while (tlbt != NULL) { 1418 if (is_better_match(newaddr, indx, tlbt)) { 1419 tlbt->masklen_used = indx; 1420 tlbt->src = src; 1421 /* 1422 * Reload to the kernel only if the 1423 * host type changed. There is no need 1424 * to load, if only the mask used has changed, 1425 * since the kernel does not need that 1426 * information. 1427 */ 1428 if (strcmp(name, tlbt->template_name) != 0) { 1429 (void) strncpy(tlbt->template_name, 1430 name, TNTNAMSIZ-1); 1431 tlbt->reload = TNDB_LOAD; 1432 rflag ++; 1433 } 1434 } 1435 1436 tlbt = tlbt->next; 1437 } 1438 } 1439 #ifdef DEBUG 1440 (void) fprintf(logf, gettext("walk_cache_table rflag=%d\n"), rflag); 1441 #endif 1442 return (rflag); 1443 } 1444 1445 /* 1446 * Check if this prefix addr will be a better match 1447 * for an existing entry. 1448 */ 1449 static int 1450 is_better_match_v6(in6_addr_t newaddr, int indx, tnrh_tlb_ipv6_t *tlbt) 1451 { 1452 in6_addr_t tmpmask; 1453 1454 if (tlbt->masklen_used <= indx) { 1455 (void) rh_index_to_mask_v6(indx, &tmpmask); 1456 1457 if (V6_MASK_EQ(newaddr, tmpmask, tlbt->addr)) 1458 return (1); 1459 } 1460 1461 return (0); 1462 } 1463 1464 1465 /* 1466 * Walk the cache table and update entries if needed. 1467 * Mark entries for reload to kernel, if somehow their 1468 * template changed. 1469 */ 1470 static int 1471 walk_cache_table_v6(in6_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src) 1472 { 1473 int i; 1474 tnrh_tlb_ipv6_t *tlbt; 1475 int rflag = 0; 1476 1477 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1478 tlbt = tnrh_cache_table_v6[i]; 1479 1480 while (tlbt != NULL) { 1481 if (is_better_match_v6(newaddr, indx, tlbt)) { 1482 tlbt->masklen_used = indx; 1483 tlbt->src = src; 1484 /* 1485 * Reload to the kernel only if the 1486 * host type changed. There is no need 1487 * to load, if only the mask used has changed, 1488 * since the kernel does not need that 1489 * information. 1490 */ 1491 if (strcmp(name, tlbt->template_name) != 0) { 1492 (void) strncpy(tlbt->template_name, 1493 name, TNTNAMSIZ-1); 1494 tlbt->reload = TNDB_LOAD; 1495 rflag ++; 1496 } 1497 } 1498 1499 tlbt = tlbt->next; 1500 } 1501 } 1502 1503 return (rflag); 1504 } 1505 1506 /* 1507 * load/delete marked rh ents into kernel 1508 * depending on the reload flag by invoking tnrh(). 1509 * It will mark other entries as TNDB_NOOP 1510 */ 1511 static void 1512 load_rh_marked() 1513 { 1514 int i; 1515 tnrh_tlb_t *tlbt, *prev; 1516 struct tsol_rhent rhentp; 1517 1518 (void) memset((char *)&rhentp, '\0', sizeof (rhentp)); 1519 1520 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1521 1522 prev = tlbt = tnrh_cache_table[i]; 1523 1524 while (tlbt != NULL) { 1525 if ((tlbt->reload == TNDB_LOAD) || 1526 (tlbt->reload == TNDB_DELETE)) { 1527 /* 1528 * We have to call tnrh() with tsol_rhent argument. 1529 * Construct such a struct from the tlbt struct we have. 1530 */ 1531 rhentp.rh_address.ip_addr_v4.sin_addr.s_addr = 1532 tlbt->addr; 1533 rhentp.rh_address.ip_addr_v4.sin_family = 1534 AF_INET; 1535 rhentp.rh_prefix = tlbt->masklen_used; 1536 (void) strcpy(rhentp.rh_template, 1537 tlbt->template_name); 1538 1539 #ifdef DEBUG 1540 (void) fprintf(logf, "load op =%d\n", 1541 tlbt->reload); 1542 print_tlbt(tlbt); 1543 #endif 1544 update_rh_entry(tlbt->reload, &rhentp); 1545 1546 if (tlbt->reload == TNDB_DELETE) { 1547 if (tlbt == tnrh_cache_table[i]) { 1548 tnrh_cache_table[i] = 1549 tlbt->next; 1550 prev = tnrh_cache_table[i]; 1551 } else { 1552 prev->next = tlbt->next; 1553 prev = prev->next; 1554 } 1555 1556 free(tlbt); 1557 if (prev == NULL) 1558 break; 1559 else { 1560 tlbt = prev; 1561 continue; 1562 } 1563 } 1564 tlbt->reload = TNDB_NOOP; 1565 } 1566 1567 prev = tlbt; 1568 tlbt = tlbt->next; 1569 } 1570 } 1571 1572 } 1573 1574 /* load marked rh ents into kernel */ 1575 static void 1576 load_rh_marked_v6() 1577 { 1578 int i; 1579 tnrh_tlb_ipv6_t *tlbt, *prev; 1580 struct tsol_rhent rhentp; 1581 1582 (void) memset((char *)&rhentp, '\0', sizeof (rhentp)); 1583 1584 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1585 prev = tlbt = tnrh_cache_table_v6[i]; 1586 1587 while (tlbt != NULL) { 1588 if ((tlbt->reload == TNDB_LOAD) || 1589 (tlbt->reload == TNDB_DELETE)) { 1590 /* 1591 * We have to call tnrh() with tsol_rhent argument. 1592 * Construct such a struct from the tlbt struct we have. 1593 */ 1594 (void) memcpy(&rhentp.rh_address.ip_addr_v6.sin6_addr, 1595 &tlbt->addr, sizeof (in6_addr_t)); 1596 rhentp.rh_address.ip_addr_v6.sin6_family = AF_INET6; 1597 rhentp.rh_prefix = tlbt->masklen_used; 1598 (void) strcpy(rhentp.rh_template, tlbt->template_name); 1599 1600 update_rh_entry(tlbt->reload, &rhentp); 1601 1602 if (tlbt->reload == TNDB_DELETE) { 1603 if (tlbt == tnrh_cache_table_v6[i]) { 1604 tnrh_cache_table_v6[i] = 1605 tlbt->next; 1606 prev = tnrh_cache_table_v6[i]; 1607 } else { 1608 prev->next = tlbt->next; 1609 prev = prev->next; 1610 } 1611 1612 free(tlbt); 1613 if (prev == NULL) 1614 break; 1615 else { 1616 tlbt = prev; 1617 continue; 1618 } 1619 } 1620 tlbt->reload = TNDB_NOOP; 1621 } 1622 1623 prev = tlbt; 1624 tlbt = tlbt->next; 1625 } 1626 } 1627 1628 } 1629 1630 /* 1631 * Does the real load/delete for the entry depending on op code. 1632 */ 1633 1634 static void 1635 update_rh_entry(int op, struct tsol_rhent *rhentp) 1636 { 1637 #ifdef DEBUG 1638 (void) fprintf(logf, gettext("\t###update_rh_entry op = %d\n"), op); 1639 print_entry(rhentp, AF_INET); 1640 #endif 1641 if (tnrh(op, rhentp) != 0) { 1642 if (debugl && (logf != NULL)) { 1643 (void) fprintf(logf, "%s : ", gettime()); 1644 (void) fprintf(logf, gettext("tnrh() failed: %s\n"), 1645 strerror(errno)); 1646 if (op == TNDB_LOAD) 1647 (void) fprintf(logf, 1648 gettext("load of remote host database " 1649 "%s into kernel cache failed\n"), 1650 rhentp->rh_template); 1651 if (op == TNDB_DELETE) 1652 (void) fprintf(logf, 1653 gettext("delete of remote host database " 1654 "%s from kernel cache failed\n"), 1655 rhentp->rh_template); 1656 (void) fflush(logf); 1657 } 1658 cprint("tnrh() failed..: %s\n", strerror(errno)); 1659 } 1660 } 1661 1662 static void 1663 timer() 1664 { 1665 poll_now(); 1666 (void) alarm(poll_interval); 1667 } 1668 1669 #define max(a, b) ((a) > (b) ? (a) : (b)) 1670 1671 static void 1672 poll_now() 1673 { 1674 1675 (void) fprintf(logf, "enter poll_now at %s \n", gettime()); 1676 (void) fflush(logf); 1677 1678 if (nss_get_tp() > 0) { 1679 load_tp(); 1680 tp_flush_cache(); 1681 } 1682 1683 #ifdef DEBUG 1684 (void) fprintf(logf, "now search for tnrhdb update %s \n", gettime()); 1685 #endif 1686 1687 if (nss_get_rh() > 0) { 1688 if (logf != NULL) { 1689 (void) fprintf(logf, "tnrhdb needs update %s \n", 1690 gettime()); 1691 } 1692 1693 (void) rw_wrlock(&cache_rwlp); 1694 /* This function will cleanup cache table */ 1695 load_rh_marked(); 1696 (void) rw_unlock(&cache_rwlp); 1697 1698 (void) rw_wrlock(&cache_rwlp_v6); 1699 /* This function will cleanup cache table */ 1700 load_rh_marked_v6(); 1701 (void) rw_unlock(&cache_rwlp_v6); 1702 } 1703 1704 #ifdef DEBUG 1705 if (logf != NULL) { 1706 cachetable_print(); 1707 cachetable_print_v6(); 1708 1709 (void) fprintf(logf, "rh table begin\n"); 1710 rhtable_print(); 1711 rhtable_print_v6(); 1712 (void) fprintf(logf, "rh table end \n"); 1713 (void) fprintf(logf, "-------------------------\n\n"); 1714 (void) fflush(logf); 1715 } 1716 #endif 1717 } 1718 1719 static void 1720 tnd_serve() 1721 { 1722 for (;;) { 1723 (void) pause(); 1724 } 1725 } 1726 1727 static void 1728 terminate() 1729 { 1730 if (debugl && (logf != NULL)) { 1731 (void) fprintf(logf, "%s : ", gettime()); 1732 (void) fprintf(logf, gettext("tnd terminating on signal.\n")); 1733 (void) fflush(logf); 1734 } 1735 exit(1); 1736 } 1737 1738 static void 1739 noop() 1740 { 1741 } 1742 1743 static char * 1744 gettime() 1745 { 1746 time_t now; 1747 struct tm *tp, tm; 1748 char *fmt; 1749 1750 (void) time(&now); 1751 tp = localtime(&now); 1752 (void) memcpy(&tm, tp, sizeof (struct tm)); 1753 fmt = nl_langinfo(_DATE_FMT); 1754 1755 (void) strftime(time_buf, _SZ_TIME_BUF, fmt, &tm); 1756 1757 return (time_buf); 1758 } 1759 /* 1760 * debugging routines 1761 */ 1762 1763 1764 #ifdef DEBUG 1765 static void 1766 print_cache_entry(tnrh_tlb_t *tlbt) 1767 { 1768 struct in_addr addr; 1769 1770 addr.s_addr = tlbt->addr; 1771 (void) fprintf(logf, "\tIP address: %s", inet_ntoa(addr)); 1772 (void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name); 1773 (void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used); 1774 } 1775 1776 static void 1777 print_cache_entry_v6(tnrh_tlb_ipv6_t *tlbt) 1778 { 1779 char abuf[INET6_ADDRSTRLEN]; 1780 1781 (void) fprintf(logf, "\tIP address: %s", 1782 inet_ntop(AF_INET6, &tlbt->addr, abuf, sizeof (abuf))); 1783 (void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name); 1784 (void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used); 1785 } 1786 1787 static void 1788 cachetable_print() 1789 { 1790 int i; 1791 tnrh_tlb_t *tlbt; 1792 1793 (void) fprintf(logf, "-------------------------\n"); 1794 (void) fprintf(logf, "Cache table begin\n"); 1795 1796 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1797 if ((tlbt = tnrh_cache_table[i]) != NULL) 1798 print_cache_entry(tlbt); 1799 } 1800 1801 (void) fprintf(logf, "Cache table end \n"); 1802 (void) fprintf(logf, "-------------------------\n\n"); 1803 } 1804 1805 static void 1806 cachetable_print_v6() 1807 { 1808 int i; 1809 tnrh_tlb_ipv6_t *tlbt; 1810 1811 (void) fprintf(logf, "-------------------------\n"); 1812 (void) fprintf(logf, "Cache table begin\n"); 1813 1814 for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) { 1815 if ((tlbt = tnrh_cache_table_v6[i]) != NULL) 1816 print_cache_entry_v6(tlbt); 1817 } 1818 1819 (void) fprintf(logf, "Cache table end \n"); 1820 (void) fprintf(logf, "-------------------------\n\n"); 1821 } 1822 1823 1824 static void 1825 print_entry(tsol_rhent_t *ent, int af) 1826 { 1827 struct sockaddr_in *saddrp; 1828 struct sockaddr_in6 *saddrp6; 1829 char abuf[INET6_ADDRSTRLEN]; 1830 1831 if (af == AF_INET) { 1832 saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4; 1833 (void) fprintf(logf, gettext("\tIP address: %s"), 1834 inet_ntoa(saddrp->sin_addr)); 1835 } else if (af == AF_INET6) { 1836 saddrp6 = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6; 1837 (void) fprintf(logf, gettext("\tIP address: %s"), 1838 inet_ntop(AF_INET6, &saddrp6->sin6_addr, abuf, 1839 sizeof (abuf))); 1840 } 1841 1842 (void) fprintf(logf, 1843 gettext("\tTemplate name: %s"), ent->rh_template); 1844 (void) fprintf(logf, gettext("\tprefix_len: %d\n"), ent->rh_prefix); 1845 (void) fflush(logf); 1846 } 1847 1848 static void 1849 print_tlbt(tnrh_tlb_t *tlbt) 1850 { 1851 (void) fprintf(logf, "tlbt addr = 0x%4x name = %s \ 1852 mask = %u, reload = %d\n", tlbt->addr, tlbt->template_name, 1853 tlbt->masklen_used, tlbt->reload); 1854 } 1855 1856 static void 1857 rhtable_print() 1858 { 1859 rhtable_walk(print_entry); 1860 (void) fprintf(logf, "-----------------------------\n\n"); 1861 } 1862 1863 static void 1864 rhtable_print_v6() 1865 { 1866 rhtable_walk_v6(print_entry); 1867 (void) fprintf(logf, "-----------------------------\n\n"); 1868 } 1869 1870 /* 1871 * Walk through all the entries in tnrh_entire_table[][] 1872 * and execute the function passing the entry as argument. 1873 */ 1874 static void 1875 rhtable_walk(void (*action)()) 1876 { 1877 int i, j; 1878 tnd_tnrhdb_t *rhent; 1879 1880 for (i = 0; i <= IP_ABITS; i++) { 1881 if (tnrh_entire_table[i] == NULL) 1882 continue; 1883 1884 for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) { 1885 rhent = tnrh_entire_table[i][j]; 1886 1887 while (rhent != NULL) { 1888 action(&rhent->rh_ent, AF_INET); 1889 rhent = rhent->rh_next; 1890 } 1891 } 1892 } 1893 } 1894 1895 /* 1896 * Walk through all the entries in tnrh_entire_table_v6[][] 1897 * and execute the function passing the entry as argument. 1898 */ 1899 static void 1900 rhtable_walk_v6(void (*action)()) 1901 { 1902 int i, j; 1903 tnd_tnrhdb_t *rhent; 1904 1905 for (i = 0; i <= IPV6_ABITS; i++) { 1906 if (tnrh_entire_table_v6[i] == NULL) 1907 continue; 1908 1909 for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) { 1910 rhent = tnrh_entire_table_v6[i][j]; 1911 1912 while (rhent != NULL) { 1913 action(&rhent->rh_ent, AF_INET6); 1914 rhent = rhent->rh_next; 1915 } 1916 } 1917 } 1918 } 1919 #endif /* DEBUG */ 1920