Added missing cleandir line for shared libs.
[unix-history] / usr.sbin / named / ns_init.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1986, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/socket.h>
40#include <sys/time.h>
41#include <sys/stat.h>
42#include <netinet/in.h>
43#include <arpa/nameser.h>
44#include <syslog.h>
45#include <signal.h>
46#include <resolv.h>
47#include <stdio.h>
48#include <errno.h>
49#include <ctype.h>
50#include <string.h>
51#undef nsaddr
52#include "pathnames.h"
53#include "ns.h"
54#include "db.h"
55
56struct zoneinfo *zones; /* zone information */
57int nzones; /* number of zones in use */
58int forward_only = 0; /* run only as a slave */
59char *cache_file;
60char *localdomain; /* "default" for non-dotted names */
61int maint_interval = 15*60; /* minimum ns_maint() interval */
62
63extern int lineno;
64
65
66/*
67 * Read boot file for configuration info.
68 */
69
70ns_init(bootfile)
71 char *bootfile;
72{
73 register struct zoneinfo *zp;
74 struct zoneinfo *find_zone();
75 char buf[BUFSIZ], obuf[BUFSIZ], *source;
76 extern char *calloc();
77 FILE *fp;
78 int type;
79 extern int needmaint;
80 struct stat f_time;
81 static int loads = 0; /* number of times loaded */
82 static int tmpnum = 0; /* unique number for tmp zone files */
83#ifdef ALLOW_UPDATES
84 char *cp, *flag;
85#endif
86
87#ifdef DEBUG
88 if (debug)
89 fprintf(ddt,"\nns_init(%s)\n", bootfile);
90#endif
91 gettime(&tt);
92
93 if ((fp = fopen(bootfile, "r")) == NULL) {
94 syslog(LOG_ERR, "%s: %m", bootfile);
95 exit(1);
96 }
97 lineno = 0;
98 if (loads == 0) {
99 if ((zones =
100 (struct zoneinfo *)calloc(64, sizeof(struct zoneinfo)))
101 == NULL) {
102 syslog(LOG_ERR,
103 "Not enough memory to allocate initial zones array");
104 exit(1);
105 }
106 nzones = 1; /* zone zero is cache data */
107 /* allocate cache hash table, formerly the root hash table. */
108 hashtab = savehash((struct hashbuf *)NULL);
109
110 /* allocate root-hints/file-cache hash table */
111 fcachetab = savehash((struct hashbuf *)NULL);
112 /* init zone data */
113 zones[0].z_type = Z_CACHE;
114 } else {
115 /* Mark previous zones as not yet found in boot file. */
116 for (zp = &zones[1]; zp < &zones[nzones]; zp++)
117 zp->z_state &= ~Z_FOUND;
118 if (localdomain)
119 free(localdomain);
120 localdomain = NULL;
121 free_forwarders();
122 forward_only = 0;
123 }
124
125#ifdef DEBUG
126 if (debug >= 3) {
127 fprintf(ddt,"\n content of zones before loading \n");
128 content_zone(nzones - 1);
129 }
130#endif
131 while (!feof(fp) && !ferror(fp)) {
132 if (!getword(buf, sizeof(buf), fp))
133 continue;
134 /* read named.boot keyword and process args */
135 if (strcasecmp(buf, "directory") == 0) {
136 (void) getword(buf, sizeof(buf), fp);
137 if (chdir(buf) < 0) {
138 syslog(LOG_CRIT, "directory %s: %m\n",
139 buf);
140 exit(1);
141 }
142 continue;
143 } else if (strcasecmp(buf, "sortlist") == 0) {
144 get_sort_list(fp);
145 continue;
146 } else if (strcasecmp(buf, "forwarders") == 0) {
147 get_forwarders(fp);
148 continue;
149 } else if (strcasecmp(buf, "slave") == 0) {
150 forward_only++;
151 endline(fp);
152 continue;
153 } else if (strcasecmp(buf, "domain") == 0) {
154 if (getword(buf, sizeof(buf), fp))
155 localdomain = savestr(buf);
156 endline(fp);
157 continue;
158 } else if (strcasecmp(buf, "cache") == 0)
159 type = Z_CACHE;
160 else if (strcasecmp(buf, "primary") == 0)
161 type = Z_PRIMARY;
162 else if (strcasecmp(buf, "secondary") == 0)
163 type = Z_SECONDARY;
164 else {
165 syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
166 bootfile, lineno, buf);
167 endline(fp);
168 continue;
169 }
170
171 /*
172 * read zone origin
173 */
174 if (!getword(obuf, sizeof(obuf), fp)) {
175 syslog(LOG_ERR, "%s: line %d: missing origin\n",
176 bootfile, lineno);
177 continue;
178 }
179#ifdef DEBUG
180 if (debug)
181 fprintf(ddt, "zone origin %s", obuf);
182#endif
183 if (obuf[0] == '.' && obuf[1] == '\0')
184 obuf[0] = '\0';
185 /*
186 * read source file or host address
187 */
188 if (!getword(buf, sizeof(buf), fp)) {
189 syslog(LOG_ERR,
190 "%s: line %d: missing source or addr\n",
191 bootfile, lineno);
192 continue;
193 }
194
195 /* check for previous instance of this zone (reload) */
196 if ((zp = find_zone(obuf, type)) == 0) {
197 if (type == Z_CACHE) {
198 zp = &zones[0];
199 zp->z_origin = "";
200 goto gotzone;
201 }
202 for (zp = &zones[1]; zp < &zones[nzones]; zp++)
203 if (zp->z_type == 0)
204 goto gotzone;
205 /*
206 * this code assume that nzones never decreases
207 */
208 if (nzones % 64 == 0) {
209#ifdef DEBUG
210 if (debug > 1)
211 fprintf(ddt, "Reallocating zones structure\n");
212#endif DEBUG
213 /*
214 * Realloc() not used since it might damage zones
215 * if an error occurs
216 */
217 if ((zp = (struct zoneinfo *)
218 malloc((64 + nzones) * sizeof(struct zoneinfo)))
219 == NULL) {
220 syslog(LOG_ERR, "no memory for more zones");
221#ifdef DEBUG
222 if (debug)
223 fprintf(ddt,
224 "Out of memory for new zones\n");
225#endif DEBUG
226 endline(fp);
227 continue;
228 }
229 bcopy((char *)zones, (char *)zp,
230 nzones * sizeof(struct zoneinfo));
231 bzero((char *)&zp[nzones],
232 64 * sizeof(struct zoneinfo));
233 free(zones);
234 zones = zp;
235 }
236 zp = &zones[nzones++];
237 gotzone:
238 zp->z_origin = savestr(obuf);
239 zp->z_type = type;
240 }
241 zp->z_addrcnt = 0;
242
243 switch (type) {
244 case Z_CACHE:
245 source = savestr(buf);
246#ifdef DEBUG
247 if (debug)
248 fprintf(ddt,", source = %s\n", source);
249#endif
250 zp->z_refresh = 0; /* by default, no dumping */
251 if (getword(buf, sizeof(buf), fp)) {
252#ifdef notyet
253 zp->z_refresh = atoi(buf);
254 if (zp->z_refresh <= 0) {
255 syslog(LOG_ERR,
256 "%s: line %d: bad refresh time '%s', ignored\n",
257 bootfile, lineno, buf);
258 zp->z_refresh = 0;
259 } else if (cache_file == NULL)
260 cache_file = source;
261#else
262 syslog(LOG_WARNING,
263 "%s: line %d: cache refresh ignored\n",
264 bootfile, lineno);
265#endif
266 endline(fp);
267 }
268 /*
269 * If we've loaded this file, and the file has
270 * not been modified and contains no $include,
271 * then there's no need to reload.
272 */
273 if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
274 (zp->z_state & Z_INCLUDE) == 0 &&
275 stat(zp->z_source, &f_time) == 0 &&
276 zp->z_ftime == f_time.st_mtime) {
277#ifdef DEBUG
278 if (debug)
279 fprintf(ddt, "cache is up to date\n");
280#endif
281 break; /* zone is already up to date */
282 }
283
284 /* file has changed, or hasn't been loaded yet */
285 if (zp->z_source) {
286 free(zp->z_source);
287 remove_zone(fcachetab, 0);
288 }
289 zp->z_source = source;
290#ifdef DEBUG
291 if (debug)
292 fprintf(ddt, "reloading zone\n");
293#endif
294 (void) db_load(zp->z_source, zp->z_origin, zp, 0);
295 break;
296
297 case Z_PRIMARY:
298 source = savestr(buf);
299#ifdef ALLOW_UPDATES
300 if (getword(buf, sizeof(buf), fp)) {
301 endline(fp);
302 flag = buf;
303 while (flag) {
304 cp = index(flag, ',');
305 if (cp)
306 *cp++ = 0;
307 if (strcasecmp(flag, "dynamic") == 0)
308 zp->z_state |= Z_DYNAMIC;
309 else if (strcasecmp(flag, "addonly") == 0)
310 zp->z_state |= Z_DYNADDONLY;
311 else {
312 syslog(LOG_ERR,
313 "%s: line %d: bad flag '%s'\n",
314 bootfile, lineno, flag);
315 }
316 flag = cp;
317 }
318 }
319#else ALLOW_UPDATES
320 endline(fp);
321#endif
322
323#ifdef DEBUG
324 if (debug)
325 fprintf(ddt,", source = %s\n", source);
326#endif
327 /*
328 * If we've loaded this file, and the file has
329 * not been modified and contains no $include,
330 * then there's no need to reload.
331 */
332 if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
333 (zp->z_state & Z_INCLUDE) == 0 &&
334 stat(zp->z_source, &f_time) == 0 &&
335 zp->z_ftime == f_time.st_mtime) {
336#ifdef DEBUG
337 if (debug)
338 fprintf(ddt, "zone is up to date\n");
339#endif
340 break; /* zone is already up to date */
341 }
342 if (zp->z_source) {
343 free(zp->z_source);
344 remove_zone(hashtab, zp - zones);
345 }
346 zp->z_source = source;
347 zp->z_auth = 0;
348#ifdef DEBUG
349 if (debug)
350 fprintf(ddt, "reloading zone\n");
351#endif
352 if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
353 zp->z_auth = 1;
354#ifdef ALLOW_UPDATES
355 /* Guarantee calls to ns_maint() */
356 zp->z_refresh = maint_interval;
357#else ALLOW_UPDATES
358 zp->z_refresh = 0; /* no maintenance needed */
359 zp->z_time = 0;
360#endif ALLOW_UPDATES
361 break;
362
363 case Z_SECONDARY:
364 source = 0;
365#ifdef DEBUG
366 if (debug)
367 fprintf(ddt,"\n\taddrs: ");
368#endif
369 do {
370 zp->z_addr[zp->z_addrcnt].s_addr =
371 inet_addr(buf);
372 if (zp->z_addr[zp->z_addrcnt].s_addr ==
373 (u_long)-1) {
374 source = savestr(buf);
375 endline(fp);
376 break;
377 }
378#ifdef DEBUG
379 if (debug)
380 fprintf(ddt,"%s, ",buf);
381#endif
382 if (++zp->z_addrcnt > NSMAX - 1) {
383 zp->z_addrcnt = NSMAX - 1;
384#ifdef DEBUG
385 if (debug)
386 fprintf(ddt,
387 "\nns.h NSMAX reached\n");
388#endif
389 }
390 } while (getword(buf, sizeof(buf), fp));
391#ifdef DEBUG
392 if (debug)
393 fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt);
394#endif
395 if (source == 0) {
396 /*
397 * We will always transfer this zone again
398 * after a reload.
399 */
400 sprintf(buf, "/%s/NsTmp%d", _PATH_TMPDIR,
401 tmpnum++);
402 source = savestr(buf);
403 zp->z_state |= Z_TMP_FILE;
404 } else
405 zp->z_state &= ~Z_TMP_FILE;
406 /*
407 * If we had a backup file name, and it was changed,
408 * free old zone and start over. If we don't have
409 * current zone contents, try again now in case
410 * we have a new server on the list.
411 */
412 if (zp->z_source && strcmp(source, zp->z_source)) {
413#ifdef DEBUG
414 if (debug)
415 fprintf(ddt,"backup file changed\n");
416#endif
417 free(zp->z_source);
418 zp->z_source = 0;
419 zp->z_auth = 0;
420 zp->z_serial = 0; /* force xfer */
421 remove_zone(hashtab, zp - zones);
422 }
423 if (zp->z_source)
424 free(source);
425 else
426 zp->z_source = source;
427 if (zp->z_auth == 0)
428 zoneinit(zp);
429 break;
430
431 }
432 zp->z_state |= Z_FOUND;
433#ifdef DEBUG
434 if (debug)
435 fprintf(ddt,"zone[%d] type %d: '%s'",
436 zp-zones, type,
437 *(zp->z_origin) == '\0' ? "." : zp->z_origin);
438#endif
439 if (zp->z_refresh && zp->z_time == 0)
440 zp->z_time = zp->z_refresh + tt.tv_sec;
441 if (zp->z_time <= tt.tv_sec)
442 needmaint = 1;
443#ifdef DEBUG
444 if (debug)
445 fprintf(ddt, " z_time %d, z_refresh %d\n",
446 zp->z_time, zp->z_refresh);
447#endif
448 }
449 (void) fclose(fp);
450 /* erase all old zones that were not found */
451 for (zp = &zones[1]; zp < &zones[nzones]; zp++)
452 if (zp->z_type && (zp->z_state & Z_FOUND) == 0) {
453 remove_zone(hashtab, zp - zones);
454 bzero((char *) zp, sizeof(*zp));
455#ifdef DEBUG
456 if(debug >=2)
457 fprintf(ddt,"\n zone no %d was removed \n", zp - zones);
458#endif
459 }
460#ifdef DEBUG
461 if(debug >= 2) {
462 fprintf(ddt,"\n content of zones after loading \n");
463 content_zone(nzones-1);
464 }
465#endif
466
467 /*
468 * Schedule calls to ns_maint().
469 */
470 if (needmaint == 0)
471 sched_maint();
472#ifdef DEBUG
473 if (debug)
474 fprintf(ddt,"exit ns_init()%s\n", needmaint ?
475 ", need maintenance immediately" : "");
476#endif
477 loads++;
478}
479
480zoneinit(zp)
481 register struct zoneinfo *zp;
482{
483 extern int needmaint;
484 struct stat sb;
485
486 /*
487 * Try to load zone from backup file,
488 * if one was specified and it exists.
489 * If not, or if the data are out of date,
490 * we will refresh the zone from a primary
491 * immediately.
492 */
493 if (zp->z_source == NULL)
494 return;
495 if (stat(zp->z_source, &sb) == -1 ||
496 db_load(zp->z_source, zp->z_origin, zp, 0) != 0) {
497 /*
498 * Set zone to be refreshed immediately.
499 */
500 zp->z_refresh = INIT_REFRESH;
501 zp->z_retry = INIT_REFRESH;
502 zp->z_time = tt.tv_sec;
503 needmaint = 1;
504 } else
505 zp->z_auth = 1;
506}
507
508#ifdef ALLOW_UPDATES
509/*
510 * Look for the authoritative zone with the longest matching RHS of dname
511 * and return its zone # or zero if not found.
512 */
513findzone(dname, class)
514 char *dname;
515 int class;
516{
517 char *dZoneName, *zoneName, *index();
518 int dZoneNameLen, zoneNameLen;
519 int maxMatchLen = 0;
520 int maxMatchZoneNum = 0;
521 int zoneNum;
522
523#ifdef DEBUG
524 if (debug >= 4)
525 fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class);
526 if (debug >= 5) {
527 fprintf(ddt, "zone dump:\n");
528 for (zoneNum = 1; zoneNum < nzones; zoneNum++)
529 printzoneinfo(zoneNum);
530 }
531#endif DEBUG
532
533 dZoneName = index(dname, '.');
534 if (dZoneName == NULL)
535 dZoneName = ""; /* root */
536 else
537 dZoneName++; /* There is a '.' in dname, so use remainder of
538 string as the zone name */
539 dZoneNameLen = strlen(dZoneName);
540 for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
541 zoneName = (zones[zoneNum]).z_origin;
542 zoneNameLen = strlen(zoneName);
543 /* The zone name may or may not end with a '.' */
544 if (zoneName[zoneNameLen - 1] == '.')
545 zoneNameLen--;
546 if (dZoneNameLen != zoneNameLen)
547 continue;
548#ifdef DEBUG
549 if (debug >= 5)
550 fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n",
551 dZoneName, zoneName, dZoneNameLen);
552#endif
553 if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
554#ifdef DEBUG
555 if (debug >= 5)
556 fprintf(ddt, "match\n");
557#endif
558 /*
559 * See if this is as long a match as any so far.
560 * Check if "<=" instead of just "<" so that if
561 * root domain (whose name length is 0) matches,
562 * we use it's zone number instead of just 0
563 */
564 if (maxMatchLen <= zoneNameLen) {
565 maxMatchZoneNum = zoneNum;
566 maxMatchLen = zoneNameLen;
567 }
568 }
569#ifdef DEBUG
570 else
571 if (debug >= 5)
572 fprintf(ddt, "no match\n");
573#endif
574 }
575#ifdef DEBUG
576 if (debug >= 4)
577 fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum);
578#endif DEBUG
579 return (maxMatchZoneNum);
580}
581#endif ALLOW_UPDATES
582
583soa_zinfo(zp, cp, eom)
584 register struct zoneinfo *zp;
585 register u_char *cp;
586 u_char *eom;
587{
588 cp += 3 * sizeof(u_short);
589 cp += sizeof(u_long);
590 cp += dn_skipname(cp, eom);
591 cp += dn_skipname(cp, eom);
592 GETLONG(zp->z_serial, cp);
593 GETLONG(zp->z_refresh, cp);
594 gettime(&tt);
595 zp->z_time = tt.tv_sec + zp->z_refresh;
596 GETLONG(zp->z_retry, cp);
597 GETLONG(zp->z_expire, cp);
598 GETLONG(zp->z_minimum, cp);
599}
600
601get_forwarders(fp)
602 FILE *fp;
603{
604 char buf[BUFSIZ];
605 register struct fwdinfo *fip = NULL, *ftp = NULL;
606 extern struct sockaddr_in nsaddr;
607 extern struct fwdinfo *fwdtab;
608
609#ifdef DEBUG
610 if (debug)
611 fprintf(ddt,"forwarders ");
612#endif
613
614 /* on mulitple forwarder lines, move to end of the list */
615 if (fwdtab != NULL)
616 for (fip = fwdtab; fip->next != NULL; fip = fip->next)
617 ;
618
619 while (getword(buf, sizeof(buf), fp)) {
620 if (strlen(buf) == 0)
621 break;
622#ifdef DEBUG
623 if (debug)
624 fprintf(ddt," %s",buf);
625#endif
626 if (ftp == NULL)
627 ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
628 if (isdigit(buf[0]) &&
629 (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf)) !=
630 (u_long)-1) {
631 ftp->fwdaddr.sin_port = nsaddr.sin_port;
632 ftp->fwdaddr.sin_family = AF_INET;
633 } else {
634 syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf);
635#ifdef DEBUG
636 if (debug)
637 fprintf(ddt," (ignored, NOT dotted quad)");
638#endif
639 continue;
640 }
641 ftp->next = NULL;
642 if (fwdtab == NULL)
643 fwdtab = ftp; /* First time only */
644 else
645 fip->next = ftp;
646 fip = ftp;
647 ftp = NULL;
648 }
649 if (ftp)
650 free((char *)ftp);
651
652#ifdef DEBUG
653 if (debug)
654 fprintf(ddt,"\n");
655 if (debug > 2)
656 for (ftp = fwdtab; ftp != NULL; ftp = ftp->next)
657 fprintf(ddt,"ftp x%x %s next x%x\n", ftp,
658 inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next);
659#endif
660}
661
662free_forwarders()
663{
664 extern struct fwdinfo *fwdtab;
665 register struct fwdinfo *ftp, *fnext;
666
667 for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
668 fnext = ftp->next;
669 free((char *)ftp);
670 }
671 fwdtab = NULL;
672}
673
674struct zoneinfo *
675find_zone(name, type)
676 char *name;
677 int type;
678{
679 register struct zoneinfo *zp;
680
681 for (zp = &zones[1]; zp < &zones[nzones]; zp++)
682 if (zp->z_type == type && strcasecmp(name, zp->z_origin) == 0) {
683#ifdef DEBUG
684 if (debug > 1)
685 fprintf(ddt, ", old zone (%d)", zp - zones);
686#endif
687 return (zp);
688 }
689#ifdef DEBUG
690 if(debug > 1)
691 fprintf(ddt, ", new zone");
692#endif
693 return ((struct zoneinfo *)NULL);
694}
695
696/* prints out the content of zones */
697content_zone(end)
698 int end;
699{
700 int i;
701 for (i = 1; i <= end; i++)
702 printzoneinfo(i);
703}