summaryrefslogtreecommitdiffstats
path: root/usr.sbin/xntpd/xntpd/ntp_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/xntpd/ntp_config.c')
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_config.c1849
1 files changed, 1849 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/xntpd/ntp_config.c b/usr.sbin/xntpd/xntpd/ntp_config.c
new file mode 100644
index 0000000..1a0e9ef
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/ntp_config.c
@@ -0,0 +1,1849 @@
+/* ntp_config.c,v 3.1 1993/07/06 01:11:12 jbj Exp
+ * ntp_config.c - read and apply configuration information
+ */
+#define RESOLVE_INTERNAL /* gdt */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#ifdef RESOLVE_INTERNAL
+#include <sys/time.h>
+#endif
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_filegen.h"
+#include "ntp_stdlib.h"
+
+/*
+ * These routines are used to read the configuration file at
+ * startup time. An entry in the file must fit on a single line.
+ * Entries are processed as multiple tokens separated by white space
+ * Lines are considered terminated when a '#' is encountered. Blank
+ * lines are ignored.
+ */
+
+/*
+ * Configuration file name
+ */
+#ifndef CONFIG_FILE
+#if defined(__bsdi__)
+#define CONFIG_FILE "/usr/local/etc/xntp.conf"
+#else
+#define CONFIG_FILE "/etc/ntp.conf"
+#endif
+#endif /* CONFIG_FILE */
+
+/*
+ * We understand the following configuration entries and defaults.
+ *
+ * peer 128.100.1.1 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * server 128.100.2.2 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * precision -7
+ * broadcast 128.100.224.255 [ version 3 ] [ key 0 ]
+ * broadcastclient yes|no
+ * broadcastdelay 0.0102
+ * authenticate yes|no
+ * monitor yes|no
+ * authdelay 0.00842
+ * pps [ delay 0.000247 ] [ baud 38400 ]
+ * restrict 128.100.100.0 [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery
+ * driftfile file_name
+ * keys file_name
+ * statsdir /var/NTP/
+ * filegen peerstats [ file peerstats ] [ type day ] [ link ]
+ * resolver /path/progname
+ *
+ * And then some. See the manual page.
+ */
+
+/*
+ * Types of entries we understand.
+ */
+#define CONFIG_UNKNOWN 0
+
+#define CONFIG_PEER 1
+#define CONFIG_SERVER 2
+#define CONFIG_PRECISION 3
+#define CONFIG_DRIFTFILE 4
+#define CONFIG_BROADCAST 5
+#define CONFIG_BROADCASTCLIENT 6
+#define CONFIG_AUTHENTICATE 7
+#define CONFIG_KEYS 8
+#define CONFIG_MONITOR 9
+#define CONFIG_AUTHDELAY 10
+#define CONFIG_RESTRICT 11
+#define CONFIG_BDELAY 12
+#define CONFIG_TRUSTEDKEY 13
+#define CONFIG_REQUESTKEY 14
+#define CONFIG_CONTROLKEY 15
+#define CONFIG_TRAP 16
+#define CONFIG_FUDGE 17
+#define CONFIG_MAXSKEW 18
+#define CONFIG_RESOLVER 19
+#define CONFIG_SELECT 20
+#define CONFIG_STATSDIR 21
+#define CONFIG_FILEGEN 22
+#define CONFIG_STATISTICS 23
+#define CONFIG_PPS 24
+#define CONFIG_PIDFILE 25
+#define CONFIG_LOGFILE 26
+
+#define CONF_MOD_VERSION 1
+#define CONF_MOD_KEY 2
+#define CONF_MOD_MINPOLL 3
+#define CONF_MOD_MAXPOLL 4
+#define CONF_MOD_PREFER 5
+
+#define CONF_PPS_DELAY 1
+#define CONF_PPS_BAUD 2
+
+#define CONF_RES_MASK 1
+#define CONF_RES_IGNORE 2
+#define CONF_RES_NOSERVE 3
+#define CONF_RES_NOTRUST 4
+#define CONF_RES_NOQUERY 5
+#define CONF_RES_NOMODIFY 6
+#define CONF_RES_NOPEER 7
+#define CONF_RES_NOTRAP 8
+#define CONF_RES_LPTRAP 9
+#define CONF_RES_NTPPORT 10
+
+#define CONF_TRAP_PORT 1
+#define CONF_TRAP_INTERFACE 2
+
+#define CONF_FDG_TIME1 1
+#define CONF_FDG_TIME2 2
+#define CONF_FDG_VALUE1 3
+#define CONF_FDG_VALUE2 4
+#define CONF_FDG_FLAG1 5
+#define CONF_FDG_FLAG2 6
+#define CONF_FDG_FLAG3 7
+#define CONF_FDG_FLAG4 8
+
+#define CONF_FGEN_FILE 1
+#define CONF_FGEN_TYPE 2
+#define CONF_FGEN_FLAG_LINK 3
+#define CONF_FGEN_FLAG_NOLINK 4
+#define CONF_FGEN_FLAG_ENABLE 5
+#define CONF_FGEN_FLAG_DISABLE 6
+
+#define CONF_BAUD_300 1
+#define CONF_BAUD_600 2
+#define CONF_BAUD_1200 3
+#define CONF_BAUD_2400 4
+#define CONF_BAUD_4800 5
+#define CONF_BAUD_9600 6
+#define CONF_BAUD_19200 7
+#define CONF_BAUD_38400 8
+
+/*
+ * Translation table - keywords to function index
+ */
+struct keyword {
+ char *text;
+ int keytype;
+};
+
+static struct keyword keywords[] = {
+ { "peer", CONFIG_PEER },
+ { "server", CONFIG_SERVER },
+ { "precision", CONFIG_PRECISION },
+ { "driftfile", CONFIG_DRIFTFILE },
+ { "broadcast", CONFIG_BROADCAST },
+ { "broadcastclient", CONFIG_BROADCASTCLIENT },
+ { "authenticate", CONFIG_AUTHENTICATE },
+ { "keys", CONFIG_KEYS },
+ { "monitor", CONFIG_MONITOR },
+ { "authdelay", CONFIG_AUTHDELAY },
+ { "pps", CONFIG_PPS },
+ { "restrict", CONFIG_RESTRICT },
+ { "broadcastdelay", CONFIG_BDELAY },
+ { "trustedkey", CONFIG_TRUSTEDKEY },
+ { "requestkey", CONFIG_REQUESTKEY },
+ { "controlkey", CONFIG_CONTROLKEY },
+ { "trap", CONFIG_TRAP },
+ { "fudge", CONFIG_FUDGE },
+ { "maxskew", CONFIG_MAXSKEW },
+ { "resolver", CONFIG_RESOLVER },
+ { "select", CONFIG_SELECT },
+ { "statsdir", CONFIG_STATSDIR },
+ { "filegen", CONFIG_FILEGEN },
+ { "statistics", CONFIG_STATISTICS },
+ { "pidfile", CONFIG_PIDFILE },
+ { "logfile", CONFIG_LOGFILE },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * Modifier keywords
+ */
+static struct keyword mod_keywords[] = {
+ { "version", CONF_MOD_VERSION },
+ { "key", CONF_MOD_KEY },
+ { "minpoll", CONF_MOD_MINPOLL },
+ { "maxpoll", CONF_MOD_MAXPOLL },
+ { "prefer", CONF_MOD_PREFER },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * PPS modifier keywords
+ */
+static struct keyword pps_keywords[] = {
+ { "delay", CONF_PPS_DELAY },
+ { "baud", CONF_PPS_BAUD },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * Special restrict keywords
+ */
+static struct keyword res_keywords[] = {
+ { "mask", CONF_RES_MASK },
+ { "ignore", CONF_RES_IGNORE },
+ { "noserve", CONF_RES_NOSERVE },
+ { "notrust", CONF_RES_NOTRUST },
+ { "noquery", CONF_RES_NOQUERY },
+ { "nomodify", CONF_RES_NOMODIFY },
+ { "nopeer", CONF_RES_NOPEER },
+ { "notrap", CONF_RES_NOTRAP },
+ { "lowpriotrap", CONF_RES_LPTRAP },
+ { "ntpport", CONF_RES_NTPPORT },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * Baud rate keywords
+ */
+static struct keyword baud_keywords[] = {
+ { "300", CONF_BAUD_300 },
+ { "600", CONF_BAUD_600 },
+ { "1200", CONF_BAUD_1200 },
+ { "2400", CONF_BAUD_2400 },
+ { "4800", CONF_BAUD_4800 },
+ { "9600", CONF_BAUD_9600 },
+ { "19200", CONF_BAUD_19200 },
+ { "38400", CONF_BAUD_38400 },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * Keywords for the trap command
+ */
+static struct keyword trap_keywords[] = {
+ { "port", CONF_TRAP_PORT },
+ { "interface", CONF_TRAP_INTERFACE },
+ { "", CONFIG_UNKNOWN }
+};
+
+
+/*
+ * Keywords for the fudge command
+ */
+static struct keyword fudge_keywords[] = {
+ { "time1", CONF_FDG_TIME1 },
+ { "time2", CONF_FDG_TIME2 },
+ { "value1", CONF_FDG_VALUE1 },
+ { "value2", CONF_FDG_VALUE2 },
+ { "flag1", CONF_FDG_FLAG1 },
+ { "flag2", CONF_FDG_FLAG2 },
+ { "flag3", CONF_FDG_FLAG3 },
+ { "flag4", CONF_FDG_FLAG4 },
+ { "", CONFIG_UNKNOWN }
+};
+
+
+/*
+ * Keywords for the filegen command
+ */
+static struct keyword filegen_keywords[] = {
+ { "file", CONF_FGEN_FILE },
+ { "type", CONF_FGEN_TYPE },
+ { "link", CONF_FGEN_FLAG_LINK },
+ { "nolink", CONF_FGEN_FLAG_NOLINK },
+ { "enable", CONF_FGEN_FLAG_ENABLE },
+ { "disable", CONF_FGEN_FLAG_DISABLE },
+ { "", CONFIG_UNKNOWN }
+};
+
+static struct keyword fgen_types[] = {
+ { "none", FILEGEN_NONE },
+ { "pid", FILEGEN_PID },
+ { "day", FILEGEN_DAY },
+ { "week", FILEGEN_WEEK },
+ { "month", FILEGEN_MONTH },
+ { "year", FILEGEN_YEAR },
+ { "age", FILEGEN_AGE },
+ { "", CONFIG_UNKNOWN}
+};
+
+
+/*
+ * Limits on things
+ */
+#define MAXTOKENS 20 /* 20 tokens on line */
+#define MAXLINE 1024 /* maximum length of line */
+#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */
+
+
+/*
+ * Miscellaneous macros
+ */
+#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
+#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
+#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
+#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+/*
+ * File descriptor used by the resolver save routines, and temporary file
+ * name.
+ */
+static FILE *res_fp;
+static char res_file[20]; /* enough for /tmp/xntpXXXXXX\0 */
+#define RES_TEMPFILE "/tmp/xntpXXXXXX"
+
+/*
+ * Definitions of things either imported from or exported to outside
+ */
+#ifdef DEBUG
+extern int debug;
+#endif
+extern char *FindConfig();
+ char *progname;
+static char *xntp_options = "abc:de:f:k:l:p:r:s:t:";
+
+static int gettokens P((FILE *, char *, char **, int *));
+static int matchkey P((char *, struct keyword *));
+static int getnetnum P((char *, struct sockaddr_in *, int));
+static void save_resolve P((char *, int, int, int, int, int, U_LONG));
+static void do_resolve P((char *, U_LONG, char *));
+#ifdef RESOLVE_INTERNAL
+static void do_resolve_internal P((void));
+#endif /* RESOLVE_INTERNAL */
+static void abort_resolve P((void));
+static RETSIGTYPE catchchild P((int));
+
+/*
+ * getstartup - search through the options looking for a debugging flag
+ */
+void
+getstartup(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef DEBUG
+ int errflg;
+ int c;
+ extern int optind;
+
+ debug = 0; /* no debugging by default */
+
+ /*
+ * This is a big hack. We don't really want to read command line
+ * configuration until everything else is initialized, since
+ * the ability to configure the system may depend on storage
+ * and the like having been initialized. Except that we also
+ * don't want to initialize anything until after detaching from
+ * the terminal, but we won't know to do that until we've
+ * parsed the command line. Do that now, crudely, and do it
+ * again later. Our getopt_l() is explicitly reusable, by the
+ * way. Your own mileage may vary.
+ */
+ errflg = 0;
+ progname = argv[0];
+
+ /*
+ * Decode argument list
+ */
+ while ((c = getopt_l(argc, argv, xntp_options)) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case '?':
+ ++errflg;
+ break;
+ default:
+ break;
+ }
+
+ if (errflg || optind != argc) {
+ (void) fprintf(stderr,
+ "usage: %s [ -bd ] [ -c config_file ]\n", progname);
+ exit(2);
+ }
+ optind = 0; /* reset optind to restart getopt_l */
+
+ if (debug) {
+#ifdef NTP_POSIX_SOURCE
+ static char buf[BUFSIZ];
+ setvbuf(stdout, buf, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(stdout);
+#endif
+ }
+
+#endif /* DEBUG */
+}
+
+/*
+ * getconfig - get command line options and read the configuration file
+ */
+void
+getconfig(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i;
+ int c;
+ int errflg;
+ int peerversion;
+ int minpoll;
+ int maxpoll;
+ U_LONG peerkey;
+ int peerflags;
+ int hmode;
+ struct sockaddr_in peeraddr;
+ struct sockaddr_in maskaddr;
+ FILE *fp;
+ char line[MAXLINE];
+ char *(tokens[MAXTOKENS]);
+ int ntokens;
+ int tok;
+ struct interface *localaddr;
+ char *config_file;
+ struct refclockstat clock;
+ int have_resolver;
+#ifdef RESOLVE_INTERNAL
+ int resolve_internal;
+#endif
+ char resolver_name[MAXFILENAME];
+ int have_keyfile;
+ char keyfile[MAXFILENAME];
+ extern int optind;
+ extern char *optarg;
+ extern U_LONG info_auth_keyid;
+ FILEGEN *filegen;
+
+ /*
+ * Initialize, initialize
+ */
+ errflg = 0;
+#ifdef DEBUG
+ debug = 0;
+#endif /* DEBUG */
+ config_file = CONFIG_FILE;
+ progname = argv[0];
+ res_fp = NULL;
+ have_resolver = have_keyfile = 0;
+
+#ifdef RESOLVE_INTERNAL
+ resolve_internal = 1;
+#endif
+
+ /*
+ * Decode argument list
+ */
+ while ((c = getopt_l(argc, argv, xntp_options)) != EOF) {
+ switch (c) {
+ case 'a':
+ proto_config(PROTO_AUTHENTICATE, (LONG)1);
+ break;
+ case 'b':
+ proto_config(PROTO_BROADCLIENT, (LONG)1);
+ break;
+ case 'c':
+ config_file = optarg;
+ break;
+ case 'd':
+#ifdef DEBUG
+ debug++;
+#else
+ errflg++;
+#endif /* DEBUG */
+ break;
+
+ case 'e':
+ do {
+ l_fp tmp;
+
+ if (!atolfp(optarg, &tmp)) {
+ syslog(LOG_ERR,
+ "command line encryption delay value %s undecodable",
+ optarg);
+ errflg++;
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "command line encryption delay value %s is unlikely",
+ optarg);
+ errflg++;
+ } else {
+ proto_config(PROTO_AUTHDELAY, tmp.l_f);
+ }
+ } while (0);
+ break;
+
+ case 'f':
+ stats_config(STATS_FREQ_FILE, optarg);
+ break;
+
+ case 'k':
+ getauthkeys(optarg);
+ if ((int)strlen(optarg) >= MAXFILENAME) {
+ syslog(LOG_ERR,
+ "key file name too LONG (>%d, sigh), no name resolution possible",
+ MAXFILENAME);
+ } else {
+ have_keyfile = 1;
+ (void)strcpy(keyfile, optarg);
+ }
+ break;
+
+ case 'p':
+ stats_config(STATS_PID_FILE, optarg);
+ break;
+
+ case 'r':
+ do {
+ l_fp tmp;
+
+ if (!atolfp(optarg, &tmp)) {
+ syslog(LOG_ERR,
+ "command line broadcast delay value %s undecodable",
+ optarg);
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "command line broadcast delay value %s is unlikely",
+ optarg);
+ } else {
+ proto_config(PROTO_BROADDELAY, tmp.l_f);
+ }
+ } while (0);
+ break;
+
+ case 's':
+ stats_config(STATS_STATSDIR, optarg);
+ break;
+
+ case 't':
+ do {
+ int tkey;
+
+ tkey = atoi(optarg);
+ if (tkey <= 0 || tkey > NTP_MAXKEY) {
+ syslog(LOG_ERR,
+ "command line trusted key %s is unlikely",
+ optarg);
+ } else {
+ authtrust(tkey, (LONG)1);
+ }
+ } while (0);
+ break;
+
+
+ default:
+ errflg++;
+ break;
+ }
+ }
+
+ if (errflg || optind != argc) {
+ (void) fprintf(stderr,
+ "usage: %s [ -bd ] [ -c config_file ]\n", progname);
+ exit(2);
+ }
+
+ if ((fp = fopen(FindConfig(config_file), "r")) == NULL) {
+ /*
+ * Broadcast clients can sometimes run without
+ * a configuration file.
+ */
+ return;
+ }
+
+ while ((tok = gettokens(fp, line, tokens, &ntokens))
+ != CONFIG_UNKNOWN) {
+ switch(tok) {
+ case CONFIG_PEER:
+ case CONFIG_SERVER:
+ case CONFIG_BROADCAST:
+ if (tok == CONFIG_PEER)
+ hmode = MODE_ACTIVE;
+ else if (tok == CONFIG_SERVER)
+ hmode = MODE_CLIENT;
+ else
+ hmode = MODE_BROADCAST;
+
+ if (ntokens < 2) {
+ syslog(LOG_ERR,
+ "No address for %s, line ignored",
+ tokens[0]);
+ break;
+ }
+
+ if (!getnetnum(tokens[1], &peeraddr, 0)) {
+ errflg = -1;
+ } else {
+ errflg = 0;
+
+ if (
+#ifdef REFCLOCK
+ !ISREFCLOCKADR(&peeraddr) &&
+#endif
+ ISBADADR(&peeraddr)) {
+ syslog(LOG_ERR,
+ "attempt to configure invalid address %s",
+ ntoa(&peeraddr));
+ break;
+ }
+ }
+
+ peerversion = NTP_VERSION;
+ minpoll = NTP_MINDPOLL;
+ maxpoll = NTP_MAXPOLL;
+ peerkey = 0;
+ peerflags = 0;
+ for (i = 2; i < ntokens; i++)
+ switch (matchkey(tokens[i], mod_keywords)) {
+ case CONF_MOD_VERSION:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "peer/server version requires an argument");
+ errflg = 1;
+ break;
+ }
+ peerversion = atoi(tokens[++i]);
+ if ((u_char)peerversion > NTP_VERSION
+ || (u_char)peerversion < NTP_OLDVERSION) {
+ syslog(LOG_ERR,
+ "inappropriate version number %s, line ignored",
+ tokens[i]);
+ errflg = 1;
+ }
+ break;
+
+ case CONF_MOD_KEY:
+ /*
+ * XXX
+ * This is bad because atoi
+ * returns 0 on errors. Do
+ * something later.
+ */
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "key: argument required");
+ errflg = 1;
+ break;
+ }
+ peerkey = (U_LONG)atoi(tokens[++i]);
+ peerflags |= FLAG_AUTHENABLE;
+ break;
+
+ case CONF_MOD_MINPOLL:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "minpoll: argument required");
+ errflg = 1;
+ break;
+ }
+ minpoll = atoi(tokens[++i]);
+ if (minpoll < NTP_MINPOLL)
+ minpoll = NTP_MINPOLL;
+ break;
+
+ case CONF_MOD_MAXPOLL:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "maxpoll: argument required"
+);
+ errflg = 1;
+ break;
+ }
+ maxpoll = atoi(tokens[++i]);
+ if (maxpoll > NTP_MAXPOLL)
+ maxpoll = NTP_MAXPOLL;
+ break;
+
+ case CONF_MOD_PREFER:
+ peerflags |= FLAG_PREFER;
+ break;
+
+ case CONFIG_UNKNOWN:
+ errflg = 1;
+ break;
+ }
+ if (minpoll > maxpoll) {
+ syslog(LOG_ERR, "config error: minpoll > maxpoll");
+ errflg = 1;
+ }
+ if (errflg == 0) {
+ if (peer_config(&peeraddr,
+ (struct interface *)0, hmode, peerversion,
+ minpoll, maxpoll, peerkey, peerflags) == 0) {
+ syslog(LOG_ERR,
+ "configuration of %s failed",
+ ntoa(&peeraddr));
+ }
+ } else if (errflg == -1) {
+ save_resolve(tokens[1], hmode, peerversion,
+ minpoll, maxpoll, peerflags, peerkey);
+ }
+ break;
+
+ case CONFIG_PRECISION:
+ if (ntokens >= 2) {
+ i = atoi(tokens[1]);
+ if (i >= 0 || i < -25)
+ syslog(LOG_ERR,
+ "unlikely precision %s, line ignored",
+ tokens[1]);
+ else
+ proto_config(PROTO_PRECISION, (LONG)i);
+ }
+ break;
+
+ case CONFIG_DRIFTFILE:
+ if (ntokens >= 2)
+ stats_config(STATS_FREQ_FILE, tokens[1]);
+ else
+ stats_config(STATS_FREQ_FILE, (char *)0);
+ break;
+
+ case CONFIG_PIDFILE:
+ if (ntokens >= 2)
+ stats_config(STATS_PID_FILE, tokens[1]);
+ else
+ stats_config(STATS_PID_FILE, (char *)0);
+ break;
+
+ case CONFIG_LOGFILE: {
+#ifdef SYSLOG_FILE
+ extern int syslogit;
+
+ syslogit = 0;
+ if (ntokens >= 2) {
+ FILE *new_file;
+ new_file = fopen(tokens[1], "a");
+ if (new_file != NULL) {
+ if (syslog_file != NULL)
+ (void)fclose(syslog_file);
+ syslog_file = new_file;
+ }
+ else
+ syslog(LOG_ERR,
+ "Cannot open log file %s",
+ tokens[1]);
+ }
+ else
+ syslog(LOG_ERR, "logfile needs one argument");
+
+#else
+ syslog(LOG_ERR, "logging to logfile not compiled into xntpd - logfile \"%s\" ignored", (ntokens == 2) ? tokens[1] : "");
+#endif
+ } break;
+
+ case CONFIG_BROADCASTCLIENT:
+ errflg = 0;
+ if (ntokens >= 2) {
+ if (STREQ(tokens[1], "yes"))
+ proto_config(PROTO_BROADCLIENT, (LONG)1);
+ else if (STREQ(tokens[1], "no"))
+ proto_config(PROTO_BROADCLIENT, (LONG)0);
+ else
+ errflg++;
+ } else {
+ errflg++;
+ }
+
+ if (errflg)
+ syslog(LOG_ERR,
+ "should be `broadcastclient yes|no'");
+ break;
+
+ case CONFIG_AUTHENTICATE:
+ errflg = 0;
+ if (ntokens >= 2) {
+ if (STREQ(tokens[1], "yes"))
+ proto_config(PROTO_AUTHENTICATE, (LONG)1);
+ else if (STREQ(tokens[1], "no"))
+ proto_config(PROTO_AUTHENTICATE, (LONG)0);
+ else
+ errflg++;
+ } else {
+ errflg++;
+ }
+
+ if (errflg)
+ syslog(LOG_ERR,
+ "should be `authenticate yes|no'");
+ break;
+
+ case CONFIG_KEYS:
+ if (ntokens >= 2) {
+ getauthkeys(tokens[1]);
+ if ((int)strlen(tokens[1]) >= MAXFILENAME) {
+ syslog(LOG_ERR,
+ "key file name too LONG (>%d, sigh), no name resolution possible",
+ MAXFILENAME);
+ } else {
+ have_keyfile = 1;
+ (void)strcpy(keyfile, tokens[1]);
+ }
+ }
+ break;
+
+ case CONFIG_MONITOR:
+ errflg = 0;
+ if (ntokens >= 2) {
+ if (STREQ(tokens[1], "yes"))
+ mon_start();
+ else if (STREQ(tokens[1], "no"))
+ mon_stop();
+ else
+ errflg++;
+ } else {
+ errflg++;
+ }
+
+ if (errflg)
+ syslog(LOG_ERR,
+ "should be `monitor yes|no'");
+ break;
+
+ case CONFIG_AUTHDELAY:
+ if (ntokens >= 2) {
+ l_fp tmp;
+
+ if (!atolfp(tokens[1], &tmp)) {
+ syslog(LOG_ERR,
+ "authdelay value %s undecodable",
+ tokens[1]);
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "authdelay value %s is unlikely",
+ tokens[1]);
+ } else {
+ proto_config(PROTO_AUTHDELAY, tmp.l_f);
+ }
+ }
+ break;
+
+ case CONFIG_PPS:
+ for (i = 1 ; i < ntokens ; i++) {
+ switch(matchkey(tokens[i],pps_keywords)) {
+ case CONF_PPS_DELAY:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "pps delay requires an argument");
+ errflg = 1;
+ break;
+ }
+ {
+ l_fp tmp;
+
+ if (!atolfp(tokens[++i],&tmp)) {
+ syslog(LOG_ERR,
+ "pps delay value %s undecodable",
+ tokens[i]);
+ } else {
+ loop_config(LOOP_PPSDELAY, &tmp, 0);
+ }
+ }
+ break;
+ case CONF_PPS_BAUD:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "pps baud requires an argument");
+ errflg = 1;
+ break;
+ }
+ {
+ int tmp;
+
+ if (matchkey(tokens[++i],baud_keywords)) {
+ tmp = atoi(tokens[i]);
+ if (tmp < 19200) {
+ syslog(LOG_WARNING,
+ "pps baud %d unlikely\n", tmp);
+ }
+ loop_config(LOOP_PPSBAUD, NULL, tmp);
+ }
+ }
+ break;
+ case CONFIG_UNKNOWN:
+ errflg = 1;
+ break;
+ }
+ }
+ break;
+
+ case CONFIG_RESTRICT:
+ if (ntokens < 2) {
+ syslog(LOG_ERR, "restrict requires an address");
+ break;
+ }
+ if (STREQ(tokens[1], "default"))
+ peeraddr.sin_addr.s_addr = INADDR_ANY;
+ else if (!getnetnum(tokens[1], &peeraddr, 1))
+ break;
+
+ /*
+ * Use peerversion as flags, peerkey as mflags. Ick.
+ */
+ peerversion = 0;
+ peerkey = 0;
+ errflg = 0;
+ maskaddr.sin_addr.s_addr = ~0;
+ for (i = 2; i < ntokens; i++) {
+ switch (matchkey(tokens[i], res_keywords)) {
+ case CONF_RES_MASK:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "mask keyword needs argument");
+ errflg++;
+ break;
+ }
+ i++;
+ if (!getnetnum(tokens[i], &maskaddr, 1))
+ errflg++;
+ break;
+
+ case CONF_RES_IGNORE:
+ peerversion |= RES_IGNORE;
+ break;
+
+ case CONF_RES_NOSERVE:
+ peerversion |= RES_DONTSERVE;
+ break;
+
+ case CONF_RES_NOTRUST:
+ peerversion |= RES_DONTTRUST;
+ break;
+
+ case CONF_RES_NOQUERY:
+ peerversion |= RES_NOQUERY;
+ break;
+
+ case CONF_RES_NOMODIFY:
+ peerversion |= RES_NOMODIFY;
+ break;
+
+ case CONF_RES_NOPEER:
+ peerversion |= RES_NOPEER;
+ break;
+
+ case CONF_RES_NOTRAP:
+ peerversion |= RES_NOTRAP;
+ break;
+
+ case CONF_RES_LPTRAP:
+ peerversion |= RES_LPTRAP;
+ break;
+
+ case CONF_RES_NTPPORT:
+ peerkey |= RESM_NTPONLY;
+ break;
+
+ case CONFIG_UNKNOWN:
+ errflg++;
+ break;
+ }
+ }
+ if (SRCADR(&peeraddr) == INADDR_ANY)
+ maskaddr.sin_addr.s_addr = 0;
+ if (!errflg)
+ restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
+ (int)peerkey, peerversion);
+ break;
+
+ case CONFIG_BDELAY:
+ if (ntokens >= 2) {
+ l_fp tmp;
+
+ if (!atolfp(tokens[1], &tmp)) {
+ syslog(LOG_ERR,
+ "broadcastdelay value %s undecodable",
+ tokens[1]);
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "broadcastdelay value %s is unlikely",
+ tokens[1]);
+ } else {
+ proto_config(PROTO_BROADDELAY, tmp.l_f);
+ }
+ }
+ break;
+
+ case CONFIG_TRUSTEDKEY:
+ for (i = 1; i < ntokens; i++) {
+ U_LONG tkey;
+
+ tkey = (U_LONG) atoi(tokens[i]);
+ if (tkey == 0) {
+ syslog(LOG_ERR,
+ "trusted key %s unlikely",
+ tokens[i]);
+ } else {
+ authtrust(tkey, 1);
+ }
+ }
+ break;
+
+ case CONFIG_REQUESTKEY:
+ if (ntokens >= 2) {
+ U_LONG rkey;
+
+ if (!atouint(tokens[1], &rkey)) {
+ syslog(LOG_ERR,
+ "%s is undecodeable as request key",
+ tokens[1]);
+ } else if (rkey == 0) {
+ syslog(LOG_ERR,
+ "%s makes a poor request keyid",
+ tokens[1]);
+ } else {
+#ifdef DEBUG
+ if (debug > 3)
+ printf(
+ "set info_auth_key to %lu\n", rkey);
+#endif
+ info_auth_keyid = rkey;
+ }
+ }
+ break;
+
+ case CONFIG_CONTROLKEY:
+ if (ntokens >= 2) {
+ U_LONG ckey;
+ extern U_LONG ctl_auth_keyid;
+
+ ckey = (U_LONG)atoi(tokens[1]);
+ if (ckey == 0) {
+ syslog(LOG_ERR,
+ "%s makes a poor control keyid",
+ tokens[1]);
+ } else {
+ ctl_auth_keyid = ckey;
+ }
+ }
+ break;
+
+ case CONFIG_TRAP:
+ if (ntokens < 2) {
+ syslog(LOG_ERR,
+ "no address for trap command, line ignored");
+ break;
+ }
+ if (!getnetnum(tokens[1], &peeraddr, 1))
+ break;
+
+ /*
+ * Use peerversion for port number. Barf.
+ */
+ errflg = 0;
+ peerversion = 0;
+ localaddr = 0;
+ for (i = 2; i < ntokens-1; i++)
+ switch (matchkey(tokens[i], trap_keywords)) {
+ case CONF_TRAP_PORT:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "trap port requires an argument");
+ errflg = 1;
+ break;
+ }
+ peerversion = atoi(tokens[++i]);
+ if (peerversion <= 0
+ || peerversion > 32767) {
+ syslog(LOG_ERR,
+ "invalid port number %s, trap ignored",
+ tokens[i]);
+ errflg = 1;
+ }
+ break;
+
+ case CONF_TRAP_INTERFACE:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "trap interface requires an argument");
+ errflg = 1;
+ break;
+ }
+
+ if (!getnetnum(tokens[++i],
+ &maskaddr, 1)) {
+ errflg = 1;
+ break;
+ }
+
+ localaddr = findinterface(&maskaddr);
+ if (localaddr == NULL) {
+ syslog(LOG_ERR,
+ "can't find interface with address %s",
+ ntoa(&maskaddr));
+ errflg = 1;
+ }
+ break;
+
+ case CONFIG_UNKNOWN:
+ errflg++;
+ break;
+ }
+
+ if (!errflg) {
+ extern struct interface *any_interface;
+
+ if (peerversion != 0)
+ peeraddr.sin_port = htons(peerversion);
+ else
+ peeraddr.sin_port = htons(TRAPPORT);
+ if (localaddr == NULL)
+ localaddr = any_interface;
+ if (!ctlsettrap(&peeraddr, localaddr, 0,
+ NTP_VERSION))
+ syslog(LOG_ERR,
+ "can't set trap for %s, no resources",
+ ntoa(&peeraddr));
+ }
+ break;
+
+ case CONFIG_FUDGE:
+ if (ntokens < 2) {
+ syslog(LOG_ERR,
+ "no address for fudge command, line ignored");
+ break;
+ }
+ if (!getnetnum(tokens[1], &peeraddr, 1))
+ break;
+
+ if (!ISREFCLOCKADR(&peeraddr)) {
+ syslog(LOG_ERR,
+ "%s is inappropriate address for the fudge command, line ignored",
+ ntoa(&peeraddr));
+ break;
+ }
+
+ bzero((char *)&clock, sizeof clock);
+ errflg = 0;
+ for (i = 2; i < ntokens-1; i++) {
+ switch (c = matchkey(tokens[i],
+ fudge_keywords)) {
+ case CONF_FDG_TIME1:
+ if (!atolfp(tokens[++i],
+ &clock.fudgetime1)) {
+ syslog(LOG_ERR,
+ "fudge %s time1 value in error",
+ ntoa(&peeraddr));
+ errflg = i;
+ break;
+ }
+ clock.haveflags |= CLK_HAVETIME1;
+ break;
+
+ case CONF_FDG_TIME2:
+ if (!atolfp(tokens[++i],
+ &clock.fudgetime2)) {
+ syslog(LOG_ERR,
+ "fudge %s time2 value in error",
+ ntoa(&peeraddr));
+ errflg = i;
+ break;
+ }
+ clock.haveflags |= CLK_HAVETIME2;
+ break;
+
+ case CONF_FDG_VALUE1:
+ if (!atoint(tokens[++i],
+ &clock.fudgeval1)) {
+ syslog(LOG_ERR,
+ "fudge %s value1 value in error",
+ ntoa(&peeraddr));
+ errflg = i;
+ break;
+ }
+ clock.haveflags |= CLK_HAVEVAL1;
+ break;
+
+ case CONF_FDG_VALUE2:
+ if (!atoint(tokens[++i],
+ &clock.fudgeval2)) {
+ syslog(LOG_ERR,
+ "fudge %s value2 value in error",
+ ntoa(&peeraddr));
+ errflg = i;
+ break;
+ }
+ clock.haveflags |= CLK_HAVEVAL2;
+ break;
+
+ case CONF_FDG_FLAG1:
+ case CONF_FDG_FLAG2:
+ case CONF_FDG_FLAG3:
+ case CONF_FDG_FLAG4:
+ if (!atouint(tokens[++i], &peerkey)
+ || peerkey > 1) {
+ syslog(LOG_ERR,
+ "fudge %s flag value in error",
+ ntoa(&peeraddr));
+ errflg = i;
+ break;
+ }
+ switch(c) {
+ case CONF_FDG_FLAG1:
+ c = CLK_FLAG1;
+ clock.haveflags|=CLK_HAVEFLAG1;
+ break;
+ case CONF_FDG_FLAG2:
+ c = CLK_FLAG2;
+ clock.haveflags|=CLK_HAVEFLAG2;
+ break;
+ case CONF_FDG_FLAG3:
+ c = CLK_FLAG3;
+ clock.haveflags|=CLK_HAVEFLAG3;
+ break;
+ case CONF_FDG_FLAG4:
+ c = CLK_FLAG4;
+ clock.haveflags|=CLK_HAVEFLAG4;
+ break;
+ }
+ if (peerkey == 0)
+ clock.flags &= ~c;
+ else
+ clock.flags |= c;
+ break;
+
+ case CONFIG_UNKNOWN:
+ errflg = -1;
+ break;
+ }
+ }
+
+#ifdef REFCLOCK
+ /*
+ * If reference clock support isn't defined the
+ * fudge line will still be accepted and syntax
+ * checked, but will essentially do nothing.
+ */
+ if (!errflg) {
+ refclock_control(&peeraddr, &clock,
+ (struct refclockstat *)0);
+ }
+#endif
+ break;
+
+ case CONFIG_MAXSKEW:
+ if (ntokens >= 2) {
+ l_fp tmp;
+ u_fp utmp;
+
+ if (!atolfp(tokens[1], &tmp)) {
+ syslog(LOG_ERR,
+ "maxskew value %s undecodable",
+ tokens[1]);
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "maxskew value %s is unlikely",
+ tokens[1]);
+ } else {
+ utmp = LFPTOFP(&tmp);
+ proto_config(PROTO_MAXSKEW, (LONG)utmp);
+ }
+ }
+ break;
+
+ case CONFIG_RESOLVER:
+ if (ntokens >= 2) {
+ if (strlen(tokens[1]) >= (size_t)MAXFILENAME) {
+ syslog(LOG_ERR,
+ "resolver path name too LONG (>%d, sigh), no name resolution possible",
+ MAXFILENAME);
+ break;
+ }
+ strcpy(resolver_name, tokens[1]);
+ have_resolver = 1;
+#ifdef RESOLVE_INTERNAL
+ resolve_internal = 0;
+#endif
+ }
+ break;
+
+ case CONFIG_SELECT:
+ if (ntokens >= 2) {
+ i = atoi(tokens[1]);
+ if (i < SELECT_1 || i > SELECT_5)
+ syslog(LOG_ERR,
+ "invalid selection algorithm %s, line ignored",
+ tokens[1]);
+ else
+ proto_config(PROTO_SELECT, (LONG)i);
+ }
+ break;
+
+ case CONFIG_STATSDIR:
+ if (ntokens >= 2) {
+ stats_config(STATS_STATSDIR,tokens[1]);
+ }
+ break;
+
+ case CONFIG_STATISTICS:
+ for (i = 1; i < ntokens; i++) {
+ filegen = filegen_get(tokens[i]);
+
+ if (filegen == NULL) {
+ syslog(LOG_ERR,
+ "no statistics named %s available",
+ tokens[i]);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug > 3)
+ printf("enabling filegen for %s statistics \"%s%s\"\n",
+ tokens[i], filegen->prefix, filegen->basename);
+#endif
+ filegen->flag |= FGEN_FLAG_ENABLED;
+ }
+ break;
+
+ case CONFIG_FILEGEN:
+ if (ntokens < 2) {
+ syslog(LOG_ERR,
+ "no id for filegen command, line ignored");
+ break;
+ }
+
+ filegen = filegen_get(tokens[1]);
+ if (filegen == NULL) {
+ syslog(LOG_ERR,
+ "unknown filegen \"%s\" ignored",
+ tokens[1]);
+ break;
+ }
+ /*
+ * peerversion is (ab)used for filegen file (index)
+ * peerkey is (ab)used for filegen type
+ * peerflags is (ab)used for filegen flags
+ */
+ peerversion = 0;
+ peerkey = filegen->type;
+ peerflags = filegen->flag;
+ errflg = 0;
+
+ for (i = 2; i < ntokens; i++) {
+ switch (matchkey(tokens[i], filegen_keywords)) {
+ case CONF_FGEN_FILE:
+ if (i >= ntokens - 1) {
+ syslog(LOG_ERR,
+ "filegen %s file requires argument",
+ tokens[1]);
+ errflg = i;
+ break;
+ }
+ peerversion = ++i;
+ break;
+ case CONF_FGEN_TYPE:
+ if (i >= ntokens -1) {
+ syslog(LOG_ERR,
+ "filegen %s type requires argument",
+ tokens[1]);
+ errflg = i;
+ break;
+ }
+ peerkey = matchkey(tokens[++i], fgen_types);
+ if (peerkey == CONFIG_UNKNOWN) {
+ syslog(LOG_ERR,
+ "filegen %s unknown type \"%s\"",
+ tokens[1], tokens[i]);
+ errflg = i;
+ break;
+ }
+ break;
+
+ case CONF_FGEN_FLAG_LINK:
+ peerflags |= FGEN_FLAG_LINK;
+ break;
+
+ case CONF_FGEN_FLAG_NOLINK:
+ peerflags &= ~FGEN_FLAG_LINK;
+ break;
+
+ case CONF_FGEN_FLAG_ENABLE:
+ peerflags |= FGEN_FLAG_ENABLED;
+ break;
+
+ case CONF_FGEN_FLAG_DISABLE:
+ peerflags &= ~FGEN_FLAG_ENABLED;
+ break;
+ }
+ }
+ if (!errflg) {
+ filegen_config(filegen, tokens[peerversion],
+ (u_char)peerkey, (u_char)peerflags);
+ }
+ break;
+
+ }
+ }
+ (void) fclose(fp);
+
+ if (res_fp != NULL) {
+ /*
+ * Need name resolution
+ */
+ errflg = 0;
+#ifdef RESOLVE_INTERNAL
+ if ( resolve_internal )
+ do_resolve_internal();
+ else
+ {
+#endif
+
+ if (info_auth_keyid == 0) {
+ syslog(LOG_ERR,
+ "no request key defined, peer name resolution not possible");
+ errflg++;
+ }
+ if (!have_resolver) {
+ syslog(LOG_ERR,
+ "no resolver defined, peer name resolution not possible");
+ errflg++;
+ }
+ if (!have_keyfile) {
+ syslog(LOG_ERR,
+ "no key file specified, peer name resolution not possible");
+ errflg++;
+ }
+
+ if (!errflg)
+
+ do_resolve(resolver_name, info_auth_keyid, keyfile);
+ else
+ abort_resolve();
+#ifdef RESOLVE_INTERNAL
+ }
+#endif
+ }
+}
+
+
+
+/*
+ * gettokens - read a line and return tokens
+ */
+static int
+gettokens(fp, line, tokenlist, ntokens)
+ FILE *fp;
+ char *line;
+ char **tokenlist;
+ int *ntokens;
+{
+ register char *cp;
+ register int eol;
+ register int ntok;
+
+ /*
+ * Find start of first token
+ */
+again:
+ while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
+ cp = line;
+ while (ISSPACE(*cp))
+ cp++;
+ if (!ISEOL(*cp))
+ break;
+ }
+ if (cp == NULL) {
+ *ntokens = 0;
+ return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
+ }
+
+ /*
+ * Now separate out the tokens
+ */
+ eol = 0;
+ ntok = 0;
+ while (!eol) {
+ tokenlist[ntok++] = cp;
+ while (!ISEOL(*cp) && !ISSPACE(*cp))
+ cp++;
+ if (ISEOL(*cp)) {
+ *cp = '\0';
+ eol = 1;
+ } else { /* must be space */
+ *cp++ = '\0';
+ while (ISSPACE(*cp))
+ cp++;
+ if (ISEOL(*cp))
+ eol = 1;
+ }
+ if (ntok == MAXTOKENS)
+ eol = 1;
+ }
+
+ /*
+ * Return the match
+ */
+ *ntokens = ntok;
+ ntok = matchkey(tokenlist[0], keywords);
+ if (ntok == CONFIG_UNKNOWN)
+ goto again;
+ return ntok;
+}
+
+
+
+/*
+ * matchkey - match a keyword to a list
+ */
+static int
+matchkey(word, keys)
+ register char *word;
+ register struct keyword *keys;
+{
+ for (;;) {
+ if (keys->keytype == CONFIG_UNKNOWN) {
+ syslog(LOG_ERR,
+ "configure: keyword \"%s\" unknown, line ignored",
+ word);
+ return CONFIG_UNKNOWN;
+ }
+ if (STRSAME(word, keys->text))
+ return keys->keytype;
+ keys++;
+ }
+}
+
+
+/*
+ * getnetnum - return a net number (this is crude, but careful)
+ */
+static int
+getnetnum(num, addr, complain)
+ char *num;
+ struct sockaddr_in *addr;
+ int complain;
+{
+ register char *cp;
+ register char *bp;
+ register int i;
+ register int temp;
+ char buf[80]; /* will core dump on really stupid stuff */
+ U_LONG netnum;
+
+/* XXX ELIMINATE replace with decodenetnum */
+ cp = num;
+ netnum = 0;
+ for (i = 0; i < 4; i++) {
+ bp = buf;
+ while (isdigit(*cp))
+ *bp++ = *cp++;
+ if (bp == buf)
+ break;
+
+ if (i < 3) {
+ if (*cp++ != '.')
+ break;
+ } else if (*cp != '\0')
+ break;
+
+ *bp = '\0';
+ temp = atoi(buf);
+ if (temp > 255)
+ break;
+ netnum <<= 8;
+ netnum += temp;
+#ifdef DEBUG
+ if (debug > 3)
+ printf("getnetnum %s step %d buf %s temp %d netnum %d\n",
+ num, i, buf, temp, netnum);
+#endif
+ }
+
+ if (i < 4) {
+ if (complain)
+ syslog(LOG_ERR,
+ "configure: \"%s\" not valid host number, line ignored",
+ num);
+#ifdef DEBUG
+ if (debug > 3)
+ printf(
+ "configure: \"%s\" not valid host number, line ignored\n",
+ num);
+#endif
+ return 0;
+ }
+
+ /*
+ * make up socket address. Clear it out for neatness.
+ */
+ bzero((char *)addr, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(NTP_PORT);
+ addr->sin_addr.s_addr = htonl(netnum);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("getnetnum given %s, got %s (%x)\n",
+ num, ntoa(addr), netnum);
+#endif
+ return 1;
+}
+
+
+/*
+ * catchchild - receive the resolver's exit status
+ */
+static RETSIGTYPE
+catchchild(sig)
+int sig;
+{
+ /*
+ * We only start up one child, and if we're here
+ * it should have already exited. Hence the following
+ * shouldn't hang. If it does, please tell me.
+ */
+ (void) wait(0);
+}
+
+
+/*
+ * save_resolve - save configuration info into a file for later name resolution
+ */
+static void
+save_resolve(name, mode, version, minpoll, maxpoll, flags, keyid)
+ char *name;
+ int mode;
+ int version;
+ int minpoll;
+ int maxpoll;
+ int flags;
+ U_LONG keyid;
+{
+ if (res_fp == NULL) {
+ (void) strcpy(res_file, RES_TEMPFILE);
+ (void) mktemp(res_file);
+ res_fp = fopen(res_file, "w");
+ if (res_fp == NULL) {
+ syslog(LOG_ERR, "open failed for %s: %m", res_file);
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ if (debug) {
+ printf("resolving %s\n", name);
+ }
+#endif
+
+ (void) fprintf(res_fp, "%s %d %d %d %d %d %lu\n", name, mode,
+ version, minpoll, maxpoll, flags, keyid);
+}
+
+
+/*
+ * abort_resolve - terminate the resolver stuff and delete the file
+ */
+static void
+abort_resolve()
+{
+ /*
+ * In an ideal world we would might reread the file and
+ * log the hosts which aren't getting configured. Since
+ * this is too much work, however, just close and delete
+ * the temp file.
+ */
+ if (res_fp != NULL)
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ (void) unlink(res_file);
+}
+
+
+/*
+ * do_resolve - start up the resolver program
+ */
+static void
+do_resolve(program, auth_keyid, keyfile)
+ char *program;
+ U_LONG auth_keyid;
+ char *keyfile;
+{
+ register LONG i;
+ register char **ap;
+ /* 1 progname + 5 -d's + 1 -r + keyid + keyfile + tempfile + 1 */
+ char *argv[15];
+ char numbuf[15];
+ /*
+ * Clean environment so the resolver is consistant
+ */
+ static char *resenv[] = {
+ "HOME=/",
+ "SHELL=/bin/sh",
+ "TERM=dumb",
+ "USER=root",
+ NULL
+ };
+
+ if (res_fp == NULL) {
+ /* belch */
+ syslog(LOG_ERR, "internal error in do_resolve: res_fp == NULL");
+ exit(1);
+ }
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ ap = argv;
+ *ap++ = program;
+
+ /*
+ * xntpres [-d ...] -r key# keyfile tempfile
+ */
+#ifdef DEBUG
+ i = debug;
+ if (i > 5)
+ i = 5;
+ while (i-- > 0)
+ *ap++ = "-d";
+#endif
+ *ap++ = "-r";
+
+ (void) sprintf(numbuf, "%lu", auth_keyid);
+ *ap++ = numbuf;
+ *ap++ = keyfile;
+ *ap++ = res_file;
+ *ap = NULL;
+
+ (void) signal_no_reset(SIGCHLD, catchchild);
+
+ i = fork();
+ if (i == 0) {
+ /*
+ * In child here, close up all descriptors and
+ * exec the resolver program. Close the syslog()
+ * facility gracefully in case we must reopen it.
+ */
+ (void) signal(SIGCHLD, SIG_DFL);
+ closelog();
+#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD)
+ i = sysconf(_SC_OPEN_MAX);
+#else
+ i = getdtablesize();
+#endif
+#ifdef DEBUG
+ while (i-- > 2)
+#else
+ while (i-- > 0)
+#endif
+ (void) close(i);
+ (void) execve(program, argv, resenv);
+
+ /*
+ * If we got here, the exec screwed up. Open the log file
+ * and print something so we don't die without complaint
+ */
+#ifndef LOG_DAEMON
+ openlog("xntpd", LOG_PID);
+#else
+#ifndef LOG_NTP
+#define LOG_NTP LOG_DAEMON
+#endif
+ openlog("xntpd", LOG_PID | LOG_NDELAY, LOG_NTP);
+#endif /* LOG_DAEMON */
+ syslog(LOG_ERR, "exec of resolver %s failed!", program);
+ abort_resolve();
+ exit(1);
+ }
+
+ if (i == -1) {
+ syslog(LOG_ERR, "fork() failed, can't start %s", program);
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+ abort_resolve();
+ }
+}
+
+
+#ifdef RESOLVE_INTERNAL
+
+#define KEY_TYPE_ASCII 3
+
+/*
+ * do_resolve_internal - start up the resolver function (not program)
+ */
+static void
+do_resolve_internal()
+{
+ int i;
+
+ extern U_LONG req_keyid; /* request keyid */
+ extern char *req_file; /* name of the file with configuration info */
+ extern U_LONG info_auth_keyid;
+
+ if (res_fp == NULL) {
+ /* belch */
+ syslog(LOG_ERR, "internal error in do_resolve_internal: res_fp == NULL");
+ exit(1);
+ }
+
+ /* we are done with this now */
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ /* find a keyid */
+ if (info_auth_keyid == 0)
+ req_keyid = 65535;
+ else
+ req_keyid = info_auth_keyid;
+
+ /* if doesn't exist, make up one at random */
+ if ( ! authhavekey(req_keyid) )
+ {
+ char rankey[9];
+ struct timeval now;
+
+ /* generate random key */
+ GETTIMEOFDAY(&now, (struct timezone *)0);
+ srand(now.tv_sec * now.tv_usec);
+
+ for ( i = 0; i < 8; i++ )
+ rankey[i] = (rand() % 255) + 1;
+ rankey[8] = 0;
+
+ authusekey(req_keyid, KEY_TYPE_ASCII, rankey);
+ }
+
+ /* save keyid so we will accept config requests with it */
+ info_auth_keyid = req_keyid;
+
+ req_file = res_file; /* set up pointer to res file */
+
+ (void) signal_no_reset(SIGCHLD, catchchild);
+
+ i = fork();
+ if (i == 0) {
+ /* this used to close everything
+ * I don't think this is necessary */
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+
+ ntp_intres();
+
+ /*
+ * If we got here, the intres code screwed up.
+ * Print something so we don't die without complaint
+ */
+ syslog(LOG_ERR, "call to ntp_intres lost");
+ abort_resolve();
+ exit(1);
+ }
+
+ if (i == -1) {
+ syslog(LOG_ERR, "fork() failed, can't start ntp_intres");
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+ abort_resolve();
+ }
+}
+#endif
OpenPOWER on IntegriCloud