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 */ 75struct keyword { 76 const char *text; 77 int keytype; 78}; 79 80/* 81 * Command keywords 82 */ 83static 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 */ 93static 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 */ 124extern struct server **sys_servers; /* the server list */ 125extern int sys_numservers; /* number of servers to poll */ 126extern char *key_file; 127 128/* 129 * Function prototypes 130 */ 131static int gettokens P((FILE *, char *, char **, int *)); 132static int matchkey P((char *, struct keyword *)); 133static 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 */ 140void 141loadservers( 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; 198M 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 */ 394static int 395gettokens( 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 */ 462static int 463matchkey( 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 */ 482static int 483getnetnum( 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} 553