diff options
Diffstat (limited to 'contrib/ntp/ntpdate/ntptime_config.c')
-rw-r--r-- | contrib/ntp/ntpdate/ntptime_config.c | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/contrib/ntp/ntpdate/ntptime_config.c b/contrib/ntp/ntpdate/ntptime_config.c new file mode 100644 index 0000000..56f6539 --- /dev/null +++ b/contrib/ntp/ntpdate/ntptime_config.c @@ -0,0 +1,557 @@ +/* + * ntptime_config.c + * + * What follows is a simplified version of the config parsing code + * in ntpd/ntp_config.c. We only parse a subset of the configuration + * syntax, and don't bother whining about things we don't understand. + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <sys/time.h> + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntpdate.h" +#include "ntp_syslog.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 +# ifndef SYS_WINNT +# define CONFIG_FILE "/etc/ntp.conf" +# else /* SYS_WINNT */ +# define CONFIG_FILE "%windir%\\ntp.conf" +# define ALT_CONFIG_FILE "%windir%\\ntp.ini" +# endif /* SYS_WINNT */ +#endif /* not CONFIG_FILE */ + +/* + * + * We understand the following configuration entries and defaults. + * + * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * keys file_name + */ + +#define CONFIG_UNKNOWN 0 + +#define CONFIG_PEER 1 +#define CONFIG_SERVER 2 +#define CONFIG_KEYS 8 + +#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_MOD_BURST 6 +#define CONF_MOD_SKEY 7 +#define CONF_MOD_TTL 8 +#define CONF_MOD_MODE 9 + +/* + * Translation table - keywords to function index + */ +struct keyword { + const char *text; + int keytype; +}; + +/* + * Command keywords + */ +static struct keyword keywords[] = { + { "peer", CONFIG_PEER }, + { "server", CONFIG_SERVER }, + { "keys", CONFIG_KEYS }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "peer", "server", "broadcast" 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 }, + { "burst", CONF_MOD_BURST }, + { "autokey", CONF_MOD_SKEY }, + { "mode", CONF_MOD_MODE }, /* reference clocks */ + { "ttl", CONF_MOD_TTL }, /* NTP peers */ + { "", 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) + +/* + * Systemwide parameters and flags + */ +extern struct server **sys_servers; /* the server list */ +extern int sys_numservers; /* number of servers to poll */ +extern char *key_file; + +/* + * Function prototypes + */ +static int gettokens P((FILE *, char *, char **, int *)); +static int matchkey P((char *, struct keyword *)); +static int getnetnum P((const char *num, struct sockaddr_in *addr, + int complain)); + + +/* + * loadservers - load list of NTP servers from configuration file + */ +void +loadservers( + char *cfgpath + ) +{ + register int i; + int errflg; + int peerversion; + int minpoll; + int maxpoll; + /* int ttl; */ + int srvcnt; + /* u_long peerkey; */ + int peerflags; + struct sockaddr_in peeraddr; + FILE *fp; + char line[MAXLINE]; + char *(tokens[MAXTOKENS]); + int ntokens; + int tok; + const char *config_file; +#ifdef SYS_WINNT + char *alt_config_file; + LPTSTR temp; + char config_file_storage[MAX_PATH]; + char alt_config_file_storage[MAX_PATH]; +#endif /* SYS_WINNT */ + struct server *server, *srvlist; + + /* + * Initialize, initialize + */ + srvcnt = 0; + srvlist = 0; + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ +#ifndef SYS_WINNT + config_file = cfgpath ? cfgpath : CONFIG_FILE; +#else + if (cfgpath) { + config_file = cfgpath; + } else { + temp = CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); + exit(1); + } + config_file = config_file_storage; + } + + temp = ALT_CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); + exit(1); + } + alt_config_file = alt_config_file_storage; +M +#endif /* SYS_WINNT */ + + if ((fp = fopen(FindConfig(config_file), "r")) == NULL) + { + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); +#ifdef SYS_WINNT + /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ + + if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { + + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); + return; + } +#else /* not SYS_WINNT */ + return; +#endif /* not SYS_WINNT */ + } + + while ((tok = gettokens(fp, line, tokens, &ntokens)) + != CONFIG_UNKNOWN) { + switch(tok) { + case CONFIG_PEER: + case CONFIG_SERVER: + + if (ntokens < 2) { + msyslog(LOG_ERR, + "No address for %s, line ignored", + tokens[0]); + break; + } + + if (!getnetnum(tokens[1], &peeraddr, 1)) { + /* Resolve now, or lose! */ + break; + } else { + errflg = 0; + + /* Shouldn't be able to specify multicast */ + if (IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr)) + || ISBADADR(&peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + } + + peerversion = NTP_VERSION; + minpoll = NTP_MINDPOLL; + maxpoll = NTP_MAXDPOLL; + /* peerkey = 0; */ + peerflags = 0; + /* ttl = 0; */ + for (i = 2; i < ntokens; i++) + switch (matchkey(tokens[i], mod_keywords)) { + case CONF_MOD_VERSION: + if (i >= ntokens-1) { + msyslog(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) { + msyslog(LOG_ERR, + "inappropriate version number %s, line ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_MOD_KEY: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "key: argument required"); + errflg = 1; + break; + } + ++i; + /* peerkey = (int)atol(tokens[i]); */ + peerflags |= FLAG_AUTHENABLE; + break; + + case CONF_MOD_MINPOLL: + if (i >= ntokens-1) { + msyslog(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) { + msyslog(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 CONF_MOD_BURST: + peerflags |= FLAG_BURST; + break; + + case CONF_MOD_SKEY: + peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; + break; + + case CONF_MOD_TTL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "ttl: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONF_MOD_MODE: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "mode: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + if (minpoll > maxpoll) { + msyslog(LOG_ERR, "config error: minpoll > maxpoll"); + errflg = 1; + } + if (errflg == 0) { + server = (struct server *)emalloc(sizeof(struct server)); + memset((char *)server, 0, sizeof(struct server)); + server->srcadr = peeraddr; + server->version = peerversion; + server->dispersion = PEER_MAXDISP; + server->next_server = srvlist; + srvlist = server; + srvcnt++; + } + break; + + case CONFIG_KEYS: + if (ntokens >= 2) { + key_file = (char *) emalloc(strlen(tokens[1]) + 1); + strcpy(key_file, tokens[1]); + } + break; + } + } + (void) fclose(fp); + + /* build final list */ + sys_numservers = srvcnt; + sys_servers = (struct server **) + emalloc(sys_numservers * sizeof(struct server *)); + for(i=0;i<sys_numservers;i++) { + sys_servers[i] = srvlist; + srvlist = srvlist->next_server; + } +} + + + +/* + * gettokens - read a line and return tokens + */ +static int +gettokens( + FILE *fp, + char *line, + char **tokenlist, + int *ntokens + ) +{ + register char *cp; + register int eol; + register int ntok; + register int quoted = 0; + + /* + * 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) || quoted)) + quoted ^= (*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( + register char *word, + register struct keyword *keys + ) +{ + for (;;) { + if (keys->keytype == CONFIG_UNKNOWN) { + 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( + const char *num, + struct sockaddr_in *addr, + int complain + ) +{ + register const char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + u_int32 netnum; + + /* XXX ELIMINATE replace with decodenetnum */ + cp = num; + netnum = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit((int)*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 %lu\n", + num, i, buf, temp, (u_long)netnum); +#endif + } + + if (i < 4) { + if (complain) + msyslog(LOG_ERR, + "getnetnum: \"%s\" invalid host number, line ignored", + num); +#ifdef DEBUG + if (debug > 3) + printf( + "getnetnum: \"%s\" invalid host number, line ignored\n", + num); +#endif + return 0; + } + + /* + * make up socket address. Clear it out for neatness. + */ + memset((void *)addr, 0, 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 (%lx)\n", + num, ntoa(addr), (u_long)netnum); +#endif + return 1; +} |