Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

426 lines
8.2 KiB

20 years ago
  1. /* $OpenBSD: parse.y,v 1.25 2005/06/19 16:42:57 henning Exp $ */
  2. /*
  3. * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
  4. * Copyright (c) 2001 Markus Friedl. All rights reserved.
  5. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
  6. * Copyright (c) 2001 Theo de Raadt. All rights reserved.
  7. *
  8. * Permission to use, copy, modify, and distribute this software for any
  9. * purpose with or without fee is hereby granted, provided that the above
  10. * copyright notice and this permission notice appear in all copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  13. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  14. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  15. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  16. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  17. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  18. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19. */
  20. %{
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #include <ctype.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <syslog.h>
  32. #include "ntpd.h"
  33. static struct ntpd_conf *conf;
  34. static FILE *fin = NULL;
  35. static int lineno = 1;
  36. static int errors = 0;
  37. const char *infile;
  38. int yyerror(const char *, ...);
  39. int yyparse(void);
  40. int kw_cmp(const void *, const void *);
  41. int lookup(char *);
  42. int lgetc(FILE *);
  43. int lungetc(int);
  44. int findeol(void);
  45. int yylex(void);
  46. typedef struct {
  47. union {
  48. u_int32_t number;
  49. char *string;
  50. struct ntp_addr_wrap *addr;
  51. } v;
  52. int lineno;
  53. } YYSTYPE;
  54. %}
  55. %token LISTEN ON
  56. %token SERVER SERVERS
  57. %token ERROR
  58. %token <v.string> STRING
  59. %type <v.addr> address
  60. %%
  61. grammar : /* empty */
  62. | grammar '\n'
  63. | grammar conf_main '\n'
  64. | grammar error '\n' { errors++; }
  65. ;
  66. conf_main : LISTEN ON address {
  67. struct listen_addr *la;
  68. struct ntp_addr *h, *next;
  69. if ((h = $3->a) == NULL &&
  70. (host_dns($3->name, &h) == -1 || !h)) {
  71. yyerror("could not resolve \"%s\"", $3->name);
  72. free($3->name);
  73. free($3);
  74. YYERROR;
  75. }
  76. for (; h != NULL; h = next) {
  77. next = h->next;
  78. if (h->ss.ss_family == AF_UNSPEC) {
  79. conf->listen_all = 1;
  80. free(h);
  81. continue;
  82. }
  83. la = calloc(1, sizeof(struct listen_addr));
  84. if (la == NULL)
  85. fatal("listen on calloc");
  86. la->fd = -1;
  87. memcpy(&la->sa, &h->ss,
  88. sizeof(struct sockaddr_storage));
  89. TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
  90. entry);
  91. free(h);
  92. }
  93. free($3->name);
  94. free($3);
  95. }
  96. | SERVERS address {
  97. struct ntp_peer *p;
  98. struct ntp_addr *h, *next;
  99. h = $2->a;
  100. do {
  101. if (h != NULL) {
  102. next = h->next;
  103. if (h->ss.ss_family != AF_INET &&
  104. h->ss.ss_family != AF_INET6) {
  105. yyerror("IPv4 or IPv6 address "
  106. "or hostname expected");
  107. free(h);
  108. free($2->name);
  109. free($2);
  110. YYERROR;
  111. }
  112. h->next = NULL;
  113. } else
  114. next = NULL;
  115. p = new_peer();
  116. p->addr = h;
  117. p->addr_head.a = h;
  118. p->addr_head.pool = 1;
  119. p->addr_head.name = strdup($2->name);
  120. if (p->addr_head.name == NULL)
  121. fatal(NULL);
  122. if (p->addr != NULL)
  123. p->state = STATE_DNS_DONE;
  124. TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
  125. h = next;
  126. } while (h != NULL);
  127. free($2->name);
  128. free($2);
  129. }
  130. | SERVER address {
  131. struct ntp_peer *p;
  132. struct ntp_addr *h, *next;
  133. p = new_peer();
  134. for (h = $2->a; h != NULL; h = next) {
  135. next = h->next;
  136. if (h->ss.ss_family != AF_INET &&
  137. h->ss.ss_family != AF_INET6) {
  138. yyerror("IPv4 or IPv6 address "
  139. "or hostname expected");
  140. free(h);
  141. free(p);
  142. free($2->name);
  143. free($2);
  144. YYERROR;
  145. }
  146. h->next = p->addr;
  147. p->addr = h;
  148. }
  149. p->addr_head.a = p->addr;
  150. p->addr_head.pool = 0;
  151. p->addr_head.name = strdup($2->name);
  152. if (p->addr_head.name == NULL)
  153. fatal(NULL);
  154. if (p->addr != NULL)
  155. p->state = STATE_DNS_DONE;
  156. TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
  157. free($2->name);
  158. free($2);
  159. }
  160. ;
  161. address : STRING {
  162. if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
  163. NULL)
  164. fatal(NULL);
  165. if (host($1, &$$->a) == -1) {
  166. yyerror("could not parse address spec \"%s\"",
  167. $1);
  168. free($1);
  169. free($$);
  170. YYERROR;
  171. }
  172. $$->name = $1;
  173. }
  174. ;
  175. %%
  176. struct keywords {
  177. const char *k_name;
  178. int k_val;
  179. };
  180. int
  181. yyerror(const char *fmt, ...)
  182. {
  183. va_list ap;
  184. char *nfmt;
  185. errors = 1;
  186. va_start(ap, fmt);
  187. if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
  188. fatalx("yyerror asprintf");
  189. vlog(LOG_CRIT, nfmt, ap);
  190. va_end(ap);
  191. free(nfmt);
  192. return (0);
  193. }
  194. int
  195. kw_cmp(const void *k, const void *e)
  196. {
  197. return (strcmp(k, ((const struct keywords *)e)->k_name));
  198. }
  199. int
  200. lookup(char *s)
  201. {
  202. /* this has to be sorted always */
  203. static const struct keywords keywords[] = {
  204. { "listen", LISTEN},
  205. { "on", ON},
  206. { "server", SERVER},
  207. { "servers", SERVERS}
  208. };
  209. const struct keywords *p;
  210. p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
  211. sizeof(keywords[0]), kw_cmp);
  212. if (p)
  213. return (p->k_val);
  214. else
  215. return (STRING);
  216. }
  217. #define MAXPUSHBACK 128
  218. char *parsebuf;
  219. int parseindex;
  220. char pushback_buffer[MAXPUSHBACK];
  221. int pushback_index = 0;
  222. int
  223. lgetc(FILE *f)
  224. {
  225. int c, next;
  226. if (parsebuf) {
  227. /* Read character from the parsebuffer instead of input. */
  228. if (parseindex >= 0) {
  229. c = parsebuf[parseindex++];
  230. if (c != '\0')
  231. return (c);
  232. parsebuf = NULL;
  233. } else
  234. parseindex++;
  235. }
  236. if (pushback_index)
  237. return (pushback_buffer[--pushback_index]);
  238. while ((c = getc(f)) == '\\') {
  239. next = getc(f);
  240. if (next != '\n') {
  241. if (isspace(next))
  242. yyerror("whitespace after \\");
  243. ungetc(next, f);
  244. break;
  245. }
  246. yylval.lineno = lineno;
  247. lineno++;
  248. }
  249. if (c == '\t' || c == ' ') {
  250. /* Compress blanks to a single space. */
  251. do {
  252. c = getc(f);
  253. } while (c == '\t' || c == ' ');
  254. ungetc(c, f);
  255. c = ' ';
  256. }
  257. return (c);
  258. }
  259. int
  260. lungetc(int c)
  261. {
  262. if (c == EOF)
  263. return (EOF);
  264. if (parsebuf) {
  265. parseindex--;
  266. if (parseindex >= 0)
  267. return (c);
  268. }
  269. if (pushback_index < MAXPUSHBACK-1)
  270. return (pushback_buffer[pushback_index++] = c);
  271. else
  272. return (EOF);
  273. }
  274. int
  275. findeol(void)
  276. {
  277. int c;
  278. parsebuf = NULL;
  279. pushback_index = 0;
  280. /* skip to either EOF or the first real EOL */
  281. while (1) {
  282. c = lgetc(fin);
  283. if (c == '\n') {
  284. lineno++;
  285. break;
  286. }
  287. if (c == EOF)
  288. break;
  289. }
  290. return (ERROR);
  291. }
  292. int
  293. yylex(void)
  294. {
  295. char buf[8096];
  296. char *p;
  297. int endc, c;
  298. int token;
  299. p = buf;
  300. while ((c = lgetc(fin)) == ' ')
  301. ; /* nothing */
  302. yylval.lineno = lineno;
  303. if (c == '#')
  304. while ((c = lgetc(fin)) != '\n' && c != EOF)
  305. ; /* nothing */
  306. switch (c) {
  307. case '\'':
  308. case '"':
  309. endc = c;
  310. while (1) {
  311. if ((c = lgetc(fin)) == EOF)
  312. return (0);
  313. if (c == endc) {
  314. *p = '\0';
  315. break;
  316. }
  317. if (c == '\n') {
  318. lineno++;
  319. continue;
  320. }
  321. if (p + 1 >= buf + sizeof(buf) - 1) {
  322. yyerror("string too long");
  323. return (findeol());
  324. }
  325. *p++ = (char)c;
  326. }
  327. yylval.v.string = strdup(buf);
  328. if (yylval.v.string == NULL)
  329. fatal("yylex: strdup");
  330. return (STRING);
  331. }
  332. #define allowed_in_string(x) \
  333. (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
  334. x != '{' && x != '}' && x != '<' && x != '>' && \
  335. x != '!' && x != '=' && x != '/' && x != '#' && \
  336. x != ','))
  337. if (isalnum(c) || c == ':' || c == '_' || c == '*') {
  338. do {
  339. *p++ = c;
  340. if ((unsigned)(p-buf) >= sizeof(buf)) {
  341. yyerror("string too long");
  342. return (findeol());
  343. }
  344. } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
  345. lungetc(c);
  346. *p = '\0';
  347. if ((token = lookup(buf)) == STRING)
  348. if ((yylval.v.string = strdup(buf)) == NULL)
  349. fatal("yylex: strdup");
  350. return (token);
  351. }
  352. if (c == '\n') {
  353. yylval.lineno = lineno;
  354. lineno++;
  355. }
  356. if (c == EOF)
  357. return (0);
  358. return (c);
  359. }
  360. int
  361. parse_config(const char *filename, struct ntpd_conf *xconf)
  362. {
  363. conf = xconf;
  364. lineno = 1;
  365. errors = 0;
  366. TAILQ_INIT(&conf->listen_addrs);
  367. TAILQ_INIT(&conf->ntp_peers);
  368. if ((fin = fopen(filename, "r")) == NULL) {
  369. log_warn("%s", filename);
  370. return (-1);
  371. }
  372. infile = filename;
  373. yyparse();
  374. fclose(fin);
  375. return (errors ? -1 : 0);
  376. }