]>
Commit | Line | Data |
---|---|---|
63115431 TL |
1 | /* parse.c |
2 | ||
3 | Common parser code for dhcpd and dhclient. */ | |
4 | ||
5 | /* | |
49733f31 TL |
6 | * Copyright (c) 1995-2000 Internet Software Consortium. |
7 | * All rights reserved. | |
63115431 | 8 | * |
49733f31 TL |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
63115431 | 12 | * |
49733f31 TL |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of The Internet Software Consortium nor the names | |
19 | * of its contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
63115431 | 21 | * |
49733f31 TL |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR | |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * This software has been written for the Internet Software Consortium | |
37 | * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. | |
38 | * To learn more about the Internet Software Consortium, see | |
39 | * ``http://www.isc.org/''. To learn more about Vixie Enterprises, | |
40 | * see ``http://www.vix.com''. To learn more about Nominum, Inc., see | |
41 | * ``http://www.nominum.com''. | |
63115431 TL |
42 | */ |
43 | ||
44 | #ifndef lint | |
45 | static char copyright[] = | |
ca5956dc | 46 | "$Id: parse.c,v 1.85 2000/09/21 07:52:19 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; |
63115431 TL |
47 | #endif /* not lint */ |
48 | ||
49 | #include "dhcpd.h" | |
63115431 TL |
50 | |
51 | /* Skip to the semicolon ending the current statement. If we encounter | |
52 | braces, the matching closing brace terminates the statement. If we | |
53 | encounter a right brace but haven't encountered a left brace, return | |
54 | leaving the brace in the token buffer for the caller. If we see a | |
55 | semicolon and haven't seen a left brace, return. This lets us skip | |
56 | over: | |
57 | ||
58 | statement; | |
59 | statement foo bar { } | |
60 | statement foo bar { statement { } } | |
61 | statement} | |
62 | ||
63 | ...et cetera. */ | |
64 | ||
65 | void skip_to_semi (cfile) | |
4615d498 | 66 | struct parse *cfile; |
cea8b5c9 TL |
67 | { |
68 | skip_to_rbrace (cfile, 0); | |
69 | } | |
70 | ||
71 | void skip_to_rbrace (cfile, brace_count) | |
4615d498 | 72 | struct parse *cfile; |
cea8b5c9 | 73 | int brace_count; |
63115431 | 74 | { |
02a015fb | 75 | enum dhcp_token token; |
b1b7b521 | 76 | const char *val; |
63115431 | 77 | |
f579f39f TL |
78 | #if defined (DEBUG_TOKEN) |
79 | log_error ("skip_to_rbrace: %d\n", brace_count); | |
80 | #endif | |
63115431 TL |
81 | do { |
82 | token = peek_token (&val, cfile); | |
83 | if (token == RBRACE) { | |
efc79acb | 84 | token = next_token (&val, cfile); |
63115431 | 85 | if (brace_count) { |
63115431 TL |
86 | if (!--brace_count) |
87 | return; | |
88 | } else | |
89 | return; | |
90 | } else if (token == LBRACE) { | |
91 | brace_count++; | |
92 | } else if (token == SEMI && !brace_count) { | |
93 | token = next_token (&val, cfile); | |
94 | return; | |
796ef008 TL |
95 | } else if (token == EOL) { |
96 | /* EOL only happens when parsing /etc/resolv.conf, | |
97 | and we treat it like a semicolon because the | |
98 | resolv.conf file is line-oriented. */ | |
99 | token = next_token (&val, cfile); | |
100 | return; | |
63115431 TL |
101 | } |
102 | token = next_token (&val, cfile); | |
103 | } while (token != EOF); | |
104 | } | |
105 | ||
106 | int parse_semi (cfile) | |
4615d498 | 107 | struct parse *cfile; |
63115431 | 108 | { |
02a015fb | 109 | enum dhcp_token token; |
b1b7b521 | 110 | const char *val; |
63115431 TL |
111 | |
112 | token = next_token (&val, cfile); | |
113 | if (token != SEMI) { | |
4615d498 | 114 | parse_warn (cfile, "semicolon expected."); |
63115431 TL |
115 | skip_to_semi (cfile); |
116 | return 0; | |
117 | } | |
118 | return 1; | |
119 | } | |
120 | ||
121 | /* string-parameter :== STRING SEMI */ | |
122 | ||
123 | char *parse_string (cfile) | |
4615d498 | 124 | struct parse *cfile; |
63115431 | 125 | { |
b1b7b521 | 126 | const char *val; |
02a015fb | 127 | enum dhcp_token token; |
63115431 TL |
128 | char *s; |
129 | ||
130 | token = next_token (&val, cfile); | |
131 | if (token != STRING) { | |
4615d498 | 132 | parse_warn (cfile, "filename must be a string"); |
63115431 TL |
133 | skip_to_semi (cfile); |
134 | return (char *)0; | |
135 | } | |
fdac15d9 | 136 | s = (char *)dmalloc (strlen (val) + 1, MDL); |
63115431 | 137 | if (!s) |
8ae2d595 | 138 | log_fatal ("no memory for string %s.", val); |
63115431 TL |
139 | strcpy (s, val); |
140 | ||
141 | if (!parse_semi (cfile)) | |
142 | return (char *)0; | |
143 | return s; | |
144 | } | |
145 | ||
be6be08d TL |
146 | /* |
147 | * hostname :== IDENTIFIER | |
148 | * | IDENTIFIER DOT | |
149 | * | hostname DOT IDENTIFIER | |
150 | */ | |
796ef008 TL |
151 | |
152 | char *parse_host_name (cfile) | |
4615d498 | 153 | struct parse *cfile; |
796ef008 | 154 | { |
b1b7b521 | 155 | const char *val; |
02a015fb | 156 | enum dhcp_token token; |
b1b7b521 | 157 | unsigned len = 0; |
796ef008 TL |
158 | char *s; |
159 | char *t; | |
160 | pair c = (pair)0; | |
88ab5737 | 161 | int ltid = 0; |
796ef008 TL |
162 | |
163 | /* Read a dotted hostname... */ | |
164 | do { | |
165 | /* Read a token, which should be an identifier. */ | |
68dda014 TL |
166 | token = peek_token (&val, cfile); |
167 | if (!is_identifier (token) && token != NUMBER) | |
168 | break; | |
796ef008 | 169 | token = next_token (&val, cfile); |
68dda014 | 170 | |
796ef008 | 171 | /* Store this identifier... */ |
fdac15d9 | 172 | if (!(s = (char *)dmalloc (strlen (val) + 1, MDL))) |
8ae2d595 | 173 | log_fatal ("can't allocate temp space for hostname."); |
796ef008 TL |
174 | strcpy (s, val); |
175 | c = cons ((caddr_t)s, c); | |
176 | len += strlen (s) + 1; | |
177 | /* Look for a dot; if it's there, keep going, otherwise | |
178 | we're done. */ | |
179 | token = peek_token (&val, cfile); | |
88ab5737 | 180 | if (token == DOT) { |
796ef008 | 181 | token = next_token (&val, cfile); |
88ab5737 TL |
182 | ltid = 1; |
183 | } else | |
184 | ltid = 0; | |
796ef008 TL |
185 | } while (token == DOT); |
186 | ||
fa392aea TL |
187 | /* Should be at least one token. */ |
188 | if (!len) | |
189 | return (char *)0; | |
190 | ||
796ef008 | 191 | /* Assemble the hostname together into a string. */ |
88ab5737 | 192 | if (!(s = (char *)dmalloc (len + ltid, MDL))) |
8ae2d595 | 193 | log_fatal ("can't allocate space for hostname."); |
88ab5737 | 194 | t = s + len + ltid; |
796ef008 | 195 | *--t = 0; |
88ab5737 TL |
196 | if (ltid) |
197 | *--t = '.'; | |
796ef008 TL |
198 | while (c) { |
199 | pair cdr = c -> cdr; | |
b1b7b521 | 200 | unsigned l = strlen ((char *)(c -> car)); |
796ef008 TL |
201 | t -= l; |
202 | memcpy (t, (char *)(c -> car), l); | |
203 | /* Free up temp space. */ | |
fdac15d9 TL |
204 | dfree (c -> car, MDL); |
205 | dfree (c, MDL); | |
796ef008 TL |
206 | c = cdr; |
207 | if (t != s) | |
208 | *--t = '.'; | |
209 | } | |
210 | return s; | |
211 | } | |
212 | ||
be6be08d TL |
213 | /* ip-addr-or-hostname :== ip-address | hostname |
214 | ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER | |
215 | ||
216 | Parse an ip address or a hostname. If uniform is zero, put in | |
217 | an expr_substring node to limit hostnames that evaluate to more | |
218 | than one IP address. */ | |
219 | ||
02a015fb TL |
220 | int parse_ip_addr_or_hostname (expr, cfile, uniform) |
221 | struct expression **expr; | |
4615d498 | 222 | struct parse *cfile; |
be6be08d TL |
223 | int uniform; |
224 | { | |
b1b7b521 | 225 | const char *val; |
02a015fb | 226 | enum dhcp_token token; |
be6be08d | 227 | unsigned char addr [4]; |
b1b7b521 | 228 | unsigned len = sizeof addr; |
be6be08d | 229 | char *name; |
02a015fb | 230 | struct expression *x = (struct expression *)0; |
be6be08d TL |
231 | |
232 | token = peek_token (&val, cfile); | |
233 | if (is_identifier (token)) { | |
234 | name = parse_host_name (cfile); | |
235 | if (!name) | |
02a015fb TL |
236 | return 0; |
237 | if (!make_host_lookup (expr, name)) | |
238 | return 0; | |
239 | if (!uniform) { | |
240 | if (!make_limit (&x, *expr, 4)) | |
241 | return 0; | |
4bd8800e | 242 | expression_dereference (expr, MDL); |
02a015fb TL |
243 | *expr = x; |
244 | } | |
be6be08d TL |
245 | } else if (token == NUMBER) { |
246 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) | |
02a015fb TL |
247 | return 0; |
248 | return make_const_data (expr, addr, len, 0, 1); | |
be6be08d TL |
249 | } else { |
250 | if (token != RBRACE && token != LBRACE) | |
251 | token = next_token (&val, cfile); | |
4615d498 | 252 | parse_warn (cfile, "%s (%d): expecting IP address or hostname", |
be6be08d TL |
253 | val, token); |
254 | if (token != SEMI) | |
255 | skip_to_semi (cfile); | |
02a015fb | 256 | return 0; |
be6be08d TL |
257 | } |
258 | ||
02a015fb | 259 | return 1; |
be6be08d TL |
260 | } |
261 | ||
262 | /* | |
263 | * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER | |
264 | */ | |
265 | ||
796ef008 | 266 | int parse_ip_addr (cfile, addr) |
4615d498 | 267 | struct parse *cfile; |
796ef008 TL |
268 | struct iaddr *addr; |
269 | { | |
b1b7b521 | 270 | const char *val; |
02a015fb | 271 | enum dhcp_token token; |
796ef008 TL |
272 | |
273 | addr -> len = 4; | |
274 | if (parse_numeric_aggregate (cfile, addr -> iabuf, | |
275 | &addr -> len, DOT, 10, 8)) | |
276 | return 1; | |
277 | return 0; | |
278 | } | |
279 | ||
be6be08d TL |
280 | /* |
281 | * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI | |
282 | * hardware-type :== ETHERNET | TOKEN_RING | |
283 | */ | |
63115431 TL |
284 | |
285 | void parse_hardware_param (cfile, hardware) | |
4615d498 | 286 | struct parse *cfile; |
63115431 TL |
287 | struct hardware *hardware; |
288 | { | |
b1b7b521 | 289 | const char *val; |
02a015fb | 290 | enum dhcp_token token; |
e703795d | 291 | unsigned hlen; |
63115431 TL |
292 | unsigned char *t; |
293 | ||
294 | token = next_token (&val, cfile); | |
295 | switch (token) { | |
296 | case ETHERNET: | |
9fb2fb28 | 297 | hardware -> hbuf [0] = HTYPE_ETHER; |
63115431 TL |
298 | break; |
299 | case TOKEN_RING: | |
9fb2fb28 | 300 | hardware -> hbuf [0] = HTYPE_IEEE802; |
63115431 | 301 | break; |
cea8b5c9 | 302 | case FDDI: |
9fb2fb28 | 303 | hardware -> hbuf [0] = HTYPE_FDDI; |
cea8b5c9 | 304 | break; |
63115431 | 305 | default: |
4615d498 | 306 | parse_warn (cfile, "expecting a network hardware type"); |
63115431 TL |
307 | skip_to_semi (cfile); |
308 | return; | |
309 | } | |
310 | ||
311 | /* Parse the hardware address information. Technically, | |
312 | it would make a lot of sense to restrict the length of the | |
313 | data we'll accept here to the length of a particular hardware | |
314 | address type. Unfortunately, there are some broken clients | |
315 | out there that put bogus data in the chaddr buffer, and we accept | |
316 | that data in the lease file rather than simply failing on such | |
317 | clients. Yuck. */ | |
318 | hlen = 0; | |
319 | t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen, | |
320 | COLON, 16, 8); | |
321 | if (!t) | |
322 | return; | |
9fb2fb28 | 323 | if (hlen + 1 > sizeof hardware -> hbuf) { |
fdac15d9 | 324 | dfree (t, MDL); |
4615d498 | 325 | parse_warn (cfile, "hardware address too long"); |
63115431 | 326 | } else { |
9fb2fb28 TL |
327 | hardware -> hlen = hlen + 1; |
328 | memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen); | |
329 | if (hlen + 1 < sizeof hardware -> hbuf) | |
330 | memset (&hardware -> hbuf [hlen + 1], 0, | |
331 | (sizeof hardware -> hbuf) - hlen - 1); | |
fdac15d9 | 332 | dfree (t, MDL); |
63115431 TL |
333 | } |
334 | ||
335 | token = next_token (&val, cfile); | |
336 | if (token != SEMI) { | |
4615d498 | 337 | parse_warn (cfile, "expecting semicolon."); |
63115431 TL |
338 | skip_to_semi (cfile); |
339 | } | |
340 | } | |
341 | ||
342 | /* lease-time :== NUMBER SEMI */ | |
343 | ||
344 | void parse_lease_time (cfile, timep) | |
4615d498 | 345 | struct parse *cfile; |
63115431 TL |
346 | TIME *timep; |
347 | { | |
b1b7b521 | 348 | const char *val; |
02a015fb | 349 | enum dhcp_token token; |
63115431 TL |
350 | |
351 | token = next_token (&val, cfile); | |
352 | if (token != NUMBER) { | |
4615d498 | 353 | parse_warn (cfile, "Expecting numeric lease time"); |
63115431 TL |
354 | skip_to_semi (cfile); |
355 | return; | |
356 | } | |
4615d498 | 357 | convert_num (cfile, (unsigned char *)timep, val, 10, 32); |
63115431 TL |
358 | /* Unswap the number - convert_num returns stuff in NBO. */ |
359 | *timep = ntohl (*timep); /* XXX */ | |
360 | ||
361 | parse_semi (cfile); | |
362 | } | |
363 | ||
364 | /* No BNF for numeric aggregates - that's defined by the caller. What | |
365 | this function does is to parse a sequence of numbers seperated by | |
366 | the token specified in seperator. If max is zero, any number of | |
367 | numbers will be parsed; otherwise, exactly max numbers are | |
368 | expected. Base and size tell us how to internalize the numbers | |
369 | once they've been tokenized. */ | |
370 | ||
371 | unsigned char *parse_numeric_aggregate (cfile, buf, | |
372 | max, seperator, base, size) | |
4615d498 | 373 | struct parse *cfile; |
63115431 | 374 | unsigned char *buf; |
b1b7b521 | 375 | unsigned *max; |
63115431 TL |
376 | int seperator; |
377 | int base; | |
b1b7b521 | 378 | unsigned size; |
63115431 | 379 | { |
b1b7b521 | 380 | const char *val; |
02a015fb | 381 | enum dhcp_token token; |
63115431 | 382 | unsigned char *bufp = buf, *s, *t; |
b1b7b521 | 383 | unsigned count = 0; |
63115431 TL |
384 | pair c = (pair)0; |
385 | ||
386 | if (!bufp && *max) { | |
fdac15d9 | 387 | bufp = (unsigned char *)dmalloc (*max * size / 8, MDL); |
63115431 | 388 | if (!bufp) |
1ff8f8ea TL |
389 | log_fatal ("no space for numeric aggregate"); |
390 | s = 0; | |
63115431 TL |
391 | } else |
392 | s = bufp; | |
393 | ||
394 | do { | |
395 | if (count) { | |
396 | token = peek_token (&val, cfile); | |
397 | if (token != seperator) { | |
398 | if (!*max) | |
399 | break; | |
400 | if (token != RBRACE && token != LBRACE) | |
401 | token = next_token (&val, cfile); | |
4615d498 | 402 | parse_warn (cfile, "too few numbers."); |
63115431 TL |
403 | if (token != SEMI) |
404 | skip_to_semi (cfile); | |
405 | return (unsigned char *)0; | |
406 | } | |
407 | token = next_token (&val, cfile); | |
408 | } | |
409 | token = next_token (&val, cfile); | |
410 | ||
411 | if (token == EOF) { | |
4615d498 | 412 | parse_warn (cfile, "unexpected end of file"); |
63115431 TL |
413 | break; |
414 | } | |
415 | ||
416 | /* Allow NUMBER_OR_NAME if base is 16. */ | |
417 | if (token != NUMBER && | |
418 | (base != 16 || token != NUMBER_OR_NAME)) { | |
4615d498 | 419 | parse_warn (cfile, "expecting numeric value."); |
63115431 TL |
420 | skip_to_semi (cfile); |
421 | return (unsigned char *)0; | |
422 | } | |
423 | /* If we can, convert the number now; otherwise, build | |
424 | a linked list of all the numbers. */ | |
425 | if (s) { | |
4615d498 | 426 | convert_num (cfile, s, val, base, size); |
63115431 TL |
427 | s += size / 8; |
428 | } else { | |
fdac15d9 | 429 | t = (unsigned char *)dmalloc (strlen (val) + 1, MDL); |
63115431 | 430 | if (!t) |
8ae2d595 | 431 | log_fatal ("no temp space for number."); |
338303a4 TL |
432 | strcpy ((char *)t, val); |
433 | c = cons ((caddr_t)t, c); | |
63115431 TL |
434 | } |
435 | } while (++count != *max); | |
436 | ||
437 | /* If we had to cons up a list, convert it now. */ | |
438 | if (c) { | |
fdac15d9 | 439 | bufp = (unsigned char *)dmalloc (count * size / 8, MDL); |
63115431 | 440 | if (!bufp) |
1ff8f8ea | 441 | log_fatal ("no space for numeric aggregate."); |
63115431 TL |
442 | s = bufp + count - size / 8; |
443 | *max = count; | |
444 | } | |
445 | while (c) { | |
446 | pair cdr = c -> cdr; | |
4615d498 | 447 | convert_num (cfile, s, (char *)(c -> car), base, size); |
63115431 TL |
448 | s -= size / 8; |
449 | /* Free up temp space. */ | |
fdac15d9 TL |
450 | dfree (c -> car, MDL); |
451 | dfree (c, MDL); | |
63115431 TL |
452 | c = cdr; |
453 | } | |
454 | return bufp; | |
455 | } | |
456 | ||
4615d498 TL |
457 | void convert_num (cfile, buf, str, base, size) |
458 | struct parse *cfile; | |
63115431 | 459 | unsigned char *buf; |
b1b7b521 | 460 | const char *str; |
63115431 | 461 | int base; |
b1b7b521 | 462 | unsigned size; |
63115431 | 463 | { |
b1b7b521 | 464 | const char *ptr = str; |
63115431 TL |
465 | int negative = 0; |
466 | u_int32_t val = 0; | |
467 | int tval; | |
468 | int max; | |
469 | ||
470 | if (*ptr == '-') { | |
471 | negative = 1; | |
472 | ++ptr; | |
473 | } | |
474 | ||
475 | /* If base wasn't specified, figure it out from the data. */ | |
476 | if (!base) { | |
477 | if (ptr [0] == '0') { | |
478 | if (ptr [1] == 'x') { | |
479 | base = 16; | |
480 | ptr += 2; | |
481 | } else if (isascii (ptr [1]) && isdigit (ptr [1])) { | |
482 | base = 8; | |
483 | ptr += 1; | |
484 | } else { | |
485 | base = 10; | |
486 | } | |
487 | } else { | |
488 | base = 10; | |
489 | } | |
490 | } | |
491 | ||
492 | do { | |
493 | tval = *ptr++; | |
494 | /* XXX assumes ASCII... */ | |
495 | if (tval >= 'a') | |
496 | tval = tval - 'a' + 10; | |
497 | else if (tval >= 'A') | |
498 | tval = tval - 'A' + 10; | |
499 | else if (tval >= '0') | |
500 | tval -= '0'; | |
501 | else { | |
4615d498 | 502 | parse_warn (cfile, "Bogus number: %s.", str); |
63115431 TL |
503 | break; |
504 | } | |
505 | if (tval >= base) { | |
4615d498 TL |
506 | parse_warn (cfile, |
507 | "Bogus number %s: digit %d not in base %d", | |
f420e08c | 508 | str, tval, base); |
63115431 TL |
509 | break; |
510 | } | |
511 | val = val * base + tval; | |
512 | } while (*ptr); | |
513 | ||
514 | if (negative) | |
515 | max = (1 << (size - 1)); | |
516 | else | |
517 | max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); | |
518 | if (val > max) { | |
519 | switch (base) { | |
520 | case 8: | |
4615d498 | 521 | parse_warn (cfile, |
06afba54 | 522 | "%s%lo exceeds max (%d) for precision.", |
b3d594dd TL |
523 | negative ? "-" : "", |
524 | (unsigned long)val, max); | |
63115431 TL |
525 | break; |
526 | case 16: | |
4615d498 | 527 | parse_warn (cfile, |
06afba54 | 528 | "%s%lx exceeds max (%d) for precision.", |
b3d594dd TL |
529 | negative ? "-" : "", |
530 | (unsigned long)val, max); | |
63115431 TL |
531 | break; |
532 | default: | |
4615d498 | 533 | parse_warn (cfile, |
06afba54 | 534 | "%s%lu exceeds max (%d) for precision.", |
b3d594dd TL |
535 | negative ? "-" : "", |
536 | (unsigned long)val, max); | |
63115431 TL |
537 | break; |
538 | } | |
539 | } | |
540 | ||
541 | if (negative) { | |
542 | switch (size) { | |
543 | case 8: | |
544 | *buf = -(unsigned long)val; | |
545 | break; | |
546 | case 16: | |
b1b7b521 | 547 | putShort (buf, -(long)val); |
63115431 TL |
548 | break; |
549 | case 32: | |
b1b7b521 | 550 | putLong (buf, -(long)val); |
63115431 TL |
551 | break; |
552 | default: | |
4615d498 TL |
553 | parse_warn (cfile, |
554 | "Unexpected integer size: %d\n", size); | |
63115431 TL |
555 | break; |
556 | } | |
557 | } else { | |
558 | switch (size) { | |
559 | case 8: | |
560 | *buf = (u_int8_t)val; | |
561 | break; | |
562 | case 16: | |
563 | putUShort (buf, (u_int16_t)val); | |
564 | break; | |
565 | case 32: | |
566 | putULong (buf, val); | |
567 | break; | |
568 | default: | |
4615d498 TL |
569 | parse_warn (cfile, |
570 | "Unexpected integer size: %d\n", size); | |
63115431 TL |
571 | break; |
572 | } | |
573 | } | |
574 | } | |
575 | ||
be6be08d TL |
576 | /* |
577 | * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER | |
a82abfc7 TL |
578 | * NUMBER COLON NUMBER COLON NUMBER SEMI | |
579 | * NUMBER NUMBER SLASH NUMBER SLASH NUMBER | |
580 | * NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI | | |
be1ee858 | 581 | * NEVER |
be6be08d | 582 | * |
a82abfc7 TL |
583 | * Dates are stored in GMT or with a timezone offset; first number is day |
584 | * of week; next is year/month/day; next is hours:minutes:seconds on a | |
585 | * 24-hour clock, followed by the timezone offset in seconds, which is | |
586 | * optional. | |
be6be08d | 587 | */ |
63115431 TL |
588 | |
589 | TIME parse_date (cfile) | |
4615d498 | 590 | struct parse *cfile; |
63115431 TL |
591 | { |
592 | struct tm tm; | |
593 | int guess; | |
a82abfc7 | 594 | int tzoff, wday, year, mon, mday, hour, min, sec; |
b1b7b521 | 595 | const char *val; |
02a015fb | 596 | enum dhcp_token token; |
63115431 TL |
597 | static int months [11] = { 31, 59, 90, 120, 151, 181, |
598 | 212, 243, 273, 304, 334 }; | |
599 | ||
be1ee858 | 600 | /* Day of week, or "never"... */ |
63115431 | 601 | token = next_token (&val, cfile); |
be1ee858 TL |
602 | if (token == NEVER) { |
603 | if (!parse_semi (cfile)) | |
604 | return 0; | |
605 | return MAX_TIME; | |
606 | } | |
607 | ||
63115431 | 608 | if (token != NUMBER) { |
4615d498 | 609 | parse_warn (cfile, "numeric day of week expected."); |
63115431 TL |
610 | if (token != SEMI) |
611 | skip_to_semi (cfile); | |
612 | return (TIME)0; | |
613 | } | |
a82abfc7 | 614 | wday = atoi (val); |
63115431 TL |
615 | |
616 | /* Year... */ | |
617 | token = next_token (&val, cfile); | |
618 | if (token != NUMBER) { | |
4615d498 | 619 | parse_warn (cfile, "numeric year expected."); |
63115431 TL |
620 | if (token != SEMI) |
621 | skip_to_semi (cfile); | |
622 | return (TIME)0; | |
623 | } | |
edca2b1a TL |
624 | |
625 | /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until | |
626 | somebody invents a time machine, I think we can safely disregard | |
627 | it. This actually works around a stupid Y2K bug that was present | |
628 | in a very early beta release of dhcpd. */ | |
a82abfc7 TL |
629 | year = atoi (val); |
630 | if (year > 1900) | |
631 | year -= 1900; | |
63115431 TL |
632 | |
633 | /* Slash seperating year from month... */ | |
634 | token = next_token (&val, cfile); | |
635 | if (token != SLASH) { | |
4615d498 TL |
636 | parse_warn (cfile, |
637 | "expected slash seperating year from month."); | |
63115431 TL |
638 | if (token != SEMI) |
639 | skip_to_semi (cfile); | |
640 | return (TIME)0; | |
641 | } | |
642 | ||
643 | /* Month... */ | |
644 | token = next_token (&val, cfile); | |
645 | if (token != NUMBER) { | |
4615d498 | 646 | parse_warn (cfile, "numeric month expected."); |
63115431 TL |
647 | if (token != SEMI) |
648 | skip_to_semi (cfile); | |
649 | return (TIME)0; | |
650 | } | |
a82abfc7 | 651 | mon = atoi (val) - 1; |
63115431 TL |
652 | |
653 | /* Slash seperating month from day... */ | |
654 | token = next_token (&val, cfile); | |
655 | if (token != SLASH) { | |
4615d498 TL |
656 | parse_warn (cfile, |
657 | "expected slash seperating month from day."); | |
63115431 TL |
658 | if (token != SEMI) |
659 | skip_to_semi (cfile); | |
660 | return (TIME)0; | |
661 | } | |
662 | ||
663 | /* Month... */ | |
664 | token = next_token (&val, cfile); | |
665 | if (token != NUMBER) { | |
4615d498 | 666 | parse_warn (cfile, "numeric day of month expected."); |
63115431 TL |
667 | if (token != SEMI) |
668 | skip_to_semi (cfile); | |
669 | return (TIME)0; | |
670 | } | |
a82abfc7 | 671 | mday = atoi (val); |
63115431 TL |
672 | |
673 | /* Hour... */ | |
674 | token = next_token (&val, cfile); | |
675 | if (token != NUMBER) { | |
4615d498 | 676 | parse_warn (cfile, "numeric hour expected."); |
63115431 TL |
677 | if (token != SEMI) |
678 | skip_to_semi (cfile); | |
679 | return (TIME)0; | |
680 | } | |
a82abfc7 | 681 | hour = atoi (val); |
63115431 TL |
682 | |
683 | /* Colon seperating hour from minute... */ | |
684 | token = next_token (&val, cfile); | |
685 | if (token != COLON) { | |
4615d498 TL |
686 | parse_warn (cfile, |
687 | "expected colon seperating hour from minute."); | |
63115431 TL |
688 | if (token != SEMI) |
689 | skip_to_semi (cfile); | |
690 | return (TIME)0; | |
691 | } | |
692 | ||
693 | /* Minute... */ | |
694 | token = next_token (&val, cfile); | |
695 | if (token != NUMBER) { | |
4615d498 | 696 | parse_warn (cfile, "numeric minute expected."); |
63115431 TL |
697 | if (token != SEMI) |
698 | skip_to_semi (cfile); | |
699 | return (TIME)0; | |
700 | } | |
a82abfc7 | 701 | min = atoi (val); |
63115431 TL |
702 | |
703 | /* Colon seperating minute from second... */ | |
704 | token = next_token (&val, cfile); | |
705 | if (token != COLON) { | |
4615d498 TL |
706 | parse_warn (cfile, |
707 | "expected colon seperating hour from minute."); | |
63115431 TL |
708 | if (token != SEMI) |
709 | skip_to_semi (cfile); | |
710 | return (TIME)0; | |
711 | } | |
712 | ||
713 | /* Minute... */ | |
714 | token = next_token (&val, cfile); | |
715 | if (token != NUMBER) { | |
4615d498 | 716 | parse_warn (cfile, "numeric minute expected."); |
63115431 TL |
717 | if (token != SEMI) |
718 | skip_to_semi (cfile); | |
719 | return (TIME)0; | |
720 | } | |
a82abfc7 | 721 | sec = atoi (val); |
63115431 | 722 | |
a82abfc7 TL |
723 | token = peek_token (&val, cfile); |
724 | if (token == NUMBER) { | |
725 | token = next_token (&val, cfile); | |
726 | tzoff = atoi (val); | |
727 | } else | |
728 | tzoff = 0; | |
63115431 TL |
729 | |
730 | /* Make sure the date ends in a semicolon... */ | |
25541f2f | 731 | if (!parse_semi (cfile)) |
63115431 | 732 | return 0; |
63115431 TL |
733 | |
734 | /* Guess the time value... */ | |
a82abfc7 TL |
735 | guess = ((((((365 * (year - 70) + /* Days in years since '70 */ |
736 | (year - 69) / 4 + /* Leap days since '70 */ | |
737 | (mon /* Days in months this year */ | |
738 | ? months [mon - 1] | |
63115431 | 739 | : 0) + |
a82abfc7 TL |
740 | (mon > 1 && /* Leap day this year */ |
741 | !((year - 72) & 3)) + | |
742 | mday - 1) * 24) + /* Day of month */ | |
743 | hour) * 60) + | |
744 | min) * 60) + sec + tzoff; | |
63115431 TL |
745 | |
746 | /* This guess could be wrong because of leap seconds or other | |
747 | weirdness we don't know about that the system does. For | |
748 | now, we're just going to accept the guess, but at some point | |
749 | it might be nice to do a successive approximation here to | |
750 | get an exact value. Even if the error is small, if the | |
751 | server is restarted frequently (and thus the lease database | |
752 | is reread), the error could accumulate into something | |
753 | significant. */ | |
754 | ||
755 | return guess; | |
756 | } | |
4761e04b | 757 | |
be6be08d TL |
758 | /* |
759 | * option-name :== IDENTIFIER | | |
760 | IDENTIFIER . IDENTIFIER | |
761 | */ | |
762 | ||
b1b7b521 | 763 | struct option *parse_option_name (cfile, allocate, known) |
4615d498 | 764 | struct parse *cfile; |
6b4b0ec7 | 765 | int allocate; |
b1b7b521 | 766 | int *known; |
4761e04b | 767 | { |
b1b7b521 | 768 | const char *val; |
02a015fb | 769 | enum dhcp_token token; |
6b4b0ec7 | 770 | char *uname; |
4761e04b TL |
771 | struct universe *universe; |
772 | struct option *option; | |
773 | ||
774 | token = next_token (&val, cfile); | |
775 | if (!is_identifier (token)) { | |
4615d498 TL |
776 | parse_warn (cfile, |
777 | "expecting identifier after option keyword."); | |
4761e04b TL |
778 | if (token != SEMI) |
779 | skip_to_semi (cfile); | |
780 | return (struct option *)0; | |
781 | } | |
fdac15d9 | 782 | uname = dmalloc (strlen (val) + 1, MDL); |
6b4b0ec7 TL |
783 | if (!uname) |
784 | log_fatal ("no memory for uname information."); | |
785 | strcpy (uname, val); | |
4761e04b TL |
786 | token = peek_token (&val, cfile); |
787 | if (token == DOT) { | |
788 | /* Go ahead and take the DOT token... */ | |
789 | token = next_token (&val, cfile); | |
790 | ||
791 | /* The next token should be an identifier... */ | |
792 | token = next_token (&val, cfile); | |
793 | if (!is_identifier (token)) { | |
4615d498 | 794 | parse_warn (cfile, "expecting identifier after '.'"); |
4761e04b TL |
795 | if (token != SEMI) |
796 | skip_to_semi (cfile); | |
797 | return (struct option *)0; | |
798 | } | |
799 | ||
800 | /* Look up the option name hash table for the specified | |
6b4b0ec7 | 801 | uname. */ |
20916cae TL |
802 | universe = (struct universe *)0; |
803 | if (!universe_hash_lookup (&universe, universe_hash, | |
804 | uname, 0, MDL)) { | |
4615d498 | 805 | parse_warn (cfile, "no option space named %s.", uname); |
4761e04b TL |
806 | skip_to_semi (cfile); |
807 | return (struct option *)0; | |
808 | } | |
809 | } else { | |
810 | /* Use the default hash table, which contains all the | |
811 | standard dhcp option names. */ | |
6b4b0ec7 | 812 | val = uname; |
4761e04b TL |
813 | universe = &dhcp_universe; |
814 | } | |
815 | ||
816 | /* Look up the actual option info... */ | |
20916cae TL |
817 | option = (struct option *)0; |
818 | option_hash_lookup (&option, universe -> hash, val, 0, MDL); | |
4761e04b TL |
819 | |
820 | /* If we didn't get an option structure, it's an undefined option. */ | |
b1b7b521 TL |
821 | if (option) { |
822 | *known = 1; | |
823 | } else { | |
6b4b0ec7 TL |
824 | /* If we've been told to allocate, that means that this |
825 | (might) be an option code definition, so we'll create | |
826 | an option structure just in case. */ | |
827 | if (allocate) { | |
4bd8800e | 828 | option = new_option (MDL); |
6b4b0ec7 TL |
829 | if (val == uname) |
830 | option -> name = val; | |
831 | else { | |
b1b7b521 | 832 | char *s; |
fdac15d9 TL |
833 | dfree (uname, MDL); |
834 | s = dmalloc (strlen (val) + 1, MDL); | |
b1b7b521 | 835 | if (!s) |
4615d498 TL |
836 | log_fatal ("no memory for option %s.%s", |
837 | universe -> name, val); | |
b1b7b521 TL |
838 | strcpy (s, val); |
839 | option -> name = s; | |
6b4b0ec7 TL |
840 | } |
841 | option -> universe = universe; | |
b1b7b521 | 842 | option -> code = 0; |
6b4b0ec7 TL |
843 | return option; |
844 | } | |
845 | if (val == uname) | |
4615d498 | 846 | parse_warn (cfile, "no option named %s", val); |
4761e04b | 847 | else |
4615d498 | 848 | parse_warn (cfile, "no option named %s in space %s", |
6b4b0ec7 | 849 | val, uname); |
4761e04b TL |
850 | skip_to_semi (cfile); |
851 | return (struct option *)0; | |
852 | } | |
853 | ||
854 | /* Free the initial identifier token. */ | |
fdac15d9 | 855 | dfree (uname, MDL); |
4761e04b TL |
856 | return option; |
857 | } | |
858 | ||
52c9d530 TL |
859 | /* IDENTIFIER SEMI */ |
860 | ||
861 | void parse_option_space_decl (cfile) | |
4615d498 | 862 | struct parse *cfile; |
52c9d530 TL |
863 | { |
864 | int token; | |
b1b7b521 | 865 | const char *val; |
52c9d530 | 866 | struct universe **ua, *nu; |
b1b7b521 | 867 | char *s; |
52c9d530 TL |
868 | |
869 | next_token (&val, cfile); /* Discard the SPACE token, which was | |
870 | checked by the caller. */ | |
871 | token = next_token (&val, cfile); | |
872 | if (!is_identifier (token)) { | |
4615d498 | 873 | parse_warn (cfile, "expecting identifier."); |
52c9d530 TL |
874 | skip_to_semi (cfile); |
875 | return; | |
876 | } | |
4bd8800e | 877 | nu = new_universe (MDL); |
52c9d530 TL |
878 | if (!nu) |
879 | log_fatal ("No memory for new option space."); | |
880 | ||
881 | /* Set up the server option universe... */ | |
fdac15d9 | 882 | s = dmalloc (strlen (val) + 1, MDL); |
b1b7b521 | 883 | if (!s) |
52c9d530 | 884 | log_fatal ("No memory for new option space name."); |
b1b7b521 TL |
885 | strcpy (s, val); |
886 | nu -> name = s; | |
52c9d530 TL |
887 | nu -> lookup_func = lookup_hashed_option; |
888 | nu -> option_state_dereference = | |
889 | hashed_option_state_dereference; | |
890 | nu -> get_func = hashed_option_get; | |
891 | nu -> set_func = hashed_option_set; | |
892 | nu -> save_func = save_hashed_option; | |
893 | nu -> delete_func = delete_hashed_option; | |
894 | nu -> encapsulate = hashed_option_space_encapsulate; | |
895 | nu -> length_size = 1; | |
896 | nu -> tag_size = 1; | |
897 | nu -> store_tag = putUChar; | |
898 | nu -> store_length = putUChar; | |
899 | nu -> index = universe_count++; | |
900 | if (nu -> index >= universe_max) { | |
fdac15d9 | 901 | ua = dmalloc (universe_max * 2 * sizeof *ua, MDL); |
52c9d530 TL |
902 | if (!ua) |
903 | log_fatal ("No memory to expand option space array."); | |
904 | memcpy (ua, universes, universe_max * sizeof *ua); | |
905 | universe_max *= 2; | |
fdac15d9 | 906 | dfree (universes, MDL); |
52c9d530 TL |
907 | universes = ua; |
908 | } | |
909 | universes [nu -> index] = nu; | |
7d9784f6 | 910 | nu -> hash = new_hash (0, 0, 1); |
52c9d530 TL |
911 | if (!nu -> hash) |
912 | log_fatal ("Can't allocate %s option hash table.", nu -> name); | |
20916cae | 913 | universe_hash_add (universe_hash, nu -> name, 0, nu, MDL); |
52c9d530 TL |
914 | parse_semi (cfile); |
915 | } | |
916 | ||
6b4b0ec7 TL |
917 | /* This is faked up to look good right now. Ideally, this should do a |
918 | recursive parse and allow arbitrary data structure definitions, but for | |
919 | now it just allows you to specify a single type, an array of single types, | |
920 | a sequence of types, or an array of sequences of types. | |
921 | ||
922 | ocd :== NUMBER EQUALS ocsd SEMI | |
923 | ||
924 | ocsd :== ocsd_type | | |
925 | ocsd_type_sequence | | |
d8fc5060 | 926 | ARRAY OF ocsd_simple_type_sequence |
6b4b0ec7 TL |
927 | |
928 | ocsd_type_sequence :== LBRACE ocsd_types RBRACE | |
929 | ||
d8fc5060 TL |
930 | ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE |
931 | ||
932 | ocsd_types :== ocsd_type | | |
933 | ocsd_types ocsd_type | |
934 | ||
935 | ocsd_type :== ocsd_simple_type | | |
936 | ARRAY OF ocsd_simple_type | |
937 | ||
938 | ocsd_simple_types :== ocsd_simple_type | | |
939 | ocsd_simple_types ocsd_simple_type | |
940 | ||
941 | ocsd_simple_type :== BOOLEAN | | |
942 | INTEGER NUMBER | | |
943 | SIGNED INTEGER NUMBER | | |
944 | UNSIGNED INTEGER NUMBER | | |
945 | IP-ADDRESS | | |
946 | TEXT | | |
947 | STRING */ | |
6b4b0ec7 TL |
948 | |
949 | int parse_option_code_definition (cfile, option) | |
4615d498 | 950 | struct parse *cfile; |
6b4b0ec7 TL |
951 | struct option *option; |
952 | { | |
b1b7b521 | 953 | const char *val; |
6b4b0ec7 | 954 | enum dhcp_token token; |
b1b7b521 | 955 | unsigned arrayp = 0; |
6b4b0ec7 TL |
956 | int recordp = 0; |
957 | int no_more_in_record = 0; | |
958 | char tokbuf [128]; | |
b1b7b521 | 959 | unsigned tokix = 0; |
6b4b0ec7 TL |
960 | char type; |
961 | int code; | |
962 | int is_signed; | |
b1b7b521 | 963 | char *s; |
6b4b0ec7 TL |
964 | |
965 | /* Parse the option code. */ | |
966 | token = next_token (&val, cfile); | |
967 | if (token != NUMBER) { | |
4615d498 | 968 | parse_warn (cfile, "expecting option code number."); |
6b4b0ec7 TL |
969 | skip_to_semi (cfile); |
970 | return 0; | |
971 | } | |
972 | option -> code = atoi (val); | |
973 | ||
974 | token = next_token (&val, cfile); | |
975 | if (token != EQUAL) { | |
4615d498 | 976 | parse_warn (cfile, "expecting \"=\""); |
6b4b0ec7 TL |
977 | skip_to_semi (cfile); |
978 | return 0; | |
979 | } | |
980 | ||
981 | /* See if this is an array. */ | |
982 | token = next_token (&val, cfile); | |
983 | if (token == ARRAY) { | |
984 | token = next_token (&val, cfile); | |
985 | if (token != OF) { | |
4615d498 | 986 | parse_warn (cfile, "expecting \"of\"."); |
6b4b0ec7 TL |
987 | skip_to_semi (cfile); |
988 | return 0; | |
989 | } | |
990 | arrayp = 1; | |
991 | token = next_token (&val, cfile); | |
992 | } | |
993 | ||
994 | if (token == LBRACE) { | |
995 | recordp = 1; | |
996 | token = next_token (&val, cfile); | |
997 | } | |
998 | ||
999 | /* At this point we're expecting a data type. */ | |
1000 | next_type: | |
1001 | switch (token) { | |
d8fc5060 TL |
1002 | case ARRAY: |
1003 | if (arrayp) { | |
1004 | parse_warn (cfile, "no nested arrays."); | |
1005 | skip_to_rbrace (cfile, recordp); | |
1006 | if (recordp) | |
1007 | skip_to_semi (cfile); | |
1008 | return 0; | |
1009 | } | |
1010 | token = next_token (&val, cfile); | |
1011 | if (token != OF) { | |
1012 | parse_warn (cfile, "expecting \"of\"."); | |
1013 | skip_to_semi (cfile); | |
1014 | return 0; | |
1015 | } | |
1016 | arrayp = recordp + 1; | |
1017 | token = next_token (&val, cfile); | |
1018 | if ((recordp) && (token == LBRACE)) { | |
1019 | parse_warn (cfile, | |
1020 | "only uniform array inside record."); | |
1021 | skip_to_rbrace (cfile, recordp + 1); | |
1022 | skip_to_semi (cfile); | |
1023 | return 0; | |
1024 | } | |
1025 | goto next_type; | |
6b4b0ec7 TL |
1026 | case BOOLEAN: |
1027 | type = 'f'; | |
1028 | break; | |
1029 | case INTEGER: | |
1030 | is_signed = 1; | |
1031 | parse_integer: | |
1032 | token = next_token (&val, cfile); | |
1033 | if (token != NUMBER) { | |
4615d498 | 1034 | parse_warn (cfile, "expecting number."); |
6b4b0ec7 TL |
1035 | skip_to_rbrace (cfile, recordp); |
1036 | if (recordp) | |
1037 | skip_to_semi (cfile); | |
1038 | return 0; | |
1039 | } | |
1040 | switch (atoi (val)) { | |
1041 | case 8: | |
1042 | type = is_signed ? 'b' : 'B'; | |
1043 | break; | |
1044 | case 16: | |
1045 | type = is_signed ? 's' : 'S'; | |
1046 | break; | |
1047 | case 32: | |
1048 | type = is_signed ? 'l' : 'L'; | |
1049 | break; | |
1050 | default: | |
4615d498 TL |
1051 | parse_warn (cfile, |
1052 | "%s bit precision is not supported.", val); | |
6b4b0ec7 TL |
1053 | skip_to_rbrace (cfile, recordp); |
1054 | if (recordp) | |
1055 | skip_to_semi (cfile); | |
1056 | return 0; | |
1057 | } | |
1058 | break; | |
1059 | case SIGNED: | |
1060 | is_signed = 1; | |
1061 | parse_signed: | |
1062 | token = next_token (&val, cfile); | |
1063 | if (token != INTEGER) { | |
4615d498 | 1064 | parse_warn (cfile, "expecting \"integer\" keyword."); |
6b4b0ec7 TL |
1065 | skip_to_rbrace (cfile, recordp); |
1066 | if (recordp) | |
1067 | skip_to_semi (cfile); | |
1068 | return 0; | |
1069 | } | |
1070 | goto parse_integer; | |
1071 | case UNSIGNED: | |
1072 | is_signed = 0; | |
1073 | goto parse_signed; | |
1074 | ||
1075 | case IP_ADDRESS: | |
1076 | type = 'I'; | |
1077 | break; | |
1078 | case TEXT: | |
1079 | type = 't'; | |
1080 | no_arrays: | |
1081 | if (arrayp) { | |
4615d498 | 1082 | parse_warn (cfile, "arrays of text strings not %s", |
6b4b0ec7 TL |
1083 | "yet supported."); |
1084 | skip_to_rbrace (cfile, recordp); | |
1085 | if (recordp) | |
1086 | skip_to_semi (cfile); | |
1087 | return 0; | |
1088 | } | |
1089 | no_more_in_record = 1; | |
1090 | break; | |
ef91cb39 | 1091 | case STRING_TOKEN: |
6b4b0ec7 TL |
1092 | type = 'X'; |
1093 | goto no_arrays; | |
1094 | ||
1095 | default: | |
4615d498 | 1096 | parse_warn (cfile, "unknown data type %s", val); |
6b4b0ec7 TL |
1097 | skip_to_rbrace (cfile, recordp); |
1098 | if (recordp) | |
1099 | skip_to_semi (cfile); | |
1100 | return 0; | |
1101 | } | |
1102 | ||
1103 | if (tokix == sizeof tokbuf) { | |
4615d498 | 1104 | parse_warn (cfile, "too many types in record."); |
6b4b0ec7 TL |
1105 | skip_to_rbrace (cfile, recordp); |
1106 | if (recordp) | |
1107 | skip_to_semi (cfile); | |
1108 | return 0; | |
1109 | } | |
1110 | tokbuf [tokix++] = type; | |
1111 | ||
1112 | if (recordp) { | |
1113 | token = next_token (&val, cfile); | |
d8fc5060 TL |
1114 | if (arrayp > recordp) { |
1115 | if (tokix == sizeof tokbuf) { | |
1116 | parse_warn (cfile, | |
1117 | "too many types in record."); | |
1118 | skip_to_rbrace (cfile, 1); | |
1119 | skip_to_semi (cfile); | |
1120 | return 0; | |
1121 | } | |
1122 | arrayp = 0; | |
1123 | tokbuf[tokix++] = 'a'; | |
1124 | } | |
6b4b0ec7 TL |
1125 | if (token == COMMA) { |
1126 | if (no_more_in_record) { | |
4615d498 TL |
1127 | parse_warn (cfile, |
1128 | "%s must be at end of record.", | |
6b4b0ec7 TL |
1129 | type == 't' ? "text" : "string"); |
1130 | skip_to_rbrace (cfile, 1); | |
1131 | if (recordp) | |
1132 | skip_to_semi (cfile); | |
1133 | return 0; | |
1134 | } | |
1135 | token = next_token (&val, cfile); | |
1136 | goto next_type; | |
1137 | } | |
1138 | if (token != RBRACE) { | |
4615d498 | 1139 | parse_warn (cfile, "expecting right brace."); |
6b4b0ec7 TL |
1140 | skip_to_rbrace (cfile, 1); |
1141 | if (recordp) | |
1142 | skip_to_semi (cfile); | |
1143 | return 0; | |
1144 | } | |
1145 | } | |
1146 | if (!parse_semi (cfile)) { | |
4615d498 | 1147 | parse_warn (cfile, "semicolon expected."); |
6b4b0ec7 TL |
1148 | skip_to_semi (cfile); |
1149 | if (recordp) | |
1150 | skip_to_semi (cfile); | |
1151 | return 0; | |
1152 | } | |
d8fc5060 | 1153 | s = dmalloc (tokix + ((arrayp) ? 1 : 0) + 1, MDL); |
b1b7b521 | 1154 | if (!s) |
6b4b0ec7 | 1155 | log_fatal ("no memory for option format."); |
b1b7b521 | 1156 | memcpy (s, tokbuf, tokix); |
6b4b0ec7 | 1157 | if (arrayp) |
d8fc5060 | 1158 | s [tokix++] = (arrayp > recordp) ? 'a' : 'A'; |
b1b7b521 TL |
1159 | s [tokix] = 0; |
1160 | option -> format = s; | |
6b4b0ec7 TL |
1161 | if (option -> universe -> options [option -> code]) { |
1162 | /* XXX Free the option, but we can't do that now because they | |
1163 | XXX may start out static. */ | |
1164 | } | |
1165 | option -> universe -> options [option -> code] = option; | |
20916cae | 1166 | option_hash_add (option -> universe -> hash, |
165bce70 | 1167 | (const char *)option -> name, |
20916cae | 1168 | 0, option, MDL); |
6b4b0ec7 TL |
1169 | return 1; |
1170 | } | |
1171 | ||
028b1f6a TL |
1172 | /* |
1173 | * base64 :== NUMBER_OR_STRING | |
1174 | */ | |
1175 | ||
1176 | int parse_base64 (data, cfile) | |
1177 | struct data_string *data; | |
1178 | struct parse *cfile; | |
1179 | { | |
1180 | enum dhcp_token token; | |
1181 | const char *val; | |
8f01f9ec | 1182 | int i, j, k; |
028b1f6a | 1183 | unsigned acc = 0; |
6b474b5b TL |
1184 | static unsigned char |
1185 | from64 [] = {64, 64, 64, 64, 64, 64, 64, 64, /* \"#$%&' */ | |
1186 | 64, 64, 64, 62, 64, 64, 64, 63, /* ()*+,-./ */ | |
1187 | 52, 53, 54, 55, 56, 57, 58, 59, /* 01234567 */ | |
1188 | 60, 61, 64, 64, 64, 64, 64, 64, /* 90:;<=>? */ | |
1189 | 64, 0, 1, 2, 3, 4, 5, 6, /* @ABCDEFG */ | |
1190 | 7, 8, 9, 10, 11, 12, 13, 14, /* HIJKLMNO */ | |
1191 | 15, 16, 17, 18, 19, 20, 21, 22, /* PQRSTUVW */ | |
1192 | 23, 24, 25, 64, 64, 64, 64, 64, /* XYZ[\]^_ */ | |
1193 | 64, 26, 27, 28, 29, 30, 31, 32, /* 'abcdefg */ | |
1194 | 33, 34, 35, 36, 37, 38, 39, 40, /* hijklmno */ | |
1195 | 41, 42, 43, 44, 45, 46, 47, 48, /* pqrstuvw */ | |
1196 | 59, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~ */ | |
8f01f9ec TL |
1197 | struct string_list *bufs = (struct string_list *)0, |
1198 | *last = (struct string_list *)0, | |
1199 | *t; | |
1200 | int cc = 0; | |
1201 | int terminated = 0; | |
028b1f6a | 1202 | |
8f01f9ec | 1203 | token = peek_token (&val, cfile); |
028b1f6a | 1204 | if (token == STRING) { |
8f01f9ec | 1205 | token = next_token (&val, cfile); |
028b1f6a TL |
1206 | data -> len = strlen (val) + 1; |
1207 | if (!buffer_allocate (&data -> buffer, data -> len, MDL)) { | |
1208 | parse_warn (cfile, "can't allocate string buffer"); | |
1209 | return 0; | |
1210 | } | |
13b0934e | 1211 | strcpy ((char *)data -> buffer -> data, val); |
028b1f6a TL |
1212 | data -> terminated = 1; |
1213 | data -> data = data -> buffer -> data; | |
1214 | return 1; | |
1215 | } | |
1216 | ||
8f01f9ec TL |
1217 | /* It's possible for a + or a / to cause a base64 quantity to be |
1218 | tokenized into more than one token, so we have to parse them all | |
1219 | in before decoding. */ | |
1220 | do { | |
1221 | int l; | |
1222 | ||
1223 | token = next_token (&val, cfile); | |
1224 | l = strlen (val); | |
1225 | t = dmalloc (l + sizeof *t, MDL); | |
1226 | if (!t) | |
1227 | log_fatal ("no memory for base64 buffer."); | |
1228 | memset (t, 0, (sizeof *t) - 1); | |
1229 | strcpy (t -> string, val); | |
1230 | cc += l; | |
1231 | if (last) | |
1232 | last -> next = t; | |
1233 | else | |
1234 | bufs = t; | |
1235 | last = t; | |
1236 | token = peek_token (&val, cfile); | |
1237 | } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL || | |
1238 | token == NUMBER || token == PLUS || token == SLASH); | |
1239 | ||
1240 | data -> len = cc; | |
028b1f6a TL |
1241 | data -> len = (data -> len * 3) / 4; |
1242 | if (!buffer_allocate (&data -> buffer, data -> len, MDL)) { | |
1243 | parse_warn (cfile, "can't allocate buffer for base64 data."); | |
1244 | data -> len = 0; | |
1245 | data -> data = (unsigned char *)0; | |
1246 | return 0; | |
1247 | } | |
1248 | ||
8f01f9ec TL |
1249 | j = k = 0; |
1250 | for (t = bufs; t; t = t -> next) { | |
1251 | for (i = 0; t -> string [i]; i++) { | |
1252 | unsigned foo = t -> string [i]; | |
1253 | if (terminated && foo != '=') { | |
1254 | parse_warn (cfile, | |
1255 | "stuff after base64 '=' terminator: %s.", | |
1256 | &t -> string [i]); | |
1257 | goto bad; | |
1258 | } | |
028b1f6a TL |
1259 | if (foo < ' ' || foo > 'z') { |
1260 | bad64: | |
1261 | parse_warn (cfile, | |
8f01f9ec TL |
1262 | "invalid base64 character %d.", |
1263 | t -> string [i]); | |
1264 | bad: | |
028b1f6a | 1265 | data_string_forget (data, MDL); |
8f01f9ec | 1266 | goto out; |
028b1f6a | 1267 | } |
8f01f9ec TL |
1268 | if (foo == '=') |
1269 | terminated = 1; | |
1270 | else { | |
1271 | foo = from64 [foo - ' ']; | |
1272 | if (foo == 64) | |
1273 | goto bad64; | |
1274 | acc = (acc << 6) + foo; | |
1275 | switch (k % 4) { | |
1276 | case 0: | |
1277 | break; | |
1278 | case 1: | |
1279 | data -> buffer -> data [j++] = (acc >> 4); | |
1280 | acc = acc & 0x0f; | |
1281 | break; | |
1282 | ||
1283 | case 2: | |
1284 | data -> buffer -> data [j++] = (acc >> 2); | |
1285 | acc = acc & 0x03; | |
1286 | break; | |
1287 | case 3: | |
1288 | data -> buffer -> data [j++] = acc; | |
1289 | acc = 0; | |
1290 | break; | |
1291 | } | |
1292 | } | |
1293 | k++; | |
1294 | } | |
1295 | } | |
1296 | if (k % 4) { | |
1297 | if (acc) { | |
1298 | parse_warn (cfile, | |
1299 | "partial base64 value left over: %d.", | |
1300 | acc); | |
028b1f6a TL |
1301 | } |
1302 | } | |
028b1f6a TL |
1303 | data -> len = j; |
1304 | data -> data = data -> buffer -> data; | |
8f01f9ec TL |
1305 | out: |
1306 | for (t = bufs; t; t = last) { | |
1307 | last = t -> next; | |
1308 | dfree (t, MDL); | |
1309 | } | |
1310 | if (data -> len) | |
1311 | return 1; | |
1312 | else | |
1313 | return 0; | |
028b1f6a TL |
1314 | } |
1315 | ||
1316 | ||
be6be08d TL |
1317 | /* |
1318 | * colon-seperated-hex-list :== NUMBER | | |
1319 | * NUMBER COLON colon-seperated-hex-list | |
1320 | */ | |
1321 | ||
02a015fb TL |
1322 | int parse_cshl (data, cfile) |
1323 | struct data_string *data; | |
4615d498 | 1324 | struct parse *cfile; |
4761e04b | 1325 | { |
c5b0f529 | 1326 | u_int8_t ibuf [128]; |
b1b7b521 TL |
1327 | unsigned ilen = 0; |
1328 | unsigned tlen = 0; | |
4761e04b TL |
1329 | struct option_tag *sl = (struct option_tag *)0; |
1330 | struct option_tag *next, **last = &sl; | |
02a015fb | 1331 | enum dhcp_token token; |
b1b7b521 | 1332 | const char *val; |
02a015fb | 1333 | unsigned char *rvp; |
4761e04b TL |
1334 | |
1335 | do { | |
1336 | token = next_token (&val, cfile); | |
1337 | if (token != NUMBER && token != NUMBER_OR_NAME) { | |
4615d498 | 1338 | parse_warn (cfile, "expecting hexadecimal number."); |
4761e04b TL |
1339 | skip_to_semi (cfile); |
1340 | for (; sl; sl = next) { | |
1341 | next = sl -> next; | |
fdac15d9 | 1342 | dfree (sl, MDL); |
4761e04b | 1343 | } |
02a015fb | 1344 | return 0; |
4761e04b TL |
1345 | } |
1346 | if (ilen == sizeof ibuf) { | |
1347 | next = (struct option_tag *) | |
1348 | dmalloc (ilen - 1 + | |
fdac15d9 | 1349 | sizeof (struct option_tag), MDL); |
4761e04b | 1350 | if (!next) |
8ae2d595 | 1351 | log_fatal ("no memory for string list."); |
4761e04b TL |
1352 | memcpy (next -> data, ibuf, ilen); |
1353 | *last = next; | |
1354 | last = &next -> next; | |
1355 | tlen += ilen; | |
1356 | ilen = 0; | |
1357 | } | |
4615d498 | 1358 | convert_num (cfile, &ibuf [ilen++], val, 16, 8); |
4761e04b TL |
1359 | |
1360 | token = peek_token (&val, cfile); | |
1361 | if (token != COLON) | |
1362 | break; | |
1363 | token = next_token (&val, cfile); | |
1364 | } while (1); | |
1365 | ||
4bd8800e | 1366 | if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL)) |
8ae2d595 | 1367 | log_fatal ("no memory to store octet data."); |
02a015fb TL |
1368 | data -> data = &data -> buffer -> data [0]; |
1369 | data -> len = tlen + ilen; | |
1370 | data -> terminated = 0; | |
1371 | ||
b1b7b521 | 1372 | rvp = &data -> buffer -> data [0]; |
4761e04b TL |
1373 | while (sl) { |
1374 | next = sl -> next; | |
1375 | memcpy (rvp, sl -> data, sizeof ibuf); | |
1376 | rvp += sizeof ibuf; | |
fdac15d9 | 1377 | dfree (sl, MDL); |
4761e04b TL |
1378 | sl = next; |
1379 | } | |
1380 | ||
1381 | memcpy (rvp, ibuf, ilen); | |
02a015fb | 1382 | return 1; |
4761e04b | 1383 | } |
be6be08d TL |
1384 | |
1385 | /* | |
1386 | * executable-statements :== executable-statement executable-statements | | |
1387 | * executable-statement | |
1388 | * | |
1389 | * executable-statement :== | |
1390 | * IF if-statement | | |
1391 | * ADD class-name SEMI | | |
1392 | * BREAK SEMI | | |
1393 | * OPTION option-parameter SEMI | | |
1394 | * SUPERSEDE option-parameter SEMI | | |
1395 | * PREPEND option-parameter SEMI | | |
1396 | * APPEND option-parameter SEMI | |
1397 | */ | |
1398 | ||
f579f39f | 1399 | int parse_executable_statements (statements, cfile, lose, case_context) |
79a65726 | 1400 | struct executable_statement **statements; |
4615d498 | 1401 | struct parse *cfile; |
be6be08d | 1402 | int *lose; |
f579f39f | 1403 | enum expression_context case_context; |
be6be08d | 1404 | { |
79a65726 | 1405 | struct executable_statement **next; |
be6be08d | 1406 | |
79a65726 | 1407 | next = statements; |
f579f39f | 1408 | while (parse_executable_statement (next, cfile, lose, case_context)) |
be6be08d | 1409 | next = &((*next) -> next); |
02a015fb | 1410 | if (!*lose) |
79a65726 TL |
1411 | return 1; |
1412 | return 0; | |
be6be08d TL |
1413 | } |
1414 | ||
f579f39f | 1415 | int parse_executable_statement (result, cfile, lose, case_context) |
79a65726 | 1416 | struct executable_statement **result; |
4615d498 | 1417 | struct parse *cfile; |
be6be08d | 1418 | int *lose; |
f579f39f | 1419 | enum expression_context case_context; |
be6be08d | 1420 | { |
02a015fb | 1421 | enum dhcp_token token; |
b1b7b521 | 1422 | const char *val; |
79a65726 | 1423 | struct executable_statement base; |
be6be08d TL |
1424 | struct class *cta; |
1425 | struct option *option; | |
b1013db7 | 1426 | struct option_cache *cache; |
b1b7b521 | 1427 | int known; |
0776fd12 | 1428 | int flag; |
88ab5737 | 1429 | int i; |
fa392aea | 1430 | struct dns_zone *zone; |
fa392aea | 1431 | isc_result_t status; |
be6be08d | 1432 | |
b1013db7 TL |
1433 | token = peek_token (&val, cfile); |
1434 | switch (token) { | |
be6be08d | 1435 | case IF: |
dce70f9f | 1436 | next_token (&val, cfile); |
79a65726 TL |
1437 | return parse_if_statement (result, cfile, lose); |
1438 | ||
eb018e2b | 1439 | case TOKEN_ADD: |
efc79acb | 1440 | token = next_token (&val, cfile); |
be6be08d TL |
1441 | token = next_token (&val, cfile); |
1442 | if (token != STRING) { | |
4615d498 | 1443 | parse_warn (cfile, "expecting class name."); |
be6be08d TL |
1444 | skip_to_semi (cfile); |
1445 | *lose = 1; | |
79a65726 | 1446 | return 0; |
be6be08d | 1447 | } |
20916cae TL |
1448 | cta = (struct class *)0; |
1449 | status = find_class (&cta, val, MDL); | |
1450 | if (status != ISC_R_SUCCESS) { | |
1451 | parse_warn (cfile, "class %s: %s", | |
1452 | val, isc_result_totext (status)); | |
be6be08d TL |
1453 | skip_to_semi (cfile); |
1454 | *lose = 1; | |
79a65726 | 1455 | return 0; |
be6be08d TL |
1456 | } |
1457 | if (!parse_semi (cfile)) { | |
1458 | *lose = 1; | |
79a65726 | 1459 | return 0; |
be6be08d | 1460 | } |
4bd8800e | 1461 | if (!executable_statement_allocate (result, MDL)) |
79a65726 TL |
1462 | log_fatal ("no memory for new statement."); |
1463 | (*result) -> op = add_statement; | |
1464 | (*result) -> data.add = cta; | |
be6be08d TL |
1465 | break; |
1466 | ||
1467 | case BREAK: | |
1468 | token = next_token (&val, cfile); | |
1469 | if (!parse_semi (cfile)) { | |
1470 | *lose = 1; | |
79a65726 | 1471 | return 0; |
be6be08d | 1472 | } |
4bd8800e | 1473 | if (!executable_statement_allocate (result, MDL)) |
79a65726 TL |
1474 | log_fatal ("no memory for new statement."); |
1475 | (*result) -> op = break_statement; | |
be6be08d TL |
1476 | break; |
1477 | ||
25541f2f TL |
1478 | case SEND: |
1479 | *lose = 1; | |
4615d498 | 1480 | parse_warn (cfile, "send not appropriate here."); |
25541f2f | 1481 | skip_to_semi (cfile); |
79a65726 | 1482 | return 0; |
25541f2f TL |
1483 | |
1484 | case SUPERSEDE: | |
be6be08d TL |
1485 | case OPTION: |
1486 | token = next_token (&val, cfile); | |
b1b7b521 TL |
1487 | known = 0; |
1488 | option = parse_option_name (cfile, 0, &known); | |
be6be08d TL |
1489 | if (!option) { |
1490 | *lose = 1; | |
79a65726 | 1491 | return 0; |
be6be08d | 1492 | } |
79a65726 | 1493 | return parse_option_statement (result, cfile, 1, option, |
be6be08d TL |
1494 | supersede_option_statement); |
1495 | ||
b1013db7 | 1496 | case ALLOW: |
0776fd12 TL |
1497 | flag = 1; |
1498 | goto pad; | |
b1013db7 | 1499 | case DENY: |
0776fd12 TL |
1500 | flag = 0; |
1501 | goto pad; | |
1502 | case IGNORE: | |
1503 | flag = 2; | |
1504 | pad: | |
b1013db7 TL |
1505 | token = next_token (&val, cfile); |
1506 | cache = (struct option_cache *)0; | |
2db25842 | 1507 | if (!parse_allow_deny (&cache, cfile, flag)) |
79a65726 | 1508 | return 0; |
4bd8800e | 1509 | if (!executable_statement_allocate (result, MDL)) |
79a65726 TL |
1510 | log_fatal ("no memory for new statement."); |
1511 | (*result) -> op = supersede_option_statement; | |
1512 | (*result) -> data.option = cache; | |
b1013db7 TL |
1513 | break; |
1514 | ||
be6be08d TL |
1515 | case DEFAULT: |
1516 | token = next_token (&val, cfile); | |
f579f39f TL |
1517 | token = peek_token (&val, cfile); |
1518 | if (token == COLON) | |
1519 | goto switch_default; | |
b1b7b521 TL |
1520 | known = 0; |
1521 | option = parse_option_name (cfile, 0, &known); | |
be6be08d TL |
1522 | if (!option) { |
1523 | *lose = 1; | |
79a65726 | 1524 | return 0; |
be6be08d | 1525 | } |
79a65726 | 1526 | return parse_option_statement (result, cfile, 1, option, |
be6be08d TL |
1527 | default_option_statement); |
1528 | ||
1529 | case PREPEND: | |
1530 | token = next_token (&val, cfile); | |
b1b7b521 TL |
1531 | known = 0; |
1532 | option = parse_option_name (cfile, 0, &known); | |
be6be08d TL |
1533 | if (!option) { |
1534 | *lose = 1; | |
79a65726 | 1535 | return 0; |
be6be08d | 1536 | } |
79a65726 | 1537 | return parse_option_statement (result, cfile, 1, option, |
be6be08d TL |
1538 | prepend_option_statement); |
1539 | ||
1540 | case APPEND: | |
1541 | token = next_token (&val, cfile); | |
b1b7b521 TL |
1542 | known = 0; |
1543 | option = parse_option_name (cfile, 0, &known); | |
be6be08d TL |
1544 | if (!option) { |
1545 | *lose = 1; | |
79a65726 | 1546 | return 0; |
be6be08d | 1547 | } |
79a65726 | 1548 | return parse_option_statement (result, cfile, 1, option, |
be6be08d TL |
1549 | append_option_statement); |
1550 | ||
79a65726 TL |
1551 | case ON: |
1552 | token = next_token (&val, cfile); | |
79a65726 TL |
1553 | return parse_on_statement (result, cfile, lose); |
1554 | ||
f579f39f TL |
1555 | case SWITCH: |
1556 | token = next_token (&val, cfile); | |
1557 | return parse_switch_statement (result, cfile, lose); | |
1558 | ||
1559 | case CASE: | |
1560 | token = next_token (&val, cfile); | |
1561 | if (case_context == context_any) { | |
1562 | parse_warn (cfile, | |
1563 | "case statement in inappropriate scope."); | |
1564 | *lose = 1; | |
1565 | skip_to_semi (cfile); | |
1566 | return 0; | |
1567 | } | |
1568 | return parse_case_statement (result, | |
1569 | cfile, lose, case_context); | |
1570 | ||
1571 | switch_default: | |
1572 | token = next_token (&val, cfile); | |
1573 | if (case_context == context_any) { | |
1574 | parse_warn (cfile, "switch default statement in %s", | |
1575 | "inappropriate scope."); | |
1576 | ||
1577 | *lose = 1; | |
1578 | return 0; | |
1579 | } else { | |
4bd8800e | 1580 | if (!executable_statement_allocate (result, MDL)) |
f579f39f TL |
1581 | log_fatal ("no memory for default statement."); |
1582 | (*result) -> op = default_statement; | |
1583 | return 1; | |
1584 | } | |
1585 | ||
31cb2a5f | 1586 | case DEFINE: |
f579f39f TL |
1587 | case TOKEN_SET: |
1588 | token = next_token (&val, cfile); | |
31cb2a5f TL |
1589 | if (token == DEFINE) |
1590 | flag = 1; | |
1591 | else | |
1592 | flag = 0; | |
f579f39f TL |
1593 | |
1594 | token = next_token (&val, cfile); | |
1595 | if (token != NAME && token != NUMBER_OR_NAME) { | |
1596 | parse_warn (cfile, | |
1597 | "%s can't be a variable name", val); | |
1598 | badset: | |
1599 | skip_to_semi (cfile); | |
1600 | *lose = 1; | |
1601 | return 0; | |
1602 | } | |
1603 | ||
4bd8800e | 1604 | if (!executable_statement_allocate (result, MDL)) |
f579f39f | 1605 | log_fatal ("no memory for set statement."); |
31cb2a5f | 1606 | (*result) -> op = flag ? define_statement : set_statement; |
fdac15d9 | 1607 | (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL); |
f579f39f TL |
1608 | if (!(*result)->data.set.name) |
1609 | log_fatal ("can't allocate variable name"); | |
1610 | strcpy ((*result) -> data.set.name, val); | |
1611 | token = next_token (&val, cfile); | |
f579f39f | 1612 | |
31cb2a5f TL |
1613 | if (token == LPAREN) { |
1614 | struct string_list *head, *cur, *new; | |
1615 | struct expression *expr; | |
1616 | head = cur = (struct string_list *)0; | |
1617 | do { | |
1618 | token = next_token (&val, cfile); | |
1619 | if (token == RPAREN) | |
1620 | break; | |
1621 | if (token != NAME && token != NUMBER_OR_NAME) { | |
1622 | parse_warn (cfile, | |
1623 | "expecting argument name"); | |
1624 | skip_to_rbrace (cfile, 0); | |
1625 | *lose = 1; | |
1626 | executable_statement_dereference | |
1627 | (result, MDL); | |
1628 | return 0; | |
1629 | } | |
1630 | new = ((struct string_list *) | |
1631 | dmalloc (sizeof (struct string_list) + | |
1632 | strlen (val), MDL)); | |
1633 | if (!new) | |
1634 | log_fatal ("can't allocate string."); | |
1635 | memset (new, 0, sizeof *new); | |
1636 | strcpy (new -> string, val); | |
1637 | if (cur) { | |
1638 | cur -> next = new; | |
1639 | cur = new; | |
1640 | } else { | |
1641 | head = cur = new; | |
1642 | } | |
1643 | token = next_token (&val, cfile); | |
1644 | } while (token == COMMA); | |
1645 | ||
1646 | if (token != RPAREN) { | |
1647 | parse_warn (cfile, "expecting right paren."); | |
1648 | badx: | |
1649 | skip_to_semi (cfile); | |
f579f39f | 1650 | *lose = 1; |
31cb2a5f TL |
1651 | executable_statement_dereference (result, MDL); |
1652 | return 0; | |
1653 | } | |
1654 | ||
1655 | token = next_token (&val, cfile); | |
1656 | if (token != LBRACE) { | |
1657 | parse_warn (cfile, "expecting left brace."); | |
1658 | goto badx; | |
1659 | } | |
1660 | ||
1661 | expr = (struct expression *)0; | |
1662 | if (!(expression_allocate (&expr, MDL))) | |
1663 | log_fatal ("can't allocate expression."); | |
1664 | expr -> op = expr_function; | |
1665 | if (!fundef_allocate (&expr -> data.func, MDL)) | |
1666 | log_fatal ("can't allocate fundef."); | |
1667 | expr -> data.func -> args = head; | |
1668 | (*result) -> data.set.expr = expr; | |
1669 | ||
1670 | if (!(parse_executable_statements | |
1671 | (&expr -> data.func -> statements, cfile, lose, | |
1672 | case_context))) { | |
1673 | if (*lose) | |
1674 | goto badx; | |
1675 | } | |
1676 | ||
1677 | token = next_token (&val, cfile); | |
1678 | if (token != RBRACE) { | |
1679 | parse_warn (cfile, "expecting rigt brace."); | |
1680 | goto badx; | |
1681 | } | |
1682 | } else { | |
1683 | if (token != EQUAL) { | |
1684 | parse_warn (cfile, | |
1685 | "expecting '=' in %s statement.", | |
1686 | flag ? "define" : "set"); | |
1687 | goto badset; | |
1688 | } | |
1689 | ||
1690 | if (!parse_expression (&(*result) -> data.set.expr, | |
1691 | cfile, lose, context_any, | |
1692 | (struct expression **)0, | |
1693 | expr_none)) { | |
1694 | if (!*lose) | |
1695 | parse_warn (cfile, | |
1696 | "expecting expression."); | |
1697 | else | |
1698 | *lose = 1; | |
1699 | skip_to_semi (cfile); | |
1700 | executable_statement_dereference (result, MDL); | |
1701 | return 0; | |
1702 | } | |
1703 | parse_semi (cfile); | |
f579f39f | 1704 | } |
f579f39f TL |
1705 | break; |
1706 | ||
fdac15d9 TL |
1707 | case UNSET: |
1708 | token = next_token (&val, cfile); | |
1709 | ||
1710 | token = next_token (&val, cfile); | |
1711 | if (token != NAME && token != NUMBER_OR_NAME) { | |
1712 | parse_warn (cfile, | |
1713 | "%s can't be a variable name", val); | |
1714 | badunset: | |
1715 | skip_to_semi (cfile); | |
1716 | *lose = 1; | |
1717 | return 0; | |
1718 | } | |
1719 | ||
4bd8800e | 1720 | if (!executable_statement_allocate (result, MDL)) |
fdac15d9 TL |
1721 | log_fatal ("no memory for set statement."); |
1722 | (*result) -> op = unset_statement; | |
1723 | (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL); | |
1724 | if (!(*result)->data.unset) | |
1725 | log_fatal ("can't allocate variable name"); | |
1726 | strcpy ((*result) -> data.unset, val); | |
1727 | parse_semi (cfile); | |
1728 | break; | |
1729 | ||
1730 | case EVAL: | |
1731 | token = next_token (&val, cfile); | |
1732 | ||
4bd8800e | 1733 | if (!executable_statement_allocate (result, MDL)) |
fdac15d9 TL |
1734 | log_fatal ("no memory for eval statement."); |
1735 | (*result) -> op = eval_statement; | |
1736 | ||
1737 | if (!parse_expression (&(*result) -> data.eval, | |
1738 | cfile, lose, context_data, /* XXX */ | |
1739 | (struct expression **)0, expr_none)) { | |
1740 | if (!*lose) | |
1741 | parse_warn (cfile, | |
1742 | "expecting data expression."); | |
1743 | else | |
1744 | *lose = 1; | |
1745 | skip_to_semi (cfile); | |
4bd8800e | 1746 | executable_statement_dereference (result, MDL); |
fdac15d9 TL |
1747 | return 0; |
1748 | } | |
1749 | parse_semi (cfile); | |
1750 | break; | |
1751 | ||
1b234d44 DN |
1752 | case RETURN: |
1753 | token = next_token (&val, cfile); | |
1754 | ||
1755 | if (!executable_statement_allocate (result, MDL)) | |
1756 | log_fatal ("no memory for return statement."); | |
1757 | (*result) -> op = return_statement; | |
1758 | ||
1759 | if (!parse_expression (&(*result) -> data.retval, | |
1760 | cfile, lose, context_data, | |
1761 | (struct expression **)0, expr_none)) { | |
1762 | if (!*lose) | |
1763 | parse_warn (cfile, | |
1764 | "expecting data expression."); | |
1765 | else | |
1766 | *lose = 1; | |
1767 | skip_to_semi (cfile); | |
1768 | executable_statement_dereference (result, MDL); | |
1769 | return 0; | |
1770 | } | |
1771 | parse_semi (cfile); | |
1772 | break; | |
1773 | ||
e7a9c293 | 1774 | case LOG: |
e7a9c293 DN |
1775 | token = next_token (&val, cfile); |
1776 | ||
1777 | if (!executable_statement_allocate (result, MDL)) | |
1778 | log_fatal ("no memory for log statement."); | |
1779 | (*result) -> op = log_statement; | |
1780 | ||
1781 | token = next_token (&val, cfile); | |
1782 | if (token != LPAREN) { | |
1783 | parse_warn (cfile, "left parenthesis expected."); | |
1784 | skip_to_semi (cfile); | |
1785 | *lose = 1; | |
1786 | return 0; | |
1787 | } | |
1788 | ||
1789 | token = peek_token (&val, cfile); | |
1790 | i = 1; | |
1791 | if (token == FATAL) { | |
1792 | (*result) -> data.log.priority = log_priority_fatal; | |
1793 | } else if (token == ERROR) { | |
1794 | (*result) -> data.log.priority = log_priority_error; | |
1795 | } else if (token == TOKEN_DEBUG) { | |
1796 | (*result) -> data.log.priority = log_priority_debug; | |
1797 | } else if (token == INFO) { | |
1798 | (*result) -> data.log.priority = log_priority_info; | |
1799 | } else { | |
1800 | (*result) -> data.log.priority = log_priority_debug; | |
1801 | i = 0; | |
1802 | } | |
1803 | if (i) { | |
1804 | token = next_token (&val, cfile); | |
1805 | token = next_token (&val, cfile); | |
1806 | if (token != COMMA) { | |
1807 | parse_warn (cfile, "comma expected."); | |
1808 | skip_to_semi (cfile); | |
1809 | *lose = 1; | |
1810 | return 0; | |
1811 | } | |
1812 | } | |
1813 | ||
1814 | if (!(parse_data_expression | |
1815 | (&(*result) -> data.log.expr, cfile, lose))) { | |
1816 | skip_to_semi (cfile); | |
1817 | *lose = 1; | |
1818 | return 0; | |
1819 | } | |
1820 | ||
1821 | token = next_token (&val, cfile); | |
1822 | if (token != RPAREN) { | |
1823 | parse_warn (cfile, "right parenthesis expected."); | |
1824 | skip_to_semi (cfile); | |
1825 | *lose = 1; | |
1826 | return 0; | |
1827 | } | |
1828 | ||
1829 | token = next_token (&val, cfile); | |
1830 | if (token != SEMI) { | |
1831 | parse_warn (cfile, "semicolon expected."); | |
1832 | skip_to_semi (cfile); | |
1833 | *lose = 1; | |
1834 | return 0; | |
1835 | } | |
1836 | break; | |
1837 | ||
fa392aea TL |
1838 | /* Not really a statement, but we parse it here anyway |
1839 | because it's appropriate for all DHCP agents with | |
1840 | parsers. */ | |
1841 | case ZONE: | |
1842 | token = next_token (&val, cfile); | |
028b1f6a | 1843 | zone = (struct dns_zone *)0; |
fa392aea TL |
1844 | if (!dns_zone_allocate (&zone, MDL)) |
1845 | log_fatal ("no memory for new zone."); | |
1846 | zone -> name = parse_host_name (cfile); | |
1847 | if (!zone -> name) { | |
1848 | badzone: | |
e7a9c293 | 1849 | parse_warn (cfile, "expecting hostname."); |
fa392aea TL |
1850 | *lose = 1; |
1851 | skip_to_semi (cfile); | |
1852 | dns_zone_dereference (&zone, MDL); | |
1853 | return 0; | |
1854 | } | |
88ab5737 TL |
1855 | i = strlen (zone -> name); |
1856 | if (zone -> name [i - 1] != '.') { | |
1857 | parse_warn (cfile, | |
1858 | "zone name must not be relative %s: %s", | |
1859 | "(must end in '.')", zone -> name); | |
1860 | } | |
fa392aea TL |
1861 | if (!parse_zone (zone, cfile)) |
1862 | goto badzone; | |
fa392aea | 1863 | status = enter_dns_zone (zone); |
fa392aea TL |
1864 | if (status != ISC_R_SUCCESS) { |
1865 | if (parse_semi (cfile)) | |
028b1f6a TL |
1866 | parse_warn (cfile, "dns zone key %s: %s", |
1867 | zone -> name, | |
fa392aea TL |
1868 | isc_result_totext (status)); |
1869 | dns_zone_dereference (&zone, MDL); | |
1870 | return 0; | |
1871 | } | |
1872 | return 1; | |
1873 | ||
1874 | /* Also not really a statement, but same idea as above. */ | |
028b1f6a | 1875 | case KEY: |
fa392aea | 1876 | token = next_token (&val, cfile); |
028b1f6a | 1877 | if (!parse_key (cfile)) { |
fa392aea | 1878 | *lose = 1; |
fa392aea TL |
1879 | return 0; |
1880 | } | |
028b1f6a | 1881 | return 1; |
e7a9c293 | 1882 | |
be6be08d | 1883 | default: |
588af269 | 1884 | if (config_universe && is_identifier (token)) { |
20916cae TL |
1885 | option = (struct option *)0; |
1886 | option_hash_lookup (&option, config_universe -> hash, | |
1887 | val, 0, MDL); | |
588af269 TL |
1888 | if (option) { |
1889 | token = next_token (&val, cfile); | |
1890 | return parse_option_statement | |
1891 | (result, cfile, 1, option, | |
1892 | supersede_option_statement); | |
1893 | } | |
1894 | } | |
1b234d44 DN |
1895 | |
1896 | if (token == NUMBER_OR_NAME || token == NAME) { | |
1897 | /* This is rather ugly. Since function calls are | |
1898 | data expressions, fake up an eval statement. */ | |
1899 | if (!executable_statement_allocate (result, MDL)) | |
1900 | log_fatal ("no memory for eval statement."); | |
1901 | (*result) -> op = eval_statement; | |
1902 | ||
1903 | if (!parse_expression (&(*result) -> data.eval, | |
1904 | cfile, lose, context_data, | |
1905 | (struct expression **)0, | |
1906 | expr_none)) { | |
1907 | if (!*lose) | |
1908 | parse_warn (cfile, "expecting " | |
1909 | "function call."); | |
1910 | else | |
1911 | *lose = 1; | |
1912 | skip_to_semi (cfile); | |
1913 | executable_statement_dereference (result, MDL); | |
1914 | return 0; | |
1915 | } | |
1916 | parse_semi (cfile); | |
1917 | break; | |
1918 | } | |
1919 | ||
be6be08d | 1920 | *lose = 0; |
79a65726 | 1921 | return 0; |
be6be08d TL |
1922 | } |
1923 | ||
79a65726 TL |
1924 | return 1; |
1925 | } | |
1926 | ||
fa392aea TL |
1927 | /* zone-statements :== zone-statement | |
1928 | zone-statement zone-statements | |
1929 | zone-statement :== | |
1930 | PRIMARY ip-addresses SEMI | | |
1931 | SECONDARY ip-addresses SEMI | | |
028b1f6a TL |
1932 | key-reference SEMI |
1933 | ip-addresses :== ip-addr-or-hostname | | |
1934 | ip-addr-or-hostname COMMA ip-addresses | |
1935 | key-reference :== KEY STRING | | |
1936 | KEY identifier */ | |
fa392aea TL |
1937 | |
1938 | int parse_zone (struct dns_zone *zone, struct parse *cfile) | |
1939 | { | |
1940 | int token; | |
1941 | const char *val; | |
1942 | struct option_cache *oc; | |
1943 | int done = 0; | |
1944 | ||
028b1f6a TL |
1945 | token = next_token (&val, cfile); |
1946 | if (token != LBRACE) { | |
1947 | parse_warn (cfile, "expecting left brace"); | |
1948 | return 0; | |
1949 | } | |
1950 | ||
fa392aea TL |
1951 | do { |
1952 | token = peek_token (&val, cfile); | |
1953 | switch (token) { | |
1954 | case PRIMARY: | |
1955 | if (zone -> primary) { | |
1956 | parse_warn (cfile, | |
1957 | "more than one primary."); | |
1958 | skip_to_semi (cfile); | |
1959 | return 0; | |
1960 | } | |
1961 | if (!option_cache_allocate (&zone -> primary, MDL)) | |
1962 | log_fatal ("can't allocate primary option cache."); | |
1963 | oc = zone -> primary; | |
1964 | goto consemup; | |
1965 | ||
1966 | case SECONDARY: | |
1967 | if (zone -> secondary) { | |
1968 | parse_warn (cfile, "more than one secondary."); | |
1969 | skip_to_semi (cfile); | |
1970 | return 0; | |
1971 | } | |
1972 | if (!option_cache_allocate (&zone -> secondary, MDL)) | |
1973 | log_fatal ("can't allocate secondary."); | |
1974 | oc = zone -> secondary; | |
1975 | consemup: | |
1976 | token = next_token (&val, cfile); | |
1977 | do { | |
1978 | struct expression *expr = (struct expression *)0; | |
1979 | if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { | |
1980 | parse_warn (cfile, | |
1981 | "expecting IP addr or hostname."); | |
1982 | skip_to_semi (cfile); | |
1983 | return 0; | |
1984 | } | |
1985 | if (oc -> expression) { | |
1986 | struct expression *old = | |
1987 | (struct expression *)0; | |
1988 | expression_reference (&old, | |
1989 | oc -> expression, | |
1990 | MDL); | |
1991 | expression_dereference (&oc -> expression, | |
1992 | MDL); | |
1993 | if (!make_concat (&oc -> expression, | |
1994 | old, expr)) | |
1995 | log_fatal ("no memory for concat."); | |
1996 | expression_dereference (&expr, MDL); | |
1997 | expression_dereference (&old, MDL); | |
1998 | } else { | |
1999 | expression_reference (&oc -> expression, | |
2000 | expr, MDL); | |
2001 | expression_dereference (&expr, MDL); | |
2002 | } | |
2003 | token = next_token (&val, cfile); | |
2004 | } while (token == COMMA); | |
2005 | if (token != SEMI) { | |
2006 | parse_warn (cfile, "expecting semicolon."); | |
2007 | skip_to_semi (cfile); | |
2008 | return 0; | |
2009 | } | |
2010 | break; | |
2011 | ||
028b1f6a | 2012 | case KEY: |
fa392aea TL |
2013 | token = next_token (&val, cfile); |
2014 | token = next_token (&val, cfile); | |
028b1f6a | 2015 | if (token != STRING && !is_identifier (token)) { |
fa392aea TL |
2016 | parse_warn (cfile, "expecting key name."); |
2017 | skip_to_semi (cfile); | |
2018 | return 0; | |
2019 | } | |
49146f3c DN |
2020 | if (omapi_auth_key_lookup_name (&zone -> key, val) != |
2021 | ISC_R_SUCCESS) | |
fa392aea TL |
2022 | parse_warn (cfile, "unknown key %s", val); |
2023 | if (!parse_semi (cfile)) | |
2024 | return 0; | |
2025 | break; | |
2026 | ||
2027 | default: | |
2028 | done = 1; | |
2029 | break; | |
2030 | } | |
2031 | } while (!done); | |
2032 | ||
028b1f6a TL |
2033 | token = next_token (&val, cfile); |
2034 | if (token != RBRACE) { | |
2035 | parse_warn (cfile, "expecting right brace."); | |
2036 | return 0; | |
2037 | } | |
fa392aea TL |
2038 | return 1; |
2039 | } | |
2040 | ||
028b1f6a TL |
2041 | /* key-statements :== key-statement | |
2042 | key-statement key-statements | |
2043 | key-statement :== | |
2044 | ALGORITHM host-name SEMI | | |
2045 | secret-definition SEMI | |
2046 | secret-definition :== SECRET base64val | | |
2047 | SECRET STRING */ | |
2048 | ||
2049 | int parse_key (struct parse *cfile) | |
2050 | { | |
2051 | int token; | |
2052 | const char *val; | |
2053 | int done = 0; | |
49146f3c DN |
2054 | struct auth_key *key; |
2055 | struct data_string ds; | |
028b1f6a TL |
2056 | isc_result_t status; |
2057 | ||
2058 | token = next_token (&val, cfile); | |
2059 | if (token != STRING && !is_identifier (token)) { | |
2060 | parse_warn (cfile, "expecting key name string."); | |
2061 | skip_to_semi (cfile); | |
2062 | return 0; | |
2063 | } | |
49146f3c DN |
2064 | key = (struct auth_key *)0; |
2065 | if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS) | |
028b1f6a TL |
2066 | log_fatal ("no memory for tsig key"); |
2067 | key -> name = dmalloc (strlen (val) + 1, MDL); | |
2068 | if (!key -> name) | |
2069 | log_fatal ("no memory for tsig key name."); | |
2070 | strcpy (key -> name, val); | |
2071 | ||
2072 | token = next_token (&val, cfile); | |
2073 | if (token != LBRACE) { | |
2074 | parse_warn (cfile, "expecting left brace"); | |
2075 | return 0; | |
2076 | } | |
2077 | ||
2078 | do { | |
2079 | token = next_token (&val, cfile); | |
2080 | switch (token) { | |
2081 | case ALGORITHM: | |
2082 | if (key -> algorithm) { | |
2083 | parse_warn (cfile, | |
2084 | "key %s: too many algorithms", | |
2085 | key -> name); | |
2086 | goto rbad; | |
2087 | } | |
2088 | key -> algorithm = parse_host_name (cfile); | |
2089 | if (!key -> algorithm) { | |
2090 | parse_warn (cfile, | |
2091 | "expecting key algorithm name."); | |
2092 | goto rbad; | |
2093 | } | |
2094 | if (!parse_semi (cfile)) | |
2095 | goto rbad; | |
2096 | break; | |
2097 | ||
2098 | case SECRET: | |
49146f3c | 2099 | if (key -> key) { |
028b1f6a TL |
2100 | parse_warn (cfile, "key %s: too many secrets", |
2101 | key -> name); | |
2102 | goto rbad; | |
2103 | } | |
49146f3c DN |
2104 | |
2105 | memset (&ds, 0, sizeof(ds)); | |
2106 | if (!parse_base64 (&ds, cfile)) | |
2107 | goto rbad; | |
2108 | status = omapi_data_string_new (&key -> key, ds.len, | |
2109 | MDL); | |
2110 | if (status != ISC_R_SUCCESS) | |
028b1f6a | 2111 | goto rbad; |
49146f3c DN |
2112 | memcpy (key -> key -> value, |
2113 | ds.buffer -> data, ds.len); | |
2114 | data_string_forget (&ds, MDL); | |
2115 | ||
028b1f6a TL |
2116 | if (!parse_semi (cfile)) |
2117 | goto rbad; | |
2118 | break; | |
2119 | ||
2120 | default: | |
2121 | done = 1; | |
2122 | break; | |
2123 | } | |
2124 | } while (!done); | |
2125 | if (token != RBRACE) { | |
2126 | parse_warn (cfile, "expecting right brace."); | |
2127 | goto rbad; | |
2128 | } | |
13b0934e TL |
2129 | /* Allow the BIND 8 syntax, which has a semicolon after each |
2130 | closing brace. */ | |
2131 | token = peek_token (&val, cfile); | |
2132 | if (token == SEMI) | |
2133 | token = next_token (&val, cfile); | |
2134 | ||
2135 | /* Remember the key. */ | |
49146f3c | 2136 | status = omapi_auth_key_enter (key); |
028b1f6a TL |
2137 | if (status != ISC_R_SUCCESS) { |
2138 | parse_warn (cfile, "tsig key %s: %s", | |
2139 | key -> name, isc_result_totext (status)); | |
2140 | goto bad; | |
2141 | } | |
2142 | return 1; | |
2143 | ||
2144 | rbad: | |
2145 | skip_to_rbrace (cfile, 1); | |
2146 | bad: | |
49146f3c | 2147 | omapi_auth_key_dereference (&key, MDL); |
028b1f6a TL |
2148 | return 0; |
2149 | } | |
79a65726 | 2150 | /* |
f579f39f TL |
2151 | * on-statement :== event-types LBRACE executable-statements RBRACE |
2152 | * event-types :== event-type OR event-types | | |
2153 | * event-type | |
79a65726 TL |
2154 | * event-type :== EXPIRY | COMMIT | RELEASE |
2155 | */ | |
2156 | ||
2157 | int parse_on_statement (result, cfile, lose) | |
2158 | struct executable_statement **result; | |
4615d498 | 2159 | struct parse *cfile; |
79a65726 TL |
2160 | int *lose; |
2161 | { | |
2162 | enum dhcp_token token; | |
b1b7b521 | 2163 | const char *val; |
79a65726 | 2164 | |
4bd8800e | 2165 | if (!executable_statement_allocate (result, MDL)) |
8ae2d595 | 2166 | log_fatal ("no memory for new statement."); |
33500c7d | 2167 | (*result) -> op = on_statement; |
79a65726 | 2168 | |
f579f39f TL |
2169 | do { |
2170 | token = next_token (&val, cfile); | |
2171 | switch (token) { | |
2172 | case EXPIRY: | |
2173 | (*result) -> data.on.evtypes |= ON_EXPIRY; | |
2174 | break; | |
79a65726 | 2175 | |
f579f39f | 2176 | case COMMIT: |
fdac15d9 | 2177 | (*result) -> data.on.evtypes |= ON_COMMIT; |
f579f39f TL |
2178 | break; |
2179 | ||
2180 | case RELEASE: | |
fdac15d9 | 2181 | (*result) -> data.on.evtypes |= ON_RELEASE; |
f579f39f TL |
2182 | break; |
2183 | ||
2184 | default: | |
2185 | parse_warn (cfile, "expecting a lease event type"); | |
2186 | skip_to_semi (cfile); | |
2187 | *lose = 1; | |
4bd8800e | 2188 | executable_statement_dereference (result, MDL); |
fdac15d9 | 2189 | return 0; |
f579f39f TL |
2190 | } |
2191 | token = next_token (&val, cfile); | |
2192 | } while (token == OR); | |
79a65726 | 2193 | |
f579f39f TL |
2194 | /* Semicolon means no statements. */ |
2195 | if (token == SEMI) | |
2196 | return 1; | |
2197 | ||
79a65726 | 2198 | if (token != LBRACE) { |
4615d498 | 2199 | parse_warn (cfile, "left brace expected."); |
79a65726 TL |
2200 | skip_to_semi (cfile); |
2201 | *lose = 1; | |
4bd8800e | 2202 | executable_statement_dereference (result, MDL); |
79a65726 TL |
2203 | return 0; |
2204 | } | |
2205 | if (!parse_executable_statements (&(*result) -> data.on.statements, | |
f579f39f | 2206 | cfile, lose, context_any)) { |
79a65726 TL |
2207 | if (*lose) { |
2208 | /* Try to even things up. */ | |
2209 | do { | |
2210 | token = next_token (&val, cfile); | |
2211 | } while (token != EOF && token != RBRACE); | |
4bd8800e | 2212 | executable_statement_dereference (result, MDL); |
79a65726 TL |
2213 | return 0; |
2214 | } | |
2215 | } | |
2216 | token = next_token (&val, cfile); | |
2217 | if (token != RBRACE) { | |
4615d498 | 2218 | parse_warn (cfile, "right brace expected."); |
79a65726 TL |
2219 | skip_to_semi (cfile); |
2220 | *lose = 1; | |
4bd8800e | 2221 | executable_statement_dereference (result, MDL); |
79a65726 TL |
2222 | return 0; |
2223 | } | |
2224 | return 1; | |
be6be08d TL |
2225 | } |
2226 | ||
f579f39f TL |
2227 | /* |
2228 | * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE | |
2229 | * | |
2230 | */ | |
2231 | ||
2232 | int parse_switch_statement (result, cfile, lose) | |
2233 | struct executable_statement **result; | |
2234 | struct parse *cfile; | |
2235 | int *lose; | |
2236 | { | |
2237 | enum dhcp_token token; | |
2238 | const char *val; | |
2239 | ||
4bd8800e | 2240 | if (!executable_statement_allocate (result, MDL)) |
f579f39f TL |
2241 | log_fatal ("no memory for new statement."); |
2242 | (*result) -> op = switch_statement; | |
2243 | ||
2244 | token = next_token (&val, cfile); | |
2245 | if (token != LPAREN) { | |
2246 | parse_warn (cfile, "expecting left brace."); | |
2247 | pfui: | |
2248 | *lose = 1; | |
2249 | skip_to_semi (cfile); | |
2250 | gnorf: | |
4bd8800e | 2251 | executable_statement_dereference (result, MDL); |
f579f39f TL |
2252 | return 0; |
2253 | } | |
2254 | ||
2255 | if (!parse_expression (&(*result) -> data.s_switch.expr, | |
2256 | cfile, lose, context_data_or_numeric, | |
2257 | (struct expression **)0, expr_none)) { | |
2258 | if (!*lose) { | |
2259 | parse_warn (cfile, | |
2260 | "expecting data or numeric expression."); | |
2261 | goto pfui; | |
2262 | } | |
2263 | goto gnorf; | |
2264 | } | |
2265 | ||
2266 | token = next_token (&val, cfile); | |
2267 | if (token != RPAREN) { | |
2268 | parse_warn (cfile, "right paren expected."); | |
2269 | goto pfui; | |
2270 | } | |
2271 | ||
2272 | token = next_token (&val, cfile); | |
2273 | if (token != LBRACE) { | |
2274 | parse_warn (cfile, "left brace expected."); | |
2275 | goto pfui; | |
2276 | } | |
2277 | if (!(parse_executable_statements | |
2278 | (&(*result) -> data.s_switch.statements, cfile, lose, | |
2279 | (is_data_expression ((*result) -> data.s_switch.expr) | |
2280 | ? context_data : context_numeric)))) { | |
2281 | if (*lose) { | |
2282 | skip_to_rbrace (cfile, 1); | |
4bd8800e | 2283 | executable_statement_dereference (result, MDL); |
f579f39f TL |
2284 | return 0; |
2285 | } | |
2286 | } | |
2287 | token = next_token (&val, cfile); | |
2288 | if (token != RBRACE) { | |
2289 | parse_warn (cfile, "right brace expected."); | |
2290 | goto pfui; | |
2291 | } | |
2292 | return 1; | |
2293 | } | |
2294 | ||
2295 | /* | |
2296 | * case-statement :== CASE expr COLON | |
2297 | * | |
2298 | */ | |
2299 | ||
2300 | int parse_case_statement (result, cfile, lose, case_context) | |
2301 | struct executable_statement **result; | |
2302 | struct parse *cfile; | |
2303 | int *lose; | |
2304 | enum expression_context case_context; | |
2305 | { | |
2306 | enum dhcp_token token; | |
2307 | const char *val; | |
2308 | ||
4bd8800e | 2309 | if (!executable_statement_allocate (result, MDL)) |
f579f39f TL |
2310 | log_fatal ("no memory for new statement."); |
2311 | (*result) -> op = case_statement; | |
2312 | ||
2313 | if (!parse_expression (&(*result) -> data.c_case, | |
2314 | cfile, lose, case_context, | |
2315 | (struct expression **)0, expr_none)) | |
2316 | { | |
2317 | if (!*lose) { | |
2318 | parse_warn (cfile, "expecting %s expression.", | |
2319 | (case_context == context_data | |
2320 | ? "data" : "numeric")); | |
2321 | } | |
2322 | pfui: | |
2323 | *lose = 1; | |
2324 | skip_to_semi (cfile); | |
4bd8800e | 2325 | executable_statement_dereference (result, MDL); |
f579f39f TL |
2326 | return 0; |
2327 | } | |
2328 | ||
2329 | token = next_token (&val, cfile); | |
2330 | if (token != COLON) { | |
2331 | parse_warn (cfile, "colon expected."); | |
2332 | goto pfui; | |
2333 | } | |
2334 | return 1; | |
2335 | } | |
2336 | ||
be6be08d TL |
2337 | /* |
2338 | * if-statement :== boolean-expression LBRACE executable-statements RBRACE | |
2339 | * else-statement | |
2340 | * | |
2341 | * else-statement :== <null> | | |
2342 | * ELSE LBRACE executable-statements RBRACE | | |
2343 | * ELSE IF if-statement | | |
2344 | * ELSIF if-statement | |
2345 | */ | |
2346 | ||
79a65726 TL |
2347 | int parse_if_statement (result, cfile, lose) |
2348 | struct executable_statement **result; | |
4615d498 | 2349 | struct parse *cfile; |
be6be08d TL |
2350 | int *lose; |
2351 | { | |
02a015fb | 2352 | enum dhcp_token token; |
b1b7b521 | 2353 | const char *val; |
fdac15d9 | 2354 | int parenp; |
be6be08d | 2355 | |
4bd8800e | 2356 | if (!executable_statement_allocate (result, MDL)) |
79a65726 TL |
2357 | log_fatal ("no memory for if statement."); |
2358 | ||
2359 | (*result) -> op = if_statement; | |
2360 | ||
fdac15d9 TL |
2361 | token = peek_token (&val, cfile); |
2362 | if (token == LPAREN) { | |
2363 | parenp = 1; | |
2364 | next_token (&val, cfile); | |
2365 | } else | |
2366 | parenp = 0; | |
2367 | ||
2368 | ||
79a65726 TL |
2369 | if (!parse_boolean_expression (&(*result) -> data.ie.expr, |
2370 | cfile, lose)) { | |
be6be08d | 2371 | if (!*lose) |
4615d498 | 2372 | parse_warn (cfile, "boolean expression expected."); |
4bd8800e | 2373 | executable_statement_dereference (result, MDL); |
166e63eb | 2374 | *lose = 1; |
79a65726 | 2375 | return 0; |
be6be08d | 2376 | } |
02a015fb TL |
2377 | #if defined (DEBUG_EXPRESSION_PARSE) |
2378 | print_expression ("if condition", if_condition); | |
2379 | #endif | |
fdac15d9 TL |
2380 | if (parenp) { |
2381 | token = next_token (&val, cfile); | |
2382 | if (token != RPAREN) { | |
2383 | parse_warn (cfile, "expecting right paren."); | |
2384 | *lose = 1; | |
4bd8800e | 2385 | executable_statement_dereference (result, MDL); |
fdac15d9 TL |
2386 | return 0; |
2387 | } | |
2388 | } | |
be6be08d TL |
2389 | token = next_token (&val, cfile); |
2390 | if (token != LBRACE) { | |
4615d498 | 2391 | parse_warn (cfile, "left brace expected."); |
be6be08d TL |
2392 | skip_to_semi (cfile); |
2393 | *lose = 1; | |
4bd8800e | 2394 | executable_statement_dereference (result, MDL); |
79a65726 | 2395 | return 0; |
be6be08d | 2396 | } |
79a65726 | 2397 | if (!parse_executable_statements (&(*result) -> data.ie.true, |
f579f39f | 2398 | cfile, lose, context_any)) { |
79a65726 TL |
2399 | if (*lose) { |
2400 | /* Try to even things up. */ | |
2401 | do { | |
2402 | token = next_token (&val, cfile); | |
2403 | } while (token != EOF && token != RBRACE); | |
4bd8800e | 2404 | executable_statement_dereference (result, MDL); |
79a65726 TL |
2405 | return 0; |
2406 | } | |
efc79acb | 2407 | } |
79a65726 | 2408 | token = next_token (&val, cfile); |
be6be08d | 2409 | if (token != RBRACE) { |
4615d498 | 2410 | parse_warn (cfile, "right brace expected."); |
be6be08d TL |
2411 | skip_to_semi (cfile); |
2412 | *lose = 1; | |
4bd8800e | 2413 | executable_statement_dereference (result, MDL); |
79a65726 | 2414 | return 0; |
be6be08d TL |
2415 | } |
2416 | token = peek_token (&val, cfile); | |
2417 | if (token == ELSE) { | |
2418 | token = next_token (&val, cfile); | |
2419 | token = peek_token (&val, cfile); | |
2420 | if (token == IF) { | |
2421 | token = next_token (&val, cfile); | |
79a65726 TL |
2422 | if (!parse_if_statement (&(*result) -> data.ie.false, |
2423 | cfile, lose)) { | |
166e63eb TL |
2424 | if (!*lose) |
2425 | parse_warn (cfile, | |
4bd8800e TL |
2426 | "expecting if statement"); |
2427 | executable_statement_dereference (result, MDL); | |
166e63eb TL |
2428 | *lose = 1; |
2429 | return 0; | |
79a65726 | 2430 | } |
be6be08d | 2431 | } else if (token != LBRACE) { |
4615d498 | 2432 | parse_warn (cfile, "left brace or if expected."); |
be6be08d TL |
2433 | skip_to_semi (cfile); |
2434 | *lose = 1; | |
4bd8800e | 2435 | executable_statement_dereference (result, MDL); |
79a65726 | 2436 | return 0; |
be6be08d TL |
2437 | } else { |
2438 | token = next_token (&val, cfile); | |
33500c7d | 2439 | if (!(parse_executable_statements |
f579f39f TL |
2440 | (&(*result) -> data.ie.false, |
2441 | cfile, lose, context_any))) { | |
4bd8800e | 2442 | executable_statement_dereference (result, MDL); |
79a65726 TL |
2443 | return 0; |
2444 | } | |
25541f2f TL |
2445 | token = next_token (&val, cfile); |
2446 | if (token != RBRACE) { | |
4615d498 | 2447 | parse_warn (cfile, "right brace expected."); |
25541f2f TL |
2448 | skip_to_semi (cfile); |
2449 | *lose = 1; | |
4bd8800e | 2450 | executable_statement_dereference (result, MDL); |
79a65726 | 2451 | return 0; |
25541f2f | 2452 | } |
be6be08d TL |
2453 | } |
2454 | } else if (token == ELSIF) { | |
2455 | token = next_token (&val, cfile); | |
79a65726 TL |
2456 | if (!parse_if_statement (&(*result) -> data.ie.false, |
2457 | cfile, lose)) { | |
166e63eb TL |
2458 | if (!*lose) |
2459 | parse_warn (cfile, | |
2460 | "expecting conditional."); | |
4bd8800e | 2461 | executable_statement_dereference (result, MDL); |
166e63eb TL |
2462 | *lose = 1; |
2463 | return 0; | |
79a65726 | 2464 | } |
be6be08d | 2465 | } else |
79a65726 | 2466 | (*result) -> data.ie.false = (struct executable_statement *)0; |
be6be08d | 2467 | |
79a65726 | 2468 | return 1; |
be6be08d TL |
2469 | } |
2470 | ||
2471 | /* | |
2472 | * boolean_expression :== CHECK STRING | | |
2473 | * NOT boolean-expression | | |
2474 | * data-expression EQUAL data-expression | | |
2b965a44 | 2475 | * data-expression BANG EQUAL data-expression | |
be6be08d TL |
2476 | * boolean-expression AND boolean-expression | |
2477 | * boolean-expression OR boolean-expression | |
02a015fb | 2478 | * EXISTS OPTION-NAME |
be6be08d TL |
2479 | */ |
2480 | ||
02a015fb TL |
2481 | int parse_boolean_expression (expr, cfile, lose) |
2482 | struct expression **expr; | |
4615d498 | 2483 | struct parse *cfile; |
02a015fb TL |
2484 | int *lose; |
2485 | { | |
2486 | /* Parse an expression... */ | |
2487 | if (!parse_expression (expr, cfile, lose, context_boolean, | |
2488 | (struct expression **)0, expr_none)) | |
2489 | return 0; | |
2490 | ||
08514fb8 TL |
2491 | if (!is_boolean_expression (*expr) && |
2492 | (*expr) -> op != expr_variable_reference && | |
2493 | (*expr) -> op != expr_funcall) { | |
4615d498 | 2494 | parse_warn (cfile, "Expecting a boolean expression."); |
02a015fb | 2495 | *lose = 1; |
4bd8800e | 2496 | expression_dereference (expr, MDL); |
02a015fb TL |
2497 | return 0; |
2498 | } | |
2499 | return 1; | |
2500 | } | |
2501 | ||
2502 | /* | |
2503 | * data_expression :== SUBSTRING LPAREN data-expression COMMA | |
2504 | * numeric-expression COMMA | |
2505 | * numeric-expression RPAREN | | |
a82abfc7 TL |
2506 | * CONCAT LPAREN data-expression COMMA |
2507 | data-expression RPAREN | |
02a015fb | 2508 | * SUFFIX LPAREN data_expression COMMA |
a82abfc7 | 2509 | * numeric-expression RPAREN | |
02a015fb TL |
2510 | * OPTION option_name | |
2511 | * HARDWARE | | |
2512 | * PACKET LPAREN numeric-expression COMMA | |
2513 | * numeric-expression RPAREN | | |
2514 | * STRING | | |
2515 | * colon_seperated_hex_list | |
2516 | */ | |
2517 | ||
2518 | int parse_data_expression (expr, cfile, lose) | |
2519 | struct expression **expr; | |
4615d498 | 2520 | struct parse *cfile; |
02a015fb TL |
2521 | int *lose; |
2522 | { | |
2523 | /* Parse an expression... */ | |
2524 | if (!parse_expression (expr, cfile, lose, context_data, | |
2525 | (struct expression **)0, expr_none)) | |
2526 | return 0; | |
2527 | ||
08514fb8 TL |
2528 | if (!is_data_expression (*expr) && |
2529 | (*expr) -> op != expr_variable_reference && | |
2530 | (*expr) -> op != expr_funcall) { | |
4615d498 | 2531 | parse_warn (cfile, "Expecting a data expression."); |
02a015fb TL |
2532 | *lose = 1; |
2533 | return 0; | |
2534 | } | |
2535 | return 1; | |
2536 | } | |
2537 | ||
2538 | /* | |
2539 | * numeric-expression :== EXTRACT_INT LPAREN data-expression | |
2540 | * COMMA number RPAREN | | |
2541 | * NUMBER | |
2542 | */ | |
2543 | ||
2544 | int parse_numeric_expression (expr, cfile, lose) | |
2545 | struct expression **expr; | |
4615d498 | 2546 | struct parse *cfile; |
02a015fb TL |
2547 | int *lose; |
2548 | { | |
2549 | /* Parse an expression... */ | |
2550 | if (!parse_expression (expr, cfile, lose, context_numeric, | |
2551 | (struct expression **)0, expr_none)) | |
2552 | return 0; | |
2553 | ||
08514fb8 TL |
2554 | if (!is_numeric_expression (*expr) && |
2555 | (*expr) -> op != expr_variable_reference && | |
2556 | (*expr) -> op != expr_funcall) { | |
4615d498 | 2557 | parse_warn (cfile, "Expecting a numeric expression."); |
02a015fb TL |
2558 | *lose = 1; |
2559 | return 0; | |
2560 | } | |
2561 | return 1; | |
2562 | } | |
2563 | ||
9fb2fb28 TL |
2564 | /* |
2565 | * dns-expression :== | |
2566 | * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA | |
2567 | * data-expression COMMA numeric-expression RPAREN | |
2568 | * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA | |
2569 | * data-expression RPAREN | |
2570 | * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA | |
2571 | * data-expression RPAREN | |
2572 | * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA | |
2573 | * data-expression RPAREN | |
2574 | * ns-class :== IN | CHAOS | HS | NUMBER | |
2575 | * ns-type :== A | PTR | MX | TXT | NUMBER | |
2576 | */ | |
2577 | ||
2578 | int parse_dns_expression (expr, cfile, lose) | |
2579 | struct expression **expr; | |
2580 | struct parse *cfile; | |
2581 | int *lose; | |
2582 | { | |
2583 | /* Parse an expression... */ | |
2584 | if (!parse_expression (expr, cfile, lose, context_dns, | |
2585 | (struct expression **)0, expr_none)) | |
2586 | return 0; | |
2587 | ||
08514fb8 TL |
2588 | if (!is_dns_expression (*expr) && |
2589 | (*expr) -> op != expr_variable_reference && | |
2590 | (*expr) -> op != expr_funcall) { | |
9fb2fb28 TL |
2591 | parse_warn (cfile, "Expecting a dns update subexpression."); |
2592 | *lose = 1; | |
2593 | return 0; | |
2594 | } | |
2595 | return 1; | |
2596 | } | |
2597 | ||
02a015fb | 2598 | /* Parse a subexpression that does not contain a binary operator. */ |
be6be08d | 2599 | |
02a015fb TL |
2600 | int parse_non_binary (expr, cfile, lose, context) |
2601 | struct expression **expr; | |
4615d498 | 2602 | struct parse *cfile; |
be6be08d | 2603 | int *lose; |
02a015fb | 2604 | enum expression_context context; |
be6be08d | 2605 | { |
02a015fb | 2606 | enum dhcp_token token; |
b1b7b521 | 2607 | const char *val; |
be6be08d | 2608 | struct collection *col; |
02a015fb | 2609 | struct option *option; |
08514fb8 | 2610 | struct expression *nexp, **ep; |
b1b7b521 | 2611 | int known; |
9fb2fb28 | 2612 | enum expr_op opcode; |
f579f39f | 2613 | const char *s; |
08514fb8 | 2614 | char *cptr; |
fdac15d9 TL |
2615 | struct executable_statement *stmt; |
2616 | int i; | |
08514fb8 | 2617 | unsigned long u; |
be6be08d TL |
2618 | |
2619 | token = peek_token (&val, cfile); | |
2620 | ||
2621 | /* Check for unary operators... */ | |
2622 | switch (token) { | |
2623 | case CHECK: | |
2624 | token = next_token (&val, cfile); | |
2625 | token = next_token (&val, cfile); | |
2626 | if (token != STRING) { | |
4615d498 | 2627 | parse_warn (cfile, "string expected."); |
be6be08d TL |
2628 | skip_to_semi (cfile); |
2629 | *lose = 1; | |
02a015fb | 2630 | return 0; |
be6be08d TL |
2631 | } |
2632 | for (col = collections; col; col = col -> next) | |
2633 | if (!strcmp (col -> name, val)) | |
2634 | break; | |
2635 | if (!col) { | |
4615d498 | 2636 | parse_warn (cfile, "unknown collection."); |
be6be08d | 2637 | *lose = 1; |
02a015fb | 2638 | return 0; |
be6be08d | 2639 | } |
4bd8800e | 2640 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 2641 | log_fatal ("can't allocate expression"); |
02a015fb TL |
2642 | (*expr) -> op = expr_check; |
2643 | (*expr) -> data.check = col; | |
2644 | break; | |
be6be08d | 2645 | |
5e6fb153 | 2646 | case TOKEN_NOT: |
be6be08d | 2647 | token = next_token (&val, cfile); |
9fb2fb28 TL |
2648 | if (context == context_dns) { |
2649 | token = peek_token (&val, cfile); | |
2650 | goto not_exists; | |
2651 | } | |
4bd8800e | 2652 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 2653 | log_fatal ("can't allocate expression"); |
02a015fb TL |
2654 | (*expr) -> op = expr_not; |
2655 | if (!parse_non_binary (&(*expr) -> data.not, | |
2656 | cfile, lose, context)) { | |
be6be08d | 2657 | if (!*lose) { |
4615d498 | 2658 | parse_warn (cfile, "expression expected"); |
be6be08d TL |
2659 | skip_to_semi (cfile); |
2660 | } | |
2661 | *lose = 1; | |
4bd8800e | 2662 | expression_dereference (expr, MDL); |
02a015fb | 2663 | return 0; |
be6be08d | 2664 | } |
be6be08d | 2665 | break; |
be6be08d | 2666 | |
fcd9651f TL |
2667 | case LPAREN: |
2668 | token = next_token (&val, cfile); | |
2669 | if (!parse_expression (expr, cfile, lose, context, | |
2670 | (struct expression **)0, expr_none)) { | |
2671 | if (!*lose) { | |
2672 | parse_warn (cfile, "expression expected"); | |
2673 | skip_to_semi (cfile); | |
2674 | } | |
2675 | *lose = 1; | |
2676 | return 0; | |
2677 | } | |
2678 | token = next_token (&val, cfile); | |
2679 | if (token != RPAREN) { | |
2680 | *lose = 1; | |
2681 | parse_warn (cfile, "right paren expected"); | |
2682 | skip_to_semi (cfile); | |
2683 | return 0; | |
2684 | } | |
2685 | break; | |
2686 | ||
02a015fb | 2687 | case EXISTS: |
9fb2fb28 TL |
2688 | if (context == context_dns) |
2689 | goto ns_exists; | |
02a015fb | 2690 | token = next_token (&val, cfile); |
4bd8800e | 2691 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 2692 | log_fatal ("can't allocate expression"); |
02a015fb | 2693 | (*expr) -> op = expr_exists; |
b1b7b521 TL |
2694 | known = 0; |
2695 | (*expr) -> data.option = parse_option_name (cfile, 0, &known); | |
02a015fb TL |
2696 | if (!(*expr) -> data.option) { |
2697 | *lose = 1; | |
4bd8800e | 2698 | expression_dereference (expr, MDL); |
02a015fb | 2699 | return 0; |
be6be08d | 2700 | } |
02a015fb | 2701 | break; |
be6be08d | 2702 | |
1c5d5731 TL |
2703 | case STATIC: |
2704 | token = next_token (&val, cfile); | |
4bd8800e | 2705 | if (!expression_allocate (expr, MDL)) |
1c5d5731 TL |
2706 | log_fatal ("can't allocate expression"); |
2707 | (*expr) -> op = expr_static; | |
2708 | break; | |
2709 | ||
70330633 TL |
2710 | case KNOWN: |
2711 | token = next_token (&val, cfile); | |
4bd8800e | 2712 | if (!expression_allocate (expr, MDL)) |
70330633 TL |
2713 | log_fatal ("can't allocate expression"); |
2714 | (*expr) -> op = expr_known; | |
2715 | break; | |
2716 | ||
be6be08d TL |
2717 | case SUBSTRING: |
2718 | token = next_token (&val, cfile); | |
4bd8800e | 2719 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 2720 | log_fatal ("can't allocate expression"); |
02a015fb | 2721 | (*expr) -> op = expr_substring; |
be6be08d TL |
2722 | |
2723 | token = next_token (&val, cfile); | |
2724 | if (token != LPAREN) { | |
2725 | nolparen: | |
4bd8800e | 2726 | expression_dereference (expr, MDL); |
4615d498 | 2727 | parse_warn (cfile, "left parenthesis expected."); |
be6be08d | 2728 | *lose = 1; |
02a015fb | 2729 | return 0; |
be6be08d TL |
2730 | } |
2731 | ||
02a015fb TL |
2732 | if (!parse_data_expression (&(*expr) -> data.substring.expr, |
2733 | cfile, lose)) { | |
be6be08d | 2734 | nodata: |
4bd8800e | 2735 | expression_dereference (expr, MDL); |
4615d498 | 2736 | parse_warn (cfile, "expecting data expression."); |
be6be08d TL |
2737 | skip_to_semi (cfile); |
2738 | *lose = 1; | |
02a015fb | 2739 | return 0; |
be6be08d TL |
2740 | } |
2741 | ||
2742 | token = next_token (&val, cfile); | |
2743 | if (token != COMMA) { | |
2744 | nocomma: | |
4bd8800e | 2745 | expression_dereference (expr, MDL); |
4615d498 | 2746 | parse_warn (cfile, "comma expected."); |
be6be08d | 2747 | *lose = 1; |
02a015fb TL |
2748 | |
2749 | return 0; | |
be6be08d TL |
2750 | } |
2751 | ||
02a015fb TL |
2752 | if (!parse_numeric_expression |
2753 | (&(*expr) -> data.substring.offset,cfile, lose)) { | |
be6be08d TL |
2754 | nonum: |
2755 | if (!*lose) { | |
4615d498 TL |
2756 | parse_warn (cfile, |
2757 | "expecting numeric expression."); | |
be6be08d TL |
2758 | skip_to_semi (cfile); |
2759 | *lose = 1; | |
2760 | } | |
4bd8800e | 2761 | expression_dereference (expr, MDL); |
02a015fb | 2762 | return 0; |
be6be08d TL |
2763 | } |
2764 | ||
2765 | token = next_token (&val, cfile); | |
2766 | if (token != COMMA) | |
2767 | goto nocomma; | |
2768 | ||
02a015fb TL |
2769 | if (!parse_numeric_expression |
2770 | (&(*expr) -> data.substring.len, cfile, lose)) | |
be6be08d TL |
2771 | goto nonum; |
2772 | ||
2773 | token = next_token (&val, cfile); | |
2774 | if (token != RPAREN) { | |
2775 | norparen: | |
4615d498 | 2776 | parse_warn (cfile, "right parenthesis expected."); |
be6be08d | 2777 | *lose = 1; |
4bd8800e | 2778 | expression_dereference (expr, MDL); |
02a015fb | 2779 | return 0; |
be6be08d | 2780 | } |
02a015fb | 2781 | break; |
be6be08d TL |
2782 | |
2783 | case SUFFIX: | |
2784 | token = next_token (&val, cfile); | |
4bd8800e | 2785 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 2786 | log_fatal ("can't allocate expression"); |
02a015fb | 2787 | (*expr) -> op = expr_suffix; |
be6be08d TL |
2788 | |
2789 | token = next_token (&val, cfile); | |
2790 | if (token != LPAREN) | |
2791 | goto nolparen; | |
2792 | ||
02a015fb TL |
2793 | if (!parse_data_expression (&(*expr) -> data.suffix.expr, |
2794 | cfile, lose)) | |
be6be08d TL |
2795 | goto nodata; |
2796 | ||
2797 | token = next_token (&val, cfile); | |
2798 | if (token != COMMA) | |
2799 | goto nocomma; | |
2800 | ||
02a015fb TL |
2801 | if (!parse_data_expression (&(*expr) -> data.suffix.len, |
2802 | cfile, lose)) | |
be6be08d TL |
2803 | goto nonum; |
2804 | ||
2805 | token = next_token (&val, cfile); | |
2806 | if (token != RPAREN) | |
2807 | goto norparen; | |
02a015fb | 2808 | break; |
be6be08d | 2809 | |
a82abfc7 TL |
2810 | case CONCAT: |
2811 | token = next_token (&val, cfile); | |
4bd8800e | 2812 | if (!expression_allocate (expr, MDL)) |
a82abfc7 TL |
2813 | log_fatal ("can't allocate expression"); |
2814 | (*expr) -> op = expr_concat; | |
2815 | ||
2816 | token = next_token (&val, cfile); | |
2817 | if (token != LPAREN) | |
2818 | goto nolparen; | |
2819 | ||
2820 | if (!parse_data_expression (&(*expr) -> data.concat [0], | |
2821 | cfile, lose)) | |
2822 | goto nodata; | |
2823 | ||
2824 | token = next_token (&val, cfile); | |
2825 | if (token != COMMA) | |
2826 | goto nocomma; | |
2827 | ||
720c8262 | 2828 | concat_another: |
a82abfc7 TL |
2829 | if (!parse_data_expression (&(*expr) -> data.concat [1], |
2830 | cfile, lose)) | |
2831 | goto nodata; | |
2832 | ||
2833 | token = next_token (&val, cfile); | |
720c8262 TL |
2834 | |
2835 | if (token == COMMA) { | |
2836 | nexp = (struct expression *)0; | |
4bd8800e | 2837 | if (!expression_allocate (&nexp, MDL)) |
720c8262 TL |
2838 | log_fatal ("can't allocate at CONCAT2"); |
2839 | nexp -> op = expr_concat; | |
4bd8800e TL |
2840 | expression_reference (&nexp -> data.concat [0], |
2841 | *expr, MDL); | |
2842 | expression_dereference (expr, MDL); | |
2843 | expression_reference (expr, nexp, MDL); | |
720c8262 TL |
2844 | goto concat_another; |
2845 | } | |
2846 | ||
a82abfc7 TL |
2847 | if (token != RPAREN) |
2848 | goto norparen; | |
2849 | break; | |
2850 | ||
da38df14 TL |
2851 | case BINARY_TO_ASCII: |
2852 | token = next_token (&val, cfile); | |
4bd8800e | 2853 | if (!expression_allocate (expr, MDL)) |
da38df14 | 2854 | log_fatal ("can't allocate expression"); |
eb42f00e | 2855 | (*expr) -> op = expr_binary_to_ascii; |
da38df14 TL |
2856 | |
2857 | token = next_token (&val, cfile); | |
2858 | if (token != LPAREN) | |
2859 | goto nolparen; | |
2860 | ||
2861 | if (!parse_numeric_expression (&(*expr) -> data.b2a.base, | |
2862 | cfile, lose)) | |
2863 | goto nodata; | |
2864 | ||
2865 | token = next_token (&val, cfile); | |
2866 | if (token != COMMA) | |
2867 | goto nocomma; | |
2868 | ||
2869 | if (!parse_numeric_expression (&(*expr) -> data.b2a.width, | |
2870 | cfile, lose)) | |
2871 | goto nodata; | |
2872 | ||
2873 | token = next_token (&val, cfile); | |
2874 | if (token != COMMA) | |
2875 | goto nocomma; | |
2876 | ||
2877 | if (!parse_data_expression (&(*expr) -> data.b2a.seperator, | |
2878 | cfile, lose)) | |
2879 | goto nodata; | |
2880 | ||
2881 | token = next_token (&val, cfile); | |
2882 | if (token != COMMA) | |
2883 | goto nocomma; | |
2884 | ||
2885 | if (!parse_data_expression (&(*expr) -> data.b2a.buffer, | |
2886 | cfile, lose)) | |
2887 | goto nodata; | |
2888 | ||
2889 | token = next_token (&val, cfile); | |
2890 | if (token != RPAREN) | |
2891 | goto norparen; | |
2892 | break; | |
2893 | ||
2894 | case REVERSE: | |
2895 | token = next_token (&val, cfile); | |
4bd8800e | 2896 | if (!expression_allocate (expr, MDL)) |
da38df14 | 2897 | log_fatal ("can't allocate expression"); |
eb42f00e | 2898 | (*expr) -> op = expr_reverse; |
da38df14 TL |
2899 | |
2900 | token = next_token (&val, cfile); | |
2901 | if (token != LPAREN) | |
2902 | goto nolparen; | |
2903 | ||
2904 | if (!(parse_numeric_expression | |
2905 | (&(*expr) -> data.reverse.width, cfile, lose))) | |
2906 | goto nodata; | |
2907 | ||
2908 | token = next_token (&val, cfile); | |
2909 | if (token != COMMA) | |
2910 | goto nocomma; | |
2911 | ||
2912 | if (!(parse_data_expression | |
2913 | (&(*expr) -> data.reverse.buffer, cfile, lose))) | |
2914 | goto nodata; | |
2915 | ||
2916 | token = next_token (&val, cfile); | |
2917 | if (token != RPAREN) | |
2918 | goto norparen; | |
2919 | break; | |
2920 | ||
fdac15d9 | 2921 | case PICK: |
79a65726 TL |
2922 | /* pick (a, b, c) actually produces an internal representation |
2923 | that looks like pick (a, pick (b, pick (c, nil))). */ | |
2924 | token = next_token (&val, cfile); | |
4bd8800e | 2925 | if (!(expression_allocate (expr, MDL))) |
79a65726 | 2926 | log_fatal ("can't allocate expression"); |
79a65726 | 2927 | |
be6be08d | 2928 | token = next_token (&val, cfile); |
79a65726 TL |
2929 | if (token != LPAREN) |
2930 | goto nolparen; | |
2931 | ||
2932 | nexp = *expr; | |
2933 | do { | |
392208d3 | 2934 | nexp -> op = expr_pick_first_value; |
79a65726 TL |
2935 | if (!(parse_data_expression |
2936 | (&nexp -> data.pick_first_value.car, | |
2937 | cfile, lose))) | |
2938 | goto nodata; | |
2939 | ||
2940 | token = next_token (&val, cfile); | |
2941 | if (token == COMMA) { | |
2942 | if (!(expression_allocate | |
2943 | (&nexp -> data.pick_first_value.cdr, | |
4bd8800e | 2944 | MDL))) |
79a65726 TL |
2945 | log_fatal ("can't allocate expr"); |
2946 | nexp = nexp -> data.pick_first_value.cdr; | |
2947 | } | |
2948 | } while (token == COMMA); | |
2949 | ||
2950 | if (token != RPAREN) | |
2951 | goto norparen; | |
2952 | break; | |
2953 | ||
9fb2fb28 TL |
2954 | /* dns-update and dns-delete are present for historical |
2955 | purposes, but are deprecated in favor of ns-update | |
2956 | in combination with update, delete, exists and not | |
2957 | exists. */ | |
069e9f4c | 2958 | case DNS_UPDATE: |
9fb2fb28 | 2959 | case DNS_DELETE: |
069e9f4c | 2960 | #if !defined (NSUPDATE) |
4615d498 TL |
2961 | parse_warn (cfile, |
2962 | "Please rebuild dhcpd with --with-nsupdate."); | |
069e9f4c | 2963 | #endif |
fdac15d9 | 2964 | token = next_token (&val, cfile); |
9fb2fb28 | 2965 | if (token == DNS_UPDATE) |
f579f39f | 2966 | opcode = expr_ns_add; |
9fb2fb28 TL |
2967 | else |
2968 | opcode = expr_ns_delete; | |
2969 | ||
069e9f4c TL |
2970 | token = next_token (&val, cfile); |
2971 | if (token != LPAREN) | |
2972 | goto nolparen; | |
2973 | ||
9fb2fb28 TL |
2974 | token = next_token (&val, cfile); |
2975 | if (token != STRING) { | |
2976 | parse_warn (cfile, | |
2977 | "parse_expression: expecting string."); | |
2978 | badnsupdate: | |
069e9f4c TL |
2979 | skip_to_semi (cfile); |
2980 | *lose = 1; | |
2981 | return 0; | |
2982 | } | |
9fb2fb28 TL |
2983 | |
2984 | if (!strcasecmp (val, "a")) | |
08514fb8 | 2985 | u = T_A; |
9fb2fb28 | 2986 | else if (!strcasecmp (val, "ptr")) |
08514fb8 | 2987 | u = T_PTR; |
9fb2fb28 | 2988 | else if (!strcasecmp (val, "mx")) |
08514fb8 | 2989 | u = T_MX; |
9fb2fb28 | 2990 | else if (!strcasecmp (val, "cname")) |
08514fb8 | 2991 | u = T_CNAME; |
9fb2fb28 | 2992 | else if (!strcasecmp (val, "TXT")) |
08514fb8 | 2993 | u = T_TXT; |
9fb2fb28 TL |
2994 | else { |
2995 | parse_warn (cfile, "unexpected rrtype: %s", val); | |
2996 | goto badnsupdate; | |
2997 | } | |
fdac15d9 | 2998 | |
08514fb8 TL |
2999 | s = (opcode == expr_ns_add |
3000 | ? "old-dns-update" | |
3001 | : "old-dns-delete"); | |
3002 | cptr = dmalloc (strlen (s) + 1, MDL); | |
3003 | if (!cptr) | |
3004 | log_fatal ("can't allocate name for %s", s); | |
3005 | strcpy (cptr, s); | |
4bd8800e | 3006 | if (!expression_allocate (expr, MDL)) |
fdac15d9 | 3007 | log_fatal ("can't allocate expression"); |
fdac15d9 | 3008 | (*expr) -> op = expr_funcall; |
08514fb8 | 3009 | (*expr) -> data.funcall.name = cptr; |
fdac15d9 | 3010 | |
08514fb8 TL |
3011 | /* Fake up a function call. */ |
3012 | ep = &(*expr) -> data.funcall.arglist; | |
3013 | if (!expression_allocate (ep, MDL)) | |
3014 | log_fatal ("can't allocate expression"); | |
3015 | (*ep) -> op = expr_arg; | |
3016 | if (!make_const_int (&(*ep) -> data.arg.val, u)) | |
fdac15d9 | 3017 | log_fatal ("can't allocate rrtype value."); |
069e9f4c TL |
3018 | |
3019 | token = next_token (&val, cfile); | |
3020 | if (token != COMMA) | |
3021 | goto nocomma; | |
08514fb8 TL |
3022 | ep = &((*ep) -> data.arg.next); |
3023 | if (!expression_allocate (ep, MDL)) | |
3024 | log_fatal ("can't allocate expression"); | |
3025 | (*ep) -> op = expr_arg; | |
3026 | if (!(parse_data_expression (&(*ep) -> data.arg.val, | |
fdac15d9 | 3027 | cfile, lose))) |
069e9f4c TL |
3028 | goto nodata; |
3029 | ||
3030 | token = next_token (&val, cfile); | |
3031 | if (token != COMMA) | |
3032 | goto nocomma; | |
3033 | ||
08514fb8 TL |
3034 | ep = &((*ep) -> data.arg.next); |
3035 | if (!expression_allocate (ep, MDL)) | |
3036 | log_fatal ("can't allocate expression"); | |
3037 | (*ep) -> op = expr_arg; | |
3038 | if (!(parse_data_expression (&(*ep) -> data.arg.val, | |
fdac15d9 | 3039 | cfile, lose))) |
069e9f4c TL |
3040 | goto nodata; |
3041 | ||
f579f39f | 3042 | if (opcode == expr_ns_add) { |
9fb2fb28 TL |
3043 | token = next_token (&val, cfile); |
3044 | if (token != COMMA) | |
3045 | goto nocomma; | |
3046 | ||
08514fb8 TL |
3047 | ep = &((*ep) -> data.arg.next); |
3048 | if (!expression_allocate (ep, MDL)) | |
3049 | log_fatal ("can't allocate expression"); | |
3050 | (*ep) -> op = expr_arg; | |
3051 | if (!(parse_numeric_expression (&(*ep) -> data.arg.val, | |
3052 | cfile, lose))) { | |
9fb2fb28 | 3053 | parse_warn (cfile, |
fdac15d9 | 3054 | "expecting numeric expression."); |
9fb2fb28 TL |
3055 | goto badnsupdate; |
3056 | } | |
069e9f4c | 3057 | } |
08514fb8 | 3058 | |
069e9f4c TL |
3059 | token = next_token (&val, cfile); |
3060 | if (token != RPAREN) | |
3061 | goto norparen; | |
3062 | break; | |
3063 | ||
9fb2fb28 | 3064 | case NS_UPDATE: |
88886e12 TL |
3065 | #if !defined (NSUPDATE) |
3066 | parse_warn (cfile, | |
3067 | "Please rebuild dhcpd with --with-nsupdate."); | |
3068 | #endif | |
3069 | token = next_token (&val, cfile); | |
4bd8800e | 3070 | if (!expression_allocate (expr, MDL)) |
88886e12 | 3071 | log_fatal ("can't allocate expression"); |
88886e12 TL |
3072 | |
3073 | token = next_token (&val, cfile); | |
3074 | if (token != LPAREN) | |
3075 | goto nolparen; | |
3076 | ||
9fb2fb28 TL |
3077 | nexp = *expr; |
3078 | do { | |
3079 | nexp -> op = expr_dns_transaction; | |
3080 | if (!(parse_dns_expression | |
3081 | (&nexp -> data.dns_transaction.car, | |
3082 | cfile, lose))) | |
3083 | { | |
f579f39f TL |
3084 | if (!*lose) |
3085 | parse_warn | |
3086 | (cfile, | |
3087 | "expecting dns expression."); | |
9fb2fb28 | 3088 | badnstrans: |
4bd8800e | 3089 | expression_dereference (expr, MDL); |
9fb2fb28 TL |
3090 | *lose = 1; |
3091 | return 0; | |
3092 | } | |
3093 | ||
3094 | token = next_token (&val, cfile); | |
3095 | ||
3096 | if (token == COMMA) { | |
3097 | if (!(expression_allocate | |
3098 | (&nexp -> data.dns_transaction.cdr, | |
4bd8800e | 3099 | MDL))) |
9fb2fb28 TL |
3100 | log_fatal |
3101 | ("can't allocate expression"); | |
3102 | nexp = nexp -> data.dns_transaction.cdr; | |
3103 | } | |
3104 | } while (token == COMMA); | |
3105 | ||
3106 | if (token != RPAREN) | |
3107 | goto norparen; | |
3108 | break; | |
3109 | ||
3110 | /* NOT EXISTS is special cased above... */ | |
3111 | not_exists: | |
fdac15d9 TL |
3112 | token = peek_token (&val, cfile); |
3113 | if (token != EXISTS) { | |
3114 | parse_warn (cfile, "expecting DNS prerequisite."); | |
3115 | *lose = 1; | |
3116 | return 0; | |
3117 | } | |
9fb2fb28 TL |
3118 | opcode = expr_ns_not_exists; |
3119 | goto nsupdatecode; | |
f579f39f TL |
3120 | case TOKEN_ADD: |
3121 | opcode = expr_ns_add; | |
9fb2fb28 TL |
3122 | goto nsupdatecode; |
3123 | case TOKEN_DELETE: | |
3124 | opcode = expr_ns_delete; | |
3125 | goto nsupdatecode; | |
3126 | ns_exists: | |
3127 | opcode = expr_ns_exists; | |
3128 | nsupdatecode: | |
3129 | token = next_token (&val, cfile); | |
3130 | ||
3131 | #if !defined (NSUPDATE) | |
3132 | parse_warn (cfile, | |
3133 | "Please rebuild dhcpd with --with-nsupdate."); | |
3134 | #endif | |
4bd8800e | 3135 | if (!expression_allocate (expr, MDL)) |
9fb2fb28 TL |
3136 | log_fatal ("can't allocate expression"); |
3137 | (*expr) -> op = opcode; | |
3138 | ||
3139 | token = next_token (&val, cfile); | |
3140 | if (token != LPAREN) | |
3141 | goto nolparen; | |
3142 | ||
3143 | token = next_token (&val, cfile); | |
3144 | if (!is_identifier (token) && token != NUMBER) { | |
3145 | parse_warn (cfile, "expecting identifier or number."); | |
3146 | badnsop: | |
4bd8800e | 3147 | expression_dereference (expr, MDL); |
88886e12 TL |
3148 | skip_to_semi (cfile); |
3149 | *lose = 1; | |
3150 | return 0; | |
3151 | } | |
9fb2fb28 TL |
3152 | |
3153 | if (token == NUMBER) | |
f579f39f | 3154 | (*expr) -> data.ns_add.rrclass = atoi (val); |
9fb2fb28 | 3155 | else if (!strcasecmp (val, "in")) |
f579f39f | 3156 | (*expr) -> data.ns_add.rrclass = C_IN; |
9fb2fb28 | 3157 | else if (!strcasecmp (val, "chaos")) |
f579f39f | 3158 | (*expr) -> data.ns_add.rrclass = C_CHAOS; |
9fb2fb28 | 3159 | else if (!strcasecmp (val, "hs")) |
f579f39f | 3160 | (*expr) -> data.ns_add.rrclass = C_HS; |
9fb2fb28 TL |
3161 | else { |
3162 | parse_warn (cfile, "unexpected rrclass: %s", val); | |
3163 | goto badnsop; | |
3164 | } | |
3165 | ||
f579f39f TL |
3166 | token = next_token (&val, cfile); |
3167 | if (token != COMMA) | |
3168 | goto nocomma; | |
3169 | ||
9fb2fb28 TL |
3170 | token = next_token (&val, cfile); |
3171 | if (!is_identifier (token) && token != NUMBER) { | |
3172 | parse_warn (cfile, "expecting identifier or number."); | |
3173 | goto badnsop; | |
3174 | } | |
3175 | ||
3176 | if (token == NUMBER) | |
f579f39f | 3177 | (*expr) -> data.ns_add.rrtype = atoi (val); |
9fb2fb28 | 3178 | else if (!strcasecmp (val, "a")) |
f579f39f | 3179 | (*expr) -> data.ns_add.rrtype = T_A; |
9fb2fb28 | 3180 | else if (!strcasecmp (val, "ptr")) |
f579f39f | 3181 | (*expr) -> data.ns_add.rrtype = T_PTR; |
9fb2fb28 | 3182 | else if (!strcasecmp (val, "mx")) |
f579f39f | 3183 | (*expr) -> data.ns_add.rrtype = T_MX; |
9fb2fb28 | 3184 | else if (!strcasecmp (val, "cname")) |
f579f39f | 3185 | (*expr) -> data.ns_add.rrtype = T_CNAME; |
9fb2fb28 | 3186 | else if (!strcasecmp (val, "TXT")) |
f579f39f | 3187 | (*expr) -> data.ns_add.rrtype = T_TXT; |
9fb2fb28 TL |
3188 | else { |
3189 | parse_warn (cfile, "unexpected rrtype: %s", val); | |
3190 | goto badnsop; | |
3191 | } | |
88886e12 TL |
3192 | |
3193 | token = next_token (&val, cfile); | |
3194 | if (token != COMMA) | |
3195 | goto nocomma; | |
3196 | ||
3197 | if (!(parse_data_expression | |
f579f39f | 3198 | (&(*expr) -> data.ns_add.rrname, cfile, lose))) |
88886e12 TL |
3199 | goto nodata; |
3200 | ||
3201 | token = next_token (&val, cfile); | |
3202 | if (token != COMMA) | |
3203 | goto nocomma; | |
3204 | ||
3205 | if (!(parse_data_expression | |
f579f39f | 3206 | (&(*expr) -> data.ns_add.rrdata, cfile, lose))) |
88886e12 TL |
3207 | goto nodata; |
3208 | ||
f579f39f | 3209 | if (opcode == expr_ns_add) { |
9fb2fb28 TL |
3210 | token = next_token (&val, cfile); |
3211 | if (token != COMMA) | |
3212 | goto nocomma; | |
3213 | ||
3214 | if (!(parse_numeric_expression | |
f579f39f TL |
3215 | (&(*expr) -> data.ns_add.ttl, cfile, |
3216 | lose))) { | |
9fb2fb28 TL |
3217 | parse_warn (cfile, |
3218 | "expecting data expression."); | |
3219 | goto badnsupdate; | |
3220 | } | |
3221 | } | |
3222 | ||
88886e12 TL |
3223 | token = next_token (&val, cfile); |
3224 | if (token != RPAREN) | |
3225 | goto norparen; | |
3226 | break; | |
3227 | ||
79a65726 TL |
3228 | case OPTION: |
3229 | case CONFIG_OPTION: | |
4bd8800e | 3230 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 3231 | log_fatal ("can't allocate expression"); |
cd31814f TL |
3232 | (*expr) -> op = (token == OPTION |
3233 | ? expr_option | |
3234 | : expr_config_option); | |
79a65726 | 3235 | token = next_token (&val, cfile); |
b1b7b521 TL |
3236 | known = 0; |
3237 | (*expr) -> data.option = parse_option_name (cfile, 0, &known); | |
02a015fb | 3238 | if (!(*expr) -> data.option) { |
be6be08d | 3239 | *lose = 1; |
4bd8800e | 3240 | expression_dereference (expr, MDL); |
02a015fb | 3241 | return 0; |
be6be08d | 3242 | } |
02a015fb | 3243 | break; |
be6be08d TL |
3244 | |
3245 | case HARDWARE: | |
3246 | token = next_token (&val, cfile); | |
4bd8800e | 3247 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 3248 | log_fatal ("can't allocate expression"); |
02a015fb TL |
3249 | (*expr) -> op = expr_hardware; |
3250 | break; | |
be6be08d | 3251 | |
da38df14 TL |
3252 | case LEASED_ADDRESS: |
3253 | token = next_token (&val, cfile); | |
4bd8800e | 3254 | if (!expression_allocate (expr, MDL)) |
da38df14 TL |
3255 | log_fatal ("can't allocate expression"); |
3256 | (*expr) -> op = expr_leased_address; | |
3257 | break; | |
3258 | ||
fdac15d9 TL |
3259 | case FILENAME: |
3260 | token = next_token (&val, cfile); | |
4bd8800e | 3261 | if (!expression_allocate (expr, MDL)) |
fdac15d9 TL |
3262 | log_fatal ("can't allocate expression"); |
3263 | (*expr) -> op = expr_filename; | |
3264 | break; | |
3265 | ||
3266 | case SERVER_NAME: | |
3267 | token = next_token (&val, cfile); | |
4bd8800e | 3268 | if (!expression_allocate (expr, MDL)) |
fdac15d9 TL |
3269 | log_fatal ("can't allocate expression"); |
3270 | (*expr) -> op = expr_sname; | |
3271 | break; | |
3272 | ||
069e9f4c TL |
3273 | case LEASE_TIME: |
3274 | token = next_token (&val, cfile); | |
4bd8800e | 3275 | if (!expression_allocate (expr, MDL)) |
069e9f4c TL |
3276 | log_fatal ("can't allocate expression"); |
3277 | (*expr) -> op = expr_lease_time; | |
3278 | break; | |
3279 | ||
f579f39f TL |
3280 | case TOKEN_NULL: |
3281 | token = next_token (&val, cfile); | |
4bd8800e | 3282 | if (!expression_allocate (expr, MDL)) |
f579f39f TL |
3283 | log_fatal ("can't allocate expression"); |
3284 | (*expr) -> op = expr_null; | |
3285 | break; | |
3286 | ||
79a65726 TL |
3287 | case HOST_DECL_NAME: |
3288 | token = next_token (&val, cfile); | |
4bd8800e | 3289 | if (!expression_allocate (expr, MDL)) |
79a65726 TL |
3290 | log_fatal ("can't allocate expression"); |
3291 | (*expr) -> op = expr_host_decl_name; | |
3292 | break; | |
3293 | ||
846d7d54 | 3294 | case UPDATED_DNS_RR: |
06a8567c | 3295 | token = next_token (&val, cfile); |
06a8567c | 3296 | |
06a8567c | 3297 | token = next_token (&val, cfile); |
846d7d54 TL |
3298 | if (token != LPAREN) |
3299 | goto nolparen; | |
f579f39f TL |
3300 | |
3301 | token = next_token (&val, cfile); | |
3302 | if (token != STRING) { | |
3303 | parse_warn (cfile, "expecting string."); | |
3304 | bad_rrtype: | |
3305 | *lose = 1; | |
3306 | return 0; | |
3307 | } | |
3308 | if (!strcasecmp (val, "a")) | |
3309 | s = "ddns-fwd-name"; | |
3310 | else if (!strcasecmp (val, "ptr")) | |
3311 | s = "ddns-rev-name"; | |
3312 | else { | |
3313 | parse_warn (cfile, "invalid DNS rrtype: %s", val); | |
3314 | goto bad_rrtype; | |
3315 | } | |
846d7d54 TL |
3316 | |
3317 | token = next_token (&val, cfile); | |
3318 | if (token != RPAREN) | |
3319 | goto norparen; | |
3320 | ||
4bd8800e | 3321 | if (!expression_allocate (expr, MDL)) |
f579f39f TL |
3322 | log_fatal ("can't allocate expression"); |
3323 | (*expr) -> op = expr_variable_reference; | |
3324 | (*expr) -> data.variable = | |
fdac15d9 | 3325 | dmalloc (strlen (s) + 1, MDL); |
f579f39f TL |
3326 | if (!(*expr) -> data.variable) |
3327 | log_fatal ("can't allocate variable name."); | |
3328 | strcpy ((*expr) -> data.variable, s); | |
06a8567c TL |
3329 | break; |
3330 | ||
be6be08d TL |
3331 | case PACKET: |
3332 | token = next_token (&val, cfile); | |
4bd8800e | 3333 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 3334 | log_fatal ("can't allocate expression"); |
02a015fb | 3335 | (*expr) -> op = expr_packet; |
be6be08d TL |
3336 | |
3337 | token = next_token (&val, cfile); | |
3338 | if (token != LPAREN) | |
3339 | goto nolparen; | |
3340 | ||
02a015fb TL |
3341 | if (!parse_numeric_expression (&(*expr) -> data.packet.offset, |
3342 | cfile, lose)) | |
be6be08d TL |
3343 | goto nonum; |
3344 | ||
3345 | token = next_token (&val, cfile); | |
3346 | if (token != COMMA) | |
3347 | goto nocomma; | |
3348 | ||
02a015fb TL |
3349 | if (!parse_numeric_expression (&(*expr) -> data.packet.len, |
3350 | cfile, lose)) | |
be6be08d TL |
3351 | goto nonum; |
3352 | ||
3353 | token = next_token (&val, cfile); | |
3354 | if (token != RPAREN) | |
3355 | goto norparen; | |
02a015fb | 3356 | break; |
be6be08d TL |
3357 | |
3358 | case STRING: | |
3359 | token = next_token (&val, cfile); | |
b1b7b521 | 3360 | if (!make_const_data (expr, (const unsigned char *)val, |
c5b0f529 | 3361 | strlen (val), 1, 1)) |
8ae2d595 | 3362 | log_fatal ("can't make constant string expression."); |
02a015fb | 3363 | break; |
be6be08d | 3364 | |
be6be08d TL |
3365 | case EXTRACT_INT: |
3366 | token = next_token (&val, cfile); | |
be6be08d TL |
3367 | token = next_token (&val, cfile); |
3368 | if (token != LPAREN) { | |
4615d498 | 3369 | parse_warn (cfile, "left parenthesis expected."); |
be6be08d | 3370 | *lose = 1; |
02a015fb | 3371 | return 0; |
be6be08d TL |
3372 | } |
3373 | ||
4bd8800e | 3374 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 3375 | log_fatal ("can't allocate expression"); |
02a015fb TL |
3376 | |
3377 | if (!parse_data_expression (&(*expr) -> data.extract_int, | |
3378 | cfile, lose)) { | |
4615d498 | 3379 | parse_warn (cfile, "expecting data expression."); |
be6be08d TL |
3380 | skip_to_semi (cfile); |
3381 | *lose = 1; | |
4bd8800e | 3382 | expression_dereference (expr, MDL); |
02a015fb | 3383 | return 0; |
be6be08d TL |
3384 | } |
3385 | ||
3386 | token = next_token (&val, cfile); | |
3387 | if (token != COMMA) { | |
4615d498 | 3388 | parse_warn (cfile, "comma expected."); |
be6be08d | 3389 | *lose = 1; |
4bd8800e | 3390 | expression_dereference (expr, MDL); |
02a015fb | 3391 | return 0; |
be6be08d TL |
3392 | } |
3393 | ||
3394 | token = next_token (&val, cfile); | |
3395 | if (token != NUMBER) { | |
4615d498 | 3396 | parse_warn (cfile, "number expected."); |
be6be08d | 3397 | *lose = 1; |
4bd8800e | 3398 | expression_dereference (expr, MDL); |
02a015fb | 3399 | return 0; |
be6be08d | 3400 | } |
be6be08d TL |
3401 | switch (atoi (val)) { |
3402 | case 8: | |
02a015fb | 3403 | (*expr) -> op = expr_extract_int8; |
be6be08d TL |
3404 | break; |
3405 | ||
3406 | case 16: | |
02a015fb | 3407 | (*expr) -> op = expr_extract_int16; |
be6be08d TL |
3408 | break; |
3409 | ||
3410 | case 32: | |
02a015fb | 3411 | (*expr) -> op = expr_extract_int32; |
be6be08d TL |
3412 | break; |
3413 | ||
3414 | default: | |
4615d498 TL |
3415 | parse_warn (cfile, |
3416 | "unsupported integer size %d", atoi (val)); | |
be6be08d TL |
3417 | *lose = 1; |
3418 | skip_to_semi (cfile); | |
4bd8800e | 3419 | expression_dereference (expr, MDL); |
02a015fb | 3420 | return 0; |
be6be08d TL |
3421 | } |
3422 | ||
3423 | token = next_token (&val, cfile); | |
3424 | if (token != RPAREN) { | |
4615d498 | 3425 | parse_warn (cfile, "right parenthesis expected."); |
be6be08d | 3426 | *lose = 1; |
4bd8800e | 3427 | expression_dereference (expr, MDL); |
02a015fb | 3428 | return 0; |
be6be08d | 3429 | } |
02a015fb | 3430 | break; |
be6be08d | 3431 | |
20c4e94d TL |
3432 | case ENCODE_INT: |
3433 | token = next_token (&val, cfile); | |
3434 | token = next_token (&val, cfile); | |
3435 | if (token != LPAREN) { | |
4615d498 | 3436 | parse_warn (cfile, "left parenthesis expected."); |
20c4e94d TL |
3437 | *lose = 1; |
3438 | return 0; | |
3439 | } | |
3440 | ||
4bd8800e | 3441 | if (!expression_allocate (expr, MDL)) |
20c4e94d TL |
3442 | log_fatal ("can't allocate expression"); |
3443 | ||
3444 | if (!parse_numeric_expression (&(*expr) -> data.encode_int, | |
3445 | cfile, lose)) { | |
4615d498 | 3446 | parse_warn (cfile, "expecting numeric expression."); |
20c4e94d TL |
3447 | skip_to_semi (cfile); |
3448 | *lose = 1; | |
4bd8800e | 3449 | expression_dereference (expr, MDL); |
20c4e94d TL |
3450 | return 0; |
3451 | } | |
3452 | ||
3453 | token = next_token (&val, cfile); | |
3454 | if (token != COMMA) { | |
4615d498 | 3455 | parse_warn (cfile, "comma expected."); |
20c4e94d | 3456 | *lose = 1; |
4bd8800e | 3457 | expression_dereference (expr, MDL); |
20c4e94d TL |
3458 | return 0; |
3459 | } | |
3460 | ||
3461 | token = next_token (&val, cfile); | |
3462 | if (token != NUMBER) { | |
4615d498 | 3463 | parse_warn (cfile, "number expected."); |
20c4e94d | 3464 | *lose = 1; |
4bd8800e | 3465 | expression_dereference (expr, MDL); |
20c4e94d TL |
3466 | return 0; |
3467 | } | |
3468 | switch (atoi (val)) { | |
3469 | case 8: | |
3470 | (*expr) -> op = expr_encode_int8; | |
3471 | break; | |
3472 | ||
3473 | case 16: | |
3474 | (*expr) -> op = expr_encode_int16; | |
3475 | break; | |
3476 | ||
3477 | case 32: | |
3478 | (*expr) -> op = expr_encode_int32; | |
3479 | break; | |
3480 | ||
3481 | default: | |
4615d498 TL |
3482 | parse_warn (cfile, |
3483 | "unsupported integer size %d", atoi (val)); | |
20c4e94d TL |
3484 | *lose = 1; |
3485 | skip_to_semi (cfile); | |
4bd8800e | 3486 | expression_dereference (expr, MDL); |
20c4e94d TL |
3487 | return 0; |
3488 | } | |
3489 | ||
3490 | token = next_token (&val, cfile); | |
3491 | if (token != RPAREN) { | |
4615d498 | 3492 | parse_warn (cfile, "right parenthesis expected."); |
20c4e94d | 3493 | *lose = 1; |
4bd8800e | 3494 | expression_dereference (expr, MDL); |
20c4e94d TL |
3495 | return 0; |
3496 | } | |
3497 | break; | |
3498 | ||
be6be08d | 3499 | case NUMBER: |
02a015fb TL |
3500 | /* If we're in a numeric context, this should just be a |
3501 | number, by itself. */ | |
f579f39f TL |
3502 | if (context == context_numeric || |
3503 | context == context_data_or_numeric) { | |
02a015fb | 3504 | next_token (&val, cfile); /* Eat the number. */ |
4bd8800e | 3505 | if (!expression_allocate (expr, MDL)) |
be19167d | 3506 | log_fatal ("can't allocate expression"); |
02a015fb TL |
3507 | (*expr) -> op = expr_const_int; |
3508 | (*expr) -> data.const_int = atoi (val); | |
3509 | break; | |
3510 | } | |
be6be08d | 3511 | |
02a015fb | 3512 | case NUMBER_OR_NAME: |
4bd8800e | 3513 | if (!expression_allocate (expr, MDL)) |
be19167d TL |
3514 | log_fatal ("can't allocate expression"); |
3515 | ||
02a015fb TL |
3516 | (*expr) -> op = expr_const_data; |
3517 | if (!parse_cshl (&(*expr) -> data.const_data, cfile)) { | |
4bd8800e | 3518 | expression_dereference (expr, MDL); |
02a015fb TL |
3519 | return 0; |
3520 | } | |
3521 | break; | |
3522 | ||
f579f39f TL |
3523 | case NS_FORMERR: |
3524 | known = FORMERR; | |
3525 | ns_const: | |
3526 | token = next_token (&val, cfile); | |
4bd8800e | 3527 | if (!expression_allocate (expr, MDL)) |
f579f39f TL |
3528 | log_fatal ("can't allocate expression"); |
3529 | (*expr) -> op = expr_const_int; | |
3530 | (*expr) -> data.const_int = known; | |
3531 | break; | |
3532 | ||
3533 | case NS_NOERROR: | |
3534 | known = NOERROR; | |
3535 | goto ns_const; | |
3536 | ||
3537 | case NS_NOTAUTH: | |
3538 | known = NOTAUTH; | |
3539 | goto ns_const; | |
3540 | ||
3541 | case NS_NOTIMP: | |
3542 | known = NOTIMP; | |
3543 | goto ns_const; | |
3544 | ||
3545 | case NS_NOTZONE: | |
3546 | known = NOTZONE; | |
3547 | goto ns_const; | |
3548 | ||
3549 | case NS_NXDOMAIN: | |
3550 | known = NXDOMAIN; | |
3551 | goto ns_const; | |
3552 | ||
3553 | case NS_NXRRSET: | |
3554 | known = NXRRSET; | |
3555 | goto ns_const; | |
3556 | ||
3557 | case NS_REFUSED: | |
3558 | known = REFUSED; | |
3559 | goto ns_const; | |
3560 | ||
3561 | case NS_SERVFAIL: | |
3562 | known = SERVFAIL; | |
3563 | goto ns_const; | |
3564 | ||
3565 | case NS_YXDOMAIN: | |
3566 | known = YXDOMAIN; | |
3567 | goto ns_const; | |
3568 | ||
3569 | case NS_YXRRSET: | |
3570 | known = YXRRSET; | |
3571 | goto ns_const; | |
3572 | ||
3573 | case DEFINED: | |
3574 | token = next_token (&val, cfile); | |
3575 | token = next_token (&val, cfile); | |
3576 | if (token != LPAREN) | |
3577 | goto nolparen; | |
3578 | ||
3579 | token = next_token (&val, cfile); | |
3580 | if (token != NAME && token != NUMBER_OR_NAME) { | |
3581 | parse_warn (cfile, "%s can't be a variable name", val); | |
3582 | skip_to_semi (cfile); | |
3583 | *lose = 1; | |
3584 | return 0; | |
3585 | } | |
3586 | ||
4bd8800e | 3587 | if (!expression_allocate (expr, MDL)) |
f579f39f TL |
3588 | log_fatal ("can't allocate expression"); |
3589 | (*expr) -> op = expr_variable_exists; | |
fdac15d9 | 3590 | (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL); |
f579f39f TL |
3591 | if (!(*expr)->data.variable) |
3592 | log_fatal ("can't allocate variable name"); | |
3593 | strcpy ((*expr) -> data.variable, val); | |
3594 | token = next_token (&val, cfile); | |
3595 | if (token != RPAREN) | |
3596 | goto norparen; | |
3597 | break; | |
3598 | ||
02a015fb | 3599 | /* Not a valid start to an expression... */ |
be6be08d | 3600 | default: |
f579f39f TL |
3601 | if (token != NAME && token != NUMBER_OR_NAME) |
3602 | return 0; | |
3603 | ||
08514fb8 TL |
3604 | token = next_token (&val, cfile); |
3605 | ||
3606 | /* Save the name of the variable being referenced. */ | |
3607 | cptr = dmalloc (strlen (val) + 1, MDL); | |
3608 | if (!cptr) | |
3609 | log_fatal ("can't allocate variable name"); | |
3610 | strcpy (cptr, val); | |
3611 | ||
3612 | /* Simple variable reference, as far as we can tell. */ | |
3613 | token = peek_token (&val, cfile); | |
3614 | if (token != LPAREN) { | |
3615 | if (!expression_allocate (expr, MDL)) | |
3616 | log_fatal ("can't allocate expression"); | |
3617 | (*expr) -> op = expr_variable_reference; | |
3618 | (*expr) -> data.variable = cptr; | |
3619 | break; | |
3620 | } | |
3621 | ||
f579f39f | 3622 | token = next_token (&val, cfile); |
4bd8800e | 3623 | if (!expression_allocate (expr, MDL)) |
f579f39f | 3624 | log_fatal ("can't allocate expression"); |
08514fb8 TL |
3625 | (*expr) -> op = expr_funcall; |
3626 | (*expr) -> data.funcall.name = cptr; | |
3627 | ||
3628 | /* Now parse the argument list. */ | |
3629 | ep = &(*expr) -> data.funcall.arglist; | |
3630 | do { | |
3631 | if (!expression_allocate (ep, MDL)) | |
3632 | log_fatal ("can't allocate expression"); | |
3633 | (*ep) -> op = expr_arg; | |
3634 | if (!parse_expression (&(*ep) -> data.arg.val, | |
3635 | cfile, lose, context_any, | |
3636 | (struct expression **)0, | |
3637 | expr_none)) { | |
3638 | if (!*lose) { | |
3639 | parse_warn (cfile, | |
3640 | "expecting expression."); | |
3641 | *lose = 1; | |
3642 | } | |
3643 | skip_to_semi (cfile); | |
3644 | expression_dereference (expr, MDL); | |
3645 | return 0; | |
3646 | } | |
3647 | ep = &((*ep) -> data.arg.next); | |
3648 | token = next_token (&val, cfile); | |
3649 | } while (token == COMMA); | |
3650 | if (token != RPAREN) { | |
3651 | parse_warn (cfile, "Right parenthesis expected."); | |
3652 | skip_to_semi (cfile); | |
3653 | *lose = 1; | |
3654 | expression_dereference (expr, MDL); | |
3655 | return 0; | |
3656 | } | |
f579f39f | 3657 | break; |
be6be08d | 3658 | } |
02a015fb | 3659 | return 1; |
be6be08d TL |
3660 | } |
3661 | ||
02a015fb TL |
3662 | /* Parse an expression. */ |
3663 | ||
3664 | int parse_expression (expr, cfile, lose, context, plhs, binop) | |
3665 | struct expression **expr; | |
4615d498 | 3666 | struct parse *cfile; |
02a015fb TL |
3667 | int *lose; |
3668 | enum expression_context context; | |
3669 | struct expression **plhs; | |
3670 | enum expr_op binop; | |
3671 | { | |
3672 | enum dhcp_token token; | |
b1b7b521 | 3673 | const char *val; |
02a015fb TL |
3674 | struct expression *rhs = (struct expression *)0, *tmp; |
3675 | struct expression *lhs; | |
3676 | enum expr_op next_op; | |
3677 | ||
3678 | /* Consume the left hand side we were passed. */ | |
3679 | if (plhs) { | |
3680 | lhs = *plhs; | |
3681 | *plhs = (struct expression *)0; | |
3682 | } else | |
3683 | lhs = (struct expression *)0; | |
3684 | ||
3685 | new_rhs: | |
3686 | if (!parse_non_binary (&rhs, cfile, lose, context)) { | |
3687 | /* If we already have a left-hand side, then it's not | |
3688 | okay for there not to be a right-hand side here, so | |
3689 | we need to flag it as an error. */ | |
3690 | if (lhs) { | |
3691 | if (!*lose) { | |
4615d498 TL |
3692 | parse_warn (cfile, |
3693 | "expecting right-hand side."); | |
02a015fb TL |
3694 | *lose = 1; |
3695 | skip_to_semi (cfile); | |
3696 | } | |
4bd8800e | 3697 | expression_dereference (&lhs, MDL); |
02a015fb TL |
3698 | } |
3699 | return 0; | |
3700 | } | |
3701 | ||
3702 | /* At this point, rhs contains either an entire subexpression, | |
3703 | or at least a left-hand-side. If we do not see a binary token | |
3704 | as the next token, we're done with the expression. */ | |
3705 | ||
3706 | token = peek_token (&val, cfile); | |
3707 | switch (token) { | |
2b965a44 TL |
3708 | case BANG: |
3709 | token = next_token (&val, cfile); | |
3710 | token = peek_token (&val, cfile); | |
3711 | if (token != EQUAL) { | |
3712 | parse_warn (cfile, "! in boolean context without ="); | |
3713 | *lose = 1; | |
3714 | skip_to_semi (cfile); | |
3715 | if (lhs) | |
4bd8800e | 3716 | expression_dereference (&lhs, MDL); |
2b965a44 TL |
3717 | return 0; |
3718 | } | |
3719 | next_op = expr_not_equal; | |
3720 | break; | |
3721 | ||
02a015fb TL |
3722 | case EQUAL: |
3723 | next_op = expr_equal; | |
3724 | break; | |
3725 | ||
3726 | case AND: | |
3727 | next_op = expr_and; | |
3728 | break; | |
3729 | ||
3730 | case OR: | |
3731 | next_op = expr_or; | |
3732 | break; | |
3733 | ||
31cb2a5f TL |
3734 | case PLUS: |
3735 | next_op = expr_add; | |
3736 | break; | |
3737 | ||
3738 | case MINUS: | |
3739 | next_op = expr_subtract; | |
3740 | break; | |
3741 | ||
3742 | case SLASH: | |
3743 | next_op = expr_divide; | |
3744 | break; | |
3745 | ||
3746 | case ASTERISK: | |
3747 | next_op = expr_multiply; | |
3748 | break; | |
3749 | ||
3750 | case PERCENT: | |
3751 | next_op = expr_remainder; | |
3752 | break; | |
3753 | ||
3c98e80b DN |
3754 | case AMPERSAND: |
3755 | next_op = expr_binary_and; | |
3756 | break; | |
3757 | ||
3758 | case PIPE: | |
3759 | next_op = expr_binary_or; | |
3760 | break; | |
3761 | ||
3762 | case CARET: | |
3763 | next_op = expr_binary_xor; | |
3764 | break; | |
3765 | ||
02a015fb TL |
3766 | default: |
3767 | next_op = expr_none; | |
3768 | } | |
3769 | ||
3770 | /* If we have no lhs yet, we just parsed it. */ | |
3771 | if (!lhs) { | |
3772 | /* If there was no operator following what we just parsed, | |
3773 | then we're done - return it. */ | |
3774 | if (next_op == expr_none) { | |
3775 | *expr = rhs; | |
3776 | return 1; | |
3777 | } | |
3778 | lhs = rhs; | |
3779 | rhs = (struct expression *)0; | |
3780 | binop = next_op; | |
3781 | next_token (&val, cfile); /* Consume the operator. */ | |
3782 | goto new_rhs; | |
3783 | } | |
3784 | ||
3785 | /* Now, if we didn't find a binary operator, we're done parsing | |
3786 | this subexpression, so combine it with the preceding binary | |
3787 | operator and return the result. */ | |
3788 | if (next_op == expr_none) { | |
4bd8800e | 3789 | if (!expression_allocate (expr, MDL)) |
8ae2d595 | 3790 | log_fatal ("Can't allocate expression!"); |
02a015fb TL |
3791 | |
3792 | (*expr) -> op = binop; | |
3793 | /* All the binary operators' data union members | |
3794 | are the same, so we'll cheat and use the member | |
3795 | for the equals operator. */ | |
3796 | (*expr) -> data.equal [0] = lhs; | |
3797 | (*expr) -> data.equal [1] = rhs; | |
3798 | return 1; | |
3799 | } | |
3800 | ||
3801 | /* Eat the operator token - we now know it was a binary operator... */ | |
3802 | token = next_token (&val, cfile); | |
3803 | ||
3804 | /* If the binary operator we saw previously has a lower precedence | |
3805 | than the next operator, then the rhs we just parsed for that | |
3806 | operator is actually the lhs of the operator with the higher | |
3807 | precedence - to get the real rhs, we need to recurse on the | |
3808 | new operator. */ | |
3809 | if (binop != expr_none && | |
3810 | op_precedence (binop, next_op) < 0) { | |
3811 | tmp = rhs; | |
3812 | rhs = (struct expression *)0; | |
3813 | if (!parse_expression (&rhs, cfile, lose, op_context (next_op), | |
3814 | &tmp, next_op)) { | |
3815 | if (!*lose) { | |
4615d498 TL |
3816 | parse_warn (cfile, |
3817 | "expecting a subexpression"); | |
02a015fb TL |
3818 | *lose = 1; |
3819 | } | |
3820 | return 0; | |
3821 | } | |
3822 | next_op = expr_none; | |
3823 | } | |
3824 | ||
3825 | /* Now combine the LHS and the RHS using binop. */ | |
3826 | tmp = (struct expression *)0; | |
4bd8800e | 3827 | if (!expression_allocate (&tmp, MDL)) |
8ae2d595 | 3828 | log_fatal ("No memory for equal precedence combination."); |
02a015fb TL |
3829 | |
3830 | /* Store the LHS and RHS. */ | |
3831 | tmp -> data.equal [0] = lhs; | |
3832 | tmp -> data.equal [1] = rhs; | |
3833 | tmp -> op = binop; | |
3834 | ||
3835 | lhs = tmp; | |
3836 | tmp = (struct expression *)0; | |
3837 | rhs = (struct expression *)0; | |
3838 | ||
3839 | /* Recursions don't return until we have parsed the end of the | |
3840 | expression, so if we recursed earlier, we can now return what | |
3841 | we got. */ | |
3842 | if (next_op == expr_none) { | |
3843 | *expr = lhs; | |
3844 | return 1; | |
3845 | } | |
3846 | ||
3847 | binop = next_op; | |
3848 | goto new_rhs; | |
3849 | } | |
3850 | ||
be6be08d TL |
3851 | /* option-statement :== identifier DOT identifier <syntax> SEMI |
3852 | | identifier <syntax> SEMI | |
3853 | ||
3854 | Option syntax is handled specially through format strings, so it | |
3855 | would be painful to come up with BNF for it. However, it always | |
3856 | starts as above and ends in a SEMI. */ | |
3857 | ||
79a65726 TL |
3858 | int parse_option_statement (result, cfile, lookups, option, op) |
3859 | struct executable_statement **result; | |
4615d498 | 3860 | struct parse *cfile; |
be6be08d TL |
3861 | int lookups; |
3862 | struct option *option; | |
3863 | enum statement_op op; | |
3864 | { | |
b1b7b521 | 3865 | const char *val; |
02a015fb | 3866 | enum dhcp_token token; |
d8fc5060 | 3867 | const char *fmt = NULL; |
be6be08d | 3868 | struct expression *expr = (struct expression *)0; |
02a015fb | 3869 | struct expression *tmp; |
be6be08d TL |
3870 | int lose; |
3871 | struct executable_statement *stmt; | |
02a015fb | 3872 | int ftt = 1; |
be6be08d TL |
3873 | |
3874 | token = peek_token (&val, cfile); | |
3875 | if (token == SEMI) { | |
3876 | /* Eat the semicolon... */ | |
3877 | token = next_token (&val, cfile); | |
be6be08d TL |
3878 | goto done; |
3879 | } | |
3880 | ||
a82abfc7 TL |
3881 | if (token == EQUAL) { |
3882 | /* Eat the equals sign. */ | |
3883 | token = next_token (&val, cfile); | |
3884 | ||
3885 | /* Parse a data expression and use its value for the data. */ | |
3886 | if (!parse_data_expression (&expr, cfile, &lose)) { | |
3887 | /* In this context, we must have an executable | |
3888 | statement, so if we found something else, it's | |
3889 | still an error. */ | |
3890 | if (!lose) { | |
4615d498 TL |
3891 | parse_warn (cfile, |
3892 | "expecting a data expression."); | |
a82abfc7 TL |
3893 | skip_to_semi (cfile); |
3894 | } | |
79a65726 | 3895 | return 0; |
a82abfc7 TL |
3896 | } |
3897 | ||
3898 | /* We got a valid expression, so use it. */ | |
3899 | goto done; | |
3900 | } | |
3901 | ||
be6be08d TL |
3902 | /* Parse the option data... */ |
3903 | do { | |
3904 | /* Set a flag if this is an array of a simple type (i.e., | |
3905 | not an array of pairs of IP addresses, or something | |
3906 | like that. */ | |
3907 | int uniform = option -> format [1] == 'A'; | |
3908 | ||
d8fc5060 TL |
3909 | and_again: |
3910 | /* Set fmt to start of format for 'A' and one char back | |
3911 | for 'a' */ | |
3912 | if ((fmt != NULL) && | |
3913 | (fmt != option -> format) && (*fmt == 'a')) | |
3914 | fmt -= 1; | |
3915 | else | |
3916 | fmt = ((fmt == NULL) || | |
3917 | (*fmt == 'A')) ? option -> format : fmt; | |
3918 | ||
3919 | /* 'a' means always uniform */ | |
3920 | uniform |= (fmt [1] == 'a'); | |
3921 | ||
3922 | for ( ; *fmt; fmt++) { | |
3923 | if ((*fmt == 'A') || (*fmt == 'a')) | |
be6be08d | 3924 | break; |
d8fc5060 TL |
3925 | if (*fmt == 'o') |
3926 | continue; | |
02a015fb | 3927 | tmp = expr; |
44aa67f6 | 3928 | expr = (struct expression *)0; |
02a015fb TL |
3929 | if (!parse_option_token (&expr, cfile, fmt, |
3930 | tmp, uniform, lookups)) { | |
d8fc5060 TL |
3931 | if (fmt [1] != 'o') { |
3932 | if (tmp) | |
3933 | expression_dereference (&tmp, | |
3934 | MDL); | |
3935 | return 0; | |
3936 | } | |
3937 | expr = tmp; | |
3938 | tmp = (struct expression *)0; | |
02a015fb TL |
3939 | } |
3940 | if (tmp) | |
4bd8800e | 3941 | expression_dereference (&tmp, MDL); |
be6be08d | 3942 | } |
d8fc5060 | 3943 | if ((*fmt == 'A') || (*fmt == 'a')) { |
be6be08d | 3944 | token = peek_token (&val, cfile); |
d8fc5060 | 3945 | /* Comma means: continue with next element in array */ |
be6be08d TL |
3946 | if (token == COMMA) { |
3947 | token = next_token (&val, cfile); | |
3948 | continue; | |
3949 | } | |
d8fc5060 TL |
3950 | /* no comma: end of array. |
3951 | 'A' or end of string means: leave the loop */ | |
3952 | if ((*fmt == 'A') || (fmt[1] == '\0')) | |
3953 | break; | |
3954 | /* 'a' means: go on with next char */ | |
3955 | if (*fmt == 'a') { | |
3956 | fmt++; | |
3957 | goto and_again; | |
3958 | } | |
be6be08d | 3959 | } |
d8fc5060 | 3960 | } while ((*fmt == 'A') || (*fmt == 'a')); |
be6be08d TL |
3961 | |
3962 | done: | |
25541f2f | 3963 | if (!parse_semi (cfile)) |
79a65726 | 3964 | return 0; |
4bd8800e | 3965 | if (!executable_statement_allocate (result, MDL)) |
79a65726 TL |
3966 | log_fatal ("no memory for option statement."); |
3967 | (*result) -> op = op; | |
3968 | if (expr && !option_cache (&(*result) -> data.option, | |
02a015fb | 3969 | (struct data_string *)0, expr, option)) |
52c9d530 | 3970 | log_fatal ("no memory for option cache"); |
79a65726 | 3971 | return 1; |
be6be08d TL |
3972 | } |
3973 | ||
02a015fb TL |
3974 | int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) |
3975 | struct expression **rv; | |
4615d498 | 3976 | struct parse *cfile; |
b1b7b521 | 3977 | const char *fmt; |
be6be08d TL |
3978 | struct expression *expr; |
3979 | int uniform; | |
3980 | int lookups; | |
3981 | { | |
b1b7b521 | 3982 | const char *val; |
02a015fb TL |
3983 | enum dhcp_token token; |
3984 | struct expression *t = (struct expression *)0; | |
be6be08d TL |
3985 | unsigned char buf [4]; |
3986 | int len; | |
3987 | unsigned char *ob; | |
3988 | struct iaddr addr; | |
fdac15d9 | 3989 | int num; |
be6be08d TL |
3990 | |
3991 | switch (*fmt) { | |
52c9d530 | 3992 | case 'U': |
d8fc5060 | 3993 | token = peek_token (&val, cfile); |
52c9d530 | 3994 | if (!is_identifier (token)) { |
d8fc5060 TL |
3995 | if (fmt [1] != 'o') { |
3996 | parse_warn (cfile, "expecting identifier."); | |
3997 | skip_to_semi (cfile); | |
3998 | } | |
52c9d530 TL |
3999 | return 0; |
4000 | } | |
d8fc5060 | 4001 | token = next_token (&val, cfile); |
b1b7b521 | 4002 | if (!make_const_data (&t, (const unsigned char *)val, |
52c9d530 TL |
4003 | strlen (val), 1, 1)) |
4004 | log_fatal ("No memory for %s", val); | |
4005 | break; | |
4006 | ||
be6be08d TL |
4007 | case 'X': |
4008 | token = peek_token (&val, cfile); | |
4009 | if (token == NUMBER_OR_NAME || token == NUMBER) { | |
4bd8800e | 4010 | if (!expression_allocate (&t, MDL)) |
02a015fb | 4011 | return 0; |
8cc4d857 | 4012 | if (!parse_cshl (&t -> data.const_data, cfile)) { |
4bd8800e | 4013 | expression_dereference (&t, MDL); |
01e20b9e | 4014 | return 0; |
8cc4d857 | 4015 | } |
efc79acb | 4016 | t -> op = expr_const_data; |
be6be08d TL |
4017 | } else if (token == STRING) { |
4018 | token = next_token (&val, cfile); | |
b1b7b521 | 4019 | if (!make_const_data (&t, (const unsigned char *)val, |
02a015fb | 4020 | strlen (val), 1, 1)) |
52c9d530 | 4021 | log_fatal ("No memory for \"%s\"", val); |
be6be08d | 4022 | } else { |
d8fc5060 TL |
4023 | if (fmt [1] != 'o') { |
4024 | parse_warn (cfile, "expecting string %s.", | |
4025 | "or hexadecimal data"); | |
4026 | skip_to_semi (cfile); | |
4027 | } | |
02a015fb | 4028 | return 0; |
be6be08d TL |
4029 | } |
4030 | break; | |
4031 | ||
4032 | case 't': /* Text string... */ | |
d8fc5060 | 4033 | token = peek_token (&val, cfile); |
be6be08d | 4034 | if (token != STRING && !is_identifier (token)) { |
d8fc5060 TL |
4035 | if (fmt [1] != 'o') { |
4036 | parse_warn (cfile, "expecting string."); | |
4037 | if (token != SEMI) | |
4038 | skip_to_semi (cfile); | |
4039 | } | |
02a015fb | 4040 | return 0; |
be6be08d | 4041 | } |
d8fc5060 | 4042 | token = next_token (&val, cfile); |
b1b7b521 | 4043 | if (!make_const_data (&t, (const unsigned char *)val, |
02a015fb | 4044 | strlen (val), 1, 1)) |
8ae2d595 | 4045 | log_fatal ("No memory for concatenation"); |
be6be08d TL |
4046 | break; |
4047 | ||
4048 | case 'I': /* IP address or hostname. */ | |
02a015fb TL |
4049 | if (lookups) { |
4050 | if (!parse_ip_addr_or_hostname (&t, cfile, uniform)) | |
4051 | return 0; | |
4052 | } else { | |
be6be08d | 4053 | if (!parse_ip_addr (cfile, &addr)) |
02a015fb TL |
4054 | return 0; |
4055 | if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1)) | |
4056 | return 0; | |
be6be08d | 4057 | } |
be6be08d TL |
4058 | break; |
4059 | ||
fdac15d9 | 4060 | case 'T': /* Lease interval. */ |
d8fc5060 | 4061 | token = peek_token (&val, cfile); |
fdac15d9 TL |
4062 | if (token != INFINITE) |
4063 | goto check_number; | |
d8fc5060 | 4064 | token = next_token (&val, cfile); |
fdac15d9 TL |
4065 | putLong (buf, -1); |
4066 | if (!make_const_data (&t, buf, 4, 0, 1)) | |
4067 | return 0; | |
4068 | break; | |
4069 | ||
be6be08d TL |
4070 | case 'L': /* Unsigned 32-bit integer... */ |
4071 | case 'l': /* Signed 32-bit integer... */ | |
d8fc5060 | 4072 | token = peek_token (&val, cfile); |
fdac15d9 | 4073 | check_number: |
be6be08d TL |
4074 | if (token != NUMBER) { |
4075 | need_number: | |
d8fc5060 TL |
4076 | if (fmt [1] != 'o') { |
4077 | parse_warn (cfile, "expecting number."); | |
4078 | if (token != SEMI) | |
4079 | skip_to_semi (cfile); | |
4080 | } | |
02a015fb | 4081 | return 0; |
be6be08d | 4082 | } |
d8fc5060 | 4083 | token = next_token (&val, cfile); |
4615d498 | 4084 | convert_num (cfile, buf, val, 0, 32); |
02a015fb TL |
4085 | if (!make_const_data (&t, buf, 4, 0, 1)) |
4086 | return 0; | |
be6be08d | 4087 | break; |
02a015fb | 4088 | |
be6be08d TL |
4089 | case 's': /* Signed 16-bit integer. */ |
4090 | case 'S': /* Unsigned 16-bit integer. */ | |
d8fc5060 | 4091 | token = peek_token (&val, cfile); |
be6be08d TL |
4092 | if (token != NUMBER) |
4093 | goto need_number; | |
d8fc5060 | 4094 | token = next_token (&val, cfile); |
4615d498 | 4095 | convert_num (cfile, buf, val, 0, 16); |
02a015fb TL |
4096 | if (!make_const_data (&t, buf, 2, 0, 1)) |
4097 | return 0; | |
be6be08d | 4098 | break; |
02a015fb | 4099 | |
be6be08d TL |
4100 | case 'b': /* Signed 8-bit integer. */ |
4101 | case 'B': /* Unsigned 8-bit integer. */ | |
d8fc5060 | 4102 | token = peek_token (&val, cfile); |
be6be08d TL |
4103 | if (token != NUMBER) |
4104 | goto need_number; | |
d8fc5060 | 4105 | token = next_token (&val, cfile); |
4615d498 | 4106 | convert_num (cfile, buf, val, 0, 8); |
02a015fb TL |
4107 | if (!make_const_data (&t, buf, 1, 0, 1)) |
4108 | return 0; | |
be6be08d | 4109 | break; |
02a015fb | 4110 | |
be6be08d | 4111 | case 'f': /* Boolean flag. */ |
d8fc5060 | 4112 | token = peek_token (&val, cfile); |
be6be08d | 4113 | if (!is_identifier (token)) { |
d8fc5060 TL |
4114 | if (fmt [1] != 'o') |
4115 | parse_warn (cfile, "expecting identifier."); | |
be6be08d | 4116 | bad_flag: |
d8fc5060 TL |
4117 | if (fmt [1] != 'o') { |
4118 | if (token != SEMI) | |
4119 | skip_to_semi (cfile); | |
4120 | } | |
02a015fb | 4121 | return 0; |
be6be08d TL |
4122 | } |
4123 | if (!strcasecmp (val, "true") | |
4124 | || !strcasecmp (val, "on")) | |
4125 | buf [0] = 1; | |
4126 | else if (!strcasecmp (val, "false") | |
4127 | || !strcasecmp (val, "off")) | |
4128 | buf [0] = 0; | |
0776fd12 TL |
4129 | else if (!strcasecmp (val, "ignore")) |
4130 | buf [0] = 2; | |
be6be08d | 4131 | else { |
d8fc5060 TL |
4132 | if (fmt [1] != 'o') |
4133 | parse_warn (cfile, "expecting boolean."); | |
be6be08d TL |
4134 | goto bad_flag; |
4135 | } | |
d8fc5060 | 4136 | token = next_token (&val, cfile); |
02a015fb TL |
4137 | if (!make_const_data (&t, buf, 1, 0, 1)) |
4138 | return 0; | |
be6be08d | 4139 | break; |
02a015fb | 4140 | |
be6be08d | 4141 | default: |
4615d498 | 4142 | parse_warn (cfile, "Bad format %c in parse_option_param.", |
f420e08c | 4143 | *fmt); |
be6be08d | 4144 | skip_to_semi (cfile); |
02a015fb | 4145 | return 0; |
be6be08d | 4146 | } |
02a015fb TL |
4147 | if (expr) { |
4148 | if (!make_concat (rv, expr, t)) | |
4149 | return 0; | |
4bd8800e | 4150 | expression_dereference (&t, MDL); |
02a015fb TL |
4151 | } else |
4152 | *rv = t; | |
4153 | return 1; | |
be6be08d | 4154 | } |
74f45f96 | 4155 | |
cfdfb9f1 | 4156 | int parse_warn (struct parse *cfile, const char *fmt, ...) |
4bd8800e TL |
4157 | { |
4158 | va_list list; | |
4bd8800e TL |
4159 | char lexbuf [256]; |
4160 | char mbuf [1024]; | |
4161 | char fbuf [1024]; | |
4162 | unsigned i, lix; | |
4163 | ||
4164 | do_percentm (mbuf, fmt); | |
4165 | #ifndef NO_SNPRINTF | |
4166 | snprintf (fbuf, sizeof fbuf, "%s line %d: %s", | |
4167 | cfile -> tlname, cfile -> lexline, mbuf); | |
4168 | #else | |
4169 | sprintf (fbuf, "%s line %d: %s", | |
4170 | cfile -> tlname, cfile -> lexline, mbuf); | |
4171 | #endif | |
4172 | ||
cfdfb9f1 | 4173 | va_start (list, fmt); |
4bd8800e TL |
4174 | vsnprintf (mbuf, sizeof mbuf, fbuf, list); |
4175 | va_end (list); | |
4176 | ||
4177 | lix = 0; | |
4178 | for (i = 0; | |
4179 | cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) { | |
4180 | if (lix < (sizeof lexbuf) - 1) | |
4181 | lexbuf [lix++] = ' '; | |
4182 | if (cfile -> token_line [i] == '\t') { | |
4183 | for (lix; | |
4184 | lix < (sizeof lexbuf) - 1 && (lix & 7); lix++) | |
4185 | lexbuf [lix] = ' '; | |
4186 | } | |
4187 | } | |
4188 | lexbuf [lix] = 0; | |
4189 | ||
4190 | #ifndef DEBUG | |
4f9e9f47 TL |
4191 | syslog (log_priority | LOG_ERR, "%s", mbuf); |
4192 | syslog (log_priority | LOG_ERR, "%s", cfile -> token_line); | |
4bd8800e TL |
4193 | if (cfile -> lexchar < 81) |
4194 | syslog (log_priority | LOG_ERR, "%s^", lexbuf); | |
4195 | #endif | |
4196 | ||
4197 | if (log_perror) { | |
4198 | write (2, mbuf, strlen (mbuf)); | |
4199 | write (2, "\n", 1); | |
4200 | write (2, cfile -> token_line, strlen (cfile -> token_line)); | |
4201 | write (2, "\n", 1); | |
4202 | if (cfile -> lexchar < 81) | |
4203 | write (2, lexbuf, lix); | |
4204 | write (2, "^\n", 2); | |
4205 | } | |
4206 | ||
4207 | cfile -> warnings_occurred = 1; | |
4208 | ||
4209 | return 0; | |
4210 | } |