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