]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpdate/ntptime_config.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / ntpdate / ntptime_config.c
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 }