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