1: /*
2: * ntptime_config.c
3: *
4: * What follows is a simplified version of the config parsing code
5: * in ntpd/ntp_config.c. We only parse a subset of the configuration
6: * syntax, and don't bother whining about things we don't understand.
7: *
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: # include <config.h>
12: #endif
13:
14: #include "ntp_fp.h"
15: #include "ntp.h"
16: #include "ntp_io.h"
17: #include "ntp_unixtime.h"
18: #include "ntp_filegen.h"
19: #include "ntpdate.h"
20: #include "ntp_syslog.h"
21: #include "ntp_stdlib.h"
22:
23: #include <stdio.h>
24: #include <signal.h>
25: #include <ctype.h>
26:
27: /*
28: * These routines are used to read the configuration file at
29: * startup time. An entry in the file must fit on a single line.
30: * Entries are processed as multiple tokens separated by white space
31: * Lines are considered terminated when a '#' is encountered. Blank
32: * lines are ignored.
33: */
34:
35: /*
36: * Configuration file name
37: */
38: #ifndef CONFIG_FILE
39: # ifndef SYS_WINNT
40: # define CONFIG_FILE "/etc/ntp.conf"
41: # else /* SYS_WINNT */
42: # define CONFIG_FILE "%windir%\\ntp.conf"
43: # define ALT_CONFIG_FILE "%windir%\\ntp.ini"
44: # endif /* SYS_WINNT */
45: #endif /* not CONFIG_FILE */
46:
47: /*
48: *
49: * We understand the following configuration entries and defaults.
50: *
51: * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
52: * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
53: * keys file_name
54: */
55:
56: #define CONFIG_UNKNOWN 0
57:
58: #define CONFIG_PEER 1
59: #define CONFIG_SERVER 2
60: #define CONFIG_KEYS 8
61:
62: #define CONF_MOD_VERSION 1
63: #define CONF_MOD_KEY 2
64: #define CONF_MOD_MINPOLL 3
65: #define CONF_MOD_MAXPOLL 4
66: #define CONF_MOD_PREFER 5
67: #define CONF_MOD_BURST 6
68: #define CONF_MOD_SKEY 7
69: #define CONF_MOD_TTL 8
70: #define CONF_MOD_MODE 9
71:
72: /*
73: * Translation table - keywords to function index
74: */
75: struct keyword {
76: const char *text;
77: int keytype;
78: };
79:
80: /*
81: * Command keywords
82: */
83: static struct keyword keywords[] = {
84: { "peer", CONFIG_PEER },
85: { "server", CONFIG_SERVER },
86: { "keys", CONFIG_KEYS },
87: { "", CONFIG_UNKNOWN }
88: };
89:
90: /*
91: * "peer", "server", "broadcast" modifier keywords
92: */
93: static struct keyword mod_keywords[] = {
94: { "version", CONF_MOD_VERSION },
95: { "key", CONF_MOD_KEY },
96: { "minpoll", CONF_MOD_MINPOLL },
97: { "maxpoll", CONF_MOD_MAXPOLL },
98: { "prefer", CONF_MOD_PREFER },
99: { "burst", CONF_MOD_BURST },
100: { "autokey", CONF_MOD_SKEY },
101: { "mode", CONF_MOD_MODE }, /* reference clocks */
102: { "ttl", CONF_MOD_TTL }, /* NTP peers */
103: { "", CONFIG_UNKNOWN }
104: };
105:
106: /*
107: * Limits on things
108: */
109: #define MAXTOKENS 20 /* 20 tokens on line */
110: #define MAXLINE 1024 /* maximum length of line */
111: #define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */
112:
113: /*
114: * Miscellaneous macros
115: */
116: #define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
117: #define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
118: #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
119: #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
120:
121: /*
122: * Systemwide parameters and flags
123: */
124: extern struct server **sys_servers; /* the server list */
125: extern int sys_numservers; /* number of servers to poll */
126: extern char *key_file;
127:
128: /*
129: * Function prototypes
130: */
131: static int gettokens P((FILE *, char *, char **, int *));
132: static int matchkey P((char *, struct keyword *));
133: static int getnetnum P((const char *num, struct sockaddr_in *addr,
134: int complain));
135:
136:
137: /*
138: * loadservers - load list of NTP servers from configuration file
139: */
140: void
141: loadservers(
142: char *cfgpath
143: )
144: {
145: register int i;
146: int errflg;
147: int peerversion;
148: int minpoll;
149: int maxpoll;
150: /* int ttl; */
151: int srvcnt;
152: /* u_long peerkey; */
153: int peerflags;
154: struct sockaddr_in peeraddr;
155: FILE *fp;
156: char line[MAXLINE];
157: char *(tokens[MAXTOKENS]);
158: int ntokens;
159: int tok;
160: const char *config_file;
161: #ifdef SYS_WINNT
162: char *alt_config_file;
163: LPTSTR temp;
164: char config_file_storage[MAX_PATH];
165: char alt_config_file_storage[MAX_PATH];
166: #endif /* SYS_WINNT */
167: struct server *server, *srvlist;
168:
169: /*
170: * Initialize, initialize
171: */
172: srvcnt = 0;
173: srvlist = 0;
174: errflg = 0;
175: #ifdef DEBUG
176: debug = 0;
177: #endif /* DEBUG */
178: #ifndef SYS_WINNT
179: config_file = cfgpath ? cfgpath : CONFIG_FILE;
180: #else
181: if (cfgpath) {
182: config_file = cfgpath;
183: } else {
184: temp = CONFIG_FILE;
185: if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
186: msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
187: exit(1);
188: }
189: config_file = config_file_storage;
190: }
191:
192: temp = ALT_CONFIG_FILE;
193: if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
194: msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
195: exit(1);
196: }
197: alt_config_file = alt_config_file_storage;
198: M
199: #endif /* SYS_WINNT */
200:
201: if ((fp = fopen(FindConfig(config_file), "r")) == NULL)
202: {
203: fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
204: msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
205: #ifdef SYS_WINNT
206: /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
207:
208: if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) {
209:
210: /*
211: * Broadcast clients can sometimes run without
212: * a configuration file.
213: */
214:
215: fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
216: msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
217: return;
218: }
219: #else /* not SYS_WINNT */
220: return;
221: #endif /* not SYS_WINNT */
222: }
223:
224: while ((tok = gettokens(fp, line, tokens, &ntokens))
225: != CONFIG_UNKNOWN) {
226: switch(tok) {
227: case CONFIG_PEER:
228: case CONFIG_SERVER:
229:
230: if (ntokens < 2) {
231: msyslog(LOG_ERR,
232: "No address for %s, line ignored",
233: tokens[0]);
234: break;
235: }
236:
237: if (!getnetnum(tokens[1], &peeraddr, 1)) {
238: /* Resolve now, or lose! */
239: break;
240: } else {
241: errflg = 0;
242:
243: /* Shouldn't be able to specify multicast */
244: if (IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))
245: || ISBADADR(&peeraddr)) {
246: msyslog(LOG_ERR,
247: "attempt to configure invalid address %s",
248: ntoa(&peeraddr));
249: break;
250: }
251: }
252:
253: peerversion = NTP_VERSION;
254: minpoll = NTP_MINDPOLL;
255: maxpoll = NTP_MAXDPOLL;
256: /* peerkey = 0; */
257: peerflags = 0;
258: /* ttl = 0; */
259: for (i = 2; i < ntokens; i++)
260: switch (matchkey(tokens[i], mod_keywords)) {
261: case CONF_MOD_VERSION:
262: if (i >= ntokens-1) {
263: msyslog(LOG_ERR,
264: "peer/server version requires an argument");
265: errflg = 1;
266: break;
267: }
268: peerversion = atoi(tokens[++i]);
269: if ((u_char)peerversion > NTP_VERSION
270: || (u_char)peerversion < NTP_OLDVERSION) {
271: msyslog(LOG_ERR,
272: "inappropriate version number %s, line ignored",
273: tokens[i]);
274: errflg = 1;
275: }
276: break;
277:
278: case CONF_MOD_KEY:
279: if (i >= ntokens-1) {
280: msyslog(LOG_ERR,
281: "key: argument required");
282: errflg = 1;
283: break;
284: }
285: ++i;
286: /* peerkey = (int)atol(tokens[i]); */
287: peerflags |= FLAG_AUTHENABLE;
288: break;
289:
290: case CONF_MOD_MINPOLL:
291: if (i >= ntokens-1) {
292: msyslog(LOG_ERR,
293: "minpoll: argument required");
294: errflg = 1;
295: break;
296: }
297: minpoll = atoi(tokens[++i]);
298: if (minpoll < NTP_MINPOLL)
299: minpoll = NTP_MINPOLL;
300: break;
301:
302: case CONF_MOD_MAXPOLL:
303: if (i >= ntokens-1) {
304: msyslog(LOG_ERR,
305: "maxpoll: argument required"
306: );
307: errflg = 1;
308: break;
309: }
310: maxpoll = atoi(tokens[++i]);
311: if (maxpoll > NTP_MAXPOLL)
312: maxpoll = NTP_MAXPOLL;
313: break;
314:
315: case CONF_MOD_PREFER:
316: peerflags |= FLAG_PREFER;
317: break;
318:
319: case CONF_MOD_BURST:
320: peerflags |= FLAG_BURST;
321: break;
322:
323: case CONF_MOD_SKEY:
324: peerflags |= FLAG_SKEY | FLAG_AUTHENABLE;
325: break;
326:
327: case CONF_MOD_TTL:
328: if (i >= ntokens-1) {
329: msyslog(LOG_ERR,
330: "ttl: argument required");
331: errflg = 1;
332: break;
333: }
334: ++i;
335: /* ttl = atoi(tokens[i]); */
336: break;
337:
338: case CONF_MOD_MODE:
339: if (i >= ntokens-1) {
340: msyslog(LOG_ERR,
341: "mode: argument required");
342: errflg = 1;
343: break;
344: }
345: ++i;
346: /* ttl = atoi(tokens[i]); */
347: break;
348:
349: case CONFIG_UNKNOWN:
350: errflg = 1;
351: break;
352: }
353: if (minpoll > maxpoll) {
354: msyslog(LOG_ERR, "config error: minpoll > maxpoll");
355: errflg = 1;
356: }
357: if (errflg == 0) {
358: server = (struct server *)emalloc(sizeof(struct server));
359: memset((char *)server, 0, sizeof(struct server));
360: server->srcadr = peeraddr;
361: server->version = peerversion;
362: server->dispersion = PEER_MAXDISP;
363: server->next_server = srvlist;
364: srvlist = server;
365: srvcnt++;
366: }
367: break;
368:
369: case CONFIG_KEYS:
370: if (ntokens >= 2) {
371: key_file = (char *) emalloc(strlen(tokens[1]) + 1);
372: strcpy(key_file, tokens[1]);
373: }
374: break;
375: }
376: }
377: (void) fclose(fp);
378:
379: /* build final list */
380: sys_numservers = srvcnt;
381: sys_servers = (struct server **)
382: emalloc(sys_numservers * sizeof(struct server *));
383: for(i=0;i<sys_numservers;i++) {
384: sys_servers[i] = srvlist;
385: srvlist = srvlist->next_server;
386: }
387: }
388:
389:
390:
391: /*
392: * gettokens - read a line and return tokens
393: */
394: static int
395: gettokens(
396: FILE *fp,
397: char *line,
398: char **tokenlist,
399: int *ntokens
400: )
401: {
402: register char *cp;
403: register int eol;
404: register int ntok;
405: register int quoted = 0;
406:
407: /*
408: * Find start of first token
409: */
410: again:
411: while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
412: cp = line;
413: while (ISSPACE(*cp))
414: cp++;
415: if (!ISEOL(*cp))
416: break;
417: }
418: if (cp == NULL) {
419: *ntokens = 0;
420: return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
421: }
422:
423: /*
424: * Now separate out the tokens
425: */
426: eol = 0;
427: ntok = 0;
428: while (!eol) {
429: tokenlist[ntok++] = cp;
430: while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
431: quoted ^= (*cp++ == '"');
432:
433: if (ISEOL(*cp)) {
434: *cp = '\0';
435: eol = 1;
436: } else { /* must be space */
437: *cp++ = '\0';
438: while (ISSPACE(*cp))
439: cp++;
440: if (ISEOL(*cp))
441: eol = 1;
442: }
443: if (ntok == MAXTOKENS)
444: eol = 1;
445: }
446:
447: /*
448: * Return the match
449: */
450: *ntokens = ntok;
451: ntok = matchkey(tokenlist[0], keywords);
452: if (ntok == CONFIG_UNKNOWN)
453: goto again;
454: return ntok;
455: }
456:
457:
458:
459: /*
460: * matchkey - match a keyword to a list
461: */
462: static int
463: matchkey(
464: register char *word,
465: register struct keyword *keys
466: )
467: {
468: for (;;) {
469: if (keys->keytype == CONFIG_UNKNOWN) {
470: return CONFIG_UNKNOWN;
471: }
472: if (STRSAME(word, keys->text))
473: return keys->keytype;
474: keys++;
475: }
476: }
477:
478:
479: /*
480: * getnetnum - return a net number (this is crude, but careful)
481: */
482: static int
483: getnetnum(
484: const char *num,
485: struct sockaddr_in *addr,
486: int complain
487: )
488: {
489: register const char *cp;
490: register char *bp;
491: register int i;
492: register int temp;
493: char buf[80]; /* will core dump on really stupid stuff */
494: u_int32 netnum;
495:
496: /* XXX ELIMINATE replace with decodenetnum */
497: cp = num;
498: netnum = 0;
499: for (i = 0; i < 4; i++) {
500: bp = buf;
501: while (isdigit((int)*cp))
502: *bp++ = *cp++;
503: if (bp == buf)
504: break;
505:
506: if (i < 3) {
507: if (*cp++ != '.')
508: break;
509: } else if (*cp != '\0')
510: break;
511:
512: *bp = '\0';
513: temp = atoi(buf);
514: if (temp > 255)
515: break;
516: netnum <<= 8;
517: netnum += temp;
518: #ifdef DEBUG
519: if (debug > 3)
520: printf("getnetnum %s step %d buf %s temp %d netnum %lu\n",
521: num, i, buf, temp, (u_long)netnum);
522: #endif
523: }
524:
525: if (i < 4) {
526: if (complain)
527: msyslog(LOG_ERR,
528: "getnetnum: \"%s\" invalid host number, line ignored",
529: num);
530: #ifdef DEBUG
531: if (debug > 3)
532: printf(
533: "getnetnum: \"%s\" invalid host number, line ignored\n",
534: num);
535: #endif
536: return 0;
537: }
538:
539: /*
540: * make up socket address. Clear it out for neatness.
541: */
542: memset((void *)addr, 0, sizeof(struct sockaddr_in));
543: addr->sin_family = AF_INET;
544: addr->sin_port = htons(NTP_PORT);
545: addr->sin_addr.s_addr = htonl(netnum);
546: #ifdef DEBUG
547: if (debug > 1)
548: printf("getnetnum given %s, got %s (%lx)\n",
549: num, ntoa(addr), (u_long)netnum);
550: #endif
551: return 1;
552: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>