]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* confpars.c |
2 | ||
3 | Parser for dhcpd config file... */ | |
4 | ||
5 | /* | |
f39b6e00 TL |
6 | * Copyright (c) 1996-1999 Internet Software Consortium. |
7 | * Use is subject to license terms which appear in the file named | |
8 | * ISC-LICENSE that should have accompanied this file when you | |
9 | * received it. If a file named ISC-LICENSE did not accompany this | |
10 | * file, or you are not sure the one you have is correct, you may | |
11 | * obtain an applicable copy of the license at: | |
d7837182 | 12 | * |
f39b6e00 | 13 | * http://www.isc.org/isc-license-1.0.html. |
d7837182 | 14 | * |
f39b6e00 TL |
15 | * This file is part of the ISC DHCP distribution. The documentation |
16 | * associated with this file is listed in the file DOCUMENTATION, | |
17 | * included in the top-level directory of this release. | |
d7837182 | 18 | * |
f39b6e00 TL |
19 | * Support and other services are available for ISC products - see |
20 | * http://www.isc.org for more information. | |
d7837182 TL |
21 | */ |
22 | ||
23 | #ifndef lint | |
24 | static char copyright[] = | |
77a5f871 | 25 | "$Id: confpars.c,v 1.86 1999/10/07 02:14:09 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; |
d7837182 TL |
26 | #endif /* not lint */ |
27 | ||
28 | #include "dhcpd.h" | |
d7837182 TL |
29 | |
30 | static TIME parsed_time; | |
31 | ||
2d59f590 TL |
32 | /* conf-file :== parameters declarations EOF |
33 | parameters :== <nil> | parameter | parameters parameter | |
34 | declarations :== <nil> | declaration | declarations declaration */ | |
d7837182 | 35 | |
35454d8a | 36 | isc_result_t readconf () |
d7837182 | 37 | { |
35454d8a TL |
38 | int file; |
39 | struct parse *cfile; | |
d7837182 | 40 | char *val; |
6f8fb41f | 41 | enum dhcp_token token; |
2d59f590 | 42 | int declaration = 0; |
35454d8a | 43 | int status; |
7e8381e5 | 44 | |
d7837182 TL |
45 | /* Set up the initial dhcp option universe. */ |
46 | initialize_universes (); | |
47 | ||
763adef1 TL |
48 | root_group.authoritative = 0; |
49 | ||
35454d8a | 50 | if ((file = open (path_dhcpd_conf, O_RDONLY)) < 0) |
8ae2d595 | 51 | log_fatal ("Can't open %s: %m", path_dhcpd_conf); |
35454d8a TL |
52 | |
53 | cfile = (struct parse *)0; | |
54 | new_parse (&cfile, file, (char *)0, 0, path_dhcpd_conf); | |
55 | ||
d7837182 TL |
56 | do { |
57 | token = peek_token (&val, cfile); | |
58 | if (token == EOF) | |
59 | break; | |
2d59f590 | 60 | declaration = parse_statement (cfile, &root_group, |
ece6ea33 TL |
61 | ROOT_GROUP, |
62 | (struct host_decl *)0, | |
63 | declaration); | |
d7837182 | 64 | } while (1); |
88ddda34 TL |
65 | token = next_token (&val, cfile); /* Clear the peek buffer */ |
66 | ||
35454d8a TL |
67 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; |
68 | ||
69 | end_parse (&cfile); | |
70 | close (file); | |
71 | return status; | |
1358b874 TL |
72 | } |
73 | ||
2d59f590 | 74 | /* lease-file :== lease-declarations EOF |
5376e3e9 | 75 | lease-statments :== <nil> |
2d59f590 TL |
76 | | lease-declaration |
77 | | lease-declarations lease-declaration */ | |
5376e3e9 | 78 | |
35454d8a | 79 | isc_result_t read_leases () |
1358b874 | 80 | { |
35454d8a TL |
81 | struct parse *cfile; |
82 | int file; | |
1358b874 | 83 | char *val; |
6f8fb41f | 84 | enum dhcp_token token; |
35454d8a | 85 | isc_result_t status; |
7dfc8ac2 TL |
86 | |
87 | /* Open the lease file. If we can't open it, fail. The reason | |
88 | for this is that although on initial startup, the absence of | |
89 | a lease file is perfectly benign, if dhcpd has been running | |
90 | and this file is absent, it means that dhcpd tried and failed | |
91 | to rewrite the lease database. If we proceed and the | |
92 | problem which caused the rewrite to fail has been fixed, but no | |
93 | human has corrected the database problem, then we are left | |
94 | thinking that no leases have been assigned to anybody, which | |
95 | could create severe network chaos. */ | |
35454d8a | 96 | if ((file = open (path_dhcpd_db, O_RDONLY)) < 0) { |
2d1b06e0 TL |
97 | log_error ("Can't open lease database %s: %m -- %s", |
98 | path_dhcpd_db, | |
99 | "check for failed database rewrite attempt!"); | |
100 | log_error ("Please read the dhcpd.leases manual page if you"); | |
101 | log_fatal ("don't know what to do about this."); | |
102 | } | |
103 | ||
35454d8a TL |
104 | cfile = (struct parse *)0; |
105 | new_parse (&cfile, file, (char *)0, 0, path_dhcpd_db); | |
106 | ||
1358b874 TL |
107 | do { |
108 | token = next_token (&val, cfile); | |
1358b874 TL |
109 | if (token == EOF) |
110 | break; | |
52e79d12 | 111 | if (token == LEASE) { |
7dfc8ac2 | 112 | struct lease *lease; |
2d59f590 | 113 | lease = parse_lease_declaration (cfile); |
96d7d13e | 114 | if (lease) { |
1358b874 | 115 | enter_lease (lease); |
96d7d13e TL |
116 | if (lease -> on_expiry) |
117 | executable_statement_dereference | |
118 | (&lease -> on_expiry, | |
119 | "read_leases"); | |
120 | if (lease -> on_commit) | |
121 | executable_statement_dereference | |
122 | (&lease -> on_commit, | |
123 | "read_leases"); | |
124 | if (lease -> on_release) | |
125 | executable_statement_dereference | |
126 | (&lease -> on_release, | |
127 | "read_leases"); | |
128 | } else | |
35454d8a TL |
129 | parse_warn (cfile, |
130 | "possibly corrupt lease file"); | |
52e79d12 TL |
131 | } else if (token == HOST) { |
132 | parse_host_declaration (cfile, &root_group); | |
35454d8a TL |
133 | } else if (token == GROUP) { |
134 | parse_group_declaration (cfile, &root_group); | |
52e79d12 TL |
135 | } else { |
136 | log_error ("Corrupt lease file - possible data loss!"); | |
137 | skip_to_semi (cfile); | |
1358b874 TL |
138 | } |
139 | ||
140 | } while (1); | |
35454d8a TL |
141 | |
142 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; | |
143 | ||
144 | end_parse (&cfile); | |
145 | close (file); | |
146 | ||
147 | return status; | |
d7837182 TL |
148 | } |
149 | ||
2d59f590 TL |
150 | /* statement :== parameter | declaration |
151 | ||
152 | parameter :== timestamp | |
153 | | DEFAULT_LEASE_TIME lease_time | |
154 | | MAX_LEASE_TIME lease_time | |
155 | | DYNAMIC_BOOTP_LEASE_CUTOFF date | |
156 | | DYNAMIC_BOOTP_LEASE_LENGTH lease_time | |
157 | | BOOT_UNKNOWN_CLIENTS boolean | |
158 | | ONE_LEASE_PER_CLIENT boolean | |
5fea7b10 | 159 | | GET_LEASE_HOSTNAMES boolean |
c256bae9 | 160 | | USE_HOST_DECL_NAME boolean |
2d59f590 TL |
161 | | NEXT_SERVER ip-addr-or-hostname SEMI |
162 | | option_parameter | |
163 | | SERVER-IDENTIFIER ip-addr-or-hostname SEMI | |
164 | | FILENAME string-parameter | |
165 | | SERVER_NAME string-parameter | |
166 | | hardware-parameter | |
167 | | fixed-address-parameter | |
99fd97cc TL |
168 | | ALLOW allow-deny-keyword |
169 | | DENY allow-deny-keyword | |
59b85ebd | 170 | | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean |
763adef1 TL |
171 | | AUTHORITATIVE |
172 | | NOT AUTHORITATIVE | |
74f45f96 | 173 | | AUTH_KEY key-id key-value |
2d59f590 TL |
174 | |
175 | declaration :== host-declaration | |
176 | | group-declaration | |
177 | | shared-network-declaration | |
178 | | subnet-declaration | |
179 | | VENDOR_CLASS class-declaration | |
180 | | USER_CLASS class-declaration | |
181 | | RANGE address-range-declaration */ | |
182 | ||
183 | int parse_statement (cfile, group, type, host_decl, declaration) | |
35454d8a | 184 | struct parse *cfile; |
7dfc8ac2 TL |
185 | struct group *group; |
186 | int type; | |
187 | struct host_decl *host_decl; | |
2d59f590 | 188 | int declaration; |
d7837182 | 189 | { |
6f8fb41f | 190 | enum dhcp_token token; |
d7837182 | 191 | char *val; |
7dfc8ac2 | 192 | struct shared_network *share; |
7dfc8ac2 | 193 | char *t, *n; |
ece6ea33 TL |
194 | struct expression *expr; |
195 | struct data_string data; | |
7dfc8ac2 | 196 | struct hardware hardware; |
ece6ea33 TL |
197 | struct executable_statement *et, *ep; |
198 | struct option *option; | |
199 | struct option_cache *cache; | |
200 | int lose; | |
74f45f96 | 201 | struct data_string key_id; |
d7837182 | 202 | |
e68de775 TL |
203 | token = peek_token (&val, cfile); |
204 | ||
205 | switch (token) { | |
74f45f96 TL |
206 | case AUTH_KEY: |
207 | memset (&key_id, 0, sizeof key_id); | |
208 | if (parse_auth_key (&key_id, cfile)) { | |
209 | if (type == HOST_DECL) | |
210 | data_string_copy (&host_decl -> auth_key_id, | |
211 | &key_id, "parse_statement"); | |
212 | data_string_forget (&key_id, "parse_statement"); | |
213 | } | |
214 | break; | |
d7837182 | 215 | case HOST: |
ece6ea33 TL |
216 | next_token (&val, cfile); |
217 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 218 | parse_host_declaration (cfile, group); |
7dfc8ac2 | 219 | else { |
35454d8a TL |
220 | parse_warn (cfile, |
221 | "host declarations not allowed here."); | |
7dfc8ac2 | 222 | skip_to_semi (cfile); |
d7837182 | 223 | } |
7dfc8ac2 TL |
224 | return 1; |
225 | ||
226 | case GROUP: | |
ece6ea33 TL |
227 | next_token (&val, cfile); |
228 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 229 | parse_group_declaration (cfile, group); |
7dfc8ac2 | 230 | else { |
35454d8a TL |
231 | parse_warn (cfile, |
232 | "group declarations not allowed here."); | |
7dfc8ac2 | 233 | skip_to_semi (cfile); |
d7837182 | 234 | } |
7dfc8ac2 TL |
235 | return 1; |
236 | ||
d7837182 | 237 | case TIMESTAMP: |
ece6ea33 | 238 | next_token (&val, cfile); |
7dfc8ac2 | 239 | parsed_time = parse_timestamp (cfile); |
d7837182 | 240 | break; |
7dfc8ac2 | 241 | |
1f814ff2 | 242 | case SHARED_NETWORK: |
ece6ea33 | 243 | next_token (&val, cfile); |
2d59f590 TL |
244 | if (type == SHARED_NET_DECL || |
245 | type == HOST_DECL || | |
ece6ea33 TL |
246 | type == SUBNET_DECL || |
247 | type == CLASS_DECL) { | |
35454d8a | 248 | parse_warn (cfile, "shared-network parameters not %s.", |
7dfc8ac2 TL |
249 | "allowed here"); |
250 | skip_to_semi (cfile); | |
251 | break; | |
1f814ff2 | 252 | } |
7dfc8ac2 | 253 | |
2d59f590 | 254 | parse_shared_net_declaration (cfile, group); |
7dfc8ac2 TL |
255 | return 1; |
256 | ||
685963dc | 257 | case SUBNET: |
ece6ea33 TL |
258 | next_token (&val, cfile); |
259 | if (type == HOST_DECL || type == SUBNET_DECL || | |
260 | type == CLASS_DECL) { | |
35454d8a TL |
261 | parse_warn (cfile, |
262 | "subnet declarations not allowed here."); | |
7dfc8ac2 TL |
263 | skip_to_semi (cfile); |
264 | return 1; | |
265 | } | |
266 | ||
2d59f590 | 267 | /* If we're in a subnet declaration, just do the parse. */ |
7dfc8ac2 | 268 | if (group -> shared_network) { |
2d59f590 TL |
269 | parse_subnet_declaration (cfile, |
270 | group -> shared_network); | |
7dfc8ac2 TL |
271 | break; |
272 | } | |
273 | ||
274 | /* Otherwise, cons up a fake shared network structure | |
275 | and populate it with the lone subnet... */ | |
276 | ||
277 | share = new_shared_network ("parse_statement"); | |
278 | if (!share) | |
8ae2d595 | 279 | log_fatal ("No memory for shared subnet"); |
7dfc8ac2 TL |
280 | share -> group = clone_group (group, "parse_statement:subnet"); |
281 | share -> group -> shared_network = share; | |
282 | ||
2d59f590 | 283 | parse_subnet_declaration (cfile, share); |
763adef1 TL |
284 | |
285 | /* share -> subnets is the subnet we just parsed. */ | |
7dfc8ac2 TL |
286 | if (share -> subnets) { |
287 | share -> interface = | |
288 | share -> subnets -> interface; | |
289 | ||
763adef1 | 290 | /* Make the shared network name from network number. */ |
7dfc8ac2 TL |
291 | n = piaddr (share -> subnets -> net); |
292 | t = malloc (strlen (n) + 1); | |
1f814ff2 | 293 | if (!t) |
8ae2d595 | 294 | log_fatal ("no memory for subnet name"); |
1f814ff2 TL |
295 | strcpy (t, n); |
296 | share -> name = t; | |
763adef1 TL |
297 | |
298 | /* Copy the authoritative parameter from the subnet, | |
299 | since there is no opportunity to declare it here. */ | |
300 | share -> group -> authoritative = | |
301 | share -> subnets -> group -> authoritative; | |
1f814ff2 | 302 | enter_shared_network (share); |
d7837182 | 303 | } |
7dfc8ac2 TL |
304 | return 1; |
305 | ||
24a75c03 | 306 | case VENDOR_CLASS: |
ece6ea33 TL |
307 | next_token (&val, cfile); |
308 | if (type == CLASS_DECL) { | |
35454d8a TL |
309 | parse_warn (cfile, |
310 | "class declarations not allowed here."); | |
ece6ea33 TL |
311 | skip_to_semi (cfile); |
312 | break; | |
313 | } | |
2d59f590 | 314 | parse_class_declaration (cfile, group, 0); |
7dfc8ac2 TL |
315 | return 1; |
316 | ||
24a75c03 | 317 | case USER_CLASS: |
ece6ea33 TL |
318 | next_token (&val, cfile); |
319 | if (type == CLASS_DECL) { | |
35454d8a TL |
320 | parse_warn (cfile, |
321 | "class declarations not allowed here."); | |
ece6ea33 TL |
322 | skip_to_semi (cfile); |
323 | break; | |
324 | } | |
2d59f590 | 325 | parse_class_declaration (cfile, group, 1); |
7dfc8ac2 | 326 | return 1; |
1f814ff2 | 327 | |
ece6ea33 TL |
328 | case CLASS: |
329 | next_token (&val, cfile); | |
330 | if (type == CLASS_DECL) { | |
35454d8a TL |
331 | parse_warn (cfile, |
332 | "class declarations not allowed here."); | |
59b85ebd | 333 | skip_to_semi (cfile); |
ece6ea33 | 334 | break; |
59b85ebd | 335 | } |
ece6ea33 TL |
336 | parse_class_declaration (cfile, group, 2); |
337 | return 1; | |
59b85ebd | 338 | |
ece6ea33 TL |
339 | case SUBCLASS: |
340 | next_token (&val, cfile); | |
341 | if (type == CLASS_DECL) { | |
35454d8a TL |
342 | parse_warn (cfile, |
343 | "class declarations not allowed here."); | |
ece6ea33 | 344 | skip_to_semi (cfile); |
7dfc8ac2 | 345 | break; |
7dfc8ac2 | 346 | } |
ece6ea33 TL |
347 | parse_class_declaration (cfile, group, 3); |
348 | return 1; | |
7dfc8ac2 TL |
349 | |
350 | case HARDWARE: | |
ece6ea33 | 351 | next_token (&val, cfile); |
2d59f590 | 352 | parse_hardware_param (cfile, &hardware); |
7dfc8ac2 TL |
353 | if (host_decl) |
354 | host_decl -> interface = hardware; | |
355 | else | |
35454d8a | 356 | parse_warn (cfile, "hardware address parameter %s", |
7dfc8ac2 TL |
357 | "not allowed here."); |
358 | break; | |
359 | ||
360 | case FIXED_ADDR: | |
ece6ea33 | 361 | next_token (&val, cfile); |
6f8fb41f TL |
362 | cache = (struct option_cache *)0; |
363 | parse_fixed_addr_param (&cache, cfile); | |
7dfc8ac2 TL |
364 | if (host_decl) |
365 | host_decl -> fixed_addr = cache; | |
6f8fb41f | 366 | else { |
35454d8a | 367 | parse_warn (cfile, "fixed-address parameter not %s", |
7dfc8ac2 | 368 | "allowed here."); |
6f8fb41f TL |
369 | option_cache_dereference (&cache, "parse_statement"); |
370 | } | |
7dfc8ac2 TL |
371 | break; |
372 | ||
f63b4929 TL |
373 | case POOL: |
374 | next_token (&val, cfile); | |
375 | if (type != SUBNET_DECL && type != SHARED_NET_DECL) { | |
35454d8a | 376 | parse_warn (cfile, "pool declared outside of network"); |
f63b4929 | 377 | } |
74f45f96 | 378 | if (type == POOL_DECL) { |
35454d8a | 379 | parse_warn (cfile, "pool declared within pool."); |
74f45f96 | 380 | } |
f63b4929 TL |
381 | parse_pool_statement (cfile, group, type); |
382 | return declaration; | |
383 | ||
7dfc8ac2 | 384 | case RANGE: |
ece6ea33 | 385 | next_token (&val, cfile); |
2d59f590 | 386 | if (type != SUBNET_DECL || !group -> subnet) { |
35454d8a TL |
387 | parse_warn (cfile, |
388 | "range declaration not allowed here."); | |
7dfc8ac2 | 389 | skip_to_semi (cfile); |
2d59f590 | 390 | return declaration; |
7dfc8ac2 | 391 | } |
f63b4929 | 392 | parse_address_range (cfile, group, type, (struct pool *)0); |
2d59f590 | 393 | return declaration; |
7dfc8ac2 | 394 | |
763adef1 | 395 | case TOKEN_NOT: |
1b8223ae | 396 | token = next_token (&val, cfile); |
763adef1 TL |
397 | token = next_token (&val, cfile); |
398 | switch (token) { | |
399 | case AUTHORITATIVE: | |
400 | group -> authoritative = 0; | |
401 | goto authoritative; | |
402 | default: | |
35454d8a | 403 | parse_warn (cfile, "expecting assertion"); |
763adef1 TL |
404 | skip_to_semi (cfile); |
405 | break; | |
406 | } | |
407 | break; | |
408 | case AUTHORITATIVE: | |
1b8223ae | 409 | token = next_token (&val, cfile); |
763adef1 TL |
410 | group -> authoritative = 1; |
411 | authoritative: | |
1b8223ae | 412 | if (type == HOST_DECL) |
35454d8a | 413 | parse_warn (cfile, "authority makes no sense here."); |
763adef1 TL |
414 | parse_semi (cfile); |
415 | break; | |
416 | ||
8230a054 TL |
417 | /* "server-identifier" is a special hack, equivalent to |
418 | "option dhcp-server-identifier". */ | |
419 | case SERVER_IDENTIFIER: | |
420 | option = dhcp_universe.options [DHO_DHCP_SERVER_IDENTIFIER]; | |
421 | token = next_token (&val, cfile); | |
422 | goto finish_option; | |
423 | ||
6f8fb41f TL |
424 | case OPTION: |
425 | token = next_token (&val, cfile); | |
822d95c9 TL |
426 | token = peek_token (&val, cfile); |
427 | if (token == SPACE) { | |
428 | if (type != ROOT_GROUP) { | |
35454d8a TL |
429 | parse_warn (cfile, |
430 | "option space definitions %s", | |
822d95c9 TL |
431 | " may not be scoped."); |
432 | skip_to_semi (cfile); | |
433 | free_option (option, "parse_statement"); | |
434 | break; | |
435 | } | |
436 | parse_option_space_decl (cfile); | |
437 | return declaration; | |
438 | } | |
439 | ||
8230a054 | 440 | option = parse_option_name (cfile, 1); |
6f8fb41f | 441 | if (option) { |
8230a054 TL |
442 | token = peek_token (&val, cfile); |
443 | if (token == CODE) { | |
444 | if (type != ROOT_GROUP) { | |
35454d8a TL |
445 | parse_warn (cfile, |
446 | "option definitions%s%s", | |
822d95c9 | 447 | " may not be scoped."); |
8230a054 TL |
448 | skip_to_semi (cfile); |
449 | free_option (option, | |
450 | "parse_statement"); | |
451 | break; | |
452 | } | |
453 | next_token (&val, cfile); | |
454 | if (!parse_option_code_definition (cfile, | |
455 | option)) | |
456 | free_option (option, | |
457 | "parse_statement"); | |
458 | return declaration; | |
459 | } | |
460 | ||
461 | /* If this wasn't an option code definition, don't | |
462 | allow an unknown option. */ | |
463 | if (option -> code == -1) { | |
35454d8a | 464 | parse_warn (cfile, "unknown option %s.%s", |
8230a054 TL |
465 | option -> universe -> name, |
466 | option -> name); | |
467 | skip_to_semi (cfile); | |
468 | free_option (option, "parse_statement"); | |
469 | return declaration; | |
470 | } | |
471 | ||
472 | finish_option: | |
79a65726 TL |
473 | et = (struct executable_statement *)0; |
474 | if (!parse_option_statement | |
475 | (&et, cfile, 1, option, | |
476 | supersede_option_statement)) | |
6f8fb41f TL |
477 | return declaration; |
478 | goto insert_statement; | |
479 | } else | |
480 | return declaration; | |
481 | ||
482 | break; | |
483 | ||
763adef1 TL |
484 | #if defined (FAILOVER_PROTOCOL) |
485 | case FAILOVER: | |
486 | parse_failover_peer (cfile, group, type); | |
487 | break; | |
488 | #endif | |
489 | ||
d7837182 | 490 | default: |
ece6ea33 TL |
491 | et = (struct executable_statement *)0; |
492 | if (is_identifier (token)) { | |
493 | option = ((struct option *) | |
494 | hash_lookup (server_universe.hash, | |
495 | (unsigned char *)val, 0)); | |
496 | if (option) { | |
6f8fb41f | 497 | token = next_token (&val, cfile); |
79a65726 TL |
498 | if (!parse_option_statement |
499 | (&et, cfile, 1, option, | |
500 | supersede_option_statement)) | |
ece6ea33 TL |
501 | return declaration; |
502 | } | |
503 | } | |
504 | ||
505 | if (!et) { | |
506 | lose = 0; | |
79a65726 | 507 | if (!parse_executable_statement (&et, cfile, &lose)) { |
de94ca72 | 508 | if (!lose) { |
35454d8a TL |
509 | if (declaration) |
510 | parse_warn (cfile, | |
511 | "expecting a declaration"); | |
512 | else | |
513 | parse_warn (cfile, | |
514 | "expecting a parameter %s" | |
515 | "or declaration"); | |
de94ca72 TL |
516 | skip_to_semi (cfile); |
517 | } | |
ece6ea33 TL |
518 | return declaration; |
519 | } | |
520 | } | |
521 | if (!et) { | |
35454d8a | 522 | parse_warn (cfile, "expecting a %sdeclaration", |
ece6ea33 TL |
523 | declaration ? "" : "parameter or "); |
524 | return declaration; | |
525 | } | |
526 | insert_statement: | |
527 | if (group -> statements) { | |
79a65726 TL |
528 | int multi = 0; |
529 | ||
530 | /* If this set of statements is only referenced | |
531 | by this group, just add the current statement | |
532 | to the end of the chain. */ | |
ece6ea33 TL |
533 | for (ep = group -> statements; ep -> next; |
534 | ep = ep -> next) | |
79a65726 TL |
535 | if (ep -> refcnt > 1) /* XXX */ |
536 | multi = 1; | |
537 | if (!multi) { | |
538 | executable_statement_reference | |
539 | (&ep -> next, et, "parse_statement"); | |
540 | return declaration; | |
541 | } | |
ece6ea33 | 542 | |
79a65726 TL |
543 | /* Otherwise, make a parent chain, and put the |
544 | current group statements first and the new | |
545 | statement in the next pointer. */ | |
546 | ep = (struct executable_statement *)0; | |
547 | if (!executable_statement_allocate | |
548 | (&ep, "parse_statement")) | |
549 | log_fatal ("No memory for statements."); | |
550 | ep -> op = statements_statement; | |
551 | executable_statement_reference | |
552 | (&ep -> data.statements, | |
553 | group -> statements, "parse_statement"); | |
554 | executable_statement_reference | |
555 | (&ep -> next, et, "parse_statement"); | |
556 | executable_statement_dereference | |
557 | (&group -> statements, "parse_statement"); | |
558 | executable_statement_reference | |
559 | (&group -> statements, ep, "parse_statements"); | |
6f8fb41f | 560 | } else |
79a65726 TL |
561 | executable_statement_reference |
562 | (&group -> statements, et, "parse_statements"); | |
6f8fb41f | 563 | return declaration; |
d7837182 | 564 | } |
1f814ff2 | 565 | |
2d59f590 | 566 | if (declaration) { |
35454d8a TL |
567 | parse_warn (cfile, |
568 | "parameters not allowed after first declaration."); | |
7dfc8ac2 | 569 | return 1; |
1f814ff2 | 570 | } |
7dfc8ac2 TL |
571 | |
572 | return 0; | |
d7837182 TL |
573 | } |
574 | ||
763adef1 TL |
575 | #if defined (FAILOVER_PROTOCOL) |
576 | void parse_failover_peer (cfile, group, type) | |
35454d8a | 577 | struct parse *cfile; |
763adef1 TL |
578 | struct group *group; |
579 | int type; | |
580 | { | |
581 | enum dhcp_token token; | |
582 | char *val; | |
583 | struct failover_peer *peer; | |
584 | TIME *tp; | |
585 | char *name; | |
586 | ||
587 | if (type != SHARED_NET_DECL && type != ROOT_GROUP) { | |
35454d8a TL |
588 | parse_warn (cfile, |
589 | "failover peer statements not in shared-network%s" | |
763adef1 TL |
590 | " declaration or at top level."); |
591 | skip_to_semi (cfile); | |
592 | return; | |
593 | } | |
594 | ||
595 | token = next_token (&val, cfile); | |
596 | if (token != PEER) { | |
35454d8a | 597 | parse_warn (cfile, "expecting peer keyword"); |
763adef1 TL |
598 | skip_to_semi (cfile); |
599 | return; | |
600 | } | |
601 | ||
602 | token = next_token (&val, cfile); | |
603 | if (is_identifier (token) || token == STRING) { | |
604 | name = dmalloc (strlen (name) + 1, "peer name"); | |
605 | if (!peer -> name) | |
8ae2d595 | 606 | log_fatal ("no memory for peer name %s", name); |
763adef1 | 607 | } else { |
35454d8a | 608 | parse_warn (cfile, "expecting identifier or left brace"); |
763adef1 TL |
609 | skip_to_semi (cfile); |
610 | return; | |
611 | } | |
612 | ||
613 | /* See if there's a peer declaration by this name. */ | |
614 | peer = find_failover_peer (name); | |
615 | ||
616 | token = next_token (&val, cfile); | |
617 | if (token == SEMI) { | |
618 | dfree (name, "peer name"); | |
619 | if (type != SHARED_NET_DECL) | |
35454d8a | 620 | parse_warn (cfile, "failover peer reference not %s", |
763adef1 TL |
621 | "in shared-network declaration"); |
622 | else { | |
623 | if (!peer) { | |
35454d8a | 624 | parse_warn (cfile, "reference to unknown%s%s", |
763adef1 TL |
625 | " failover peer ", name); |
626 | return; | |
627 | } | |
628 | group -> shared_network -> failover_peer = | |
629 | peer; | |
630 | } | |
631 | return; | |
632 | } else if (token == MY || token == PARTNER) { | |
633 | if (!peer) { | |
35454d8a | 634 | parse_warn (cfile, "reference to unknown%s%s", |
763adef1 TL |
635 | " failover peer ", name); |
636 | return; | |
637 | } | |
638 | if ((token == MY | |
639 | ? peer -> my_state | |
640 | : peer -> partner_state) = parse_failover_state (cfile) == | |
641 | invalid_state) | |
642 | skip_to_semi (cfile); | |
643 | else | |
644 | parse_semi (cfile); | |
645 | return; | |
646 | } else if (token != LBRACE) { | |
35454d8a | 647 | parse_warn (cfile, "expecting left brace"); |
763adef1 TL |
648 | skip_to_semi (cfile); |
649 | } | |
650 | ||
651 | /* Make sure this isn't a redeclaration. */ | |
652 | if (peer) { | |
35454d8a | 653 | parse_warn (cfile, "redeclaration of failover peer %s", name); |
763adef1 TL |
654 | skip_to_rbrace (cfile, 1); |
655 | return; | |
656 | } | |
657 | ||
658 | peer = new_failover_peer ("parse_failover_peer"); | |
659 | if (!peer) | |
8ae2d595 | 660 | log_fatal ("no memory for %sfailover peer%s%s.", |
763adef1 TL |
661 | name ? "" : "anonymous", name ? " " : "", name); |
662 | ||
663 | /* Save the name. */ | |
664 | peer -> name = name; | |
665 | ||
666 | do { | |
667 | token = next_token (&val, cfile); | |
668 | switch (token) { | |
669 | case RBRACE: | |
670 | break; | |
671 | case PRIMARY: | |
672 | peer -> i_am = primary; | |
673 | break; | |
674 | case SECONDARY: | |
675 | peer -> i_am = secondary; | |
676 | break; | |
677 | case IDENTIFIER: | |
678 | if (!parse_ip_addr_or_hostname (&peer -> address, | |
679 | cfile, 0)) { | |
680 | skip_to_rbrace (cfile, 1); | |
681 | return; | |
682 | } | |
683 | break; | |
684 | case PORT: | |
685 | token = next_token (&val, cfile); | |
686 | if (token != NUMBER) { | |
35454d8a | 687 | parse_warn (cfile, "expecting number"); |
763adef1 TL |
688 | skip_to_rbrace (cfile, 1); |
689 | } | |
690 | peer -> port = atoi (val); | |
691 | if (!parse_semi (cfile)) { | |
692 | skip_to_rbrace (cfile, 1); | |
693 | return; | |
694 | } | |
695 | break; | |
696 | case MAX_TRANSMIT_IDLE: | |
697 | tp = &peer -> max_transmit_idle; | |
698 | goto parse_idle; | |
699 | case MAX_RESPONSE_DELAY: | |
700 | tp = &peer -> max_transmit_idle; | |
701 | parse_idle: | |
702 | token = next_token (&val, cfile); | |
703 | if (token != NUMBER) { | |
35454d8a | 704 | parse_warn (cfile, "expecting number."); |
763adef1 TL |
705 | skip_to_rbrace (cfile, 1); |
706 | return; | |
707 | } | |
708 | *tp = atoi (val); | |
709 | default: | |
35454d8a TL |
710 | parse_warn (cfile, |
711 | "invalid statement in peer declaration"); | |
763adef1 TL |
712 | skip_to_rbrace (cfile, 1); |
713 | return; | |
714 | } | |
715 | } while (token != RBRACE); | |
716 | ||
717 | if (type == SHARED_NET_DECL) { | |
718 | group -> shared_network -> failover_peer = peer; | |
719 | } | |
720 | enter_failover_peer (peer); | |
721 | } | |
722 | ||
723 | enum failover_state parse_failover_state (cfile) | |
35454d8a | 724 | struct parse *cfile; |
763adef1 TL |
725 | { |
726 | enum dhcp_token token; | |
727 | char *val; | |
728 | ||
729 | token = next_token (&val, cfile); | |
730 | switch (token) { | |
731 | case PARTNER_DOWN: | |
732 | return partner_down; | |
733 | case NORMAL: | |
734 | return normal; | |
735 | case COMMUNICATIONS_INTERRUPTED: | |
736 | return communications_interrupted; | |
737 | case POTENTIAL_CONFLICT: | |
738 | return potential_conflict; | |
739 | case RECOVER: | |
740 | return recover; | |
741 | default: | |
35454d8a | 742 | parse_warn (cfile, "unknown failover state"); |
763adef1 TL |
743 | break; |
744 | } | |
745 | return invalid_state; | |
746 | } | |
747 | #endif /* defined (FAILOVER_PROTOCOL) */ | |
748 | ||
f63b4929 | 749 | void parse_pool_statement (cfile, group, type) |
35454d8a | 750 | struct parse *cfile; |
f63b4929 TL |
751 | struct group *group; |
752 | int type; | |
753 | { | |
754 | enum dhcp_token token; | |
755 | char *val; | |
756 | int done = 0; | |
757 | struct pool *pool, **p; | |
758 | struct permit *permit; | |
759 | struct permit **permit_head; | |
74f45f96 | 760 | int declaration = 0; |
f63b4929 TL |
761 | |
762 | pool = new_pool ("parse_pool_statement"); | |
763 | if (!pool) | |
8ae2d595 | 764 | log_fatal ("no memory for pool."); |
f63b4929 | 765 | |
74f45f96 TL |
766 | pool -> group = clone_group (group, "parse_pool_statement"); |
767 | ||
f63b4929 TL |
768 | if (!parse_lbrace (cfile)) |
769 | return; | |
770 | do { | |
e5e41be4 TL |
771 | token = peek_token (&val, cfile); |
772 | switch (token) { | |
f63b4929 TL |
773 | case RANGE: |
774 | next_token (&val, cfile); | |
775 | parse_address_range (cfile, group, type, pool); | |
776 | break; | |
777 | case ALLOW: | |
778 | permit_head = &pool -> permit_list; | |
779 | get_permit: | |
780 | permit = new_permit ("parse_pool_statement"); | |
781 | if (!permit) | |
8ae2d595 | 782 | log_fatal ("no memory for permit"); |
f63b4929 TL |
783 | next_token (&val, cfile); |
784 | token = next_token (&val, cfile); | |
785 | switch (token) { | |
786 | case UNKNOWN: | |
787 | permit -> type = permit_unknown_clients; | |
788 | get_clients: | |
789 | if (next_token (&val, cfile) != CLIENTS) { | |
35454d8a TL |
790 | parse_warn (cfile, |
791 | "expecting \"clients\""); | |
f63b4929 TL |
792 | skip_to_semi (cfile); |
793 | free_permit (permit, | |
794 | "parse_pool_statement"); | |
795 | continue; | |
796 | } | |
797 | break; | |
798 | ||
ad1a6484 TL |
799 | case UNKNOWN_CLIENTS: |
800 | permit -> type = permit_unknown_clients; | |
801 | break; | |
802 | ||
f63b4929 TL |
803 | case KNOWN: |
804 | permit -> type = permit_known_clients; | |
805 | goto get_clients; | |
806 | ||
807 | case AUTHENTICATED: | |
808 | permit -> type = permit_authenticated_clients; | |
809 | goto get_clients; | |
810 | ||
811 | case UNAUTHENTICATED: | |
812 | permit -> type = | |
813 | permit_unauthenticated_clients; | |
814 | goto get_clients; | |
815 | ||
816 | case ALL: | |
817 | permit -> type = permit_all_clients; | |
818 | goto get_clients; | |
819 | break; | |
820 | ||
821 | case DYNAMIC: | |
822 | permit -> type = permit_dynamic_bootp_clients; | |
823 | if (next_token (&val, cfile) != BOOTP) { | |
35454d8a TL |
824 | parse_warn (cfile, |
825 | "expecting \"bootp\""); | |
f63b4929 TL |
826 | skip_to_semi (cfile); |
827 | free_permit (permit, | |
828 | "parse_pool_statement"); | |
829 | continue; | |
830 | } | |
831 | goto get_clients; | |
832 | ||
833 | case MEMBERS: | |
834 | if (next_token (&val, cfile) != OF) { | |
35454d8a | 835 | parse_warn (cfile, "expecting \"of\""); |
f63b4929 TL |
836 | skip_to_semi (cfile); |
837 | free_permit (permit, | |
838 | "parse_pool_statement"); | |
839 | continue; | |
840 | } | |
841 | if (next_token (&val, cfile) != STRING) { | |
35454d8a TL |
842 | parse_warn (cfile, |
843 | "expecting class name."); | |
f63b4929 TL |
844 | skip_to_semi (cfile); |
845 | free_permit (permit, | |
846 | "parse_pool_statement"); | |
847 | continue; | |
848 | } | |
849 | permit -> type = permit_class; | |
850 | permit -> class = find_class (val); | |
851 | if (!permit -> class) | |
35454d8a TL |
852 | parse_warn (cfile, |
853 | "no such class: %s", val); | |
e5e41be4 TL |
854 | break; |
855 | ||
f63b4929 | 856 | default: |
35454d8a | 857 | parse_warn (cfile, "expecting permit type."); |
f63b4929 TL |
858 | skip_to_semi (cfile); |
859 | break; | |
860 | } | |
861 | while (*permit_head) | |
862 | permit_head = &((*permit_head) -> next); | |
863 | *permit_head = permit; | |
74f45f96 | 864 | parse_semi (cfile); |
f63b4929 TL |
865 | break; |
866 | ||
867 | case DENY: | |
868 | permit_head = &pool -> prohibit_list; | |
869 | goto get_permit; | |
870 | ||
871 | case RBRACE: | |
872 | next_token (&val, cfile); | |
873 | done = 1; | |
874 | break; | |
875 | ||
876 | default: | |
74f45f96 TL |
877 | declaration = parse_statement (cfile, pool -> group, |
878 | POOL_DECL, | |
879 | (struct host_decl *)0, | |
880 | declaration); | |
f63b4929 TL |
881 | break; |
882 | } | |
883 | } while (!done); | |
884 | ||
885 | if (type == SUBNET_DECL) | |
886 | pool -> shared_network = group -> subnet -> shared_network; | |
887 | else | |
888 | pool -> shared_network = group -> shared_network; | |
889 | ||
890 | p = &pool -> shared_network -> pools; | |
891 | for (; *p; p = &((*p) -> next)) | |
892 | ; | |
893 | *p = pool; | |
894 | } | |
895 | ||
5376e3e9 TL |
896 | /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ |
897 | ||
898 | int parse_boolean (cfile) | |
35454d8a | 899 | struct parse *cfile; |
5376e3e9 | 900 | { |
6f8fb41f | 901 | enum dhcp_token token; |
5376e3e9 TL |
902 | char *val; |
903 | int rv; | |
904 | ||
905 | token = next_token (&val, cfile); | |
906 | if (!strcasecmp (val, "true") | |
907 | || !strcasecmp (val, "on")) | |
b179c997 | 908 | rv = 1; |
5376e3e9 TL |
909 | else if (!strcasecmp (val, "false") |
910 | || !strcasecmp (val, "off")) | |
911 | rv = 0; | |
912 | else { | |
35454d8a TL |
913 | parse_warn (cfile, |
914 | "boolean value (true/false/on/off) expected"); | |
5376e3e9 TL |
915 | skip_to_semi (cfile); |
916 | return 0; | |
917 | } | |
918 | parse_semi (cfile); | |
919 | return rv; | |
920 | } | |
921 | ||
7dfc8ac2 TL |
922 | /* Expect a left brace; if there isn't one, skip over the rest of the |
923 | statement and return zero; otherwise, return 1. */ | |
924 | ||
925 | int parse_lbrace (cfile) | |
35454d8a | 926 | struct parse *cfile; |
7dfc8ac2 | 927 | { |
6f8fb41f | 928 | enum dhcp_token token; |
7dfc8ac2 TL |
929 | char *val; |
930 | ||
931 | token = next_token (&val, cfile); | |
932 | if (token != LBRACE) { | |
35454d8a | 933 | parse_warn (cfile, "expecting left brace."); |
7dfc8ac2 TL |
934 | skip_to_semi (cfile); |
935 | return 0; | |
936 | } | |
937 | return 1; | |
d7837182 TL |
938 | } |
939 | ||
7dfc8ac2 | 940 | |
2d59f590 | 941 | /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ |
d7837182 | 942 | |
2d59f590 | 943 | void parse_host_declaration (cfile, group) |
35454d8a | 944 | struct parse *cfile; |
7dfc8ac2 | 945 | struct group *group; |
d7837182 TL |
946 | { |
947 | char *val; | |
6f8fb41f | 948 | enum dhcp_token token; |
7dfc8ac2 | 949 | struct host_decl *host; |
f3c3d674 | 950 | char *name; |
2d59f590 | 951 | int declaration = 0; |
612fded7 | 952 | int dynamicp = 0; |
ff129930 | 953 | int deleted = 0; |
92ce3f81 | 954 | isc_result_t status; |
7dfc8ac2 | 955 | |
f3c3d674 TL |
956 | token = peek_token (&val, cfile); |
957 | if (token != LBRACE) { | |
958 | name = parse_host_name (cfile); | |
959 | if (!name) | |
960 | return; | |
961 | } else { | |
962 | name = (char *)0; | |
963 | } | |
7dfc8ac2 TL |
964 | |
965 | host = (struct host_decl *)dmalloc (sizeof (struct host_decl), | |
2d59f590 | 966 | "parse_host_declaration"); |
7dfc8ac2 | 967 | if (!host) |
8ae2d595 | 968 | log_fatal ("can't allocate host decl struct %s.", name); |
2d92095d | 969 | memset (host, 0, sizeof *host); |
7dfc8ac2 | 970 | host -> name = name; |
2d59f590 | 971 | host -> group = clone_group (group, "parse_host_declaration"); |
7dfc8ac2 TL |
972 | |
973 | if (!parse_lbrace (cfile)) | |
974 | return; | |
d7837182 | 975 | |
d7837182 TL |
976 | do { |
977 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 978 | if (token == RBRACE) { |
d7837182 TL |
979 | token = next_token (&val, cfile); |
980 | break; | |
981 | } | |
5376e3e9 TL |
982 | if (token == EOF) { |
983 | token = next_token (&val, cfile); | |
35454d8a | 984 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
985 | break; |
986 | } | |
612fded7 TL |
987 | /* If the host declaration was created by the server, |
988 | remember to save it. */ | |
989 | if (token == DYNAMIC) { | |
990 | dynamicp = 1; | |
991 | token = next_token (&val, cfile); | |
992 | if (!parse_semi (cfile)) | |
993 | break; | |
994 | continue; | |
995 | } | |
ff129930 TL |
996 | /* If the host declaration was created by the server, |
997 | remember to save it. */ | |
998 | if (token == DELETED) { | |
999 | deleted = 1; | |
1000 | token = next_token (&val, cfile); | |
1001 | if (!parse_semi (cfile)) | |
1002 | break; | |
1003 | continue; | |
1004 | } | |
29c35bed TL |
1005 | |
1006 | if (token == GROUP) { | |
1007 | struct group_object *go; | |
1008 | token = next_token (&val, cfile); | |
1009 | token = next_token (&val, cfile); | |
1010 | if (token != STRING && !is_identifier (token)) { | |
35454d8a TL |
1011 | parse_warn (cfile, |
1012 | "expecting string or identifier."); | |
29c35bed TL |
1013 | skip_to_rbrace (cfile, 1); |
1014 | break; | |
1015 | } | |
1016 | go = ((struct group_object *) | |
1017 | hash_lookup (group_name_hash, | |
77a5f871 TL |
1018 | (unsigned char *)val, |
1019 | strlen (val))); | |
29c35bed | 1020 | if (!go) { |
35454d8a TL |
1021 | parse_warn (cfile, "unknown group %s in host %s", |
1022 | val, host -> name); | |
29c35bed TL |
1023 | } else { |
1024 | if (host -> named_group) | |
1025 | omapi_object_dereference | |
1026 | ((omapi_object_t **) | |
1027 | &host -> named_group, | |
1028 | "parse_host_declaration"); | |
1029 | omapi_object_reference | |
1030 | ((omapi_object_t **) | |
1031 | &host -> named_group, | |
1032 | (omapi_object_t *)go, | |
1033 | "parse_host_declaration"); | |
1034 | } | |
1035 | if (!parse_semi (cfile)) | |
1036 | break; | |
1037 | continue; | |
1038 | } | |
1039 | ||
1040 | if (token == UID) { | |
1041 | char *s; | |
1042 | unsigned char *t = 0; | |
1043 | int len; | |
1044 | ||
1045 | token = next_token (&val, cfile); | |
1046 | data_string_forget (&host -> client_identifier, | |
1047 | "parse_host_declaration"); | |
1048 | ||
1049 | /* See if it's a string or a cshl. */ | |
1050 | token = peek_token (&val, cfile); | |
1051 | if (token == STRING) { | |
1052 | token = next_token (&val, cfile); | |
1053 | s = val; | |
1054 | len = strlen (val); | |
1055 | host -> client_identifier.terminated = 1; | |
1056 | } else { | |
1057 | len = 0; | |
1058 | t = parse_numeric_aggregate | |
1059 | (cfile, | |
1060 | (unsigned char *)0, &len, ':', 16, 8); | |
1061 | if (!t) { | |
35454d8a TL |
1062 | parse_warn (cfile, |
1063 | "expecting hex list."); | |
29c35bed TL |
1064 | skip_to_semi (cfile); |
1065 | } | |
1066 | s = (char *)t; | |
1067 | } | |
1068 | if (!buffer_allocate | |
1069 | (&host -> client_identifier.buffer, | |
1070 | len + host -> client_identifier.terminated, | |
1071 | "parse_host_declaration")) | |
1072 | log_fatal ("no memory for uid for host %s.", | |
1073 | host -> name); | |
1074 | host -> client_identifier.data = | |
1075 | host -> client_identifier.buffer -> data; | |
1076 | host -> client_identifier.len = len; | |
1077 | memcpy (host -> client_identifier.data, s, | |
1078 | len + host -> client_identifier.terminated); | |
1079 | if (t) | |
1080 | dfree (t, "parse_host_declaration"); | |
1081 | ||
1082 | if (!parse_semi (cfile)) | |
1083 | break; | |
1084 | continue; | |
1085 | } | |
2d59f590 TL |
1086 | declaration = parse_statement (cfile, host -> group, |
1087 | HOST_DECL, host, | |
1088 | declaration); | |
d7837182 | 1089 | } while (1); |
7dfc8ac2 | 1090 | |
ff129930 TL |
1091 | if (deleted) { |
1092 | struct host_decl *hp = | |
1093 | (struct host_decl *) | |
1094 | hash_lookup (host_name_hash, | |
29c35bed TL |
1095 | (unsigned char *)host -> name, |
1096 | strlen (host -> name)); | |
ff129930 TL |
1097 | if (hp) { |
1098 | delete_host (hp, 0); | |
1099 | } | |
1100 | dfree (host -> name, "parse_host_declaration"); | |
29c35bed TL |
1101 | if (host -> group) |
1102 | free_group (host -> group, "parse_host_declaration"); | |
ff129930 TL |
1103 | dfree (host, "parse_host_declaration"); |
1104 | } else { | |
29c35bed TL |
1105 | if (host -> named_group && host -> named_group -> group) { |
1106 | if (host -> group -> statements || | |
1107 | (host -> group -> authoritative != | |
1108 | host -> named_group -> group -> authoritative)) | |
1109 | host -> group -> next = | |
1110 | host -> named_group -> group; | |
1111 | else { | |
1112 | dfree (host -> group, | |
1113 | "parse_host_declaration"); | |
1114 | host -> group = host -> named_group -> group; | |
1115 | } | |
1116 | } | |
1117 | ||
92ce3f81 TL |
1118 | status = enter_host (host, dynamicp, 0); |
1119 | if (status != ISC_R_SUCCESS) | |
35454d8a TL |
1120 | parse_warn (cfile, |
1121 | "host %s: %s", isc_result_totext (status)); | |
ff129930 | 1122 | } |
d7837182 TL |
1123 | } |
1124 | ||
2d59f590 | 1125 | /* class-declaration :== STRING LBRACE parameters declarations RBRACE |
24a75c03 TL |
1126 | */ |
1127 | ||
88dcab62 | 1128 | struct class *parse_class_declaration (cfile, group, type) |
35454d8a | 1129 | struct parse *cfile; |
7dfc8ac2 | 1130 | struct group *group; |
24a75c03 TL |
1131 | int type; |
1132 | { | |
1133 | char *val; | |
6f8fb41f | 1134 | enum dhcp_token token; |
de94ca72 | 1135 | struct class *class = (struct class *)0, *pc; |
f4d0f440 | 1136 | int declaration = 0; |
e5e41be4 | 1137 | int lose = 0; |
ece6ea33 TL |
1138 | struct data_string data; |
1139 | char *name; | |
1140 | struct executable_statement *stmt = (struct executable_statement *)0; | |
1141 | struct expression *expr; | |
de94ca72 | 1142 | int new = 1; |
24a75c03 TL |
1143 | |
1144 | token = next_token (&val, cfile); | |
1145 | if (token != STRING) { | |
35454d8a | 1146 | parse_warn (cfile, "Expecting class name"); |
24a75c03 | 1147 | skip_to_semi (cfile); |
88dcab62 | 1148 | return (struct class *)0; |
24a75c03 TL |
1149 | } |
1150 | ||
ece6ea33 TL |
1151 | /* See if there's already a class with the specified name. */ |
1152 | pc = (struct class *)find_class (val); | |
1153 | ||
1154 | /* If this isn't a subclass, we're updating an existing class. */ | |
1155 | if (pc && type != 0 && type != 1 && type != 3) { | |
1156 | class = pc; | |
de94ca72 | 1157 | new = 0; |
ece6ea33 TL |
1158 | pc = (struct class *)0; |
1159 | } | |
1160 | ||
1161 | /* If this _is_ a subclass, there _must_ be a class with the | |
1162 | same name. */ | |
1163 | if (!pc && (type == 0 || type == 1 || type == 3)) { | |
35454d8a | 1164 | parse_warn (cfile, "no class named %s", val); |
ece6ea33 | 1165 | skip_to_semi (cfile); |
88dcab62 | 1166 | return (struct class *)0; |
ece6ea33 TL |
1167 | } |
1168 | ||
1169 | /* The old vendor-class and user-class declarations had an implicit | |
1170 | match. We don't do the implicit match anymore. Instead, for | |
1171 | backward compatibility, we have an implicit-vendor-class and an | |
1172 | implicit-user-class. vendor-class and user-class declarations | |
1173 | are turned into subclasses of the implicit classes, and the | |
8b500185 | 1174 | submatch expression of the implicit classes extracts the contents of |
ece6ea33 TL |
1175 | the vendor class or user class. */ |
1176 | if (type == 0 || type == 1) { | |
1177 | data.len = strlen (val); | |
6f8fb41f TL |
1178 | data.buffer = (struct buffer *)0; |
1179 | if (!buffer_allocate (&data.buffer, | |
1180 | data.len + 1, "parse_class_declaration")) | |
8ae2d595 | 1181 | log_fatal ("no memoy for class name."); |
6f8fb41f | 1182 | data.data = &data.buffer -> data [0]; |
ece6ea33 TL |
1183 | data.terminated = 1; |
1184 | ||
1185 | name = type ? "implicit-vendor-class" : "implicit-user-class"; | |
1186 | } else if (type == 2) { | |
1187 | if (!(name = dmalloc (strlen (val) + 1, | |
1188 | "parse_class_declaration"))) | |
8ae2d595 | 1189 | log_fatal ("No memory for class name %s.", val); |
ece6ea33 TL |
1190 | strcpy (name, val); |
1191 | } else { | |
1192 | name = (char *)0; | |
1193 | } | |
1194 | ||
1195 | /* If this is a straight subclass, parse the hash string. */ | |
1196 | if (type == 3) { | |
1197 | token = peek_token (&val, cfile); | |
1198 | if (token == STRING) { | |
1199 | token = next_token (&val, cfile); | |
1200 | data.len = strlen (val); | |
6f8fb41f TL |
1201 | data.buffer = (struct buffer *)0; |
1202 | if (!buffer_allocate (&data.buffer, data.len + 1, | |
1203 | "parse_class_declaration")) | |
88dcab62 | 1204 | return (struct class *)0; |
ece6ea33 | 1205 | data.terminated = 1; |
6f8fb41f | 1206 | data.data = &data.buffer -> data [0]; |
c5b0f529 | 1207 | strcpy ((char *)data.data, val); |
ece6ea33 | 1208 | } else if (token == NUMBER_OR_NAME || token == NUMBER) { |
6f8fb41f TL |
1209 | memset (&data, 0, sizeof data); |
1210 | if (!parse_cshl (&data, cfile)) | |
88dcab62 | 1211 | return (struct class *)0; |
e68de775 | 1212 | } else { |
35454d8a | 1213 | parse_warn (cfile, "Expecting string or hex list."); |
e68de775 | 1214 | return (struct class *)0; |
ece6ea33 TL |
1215 | } |
1216 | } | |
1217 | ||
1218 | /* See if there's already a class in the hash table matching the | |
1219 | hash data. */ | |
1220 | if (type == 0 || type == 1 || type == 3) | |
1221 | class = ((struct class *) | |
1222 | hash_lookup (pc -> hash, data.data, data.len)); | |
1223 | ||
1224 | /* If we didn't find an existing class, allocate a new one. */ | |
1225 | if (!class) { | |
1226 | /* Allocate the class structure... */ | |
1227 | class = (struct class *)dmalloc (sizeof (struct class), | |
1228 | "parse_class_declaration"); | |
1229 | if (!class) | |
8ae2d595 | 1230 | log_fatal ("No memory for class %s.", val); |
ece6ea33 TL |
1231 | memset (class, 0, sizeof *class); |
1232 | if (pc) { | |
88dcab62 TL |
1233 | class -> group = pc -> group; |
1234 | class -> superclass = pc; | |
1235 | class -> lease_limit = pc -> lease_limit; | |
1236 | if (class -> lease_limit) { | |
1237 | class -> billed_leases = | |
1238 | dmalloc (class -> lease_limit * | |
1239 | sizeof (struct lease *), | |
e68de775 | 1240 | "parse_class_declaration"); |
88dcab62 | 1241 | if (!class -> billed_leases) |
e68de775 | 1242 | log_fatal ("no memory for billing"); |
88dcab62 TL |
1243 | memset (class -> billed_leases, 0, |
1244 | (class -> lease_limit * | |
1245 | sizeof class -> billed_leases)); | |
1246 | } | |
1247 | data_string_copy (&class -> hash_string, &data, | |
e68de775 | 1248 | "parse_class_declaration"); |
88dcab62 TL |
1249 | if (!pc -> hash) |
1250 | pc -> hash = new_hash (); | |
ece6ea33 | 1251 | add_hash (pc -> hash, |
88dcab62 TL |
1252 | class -> hash_string.data, |
1253 | class -> hash_string.len, | |
1254 | (unsigned char *)class); | |
ece6ea33 TL |
1255 | } else { |
1256 | class -> group = | |
1257 | clone_group (group, "parse_class_declaration"); | |
1258 | } | |
1259 | ||
1260 | /* If this is an implicit vendor or user class, add a | |
1261 | statement that causes the vendor or user class ID to | |
1262 | be sent back in the reply. */ | |
1263 | if (type == 0 || type == 1) { | |
1264 | stmt = ((struct executable_statement *) | |
1265 | dmalloc (sizeof (struct executable_statement), | |
1266 | "implicit user/vendor class")); | |
1267 | if (!stmt) | |
8ae2d595 | 1268 | log_fatal ("no memory for class statement."); |
ece6ea33 TL |
1269 | memset (stmt, 0, sizeof *stmt); |
1270 | stmt -> op = supersede_option_statement; | |
6f8fb41f TL |
1271 | if (option_cache_allocate (&stmt -> data.option, |
1272 | "parse_class_statement")) { | |
1273 | stmt -> data.option -> data = data; | |
1274 | stmt -> data.option -> option = | |
1275 | dhcp_universe.options | |
1276 | [type | |
ca3a51a5 TL |
1277 | ? DHO_VENDOR_CLASS_IDENTIFIER |
1278 | : DHO_USER_CLASS]; | |
6f8fb41f | 1279 | } |
ece6ea33 TL |
1280 | class -> statements = stmt; |
1281 | } | |
de94ca72 TL |
1282 | |
1283 | /* Save the name, if there is one. */ | |
1284 | class -> name = name; | |
ece6ea33 | 1285 | } |
7dfc8ac2 | 1286 | |
88dcab62 | 1287 | if (type == 0 || type == 1 || type == 3) |
e68de775 | 1288 | data_string_forget (&data, "parse_class_declaration"); |
88dcab62 TL |
1289 | |
1290 | /* Spawned classes don't have their own settings. */ | |
1291 | if (class -> superclass) { | |
e68de775 TL |
1292 | token = peek_token (&val, cfile); |
1293 | if (token == SEMI) { | |
1294 | next_token (&val, cfile); | |
1295 | return class; | |
1296 | } | |
1297 | /* Give the subclass its own group. */ | |
1298 | class -> group = clone_group (class -> group, | |
1299 | "parse_class_declaration"); | |
88dcab62 TL |
1300 | } |
1301 | ||
7dfc8ac2 | 1302 | if (!parse_lbrace (cfile)) |
88dcab62 | 1303 | return (struct class *)0; |
24a75c03 TL |
1304 | |
1305 | do { | |
1306 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 1307 | if (token == RBRACE) { |
24a75c03 TL |
1308 | token = next_token (&val, cfile); |
1309 | break; | |
5376e3e9 TL |
1310 | } else if (token == EOF) { |
1311 | token = next_token (&val, cfile); | |
35454d8a | 1312 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1313 | break; |
ece6ea33 TL |
1314 | } else if (token == MATCH) { |
1315 | if (pc) { | |
35454d8a TL |
1316 | parse_warn (cfile, |
1317 | "invalid match in subclass."); | |
ece6ea33 TL |
1318 | skip_to_semi (cfile); |
1319 | break; | |
1320 | } | |
1321 | if (class -> expr) { | |
35454d8a | 1322 | parse_warn (cfile, "can't override match."); |
ece6ea33 TL |
1323 | skip_to_semi (cfile); |
1324 | break; | |
1325 | } | |
1326 | token = next_token (&val, cfile); | |
e68de775 | 1327 | token = peek_token (&val, cfile); |
8b500185 TL |
1328 | if (token != IF) |
1329 | goto submatch; | |
e68de775 | 1330 | token = next_token (&val, cfile); |
6f8fb41f TL |
1331 | parse_boolean_expression (&class -> expr, cfile, |
1332 | &lose); | |
ece6ea33 TL |
1333 | if (lose) |
1334 | break; | |
6f8fb41f TL |
1335 | #if defined (DEBUG_EXPRESSION_PARSE) |
1336 | print_expression ("class match", class -> expr); | |
1337 | #endif | |
de94ca72 | 1338 | parse_semi (cfile); |
ece6ea33 TL |
1339 | } else if (token == SPAWN) { |
1340 | if (pc) { | |
35454d8a TL |
1341 | parse_warn (cfile, |
1342 | "invalid spawn in subclass."); | |
ece6ea33 TL |
1343 | skip_to_semi (cfile); |
1344 | break; | |
1345 | } | |
ece6ea33 TL |
1346 | token = next_token (&val, cfile); |
1347 | token = next_token (&val, cfile); | |
1348 | if (token != WITH) { | |
35454d8a TL |
1349 | parse_warn (cfile, |
1350 | "expecting with after spawn"); | |
ece6ea33 TL |
1351 | skip_to_semi (cfile); |
1352 | break; | |
1353 | } | |
8b500185 TL |
1354 | class -> spawning = 1; |
1355 | submatch: | |
1356 | if (class -> submatch) { | |
35454d8a TL |
1357 | parse_warn (cfile, |
1358 | "can't override existing %s.", | |
8b500185 TL |
1359 | "submatch/spawn"); |
1360 | skip_to_semi (cfile); | |
1361 | break; | |
1362 | } | |
1363 | parse_data_expression (&class -> submatch, | |
1364 | cfile, &lose); | |
ece6ea33 TL |
1365 | if (lose) |
1366 | break; | |
6f8fb41f | 1367 | #if defined (DEBUG_EXPRESSION_PARSE) |
8b500185 TL |
1368 | print_expression ("class submatch", |
1369 | class -> submatch); | |
6f8fb41f | 1370 | #endif |
de94ca72 | 1371 | parse_semi (cfile); |
88dcab62 TL |
1372 | } else if (token == LEASE) { |
1373 | next_token (&val, cfile); | |
1374 | token = next_token (&val, cfile); | |
1375 | if (token != LIMIT) { | |
35454d8a | 1376 | parse_warn (cfile, "expecting \"limit\""); |
88dcab62 TL |
1377 | if (token != SEMI) |
1378 | skip_to_semi (cfile); | |
1379 | break; | |
1380 | } | |
1381 | token = next_token (&val, cfile); | |
1382 | if (token != NUMBER) { | |
35454d8a | 1383 | parse_warn (cfile, "expecting a number"); |
88dcab62 TL |
1384 | if (token != SEMI) |
1385 | skip_to_semi (cfile); | |
1386 | break; | |
1387 | } | |
1388 | class -> lease_limit = atoi (val); | |
1389 | class -> billed_leases = | |
1390 | dmalloc (class -> lease_limit * | |
1391 | sizeof (struct lease *), | |
e68de775 | 1392 | "parse_class_declaration"); |
88dcab62 | 1393 | if (!class -> billed_leases) |
8ae2d595 | 1394 | log_fatal ("no memory for billed leases."); |
88dcab62 TL |
1395 | memset (class -> billed_leases, 0, |
1396 | (class -> lease_limit * | |
1397 | sizeof class -> billed_leases)); | |
1398 | have_billing_classes = 1; | |
1399 | parse_semi (cfile); | |
24a75c03 | 1400 | } else { |
2d59f590 TL |
1401 | declaration = parse_statement (cfile, class -> group, |
1402 | CLASS_DECL, | |
1403 | (struct host_decl *)0, | |
1404 | declaration); | |
24a75c03 TL |
1405 | } |
1406 | } while (1); | |
de94ca72 TL |
1407 | if (type == 2 && new) { |
1408 | if (!collections -> classes) | |
1409 | collections -> classes = class; | |
1410 | else { | |
1411 | struct class *cp; | |
1412 | for (cp = collections -> classes; | |
1413 | cp -> nic; cp = cp -> nic) | |
1414 | ; | |
1415 | cp -> nic = class; | |
1416 | } | |
1417 | } | |
88dcab62 | 1418 | return class; |
24a75c03 TL |
1419 | } |
1420 | ||
2d59f590 TL |
1421 | /* shared-network-declaration :== |
1422 | hostname LBRACE declarations parameters RBRACE */ | |
1f814ff2 | 1423 | |
2d59f590 | 1424 | void parse_shared_net_declaration (cfile, group) |
35454d8a | 1425 | struct parse *cfile; |
7dfc8ac2 | 1426 | struct group *group; |
1f814ff2 TL |
1427 | { |
1428 | char *val; | |
6f8fb41f | 1429 | enum dhcp_token token; |
1f814ff2 | 1430 | struct shared_network *share; |
1f814ff2 | 1431 | char *name; |
2d59f590 | 1432 | int declaration = 0; |
1f814ff2 | 1433 | |
2d59f590 | 1434 | share = new_shared_network ("parse_shared_net_declaration"); |
1f814ff2 | 1435 | if (!share) |
8ae2d595 | 1436 | log_fatal ("No memory for shared subnet"); |
f63b4929 | 1437 | share -> pools = (struct pool *)0; |
1f814ff2 | 1438 | share -> next = (struct shared_network *)0; |
9ab92650 | 1439 | share -> interface = (struct interface_info *)0; |
2d59f590 | 1440 | share -> group = clone_group (group, "parse_shared_net_declaration"); |
7dfc8ac2 | 1441 | share -> group -> shared_network = share; |
1f814ff2 TL |
1442 | |
1443 | /* Get the name of the shared network... */ | |
7dfc8ac2 TL |
1444 | token = peek_token (&val, cfile); |
1445 | if (token == STRING) { | |
1446 | token = next_token (&val, cfile); | |
1447 | ||
1448 | if (val [0] == 0) { | |
35454d8a | 1449 | parse_warn (cfile, "zero-length shared network name"); |
7dfc8ac2 TL |
1450 | val = "<no-name-given>"; |
1451 | } | |
1452 | name = malloc (strlen (val) + 1); | |
1453 | if (!name) | |
8ae2d595 | 1454 | log_fatal ("no memory for shared network name"); |
7dfc8ac2 TL |
1455 | strcpy (name, val); |
1456 | } else { | |
1457 | name = parse_host_name (cfile); | |
1458 | if (!name) | |
1459 | return; | |
1f814ff2 | 1460 | } |
1f814ff2 TL |
1461 | share -> name = name; |
1462 | ||
7dfc8ac2 TL |
1463 | if (!parse_lbrace (cfile)) |
1464 | return; | |
1465 | ||
1f814ff2 | 1466 | do { |
7dfc8ac2 TL |
1467 | token = peek_token (&val, cfile); |
1468 | if (token == RBRACE) { | |
1469 | token = next_token (&val, cfile); | |
1470 | if (!share -> subnets) { | |
35454d8a TL |
1471 | parse_warn (cfile, |
1472 | "empty shared-network decl"); | |
1f814ff2 TL |
1473 | return; |
1474 | } | |
1f814ff2 TL |
1475 | enter_shared_network (share); |
1476 | return; | |
5376e3e9 TL |
1477 | } else if (token == EOF) { |
1478 | token = next_token (&val, cfile); | |
35454d8a | 1479 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1480 | break; |
1f814ff2 | 1481 | } |
5376e3e9 | 1482 | |
2d59f590 TL |
1483 | declaration = parse_statement (cfile, share -> group, |
1484 | SHARED_NET_DECL, | |
1485 | (struct host_decl *)0, | |
1486 | declaration); | |
1f814ff2 TL |
1487 | } while (1); |
1488 | } | |
1489 | ||
2d59f590 TL |
1490 | /* subnet-declaration :== |
1491 | net NETMASK netmask RBRACE parameters declarations LBRACE */ | |
685963dc | 1492 | |
2d59f590 | 1493 | void parse_subnet_declaration (cfile, share) |
35454d8a | 1494 | struct parse *cfile; |
1f814ff2 | 1495 | struct shared_network *share; |
685963dc TL |
1496 | { |
1497 | char *val; | |
6f8fb41f | 1498 | enum dhcp_token token; |
763adef1 | 1499 | struct subnet *subnet, *t, *u; |
7dfc8ac2 | 1500 | struct iaddr iaddr; |
685963dc TL |
1501 | unsigned char addr [4]; |
1502 | int len = sizeof addr; | |
2d59f590 | 1503 | int declaration = 0; |
685963dc | 1504 | |
2d59f590 | 1505 | subnet = new_subnet ("parse_subnet_declaration"); |
685963dc | 1506 | if (!subnet) |
8ae2d595 | 1507 | log_fatal ("No memory for new subnet"); |
1f814ff2 | 1508 | subnet -> shared_network = share; |
7dfc8ac2 | 1509 | subnet -> group = clone_group (share -> group, |
2d59f590 | 1510 | "parse_subnet_declaration"); |
7dfc8ac2 | 1511 | subnet -> group -> subnet = subnet; |
685963dc TL |
1512 | |
1513 | /* Get the network number... */ | |
7dfc8ac2 TL |
1514 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1515 | return; | |
1516 | memcpy (iaddr.iabuf, addr, len); | |
1517 | iaddr.len = len; | |
1518 | subnet -> net = iaddr; | |
685963dc TL |
1519 | |
1520 | token = next_token (&val, cfile); | |
1521 | if (token != NETMASK) { | |
35454d8a | 1522 | parse_warn (cfile, "Expecting netmask"); |
685963dc | 1523 | skip_to_semi (cfile); |
7dfc8ac2 | 1524 | return; |
685963dc TL |
1525 | } |
1526 | ||
1527 | /* Get the netmask... */ | |
7dfc8ac2 TL |
1528 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1529 | return; | |
1530 | memcpy (iaddr.iabuf, addr, len); | |
1531 | iaddr.len = len; | |
1532 | subnet -> netmask = iaddr; | |
685963dc TL |
1533 | |
1534 | enter_subnet (subnet); | |
1535 | ||
7dfc8ac2 TL |
1536 | if (!parse_lbrace (cfile)) |
1537 | return; | |
1538 | ||
685963dc TL |
1539 | do { |
1540 | token = peek_token (&val, cfile); | |
7dfc8ac2 TL |
1541 | if (token == RBRACE) { |
1542 | token = next_token (&val, cfile); | |
685963dc | 1543 | break; |
5376e3e9 TL |
1544 | } else if (token == EOF) { |
1545 | token = next_token (&val, cfile); | |
35454d8a | 1546 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1547 | break; |
7dfc8ac2 | 1548 | } |
2d59f590 TL |
1549 | declaration = parse_statement (cfile, subnet -> group, |
1550 | SUBNET_DECL, | |
1551 | (struct host_decl *)0, | |
1552 | declaration); | |
685963dc | 1553 | } while (1); |
1f814ff2 | 1554 | |
6cdd0d0d | 1555 | /* Add the subnet to the list of subnets in this shared net. */ |
7dfc8ac2 TL |
1556 | if (!share -> subnets) |
1557 | share -> subnets = subnet; | |
1558 | else { | |
763adef1 | 1559 | u = (struct subnet *)0; |
7dfc8ac2 | 1560 | for (t = share -> subnets; |
763adef1 TL |
1561 | t -> next_sibling; t = t -> next_sibling) { |
1562 | if (subnet_inner_than (subnet, t, 0)) { | |
1563 | if (u) | |
1564 | u -> next_sibling = subnet; | |
1565 | else | |
1566 | share -> subnets = subnet; | |
1567 | subnet -> next_sibling = t; | |
1568 | return; | |
1569 | } | |
1570 | u = t; | |
1571 | } | |
6cdd0d0d | 1572 | t -> next_sibling = subnet; |
7dfc8ac2 | 1573 | } |
685963dc TL |
1574 | } |
1575 | ||
2d59f590 | 1576 | /* group-declaration :== RBRACE parameters declarations LBRACE */ |
7dfc8ac2 | 1577 | |
2d59f590 | 1578 | void parse_group_declaration (cfile, group) |
35454d8a | 1579 | struct parse *cfile; |
7dfc8ac2 | 1580 | struct group *group; |
685963dc TL |
1581 | { |
1582 | char *val; | |
6f8fb41f | 1583 | enum dhcp_token token; |
7dfc8ac2 | 1584 | struct group *g; |
2d59f590 | 1585 | int declaration = 0; |
29c35bed TL |
1586 | struct group_object *t; |
1587 | isc_result_t status; | |
1588 | char *name; | |
1589 | int deletedp = 0; | |
1590 | int dynamicp = 0; | |
1591 | int staticp = 0; | |
685963dc | 1592 | |
2d59f590 | 1593 | g = clone_group (group, "parse_group_declaration"); |
685963dc | 1594 | |
29c35bed TL |
1595 | token = peek_token (&val, cfile); |
1596 | if (is_identifier (token) || token == STRING) { | |
1597 | next_token (&val, cfile); | |
1598 | ||
1599 | name = dmalloc (strlen (val) + 1, "parse_group_declaration"); | |
1600 | if (!name) | |
1601 | log_fatal ("no memory for group decl name %s", val); | |
1602 | strcpy (name, val); | |
1603 | } | |
1604 | ||
7dfc8ac2 TL |
1605 | if (!parse_lbrace (cfile)) |
1606 | return; | |
d7837182 | 1607 | |
7dfc8ac2 TL |
1608 | do { |
1609 | token = peek_token (&val, cfile); | |
5376e3e9 TL |
1610 | if (token == RBRACE) { |
1611 | token = next_token (&val, cfile); | |
7dfc8ac2 | 1612 | break; |
5376e3e9 TL |
1613 | } else if (token == EOF) { |
1614 | token = next_token (&val, cfile); | |
35454d8a | 1615 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1616 | break; |
29c35bed TL |
1617 | } else if (token == DELETED) { |
1618 | token = next_token (&val, cfile); | |
1619 | parse_semi (cfile); | |
1620 | deletedp = 1; | |
1621 | } else if (token == DYNAMIC) { | |
1622 | token = next_token (&val, cfile); | |
1623 | parse_semi (cfile); | |
1624 | dynamicp = 1; | |
1625 | } else if (token == STATIC) { | |
1626 | token = next_token (&val, cfile); | |
1627 | parse_semi (cfile); | |
1628 | staticp = 1; | |
5376e3e9 | 1629 | } |
2d59f590 TL |
1630 | declaration = parse_statement (cfile, g, GROUP_DECL, |
1631 | (struct host_decl *)0, | |
1632 | declaration); | |
7dfc8ac2 | 1633 | } while (1); |
29c35bed TL |
1634 | |
1635 | if (name) { | |
1636 | if (deletedp) { | |
1637 | if (group_name_hash) { | |
1638 | t = ((struct group_object *) | |
1639 | hash_lookup (group_name_hash, | |
77a5f871 TL |
1640 | (unsigned char *)name, |
1641 | strlen (name))); | |
29c35bed TL |
1642 | if (t) { |
1643 | delete_group (t, 0); | |
1644 | } | |
1645 | } | |
1646 | } else { | |
1647 | t = dmalloc (sizeof *t, "parse_group_declaration"); | |
1648 | if (!t) | |
1649 | log_fatal ("no memory for group decl %s", val); | |
1650 | memset (t, 0, sizeof *t); | |
1651 | t -> type = dhcp_type_group; | |
1652 | t -> group = g; | |
1653 | t -> name = name; | |
1654 | t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) | | |
1655 | (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) | | |
1656 | (deletedp ? GROUP_OBJECT_DELETED : 0)); | |
1657 | supersede_group (t, 0); | |
1658 | } | |
1659 | } | |
d7837182 TL |
1660 | } |
1661 | ||
2d59f590 TL |
1662 | /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI |
1663 | ip-addrs-or-hostnames :== ip-addr-or-hostname | |
1664 | | ip-addrs-or-hostnames ip-addr-or-hostname */ | |
d7837182 | 1665 | |
6f8fb41f TL |
1666 | int parse_fixed_addr_param (oc, cfile) |
1667 | struct option_cache **oc; | |
35454d8a | 1668 | struct parse *cfile; |
d7837182 | 1669 | { |
1f814ff2 | 1670 | char *val; |
6f8fb41f | 1671 | enum dhcp_token token; |
ece6ea33 | 1672 | struct expression *expr = (struct expression *)0; |
6f8fb41f TL |
1673 | struct expression *tmp, *new; |
1674 | int status; | |
1f814ff2 TL |
1675 | |
1676 | do { | |
6f8fb41f TL |
1677 | tmp = (struct expression *)0; |
1678 | if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) { | |
028a8588 TL |
1679 | if (expr) { |
1680 | new = (struct expression *)0; | |
1681 | status = make_concat (&new, expr, tmp); | |
1682 | expression_dereference | |
1683 | (&expr, "parse_fixed_addr_param"); | |
1684 | expression_dereference | |
1685 | (&tmp, "parse_fixed_addr_param"); | |
1686 | if (status) | |
1687 | return 0; | |
1688 | expr = new; | |
1689 | } else | |
1690 | expr = tmp; | |
6f8fb41f TL |
1691 | } else { |
1692 | if (expr) | |
1693 | expression_dereference | |
1694 | (&expr, "parse_fixed_addr_param"); | |
1695 | return 0; | |
1696 | } | |
1f814ff2 | 1697 | token = peek_token (&val, cfile); |
5376e3e9 | 1698 | if (token == COMMA) |
1f814ff2 TL |
1699 | token = next_token (&val, cfile); |
1700 | } while (token == COMMA); | |
7dfc8ac2 | 1701 | |
6f8fb41f TL |
1702 | if (!parse_semi (cfile)) { |
1703 | if (expr) | |
1704 | expression_dereference (&expr, | |
1705 | "parse_fixed_addr_param"); | |
1706 | return 0; | |
1707 | } | |
1708 | status = option_cache (oc, (struct data_string *)0, expr, | |
1709 | (struct option *)0); | |
1710 | expression_dereference (&expr, "parse_fixed_addr_param"); | |
1711 | return status; | |
d7837182 TL |
1712 | } |
1713 | ||
5376e3e9 | 1714 | /* timestamp :== date |
d7837182 TL |
1715 | |
1716 | Timestamps are actually not used in dhcpd.conf, which is a static file, | |
5376e3e9 TL |
1717 | but rather in the database file and the journal file. (Okay, actually |
1718 | they're not even used there yet). */ | |
d7837182 | 1719 | |
7dfc8ac2 | 1720 | TIME parse_timestamp (cfile) |
35454d8a | 1721 | struct parse *cfile; |
d7837182 | 1722 | { |
089fb364 | 1723 | TIME rv; |
089fb364 | 1724 | |
7dfc8ac2 | 1725 | rv = parse_date (cfile); |
089fb364 | 1726 | return rv; |
d7837182 TL |
1727 | } |
1728 | ||
2d59f590 TL |
1729 | /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE |
1730 | ||
1731 | lease_parameters :== <nil> | |
1732 | | lease_parameter | |
1733 | | lease_parameters lease_parameter | |
1734 | ||
1735 | lease_parameter :== STARTS date | |
1736 | | ENDS date | |
1737 | | TIMESTAMP date | |
1738 | | HARDWARE hardware-parameter | |
1739 | | UID hex_numbers SEMI | |
f7c82688 TL |
1740 | | DDNS_FWD_NAME hostname |
1741 | | DDNS_REV_NAME hostname | |
ccf5778a TL |
1742 | | HOSTNAME hostname SEMI |
1743 | | CLIENT_HOSTNAME hostname SEMI | |
2d59f590 TL |
1744 | | CLASS identifier SEMI |
1745 | | DYNAMIC_BOOTP SEMI */ | |
1746 | ||
1747 | struct lease *parse_lease_declaration (cfile) | |
35454d8a | 1748 | struct parse *cfile; |
d7837182 TL |
1749 | { |
1750 | char *val; | |
6f8fb41f | 1751 | enum dhcp_token token; |
d7837182 TL |
1752 | unsigned char addr [4]; |
1753 | int len = sizeof addr; | |
d7837182 TL |
1754 | int seenmask = 0; |
1755 | int seenbit; | |
1756 | char tbuf [32]; | |
d7837182 | 1757 | static struct lease lease; |
96d7d13e TL |
1758 | struct executable_statement *on; |
1759 | int lose; | |
d7837182 | 1760 | |
9375101b TL |
1761 | /* Zap the lease structure... */ |
1762 | memset (&lease, 0, sizeof lease); | |
1763 | ||
d7837182 | 1764 | /* Get the address for which the lease has been issued. */ |
7dfc8ac2 TL |
1765 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
1766 | return (struct lease *)0; | |
089fb364 TL |
1767 | memcpy (lease.ip_addr.iabuf, addr, len); |
1768 | lease.ip_addr.len = len; | |
d7837182 | 1769 | |
7dfc8ac2 TL |
1770 | if (!parse_lbrace (cfile)) |
1771 | return (struct lease *)0; | |
1772 | ||
d7837182 TL |
1773 | do { |
1774 | token = next_token (&val, cfile); | |
7dfc8ac2 | 1775 | if (token == RBRACE) |
d7837182 | 1776 | break; |
5376e3e9 | 1777 | else if (token == EOF) { |
35454d8a | 1778 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
1779 | break; |
1780 | } | |
ece6ea33 | 1781 | strncpy (tbuf, val, sizeof tbuf); |
d7837182 TL |
1782 | tbuf [(sizeof tbuf) - 1] = 0; |
1783 | ||
1784 | /* Parse any of the times associated with the lease. */ | |
1785 | if (token == STARTS || token == ENDS || token == TIMESTAMP) { | |
1786 | TIME t; | |
7dfc8ac2 | 1787 | t = parse_date (cfile); |
d7837182 TL |
1788 | switch (token) { |
1789 | case STARTS: | |
1790 | seenbit = 1; | |
1791 | lease.starts = t; | |
1792 | break; | |
1793 | ||
1794 | case ENDS: | |
1795 | seenbit = 2; | |
1796 | lease.ends = t; | |
1797 | break; | |
1798 | ||
1799 | case TIMESTAMP: | |
1800 | seenbit = 4; | |
1801 | lease.timestamp = t; | |
1802 | break; | |
19d868b2 TL |
1803 | |
1804 | default: | |
1805 | /*NOTREACHED*/ | |
1806 | seenbit = 0; | |
1807 | break; | |
d7837182 TL |
1808 | } |
1809 | } else { | |
1810 | switch (token) { | |
1811 | /* Colon-seperated hexadecimal octets... */ | |
1812 | case UID: | |
1813 | seenbit = 8; | |
9375101b TL |
1814 | token = peek_token (&val, cfile); |
1815 | if (token == STRING) { | |
c4f1fbb0 | 1816 | token = next_token (&val, cfile); |
29c35bed | 1817 | lease.uid_len = strlen (val); |
7e8381e5 TL |
1818 | lease.uid = (unsigned char *) |
1819 | malloc (lease.uid_len); | |
c256bae9 | 1820 | if (!lease.uid) { |
8ae2d595 | 1821 | log_error ("no space for uid"); |
c256bae9 TL |
1822 | return (struct lease *)0; |
1823 | } | |
7e8381e5 | 1824 | memcpy (lease.uid, val, lease.uid_len); |
29c35bed | 1825 | parse_semi (cfile); |
9375101b | 1826 | } else { |
7e8381e5 TL |
1827 | lease.uid_len = 0; |
1828 | lease.uid = parse_numeric_aggregate | |
7dfc8ac2 | 1829 | (cfile, (unsigned char *)0, |
9375101b | 1830 | &lease.uid_len, ':', 16, 8); |
c256bae9 | 1831 | if (!lease.uid) { |
8ae2d595 | 1832 | log_error ("no space for uid"); |
7dfc8ac2 | 1833 | return (struct lease *)0; |
c256bae9 | 1834 | } |
9375101b | 1835 | if (lease.uid_len == 0) { |
c256bae9 | 1836 | lease.uid = (unsigned char *)0; |
35454d8a TL |
1837 | parse_warn (cfile, |
1838 | "zero-length uid"); | |
c4f1fbb0 | 1839 | seenbit = 0; |
9375101b TL |
1840 | break; |
1841 | } | |
1842 | } | |
d7837182 | 1843 | if (!lease.uid) { |
8ae2d595 | 1844 | log_fatal ("No memory for lease uid"); |
d7837182 | 1845 | } |
d7837182 TL |
1846 | break; |
1847 | ||
d7837182 TL |
1848 | case CLASS: |
1849 | seenbit = 32; | |
1850 | token = next_token (&val, cfile); | |
1851 | if (!is_identifier (token)) { | |
1852 | if (token != SEMI) | |
1853 | skip_to_semi (cfile); | |
7dfc8ac2 | 1854 | return (struct lease *)0; |
d7837182 TL |
1855 | } |
1856 | /* for now, we aren't using this. */ | |
1857 | break; | |
1858 | ||
1859 | case HARDWARE: | |
1860 | seenbit = 64; | |
2d59f590 | 1861 | parse_hardware_param (cfile, |
7dfc8ac2 | 1862 | &lease.hardware_addr); |
d7837182 TL |
1863 | break; |
1864 | ||
1f814ff2 TL |
1865 | case DYNAMIC_BOOTP: |
1866 | seenbit = 128; | |
1867 | lease.flags |= BOOTP_LEASE; | |
1868 | break; | |
1869 | ||
4006d804 TL |
1870 | case ABANDONED: |
1871 | seenbit = 256; | |
1872 | lease.flags |= ABANDONED_LEASE; | |
1873 | break; | |
1874 | ||
ccf5778a TL |
1875 | case HOSTNAME: |
1876 | seenbit = 512; | |
56a89931 TL |
1877 | token = peek_token (&val, cfile); |
1878 | if (token == STRING) | |
1879 | lease.hostname = parse_string (cfile); | |
1880 | else | |
1881 | lease.hostname = | |
1882 | parse_host_name (cfile); | |
ccf5778a TL |
1883 | if (!lease.hostname) { |
1884 | seenbit = 0; | |
1885 | return (struct lease *)0; | |
1886 | } | |
1887 | break; | |
1888 | ||
1889 | case CLIENT_HOSTNAME: | |
05a8d03c | 1890 | seenbit = 1024; |
200d216c TL |
1891 | token = peek_token (&val, cfile); |
1892 | if (token == STRING) | |
1893 | lease.client_hostname = | |
1894 | parse_string (cfile); | |
1895 | else | |
1896 | lease.client_hostname = | |
1897 | parse_host_name (cfile); | |
ccf5778a TL |
1898 | break; |
1899 | ||
88dcab62 TL |
1900 | case BILLING: |
1901 | seenbit = 2048; | |
1902 | token = next_token (&val, cfile); | |
1903 | if (token == CLASS) { | |
1904 | token = next_token (&val, cfile); | |
1905 | if (token != STRING) { | |
35454d8a TL |
1906 | parse_warn (cfile, |
1907 | "expecting string"); | |
1908 | if (token != SEMI) | |
1909 | skip_to_semi (cfile); | |
1910 | token = BILLING; | |
1911 | break; | |
88dcab62 TL |
1912 | } |
1913 | lease.billing_class = find_class (val); | |
1914 | if (!lease.billing_class) | |
35454d8a TL |
1915 | parse_warn (cfile, |
1916 | "unknown class %s", | |
88dcab62 TL |
1917 | val); |
1918 | parse_semi (cfile); | |
1919 | } else if (token == SUBCLASS) { | |
1920 | lease.billing_class = | |
1921 | parse_class_declaration | |
1922 | (cfile, (struct group *)0, 3); | |
1923 | } else { | |
35454d8a TL |
1924 | parse_warn (cfile, |
1925 | "expecting \"class\""); | |
88dcab62 TL |
1926 | if (token != SEMI) |
1927 | skip_to_semi (cfile); | |
1928 | } | |
1929 | token = BILLING; | |
1930 | break; | |
1931 | ||
f7c82688 TL |
1932 | case DDNS_FWD_NAME: |
1933 | seenbit = 4096; | |
1934 | token = peek_token (&val, cfile); | |
1935 | if (token == STRING) | |
1936 | lease.ddns_fwd_name = | |
1937 | parse_string (cfile); | |
1938 | else | |
1939 | lease.ddns_fwd_name = | |
1940 | parse_host_name (cfile); | |
1941 | break; | |
1942 | ||
1943 | case DDNS_REV_NAME: | |
1944 | seenbit = 8192; | |
1945 | token = peek_token (&val, cfile); | |
1946 | if (token == STRING) | |
1947 | lease.ddns_rev_name = | |
1948 | parse_string (cfile); | |
1949 | else | |
1950 | lease.ddns_rev_name = | |
1951 | parse_host_name (cfile); | |
1952 | break; | |
f7c82688 | 1953 | |
96d7d13e TL |
1954 | case ON: |
1955 | on = (struct executable_statement *)0; | |
1956 | lose = 0; | |
1957 | if (!parse_on_statement (&on, cfile, &lose)) { | |
1958 | skip_to_rbrace (cfile, 1); | |
1959 | return (struct lease *)0; | |
1960 | } | |
1961 | if (on -> data.on.evtype == expiry && | |
1962 | on -> data.on.statements) { | |
1963 | seenbit = 16384; | |
1964 | executable_statement_reference | |
1965 | (&lease.on_expiry, | |
1966 | on -> data.on.statements, | |
1967 | "parse_lease_declaration"); | |
1968 | } else if (on -> data.on.evtype == release && | |
1969 | on -> data.on.statements) { | |
1970 | seenbit = 32768; | |
1971 | executable_statement_reference | |
1972 | (&lease.on_release, | |
1973 | on -> data.on.statements, | |
1974 | "parse_lease_declaration"); | |
1975 | } else { | |
1976 | seenbit = 0; | |
1977 | } | |
1978 | executable_statement_dereference | |
1979 | (&on, "parse_lease_declaration"); | |
1980 | break; | |
1981 | ||
d7837182 | 1982 | default: |
7dfc8ac2 | 1983 | skip_to_semi (cfile); |
19d868b2 | 1984 | seenbit = 0; |
7dfc8ac2 TL |
1985 | return (struct lease *)0; |
1986 | } | |
1987 | ||
88dcab62 | 1988 | if (token != HARDWARE && token != STRING |
96d7d13e | 1989 | && token != BILLING && token != ON) { |
7dfc8ac2 TL |
1990 | token = next_token (&val, cfile); |
1991 | if (token != SEMI) { | |
35454d8a TL |
1992 | parse_warn (cfile, |
1993 | "semicolon expected."); | |
7dfc8ac2 TL |
1994 | skip_to_semi (cfile); |
1995 | return (struct lease *)0; | |
1996 | } | |
d7837182 TL |
1997 | } |
1998 | } | |
1999 | if (seenmask & seenbit) { | |
35454d8a TL |
2000 | parse_warn (cfile, |
2001 | "Too many %s parameters in lease %s\n", | |
089fb364 | 2002 | tbuf, piaddr (lease.ip_addr)); |
d7837182 TL |
2003 | } else |
2004 | seenmask |= seenbit; | |
7dfc8ac2 | 2005 | |
d7837182 TL |
2006 | } while (1); |
2007 | return &lease; | |
2008 | } | |
2009 | ||
2d59f590 TL |
2010 | /* address-range-declaration :== ip-address ip-address SEMI |
2011 | | DYNAMIC_BOOTP ip-address ip-address SEMI */ | |
d7837182 | 2012 | |
f63b4929 | 2013 | void parse_address_range (cfile, group, type, pool) |
35454d8a | 2014 | struct parse *cfile; |
f63b4929 TL |
2015 | struct group *group; |
2016 | int type; | |
2017 | struct pool *pool; | |
d7837182 | 2018 | { |
f63b4929 | 2019 | struct iaddr low, high, net; |
d7837182 TL |
2020 | unsigned char addr [4]; |
2021 | int len = sizeof addr; | |
6f8fb41f | 2022 | enum dhcp_token token; |
089fb364 | 2023 | char *val; |
1f814ff2 | 2024 | int dynamic = 0; |
f63b4929 TL |
2025 | struct subnet *subnet; |
2026 | struct shared_network *share; | |
2027 | struct pool *p; | |
1f814ff2 TL |
2028 | |
2029 | if ((token = peek_token (&val, cfile)) == DYNAMIC_BOOTP) { | |
5376e3e9 | 2030 | token = next_token (&val, cfile); |
ece6ea33 | 2031 | dynamic = 1; |
1f814ff2 | 2032 | } |
d7837182 TL |
2033 | |
2034 | /* Get the bottom address in the range... */ | |
7dfc8ac2 TL |
2035 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2036 | return; | |
089fb364 TL |
2037 | memcpy (low.iabuf, addr, len); |
2038 | low.len = len; | |
d7837182 | 2039 | |
2d59f590 TL |
2040 | /* Only one address? */ |
2041 | token = peek_token (&val, cfile); | |
2042 | if (token == SEMI) | |
2043 | high = low; | |
2044 | else { | |
d7837182 | 2045 | /* Get the top address in the range... */ |
2d59f590 TL |
2046 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2047 | return; | |
2048 | memcpy (high.iabuf, addr, len); | |
2049 | high.len = len; | |
2050 | } | |
d7837182 | 2051 | |
7dfc8ac2 TL |
2052 | token = next_token (&val, cfile); |
2053 | if (token != SEMI) { | |
35454d8a | 2054 | parse_warn (cfile, "semicolon expected."); |
7dfc8ac2 TL |
2055 | skip_to_semi (cfile); |
2056 | return; | |
2057 | } | |
2058 | ||
f63b4929 TL |
2059 | if (type == SUBNET_DECL) { |
2060 | subnet = group -> subnet; | |
2061 | share = subnet -> shared_network; | |
2062 | } else { | |
2063 | share = group -> shared_network; | |
2064 | for (subnet = share -> subnets; | |
2065 | subnet; subnet = subnet -> next_sibling) { | |
2066 | net = subnet_number (low, subnet -> netmask); | |
e5e41be4 | 2067 | if (addr_eq (net, subnet -> net)) |
f63b4929 TL |
2068 | break; |
2069 | } | |
2070 | if (!subnet) { | |
35454d8a | 2071 | parse_warn (cfile, "address range not on network %s", |
f63b4929 | 2072 | group -> shared_network -> name); |
e5e41be4 TL |
2073 | log_error ("Be sure to place pool statement after %s", |
2074 | "related subnet declarations."); | |
f63b4929 TL |
2075 | return; |
2076 | } | |
2077 | } | |
2078 | ||
2079 | if (!pool) { | |
2080 | struct pool *last; | |
2081 | /* If we're permitting dynamic bootp for this range, | |
2082 | then look for a pool with an empty prohibit list and | |
2083 | a permit list with one entry which permits dynamic | |
2084 | bootp. */ | |
2085 | for (pool = share -> pools; pool; pool = pool -> next) { | |
2086 | if ((!dynamic && | |
2087 | !pool -> permit_list && !pool -> prohibit_list) || | |
2088 | (dynamic && | |
2089 | !pool -> prohibit_list && | |
2090 | pool -> permit_list && | |
2091 | !pool -> permit_list -> next && | |
2092 | (pool -> permit_list -> type == | |
2093 | permit_dynamic_bootp_clients))) { | |
2094 | break; | |
2095 | } | |
2096 | last = pool; | |
2097 | } | |
2098 | ||
2099 | /* If we didn't get a pool, make one. */ | |
2100 | if (!pool) { | |
2101 | pool = new_pool ("parse_address_range"); | |
2102 | if (!pool) | |
8ae2d595 | 2103 | log_fatal ("no memory for ad-hoc pool."); |
f63b4929 TL |
2104 | if (dynamic) { |
2105 | pool -> permit_list = | |
2106 | new_permit ("parse_address_range"); | |
2107 | if (!pool -> permit_list) | |
e5e41be4 TL |
2108 | log_fatal ("no memory for ad-hoc %s.", |
2109 | "permit"); | |
f63b4929 TL |
2110 | pool -> permit_list -> type = |
2111 | permit_dynamic_bootp_clients; | |
2112 | } | |
2113 | if (share -> pools) | |
2114 | last -> next = pool; | |
2115 | else | |
2116 | share -> pools = pool; | |
ac3d438f TL |
2117 | pool -> shared_network = share; |
2118 | pool -> group = clone_group (share -> group, | |
2119 | "parse_address_range"); | |
f63b4929 TL |
2120 | } |
2121 | } | |
2122 | ||
d7837182 | 2123 | /* Create the new address range... */ |
f63b4929 | 2124 | new_address_range (low, high, subnet, pool); |
d7837182 TL |
2125 | } |
2126 |