]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* confpars.c |
2 | ||
3 | Parser for dhcpd config file... */ | |
4 | ||
5 | /* | |
59b85ebd | 6 | * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. |
95821729 | 7 | * All rights reserved. |
d7837182 TL |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
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. | |
21 | * | |
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 <mellon@fugue.com> in cooperation with Vixie | |
38 | * Enterprises. To learn more about the Internet Software Consortium, | |
39 | * see ``http://www.vix.com/isc''. To learn more about Vixie | |
40 | * Enterprises, see ``http://www.vix.com''. | |
41 | */ | |
42 | ||
43 | #ifndef lint | |
44 | static char copyright[] = | |
028a8588 | 45 | "$Id: confpars.c,v 1.53 1998/11/06 00:31:08 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; |
d7837182 TL |
46 | #endif /* not lint */ |
47 | ||
48 | #include "dhcpd.h" | |
49 | #include "dhctoken.h" | |
50 | ||
51 | static TIME parsed_time; | |
52 | ||
2d59f590 TL |
53 | /* conf-file :== parameters declarations EOF |
54 | parameters :== <nil> | parameter | parameters parameter | |
55 | declarations :== <nil> | declaration | declarations declaration */ | |
d7837182 | 56 | |
88ddda34 | 57 | int readconf () |
d7837182 TL |
58 | { |
59 | FILE *cfile; | |
60 | char *val; | |
6f8fb41f | 61 | enum dhcp_token token; |
2d59f590 | 62 | int declaration = 0; |
d7837182 | 63 | |
e2ac5814 | 64 | new_parse (path_dhcpd_conf); |
7e8381e5 | 65 | |
d7837182 TL |
66 | /* Set up the initial dhcp option universe. */ |
67 | initialize_universes (); | |
68 | ||
e2ac5814 TL |
69 | if ((cfile = fopen (path_dhcpd_conf, "r")) == NULL) |
70 | error ("Can't open %s: %m", path_dhcpd_conf); | |
d7837182 TL |
71 | do { |
72 | token = peek_token (&val, cfile); | |
73 | if (token == EOF) | |
74 | break; | |
2d59f590 | 75 | declaration = parse_statement (cfile, &root_group, |
ece6ea33 TL |
76 | ROOT_GROUP, |
77 | (struct host_decl *)0, | |
78 | declaration); | |
d7837182 | 79 | } while (1); |
88ddda34 TL |
80 | token = next_token (&val, cfile); /* Clear the peek buffer */ |
81 | ||
82 | return !warnings_occurred; | |
1358b874 TL |
83 | } |
84 | ||
2d59f590 | 85 | /* lease-file :== lease-declarations EOF |
5376e3e9 | 86 | lease-statments :== <nil> |
2d59f590 TL |
87 | | lease-declaration |
88 | | lease-declarations lease-declaration */ | |
5376e3e9 | 89 | |
31f26cd3 | 90 | void read_leases () |
1358b874 TL |
91 | { |
92 | FILE *cfile; | |
93 | char *val; | |
6f8fb41f | 94 | enum dhcp_token token; |
1358b874 | 95 | |
e2ac5814 | 96 | new_parse (path_dhcpd_db); |
7dfc8ac2 TL |
97 | |
98 | /* Open the lease file. If we can't open it, fail. The reason | |
99 | for this is that although on initial startup, the absence of | |
100 | a lease file is perfectly benign, if dhcpd has been running | |
101 | and this file is absent, it means that dhcpd tried and failed | |
102 | to rewrite the lease database. If we proceed and the | |
103 | problem which caused the rewrite to fail has been fixed, but no | |
104 | human has corrected the database problem, then we are left | |
105 | thinking that no leases have been assigned to anybody, which | |
106 | could create severe network chaos. */ | |
e2ac5814 | 107 | if ((cfile = fopen (path_dhcpd_db, "r")) == NULL) |
7dfc8ac2 | 108 | error ("Can't open lease database %s: %m -- %s", |
e2ac5814 | 109 | path_dhcpd_db, |
7dfc8ac2 | 110 | "check for failed database rewrite attempt!"); |
1358b874 TL |
111 | do { |
112 | token = next_token (&val, cfile); | |
1358b874 TL |
113 | if (token == EOF) |
114 | break; | |
115 | if (token != LEASE) { | |
116 | warn ("Corrupt lease file - possible data loss!"); | |
117 | skip_to_semi (cfile); | |
118 | } else { | |
7dfc8ac2 | 119 | struct lease *lease; |
2d59f590 | 120 | lease = parse_lease_declaration (cfile); |
7dfc8ac2 | 121 | if (lease) |
1358b874 | 122 | enter_lease (lease); |
7dfc8ac2 | 123 | else |
1f814ff2 | 124 | parse_warn ("possibly corrupt lease file"); |
1358b874 TL |
125 | } |
126 | ||
127 | } while (1); | |
d7837182 TL |
128 | } |
129 | ||
2d59f590 TL |
130 | /* statement :== parameter | declaration |
131 | ||
132 | parameter :== timestamp | |
133 | | DEFAULT_LEASE_TIME lease_time | |
134 | | MAX_LEASE_TIME lease_time | |
135 | | DYNAMIC_BOOTP_LEASE_CUTOFF date | |
136 | | DYNAMIC_BOOTP_LEASE_LENGTH lease_time | |
137 | | BOOT_UNKNOWN_CLIENTS boolean | |
138 | | ONE_LEASE_PER_CLIENT boolean | |
5fea7b10 | 139 | | GET_LEASE_HOSTNAMES boolean |
c256bae9 | 140 | | USE_HOST_DECL_NAME boolean |
2d59f590 TL |
141 | | NEXT_SERVER ip-addr-or-hostname SEMI |
142 | | option_parameter | |
143 | | SERVER-IDENTIFIER ip-addr-or-hostname SEMI | |
144 | | FILENAME string-parameter | |
145 | | SERVER_NAME string-parameter | |
146 | | hardware-parameter | |
147 | | fixed-address-parameter | |
99fd97cc TL |
148 | | ALLOW allow-deny-keyword |
149 | | DENY allow-deny-keyword | |
59b85ebd | 150 | | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean |
2d59f590 TL |
151 | |
152 | declaration :== host-declaration | |
153 | | group-declaration | |
154 | | shared-network-declaration | |
155 | | subnet-declaration | |
156 | | VENDOR_CLASS class-declaration | |
157 | | USER_CLASS class-declaration | |
158 | | RANGE address-range-declaration */ | |
159 | ||
160 | int parse_statement (cfile, group, type, host_decl, declaration) | |
d7837182 | 161 | FILE *cfile; |
7dfc8ac2 TL |
162 | struct group *group; |
163 | int type; | |
164 | struct host_decl *host_decl; | |
2d59f590 | 165 | int declaration; |
d7837182 | 166 | { |
6f8fb41f | 167 | enum dhcp_token token; |
d7837182 | 168 | char *val; |
7dfc8ac2 | 169 | struct shared_network *share; |
7dfc8ac2 | 170 | char *t, *n; |
ece6ea33 TL |
171 | struct expression *expr; |
172 | struct data_string data; | |
7dfc8ac2 | 173 | struct hardware hardware; |
ece6ea33 TL |
174 | struct executable_statement *et, *ep; |
175 | struct option *option; | |
176 | struct option_cache *cache; | |
177 | int lose; | |
d7837182 | 178 | |
ece6ea33 | 179 | switch (peek_token (&val, cfile)) { |
d7837182 | 180 | case HOST: |
ece6ea33 TL |
181 | next_token (&val, cfile); |
182 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 183 | parse_host_declaration (cfile, group); |
7dfc8ac2 | 184 | else { |
2d59f590 | 185 | parse_warn ("host declarations not allowed here."); |
7dfc8ac2 | 186 | skip_to_semi (cfile); |
d7837182 | 187 | } |
7dfc8ac2 TL |
188 | return 1; |
189 | ||
190 | case GROUP: | |
ece6ea33 TL |
191 | next_token (&val, cfile); |
192 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 193 | parse_group_declaration (cfile, group); |
7dfc8ac2 | 194 | else { |
2d59f590 | 195 | parse_warn ("host declarations not allowed here."); |
7dfc8ac2 | 196 | skip_to_semi (cfile); |
d7837182 | 197 | } |
7dfc8ac2 TL |
198 | return 1; |
199 | ||
d7837182 | 200 | case TIMESTAMP: |
ece6ea33 | 201 | next_token (&val, cfile); |
7dfc8ac2 | 202 | parsed_time = parse_timestamp (cfile); |
d7837182 | 203 | break; |
7dfc8ac2 | 204 | |
1f814ff2 | 205 | case SHARED_NETWORK: |
ece6ea33 | 206 | next_token (&val, cfile); |
2d59f590 TL |
207 | if (type == SHARED_NET_DECL || |
208 | type == HOST_DECL || | |
ece6ea33 TL |
209 | type == SUBNET_DECL || |
210 | type == CLASS_DECL) { | |
2d59f590 | 211 | parse_warn ("shared-network parameters not %s.", |
7dfc8ac2 TL |
212 | "allowed here"); |
213 | skip_to_semi (cfile); | |
214 | break; | |
1f814ff2 | 215 | } |
7dfc8ac2 | 216 | |
2d59f590 | 217 | parse_shared_net_declaration (cfile, group); |
7dfc8ac2 TL |
218 | return 1; |
219 | ||
685963dc | 220 | case SUBNET: |
ece6ea33 TL |
221 | next_token (&val, cfile); |
222 | if (type == HOST_DECL || type == SUBNET_DECL || | |
223 | type == CLASS_DECL) { | |
2d59f590 | 224 | parse_warn ("subnet declarations not allowed here."); |
7dfc8ac2 TL |
225 | skip_to_semi (cfile); |
226 | return 1; | |
227 | } | |
228 | ||
2d59f590 | 229 | /* If we're in a subnet declaration, just do the parse. */ |
7dfc8ac2 | 230 | if (group -> shared_network) { |
2d59f590 TL |
231 | parse_subnet_declaration (cfile, |
232 | group -> shared_network); | |
7dfc8ac2 TL |
233 | break; |
234 | } | |
235 | ||
236 | /* Otherwise, cons up a fake shared network structure | |
237 | and populate it with the lone subnet... */ | |
238 | ||
239 | share = new_shared_network ("parse_statement"); | |
240 | if (!share) | |
241 | error ("No memory for shared subnet"); | |
242 | share -> group = clone_group (group, "parse_statement:subnet"); | |
243 | share -> group -> shared_network = share; | |
244 | ||
2d59f590 | 245 | parse_subnet_declaration (cfile, share); |
7dfc8ac2 TL |
246 | if (share -> subnets) { |
247 | share -> interface = | |
248 | share -> subnets -> interface; | |
249 | ||
250 | n = piaddr (share -> subnets -> net); | |
251 | t = malloc (strlen (n) + 1); | |
1f814ff2 TL |
252 | if (!t) |
253 | error ("no memory for subnet name"); | |
254 | strcpy (t, n); | |
255 | share -> name = t; | |
256 | enter_shared_network (share); | |
d7837182 | 257 | } |
7dfc8ac2 TL |
258 | return 1; |
259 | ||
24a75c03 | 260 | case VENDOR_CLASS: |
ece6ea33 TL |
261 | next_token (&val, cfile); |
262 | if (type == CLASS_DECL) { | |
263 | parse_warn ("class declarations not allowed here."); | |
264 | skip_to_semi (cfile); | |
265 | break; | |
266 | } | |
2d59f590 | 267 | parse_class_declaration (cfile, group, 0); |
7dfc8ac2 TL |
268 | return 1; |
269 | ||
24a75c03 | 270 | case USER_CLASS: |
ece6ea33 TL |
271 | next_token (&val, cfile); |
272 | if (type == CLASS_DECL) { | |
273 | parse_warn ("class declarations not allowed here."); | |
274 | skip_to_semi (cfile); | |
275 | break; | |
276 | } | |
2d59f590 | 277 | parse_class_declaration (cfile, group, 1); |
7dfc8ac2 | 278 | return 1; |
1f814ff2 | 279 | |
ece6ea33 TL |
280 | case CLASS: |
281 | next_token (&val, cfile); | |
282 | if (type == CLASS_DECL) { | |
283 | parse_warn ("class declarations not allowed here."); | |
59b85ebd | 284 | skip_to_semi (cfile); |
ece6ea33 | 285 | break; |
59b85ebd | 286 | } |
ece6ea33 TL |
287 | parse_class_declaration (cfile, group, 2); |
288 | return 1; | |
59b85ebd | 289 | |
ece6ea33 TL |
290 | case SUBCLASS: |
291 | next_token (&val, cfile); | |
292 | if (type == CLASS_DECL) { | |
293 | parse_warn ("class declarations not allowed here."); | |
294 | skip_to_semi (cfile); | |
7dfc8ac2 | 295 | break; |
7dfc8ac2 | 296 | } |
ece6ea33 TL |
297 | parse_class_declaration (cfile, group, 3); |
298 | return 1; | |
7dfc8ac2 TL |
299 | |
300 | case HARDWARE: | |
ece6ea33 | 301 | next_token (&val, cfile); |
2d59f590 | 302 | parse_hardware_param (cfile, &hardware); |
7dfc8ac2 TL |
303 | if (host_decl) |
304 | host_decl -> interface = hardware; | |
305 | else | |
2d59f590 | 306 | parse_warn ("hardware address parameter %s", |
7dfc8ac2 TL |
307 | "not allowed here."); |
308 | break; | |
309 | ||
310 | case FIXED_ADDR: | |
ece6ea33 | 311 | next_token (&val, cfile); |
6f8fb41f TL |
312 | cache = (struct option_cache *)0; |
313 | parse_fixed_addr_param (&cache, cfile); | |
7dfc8ac2 TL |
314 | if (host_decl) |
315 | host_decl -> fixed_addr = cache; | |
6f8fb41f | 316 | else { |
2d59f590 | 317 | parse_warn ("fixed-address parameter not %s", |
7dfc8ac2 | 318 | "allowed here."); |
6f8fb41f TL |
319 | option_cache_dereference (&cache, "parse_statement"); |
320 | } | |
7dfc8ac2 TL |
321 | break; |
322 | ||
323 | case RANGE: | |
ece6ea33 | 324 | next_token (&val, cfile); |
2d59f590 TL |
325 | if (type != SUBNET_DECL || !group -> subnet) { |
326 | parse_warn ("range declaration not allowed here."); | |
7dfc8ac2 | 327 | skip_to_semi (cfile); |
2d59f590 | 328 | return declaration; |
7dfc8ac2 TL |
329 | } |
330 | parse_address_range (cfile, group -> subnet); | |
2d59f590 | 331 | return declaration; |
7dfc8ac2 | 332 | |
99fd97cc | 333 | case ALLOW: |
99fd97cc | 334 | case DENY: |
ece6ea33 | 335 | token = next_token (&val, cfile); |
6f8fb41f TL |
336 | cache = (struct option_cache *)0; |
337 | if (!parse_allow_deny (&cache, cfile, | |
338 | token == ALLOW ? 1 : 0)) | |
339 | return declaration; | |
ece6ea33 TL |
340 | et = (struct executable_statement *)dmalloc (sizeof *et, |
341 | "allow/deny"); | |
342 | if (!et) | |
343 | error ("no memory for %s statement", | |
344 | token == ALLOW ? "allow" : "deny"); | |
345 | memset (et, 0, sizeof *et); | |
346 | et -> op = supersede_option_statement; | |
347 | et -> data.option = cache; | |
348 | goto insert_statement; | |
99fd97cc | 349 | |
6f8fb41f TL |
350 | case OPTION: |
351 | token = next_token (&val, cfile); | |
352 | option = parse_option_name (cfile); | |
353 | if (option) { | |
354 | et = parse_option_statement | |
355 | (cfile, 1, option, | |
356 | supersede_option_statement); | |
357 | if (!et) | |
358 | return declaration; | |
359 | goto insert_statement; | |
360 | } else | |
361 | return declaration; | |
362 | ||
363 | break; | |
364 | ||
d7837182 | 365 | default: |
ece6ea33 TL |
366 | et = (struct executable_statement *)0; |
367 | if (is_identifier (token)) { | |
368 | option = ((struct option *) | |
369 | hash_lookup (server_universe.hash, | |
370 | (unsigned char *)val, 0)); | |
371 | if (option) { | |
6f8fb41f | 372 | token = next_token (&val, cfile); |
ece6ea33 TL |
373 | et = parse_option_statement |
374 | (cfile, 1, option, | |
375 | supersede_option_statement); | |
376 | if (!et) | |
377 | return declaration; | |
378 | } | |
379 | } | |
380 | ||
381 | if (!et) { | |
382 | lose = 0; | |
383 | et = parse_executable_statement (cfile, &lose); | |
384 | if (!et) { | |
385 | if (declaration && !lose) | |
386 | parse_warn ("expecting a %s.", | |
387 | "declaration"); | |
6f8fb41f | 388 | else if (!lose) |
ece6ea33 TL |
389 | parse_warn ("expecting a parameter%s.", |
390 | " or declaration"); | |
391 | skip_to_semi (cfile); | |
392 | return declaration; | |
393 | } | |
394 | } | |
395 | if (!et) { | |
396 | parse_warn ("expecting a %sdeclaration", | |
397 | declaration ? "" : "parameter or "); | |
398 | return declaration; | |
399 | } | |
400 | insert_statement: | |
401 | if (group -> statements) { | |
402 | for (ep = group -> statements; ep -> next; | |
403 | ep = ep -> next) | |
404 | ; | |
405 | ep -> next = et; | |
406 | ||
6f8fb41f TL |
407 | } else |
408 | group -> statements = et; | |
409 | return declaration; | |
d7837182 | 410 | } |
1f814ff2 | 411 | |
2d59f590 TL |
412 | if (declaration) { |
413 | parse_warn ("parameters not allowed after first declaration."); | |
7dfc8ac2 | 414 | return 1; |
1f814ff2 | 415 | } |
7dfc8ac2 TL |
416 | |
417 | return 0; | |
d7837182 TL |
418 | } |
419 | ||
99fd97cc TL |
420 | /* allow-deny-keyword :== BOOTP |
421 | | BOOTING | |
422 | | DYNAMIC_BOOTP | |
423 | | UNKNOWN_CLIENTS */ | |
424 | ||
6f8fb41f TL |
425 | int parse_allow_deny (oc, cfile, flag) |
426 | struct option_cache **oc; | |
99fd97cc | 427 | FILE *cfile; |
99fd97cc TL |
428 | int flag; |
429 | { | |
6f8fb41f | 430 | enum dhcp_token token; |
99fd97cc | 431 | char *val; |
ece6ea33 | 432 | char rf = flag; |
6f8fb41f TL |
433 | struct expression *data = (struct expression *)0; |
434 | int status; | |
435 | ||
436 | if (!make_const_data (&data, &rf, 1, 0, 1)) | |
437 | return 0; | |
99fd97cc TL |
438 | |
439 | token = next_token (&val, cfile); | |
440 | switch (token) { | |
441 | case BOOTP: | |
6f8fb41f TL |
442 | status = option_cache (oc, (struct data_string *)0, data, |
443 | &server_options [SV_ALLOW_BOOTP]); | |
99fd97cc TL |
444 | break; |
445 | ||
446 | case BOOTING: | |
6f8fb41f TL |
447 | status = option_cache (oc, (struct data_string *)0, data, |
448 | &server_options [SV_ALLOW_BOOTING]); | |
99fd97cc TL |
449 | break; |
450 | ||
451 | case DYNAMIC_BOOTP: | |
6f8fb41f TL |
452 | status = option_cache (oc, (struct data_string *)0, data, |
453 | &server_options [SV_DYNAMIC_BOOTP]); | |
99fd97cc TL |
454 | break; |
455 | ||
456 | case UNKNOWN_CLIENTS: | |
6f8fb41f TL |
457 | status = (option_cache |
458 | (oc, (struct data_string *)0, data, | |
459 | &server_options [SV_BOOT_UNKNOWN_CLIENTS])); | |
99fd97cc TL |
460 | break; |
461 | ||
462 | default: | |
463 | parse_warn ("expecting allow/deny key"); | |
464 | skip_to_semi (cfile); | |
6f8fb41f | 465 | return 0; |
99fd97cc TL |
466 | } |
467 | parse_semi (cfile); | |
6f8fb41f | 468 | return status; |
99fd97cc TL |
469 | } |
470 | ||
5376e3e9 TL |
471 | /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ |
472 | ||
473 | int parse_boolean (cfile) | |
474 | FILE *cfile; | |
475 | { | |
6f8fb41f | 476 | enum dhcp_token token; |
5376e3e9 TL |
477 | char *val; |
478 | int rv; | |
479 | ||
480 | token = next_token (&val, cfile); | |
481 | if (!strcasecmp (val, "true") | |
482 | || !strcasecmp (val, "on")) | |
b179c997 | 483 | rv = 1; |
5376e3e9 TL |
484 | else if (!strcasecmp (val, "false") |
485 | || !strcasecmp (val, "off")) | |
486 | rv = 0; | |
487 | else { | |
488 | parse_warn ("boolean value (true/false/on/off) expected"); | |
489 | skip_to_semi (cfile); | |
490 | return 0; | |
491 | } | |
492 | parse_semi (cfile); | |
493 | return rv; | |
494 | } | |
495 | ||
7dfc8ac2 TL |
496 | /* Expect a left brace; if there isn't one, skip over the rest of the |
497 | statement and return zero; otherwise, return 1. */ | |
498 | ||
499 | int parse_lbrace (cfile) | |
500 | FILE *cfile; | |
501 | { | |
6f8fb41f | 502 | enum dhcp_token token; |
7dfc8ac2 TL |
503 | char *val; |
504 | ||
505 | token = next_token (&val, cfile); | |
506 | if (token != LBRACE) { | |
507 | parse_warn ("expecting left brace."); | |
508 | skip_to_semi (cfile); | |
509 | return 0; | |
510 | } | |
511 | return 1; | |
d7837182 TL |
512 | } |
513 | ||
7dfc8ac2 | 514 | |
2d59f590 | 515 | /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ |
d7837182 | 516 | |
2d59f590 | 517 | void parse_host_declaration (cfile, group) |
d7837182 | 518 | FILE *cfile; |
7dfc8ac2 | 519 | struct group *group; |
d7837182 TL |
520 | { |
521 | char *val; | |
6f8fb41f | 522 | enum dhcp_token token; |
7dfc8ac2 | 523 | struct host_decl *host; |
f3c3d674 | 524 | char *name; |
2d59f590 | 525 | int declaration = 0; |
7dfc8ac2 | 526 | |
f3c3d674 TL |
527 | token = peek_token (&val, cfile); |
528 | if (token != LBRACE) { | |
529 | name = parse_host_name (cfile); | |
530 | if (!name) | |
531 | return; | |
532 | } else { | |
533 | name = (char *)0; | |
534 | } | |
7dfc8ac2 TL |
535 | |
536 | host = (struct host_decl *)dmalloc (sizeof (struct host_decl), | |
2d59f590 | 537 | "parse_host_declaration"); |
7dfc8ac2 TL |
538 | if (!host) |
539 | error ("can't allocate host decl struct %s.", name); | |
540 | ||
541 | host -> name = name; | |
2d59f590 | 542 | host -> group = clone_group (group, "parse_host_declaration"); |
7dfc8ac2 TL |
543 | |
544 | if (!parse_lbrace (cfile)) | |
545 | return; | |
d7837182 | 546 | |
d7837182 TL |
547 | do { |
548 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 549 | if (token == RBRACE) { |
d7837182 TL |
550 | token = next_token (&val, cfile); |
551 | break; | |
552 | } | |
5376e3e9 TL |
553 | if (token == EOF) { |
554 | token = next_token (&val, cfile); | |
555 | parse_warn ("unexpected end of file"); | |
556 | break; | |
557 | } | |
2d59f590 TL |
558 | declaration = parse_statement (cfile, host -> group, |
559 | HOST_DECL, host, | |
560 | declaration); | |
d7837182 | 561 | } while (1); |
7dfc8ac2 TL |
562 | |
563 | enter_host (host); | |
d7837182 TL |
564 | } |
565 | ||
2d59f590 | 566 | /* class-declaration :== STRING LBRACE parameters declarations RBRACE |
24a75c03 TL |
567 | */ |
568 | ||
2d59f590 | 569 | void parse_class_declaration (cfile, group, type) |
24a75c03 | 570 | FILE *cfile; |
7dfc8ac2 | 571 | struct group *group; |
24a75c03 TL |
572 | int type; |
573 | { | |
574 | char *val; | |
6f8fb41f | 575 | enum dhcp_token token; |
ece6ea33 | 576 | struct class *class, *pc; |
f4d0f440 | 577 | int declaration = 0; |
ece6ea33 TL |
578 | int lose; |
579 | struct data_string data; | |
580 | char *name; | |
581 | struct executable_statement *stmt = (struct executable_statement *)0; | |
582 | struct expression *expr; | |
24a75c03 TL |
583 | |
584 | token = next_token (&val, cfile); | |
585 | if (token != STRING) { | |
586 | parse_warn ("Expecting class name"); | |
587 | skip_to_semi (cfile); | |
7dfc8ac2 | 588 | return; |
24a75c03 TL |
589 | } |
590 | ||
ece6ea33 TL |
591 | /* See if there's already a class with the specified name. */ |
592 | pc = (struct class *)find_class (val); | |
593 | ||
594 | /* If this isn't a subclass, we're updating an existing class. */ | |
595 | if (pc && type != 0 && type != 1 && type != 3) { | |
596 | class = pc; | |
597 | pc = (struct class *)0; | |
598 | } | |
599 | ||
600 | /* If this _is_ a subclass, there _must_ be a class with the | |
601 | same name. */ | |
602 | if (!pc && (type == 0 || type == 1 || type == 3)) { | |
603 | parse_warn ("no class named %s", val); | |
604 | skip_to_semi (cfile); | |
605 | return; | |
606 | } | |
607 | ||
608 | /* The old vendor-class and user-class declarations had an implicit | |
609 | match. We don't do the implicit match anymore. Instead, for | |
610 | backward compatibility, we have an implicit-vendor-class and an | |
611 | implicit-user-class. vendor-class and user-class declarations | |
612 | are turned into subclasses of the implicit classes, and the | |
613 | spawn expression of the implicit classes extracts the contents of | |
614 | the vendor class or user class. */ | |
615 | if (type == 0 || type == 1) { | |
616 | data.len = strlen (val); | |
6f8fb41f TL |
617 | data.buffer = (struct buffer *)0; |
618 | if (!buffer_allocate (&data.buffer, | |
619 | data.len + 1, "parse_class_declaration")) | |
620 | error ("no memoy for class name."); | |
621 | data.data = &data.buffer -> data [0]; | |
ece6ea33 TL |
622 | data.terminated = 1; |
623 | ||
624 | name = type ? "implicit-vendor-class" : "implicit-user-class"; | |
625 | } else if (type == 2) { | |
626 | if (!(name = dmalloc (strlen (val) + 1, | |
627 | "parse_class_declaration"))) | |
628 | error ("No memory for class name %s.", val); | |
629 | strcpy (name, val); | |
630 | } else { | |
631 | name = (char *)0; | |
632 | } | |
633 | ||
634 | /* If this is a straight subclass, parse the hash string. */ | |
635 | if (type == 3) { | |
636 | token = peek_token (&val, cfile); | |
637 | if (token == STRING) { | |
638 | token = next_token (&val, cfile); | |
639 | data.len = strlen (val); | |
6f8fb41f TL |
640 | data.buffer = (struct buffer *)0; |
641 | if (!buffer_allocate (&data.buffer, data.len + 1, | |
642 | "parse_class_declaration")) | |
643 | return; | |
ece6ea33 | 644 | data.terminated = 1; |
6f8fb41f TL |
645 | data.data = &data.buffer -> data [0]; |
646 | strcpy (data.data, val); | |
ece6ea33 | 647 | } else if (token == NUMBER_OR_NAME || token == NUMBER) { |
6f8fb41f TL |
648 | memset (&data, 0, sizeof data); |
649 | if (!parse_cshl (&data, cfile)) | |
ece6ea33 TL |
650 | return; |
651 | data.terminated = 0; | |
652 | data.buffer = 0; | |
653 | } | |
654 | } | |
655 | ||
656 | /* See if there's already a class in the hash table matching the | |
657 | hash data. */ | |
658 | if (type == 0 || type == 1 || type == 3) | |
659 | class = ((struct class *) | |
660 | hash_lookup (pc -> hash, data.data, data.len)); | |
661 | ||
662 | /* If we didn't find an existing class, allocate a new one. */ | |
663 | if (!class) { | |
664 | /* Allocate the class structure... */ | |
665 | class = (struct class *)dmalloc (sizeof (struct class), | |
666 | "parse_class_declaration"); | |
667 | if (!class) | |
668 | error ("No memory for class %s.", val); | |
669 | memset (class, 0, sizeof *class); | |
670 | if (pc) { | |
671 | class -> group = | |
672 | clone_group (pc -> group, | |
673 | "parse_class_declaration"); | |
674 | add_hash (pc -> hash, | |
675 | data.data, data.len, (unsigned char *)class); | |
676 | } else { | |
677 | class -> group = | |
678 | clone_group (group, "parse_class_declaration"); | |
679 | } | |
680 | ||
681 | /* If this is an implicit vendor or user class, add a | |
682 | statement that causes the vendor or user class ID to | |
683 | be sent back in the reply. */ | |
684 | if (type == 0 || type == 1) { | |
685 | stmt = ((struct executable_statement *) | |
686 | dmalloc (sizeof (struct executable_statement), | |
687 | "implicit user/vendor class")); | |
688 | if (!stmt) | |
689 | error ("no memory for class statement."); | |
690 | memset (stmt, 0, sizeof *stmt); | |
691 | stmt -> op = supersede_option_statement; | |
6f8fb41f TL |
692 | if (option_cache_allocate (&stmt -> data.option, |
693 | "parse_class_statement")) { | |
694 | stmt -> data.option -> data = data; | |
695 | stmt -> data.option -> option = | |
696 | dhcp_universe.options | |
697 | [type | |
698 | ? DHO_DHCP_CLASS_IDENTIFIER | |
699 | : DHO_DHCP_USER_CLASS_ID]; | |
700 | } | |
ece6ea33 TL |
701 | class -> statements = stmt; |
702 | } | |
703 | } | |
7dfc8ac2 TL |
704 | |
705 | if (!parse_lbrace (cfile)) | |
706 | return; | |
24a75c03 TL |
707 | |
708 | do { | |
709 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 710 | if (token == RBRACE) { |
24a75c03 TL |
711 | token = next_token (&val, cfile); |
712 | break; | |
5376e3e9 TL |
713 | } else if (token == EOF) { |
714 | token = next_token (&val, cfile); | |
715 | parse_warn ("unexpected end of file"); | |
716 | break; | |
ece6ea33 TL |
717 | } else if (token == MATCH) { |
718 | if (pc) { | |
719 | parse_warn ("invalid match in subclass."); | |
720 | skip_to_semi (cfile); | |
721 | break; | |
722 | } | |
723 | if (class -> expr) { | |
724 | parse_warn ("can't override match."); | |
725 | skip_to_semi (cfile); | |
726 | break; | |
727 | } | |
728 | token = next_token (&val, cfile); | |
729 | token = next_token (&val, cfile); | |
730 | if (token != IF) { | |
731 | parse_warn ("expecting if after match"); | |
732 | skip_to_semi (cfile); | |
733 | break; | |
734 | } | |
6f8fb41f TL |
735 | parse_boolean_expression (&class -> expr, cfile, |
736 | &lose); | |
ece6ea33 TL |
737 | if (lose) |
738 | break; | |
6f8fb41f TL |
739 | #if defined (DEBUG_EXPRESSION_PARSE) |
740 | print_expression ("class match", class -> expr); | |
741 | #endif | |
ece6ea33 TL |
742 | } else if (token == SPAWN) { |
743 | if (pc) { | |
744 | parse_warn ("invalid spawn in subclass."); | |
745 | skip_to_semi (cfile); | |
746 | break; | |
747 | } | |
748 | if (class -> spawn) { | |
749 | parse_warn ("can't override spawn."); | |
750 | skip_to_semi (cfile); | |
751 | break; | |
752 | } | |
753 | token = next_token (&val, cfile); | |
754 | token = next_token (&val, cfile); | |
755 | if (token != WITH) { | |
756 | parse_warn ("expecting with after spawn"); | |
757 | skip_to_semi (cfile); | |
758 | break; | |
759 | } | |
6f8fb41f | 760 | parse_data_expression (&class -> spawn, cfile, &lose); |
ece6ea33 TL |
761 | if (lose) |
762 | break; | |
6f8fb41f TL |
763 | #if defined (DEBUG_EXPRESSION_PARSE) |
764 | print_expression ("class match", class -> spawn); | |
765 | #endif | |
24a75c03 | 766 | } else { |
2d59f590 TL |
767 | declaration = parse_statement (cfile, class -> group, |
768 | CLASS_DECL, | |
769 | (struct host_decl *)0, | |
770 | declaration); | |
24a75c03 TL |
771 | } |
772 | } while (1); | |
773 | } | |
774 | ||
2d59f590 TL |
775 | /* shared-network-declaration :== |
776 | hostname LBRACE declarations parameters RBRACE */ | |
1f814ff2 | 777 | |
2d59f590 | 778 | void parse_shared_net_declaration (cfile, group) |
1f814ff2 | 779 | FILE *cfile; |
7dfc8ac2 | 780 | struct group *group; |
1f814ff2 TL |
781 | { |
782 | char *val; | |
6f8fb41f | 783 | enum dhcp_token token; |
1f814ff2 | 784 | struct shared_network *share; |
1f814ff2 | 785 | char *name; |
2d59f590 | 786 | int declaration = 0; |
1f814ff2 | 787 | |
2d59f590 | 788 | share = new_shared_network ("parse_shared_net_declaration"); |
1f814ff2 TL |
789 | if (!share) |
790 | error ("No memory for shared subnet"); | |
791 | share -> leases = (struct lease *)0; | |
792 | share -> last_lease = (struct lease *)0; | |
793 | share -> insertion_point = (struct lease *)0; | |
794 | share -> next = (struct shared_network *)0; | |
9ab92650 | 795 | share -> interface = (struct interface_info *)0; |
2d59f590 | 796 | share -> group = clone_group (group, "parse_shared_net_declaration"); |
7dfc8ac2 | 797 | share -> group -> shared_network = share; |
1f814ff2 TL |
798 | |
799 | /* Get the name of the shared network... */ | |
7dfc8ac2 TL |
800 | token = peek_token (&val, cfile); |
801 | if (token == STRING) { | |
802 | token = next_token (&val, cfile); | |
803 | ||
804 | if (val [0] == 0) { | |
805 | parse_warn ("zero-length shared network name"); | |
806 | val = "<no-name-given>"; | |
807 | } | |
808 | name = malloc (strlen (val) + 1); | |
809 | if (!name) | |
810 | error ("no memory for shared network name"); | |
811 | strcpy (name, val); | |
812 | } else { | |
813 | name = parse_host_name (cfile); | |
814 | if (!name) | |
815 | return; | |
1f814ff2 | 816 | } |
1f814ff2 TL |
817 | share -> name = name; |
818 | ||
7dfc8ac2 TL |
819 | if (!parse_lbrace (cfile)) |
820 | return; | |
821 | ||
1f814ff2 | 822 | do { |
7dfc8ac2 TL |
823 | token = peek_token (&val, cfile); |
824 | if (token == RBRACE) { | |
825 | token = next_token (&val, cfile); | |
826 | if (!share -> subnets) { | |
1f814ff2 TL |
827 | parse_warn ("empty shared-network decl"); |
828 | return; | |
829 | } | |
1f814ff2 TL |
830 | enter_shared_network (share); |
831 | return; | |
5376e3e9 TL |
832 | } else if (token == EOF) { |
833 | token = next_token (&val, cfile); | |
834 | parse_warn ("unexpected end of file"); | |
835 | break; | |
1f814ff2 | 836 | } |
5376e3e9 | 837 | |
2d59f590 TL |
838 | declaration = parse_statement (cfile, share -> group, |
839 | SHARED_NET_DECL, | |
840 | (struct host_decl *)0, | |
841 | declaration); | |
1f814ff2 TL |
842 | } while (1); |
843 | } | |
844 | ||
2d59f590 TL |
845 | /* subnet-declaration :== |
846 | net NETMASK netmask RBRACE parameters declarations LBRACE */ | |
685963dc | 847 | |
2d59f590 | 848 | void parse_subnet_declaration (cfile, share) |
685963dc | 849 | FILE *cfile; |
1f814ff2 | 850 | struct shared_network *share; |
685963dc TL |
851 | { |
852 | char *val; | |
6f8fb41f | 853 | enum dhcp_token token; |
7dfc8ac2 TL |
854 | struct subnet *subnet, *t; |
855 | struct iaddr iaddr; | |
685963dc TL |
856 | unsigned char addr [4]; |
857 | int len = sizeof addr; | |
2d59f590 | 858 | int declaration = 0; |
685963dc | 859 | |
2d59f590 | 860 | subnet = new_subnet ("parse_subnet_declaration"); |
685963dc TL |
861 | if (!subnet) |
862 | error ("No memory for new subnet"); | |
1f814ff2 | 863 | subnet -> shared_network = share; |
7dfc8ac2 | 864 | subnet -> group = clone_group (share -> group, |
2d59f590 | 865 | "parse_subnet_declaration"); |
7dfc8ac2 | 866 | subnet -> group -> subnet = subnet; |
685963dc TL |
867 | |
868 | /* Get the network number... */ | |
7dfc8ac2 TL |
869 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
870 | return; | |
871 | memcpy (iaddr.iabuf, addr, len); | |
872 | iaddr.len = len; | |
873 | subnet -> net = iaddr; | |
685963dc TL |
874 | |
875 | token = next_token (&val, cfile); | |
876 | if (token != NETMASK) { | |
877 | parse_warn ("Expecting netmask"); | |
878 | skip_to_semi (cfile); | |
7dfc8ac2 | 879 | return; |
685963dc TL |
880 | } |
881 | ||
882 | /* Get the netmask... */ | |
7dfc8ac2 TL |
883 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
884 | return; | |
885 | memcpy (iaddr.iabuf, addr, len); | |
886 | iaddr.len = len; | |
887 | subnet -> netmask = iaddr; | |
685963dc TL |
888 | |
889 | enter_subnet (subnet); | |
890 | ||
7dfc8ac2 TL |
891 | if (!parse_lbrace (cfile)) |
892 | return; | |
893 | ||
685963dc TL |
894 | do { |
895 | token = peek_token (&val, cfile); | |
7dfc8ac2 TL |
896 | if (token == RBRACE) { |
897 | token = next_token (&val, cfile); | |
685963dc | 898 | break; |
5376e3e9 TL |
899 | } else if (token == EOF) { |
900 | token = next_token (&val, cfile); | |
901 | parse_warn ("unexpected end of file"); | |
902 | break; | |
7dfc8ac2 | 903 | } |
2d59f590 TL |
904 | declaration = parse_statement (cfile, subnet -> group, |
905 | SUBNET_DECL, | |
906 | (struct host_decl *)0, | |
907 | declaration); | |
685963dc | 908 | } while (1); |
1f814ff2 | 909 | |
6cdd0d0d | 910 | /* Add the subnet to the list of subnets in this shared net. */ |
7dfc8ac2 TL |
911 | if (!share -> subnets) |
912 | share -> subnets = subnet; | |
913 | else { | |
914 | for (t = share -> subnets; | |
6cdd0d0d | 915 | t -> next_sibling; t = t -> next_sibling) |
7dfc8ac2 | 916 | ; |
6cdd0d0d | 917 | t -> next_sibling = subnet; |
7dfc8ac2 | 918 | } |
685963dc TL |
919 | } |
920 | ||
2d59f590 | 921 | /* group-declaration :== RBRACE parameters declarations LBRACE */ |
7dfc8ac2 | 922 | |
2d59f590 | 923 | void parse_group_declaration (cfile, group) |
685963dc | 924 | FILE *cfile; |
7dfc8ac2 | 925 | struct group *group; |
685963dc TL |
926 | { |
927 | char *val; | |
6f8fb41f | 928 | enum dhcp_token token; |
7dfc8ac2 | 929 | struct group *g; |
2d59f590 | 930 | int declaration = 0; |
685963dc | 931 | |
2d59f590 | 932 | g = clone_group (group, "parse_group_declaration"); |
685963dc | 933 | |
7dfc8ac2 TL |
934 | if (!parse_lbrace (cfile)) |
935 | return; | |
d7837182 | 936 | |
7dfc8ac2 TL |
937 | do { |
938 | token = peek_token (&val, cfile); | |
5376e3e9 TL |
939 | if (token == RBRACE) { |
940 | token = next_token (&val, cfile); | |
7dfc8ac2 | 941 | break; |
5376e3e9 TL |
942 | } else if (token == EOF) { |
943 | token = next_token (&val, cfile); | |
944 | parse_warn ("unexpected end of file"); | |
945 | break; | |
946 | } | |
2d59f590 TL |
947 | declaration = parse_statement (cfile, g, GROUP_DECL, |
948 | (struct host_decl *)0, | |
949 | declaration); | |
7dfc8ac2 | 950 | } while (1); |
d7837182 TL |
951 | } |
952 | ||
2d59f590 TL |
953 | /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI |
954 | ip-addrs-or-hostnames :== ip-addr-or-hostname | |
955 | | ip-addrs-or-hostnames ip-addr-or-hostname */ | |
d7837182 | 956 | |
6f8fb41f TL |
957 | int parse_fixed_addr_param (oc, cfile) |
958 | struct option_cache **oc; | |
d7837182 | 959 | FILE *cfile; |
d7837182 | 960 | { |
1f814ff2 | 961 | char *val; |
6f8fb41f | 962 | enum dhcp_token token; |
ece6ea33 | 963 | struct expression *expr = (struct expression *)0; |
6f8fb41f TL |
964 | struct expression *tmp, *new; |
965 | int status; | |
1f814ff2 TL |
966 | |
967 | do { | |
6f8fb41f TL |
968 | tmp = (struct expression *)0; |
969 | if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) { | |
028a8588 TL |
970 | if (expr) { |
971 | new = (struct expression *)0; | |
972 | status = make_concat (&new, expr, tmp); | |
973 | expression_dereference | |
974 | (&expr, "parse_fixed_addr_param"); | |
975 | expression_dereference | |
976 | (&tmp, "parse_fixed_addr_param"); | |
977 | if (status) | |
978 | return 0; | |
979 | expr = new; | |
980 | } else | |
981 | expr = tmp; | |
6f8fb41f TL |
982 | } else { |
983 | if (expr) | |
984 | expression_dereference | |
985 | (&expr, "parse_fixed_addr_param"); | |
986 | return 0; | |
987 | } | |
1f814ff2 | 988 | token = peek_token (&val, cfile); |
5376e3e9 | 989 | if (token == COMMA) |
1f814ff2 TL |
990 | token = next_token (&val, cfile); |
991 | } while (token == COMMA); | |
7dfc8ac2 | 992 | |
6f8fb41f TL |
993 | if (!parse_semi (cfile)) { |
994 | if (expr) | |
995 | expression_dereference (&expr, | |
996 | "parse_fixed_addr_param"); | |
997 | return 0; | |
998 | } | |
999 | status = option_cache (oc, (struct data_string *)0, expr, | |
1000 | (struct option *)0); | |
1001 | expression_dereference (&expr, "parse_fixed_addr_param"); | |
1002 | return status; | |
d7837182 TL |
1003 | } |
1004 | ||
5376e3e9 | 1005 | /* timestamp :== date |
d7837182 TL |
1006 | |
1007 | Timestamps are actually not used in dhcpd.conf, which is a static file, | |
5376e3e9 TL |
1008 | but rather in the database file and the journal file. (Okay, actually |
1009 | they're not even used there yet). */ | |
d7837182 | 1010 | |
7dfc8ac2 | 1011 | TIME parse_timestamp (cfile) |
d7837182 | 1012 | FILE *cfile; |
d7837182 | 1013 | { |
089fb364 | 1014 | TIME rv; |
089fb364 | 1015 | |
7dfc8ac2 | 1016 | rv = parse_date (cfile); |
089fb364 | 1017 | return rv; |
d7837182 TL |
1018 | } |
1019 | ||
2d59f590 TL |
1020 | /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE |
1021 | ||
1022 | lease_parameters :== <nil> | |
1023 | | lease_parameter | |
1024 | | lease_parameters lease_parameter | |
1025 | ||
1026 | lease_parameter :== STARTS date | |
1027 | | ENDS date | |
1028 | | TIMESTAMP date | |
1029 | | HARDWARE hardware-parameter | |
1030 | | UID hex_numbers SEMI | |
ccf5778a TL |
1031 | | HOSTNAME hostname SEMI |
1032 | | CLIENT_HOSTNAME hostname SEMI | |
2d59f590 TL |
1033 | | CLASS identifier SEMI |
1034 | | DYNAMIC_BOOTP SEMI */ | |
1035 | ||
1036 | struct lease *parse_lease_declaration (cfile) | |
d7837182 | 1037 | FILE *cfile; |
d7837182 TL |
1038 | { |
1039 | char *val; | |
6f8fb41f | 1040 | enum dhcp_token token; |
d7837182 TL |
1041 | unsigned char addr [4]; |
1042 | int len = sizeof addr; | |
d7837182 TL |
1043 | int seenmask = 0; |
1044 | int seenbit; | |
1045 | char tbuf [32]; | |
d7837182 TL |
1046 | static struct lease lease; |
1047 | ||
9375101b TL |
1048 | /* Zap the lease structure... */ |
1049 | memset (&lease, 0, sizeof lease); | |
1050 | ||
d7837182 | 1051 | /* Get the address for which the lease has been issued. */ |
7dfc8ac2 TL |
1052 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1053 | return (struct lease *)0; | |
089fb364 TL |
1054 | memcpy (lease.ip_addr.iabuf, addr, len); |
1055 | lease.ip_addr.len = len; | |
d7837182 | 1056 | |
7dfc8ac2 TL |
1057 | if (!parse_lbrace (cfile)) |
1058 | return (struct lease *)0; | |
1059 | ||
d7837182 TL |
1060 | do { |
1061 | token = next_token (&val, cfile); | |
7dfc8ac2 | 1062 | if (token == RBRACE) |
d7837182 | 1063 | break; |
5376e3e9 TL |
1064 | else if (token == EOF) { |
1065 | parse_warn ("unexpected end of file"); | |
1066 | break; | |
1067 | } | |
ece6ea33 | 1068 | strncpy (tbuf, val, sizeof tbuf); |
d7837182 TL |
1069 | tbuf [(sizeof tbuf) - 1] = 0; |
1070 | ||
1071 | /* Parse any of the times associated with the lease. */ | |
1072 | if (token == STARTS || token == ENDS || token == TIMESTAMP) { | |
1073 | TIME t; | |
7dfc8ac2 | 1074 | t = parse_date (cfile); |
d7837182 TL |
1075 | switch (token) { |
1076 | case STARTS: | |
1077 | seenbit = 1; | |
1078 | lease.starts = t; | |
1079 | break; | |
1080 | ||
1081 | case ENDS: | |
1082 | seenbit = 2; | |
1083 | lease.ends = t; | |
1084 | break; | |
1085 | ||
1086 | case TIMESTAMP: | |
1087 | seenbit = 4; | |
1088 | lease.timestamp = t; | |
1089 | break; | |
19d868b2 TL |
1090 | |
1091 | default: | |
1092 | /*NOTREACHED*/ | |
1093 | seenbit = 0; | |
1094 | break; | |
d7837182 TL |
1095 | } |
1096 | } else { | |
1097 | switch (token) { | |
1098 | /* Colon-seperated hexadecimal octets... */ | |
1099 | case UID: | |
1100 | seenbit = 8; | |
9375101b TL |
1101 | token = peek_token (&val, cfile); |
1102 | if (token == STRING) { | |
c4f1fbb0 | 1103 | token = next_token (&val, cfile); |
9375101b | 1104 | lease.uid_len = strlen (val) + 1; |
7e8381e5 TL |
1105 | lease.uid = (unsigned char *) |
1106 | malloc (lease.uid_len); | |
c256bae9 TL |
1107 | if (!lease.uid) { |
1108 | warn ("no space for uid"); | |
1109 | return (struct lease *)0; | |
1110 | } | |
7e8381e5 | 1111 | memcpy (lease.uid, val, lease.uid_len); |
9375101b | 1112 | } else { |
7e8381e5 TL |
1113 | lease.uid_len = 0; |
1114 | lease.uid = parse_numeric_aggregate | |
7dfc8ac2 | 1115 | (cfile, (unsigned char *)0, |
9375101b | 1116 | &lease.uid_len, ':', 16, 8); |
c256bae9 TL |
1117 | if (!lease.uid) { |
1118 | warn ("no space for uid"); | |
7dfc8ac2 | 1119 | return (struct lease *)0; |
c256bae9 | 1120 | } |
9375101b | 1121 | if (lease.uid_len == 0) { |
c256bae9 | 1122 | lease.uid = (unsigned char *)0; |
9375101b | 1123 | parse_warn ("zero-length uid"); |
c4f1fbb0 | 1124 | seenbit = 0; |
9375101b TL |
1125 | break; |
1126 | } | |
1127 | } | |
d7837182 TL |
1128 | if (!lease.uid) { |
1129 | error ("No memory for lease uid"); | |
1130 | } | |
d7837182 TL |
1131 | break; |
1132 | ||
d7837182 TL |
1133 | case CLASS: |
1134 | seenbit = 32; | |
1135 | token = next_token (&val, cfile); | |
1136 | if (!is_identifier (token)) { | |
1137 | if (token != SEMI) | |
1138 | skip_to_semi (cfile); | |
7dfc8ac2 | 1139 | return (struct lease *)0; |
d7837182 TL |
1140 | } |
1141 | /* for now, we aren't using this. */ | |
1142 | break; | |
1143 | ||
1144 | case HARDWARE: | |
1145 | seenbit = 64; | |
2d59f590 | 1146 | parse_hardware_param (cfile, |
7dfc8ac2 | 1147 | &lease.hardware_addr); |
d7837182 TL |
1148 | break; |
1149 | ||
1f814ff2 TL |
1150 | case DYNAMIC_BOOTP: |
1151 | seenbit = 128; | |
1152 | lease.flags |= BOOTP_LEASE; | |
1153 | break; | |
1154 | ||
4006d804 TL |
1155 | case ABANDONED: |
1156 | seenbit = 256; | |
1157 | lease.flags |= ABANDONED_LEASE; | |
1158 | break; | |
1159 | ||
ccf5778a TL |
1160 | case HOSTNAME: |
1161 | seenbit = 512; | |
56a89931 TL |
1162 | token = peek_token (&val, cfile); |
1163 | if (token == STRING) | |
1164 | lease.hostname = parse_string (cfile); | |
1165 | else | |
1166 | lease.hostname = | |
1167 | parse_host_name (cfile); | |
ccf5778a TL |
1168 | if (!lease.hostname) { |
1169 | seenbit = 0; | |
1170 | return (struct lease *)0; | |
1171 | } | |
1172 | break; | |
1173 | ||
1174 | case CLIENT_HOSTNAME: | |
05a8d03c | 1175 | seenbit = 1024; |
200d216c TL |
1176 | token = peek_token (&val, cfile); |
1177 | if (token == STRING) | |
1178 | lease.client_hostname = | |
1179 | parse_string (cfile); | |
1180 | else | |
1181 | lease.client_hostname = | |
1182 | parse_host_name (cfile); | |
ccf5778a TL |
1183 | break; |
1184 | ||
d7837182 | 1185 | default: |
7dfc8ac2 | 1186 | skip_to_semi (cfile); |
19d868b2 | 1187 | seenbit = 0; |
7dfc8ac2 TL |
1188 | return (struct lease *)0; |
1189 | } | |
1190 | ||
ffba7052 | 1191 | if (token != HARDWARE && token != STRING) { |
7dfc8ac2 TL |
1192 | token = next_token (&val, cfile); |
1193 | if (token != SEMI) { | |
1194 | parse_warn ("semicolon expected."); | |
1195 | skip_to_semi (cfile); | |
1196 | return (struct lease *)0; | |
1197 | } | |
d7837182 TL |
1198 | } |
1199 | } | |
1200 | if (seenmask & seenbit) { | |
2d59f590 | 1201 | parse_warn ("Too many %s parameters in lease %s\n", |
089fb364 | 1202 | tbuf, piaddr (lease.ip_addr)); |
d7837182 TL |
1203 | } else |
1204 | seenmask |= seenbit; | |
7dfc8ac2 | 1205 | |
d7837182 TL |
1206 | } while (1); |
1207 | return &lease; | |
1208 | } | |
1209 | ||
2d59f590 TL |
1210 | /* address-range-declaration :== ip-address ip-address SEMI |
1211 | | DYNAMIC_BOOTP ip-address ip-address SEMI */ | |
d7837182 | 1212 | |
7dfc8ac2 | 1213 | void parse_address_range (cfile, subnet) |
d7837182 | 1214 | FILE *cfile; |
685963dc | 1215 | struct subnet *subnet; |
d7837182 | 1216 | { |
685963dc | 1217 | struct iaddr low, high; |
d7837182 TL |
1218 | unsigned char addr [4]; |
1219 | int len = sizeof addr; | |
6f8fb41f | 1220 | enum dhcp_token token; |
089fb364 | 1221 | char *val; |
1f814ff2 TL |
1222 | int dynamic = 0; |
1223 | ||
1224 | if ((token = peek_token (&val, cfile)) == DYNAMIC_BOOTP) { | |
5376e3e9 | 1225 | token = next_token (&val, cfile); |
ece6ea33 | 1226 | dynamic = 1; |
1f814ff2 | 1227 | } |
d7837182 TL |
1228 | |
1229 | /* Get the bottom address in the range... */ | |
7dfc8ac2 TL |
1230 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1231 | return; | |
089fb364 TL |
1232 | memcpy (low.iabuf, addr, len); |
1233 | low.len = len; | |
d7837182 | 1234 | |
2d59f590 TL |
1235 | /* Only one address? */ |
1236 | token = peek_token (&val, cfile); | |
1237 | if (token == SEMI) | |
1238 | high = low; | |
1239 | else { | |
d7837182 | 1240 | /* Get the top address in the range... */ |
2d59f590 TL |
1241 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1242 | return; | |
1243 | memcpy (high.iabuf, addr, len); | |
1244 | high.len = len; | |
1245 | } | |
d7837182 | 1246 | |
7dfc8ac2 TL |
1247 | token = next_token (&val, cfile); |
1248 | if (token != SEMI) { | |
1249 | parse_warn ("semicolon expected."); | |
1250 | skip_to_semi (cfile); | |
1251 | return; | |
1252 | } | |
1253 | ||
d7837182 | 1254 | /* Create the new address range... */ |
1f814ff2 | 1255 | new_address_range (low, high, subnet, dynamic); |
d7837182 TL |
1256 | } |
1257 |