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