mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 10:29:15 +00:00
851 lines
18 KiB
C
851 lines
18 KiB
C
/* xntpres.c,v 3.1 1993/07/06 01:12:09 jbj Exp
|
|
* xntpres - process configuration entries which require use of the resolver
|
|
*
|
|
* This is meant to be run by xntpd on the fly. It is not guaranteed
|
|
* to work properly if run by hand. This is actually a quick hack to
|
|
* stave off violence from people who hate using numbers in the
|
|
* configuration file (at least I hope the rest of the daemon is
|
|
* better than this). Also might provide some ideas about how one
|
|
* might go about autoconfiguring an NTP distribution network.
|
|
*
|
|
* Usage is:
|
|
* xntpres [-d] [-r] keyid keyfile configuration_data
|
|
*/
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
|
|
#include "ntp_select.h"
|
|
#include "ntp_fp.h"
|
|
#include "ntp.h"
|
|
#include "ntp_io.h"
|
|
#include "ntp_malloc.h"
|
|
#include "ntp_request.h"
|
|
#include "ntp_string.h"
|
|
#include "ntp_stdlib.h"
|
|
#include "ntp_syslog.h"
|
|
|
|
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
|
|
|
|
/*
|
|
* Each item we are to resolve and configure gets one of these
|
|
* structures defined for it.
|
|
*/
|
|
struct conf_entry {
|
|
struct conf_entry *ce_next;
|
|
char *ce_name; /* name we are trying to resolve */
|
|
struct conf_peer ce_config; /* configuration info for peer */
|
|
};
|
|
#define ce_peeraddr ce_config.peeraddr
|
|
#define ce_hmode ce_config.hmode
|
|
#define ce_version ce_config.version
|
|
#define ce_minpoll ce_config.minpoll
|
|
#define ce_maxpoll ce_config.maxpoll
|
|
#define ce_flags ce_config.flags
|
|
#define ce_ttl ce_config.ttl
|
|
#define ce_keyid ce_config.keyid
|
|
|
|
/*
|
|
* confentries is a pointer to the list of configuration entries
|
|
* we have left to do.
|
|
*/
|
|
struct conf_entry *confentries = NULL;
|
|
|
|
/*
|
|
* We take an interrupt every thirty seconds, at which time we decrement
|
|
* config_timer and resolve_timer. The former is set to 2, so we retry
|
|
* unsucessful reconfigurations every minute. The latter is set to
|
|
* an exponentially increasing value which starts at 2 and increases to
|
|
* 32. When this expires we retry failed name resolutions.
|
|
*
|
|
* We sleep SLEEPTIME seconds before doing anything, to give the server
|
|
* time to arrange itself.
|
|
*/
|
|
#define MINRESOLVE 2
|
|
#define MAXRESOLVE 32
|
|
#define CONFIG_TIME 2
|
|
#define ALARM_TIME 30
|
|
|
|
#define SLEEPTIME 2
|
|
|
|
int config_timer = 0;
|
|
int resolve_timer = 0;
|
|
|
|
int resolve_value; /* next value of resolve timer */
|
|
|
|
/*
|
|
* Big hack attack
|
|
*/
|
|
#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */
|
|
#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
|
|
|
|
/*
|
|
* Select time out. Set to 2 seconds. The server is on the local machine,
|
|
* after all.
|
|
*/
|
|
#define TIMEOUT_SEC 2
|
|
#define TIMEOUT_USEC 0
|
|
|
|
|
|
/*
|
|
* Input processing. The data on each line in the configuration file
|
|
* is supposed to consist of entries in the following order
|
|
*/
|
|
#define TOK_HOSTNAME 0
|
|
#define TOK_HMODE 1
|
|
#define TOK_VERSION 2
|
|
#define TOK_MINPOLL 3
|
|
#define TOK_MAXPOLL 4
|
|
#define TOK_FLAGS 5
|
|
#define TOK_TTL 6
|
|
#define TOK_KEYID 7
|
|
#define NUMTOK 8
|
|
|
|
#define MAXLINESIZE 512
|
|
|
|
|
|
/*
|
|
* File descriptor for ntp request code.
|
|
*/
|
|
int sockfd = -1;
|
|
|
|
/*
|
|
* Misc. data from argument processing
|
|
*/
|
|
int removefile = 0; /* remove configuration file when done */
|
|
|
|
U_LONG req_keyid; /* request keyid */
|
|
char *keyfile; /* file where keys are kept */
|
|
char *conffile; /* name of the file with configuration info */
|
|
|
|
char *progname;
|
|
int debug = 0;
|
|
extern char *Version;
|
|
extern int errno;
|
|
|
|
static RETSIGTYPE bong P((int));
|
|
static void checkparent P((void));
|
|
static void removeentry P((struct conf_entry *));
|
|
static void addentry P((char *, int, int, int, int, int, int, U_LONG));
|
|
static int findhostaddr P((struct conf_entry *));
|
|
static void openntp P((void));
|
|
static int request P((struct conf_peer *));
|
|
static char * nexttoken P((char **));
|
|
static void readconf P((FILE *, char *));
|
|
static void doconfigure P((int));
|
|
|
|
/*
|
|
* main - parse arguments and handle options
|
|
*/
|
|
void
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int c;
|
|
int errflg = 0;
|
|
char *cp;
|
|
FILE *in;
|
|
extern int ntp_optind;
|
|
|
|
progname = argv[0];
|
|
|
|
/*
|
|
* Better get syslog open early since stderr messages are likely
|
|
* ending up in the twilight zone
|
|
*/
|
|
cp = strrchr(argv[0], '/');
|
|
if (cp == 0)
|
|
cp = argv[0];
|
|
else
|
|
cp++;
|
|
|
|
#ifndef LOG_DAEMON
|
|
openlog(cp, LOG_PID);
|
|
#else
|
|
|
|
#ifndef LOG_NTP
|
|
#define LOG_NTP LOG_DAEMON
|
|
#endif
|
|
openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
|
else
|
|
#endif /* DEBUG */
|
|
setlogmask(LOG_UPTO(LOG_INFO));
|
|
#endif /* LOG_DAEMON */
|
|
|
|
syslog(LOG_NOTICE, Version);
|
|
|
|
while ((c = ntp_getopt(argc, argv, "dr")) != EOF)
|
|
switch (c) {
|
|
case 'd':
|
|
++debug;
|
|
break;
|
|
case 'r':
|
|
++removefile;
|
|
break;
|
|
default:
|
|
errflg++;
|
|
break;
|
|
}
|
|
if (errflg || (ntp_optind + 3) != argc) {
|
|
(void) fprintf(stderr,
|
|
"usage: %s [-d] [-r] keyid keyfile conffile\n", progname);
|
|
syslog(LOG_ERR, "exiting due to usage error");
|
|
exit(2);
|
|
}
|
|
|
|
if (!atouint(argv[ntp_optind], &req_keyid)) {
|
|
syslog(LOG_ERR, "undecodeable keyid %s", argv[ntp_optind]);
|
|
exit(1);
|
|
}
|
|
|
|
keyfile = argv[ntp_optind+1];
|
|
conffile = argv[ntp_optind+2];
|
|
|
|
/*
|
|
* Make sure we have the key we need
|
|
*/
|
|
if (!authreadkeys(keyfile))
|
|
exit(1);
|
|
if (!authhavekey(req_keyid)) {
|
|
syslog(LOG_ERR, "request keyid %lu not found in %s",
|
|
req_keyid, keyfile);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Read the configuration info
|
|
*/
|
|
if ((in = fopen(conffile, "r")) == NULL) {
|
|
syslog(LOG_ERR, "can't open configuration file %s: %m",
|
|
conffile);
|
|
exit(1);
|
|
}
|
|
readconf(in, conffile);
|
|
(void) fclose(in);
|
|
if (removefile)
|
|
(void) unlink(conffile);
|
|
|
|
/*
|
|
* Sleep a little to make sure the server is completely up
|
|
*/
|
|
sleep(SLEEPTIME);
|
|
|
|
/*
|
|
* Make a first cut at resolving the bunch
|
|
*/
|
|
doconfigure(1);
|
|
if (confentries == NULL)
|
|
exit(0); /* done that quick */
|
|
|
|
/*
|
|
* Here we've got some problem children. Set up the timer
|
|
* and wait for it.
|
|
*/
|
|
resolve_value = resolve_timer = MINRESOLVE;
|
|
config_timer = CONFIG_TIME;
|
|
(void) signal(SIGALRM, bong);
|
|
alarm(ALARM_TIME);
|
|
|
|
for (;;) {
|
|
if (confentries == NULL)
|
|
exit(0);
|
|
checkparent();
|
|
if (resolve_timer == 0) {
|
|
if (resolve_value < MAXRESOLVE)
|
|
resolve_value <<= 1;
|
|
resolve_timer = resolve_value;
|
|
config_timer = CONFIG_TIME;
|
|
doconfigure(1);
|
|
continue;
|
|
} else if (config_timer == 0) {
|
|
config_timer = CONFIG_TIME;
|
|
doconfigure(0);
|
|
continue;
|
|
}
|
|
/*
|
|
* There is a race in here. Is okay, though, since
|
|
* all it does is delay things by 30 seconds.
|
|
*/
|
|
(void) pause();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* bong - service and reschedule an alarm() interrupt
|
|
*/
|
|
static RETSIGTYPE
|
|
bong(sig)
|
|
int sig;
|
|
{
|
|
if (config_timer > 0)
|
|
config_timer--;
|
|
if (resolve_timer > 0)
|
|
resolve_timer--;
|
|
alarm(ALARM_TIME);
|
|
}
|
|
|
|
|
|
/*
|
|
* checkparent - see if our parent process is still running
|
|
*/
|
|
static void
|
|
checkparent()
|
|
{
|
|
/*
|
|
* If our parent (the server) has died we will have been
|
|
* inherited by init. If so, exit.
|
|
*/
|
|
if (getppid() == 1) {
|
|
syslog(LOG_INFO, "parent died before we finished, exiting");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* removeentry - we are done with an entry, remove it from the list
|
|
*/
|
|
static void
|
|
removeentry(entry)
|
|
struct conf_entry *entry;
|
|
{
|
|
register struct conf_entry *ce;
|
|
|
|
ce = confentries;
|
|
if (ce == entry) {
|
|
confentries = ce->ce_next;
|
|
return;
|
|
}
|
|
|
|
while (ce != NULL) {
|
|
if (ce->ce_next == entry) {
|
|
ce->ce_next = entry->ce_next;
|
|
return;
|
|
}
|
|
ce = ce->ce_next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* addentry - add an entry to the configuration list
|
|
*/
|
|
static void
|
|
addentry(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
|
|
char *name;
|
|
int mode;
|
|
int version;
|
|
int minpoll;
|
|
int maxpoll;
|
|
int flags;
|
|
int ttl;
|
|
U_LONG keyid;
|
|
{
|
|
register char *cp;
|
|
register struct conf_entry *ce;
|
|
int len;
|
|
|
|
len = strlen(name) + 1;
|
|
cp = emalloc((unsigned)len);
|
|
memmove(cp, name, len);
|
|
|
|
ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
|
|
ce->ce_name = cp;
|
|
ce->ce_peeraddr = 0;
|
|
ce->ce_hmode = (u_char)mode;
|
|
ce->ce_version = (u_char)version;
|
|
ce->ce_minpoll = (u_char)minpoll;
|
|
ce->ce_maxpoll = (u_char)maxpoll;
|
|
ce->ce_flags = (u_char)flags;
|
|
ce->ce_ttl = (u_char)ttl;
|
|
ce->ce_keyid = htonl(keyid);
|
|
ce->ce_next = NULL;
|
|
|
|
if (confentries == NULL) {
|
|
confentries = ce;
|
|
} else {
|
|
register struct conf_entry *cep;
|
|
|
|
for (cep = confentries; cep->ce_next != NULL;
|
|
cep = cep->ce_next)
|
|
/* nothing */;
|
|
cep->ce_next = ce;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* findhostaddr - resolve a host name into an address
|
|
*
|
|
* The routine sticks the address into the entry's ce_peeraddr if it
|
|
* gets one. It returns 1 for "success" and 0 for an uncorrectable
|
|
* failure. Note that "success" includes try again errors. You can
|
|
* tell that you got a try again since ce_peeraddr will still be zero.
|
|
*/
|
|
static int
|
|
findhostaddr(entry)
|
|
struct conf_entry *entry;
|
|
{
|
|
struct hostent *hp;
|
|
|
|
checkparent(); /* make sure our guy is still running */
|
|
|
|
hp = gethostbyname(entry->ce_name);
|
|
|
|
if (hp == NULL) {
|
|
#ifndef NODNS
|
|
/*
|
|
* If the resolver is in use, see if the failure is
|
|
* temporary. If so, return success.
|
|
*/
|
|
extern int h_errno;
|
|
|
|
if (h_errno == TRY_AGAIN)
|
|
return 1;
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Use the first address. We don't have any way to
|
|
* tell preferences and older gethostbyname() implementations
|
|
* only return one.
|
|
*/
|
|
memmove((char *)&(entry->ce_peeraddr),
|
|
hp->h_addr,
|
|
sizeof(struct in_addr));
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* openntp - open a socket to the ntp server
|
|
*/
|
|
static void
|
|
openntp()
|
|
{
|
|
struct sockaddr_in saddr;
|
|
|
|
if (sockfd >= 0)
|
|
return;
|
|
|
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sockfd == -1) {
|
|
syslog(LOG_ERR, "socket() failed: %m");
|
|
exit(1);
|
|
}
|
|
|
|
memset((char *)&saddr, 0, sizeof(saddr));
|
|
saddr.sin_family = AF_INET;
|
|
saddr.sin_port = htons(NTP_PORT); /* trash */
|
|
saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */
|
|
|
|
|
|
/*
|
|
* Make the socket non-blocking. We'll wait with select()
|
|
*/
|
|
#if defined(O_NONBLOCK)
|
|
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
|
|
syslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
|
|
exit(1);
|
|
}
|
|
#else
|
|
#if defined(FNDELAY)
|
|
if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
|
|
syslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
|
|
exit(1);
|
|
}
|
|
#else
|
|
NEED NON BLOCKING IO
|
|
#endif
|
|
#endif
|
|
|
|
if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
|
|
syslog(LOG_ERR, "connect() failed: %m");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* request - send a configuration request to the server, wait for a response
|
|
*/
|
|
static int
|
|
request(conf)
|
|
struct conf_peer *conf;
|
|
{
|
|
fd_set fdset;
|
|
struct timeval tvout;
|
|
struct req_pkt reqpkt;
|
|
l_fp ts;
|
|
int n;
|
|
|
|
checkparent(); /* make sure our guy is still running */
|
|
|
|
if (sockfd < 0)
|
|
openntp();
|
|
|
|
/*
|
|
* Try to clear out any previously received traffic so it
|
|
* doesn't fool us. Note the socket is nonblocking.
|
|
*/
|
|
while (read(sockfd, (char *)&reqpkt, REQ_LEN_MAC) > 0)
|
|
/* nothing */;
|
|
|
|
/*
|
|
* Make up a request packet with the configuration info
|
|
*/
|
|
memset((char *)&reqpkt, 0, sizeof(reqpkt));
|
|
|
|
reqpkt.rm_vn_mode = RM_VN_MODE(0, 0);
|
|
reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */
|
|
reqpkt.implementation = IMPL_XNTPD; /* local implementation */
|
|
reqpkt.request = REQ_CONFIG; /* configure a new peer */
|
|
reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */
|
|
reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer));
|
|
memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
|
|
reqpkt.keyid = htonl(req_keyid);
|
|
|
|
auth1crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
|
|
gettstamp(&ts);
|
|
M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME);
|
|
HTONL_FP(&ts, &reqpkt.tstamp);
|
|
n = auth2crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
|
|
|
|
/*
|
|
* Done. Send it.
|
|
*/
|
|
n = write(sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n);
|
|
if (n < 0) {
|
|
syslog(LOG_ERR, "send to NTP server failed: %m");
|
|
return 0; /* maybe should exit */
|
|
}
|
|
|
|
/*
|
|
* Wait for a response. A weakness of the mode 7 protocol used
|
|
* is that there is no way to associate a response with a
|
|
* particular request, i.e. the response to this configuration
|
|
* request is indistinguishable from that to any other. I should
|
|
* fix this some day. In any event, the time out is fairly
|
|
* pessimistic to make sure that if an answer is coming back
|
|
* at all, we get it.
|
|
*/
|
|
for (;;) {
|
|
FD_ZERO(&fdset);
|
|
FD_SET(sockfd, &fdset);
|
|
tvout.tv_sec = TIMEOUT_SEC;
|
|
tvout.tv_usec = TIMEOUT_USEC;
|
|
|
|
n = select(sockfd + 1, &fdset, (fd_set *)0,
|
|
(fd_set *)0, &tvout);
|
|
|
|
if (n <= 0) {
|
|
if (n < 0)
|
|
syslog(LOG_ERR, "select() fails: %m");
|
|
return 0;
|
|
}
|
|
|
|
n = read(sockfd, (char *)&reqpkt, REQ_LEN_MAC);
|
|
if (n <= 0) {
|
|
if (n < 0) {
|
|
syslog(LOG_ERR, "read() fails: %m");
|
|
return 0;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Got one. Check through to make sure it is what
|
|
* we expect.
|
|
*/
|
|
if (n < RESP_HEADER_SIZE) {
|
|
syslog(LOG_ERR, "received runt response (%d octets)",
|
|
n);
|
|
continue;
|
|
}
|
|
|
|
if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf("received non-response packet\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (ISMORE(reqpkt.rm_vn_mode)) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf("received fragmented packet\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (INFO_VERSION(reqpkt.rm_vn_mode) != NTP_VERSION
|
|
|| INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf("version (%d) or mode (%d) incorrect\n",
|
|
INFO_VERSION(reqpkt.rm_vn_mode),
|
|
INFO_MODE(reqpkt.rm_vn_mode));
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (INFO_SEQ(reqpkt.auth_seq) != 0) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf("nonzero sequence number (%d)\n",
|
|
INFO_SEQ(reqpkt.auth_seq));
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (reqpkt.implementation != IMPL_XNTPD ||
|
|
reqpkt.request != REQ_CONFIG) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf(
|
|
"implementation (%d) or request (%d) incorrect\n",
|
|
reqpkt.implementation, reqpkt.request);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
|
|
INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
|
|
INFO_ITEMSIZE(reqpkt.mbz_itemsize != 0)) {
|
|
#ifdef DEBUG
|
|
if (debug > 1)
|
|
printf(
|
|
"nitems (%d) mbz (%d) or itemsize (%d) nonzero\n",
|
|
INFO_NITEMS(reqpkt.err_nitems),
|
|
INFO_MBZ(reqpkt.mbz_itemsize),
|
|
INFO_ITEMSIZE(reqpkt.mbz_itemsize));
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
n = INFO_ERR(reqpkt.err_nitems);
|
|
switch (n) {
|
|
case INFO_OKAY:
|
|
/* success */
|
|
return 1;
|
|
|
|
case INFO_ERR_IMPL:
|
|
syslog(LOG_ERR,
|
|
"server reports implementation mismatch!!");
|
|
return 0;
|
|
|
|
case INFO_ERR_REQ:
|
|
syslog(LOG_ERR,
|
|
"server claims configuration request is unknown");
|
|
return 0;
|
|
|
|
case INFO_ERR_FMT:
|
|
syslog(LOG_ERR,
|
|
"server indicates a format error occured(!!)");
|
|
return 0;
|
|
|
|
case INFO_ERR_NODATA:
|
|
syslog(LOG_ERR,
|
|
"server indicates no data available (shouldn't happen)");
|
|
return 0;
|
|
|
|
case INFO_ERR_AUTH:
|
|
syslog(LOG_ERR,
|
|
"server returns a permission denied error");
|
|
return 0;
|
|
|
|
default:
|
|
syslog(LOG_ERR,
|
|
"server returns unknown error code %d", n);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* nexttoken - return the next token from a line
|
|
*/
|
|
static char *
|
|
nexttoken(lptr)
|
|
char **lptr;
|
|
{
|
|
register char *cp;
|
|
register char *tstart;
|
|
|
|
cp = *lptr;
|
|
|
|
/*
|
|
* Skip leading white space
|
|
*/
|
|
while (*cp == ' ' || *cp == '\t')
|
|
cp++;
|
|
|
|
/*
|
|
* If this is the end of the line, return nothing.
|
|
*/
|
|
if (*cp == '\n' || *cp == '\0') {
|
|
*lptr = cp;
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Must be the start of a token. Record the pointer and look
|
|
* for the end.
|
|
*/
|
|
tstart = cp++;
|
|
while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
|
|
cp++;
|
|
|
|
/*
|
|
* Terminate the token with a \0. If this isn't the end of the
|
|
* line, space to the next character.
|
|
*/
|
|
if (*cp == '\n' || *cp == '\0')
|
|
*cp = '\0';
|
|
else
|
|
*cp++ = '\0';
|
|
|
|
*lptr = cp;
|
|
return tstart;
|
|
}
|
|
|
|
|
|
/*
|
|
* readconf - read the configuration information out of the file we
|
|
* were passed. Note that since the file is supposed to be
|
|
* machine generated, we bail out at the first sign of trouble.
|
|
*/
|
|
static void
|
|
readconf(fp, name)
|
|
FILE *fp;
|
|
char *name;
|
|
{
|
|
register int i;
|
|
char *token[NUMTOK];
|
|
U_LONG intval[NUMTOK];
|
|
int flags;
|
|
char buf[MAXLINESIZE];
|
|
char *bp;
|
|
|
|
while (fgets(buf, MAXLINESIZE, fp) != NULL) {
|
|
|
|
bp = buf;
|
|
for (i = 0; i < NUMTOK; i++) {
|
|
if ((token[i] = nexttoken(&bp)) == NULL) {
|
|
syslog(LOG_ERR,
|
|
"tokenizing error in file `%s', quitting",
|
|
name);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
for (i = 1; i < NUMTOK; i++) {
|
|
if (!atouint(token[i], &intval[i])) {
|
|
syslog(LOG_ERR,
|
|
"format error for integer token `%s', file `%s', quitting",
|
|
token[i], name);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (intval[TOK_HMODE] != MODE_ACTIVE &&
|
|
intval[TOK_HMODE] != MODE_CLIENT &&
|
|
intval[TOK_HMODE] != MODE_BROADCAST) {
|
|
syslog(LOG_ERR, "invalid mode (%d) in file %s",
|
|
intval[TOK_HMODE], name);
|
|
exit(1);
|
|
}
|
|
|
|
if (intval[TOK_VERSION] > NTP_VERSION ||
|
|
intval[TOK_VERSION] < NTP_OLDVERSION) {
|
|
syslog(LOG_ERR, "invalid version (%d) in file %s",
|
|
intval[TOK_VERSION], name);
|
|
exit(1);
|
|
}
|
|
|
|
if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
|
|
intval[TOK_MINPOLL] > NTP_MAXPOLL) {
|
|
syslog(LOG_ERR, "invalid MINPOLL value (%d) in file %s",
|
|
intval[TOK_MINPOLL], name);
|
|
exit(1);
|
|
}
|
|
|
|
if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
|
|
intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
|
|
syslog(LOG_ERR, "invalid MAXPOLL value (%d) in file %s",
|
|
intval[TOK_MAXPOLL], name);
|
|
exit(1);
|
|
}
|
|
|
|
if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE|FLAG_PREFER))
|
|
!= 0) {
|
|
syslog(LOG_ERR, "invalid flags (%d) in file %s",
|
|
intval[TOK_FLAGS], name);
|
|
exit(1);
|
|
}
|
|
|
|
flags = 0;
|
|
if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
|
|
flags |= CONF_FLAG_AUTHENABLE;
|
|
if (intval[TOK_FLAGS] & FLAG_PREFER)
|
|
flags |= CONF_FLAG_PREFER;
|
|
|
|
/*
|
|
* This is as good as we can check it. Add it in.
|
|
*/
|
|
addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
|
|
(int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
|
|
(int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
|
|
intval[TOK_KEYID]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* doconfigure - attempt to resolve names and configure the server
|
|
*/
|
|
static void
|
|
doconfigure(dores)
|
|
int dores;
|
|
{
|
|
register struct conf_entry *ce;
|
|
register struct conf_entry *ceremove;
|
|
|
|
ce = confentries;
|
|
while (ce != NULL) {
|
|
if (dores && ce->ce_peeraddr == 0) {
|
|
if (!findhostaddr(ce)) {
|
|
syslog(LOG_ERR,
|
|
"couldn't resolve `%s', giving up on it",
|
|
ce->ce_name);
|
|
ceremove = ce;
|
|
ce = ceremove->ce_next;
|
|
removeentry(ceremove);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (ce->ce_peeraddr != 0) {
|
|
if (request(&ce->ce_config)) {
|
|
ceremove = ce;
|
|
ce = ceremove->ce_next;
|
|
removeentry(ceremove);
|
|
continue;
|
|
}
|
|
}
|
|
ce = ce->ce_next;
|
|
}
|
|
}
|