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