xref: /titanic_51/usr/src/cmd/tsol/tnd/tnd.c (revision 4c36ab8840d241bee6c7f9b5c69205a9ffbd66dd)
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