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
main(int argc,char ** argv)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
rhaddr_compar_mask(struct sockaddr_in * tp1,struct tnd_tnrhdb_c * tp2,int i)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
rhaddr_compar(struct sockaddr_in * tp1,struct tnd_tnrhdb_c * tp2)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
rhaddr_compar_mask_v6(struct sockaddr_in6 * tp1,struct tnd_tnrhdb_c * tp2,int i)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
rhaddr_compar_v6(struct sockaddr_in6 * tp1,struct tnd_tnrhdb_c * tp2)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
get_hashvalue(in_addr_t addr)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
rh_index_to_mask(uint_t masklen)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 *
rh_index_to_mask_v6(uint_t masklen,in6_addr_t * bitmask)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
parse_opts(argc,argv)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
check_debugl(debug_level)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 *
tnlog_open(logfile)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
detachfromtty()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
usage()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
isnumber(s)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
any_compar(const void * v1,const void * v2)561 any_compar(const void *v1, const void *v2)
562 {
563 return (0);
564 }
565
566 static int
tp_compar(const void * v1,const void * v2)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
nss_get_tp()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
load_tp()607 load_tp()
608 {
609 twalk(tp_tree, load_tp_entry);
610 }
611
612
613 static void
614 /* LINTED */
load_tp_entry(struct tnd_tnrhtp_c ** tppp,VISIT visit,int level)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
tp_flush_cache()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
nss_get_rh()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
handle_unvisited_nodes()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
handle_unvisited_nodes_v6()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
rhtable_search_and_update(struct tsol_rhent * ent,int duplflag)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
rhtable_search_and_update_v6(struct tsol_rhent * ent,int duplflag)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 *
rhtable_lookup(struct sockaddr_in * saddrp,int i)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 *
rhtable_lookup_v6(struct sockaddr_in6 * saddrp,in6_addr_t mask,int i)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
add_cache_entry(in_addr_t addr,char * name,int indx,tnd_tnrhdb_t * src)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 *
lookup_cache_table(in_addr_t addr)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
add_cache_entry_v6(in6_addr_t addr,char * name,int indx,tnd_tnrhdb_t * src)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 *
lookup_cache_table_v6(in6_addr_t addr)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
update_cache_table(tsol_rhent_t * ent,tnd_tnrhdb_t * src)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
update_cache_table_v6(tsol_rhent_t * ent,tnd_tnrhdb_t * src)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
is_better_match(in_addr_t newaddr,int indx,tnrh_tlb_t * tlbt)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
walk_cache_table(in_addr_t newaddr,char * name,int indx,tnd_tnrhdb_t * src)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
is_better_match_v6(in6_addr_t newaddr,int indx,tnrh_tlb_ipv6_t * tlbt)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
walk_cache_table_v6(in6_addr_t newaddr,char * name,int indx,tnd_tnrhdb_t * src)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
load_rh_marked()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
load_rh_marked_v6()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
update_rh_entry(int op,struct tsol_rhent * rhentp)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
timer()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
poll_now()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
tnd_serve()1720 tnd_serve()
1721 {
1722 for (;;) {
1723 (void) pause();
1724 }
1725 }
1726
1727 static void
terminate()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
noop()1739 noop()
1740 {
1741 }
1742
1743 static char *
gettime()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
print_cache_entry(tnrh_tlb_t * tlbt)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
print_cache_entry_v6(tnrh_tlb_ipv6_t * tlbt)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
cachetable_print()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
cachetable_print_v6()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
print_entry(tsol_rhent_t * ent,int af)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
print_tlbt(tnrh_tlb_t * tlbt)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
rhtable_print()1857 rhtable_print()
1858 {
1859 rhtable_walk(print_entry);
1860 (void) fprintf(logf, "-----------------------------\n\n");
1861 }
1862
1863 static void
rhtable_print_v6()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
rhtable_walk(void (* action)())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
rhtable_walk_v6(void (* action)())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