diff -urP bind-4.9.11-REL/Makefile bind-4.9.11-ow1/Makefile --- bind-4.9.11-REL/Makefile Wed Oct 23 10:58:01 2002 +++ bind-4.9.11-ow1/Makefile Wed Nov 20 14:20:57 2002 @@ -52,7 +52,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -VER = 4.9.11-REL +VER = 4.9.11-OW1 SHELL = /bin/sh MAKE = make DESTDIR = diff -urP bind-4.9.11-REL/named/Makefile bind-4.9.11-ow1/named/Makefile --- bind-4.9.11-REL/named/Makefile Sun Sep 22 04:13:10 1996 +++ bind-4.9.11-ow1/named/Makefile Wed Nov 20 14:20:57 2002 @@ -107,7 +107,7 @@ db_secure.o db_glue.o \ ns_forw.o ns_init.o ns_main.o ns_maint.o ns_req.o ns_resp.o \ ns_sort.o ns_stats.o ns_validate.o ns_ncache.o \ - storage.o tree.o ns_udp.o + storage.o tree.o ns_udp.o shuffle.o XFERSRCS= named-xfer.c XFEROBJ= named-xfer.o db_glue.o storage.o version.o @@ -148,7 +148,7 @@ chmod +x ndc named-xfer: ${XFEROBJ} ${RES} ${COMPLIB} - ${CC} ${CDEBUG} ${LDFLAGS} -o $@ ${XFEROBJ} \ + ${CC} ${CDEBUG} ${LDFLAGS} -static -o $@ ${XFEROBJ} \ ${RES} ${COMPLIB} ${LIBS} centerline_named: diff -urP bind-4.9.11-REL/named/db_func.h bind-4.9.11-ow1/named/db_func.h --- bind-4.9.11-REL/named/db_func.h Mon Jun 2 00:34:34 1997 +++ bind-4.9.11-ow1/named/db_func.h Wed Nov 20 14:20:57 2002 @@ -15,7 +15,7 @@ /* --from db_update.c-- */ /* ++from db_reload.c++ */ -extern void db_reload __P((void)); +extern void db_reload __P((int)); /* --from db_reload.c-- */ /* ++from db_save.c++ */ diff -urP bind-4.9.11-REL/named/db_load.c bind-4.9.11-ow1/named/db_load.c --- bind-4.9.11-REL/named/db_load.c Mon May 11 08:19:45 1998 +++ bind-4.9.11-ow1/named/db_load.c Wed Nov 20 14:20:57 2002 @@ -690,6 +690,7 @@ if (!getword((char *)buf, sizeof(buf), fp, 0)) goto err; n = strlen((char *)buf); + if (n >= MAXDATA / 8) goto err; *cp++ = n; bcopy(buf, (char *)cp, (int)n); cp += n; @@ -698,6 +699,7 @@ if (!getword((char *)buf, sizeof(buf), fp, 0)) goto err; n = strlen((char *)buf); + if (n >= MAXDATA / 8) goto err; *cp++ = n; bcopy(buf, (char *)cp, (int)n); cp += n; @@ -706,6 +708,7 @@ if (!getword((char *)buf, sizeof(buf), fp, 0)) goto err; n = strlen((char *)buf); + if (n >= MAXDATA / 8) goto err; *cp++ = n; bcopy(buf, (char *)cp, (int)n); cp += n; @@ -713,6 +716,7 @@ /* Replacement */ if (!getword((char *)buf, sizeof(buf), fp, 1)) goto err; + if (strlen(buf) >= MAXDATA / 8) goto err; (void) strcpy((char *)cp, (char *)buf); context = domain_ctx; MAKENAME_OK(cp); diff -urP bind-4.9.11-REL/named/db_reload.c bind-4.9.11-ow1/named/db_reload.c --- bind-4.9.11-REL/named/db_reload.c Tue Aug 27 12:33:23 1996 +++ bind-4.9.11-ow1/named/db_reload.c Wed Nov 20 14:20:57 2002 @@ -72,14 +72,16 @@ * Flush and reload data base. */ void -db_reload() +db_reload(reloadnets) + int reloadnets; { dprintf(3, (ddt, "reload()\n")); syslog(LOG_NOTICE, "reloading nameserver\n"); qflush(); sqflush(NULL); - getnetconf(); + if (reloadnets) + getnetconf(); #ifdef FORCED_RELOAD reloading = 1; /* to force transfer if secondary and backing up */ #endif diff -urP bind-4.9.11-REL/named/named-xfer.c bind-4.9.11-ow1/named/named-xfer.c --- bind-4.9.11-REL/named/named-xfer.c Sun Dec 17 01:54:43 2000 +++ bind-4.9.11-ow1/named/named-xfer.c Wed Nov 20 14:20:57 2002 @@ -214,10 +214,11 @@ #else openlog(ProgName, LOG_PID); #endif + axfr_src.s_addr = 0; #ifdef STUBS - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qS")) != EOF) + while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qSx:")) != EOF) #else - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:q")) != EOF) + while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:")) != EOF) #endif switch (c) { #ifdef GEN_AXFR @@ -281,6 +282,10 @@ case 'q': quiet++; break; + case 'x': + if (!inet_aton(optarg, &axfr_src)) + panic(-1, "bad -x addr"); + break; case '?': default: usage("unrecognized argument"); @@ -484,6 +489,7 @@ #ifdef GEN_AXFR "\t[-C class]\n", #endif + "\t[-x axfr-src]\n", "\tservers...\n", NULL }; @@ -598,15 +604,24 @@ } bufsize = 2 * PACKETSZ; } - bzero((char *)&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = (u_int16_t)port; - sin.sin_addr = zp->z_addr[cnt]; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_INFO, "socket: %m"); error++; break; } + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + if (axfr_src.s_addr != 0) { + sin.sin_port = 0; /* "ANY" */ + sin.sin_addr = axfr_src; + dprintf(2, (ddt, "binding to address [%s]\n", + inet_ntoa(sin.sin_addr))); + if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) + syslog(LOG_INFO, "warning: bind(%s) failed", + inet_ntoa(axfr_src)); + } + sin.sin_port = (u_int16_t)port; + sin.sin_addr = zp->z_addr[cnt]; dprintf(2, (ddt, "connecting to server #%d [%s].%d\n", cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port))); diff -urP bind-4.9.11-REL/named/ns_forw.c bind-4.9.11-ow1/named/ns_forw.c --- bind-4.9.11-REL/named/ns_forw.c Sun Dec 17 01:59:16 2000 +++ bind-4.9.11-ow1/named/ns_forw.c Wed Nov 20 14:20:57 2002 @@ -306,8 +306,6 @@ dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint)); if (sysloginfo && queryname && !haveComplained(queryname, complaint)) { - char buf[999]; - a = ns = (char *)NULL; print_a = (a_rr->d_type == T_A); a_type = p_type(a_rr->d_type); @@ -340,9 +338,9 @@ a = zones[a_rr->d_zone].z_origin; } #endif - /* syslog only takes 5 params */ + /* XXX: syslog only takes 5 params on really broken systems */ if ( a != NULL || ns != NULL) - sprintf(buf, "%s: query(%s) %s (%s:%s) learnt (%s=%s:NS=%s)", + syslog(LOG_INFO, "%s: query(%.64s) %s (%.64s:%s) learnt (%s=%s:NS=%s)", sysloginfo, queryname, complaint, dname, print_a ? @@ -351,12 +349,11 @@ a ? a : "", ns ? ns : "" ); else - sprintf(buf, "%s: query(%s) %s (%s:%s)", + syslog(LOG_INFO, "%s: query(%.64s) %s (%.64s:%s)", sysloginfo, queryname, complaint, dname, print_a ? inet_ntoa(data_inaddr(a_rr->d_data)) : ""); - syslog(LOG_INFO, "%s", buf); } } diff -urP bind-4.9.11-REL/named/ns_glob.h bind-4.9.11-ow1/named/ns_glob.h --- bind-4.9.11-REL/named/ns_glob.h Mon Jun 2 00:34:34 1997 +++ bind-4.9.11-ow1/named/ns_glob.h Wed Nov 20 14:20:57 2002 @@ -195,6 +195,9 @@ DECL char *debugfile INIT(_PATH_DEBUG); #endif + /* default path to named-xfer */ +DECL char *NamedXfer INIT(_PATH_XFER); + #ifdef WANT_PIDFILE /* file to store current named PID */ #ifdef PIDFILE @@ -209,6 +212,9 @@ /* number of zones in use */ DECL int nzones INIT(0); + + /* bind() the axfr socket to this */ +DECL struct in_addr axfr_src INIT({0}); /* true on slave server */ DECL int forward_only INIT(0); diff -urP bind-4.9.11-REL/named/ns_main.c bind-4.9.11-ow1/named/ns_main.c --- bind-4.9.11-REL/named/ns_main.c Sun Dec 17 01:54:43 2000 +++ bind-4.9.11-ow1/named/ns_main.c Wed Nov 20 14:23:33 2002 @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,8 @@ usage() { fprintf(stderr, -"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n"); +"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n" +" [-t directory] [-u username] [-x axfr-src]\n"); exit(1); } @@ -179,7 +181,12 @@ fd_set tmpmask; struct timeval t, *tp; struct qstream *candidate = QSTREAM_NULL; - char **argp; + char **argp, *p; + char *chroot_dir = NULL; + char *user_name = NULL; + uid_t user_id; + gid_t group_id; + struct passwd *pw; #ifdef PID_FIX char oldpid[10]; #endif @@ -193,6 +200,9 @@ struct rlimit rl; #endif + user_id = getuid(); + group_id = getgid(); + local_ns_port = ns_port = htons(NAMESERVER_PORT); /* BSD has a better random number generator but it's not clear @@ -277,12 +287,45 @@ NoRecurse = 1; break; + case 't': + if (--argc <= 0) + usage(); + chroot_dir = savestr(*++argv); + break; + + case 'u': + if (--argc <= 0) + usage(); + user_name = *++argv; + if ((pw = getpwnam(user_name))) { + user_name = savestr(pw->pw_name); + user_id = pw->pw_uid; + group_id = pw->pw_gid; + } else { + fprintf(stderr, + "user \"%s\" unknown\n", + user_name); + exit(1); + } + break; + + case 'x': + --argc; + if (!*++argv || + !inet_aton(*argv, &axfr_src)) { + fprintf(stderr, + "bad -x addr: %s", *argv); + exit(1); + } + break; + default: usage(); } } else bootfile = savestr(*argv); } + endpwent(); #ifdef DEBUG if (!debug) @@ -311,6 +354,39 @@ openlog("named", LOG_PID); #endif + nsid_init(); + + /* + * Chroot if desired. + */ + if (chroot_dir != NULL) { + struct stat sb; + + tzset(); + + if (chroot(chroot_dir) < 0) { + fprintf(stderr, "chroot %s failed: %s\n", chroot_dir, + strerror(errno)); + exit(1); + } + if (chdir("/") < 0) { + fprintf(stderr, "chdir(\"/\") failed: %s\n", + strerror(errno)); + exit(1); + } + /* + * Paths to boot file, pid file and named-xfer may need to + * be relative. This is to allow chroot'ing to the named + * homedir. + */ + if (stat(bootfile, &sb) != 0 && (p = strrchr(bootfile, '/'))) + bootfile = p; + if (stat(PidFile, &sb) != 0 && (p = strrchr(PidFile, '/'))) + PidFile = p; + if (stat(NamedXfer, &sb) != 0 && (p = strrchr(NamedXfer, '/'))) + NamedXfer = p; + } + #ifdef RLIMIT_NOFILE rl.rlim_cur = rl.rlim_max = FD_SETSIZE; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) @@ -339,13 +415,14 @@ #endif /*WANT_PIDFILE*/ syslog(LOG_NOTICE, "starting. %s", Version); + if (chroot_dir != NULL) + syslog(LOG_NOTICE, "chrooted to %s", chroot_dir); _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); nsaddr.sin_family = AF_INET; nsaddr.sin_addr.s_addr = INADDR_ANY; nsaddr.sin_port = local_ns_port; - nsid_init(); /* ** Open stream port. @@ -432,9 +509,10 @@ gettime(&tt); buildservicelist(); buildprotolist(); - ns_init(bootfile); + if (user_name == NULL) + ns_init(bootfile); #ifdef DEBUG - if (debug) { + if (user_name == NULL && debug) { fprintf(ddt, "Network and sort list:\n"); printnetinfo(nettab); } @@ -555,6 +633,30 @@ (void) my_fclose(fp); } #endif + /* + * Set user if desired. + */ + if (user_name != NULL) { + gid_t group_list[2]; + + if (setgid(group_id) != 0) { + syslog(LOG_ERR, "setgid(%d): %m", (int)group_id); + exit(1); + } + group_list[0] = group_list[1] = group_id; + if (setgroups(1, group_list) != 0) { + syslog(LOG_ERR, "setgroups(1, [%d]): %m", + (int)group_id); + exit(1); + } + if (setuid(user_id) != 0) { + syslog(LOG_ERR, "setuid(%s): %m", user_name); + exit(1); + } + syslog(LOG_NOTICE, "user = %s", user_name); + + ns_init(bootfile); + } syslog(LOG_NOTICE, "Ready to answer queries.\n"); prime_cache(); @@ -582,7 +684,7 @@ #endif /* XSTATS */ if (needreload) { needreload = 0; - db_reload(); + db_reload((user_name == NULL)); } if (needStatsDump) { needStatsDump = 0; @@ -1040,6 +1142,7 @@ dqp->dq_addr = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr; dqp->dq_gen = my_generation; + /* XXX - this will fail on reload if we run as non-root */ opensocket(dqp); dprintf(1, (ddt, "listening [%s]\n", inet_ntoa(((struct sockaddr_in *) @@ -1669,21 +1772,20 @@ * allocation scheme to make it a little harder to predict them. Note * that the resolver will need the same protection so the cleverness * should be put there rather than here; this is just an interface layer. + * + * Only put the calls to shuffle_*() in here for now... -- 19991107 SD. */ void nsid_init() { - nsid_state = res_randomid(); + nsid_state = _shuffle_next(); } u_int16_t nsid_next() { - if (nsid_state == 65535) - nsid_state = 0; - else - nsid_state++; + nsid_state = _shuffle_next(); return (nsid_state); } diff -urP bind-4.9.11-REL/named/ns_maint.c bind-4.9.11-ow1/named/ns_maint.c --- bind-4.9.11-REL/named/ns_maint.c Sun Sep 22 04:13:10 1996 +++ bind-4.9.11-ow1/named/ns_maint.c Wed Nov 20 14:20:57 2002 @@ -398,10 +398,11 @@ #ifdef GEN_AXFR char class_str[10]; #endif + char src_str[20]; dprintf(1, (ddt, "startxfer() %s\n", zp->z_origin)); - argv[argc++] = _PATH_XFER; + argv[argc++] = NamedXfer; argv[argc++] = "-z"; argv[argc++] = zp->z_origin; argv[argc++] = "-f"; @@ -409,6 +410,10 @@ argv[argc++] = "-s"; sprintf(serial_str, "%lu", (u_long)zp->z_serial); argv[argc++] = serial_str; + if (axfr_src.s_addr != 0) { + argv[argc++] = "-x"; + argv[argc++] = strcpy(src_str, inet_ntoa(axfr_src)); + } #ifdef GEN_AXFR argv[argc++] = "-C"; sprintf(class_str, "%d", zp->z_class); @@ -489,8 +494,8 @@ if (pid == 0) { /* Child. */ - execv(_PATH_XFER, argv); - syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER); + execv(NamedXfer, argv); + syslog(LOG_ERR, "can't exec %s: %m", NamedXfer); _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ } /* Parent. */ diff -urP bind-4.9.11-REL/named/ns_resp.c bind-4.9.11-ow1/named/ns_resp.c --- bind-4.9.11-REL/named/ns_resp.c Fri Nov 15 12:10:05 2002 +++ bind-4.9.11-ow1/named/ns_resp.c Wed Nov 20 14:20:57 2002 @@ -252,7 +252,7 @@ int buflen; int newmsglen; char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME]; - char msgbuf[MAXDNAME]; + char msgbuf[MAXDNAME+100]; char *dname, tmpdomain[MAXDNAME]; const char *fname; const char *formerrmsg = "brain damage"; diff -urP bind-4.9.11-REL/named/shuffle.c bind-4.9.11-ow1/named/shuffle.c --- bind-4.9.11-REL/named/shuffle.c Thu Jan 1 03:00:00 1970 +++ bind-4.9.11-ow1/named/shuffle.c Wed Nov 20 14:20:57 2002 @@ -0,0 +1,257 @@ +/* + * Written by Solar Designer and placed in the public domain. + */ + +#include +#include + +#ifdef __linux__ +#define DEVICE "/dev/urandom" +#else +#undef DEVICE +#endif + +#if defined(DEVICE) && defined(_LIBC) +#define CONSERVE_KERNEL_RANDOMNESS +#else +#undef CONSERVE_KERNEL_RANDOMNESS +#endif + +#ifdef DEVICE +#include +#endif + +#include +#include +#include +#include + +#ifdef TEST +#include +#endif + +#define DIV 0x8000 + +static unsigned char pool[0x100]; + +static struct { + unsigned int base, xor; + unsigned char s[0x80]; +} seed_c; +static unsigned char seed_f[0x100]; + +static struct { + unsigned int msb; + unsigned int a, b; + unsigned int n; +} state; + +static void pool_update(unsigned int seed) +{ + int i, x; + + srand(seed ^ rand()); + for (i = 0; i < sizeof(pool); i++) { + x = rand(); + pool[i] += (x >> 16) ^ x; + } +} + +#ifdef DEVICE +static int read_loop(int fd, char *buffer, int count) +{ + int offset, block; + + offset = 0; + while (count > 0) { + block = read(fd, &buffer[offset], count); + + if (block < 0) { + if (errno == EINTR) continue; + return block; + } + if (!block) return offset; + + offset += block; + count -= block; + } + + return offset; +} + +static int read_random(char *buffer, int count) +{ + int fd; +#ifdef CONSERVE_KERNEL_RANDOMNESS + unsigned int seed[2]; + + if (count > sizeof(pool)) + return -1; +#endif + + if ((fd = open(DEVICE, O_RDONLY)) < 0) + return -1; + +#ifdef CONSERVE_KERNEL_RANDOMNESS + if (read_loop(fd, (char *)seed, sizeof(seed)) != sizeof(seed)) { + close(fd); + return -1; + } + close(fd); + + memset(pool, 'X', sizeof(pool)); + pool_update(seed[0]); + pool_update(seed[1]); + + memcpy(buffer, pool, count); +#else + count = read_loop(fd, buffer, count); + close(fd); +#endif + + return count; +} +#else +#define read_random(buffer, count) (-1) +#endif + +static void shuffle_init() +{ + struct timeval tv; + + if (read_random((char *)seed_f, sizeof(seed_f)) != sizeof(seed_f)) { + memset(pool, 'X', sizeof(pool)); + pool_update(getpid()); + pool_update(getppid()); + if (!gettimeofday(&tv, NULL)) { + pool_update(tv.tv_sec); + pool_update(tv.tv_usec); + } + + memcpy(seed_f, pool, sizeof(seed_f)); + } + + state.msb = 0; + state.n = DIV; /* force a reseed() */ +} + +static void reseed() +{ + struct tms buf; + + if (read_random((char *)&seed_c, sizeof(seed_c)) != sizeof(seed_c)) { + pool_update(times(&buf)); + pool_update(buf.tms_utime); + pool_update(buf.tms_stime); + + memcpy(&seed_c, pool, sizeof(seed_c)); + } + + seed_c.base &= 0x1fff; + seed_c.base <<= 3; + seed_c.base += DIV + 3; + seed_c.xor &= (DIV - 1); + state.msb ^= 0x8000; + state.a = 1; + state.b = 1; + state.n = 0; +} + +/* + * Now, time for a puzzle. Think of division by DIV in seed_c.base. + * This is not as slow as it might appear: the inner loop needs only + * a few iterations per call, on average. + */ +static unsigned int shuffle_1_next() +{ + if (state.n >= DIV - 1) + reseed(); + + if (state.n && state.b <= state.a) { + do { + state.b = ++state.a; + do { + state.b *= seed_c.base; + state.b %= DIV; + } while (state.b > state.a); + } while (state.a != state.b); + } + + state.b *= seed_c.base; + state.b %= DIV; + state.n++; + + return state.b ^ seed_c.xor; +} + +/* + * The idea behind shuffle_2 is David Wagner's (any bugs are mine, + * of course). + */ +static unsigned int shuffle_2(unsigned int x) +{ + unsigned int i, sum; + + sum = 0; + for (i = 0; i < 8; i++) { + sum += 0x79b9; + x ^= ((unsigned int)seed_c.s[(x ^ sum) & 0x7f]) << 7; + x = ((x & 0xff) << 7) | (x >> 8); + } + + return x; +} + +/* + * A full 16-bit permutation. This one can't be re-seeded, but still + * makes some attacks quite a bit harder. + */ +static unsigned int shuffle_3(unsigned int x) +{ + unsigned int i, sum; + + sum = 0; + for (i = 0; i < 8; i++) { + sum += 0x79b9; + x ^= ((unsigned int)seed_f[(x ^ sum) & 0xff]) << 8; + x = ((x & 0xff) << 8) | (x >> 8); + } + + return x; +} + +unsigned int _shuffle_next() +{ + static int initialized = 0; + unsigned int pid, x; + +/* This isn't MT-safe, but the resolver itself isn't safe, anyway */ + if (!initialized) { + shuffle_init(); + initialized = 1; + } + +/* Make sure the sequence we generate changes after fork() */ + pid = getpid(); + + x = shuffle_1_next(); + x ^= pid & 0x7fff; + x = shuffle_2(x); + x |= state.msb; + x ^= (pid >> 15) & 0xffff; + x = shuffle_3(x); + + return x; +} + +#ifdef TEST +int main() +{ + int i; + + for (i = 0; i < 0xfffe; i++) + printf("%u\n", _shuffle_next()); + + return 0; +} +#endif