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