]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* confpars.c |
2 | ||
3 | Parser for dhcpd config file... */ | |
4 | ||
5 | /* | |
49733f31 TL |
6 | * Copyright (c) 1995-2000 Internet Software Consortium. |
7 | * All rights reserved. | |
d7837182 | 8 | * |
49733f31 TL |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
d7837182 | 12 | * |
49733f31 TL |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of The Internet Software Consortium nor the names | |
19 | * of its contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
d7837182 | 21 | * |
49733f31 TL |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR | |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * This software has been written for the Internet Software Consortium | |
37 | * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. | |
38 | * To learn more about the Internet Software Consortium, see | |
39 | * ``http://www.isc.org/''. To learn more about Vixie Enterprises, | |
40 | * see ``http://www.vix.com''. To learn more about Nominum, Inc., see | |
41 | * ``http://www.nominum.com''. | |
d7837182 TL |
42 | */ |
43 | ||
44 | #ifndef lint | |
45 | static char copyright[] = | |
06d3e394 | 46 | "$Id: confpars.c,v 1.126 2000/09/01 19:35:38 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; |
d7837182 TL |
47 | #endif /* not lint */ |
48 | ||
49 | #include "dhcpd.h" | |
d7837182 TL |
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 | |
35454d8a | 57 | isc_result_t readconf () |
20916cae TL |
58 | { |
59 | return parse_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP); | |
60 | } | |
61 | ||
62 | /* conf-file :== parameters declarations EOF | |
63 | parameters :== <nil> | parameter | parameters parameter | |
64 | declarations :== <nil> | declaration | declarations declaration */ | |
65 | ||
66 | isc_result_t parse_conf_file (const char *filename, struct group *group, | |
67 | int group_type) | |
d7837182 | 68 | { |
35454d8a TL |
69 | int file; |
70 | struct parse *cfile; | |
b1b7b521 | 71 | const char *val; |
6f8fb41f | 72 | enum dhcp_token token; |
2d59f590 | 73 | int declaration = 0; |
35454d8a | 74 | int status; |
7e8381e5 | 75 | |
20916cae TL |
76 | if ((file = open (filename, O_RDONLY)) < 0) |
77 | log_fatal ("Can't open %s: %m", filename); | |
35454d8a TL |
78 | |
79 | cfile = (struct parse *)0; | |
20916cae | 80 | new_parse (&cfile, file, (char *)0, 0, filename); |
35454d8a | 81 | |
d7837182 TL |
82 | do { |
83 | token = peek_token (&val, cfile); | |
84 | if (token == EOF) | |
85 | break; | |
20916cae | 86 | declaration = parse_statement (cfile, group, group_type, |
ece6ea33 TL |
87 | (struct host_decl *)0, |
88 | declaration); | |
d7837182 | 89 | } while (1); |
88ddda34 TL |
90 | token = next_token (&val, cfile); /* Clear the peek buffer */ |
91 | ||
35454d8a TL |
92 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; |
93 | ||
94 | end_parse (&cfile); | |
95 | close (file); | |
96 | return status; | |
1358b874 TL |
97 | } |
98 | ||
2d59f590 | 99 | /* lease-file :== lease-declarations EOF |
5376e3e9 | 100 | lease-statments :== <nil> |
2d59f590 TL |
101 | | lease-declaration |
102 | | lease-declarations lease-declaration */ | |
5376e3e9 | 103 | |
35454d8a | 104 | isc_result_t read_leases () |
1358b874 | 105 | { |
35454d8a TL |
106 | struct parse *cfile; |
107 | int file; | |
b1b7b521 | 108 | const char *val; |
6f8fb41f | 109 | enum dhcp_token token; |
35454d8a | 110 | isc_result_t status; |
7dfc8ac2 TL |
111 | |
112 | /* Open the lease file. If we can't open it, fail. The reason | |
113 | for this is that although on initial startup, the absence of | |
114 | a lease file is perfectly benign, if dhcpd has been running | |
115 | and this file is absent, it means that dhcpd tried and failed | |
116 | to rewrite the lease database. If we proceed and the | |
117 | problem which caused the rewrite to fail has been fixed, but no | |
118 | human has corrected the database problem, then we are left | |
119 | thinking that no leases have been assigned to anybody, which | |
120 | could create severe network chaos. */ | |
35454d8a | 121 | if ((file = open (path_dhcpd_db, O_RDONLY)) < 0) { |
2d1b06e0 TL |
122 | log_error ("Can't open lease database %s: %m -- %s", |
123 | path_dhcpd_db, | |
124 | "check for failed database rewrite attempt!"); | |
125 | log_error ("Please read the dhcpd.leases manual page if you"); | |
126 | log_fatal ("don't know what to do about this."); | |
127 | } | |
128 | ||
35454d8a TL |
129 | cfile = (struct parse *)0; |
130 | new_parse (&cfile, file, (char *)0, 0, path_dhcpd_db); | |
131 | ||
1358b874 TL |
132 | do { |
133 | token = next_token (&val, cfile); | |
1358b874 TL |
134 | if (token == EOF) |
135 | break; | |
52e79d12 | 136 | if (token == LEASE) { |
20916cae TL |
137 | struct lease *lease = (struct lease *)0; |
138 | if (parse_lease_declaration (&lease, cfile)) { | |
1358b874 | 139 | enter_lease (lease); |
20916cae | 140 | lease_dereference (&lease, MDL); |
96d7d13e | 141 | } else |
35454d8a TL |
142 | parse_warn (cfile, |
143 | "possibly corrupt lease file"); | |
52e79d12 | 144 | } else if (token == HOST) { |
20916cae | 145 | parse_host_declaration (cfile, root_group); |
35454d8a | 146 | } else if (token == GROUP) { |
20916cae | 147 | parse_group_declaration (cfile, root_group); |
a4ba3160 TL |
148 | #if defined (FAILOVER_PROTOCOL) |
149 | } else if (token == FAILOVER) { | |
150 | parse_failover_state_declaration | |
151 | (cfile, (dhcp_failover_state_t *)0); | |
152 | #endif | |
52e79d12 TL |
153 | } else { |
154 | log_error ("Corrupt lease file - possible data loss!"); | |
155 | skip_to_semi (cfile); | |
1358b874 TL |
156 | } |
157 | ||
158 | } while (1); | |
35454d8a TL |
159 | |
160 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; | |
161 | ||
162 | end_parse (&cfile); | |
163 | close (file); | |
164 | ||
165 | return status; | |
d7837182 TL |
166 | } |
167 | ||
2d59f590 TL |
168 | /* statement :== parameter | declaration |
169 | ||
170 | parameter :== timestamp | |
171 | | DEFAULT_LEASE_TIME lease_time | |
172 | | MAX_LEASE_TIME lease_time | |
173 | | DYNAMIC_BOOTP_LEASE_CUTOFF date | |
174 | | DYNAMIC_BOOTP_LEASE_LENGTH lease_time | |
175 | | BOOT_UNKNOWN_CLIENTS boolean | |
176 | | ONE_LEASE_PER_CLIENT boolean | |
5fea7b10 | 177 | | GET_LEASE_HOSTNAMES boolean |
c256bae9 | 178 | | USE_HOST_DECL_NAME boolean |
2d59f590 TL |
179 | | NEXT_SERVER ip-addr-or-hostname SEMI |
180 | | option_parameter | |
181 | | SERVER-IDENTIFIER ip-addr-or-hostname SEMI | |
182 | | FILENAME string-parameter | |
183 | | SERVER_NAME string-parameter | |
184 | | hardware-parameter | |
185 | | fixed-address-parameter | |
99fd97cc TL |
186 | | ALLOW allow-deny-keyword |
187 | | DENY allow-deny-keyword | |
59b85ebd | 188 | | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean |
763adef1 TL |
189 | | AUTHORITATIVE |
190 | | NOT AUTHORITATIVE | |
2d59f590 TL |
191 | |
192 | declaration :== host-declaration | |
193 | | group-declaration | |
194 | | shared-network-declaration | |
195 | | subnet-declaration | |
196 | | VENDOR_CLASS class-declaration | |
197 | | USER_CLASS class-declaration | |
198 | | RANGE address-range-declaration */ | |
199 | ||
200 | int parse_statement (cfile, group, type, host_decl, declaration) | |
35454d8a | 201 | struct parse *cfile; |
7dfc8ac2 TL |
202 | struct group *group; |
203 | int type; | |
204 | struct host_decl *host_decl; | |
2d59f590 | 205 | int declaration; |
d7837182 | 206 | { |
6f8fb41f | 207 | enum dhcp_token token; |
b1b7b521 | 208 | const char *val; |
7dfc8ac2 | 209 | struct shared_network *share; |
7dfc8ac2 | 210 | char *t, *n; |
ece6ea33 TL |
211 | struct expression *expr; |
212 | struct data_string data; | |
7dfc8ac2 | 213 | struct hardware hardware; |
ece6ea33 TL |
214 | struct executable_statement *et, *ep; |
215 | struct option *option; | |
216 | struct option_cache *cache; | |
217 | int lose; | |
74f45f96 | 218 | struct data_string key_id; |
b1b7b521 | 219 | int known; |
20916cae | 220 | isc_result_t status; |
d7837182 | 221 | |
e68de775 TL |
222 | token = peek_token (&val, cfile); |
223 | ||
224 | switch (token) { | |
20916cae TL |
225 | case INCLUDE: |
226 | next_token (&val, cfile); | |
227 | token = next_token (&val, cfile); | |
228 | if (token != STRING) { | |
229 | parse_warn (cfile, "filename string expected."); | |
230 | skip_to_semi (cfile); | |
231 | } else { | |
232 | status = parse_conf_file (val, group, type); | |
233 | if (status != ISC_R_SUCCESS) | |
234 | parse_warn (cfile, "%s: bad parse.", val); | |
235 | parse_semi (cfile); | |
236 | } | |
237 | return 1; | |
238 | ||
d7837182 | 239 | case HOST: |
ece6ea33 TL |
240 | next_token (&val, cfile); |
241 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 242 | parse_host_declaration (cfile, group); |
7dfc8ac2 | 243 | else { |
35454d8a TL |
244 | parse_warn (cfile, |
245 | "host declarations not allowed here."); | |
7dfc8ac2 | 246 | skip_to_semi (cfile); |
d7837182 | 247 | } |
7dfc8ac2 TL |
248 | return 1; |
249 | ||
250 | case GROUP: | |
ece6ea33 TL |
251 | next_token (&val, cfile); |
252 | if (type != HOST_DECL && type != CLASS_DECL) | |
2d59f590 | 253 | parse_group_declaration (cfile, group); |
7dfc8ac2 | 254 | else { |
35454d8a TL |
255 | parse_warn (cfile, |
256 | "group declarations not allowed here."); | |
7dfc8ac2 | 257 | skip_to_semi (cfile); |
d7837182 | 258 | } |
7dfc8ac2 TL |
259 | return 1; |
260 | ||
d7837182 | 261 | case TIMESTAMP: |
ece6ea33 | 262 | next_token (&val, cfile); |
7dfc8ac2 | 263 | parsed_time = parse_timestamp (cfile); |
d7837182 | 264 | break; |
7dfc8ac2 | 265 | |
1f814ff2 | 266 | case SHARED_NETWORK: |
ece6ea33 | 267 | next_token (&val, cfile); |
2d59f590 TL |
268 | if (type == SHARED_NET_DECL || |
269 | type == HOST_DECL || | |
ece6ea33 TL |
270 | type == SUBNET_DECL || |
271 | type == CLASS_DECL) { | |
35454d8a | 272 | parse_warn (cfile, "shared-network parameters not %s.", |
7dfc8ac2 TL |
273 | "allowed here"); |
274 | skip_to_semi (cfile); | |
275 | break; | |
1f814ff2 | 276 | } |
7dfc8ac2 | 277 | |
2d59f590 | 278 | parse_shared_net_declaration (cfile, group); |
7dfc8ac2 TL |
279 | return 1; |
280 | ||
685963dc | 281 | case SUBNET: |
ece6ea33 TL |
282 | next_token (&val, cfile); |
283 | if (type == HOST_DECL || type == SUBNET_DECL || | |
284 | type == CLASS_DECL) { | |
35454d8a TL |
285 | parse_warn (cfile, |
286 | "subnet declarations not allowed here."); | |
7dfc8ac2 TL |
287 | skip_to_semi (cfile); |
288 | return 1; | |
289 | } | |
290 | ||
2d59f590 | 291 | /* If we're in a subnet declaration, just do the parse. */ |
7dfc8ac2 | 292 | if (group -> shared_network) { |
2d59f590 TL |
293 | parse_subnet_declaration (cfile, |
294 | group -> shared_network); | |
7dfc8ac2 TL |
295 | break; |
296 | } | |
297 | ||
298 | /* Otherwise, cons up a fake shared network structure | |
299 | and populate it with the lone subnet... */ | |
300 | ||
20916cae TL |
301 | share = (struct shared_network *)0; |
302 | status = shared_network_allocate (&share, MDL); | |
303 | if (status != ISC_R_SUCCESS) | |
304 | log_fatal ("Can't allocate shared subnet: %s", | |
305 | isc_result_totext (status)); | |
306 | if (!clone_group (&share -> group, group, MDL)) | |
f84d544b | 307 | log_fatal ("Can't allocate group for shared net"); |
6ceb9118 TL |
308 | shared_network_reference (&share -> group -> shared_network, |
309 | share, MDL); | |
7dfc8ac2 | 310 | |
2d59f590 | 311 | parse_subnet_declaration (cfile, share); |
763adef1 TL |
312 | |
313 | /* share -> subnets is the subnet we just parsed. */ | |
7dfc8ac2 | 314 | if (share -> subnets) { |
20916cae TL |
315 | interface_reference (&share -> interface, |
316 | share -> subnets -> interface, | |
317 | MDL); | |
7dfc8ac2 | 318 | |
763adef1 | 319 | /* Make the shared network name from network number. */ |
7dfc8ac2 | 320 | n = piaddr (share -> subnets -> net); |
436f1c8c | 321 | t = dmalloc (strlen (n) + 1, MDL); |
1f814ff2 | 322 | if (!t) |
8ae2d595 | 323 | log_fatal ("no memory for subnet name"); |
1f814ff2 TL |
324 | strcpy (t, n); |
325 | share -> name = t; | |
763adef1 TL |
326 | |
327 | /* Copy the authoritative parameter from the subnet, | |
328 | since there is no opportunity to declare it here. */ | |
329 | share -> group -> authoritative = | |
330 | share -> subnets -> group -> authoritative; | |
1f814ff2 | 331 | enter_shared_network (share); |
d7837182 | 332 | } |
7dfc8ac2 TL |
333 | return 1; |
334 | ||
24a75c03 | 335 | case VENDOR_CLASS: |
ece6ea33 TL |
336 | next_token (&val, cfile); |
337 | if (type == CLASS_DECL) { | |
35454d8a TL |
338 | parse_warn (cfile, |
339 | "class declarations not allowed here."); | |
ece6ea33 TL |
340 | skip_to_semi (cfile); |
341 | break; | |
342 | } | |
20916cae | 343 | parse_class_declaration ((struct class **)0, cfile, group, 0); |
7dfc8ac2 TL |
344 | return 1; |
345 | ||
24a75c03 | 346 | case USER_CLASS: |
ece6ea33 TL |
347 | next_token (&val, cfile); |
348 | if (type == CLASS_DECL) { | |
35454d8a TL |
349 | parse_warn (cfile, |
350 | "class declarations not allowed here."); | |
ece6ea33 TL |
351 | skip_to_semi (cfile); |
352 | break; | |
353 | } | |
20916cae | 354 | parse_class_declaration ((struct class **)0, cfile, group, 1); |
7dfc8ac2 | 355 | return 1; |
1f814ff2 | 356 | |
ece6ea33 TL |
357 | case CLASS: |
358 | next_token (&val, cfile); | |
359 | if (type == CLASS_DECL) { | |
35454d8a TL |
360 | parse_warn (cfile, |
361 | "class declarations not allowed here."); | |
59b85ebd | 362 | skip_to_semi (cfile); |
ece6ea33 | 363 | break; |
59b85ebd | 364 | } |
20916cae | 365 | parse_class_declaration ((struct class **)0, cfile, group, 2); |
ece6ea33 | 366 | return 1; |
59b85ebd | 367 | |
ece6ea33 TL |
368 | case SUBCLASS: |
369 | next_token (&val, cfile); | |
370 | if (type == CLASS_DECL) { | |
35454d8a TL |
371 | parse_warn (cfile, |
372 | "class declarations not allowed here."); | |
ece6ea33 | 373 | skip_to_semi (cfile); |
7dfc8ac2 | 374 | break; |
7dfc8ac2 | 375 | } |
20916cae | 376 | parse_class_declaration ((struct class **)0, cfile, group, 3); |
ece6ea33 | 377 | return 1; |
7dfc8ac2 TL |
378 | |
379 | case HARDWARE: | |
ece6ea33 | 380 | next_token (&val, cfile); |
2d59f590 | 381 | parse_hardware_param (cfile, &hardware); |
7dfc8ac2 TL |
382 | if (host_decl) |
383 | host_decl -> interface = hardware; | |
384 | else | |
35454d8a | 385 | parse_warn (cfile, "hardware address parameter %s", |
7dfc8ac2 TL |
386 | "not allowed here."); |
387 | break; | |
388 | ||
389 | case FIXED_ADDR: | |
ece6ea33 | 390 | next_token (&val, cfile); |
6f8fb41f | 391 | cache = (struct option_cache *)0; |
20916cae TL |
392 | if (parse_fixed_addr_param (&cache, cfile)) { |
393 | if (host_decl) | |
394 | host_decl -> fixed_addr = cache; | |
395 | else { | |
396 | parse_warn (cfile, | |
397 | "fixed-address parameter not %s", | |
398 | "allowed here."); | |
399 | option_cache_dereference (&cache, MDL); | |
400 | } | |
6f8fb41f | 401 | } |
7dfc8ac2 TL |
402 | break; |
403 | ||
f63b4929 TL |
404 | case POOL: |
405 | next_token (&val, cfile); | |
406 | if (type != SUBNET_DECL && type != SHARED_NET_DECL) { | |
35454d8a | 407 | parse_warn (cfile, "pool declared outside of network"); |
f63b4929 | 408 | } |
74f45f96 | 409 | if (type == POOL_DECL) { |
35454d8a | 410 | parse_warn (cfile, "pool declared within pool."); |
74f45f96 | 411 | } |
f63b4929 TL |
412 | parse_pool_statement (cfile, group, type); |
413 | return declaration; | |
414 | ||
7dfc8ac2 | 415 | case RANGE: |
ece6ea33 | 416 | next_token (&val, cfile); |
2d59f590 | 417 | if (type != SUBNET_DECL || !group -> subnet) { |
35454d8a TL |
418 | parse_warn (cfile, |
419 | "range declaration not allowed here."); | |
7dfc8ac2 | 420 | skip_to_semi (cfile); |
2d59f590 | 421 | return declaration; |
7dfc8ac2 | 422 | } |
f63b4929 | 423 | parse_address_range (cfile, group, type, (struct pool *)0); |
2d59f590 | 424 | return declaration; |
7dfc8ac2 | 425 | |
763adef1 | 426 | case TOKEN_NOT: |
1b8223ae | 427 | token = next_token (&val, cfile); |
763adef1 TL |
428 | token = next_token (&val, cfile); |
429 | switch (token) { | |
430 | case AUTHORITATIVE: | |
431 | group -> authoritative = 0; | |
432 | goto authoritative; | |
433 | default: | |
35454d8a | 434 | parse_warn (cfile, "expecting assertion"); |
763adef1 TL |
435 | skip_to_semi (cfile); |
436 | break; | |
437 | } | |
438 | break; | |
439 | case AUTHORITATIVE: | |
1b8223ae | 440 | token = next_token (&val, cfile); |
763adef1 TL |
441 | group -> authoritative = 1; |
442 | authoritative: | |
1b8223ae | 443 | if (type == HOST_DECL) |
35454d8a | 444 | parse_warn (cfile, "authority makes no sense here."); |
763adef1 TL |
445 | parse_semi (cfile); |
446 | break; | |
447 | ||
8230a054 TL |
448 | /* "server-identifier" is a special hack, equivalent to |
449 | "option dhcp-server-identifier". */ | |
450 | case SERVER_IDENTIFIER: | |
451 | option = dhcp_universe.options [DHO_DHCP_SERVER_IDENTIFIER]; | |
452 | token = next_token (&val, cfile); | |
453 | goto finish_option; | |
454 | ||
6f8fb41f TL |
455 | case OPTION: |
456 | token = next_token (&val, cfile); | |
822d95c9 TL |
457 | token = peek_token (&val, cfile); |
458 | if (token == SPACE) { | |
459 | if (type != ROOT_GROUP) { | |
35454d8a TL |
460 | parse_warn (cfile, |
461 | "option space definitions %s", | |
436f1c8c | 462 | "may not be scoped."); |
822d95c9 | 463 | skip_to_semi (cfile); |
822d95c9 TL |
464 | break; |
465 | } | |
466 | parse_option_space_decl (cfile); | |
467 | return declaration; | |
468 | } | |
469 | ||
b1b7b521 TL |
470 | known = 0; |
471 | option = parse_option_name (cfile, 1, &known); | |
6f8fb41f | 472 | if (option) { |
8230a054 TL |
473 | token = peek_token (&val, cfile); |
474 | if (token == CODE) { | |
475 | if (type != ROOT_GROUP) { | |
35454d8a | 476 | parse_warn (cfile, |
ab58ff49 | 477 | "option definitions%s", |
822d95c9 | 478 | " may not be scoped."); |
8230a054 | 479 | skip_to_semi (cfile); |
436f1c8c | 480 | free_option (option, MDL); |
8230a054 TL |
481 | break; |
482 | } | |
483 | next_token (&val, cfile); | |
484 | if (!parse_option_code_definition (cfile, | |
485 | option)) | |
436f1c8c | 486 | free_option (option, MDL); |
8230a054 TL |
487 | return declaration; |
488 | } | |
489 | ||
490 | /* If this wasn't an option code definition, don't | |
491 | allow an unknown option. */ | |
b1b7b521 | 492 | if (!known) { |
35454d8a | 493 | parse_warn (cfile, "unknown option %s.%s", |
8230a054 TL |
494 | option -> universe -> name, |
495 | option -> name); | |
496 | skip_to_semi (cfile); | |
436f1c8c | 497 | free_option (option, MDL); |
8230a054 TL |
498 | return declaration; |
499 | } | |
500 | ||
501 | finish_option: | |
79a65726 TL |
502 | et = (struct executable_statement *)0; |
503 | if (!parse_option_statement | |
504 | (&et, cfile, 1, option, | |
505 | supersede_option_statement)) | |
6f8fb41f TL |
506 | return declaration; |
507 | goto insert_statement; | |
508 | } else | |
509 | return declaration; | |
510 | ||
511 | break; | |
512 | ||
763adef1 | 513 | case FAILOVER: |
9e9b2261 TL |
514 | if (type != ROOT_GROUP && type != SHARED_NETWORK) { |
515 | parse_warn (cfile, "failover peers may only be %s", | |
516 | "defined in shared-network"); | |
517 | log_error ("declarations and the outer scope."); | |
518 | skip_to_semi (cfile); | |
519 | break; | |
520 | } | |
521 | token = next_token (&val, cfile); | |
22009f79 | 522 | #if defined (FAILOVER_PROTOCOL) |
763adef1 | 523 | parse_failover_peer (cfile, group, type); |
22009f79 TL |
524 | #else |
525 | parse_warn (cfile, "No failover support."); | |
526 | skip_to_semi (cfile); | |
763adef1 | 527 | #endif |
22009f79 | 528 | break; |
763adef1 | 529 | |
d7837182 | 530 | default: |
ece6ea33 | 531 | et = (struct executable_statement *)0; |
588af269 TL |
532 | lose = 0; |
533 | if (!parse_executable_statement (&et, cfile, &lose, | |
534 | context_any)) { | |
535 | if (!lose) { | |
536 | if (declaration) | |
35454d8a TL |
537 | parse_warn (cfile, |
538 | "expecting a declaration"); | |
588af269 | 539 | else |
35454d8a | 540 | parse_warn (cfile, |
ab58ff49 | 541 | "expecting a parameter %s", |
35454d8a | 542 | "or declaration"); |
588af269 | 543 | skip_to_semi (cfile); |
ece6ea33 | 544 | } |
ece6ea33 TL |
545 | return declaration; |
546 | } | |
026975bb TL |
547 | if (!et) |
548 | return declaration; | |
ece6ea33 TL |
549 | insert_statement: |
550 | if (group -> statements) { | |
79a65726 TL |
551 | int multi = 0; |
552 | ||
553 | /* If this set of statements is only referenced | |
554 | by this group, just add the current statement | |
555 | to the end of the chain. */ | |
ece6ea33 TL |
556 | for (ep = group -> statements; ep -> next; |
557 | ep = ep -> next) | |
79a65726 TL |
558 | if (ep -> refcnt > 1) /* XXX */ |
559 | multi = 1; | |
560 | if (!multi) { | |
436f1c8c TL |
561 | executable_statement_reference (&ep -> next, |
562 | et, MDL); | |
79a65726 TL |
563 | return declaration; |
564 | } | |
ece6ea33 | 565 | |
79a65726 TL |
566 | /* Otherwise, make a parent chain, and put the |
567 | current group statements first and the new | |
568 | statement in the next pointer. */ | |
569 | ep = (struct executable_statement *)0; | |
436f1c8c | 570 | if (!executable_statement_allocate (&ep, MDL)) |
79a65726 TL |
571 | log_fatal ("No memory for statements."); |
572 | ep -> op = statements_statement; | |
436f1c8c TL |
573 | executable_statement_reference (&ep -> data.statements, |
574 | group -> statements, | |
575 | MDL); | |
576 | executable_statement_reference (&ep -> next, et, MDL); | |
577 | executable_statement_dereference (&group -> statements, | |
578 | MDL); | |
579 | executable_statement_reference (&group -> statements, | |
580 | ep, MDL); | |
6f8fb41f | 581 | } else |
436f1c8c TL |
582 | executable_statement_reference (&group -> statements, |
583 | et, MDL); | |
6f8fb41f | 584 | return declaration; |
d7837182 | 585 | } |
1f814ff2 | 586 | |
7dfc8ac2 | 587 | return 0; |
d7837182 TL |
588 | } |
589 | ||
763adef1 TL |
590 | #if defined (FAILOVER_PROTOCOL) |
591 | void parse_failover_peer (cfile, group, type) | |
35454d8a | 592 | struct parse *cfile; |
763adef1 TL |
593 | struct group *group; |
594 | int type; | |
595 | { | |
596 | enum dhcp_token token; | |
b1b7b521 | 597 | const char *val; |
9e9b2261 TL |
598 | dhcp_failover_state_t *peer; |
599 | u_int32_t *tp; | |
763adef1 | 600 | char *name; |
9e9b2261 TL |
601 | u_int32_t split; |
602 | u_int8_t hba [32]; | |
165bce70 | 603 | unsigned hba_len = sizeof hba; |
9e9b2261 TL |
604 | int i; |
605 | struct expression *expr; | |
e9623235 | 606 | isc_result_t status; |
05815916 | 607 | dhcp_failover_config_t *cp; |
763adef1 TL |
608 | |
609 | token = next_token (&val, cfile); | |
610 | if (token != PEER) { | |
9e9b2261 | 611 | parse_warn (cfile, "expecting \"peer\""); |
763adef1 TL |
612 | skip_to_semi (cfile); |
613 | return; | |
614 | } | |
615 | ||
616 | token = next_token (&val, cfile); | |
617 | if (is_identifier (token) || token == STRING) { | |
436f1c8c | 618 | name = dmalloc (strlen (val) + 1, MDL); |
9e9b2261 | 619 | if (!name) |
8ae2d595 | 620 | log_fatal ("no memory for peer name %s", name); |
9e9b2261 | 621 | strcpy (name, val); |
763adef1 | 622 | } else { |
9e9b2261 | 623 | parse_warn (cfile, "expecting failover peer name."); |
763adef1 TL |
624 | skip_to_semi (cfile); |
625 | return; | |
626 | } | |
627 | ||
628 | /* See if there's a peer declaration by this name. */ | |
9e9b2261 | 629 | peer = (dhcp_failover_state_t *)0; |
20916cae | 630 | find_failover_peer (&peer, name, MDL); |
763adef1 TL |
631 | |
632 | token = next_token (&val, cfile); | |
633 | if (token == SEMI) { | |
436f1c8c | 634 | dfree (name, MDL); |
763adef1 | 635 | if (type != SHARED_NET_DECL) |
35454d8a | 636 | parse_warn (cfile, "failover peer reference not %s", |
763adef1 TL |
637 | "in shared-network declaration"); |
638 | else { | |
639 | if (!peer) { | |
35454d8a | 640 | parse_warn (cfile, "reference to unknown%s%s", |
763adef1 TL |
641 | " failover peer ", name); |
642 | return; | |
643 | } | |
20916cae TL |
644 | dhcp_failover_state_reference |
645 | (&group -> shared_network -> failover_peer, | |
646 | peer, MDL); | |
763adef1 | 647 | } |
20916cae | 648 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 | 649 | return; |
a4ba3160 | 650 | } else if (token == STATE) { |
763adef1 | 651 | if (!peer) { |
a4ba3160 | 652 | parse_warn (cfile, "state declaration for unknown%s%s", |
763adef1 TL |
653 | " failover peer ", name); |
654 | return; | |
655 | } | |
a4ba3160 | 656 | parse_failover_state_declaration (cfile, peer); |
20916cae | 657 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
658 | return; |
659 | } else if (token != LBRACE) { | |
35454d8a | 660 | parse_warn (cfile, "expecting left brace"); |
763adef1 TL |
661 | skip_to_semi (cfile); |
662 | } | |
663 | ||
664 | /* Make sure this isn't a redeclaration. */ | |
665 | if (peer) { | |
35454d8a | 666 | parse_warn (cfile, "redeclaration of failover peer %s", name); |
763adef1 | 667 | skip_to_rbrace (cfile, 1); |
20916cae | 668 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
669 | return; |
670 | } | |
671 | ||
20916cae TL |
672 | status = dhcp_failover_state_allocate (&peer, MDL); |
673 | if (status != ISC_R_SUCCESS) | |
674 | log_fatal ("Can't allocate failover peer %s: %s", | |
675 | name, isc_result_totext (status)); | |
763adef1 TL |
676 | |
677 | /* Save the name. */ | |
678 | peer -> name = name; | |
679 | ||
a4ba3160 | 680 | /* Set the initial state. */ |
05815916 TL |
681 | peer -> me.state = potential_conflict; |
682 | peer -> me.stos = cur_time; | |
683 | peer -> partner.state = unknown_state; | |
684 | peer -> partner.stos = cur_time; | |
a4ba3160 | 685 | |
763adef1 | 686 | do { |
05815916 TL |
687 | cp = &peer -> me; |
688 | peer: | |
763adef1 TL |
689 | token = next_token (&val, cfile); |
690 | switch (token) { | |
691 | case RBRACE: | |
692 | break; | |
9e9b2261 | 693 | |
763adef1 TL |
694 | case PRIMARY: |
695 | peer -> i_am = primary; | |
696 | break; | |
9e9b2261 | 697 | |
763adef1 TL |
698 | case SECONDARY: |
699 | peer -> i_am = secondary; | |
007e3ee4 TL |
700 | if (peer -> hba) |
701 | parse_warn (cfile, | |
702 | "secondary may not define %s", | |
703 | "load balance settings."); | |
763adef1 | 704 | break; |
9e9b2261 | 705 | |
e9623235 | 706 | case PEER: |
05815916 TL |
707 | cp = &peer -> partner; |
708 | goto peer; | |
e9623235 TL |
709 | |
710 | case ADDRESS: | |
9e9b2261 TL |
711 | expr = (struct expression *)0; |
712 | if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { | |
763adef1 | 713 | skip_to_rbrace (cfile, 1); |
20916cae | 714 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
715 | return; |
716 | } | |
05815916 TL |
717 | option_cache (&cp -> address, |
718 | (struct data_string *)0, expr, | |
9e9b2261 | 719 | (struct option *)0); |
436f1c8c | 720 | expression_dereference (&expr, MDL); |
763adef1 | 721 | break; |
e9623235 | 722 | |
763adef1 TL |
723 | case PORT: |
724 | token = next_token (&val, cfile); | |
725 | if (token != NUMBER) { | |
35454d8a | 726 | parse_warn (cfile, "expecting number"); |
763adef1 TL |
727 | skip_to_rbrace (cfile, 1); |
728 | } | |
05815916 | 729 | cp -> port = atoi (val); |
763adef1 | 730 | break; |
9e9b2261 | 731 | |
763adef1 | 732 | case MAX_RESPONSE_DELAY: |
05815916 | 733 | tp = &cp -> max_response_delay; |
763adef1 TL |
734 | parse_idle: |
735 | token = next_token (&val, cfile); | |
736 | if (token != NUMBER) { | |
35454d8a | 737 | parse_warn (cfile, "expecting number."); |
763adef1 | 738 | skip_to_rbrace (cfile, 1); |
20916cae | 739 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
740 | return; |
741 | } | |
742 | *tp = atoi (val); | |
9e9b2261 TL |
743 | break; |
744 | ||
745 | case MAX_UNACKED_UPDATES: | |
05815916 | 746 | tp = &cp -> max_flying_updates; |
9e9b2261 TL |
747 | goto parse_idle; |
748 | ||
749 | case MCLT: | |
750 | tp = &peer -> mclt; | |
751 | goto parse_idle; | |
752 | ||
753 | case HBA: | |
e9623235 | 754 | hba_len = 32; |
007e3ee4 TL |
755 | if (peer -> i_am == secondary) |
756 | parse_warn (cfile, | |
757 | "secondary may not define %s", | |
758 | "load balance settings."); | |
9e9b2261 | 759 | if (!parse_numeric_aggregate (cfile, hba, &hba_len, |
e9623235 | 760 | COLON, 16, 8)) { |
9e9b2261 | 761 | skip_to_rbrace (cfile, 1); |
20916cae | 762 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
763 | return; |
764 | } | |
e9623235 TL |
765 | if (hba_len != 32) { |
766 | parse_warn (cfile, | |
767 | "HBA must be exactly 32 bytes."); | |
768 | dfree (hba, MDL); | |
769 | break; | |
770 | } | |
9e9b2261 | 771 | make_hba: |
436f1c8c | 772 | peer -> hba = dmalloc (32, MDL); |
9e9b2261 | 773 | if (!peer -> hba) { |
436f1c8c TL |
774 | dfree (peer -> name, MDL); |
775 | dfree (peer, MDL); | |
9e9b2261 TL |
776 | } |
777 | memcpy (peer -> hba, hba, 32); | |
778 | break; | |
779 | ||
780 | case SPLIT: | |
781 | token = next_token (&val, cfile); | |
007e3ee4 TL |
782 | if (peer -> i_am == secondary) |
783 | parse_warn (cfile, | |
784 | "secondary may not define %s", | |
785 | "load balance settings."); | |
9e9b2261 TL |
786 | if (token != NUMBER) { |
787 | parse_warn (cfile, "expecting number"); | |
20916cae | 788 | badsplit: |
9e9b2261 | 789 | skip_to_rbrace (cfile, 1); |
20916cae | 790 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
791 | return; |
792 | } | |
20916cae TL |
793 | split = atoi (val); |
794 | if (!parse_semi (cfile)) | |
795 | goto badsplit; | |
9e9b2261 TL |
796 | if (split > 255) { |
797 | parse_warn (cfile, "split must be < 256"); | |
798 | } else { | |
799 | memset (hba, 0, sizeof hba); | |
800 | for (i = 0; i < split; i++) { | |
801 | if (i < split) | |
802 | hba [i / 8] |= (1 << (i & 7)); | |
803 | } | |
804 | goto make_hba; | |
805 | } | |
806 | break; | |
807 | ||
e9623235 TL |
808 | case LOAD: |
809 | token = next_token (&val, cfile); | |
810 | if (token != BALANCE) { | |
811 | parse_warn (cfile, "expecting 'balance'"); | |
812 | badload: | |
813 | skip_to_rbrace (cfile, 1); | |
814 | break; | |
815 | } | |
816 | token = next_token (&val, cfile); | |
817 | if (token != TOKEN_MAX) { | |
818 | parse_warn (cfile, "expecting 'max'"); | |
819 | goto badload; | |
820 | } | |
821 | token = next_token (&val, cfile); | |
822 | if (token != SECONDS) { | |
823 | parse_warn (cfile, "expecting 'secs'"); | |
824 | goto badload; | |
825 | } | |
826 | token = next_token (&val, cfile); | |
827 | if (token != NUMBER) { | |
828 | parse_warn (cfile, "expecting number"); | |
829 | goto badload; | |
830 | } | |
831 | peer -> load_balance_max_secs = atoi (val); | |
832 | break; | |
833 | ||
763adef1 | 834 | default: |
35454d8a TL |
835 | parse_warn (cfile, |
836 | "invalid statement in peer declaration"); | |
763adef1 | 837 | skip_to_rbrace (cfile, 1); |
20916cae | 838 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
839 | return; |
840 | } | |
e9623235 TL |
841 | if (token != RBRACE && !parse_semi (cfile)) { |
842 | skip_to_rbrace (cfile, 1); | |
20916cae | 843 | dhcp_failover_state_dereference (&peer, MDL); |
e9623235 TL |
844 | return; |
845 | } | |
763adef1 TL |
846 | } while (token != RBRACE); |
847 | ||
007e3ee4 TL |
848 | if (peer -> i_am == primary && !peer -> hba) { |
849 | parse_warn (cfile, | |
850 | "primary failover server must have hba or split."); | |
851 | } | |
852 | ||
763adef1 TL |
853 | if (type == SHARED_NET_DECL) { |
854 | group -> shared_network -> failover_peer = peer; | |
855 | } | |
e9623235 TL |
856 | status = enter_failover_peer (peer); |
857 | if (status != ISC_R_SUCCESS) | |
858 | parse_warn (cfile, "failover peer %s: %s", | |
859 | peer -> name, isc_result_totext (status)); | |
20916cae | 860 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
861 | } |
862 | ||
a4ba3160 TL |
863 | void parse_failover_state_declaration (struct parse *cfile, |
864 | dhcp_failover_state_t *peer) | |
865 | { | |
866 | enum dhcp_token token; | |
867 | const char *val; | |
868 | char *name; | |
869 | dhcp_failover_state_t *state; | |
05815916 | 870 | dhcp_failover_config_t *cp; |
a4ba3160 TL |
871 | |
872 | if (!peer) { | |
873 | token = next_token (&val, cfile); | |
874 | if (token != PEER) { | |
875 | parse_warn (cfile, "expecting \"peer\""); | |
876 | skip_to_semi (cfile); | |
877 | return; | |
878 | } | |
879 | ||
880 | token = next_token (&val, cfile); | |
881 | if (is_identifier (token) || token == STRING) { | |
882 | name = dmalloc (strlen (val) + 1, MDL); | |
883 | if (!name) | |
884 | log_fatal ("failover peer name %s: no memory", | |
885 | name); | |
886 | strcpy (name, val); | |
887 | } else { | |
888 | parse_warn (cfile, "expecting failover peer name."); | |
889 | skip_to_semi (cfile); | |
890 | return; | |
891 | } | |
892 | ||
893 | /* See if there's a peer declaration by this name. */ | |
894 | state = (dhcp_failover_state_t *)0; | |
20916cae | 895 | find_failover_peer (&state, name, MDL); |
a4ba3160 TL |
896 | if (!state) { |
897 | parse_warn (cfile, "unknown failover peer: %s", name); | |
898 | skip_to_semi (cfile); | |
899 | return; | |
900 | } | |
901 | ||
902 | token = next_token (&val, cfile); | |
903 | if (token != STATE) { | |
904 | parse_warn (cfile, "expecting 'state'"); | |
905 | if (token != SEMI) | |
906 | skip_to_semi (cfile); | |
907 | return; | |
908 | } | |
20916cae TL |
909 | } else { |
910 | state = (dhcp_failover_state_t *)0; | |
911 | dhcp_failover_state_reference (&state, peer, MDL); | |
912 | } | |
a4ba3160 TL |
913 | token = next_token (&val, cfile); |
914 | if (token != LBRACE) { | |
915 | parse_warn (cfile, "expecting left brace"); | |
916 | if (token != SEMI) | |
917 | skip_to_semi (cfile); | |
20916cae | 918 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
919 | return; |
920 | } | |
921 | do { | |
922 | token = next_token (&val, cfile); | |
923 | switch (token) { | |
924 | case RBRACE: | |
925 | break; | |
926 | case MY: | |
05815916 TL |
927 | cp = &state -> me; |
928 | do_state: | |
a4ba3160 TL |
929 | token = next_token (&val, cfile); |
930 | if (token != STATE) { | |
931 | parse_warn (cfile, "expecting 'state'"); | |
20916cae | 932 | goto bogus; |
a4ba3160 TL |
933 | } |
934 | parse_failover_state (cfile, | |
05815916 | 935 | &cp -> state, &cp -> stos); |
a4ba3160 | 936 | break; |
05815916 | 937 | |
a4ba3160 | 938 | case PARTNER: |
05815916 TL |
939 | cp = &state -> partner; |
940 | goto do_state; | |
941 | ||
a4ba3160 | 942 | default: |
20916cae | 943 | bogus: |
a4ba3160 | 944 | parse_warn (cfile, "expecting state setting."); |
20916cae TL |
945 | skip_to_rbrace (cfile, 1); |
946 | dhcp_failover_state_dereference (&state, MDL); | |
a4ba3160 TL |
947 | return; |
948 | } | |
949 | } while (token != RBRACE); | |
20916cae | 950 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
951 | } |
952 | ||
9e9b2261 | 953 | void parse_failover_state (cfile, state, stos) |
35454d8a | 954 | struct parse *cfile; |
9e9b2261 TL |
955 | enum failover_state *state; |
956 | TIME *stos; | |
763adef1 TL |
957 | { |
958 | enum dhcp_token token; | |
b1b7b521 | 959 | const char *val; |
9e9b2261 TL |
960 | enum failover_state state_in; |
961 | TIME stos_in; | |
763adef1 TL |
962 | |
963 | token = next_token (&val, cfile); | |
964 | switch (token) { | |
05815916 TL |
965 | case UNKNOWN_STATE: |
966 | state_in = unknown_state; | |
967 | break; | |
968 | ||
763adef1 | 969 | case PARTNER_DOWN: |
9e9b2261 TL |
970 | state_in = partner_down; |
971 | break; | |
972 | ||
763adef1 | 973 | case NORMAL: |
9e9b2261 TL |
974 | state_in = normal; |
975 | break; | |
976 | ||
763adef1 | 977 | case COMMUNICATIONS_INTERRUPTED: |
9e9b2261 TL |
978 | state_in = communications_interrupted; |
979 | break; | |
980 | ||
9a092d2e TL |
981 | case RESOLUTION_INTERRUPTED: |
982 | state_in = resolution_interrupted; | |
a4ba3160 TL |
983 | break; |
984 | ||
05815916 TL |
985 | case POTENTIAL_CONFLICT: |
986 | state_in = potential_conflict; | |
987 | break; | |
988 | ||
763adef1 | 989 | case RECOVER: |
9e9b2261 TL |
990 | state_in = recover; |
991 | break; | |
a4ba3160 | 992 | |
05815916 TL |
993 | case RECOVER_DONE: |
994 | state_in = recover_done; | |
995 | break; | |
996 | ||
997 | case SHUTDOWN: | |
998 | state_in = shut_down; | |
999 | break; | |
1000 | ||
1001 | case PAUSED: | |
1002 | state_in = paused; | |
1003 | break; | |
1004 | ||
1005 | case STARTUP: | |
1006 | state_in = startup; | |
a4ba3160 | 1007 | break; |
9e9b2261 | 1008 | |
763adef1 | 1009 | default: |
35454d8a | 1010 | parse_warn (cfile, "unknown failover state"); |
9e9b2261 TL |
1011 | skip_to_semi (cfile); |
1012 | return; | |
763adef1 | 1013 | } |
9e9b2261 TL |
1014 | |
1015 | token = next_token (&val, cfile); | |
1016 | if (token != AT) { | |
1017 | parse_warn (cfile, "expecting \"at\""); | |
1018 | skip_to_semi (cfile); | |
1019 | return; | |
1020 | } | |
1021 | ||
1022 | stos_in = parse_date (cfile); | |
1023 | if (!stos_in) | |
1024 | return; | |
1025 | ||
1026 | /* Now that we've apparently gotten a clean parse, we can trust | |
1027 | that this is a state that was fully committed to disk, so | |
1028 | we can install it. */ | |
1029 | *stos = stos_in; | |
1030 | *state = state_in; | |
763adef1 TL |
1031 | } |
1032 | #endif /* defined (FAILOVER_PROTOCOL) */ | |
1033 | ||
f63b4929 | 1034 | void parse_pool_statement (cfile, group, type) |
35454d8a | 1035 | struct parse *cfile; |
f63b4929 TL |
1036 | struct group *group; |
1037 | int type; | |
1038 | { | |
1039 | enum dhcp_token token; | |
b1b7b521 | 1040 | const char *val; |
f63b4929 TL |
1041 | int done = 0; |
1042 | struct pool *pool, **p; | |
1043 | struct permit *permit; | |
1044 | struct permit **permit_head; | |
74f45f96 | 1045 | int declaration = 0; |
e9623235 | 1046 | isc_result_t status; |
f63b4929 | 1047 | |
20916cae TL |
1048 | pool = (struct pool *)0; |
1049 | status = pool_allocate (&pool, MDL); | |
1050 | if (status != ISC_R_SUCCESS) | |
6ceb9118 TL |
1051 | log_fatal ("no memory for pool: %s", |
1052 | isc_result_totext (status)); | |
f63b4929 | 1053 | |
f84d544b | 1054 | if (!clone_group (&pool -> group, group, MDL)) |
6ceb9118 | 1055 | log_fatal ("can't clone pool group."); |
74f45f96 | 1056 | |
9e9b2261 | 1057 | if (type == SUBNET_DECL) |
20916cae TL |
1058 | shared_network_reference (&pool -> shared_network, |
1059 | group -> subnet -> shared_network, | |
1060 | MDL); | |
9e9b2261 | 1061 | else |
20916cae TL |
1062 | shared_network_reference (&pool -> shared_network, |
1063 | group -> shared_network, MDL); | |
9e9b2261 | 1064 | |
22009f79 | 1065 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 TL |
1066 | /* Inherit the failover peer from the shared network. */ |
1067 | if (pool -> shared_network -> failover_peer) | |
20916cae TL |
1068 | dhcp_failover_state_reference |
1069 | (&pool -> failover_peer, | |
1070 | pool -> shared_network -> failover_peer, MDL); | |
22009f79 | 1071 | #endif |
9e9b2261 | 1072 | |
20916cae TL |
1073 | if (!parse_lbrace (cfile)) { |
1074 | pool_dereference (&pool, MDL); | |
f63b4929 | 1075 | return; |
20916cae TL |
1076 | } |
1077 | ||
f63b4929 | 1078 | do { |
e5e41be4 TL |
1079 | token = peek_token (&val, cfile); |
1080 | switch (token) { | |
9e9b2261 TL |
1081 | case NO: |
1082 | next_token (&val, cfile); | |
1083 | token = next_token (&val, cfile); | |
1084 | if (token != FAILOVER || | |
1085 | (token = next_token (&val, cfile)) != PEER) { | |
1086 | parse_warn (cfile, | |
1087 | "expecting \"failover peer\"."); | |
1088 | skip_to_semi (cfile); | |
1089 | continue; | |
1090 | } | |
22009f79 | 1091 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 | 1092 | if (pool -> failover_peer) |
20916cae TL |
1093 | dhcp_failover_state_dereference |
1094 | (&pool -> failover_peer, MDL); | |
22009f79 | 1095 | #endif |
9e9b2261 TL |
1096 | break; |
1097 | ||
a4ba3160 | 1098 | #if defined (FAILOVER_PROTOCOL) |
e9623235 TL |
1099 | case FAILOVER: |
1100 | next_token (&val, cfile); | |
1101 | token = next_token (&val, cfile); | |
1102 | if (token != PEER) { | |
1103 | parse_warn (cfile, "expecting 'peer'."); | |
1104 | skip_to_semi (cfile); | |
1105 | break; | |
1106 | } | |
1107 | token = next_token (&val, cfile); | |
1108 | if (token != STRING) { | |
1109 | parse_warn (cfile, "expecting string."); | |
1110 | skip_to_semi (cfile); | |
1111 | break; | |
1112 | } | |
1113 | if (pool -> failover_peer) | |
20916cae TL |
1114 | dhcp_failover_state_dereference |
1115 | (&pool -> failover_peer, MDL); | |
e9623235 | 1116 | status = find_failover_peer (&pool -> failover_peer, |
20916cae | 1117 | val, MDL); |
e9623235 TL |
1118 | if (status != ISC_R_SUCCESS) |
1119 | parse_warn (cfile, | |
1120 | "failover peer %s: %s", val, | |
1121 | isc_result_totext (status)); | |
1122 | parse_semi (cfile); | |
1123 | break; | |
a4ba3160 | 1124 | #endif |
e9623235 | 1125 | |
f63b4929 TL |
1126 | case RANGE: |
1127 | next_token (&val, cfile); | |
1128 | parse_address_range (cfile, group, type, pool); | |
1129 | break; | |
1130 | case ALLOW: | |
1131 | permit_head = &pool -> permit_list; | |
1132 | get_permit: | |
436f1c8c | 1133 | permit = new_permit (MDL); |
f63b4929 | 1134 | if (!permit) |
8ae2d595 | 1135 | log_fatal ("no memory for permit"); |
f63b4929 TL |
1136 | next_token (&val, cfile); |
1137 | token = next_token (&val, cfile); | |
1138 | switch (token) { | |
1139 | case UNKNOWN: | |
1140 | permit -> type = permit_unknown_clients; | |
1141 | get_clients: | |
1142 | if (next_token (&val, cfile) != CLIENTS) { | |
35454d8a TL |
1143 | parse_warn (cfile, |
1144 | "expecting \"clients\""); | |
f63b4929 | 1145 | skip_to_semi (cfile); |
436f1c8c | 1146 | free_permit (permit, MDL); |
f63b4929 TL |
1147 | continue; |
1148 | } | |
1149 | break; | |
1150 | ||
ad1a6484 TL |
1151 | case UNKNOWN_CLIENTS: |
1152 | permit -> type = permit_unknown_clients; | |
1153 | break; | |
1154 | ||
f63b4929 TL |
1155 | case KNOWN: |
1156 | permit -> type = permit_known_clients; | |
1157 | goto get_clients; | |
1158 | ||
1159 | case AUTHENTICATED: | |
1160 | permit -> type = permit_authenticated_clients; | |
1161 | goto get_clients; | |
1162 | ||
1163 | case UNAUTHENTICATED: | |
1164 | permit -> type = | |
1165 | permit_unauthenticated_clients; | |
1166 | goto get_clients; | |
1167 | ||
1168 | case ALL: | |
1169 | permit -> type = permit_all_clients; | |
1170 | goto get_clients; | |
1171 | break; | |
1172 | ||
1173 | case DYNAMIC: | |
1174 | permit -> type = permit_dynamic_bootp_clients; | |
007e3ee4 | 1175 | if (next_token (&val, cfile) != TOKEN_BOOTP) { |
35454d8a TL |
1176 | parse_warn (cfile, |
1177 | "expecting \"bootp\""); | |
f63b4929 | 1178 | skip_to_semi (cfile); |
436f1c8c | 1179 | free_permit (permit, MDL); |
f63b4929 TL |
1180 | continue; |
1181 | } | |
1182 | goto get_clients; | |
1183 | ||
1184 | case MEMBERS: | |
1185 | if (next_token (&val, cfile) != OF) { | |
35454d8a | 1186 | parse_warn (cfile, "expecting \"of\""); |
f63b4929 | 1187 | skip_to_semi (cfile); |
436f1c8c | 1188 | free_permit (permit, MDL); |
f63b4929 TL |
1189 | continue; |
1190 | } | |
1191 | if (next_token (&val, cfile) != STRING) { | |
35454d8a TL |
1192 | parse_warn (cfile, |
1193 | "expecting class name."); | |
f63b4929 | 1194 | skip_to_semi (cfile); |
436f1c8c | 1195 | free_permit (permit, MDL); |
f63b4929 TL |
1196 | continue; |
1197 | } | |
1198 | permit -> type = permit_class; | |
20916cae TL |
1199 | permit -> class = (struct class *)0; |
1200 | find_class (&permit -> class, val, MDL); | |
f63b4929 | 1201 | if (!permit -> class) |
35454d8a TL |
1202 | parse_warn (cfile, |
1203 | "no such class: %s", val); | |
e5e41be4 TL |
1204 | break; |
1205 | ||
f63b4929 | 1206 | default: |
35454d8a | 1207 | parse_warn (cfile, "expecting permit type."); |
f63b4929 TL |
1208 | skip_to_semi (cfile); |
1209 | break; | |
1210 | } | |
1211 | while (*permit_head) | |
1212 | permit_head = &((*permit_head) -> next); | |
1213 | *permit_head = permit; | |
74f45f96 | 1214 | parse_semi (cfile); |
f63b4929 TL |
1215 | break; |
1216 | ||
1217 | case DENY: | |
1218 | permit_head = &pool -> prohibit_list; | |
1219 | goto get_permit; | |
1220 | ||
1221 | case RBRACE: | |
1222 | next_token (&val, cfile); | |
1223 | done = 1; | |
1224 | break; | |
1225 | ||
1226 | default: | |
74f45f96 TL |
1227 | declaration = parse_statement (cfile, pool -> group, |
1228 | POOL_DECL, | |
1229 | (struct host_decl *)0, | |
1230 | declaration); | |
f63b4929 TL |
1231 | break; |
1232 | } | |
1233 | } while (!done); | |
1234 | ||
9e9b2261 TL |
1235 | #if defined (FAILOVER_PROTOCOL) |
1236 | /* We can't do failover on a pool that supports dynamic bootp, | |
1237 | because BOOTP doesn't support leases, and failover absolutely | |
1238 | depends on lease timing. */ | |
1239 | if (pool -> failover_peer) { | |
1240 | for (permit = pool -> permit_list; | |
1241 | permit; permit = permit -> next) { | |
1242 | if (permit -> type == permit_dynamic_bootp_clients || | |
1243 | permit -> type == permit_all_clients) { | |
1244 | dynamic_bootp_clash: | |
1245 | parse_warn (cfile, | |
1246 | "pools with failover peers %s", | |
1247 | "may not permit dynamic bootp."); | |
e9623235 | 1248 | log_error ("Either write a \"no failover\" %s", |
9e9b2261 TL |
1249 | "statement and use disjoint"); |
1250 | log_error ("pools, or don't permit dynamic%s", | |
e9623235 | 1251 | " bootp."); |
9e9b2261 | 1252 | log_error ("This is a protocol limitation,%s", |
e9623235 | 1253 | " not an ISC DHCP limitation, so"); |
9e9b2261 TL |
1254 | log_error ("please don't request an %s", |
1255 | "enhancement or ask why this is."); | |
1256 | goto clash_testing_done; | |
1257 | } | |
1258 | } | |
1259 | if (!pool -> permit_list) { | |
1260 | if (!pool -> prohibit_list) | |
1261 | goto dynamic_bootp_clash; | |
1262 | ||
1263 | for (permit = pool -> prohibit_list; permit; | |
1264 | permit = permit -> next) { | |
1265 | if (permit -> type == | |
1266 | permit_dynamic_bootp_clients || | |
1267 | permit -> type == permit_all_clients) | |
1268 | goto clash_testing_done; | |
1269 | } | |
1270 | } | |
1271 | } | |
1272 | clash_testing_done: | |
1273 | #endif /* FAILOVER_PROTOCOL */ | |
1274 | ||
f63b4929 TL |
1275 | p = &pool -> shared_network -> pools; |
1276 | for (; *p; p = &((*p) -> next)) | |
1277 | ; | |
20916cae TL |
1278 | pool_reference (p, pool, MDL); |
1279 | pool_dereference (&pool, MDL); | |
f63b4929 TL |
1280 | } |
1281 | ||
5376e3e9 TL |
1282 | /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ |
1283 | ||
1284 | int parse_boolean (cfile) | |
35454d8a | 1285 | struct parse *cfile; |
5376e3e9 | 1286 | { |
6f8fb41f | 1287 | enum dhcp_token token; |
b1b7b521 | 1288 | const char *val; |
5376e3e9 TL |
1289 | int rv; |
1290 | ||
1291 | token = next_token (&val, cfile); | |
1292 | if (!strcasecmp (val, "true") | |
1293 | || !strcasecmp (val, "on")) | |
b179c997 | 1294 | rv = 1; |
5376e3e9 TL |
1295 | else if (!strcasecmp (val, "false") |
1296 | || !strcasecmp (val, "off")) | |
1297 | rv = 0; | |
1298 | else { | |
35454d8a TL |
1299 | parse_warn (cfile, |
1300 | "boolean value (true/false/on/off) expected"); | |
5376e3e9 TL |
1301 | skip_to_semi (cfile); |
1302 | return 0; | |
1303 | } | |
1304 | parse_semi (cfile); | |
1305 | return rv; | |
1306 | } | |
1307 | ||
7dfc8ac2 TL |
1308 | /* Expect a left brace; if there isn't one, skip over the rest of the |
1309 | statement and return zero; otherwise, return 1. */ | |
1310 | ||
1311 | int parse_lbrace (cfile) | |
35454d8a | 1312 | struct parse *cfile; |
7dfc8ac2 | 1313 | { |
6f8fb41f | 1314 | enum dhcp_token token; |
b1b7b521 | 1315 | const char *val; |
7dfc8ac2 TL |
1316 | |
1317 | token = next_token (&val, cfile); | |
1318 | if (token != LBRACE) { | |
35454d8a | 1319 | parse_warn (cfile, "expecting left brace."); |
7dfc8ac2 TL |
1320 | skip_to_semi (cfile); |
1321 | return 0; | |
1322 | } | |
1323 | return 1; | |
d7837182 TL |
1324 | } |
1325 | ||
7dfc8ac2 | 1326 | |
2d59f590 | 1327 | /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ |
d7837182 | 1328 | |
2d59f590 | 1329 | void parse_host_declaration (cfile, group) |
35454d8a | 1330 | struct parse *cfile; |
7dfc8ac2 | 1331 | struct group *group; |
d7837182 | 1332 | { |
b1b7b521 | 1333 | const char *val; |
6f8fb41f | 1334 | enum dhcp_token token; |
7dfc8ac2 | 1335 | struct host_decl *host; |
f3c3d674 | 1336 | char *name; |
2d59f590 | 1337 | int declaration = 0; |
612fded7 | 1338 | int dynamicp = 0; |
ff129930 | 1339 | int deleted = 0; |
92ce3f81 | 1340 | isc_result_t status; |
7dfc8ac2 | 1341 | |
20916cae TL |
1342 | name = parse_host_name (cfile); |
1343 | if (!name) | |
1344 | return; | |
7dfc8ac2 | 1345 | |
20916cae TL |
1346 | host = (struct host_decl *)0; |
1347 | status = host_allocate (&host, MDL); | |
1348 | if (status != ISC_R_SUCCESS) | |
1349 | log_fatal ("can't allocate host decl struct %s: %s", | |
1350 | name, isc_result_totext (status)); | |
7dfc8ac2 | 1351 | host -> name = name; |
f84d544b TL |
1352 | if (!clone_group (&host -> group, group, MDL)) { |
1353 | log_fatal ("can't clone group for host %s", name); | |
20916cae TL |
1354 | boom: |
1355 | host_dereference (&host, MDL); | |
1356 | return; | |
1357 | } | |
7dfc8ac2 TL |
1358 | |
1359 | if (!parse_lbrace (cfile)) | |
20916cae | 1360 | goto boom; |
d7837182 | 1361 | |
d7837182 TL |
1362 | do { |
1363 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 1364 | if (token == RBRACE) { |
d7837182 TL |
1365 | token = next_token (&val, cfile); |
1366 | break; | |
1367 | } | |
5376e3e9 TL |
1368 | if (token == EOF) { |
1369 | token = next_token (&val, cfile); | |
35454d8a | 1370 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
1371 | break; |
1372 | } | |
612fded7 TL |
1373 | /* If the host declaration was created by the server, |
1374 | remember to save it. */ | |
1375 | if (token == DYNAMIC) { | |
1376 | dynamicp = 1; | |
1377 | token = next_token (&val, cfile); | |
1378 | if (!parse_semi (cfile)) | |
1379 | break; | |
1380 | continue; | |
1381 | } | |
ff129930 TL |
1382 | /* If the host declaration was created by the server, |
1383 | remember to save it. */ | |
007e3ee4 | 1384 | if (token == TOKEN_DELETED) { |
ff129930 TL |
1385 | deleted = 1; |
1386 | token = next_token (&val, cfile); | |
1387 | if (!parse_semi (cfile)) | |
1388 | break; | |
1389 | continue; | |
1390 | } | |
29c35bed TL |
1391 | |
1392 | if (token == GROUP) { | |
1393 | struct group_object *go; | |
1394 | token = next_token (&val, cfile); | |
1395 | token = next_token (&val, cfile); | |
1396 | if (token != STRING && !is_identifier (token)) { | |
35454d8a TL |
1397 | parse_warn (cfile, |
1398 | "expecting string or identifier."); | |
29c35bed TL |
1399 | skip_to_rbrace (cfile, 1); |
1400 | break; | |
1401 | } | |
20916cae TL |
1402 | go = (struct group_object *)0; |
1403 | if (!group_hash_lookup (&go, group_name_hash, | |
1404 | val, strlen (val), MDL)) { | |
35454d8a TL |
1405 | parse_warn (cfile, "unknown group %s in host %s", |
1406 | val, host -> name); | |
29c35bed TL |
1407 | } else { |
1408 | if (host -> named_group) | |
20916cae TL |
1409 | group_object_dereference |
1410 | (&host -> named_group, MDL); | |
1411 | group_object_reference (&host -> named_group, | |
1412 | go, MDL); | |
1413 | group_object_dereference (&go, MDL); | |
29c35bed TL |
1414 | } |
1415 | if (!parse_semi (cfile)) | |
1416 | break; | |
1417 | continue; | |
1418 | } | |
1419 | ||
1420 | if (token == UID) { | |
b1b7b521 | 1421 | const char *s; |
29c35bed | 1422 | unsigned char *t = 0; |
b1b7b521 | 1423 | unsigned len; |
29c35bed TL |
1424 | |
1425 | token = next_token (&val, cfile); | |
436f1c8c | 1426 | data_string_forget (&host -> client_identifier, MDL); |
29c35bed TL |
1427 | |
1428 | /* See if it's a string or a cshl. */ | |
1429 | token = peek_token (&val, cfile); | |
1430 | if (token == STRING) { | |
1431 | token = next_token (&val, cfile); | |
1432 | s = val; | |
1433 | len = strlen (val); | |
1434 | host -> client_identifier.terminated = 1; | |
1435 | } else { | |
1436 | len = 0; | |
1437 | t = parse_numeric_aggregate | |
1438 | (cfile, | |
1439 | (unsigned char *)0, &len, ':', 16, 8); | |
1440 | if (!t) { | |
35454d8a TL |
1441 | parse_warn (cfile, |
1442 | "expecting hex list."); | |
29c35bed TL |
1443 | skip_to_semi (cfile); |
1444 | } | |
b1b7b521 | 1445 | s = (const char *)t; |
29c35bed TL |
1446 | } |
1447 | if (!buffer_allocate | |
1448 | (&host -> client_identifier.buffer, | |
436f1c8c | 1449 | len + host -> client_identifier.terminated, MDL)) |
29c35bed TL |
1450 | log_fatal ("no memory for uid for host %s.", |
1451 | host -> name); | |
1452 | host -> client_identifier.data = | |
1453 | host -> client_identifier.buffer -> data; | |
1454 | host -> client_identifier.len = len; | |
b1b7b521 | 1455 | memcpy (host -> client_identifier.buffer -> data, s, |
29c35bed TL |
1456 | len + host -> client_identifier.terminated); |
1457 | if (t) | |
436f1c8c | 1458 | dfree (t, MDL); |
29c35bed TL |
1459 | |
1460 | if (!parse_semi (cfile)) | |
1461 | break; | |
1462 | continue; | |
1463 | } | |
2d59f590 TL |
1464 | declaration = parse_statement (cfile, host -> group, |
1465 | HOST_DECL, host, | |
1466 | declaration); | |
d7837182 | 1467 | } while (1); |
7dfc8ac2 | 1468 | |
ff129930 | 1469 | if (deleted) { |
20916cae TL |
1470 | struct host_decl *hp = (struct host_decl *)0; |
1471 | if (host_hash_lookup (&hp, host_name_hash, | |
1472 | (unsigned char *)host -> name, | |
1473 | strlen (host -> name), MDL)) { | |
ff129930 | 1474 | delete_host (hp, 0); |
20916cae | 1475 | host_dereference (&hp, MDL); |
ff129930 | 1476 | } |
ff129930 | 1477 | } else { |
29c35bed TL |
1478 | if (host -> named_group && host -> named_group -> group) { |
1479 | if (host -> group -> statements || | |
1480 | (host -> group -> authoritative != | |
b83bf1d1 TL |
1481 | host -> named_group -> group -> authoritative)) { |
1482 | if (host -> group -> next) | |
1483 | group_dereference (&host -> group -> next, | |
1484 | MDL); | |
20916cae TL |
1485 | group_reference (&host -> group -> next, |
1486 | host -> named_group -> group, | |
1487 | MDL); | |
b83bf1d1 | 1488 | } else { |
20916cae TL |
1489 | group_dereference (&host -> group, MDL); |
1490 | group_reference (&host -> group, | |
1491 | host -> named_group -> group, | |
1492 | MDL); | |
29c35bed TL |
1493 | } |
1494 | } | |
1495 | ||
b86799bf TL |
1496 | if (dynamicp) |
1497 | host -> flags |= HOST_DECL_DYNAMIC; | |
1498 | else | |
1499 | host -> flags |= HOST_DECL_STATIC; | |
1500 | ||
92ce3f81 TL |
1501 | status = enter_host (host, dynamicp, 0); |
1502 | if (status != ISC_R_SUCCESS) | |
ab58ff49 TL |
1503 | parse_warn (cfile, "host %s: %s", host -> name, |
1504 | isc_result_totext (status)); | |
ff129930 | 1505 | } |
20916cae | 1506 | host_dereference (&host, MDL); |
d7837182 TL |
1507 | } |
1508 | ||
2d59f590 | 1509 | /* class-declaration :== STRING LBRACE parameters declarations RBRACE |
24a75c03 TL |
1510 | */ |
1511 | ||
20916cae TL |
1512 | int parse_class_declaration (cp, cfile, group, type) |
1513 | struct class **cp; | |
35454d8a | 1514 | struct parse *cfile; |
7dfc8ac2 | 1515 | struct group *group; |
24a75c03 TL |
1516 | int type; |
1517 | { | |
b1b7b521 | 1518 | const char *val; |
6f8fb41f | 1519 | enum dhcp_token token; |
20916cae | 1520 | struct class *class = (struct class *)0, *pc = (struct class *)0; |
f4d0f440 | 1521 | int declaration = 0; |
e5e41be4 | 1522 | int lose = 0; |
ece6ea33 | 1523 | struct data_string data; |
b1b7b521 | 1524 | const char *name; |
ece6ea33 TL |
1525 | struct executable_statement *stmt = (struct executable_statement *)0; |
1526 | struct expression *expr; | |
de94ca72 | 1527 | int new = 1; |
20916cae | 1528 | isc_result_t status; |
24a75c03 TL |
1529 | |
1530 | token = next_token (&val, cfile); | |
1531 | if (token != STRING) { | |
35454d8a | 1532 | parse_warn (cfile, "Expecting class name"); |
24a75c03 | 1533 | skip_to_semi (cfile); |
20916cae | 1534 | return 0; |
24a75c03 TL |
1535 | } |
1536 | ||
ece6ea33 | 1537 | /* See if there's already a class with the specified name. */ |
20916cae | 1538 | find_class (&pc, val, MDL); |
ece6ea33 TL |
1539 | |
1540 | /* If this isn't a subclass, we're updating an existing class. */ | |
1541 | if (pc && type != 0 && type != 1 && type != 3) { | |
20916cae | 1542 | class_reference (&class, pc, MDL); |
de94ca72 | 1543 | new = 0; |
20916cae | 1544 | class_dereference (&pc, MDL); |
ece6ea33 TL |
1545 | } |
1546 | ||
1547 | /* If this _is_ a subclass, there _must_ be a class with the | |
1548 | same name. */ | |
1549 | if (!pc && (type == 0 || type == 1 || type == 3)) { | |
35454d8a | 1550 | parse_warn (cfile, "no class named %s", val); |
ece6ea33 | 1551 | skip_to_semi (cfile); |
20916cae | 1552 | return 0; |
ece6ea33 TL |
1553 | } |
1554 | ||
1555 | /* The old vendor-class and user-class declarations had an implicit | |
1556 | match. We don't do the implicit match anymore. Instead, for | |
1557 | backward compatibility, we have an implicit-vendor-class and an | |
1558 | implicit-user-class. vendor-class and user-class declarations | |
1559 | are turned into subclasses of the implicit classes, and the | |
8b500185 | 1560 | submatch expression of the implicit classes extracts the contents of |
ece6ea33 TL |
1561 | the vendor class or user class. */ |
1562 | if (type == 0 || type == 1) { | |
1563 | data.len = strlen (val); | |
6f8fb41f | 1564 | data.buffer = (struct buffer *)0; |
436f1c8c | 1565 | if (!buffer_allocate (&data.buffer, data.len + 1, MDL)) |
20916cae | 1566 | log_fatal ("no memory for class name."); |
6f8fb41f | 1567 | data.data = &data.buffer -> data [0]; |
ece6ea33 TL |
1568 | data.terminated = 1; |
1569 | ||
1570 | name = type ? "implicit-vendor-class" : "implicit-user-class"; | |
1571 | } else if (type == 2) { | |
20916cae TL |
1572 | name = val; |
1573 | } else { | |
1574 | name = (char *)0; | |
1575 | } | |
1576 | ||
1577 | if (name) { | |
b1b7b521 | 1578 | char *tname; |
436f1c8c | 1579 | if (!(tname = dmalloc (strlen (val) + 1, MDL))) |
8ae2d595 | 1580 | log_fatal ("No memory for class name %s.", val); |
b1b7b521 TL |
1581 | strcpy (tname, val); |
1582 | name = tname; | |
ece6ea33 TL |
1583 | } |
1584 | ||
1585 | /* If this is a straight subclass, parse the hash string. */ | |
1586 | if (type == 3) { | |
1587 | token = peek_token (&val, cfile); | |
1588 | if (token == STRING) { | |
1589 | token = next_token (&val, cfile); | |
1590 | data.len = strlen (val); | |
6f8fb41f | 1591 | data.buffer = (struct buffer *)0; |
20916cae TL |
1592 | if (!buffer_allocate (&data.buffer, |
1593 | data.len + 1, MDL)) { | |
1594 | if (pc) | |
1595 | class_dereference (&pc, MDL); | |
1596 | ||
1597 | return 0; | |
1598 | } | |
ece6ea33 | 1599 | data.terminated = 1; |
6f8fb41f | 1600 | data.data = &data.buffer -> data [0]; |
b1b7b521 | 1601 | strcpy ((char *)data.buffer -> data, val); |
ece6ea33 | 1602 | } else if (token == NUMBER_OR_NAME || token == NUMBER) { |
6f8fb41f | 1603 | memset (&data, 0, sizeof data); |
20916cae TL |
1604 | if (!parse_cshl (&data, cfile)) { |
1605 | class_dereference (&pc, MDL); | |
20916cae | 1606 | return 0; |
b19f2e1c | 1607 | } |
e68de775 | 1608 | } else { |
35454d8a | 1609 | parse_warn (cfile, "Expecting string or hex list."); |
20916cae TL |
1610 | class_dereference (&pc, MDL); |
1611 | return 0; | |
ece6ea33 TL |
1612 | } |
1613 | } | |
1614 | ||
1615 | /* See if there's already a class in the hash table matching the | |
1616 | hash data. */ | |
1617 | if (type == 0 || type == 1 || type == 3) | |
20916cae TL |
1618 | class_hash_lookup (&class, pc -> hash, |
1619 | (const char *)data.data, data.len, MDL); | |
ece6ea33 TL |
1620 | |
1621 | /* If we didn't find an existing class, allocate a new one. */ | |
1622 | if (!class) { | |
1623 | /* Allocate the class structure... */ | |
20916cae | 1624 | status = class_allocate (&class, MDL); |
ece6ea33 | 1625 | if (pc) { |
20916cae TL |
1626 | group_reference (&class -> group, pc -> group, MDL); |
1627 | class_reference (&class -> superclass, pc, MDL); | |
88dcab62 TL |
1628 | class -> lease_limit = pc -> lease_limit; |
1629 | if (class -> lease_limit) { | |
1630 | class -> billed_leases = | |
1631 | dmalloc (class -> lease_limit * | |
436f1c8c | 1632 | sizeof (struct lease *), MDL); |
88dcab62 | 1633 | if (!class -> billed_leases) |
e68de775 | 1634 | log_fatal ("no memory for billing"); |
88dcab62 TL |
1635 | memset (class -> billed_leases, 0, |
1636 | (class -> lease_limit * | |
1637 | sizeof class -> billed_leases)); | |
1638 | } | |
436f1c8c | 1639 | data_string_copy (&class -> hash_string, &data, MDL); |
88dcab62 | 1640 | if (!pc -> hash) |
20916cae TL |
1641 | pc -> hash = |
1642 | new_hash ((hash_reference) | |
1643 | omapi_object_reference, | |
1644 | (hash_dereference) | |
1645 | omapi_object_dereference, 0); | |
ece6ea33 | 1646 | add_hash (pc -> hash, |
88dcab62 TL |
1647 | class -> hash_string.data, |
1648 | class -> hash_string.len, | |
20916cae | 1649 | (void *)class, MDL); |
ece6ea33 | 1650 | } else { |
20916cae TL |
1651 | if (!clone_group (&class -> group, group, MDL)) |
1652 | log_fatal ("no memory to clone class group."); | |
ece6ea33 TL |
1653 | } |
1654 | ||
1655 | /* If this is an implicit vendor or user class, add a | |
1656 | statement that causes the vendor or user class ID to | |
1657 | be sent back in the reply. */ | |
1658 | if (type == 0 || type == 1) { | |
20916cae TL |
1659 | stmt = (struct executable_statement *)0; |
1660 | if (!executable_statement_allocate (&stmt, MDL)) | |
8ae2d595 | 1661 | log_fatal ("no memory for class statement."); |
ece6ea33 | 1662 | stmt -> op = supersede_option_statement; |
6f8fb41f | 1663 | if (option_cache_allocate (&stmt -> data.option, |
436f1c8c | 1664 | MDL)) { |
6f8fb41f TL |
1665 | stmt -> data.option -> data = data; |
1666 | stmt -> data.option -> option = | |
1667 | dhcp_universe.options | |
1668 | [type | |
ca3a51a5 TL |
1669 | ? DHO_VENDOR_CLASS_IDENTIFIER |
1670 | : DHO_USER_CLASS]; | |
6f8fb41f | 1671 | } |
ece6ea33 TL |
1672 | class -> statements = stmt; |
1673 | } | |
de94ca72 TL |
1674 | |
1675 | /* Save the name, if there is one. */ | |
1676 | class -> name = name; | |
ece6ea33 | 1677 | } |
7dfc8ac2 | 1678 | |
88dcab62 | 1679 | if (type == 0 || type == 1 || type == 3) |
436f1c8c | 1680 | data_string_forget (&data, MDL); |
88dcab62 | 1681 | |
20916cae | 1682 | /* Spawned classes don't have to have their own settings. */ |
88dcab62 | 1683 | if (class -> superclass) { |
e68de775 TL |
1684 | token = peek_token (&val, cfile); |
1685 | if (token == SEMI) { | |
1686 | next_token (&val, cfile); | |
20916cae TL |
1687 | if (cp) |
1688 | status = class_reference (cp, class, MDL); | |
1689 | class_dereference (&class, MDL); | |
1690 | return cp ? (status == ISC_R_SUCCESS) : 1; | |
e68de775 TL |
1691 | } |
1692 | /* Give the subclass its own group. */ | |
f84d544b TL |
1693 | if (!clone_group (&class -> group, class -> group, MDL)) |
1694 | log_fatal ("can't clone class group."); | |
1695 | ||
88dcab62 TL |
1696 | } |
1697 | ||
20916cae TL |
1698 | if (!parse_lbrace (cfile)) { |
1699 | class_dereference (&class, MDL); | |
1700 | if (pc) | |
1701 | class_dereference (&pc, MDL); | |
1702 | return 0; | |
1703 | } | |
24a75c03 TL |
1704 | |
1705 | do { | |
1706 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 1707 | if (token == RBRACE) { |
24a75c03 TL |
1708 | token = next_token (&val, cfile); |
1709 | break; | |
5376e3e9 TL |
1710 | } else if (token == EOF) { |
1711 | token = next_token (&val, cfile); | |
35454d8a | 1712 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1713 | break; |
ece6ea33 TL |
1714 | } else if (token == MATCH) { |
1715 | if (pc) { | |
35454d8a TL |
1716 | parse_warn (cfile, |
1717 | "invalid match in subclass."); | |
ece6ea33 TL |
1718 | skip_to_semi (cfile); |
1719 | break; | |
1720 | } | |
1721 | if (class -> expr) { | |
35454d8a | 1722 | parse_warn (cfile, "can't override match."); |
ece6ea33 TL |
1723 | skip_to_semi (cfile); |
1724 | break; | |
1725 | } | |
1726 | token = next_token (&val, cfile); | |
e68de775 | 1727 | token = peek_token (&val, cfile); |
8b500185 TL |
1728 | if (token != IF) |
1729 | goto submatch; | |
e68de775 | 1730 | token = next_token (&val, cfile); |
6f8fb41f TL |
1731 | parse_boolean_expression (&class -> expr, cfile, |
1732 | &lose); | |
ece6ea33 TL |
1733 | if (lose) |
1734 | break; | |
6f8fb41f TL |
1735 | #if defined (DEBUG_EXPRESSION_PARSE) |
1736 | print_expression ("class match", class -> expr); | |
1737 | #endif | |
de94ca72 | 1738 | parse_semi (cfile); |
ece6ea33 TL |
1739 | } else if (token == SPAWN) { |
1740 | if (pc) { | |
35454d8a TL |
1741 | parse_warn (cfile, |
1742 | "invalid spawn in subclass."); | |
ece6ea33 TL |
1743 | skip_to_semi (cfile); |
1744 | break; | |
1745 | } | |
ece6ea33 | 1746 | token = next_token (&val, cfile); |
b19f2e1c | 1747 | class -> spawning = 1; |
ece6ea33 TL |
1748 | token = next_token (&val, cfile); |
1749 | if (token != WITH) { | |
35454d8a TL |
1750 | parse_warn (cfile, |
1751 | "expecting with after spawn"); | |
ece6ea33 TL |
1752 | skip_to_semi (cfile); |
1753 | break; | |
1754 | } | |
06d3e394 | 1755 | submatch: |
8b500185 | 1756 | if (class -> submatch) { |
35454d8a TL |
1757 | parse_warn (cfile, |
1758 | "can't override existing %s.", | |
8b500185 TL |
1759 | "submatch/spawn"); |
1760 | skip_to_semi (cfile); | |
1761 | break; | |
1762 | } | |
1763 | parse_data_expression (&class -> submatch, | |
1764 | cfile, &lose); | |
ece6ea33 TL |
1765 | if (lose) |
1766 | break; | |
6f8fb41f | 1767 | #if defined (DEBUG_EXPRESSION_PARSE) |
8b500185 TL |
1768 | print_expression ("class submatch", |
1769 | class -> submatch); | |
6f8fb41f | 1770 | #endif |
de94ca72 | 1771 | parse_semi (cfile); |
88dcab62 TL |
1772 | } else if (token == LEASE) { |
1773 | next_token (&val, cfile); | |
1774 | token = next_token (&val, cfile); | |
1775 | if (token != LIMIT) { | |
35454d8a | 1776 | parse_warn (cfile, "expecting \"limit\""); |
88dcab62 TL |
1777 | if (token != SEMI) |
1778 | skip_to_semi (cfile); | |
1779 | break; | |
1780 | } | |
1781 | token = next_token (&val, cfile); | |
1782 | if (token != NUMBER) { | |
35454d8a | 1783 | parse_warn (cfile, "expecting a number"); |
88dcab62 TL |
1784 | if (token != SEMI) |
1785 | skip_to_semi (cfile); | |
1786 | break; | |
1787 | } | |
1788 | class -> lease_limit = atoi (val); | |
1789 | class -> billed_leases = | |
1790 | dmalloc (class -> lease_limit * | |
436f1c8c | 1791 | sizeof (struct lease *), MDL); |
88dcab62 | 1792 | if (!class -> billed_leases) |
8ae2d595 | 1793 | log_fatal ("no memory for billed leases."); |
88dcab62 TL |
1794 | memset (class -> billed_leases, 0, |
1795 | (class -> lease_limit * | |
1796 | sizeof class -> billed_leases)); | |
1797 | have_billing_classes = 1; | |
1798 | parse_semi (cfile); | |
24a75c03 | 1799 | } else { |
2d59f590 TL |
1800 | declaration = parse_statement (cfile, class -> group, |
1801 | CLASS_DECL, | |
1802 | (struct host_decl *)0, | |
1803 | declaration); | |
24a75c03 TL |
1804 | } |
1805 | } while (1); | |
de94ca72 TL |
1806 | if (type == 2 && new) { |
1807 | if (!collections -> classes) | |
20916cae | 1808 | class_reference (&collections -> classes, class, MDL); |
de94ca72 | 1809 | else { |
20916cae TL |
1810 | struct class *c; |
1811 | for (c = collections -> classes; | |
1812 | c -> nic; c = c -> nic) | |
de94ca72 | 1813 | ; |
20916cae | 1814 | class_reference (&c -> nic, class, MDL); |
de94ca72 TL |
1815 | } |
1816 | } | |
20916cae TL |
1817 | if (cp) |
1818 | status = class_reference (cp, class, MDL); | |
1819 | class_dereference (&class, MDL); | |
1820 | if (pc) | |
1821 | class_dereference (&pc, MDL); | |
1822 | return cp ? (status == ISC_R_SUCCESS) : 1; | |
24a75c03 TL |
1823 | } |
1824 | ||
2d59f590 TL |
1825 | /* shared-network-declaration :== |
1826 | hostname LBRACE declarations parameters RBRACE */ | |
1f814ff2 | 1827 | |
2d59f590 | 1828 | void parse_shared_net_declaration (cfile, group) |
35454d8a | 1829 | struct parse *cfile; |
7dfc8ac2 | 1830 | struct group *group; |
1f814ff2 | 1831 | { |
b1b7b521 | 1832 | const char *val; |
6f8fb41f | 1833 | enum dhcp_token token; |
1f814ff2 | 1834 | struct shared_network *share; |
1f814ff2 | 1835 | char *name; |
2d59f590 | 1836 | int declaration = 0; |
20916cae | 1837 | isc_result_t status; |
1f814ff2 | 1838 | |
20916cae TL |
1839 | share = (struct shared_network *)0; |
1840 | status = shared_network_allocate (&share, MDL); | |
1841 | if (status != ISC_R_SUCCESS) | |
1842 | log_fatal ("Can't allocate shared subnet: %s", | |
1843 | isc_result_totext (status)); | |
1844 | clone_group (&share -> group, group, MDL); | |
1845 | shared_network_reference (&share -> group -> shared_network, | |
1846 | share, MDL); | |
1f814ff2 TL |
1847 | |
1848 | /* Get the name of the shared network... */ | |
7dfc8ac2 TL |
1849 | token = peek_token (&val, cfile); |
1850 | if (token == STRING) { | |
1851 | token = next_token (&val, cfile); | |
1852 | ||
1853 | if (val [0] == 0) { | |
35454d8a | 1854 | parse_warn (cfile, "zero-length shared network name"); |
7dfc8ac2 TL |
1855 | val = "<no-name-given>"; |
1856 | } | |
436f1c8c | 1857 | name = dmalloc (strlen (val) + 1, MDL); |
7dfc8ac2 | 1858 | if (!name) |
8ae2d595 | 1859 | log_fatal ("no memory for shared network name"); |
7dfc8ac2 TL |
1860 | strcpy (name, val); |
1861 | } else { | |
1862 | name = parse_host_name (cfile); | |
20916cae TL |
1863 | if (!name) { |
1864 | shared_network_dereference (&share, MDL); | |
7dfc8ac2 | 1865 | return; |
20916cae | 1866 | } |
1f814ff2 | 1867 | } |
1f814ff2 TL |
1868 | share -> name = name; |
1869 | ||
20916cae TL |
1870 | if (!parse_lbrace (cfile)) { |
1871 | shared_network_dereference (&share, MDL); | |
7dfc8ac2 | 1872 | return; |
20916cae | 1873 | } |
7dfc8ac2 | 1874 | |
1f814ff2 | 1875 | do { |
7dfc8ac2 TL |
1876 | token = peek_token (&val, cfile); |
1877 | if (token == RBRACE) { | |
1878 | token = next_token (&val, cfile); | |
20916cae | 1879 | if (!share -> subnets) |
4bd8800e TL |
1880 | parse_warn (cfile, |
1881 | "empty shared-network decl"); | |
20916cae TL |
1882 | else |
1883 | enter_shared_network (share); | |
1884 | shared_network_dereference (&share, MDL); | |
1f814ff2 | 1885 | return; |
5376e3e9 TL |
1886 | } else if (token == EOF) { |
1887 | token = next_token (&val, cfile); | |
35454d8a | 1888 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1889 | break; |
79931db3 TL |
1890 | } else if (token == INTERFACE) { |
1891 | token = next_token (&val, cfile); | |
1892 | token = next_token (&val, cfile); | |
1893 | new_shared_network_interface (cfile, share, val); | |
1894 | if (!parse_semi (cfile)) | |
1895 | break; | |
1896 | continue; | |
1f814ff2 | 1897 | } |
5376e3e9 | 1898 | |
2d59f590 TL |
1899 | declaration = parse_statement (cfile, share -> group, |
1900 | SHARED_NET_DECL, | |
1901 | (struct host_decl *)0, | |
1902 | declaration); | |
1f814ff2 | 1903 | } while (1); |
20916cae | 1904 | shared_network_dereference (&share, MDL); |
1f814ff2 TL |
1905 | } |
1906 | ||
2d59f590 TL |
1907 | /* subnet-declaration :== |
1908 | net NETMASK netmask RBRACE parameters declarations LBRACE */ | |
685963dc | 1909 | |
2d59f590 | 1910 | void parse_subnet_declaration (cfile, share) |
35454d8a | 1911 | struct parse *cfile; |
1f814ff2 | 1912 | struct shared_network *share; |
685963dc | 1913 | { |
b1b7b521 | 1914 | const char *val; |
6f8fb41f | 1915 | enum dhcp_token token; |
763adef1 | 1916 | struct subnet *subnet, *t, *u; |
7dfc8ac2 | 1917 | struct iaddr iaddr; |
685963dc | 1918 | unsigned char addr [4]; |
b1b7b521 | 1919 | unsigned len = sizeof addr; |
2d59f590 | 1920 | int declaration = 0; |
79931db3 | 1921 | struct interface_info *ip; |
20916cae | 1922 | isc_result_t status; |
685963dc | 1923 | |
20916cae TL |
1924 | subnet = (struct subnet *)0; |
1925 | status = subnet_allocate (&subnet, MDL); | |
1926 | if (status != ISC_R_SUCCESS) | |
1927 | log_fatal ("Allocation of new subnet failed: %s", | |
1928 | isc_result_totext (status)); | |
1929 | shared_network_reference (&subnet -> shared_network, share, MDL); | |
1930 | if (!clone_group (&subnet -> group, share -> group, MDL)) | |
1931 | log_fatal ("allocation of group for new subnet failed."); | |
1932 | subnet_reference (&subnet -> group -> subnet, subnet, MDL); | |
685963dc TL |
1933 | |
1934 | /* Get the network number... */ | |
20916cae TL |
1935 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
1936 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1937 | return; |
20916cae | 1938 | } |
7dfc8ac2 TL |
1939 | memcpy (iaddr.iabuf, addr, len); |
1940 | iaddr.len = len; | |
1941 | subnet -> net = iaddr; | |
685963dc TL |
1942 | |
1943 | token = next_token (&val, cfile); | |
1944 | if (token != NETMASK) { | |
35454d8a | 1945 | parse_warn (cfile, "Expecting netmask"); |
685963dc | 1946 | skip_to_semi (cfile); |
7dfc8ac2 | 1947 | return; |
685963dc TL |
1948 | } |
1949 | ||
1950 | /* Get the netmask... */ | |
20916cae TL |
1951 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
1952 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1953 | return; |
20916cae | 1954 | } |
7dfc8ac2 TL |
1955 | memcpy (iaddr.iabuf, addr, len); |
1956 | iaddr.len = len; | |
1957 | subnet -> netmask = iaddr; | |
685963dc | 1958 | |
20916cae TL |
1959 | /* Validate the network number/netmask pair. */ |
1960 | if (host_addr (subnet -> net, subnet -> netmask)) { | |
1961 | parse_warn (cfile, | |
1962 | "subnet %s: bad subnet number/mask combination.", | |
1963 | piaddr (subnet -> net)); | |
1964 | subnet_dereference (&subnet, MDL); | |
1965 | skip_to_semi (cfile); | |
1966 | return; | |
1967 | } | |
1968 | ||
685963dc TL |
1969 | enter_subnet (subnet); |
1970 | ||
20916cae TL |
1971 | if (!parse_lbrace (cfile)) { |
1972 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1973 | return; |
20916cae | 1974 | } |
7dfc8ac2 | 1975 | |
685963dc TL |
1976 | do { |
1977 | token = peek_token (&val, cfile); | |
7dfc8ac2 TL |
1978 | if (token == RBRACE) { |
1979 | token = next_token (&val, cfile); | |
685963dc | 1980 | break; |
5376e3e9 TL |
1981 | } else if (token == EOF) { |
1982 | token = next_token (&val, cfile); | |
35454d8a | 1983 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1984 | break; |
79931db3 TL |
1985 | } else if (token == INTERFACE) { |
1986 | token = next_token (&val, cfile); | |
1987 | token = next_token (&val, cfile); | |
1988 | new_shared_network_interface (cfile, share, val); | |
1989 | if (!parse_semi (cfile)) | |
1990 | break; | |
1991 | continue; | |
7dfc8ac2 | 1992 | } |
2d59f590 TL |
1993 | declaration = parse_statement (cfile, subnet -> group, |
1994 | SUBNET_DECL, | |
1995 | (struct host_decl *)0, | |
1996 | declaration); | |
685963dc | 1997 | } while (1); |
1f814ff2 | 1998 | |
6cdd0d0d | 1999 | /* Add the subnet to the list of subnets in this shared net. */ |
7dfc8ac2 | 2000 | if (!share -> subnets) |
20916cae | 2001 | subnet_reference (&share -> subnets, subnet, MDL); |
7dfc8ac2 | 2002 | else { |
763adef1 | 2003 | u = (struct subnet *)0; |
7dfc8ac2 | 2004 | for (t = share -> subnets; |
763adef1 TL |
2005 | t -> next_sibling; t = t -> next_sibling) { |
2006 | if (subnet_inner_than (subnet, t, 0)) { | |
20916cae TL |
2007 | subnet_reference (&subnet -> next_sibling, |
2008 | t, MDL); | |
2009 | if (u) { | |
2010 | subnet_dereference (&u -> next_sibling, | |
2011 | MDL); | |
2012 | subnet_reference (&u -> next_sibling, | |
2013 | subnet, MDL); | |
2014 | } else { | |
2015 | subnet_dereference (&share -> subnets, | |
2016 | MDL); | |
2017 | subnet_reference (&share -> subnets, | |
2018 | subnet, MDL); | |
2019 | } | |
2020 | subnet_dereference (&subnet, MDL); | |
763adef1 TL |
2021 | return; |
2022 | } | |
2023 | u = t; | |
2024 | } | |
20916cae | 2025 | subnet_reference (&t -> next_sibling, subnet, MDL); |
7dfc8ac2 | 2026 | } |
20916cae | 2027 | subnet_dereference (&subnet, MDL); |
685963dc TL |
2028 | } |
2029 | ||
2d59f590 | 2030 | /* group-declaration :== RBRACE parameters declarations LBRACE */ |
7dfc8ac2 | 2031 | |
2d59f590 | 2032 | void parse_group_declaration (cfile, group) |
35454d8a | 2033 | struct parse *cfile; |
7dfc8ac2 | 2034 | struct group *group; |
685963dc | 2035 | { |
b1b7b521 | 2036 | const char *val; |
6f8fb41f | 2037 | enum dhcp_token token; |
7dfc8ac2 | 2038 | struct group *g; |
2d59f590 | 2039 | int declaration = 0; |
29c35bed TL |
2040 | struct group_object *t; |
2041 | isc_result_t status; | |
d9eefc5d | 2042 | char *name = NULL; |
29c35bed TL |
2043 | int deletedp = 0; |
2044 | int dynamicp = 0; | |
2045 | int staticp = 0; | |
685963dc | 2046 | |
20916cae TL |
2047 | g = (struct group *)0; |
2048 | if (!clone_group (&g, group, MDL)) | |
2049 | log_fatal ("no memory for explicit group."); | |
685963dc | 2050 | |
29c35bed TL |
2051 | token = peek_token (&val, cfile); |
2052 | if (is_identifier (token) || token == STRING) { | |
2053 | next_token (&val, cfile); | |
2054 | ||
436f1c8c | 2055 | name = dmalloc (strlen (val) + 1, MDL); |
29c35bed TL |
2056 | if (!name) |
2057 | log_fatal ("no memory for group decl name %s", val); | |
2058 | strcpy (name, val); | |
2059 | } | |
2060 | ||
20916cae TL |
2061 | if (!parse_lbrace (cfile)) { |
2062 | group_dereference (&g, MDL); | |
7dfc8ac2 | 2063 | return; |
20916cae | 2064 | } |
d7837182 | 2065 | |
7dfc8ac2 TL |
2066 | do { |
2067 | token = peek_token (&val, cfile); | |
5376e3e9 TL |
2068 | if (token == RBRACE) { |
2069 | token = next_token (&val, cfile); | |
7dfc8ac2 | 2070 | break; |
5376e3e9 TL |
2071 | } else if (token == EOF) { |
2072 | token = next_token (&val, cfile); | |
35454d8a | 2073 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 2074 | break; |
007e3ee4 | 2075 | } else if (token == TOKEN_DELETED) { |
29c35bed TL |
2076 | token = next_token (&val, cfile); |
2077 | parse_semi (cfile); | |
2078 | deletedp = 1; | |
2079 | } else if (token == DYNAMIC) { | |
2080 | token = next_token (&val, cfile); | |
2081 | parse_semi (cfile); | |
2082 | dynamicp = 1; | |
2083 | } else if (token == STATIC) { | |
2084 | token = next_token (&val, cfile); | |
2085 | parse_semi (cfile); | |
2086 | staticp = 1; | |
5376e3e9 | 2087 | } |
2d59f590 TL |
2088 | declaration = parse_statement (cfile, g, GROUP_DECL, |
2089 | (struct host_decl *)0, | |
2090 | declaration); | |
7dfc8ac2 | 2091 | } while (1); |
29c35bed TL |
2092 | |
2093 | if (name) { | |
2094 | if (deletedp) { | |
2095 | if (group_name_hash) { | |
20916cae TL |
2096 | t = (struct group_object *)0; |
2097 | if (group_hash_lookup (&t, group_name_hash, | |
2098 | name, | |
2099 | strlen (name), MDL)) { | |
29c35bed TL |
2100 | delete_group (t, 0); |
2101 | } | |
2102 | } | |
2103 | } else { | |
20916cae TL |
2104 | t = (struct group_object *)0; |
2105 | status = group_object_allocate (&t, MDL); | |
2106 | if (status != ISC_R_SUCCESS) | |
2107 | log_fatal ("no memory for group decl %s: %s", | |
2108 | val, isc_result_totext (status)); | |
2109 | group_reference (&t -> group, g, MDL); | |
29c35bed TL |
2110 | t -> name = name; |
2111 | t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) | | |
2112 | (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) | | |
2113 | (deletedp ? GROUP_OBJECT_DELETED : 0)); | |
2114 | supersede_group (t, 0); | |
2115 | } | |
20916cae TL |
2116 | if (t) |
2117 | group_object_dereference (&t, MDL); | |
29c35bed | 2118 | } |
d7837182 TL |
2119 | } |
2120 | ||
2d59f590 TL |
2121 | /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI |
2122 | ip-addrs-or-hostnames :== ip-addr-or-hostname | |
2123 | | ip-addrs-or-hostnames ip-addr-or-hostname */ | |
d7837182 | 2124 | |
6f8fb41f TL |
2125 | int parse_fixed_addr_param (oc, cfile) |
2126 | struct option_cache **oc; | |
35454d8a | 2127 | struct parse *cfile; |
d7837182 | 2128 | { |
b1b7b521 | 2129 | const char *val; |
6f8fb41f | 2130 | enum dhcp_token token; |
ece6ea33 | 2131 | struct expression *expr = (struct expression *)0; |
6f8fb41f TL |
2132 | struct expression *tmp, *new; |
2133 | int status; | |
1f814ff2 TL |
2134 | |
2135 | do { | |
6f8fb41f TL |
2136 | tmp = (struct expression *)0; |
2137 | if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) { | |
028a8588 TL |
2138 | if (expr) { |
2139 | new = (struct expression *)0; | |
2140 | status = make_concat (&new, expr, tmp); | |
436f1c8c TL |
2141 | expression_dereference (&expr, MDL); |
2142 | expression_dereference (&tmp, MDL); | |
1dd632af | 2143 | if (!status) |
028a8588 TL |
2144 | return 0; |
2145 | expr = new; | |
2146 | } else | |
2147 | expr = tmp; | |
6f8fb41f TL |
2148 | } else { |
2149 | if (expr) | |
436f1c8c | 2150 | expression_dereference (&expr, MDL); |
6f8fb41f TL |
2151 | return 0; |
2152 | } | |
1f814ff2 | 2153 | token = peek_token (&val, cfile); |
5376e3e9 | 2154 | if (token == COMMA) |
1f814ff2 TL |
2155 | token = next_token (&val, cfile); |
2156 | } while (token == COMMA); | |
7dfc8ac2 | 2157 | |
6f8fb41f TL |
2158 | if (!parse_semi (cfile)) { |
2159 | if (expr) | |
436f1c8c | 2160 | expression_dereference (&expr, MDL); |
6f8fb41f TL |
2161 | return 0; |
2162 | } | |
2163 | status = option_cache (oc, (struct data_string *)0, expr, | |
2164 | (struct option *)0); | |
436f1c8c | 2165 | expression_dereference (&expr, MDL); |
6f8fb41f | 2166 | return status; |
d7837182 TL |
2167 | } |
2168 | ||
5376e3e9 | 2169 | /* timestamp :== date |
d7837182 TL |
2170 | |
2171 | Timestamps are actually not used in dhcpd.conf, which is a static file, | |
5376e3e9 TL |
2172 | but rather in the database file and the journal file. (Okay, actually |
2173 | they're not even used there yet). */ | |
d7837182 | 2174 | |
7dfc8ac2 | 2175 | TIME parse_timestamp (cfile) |
35454d8a | 2176 | struct parse *cfile; |
d7837182 | 2177 | { |
089fb364 | 2178 | TIME rv; |
089fb364 | 2179 | |
7dfc8ac2 | 2180 | rv = parse_date (cfile); |
089fb364 | 2181 | return rv; |
d7837182 TL |
2182 | } |
2183 | ||
2d59f590 TL |
2184 | /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE |
2185 | ||
2186 | lease_parameters :== <nil> | |
2187 | | lease_parameter | |
2188 | | lease_parameters lease_parameter | |
2189 | ||
2190 | lease_parameter :== STARTS date | |
2191 | | ENDS date | |
2192 | | TIMESTAMP date | |
2193 | | HARDWARE hardware-parameter | |
2194 | | UID hex_numbers SEMI | |
ccf5778a TL |
2195 | | HOSTNAME hostname SEMI |
2196 | | CLIENT_HOSTNAME hostname SEMI | |
2d59f590 TL |
2197 | | CLASS identifier SEMI |
2198 | | DYNAMIC_BOOTP SEMI */ | |
2199 | ||
20916cae | 2200 | int parse_lease_declaration (struct lease **lp, struct parse *cfile) |
d7837182 | 2201 | { |
b1b7b521 | 2202 | const char *val; |
6f8fb41f | 2203 | enum dhcp_token token; |
d7837182 | 2204 | unsigned char addr [4]; |
b1b7b521 | 2205 | unsigned len = sizeof addr; |
d7837182 TL |
2206 | int seenmask = 0; |
2207 | int seenbit; | |
2208 | char tbuf [32]; | |
20916cae | 2209 | struct lease *lease; |
96d7d13e | 2210 | struct executable_statement *on; |
436f1c8c TL |
2211 | struct expression *exp; |
2212 | struct data_string ds; | |
96d7d13e | 2213 | int lose; |
9e9b2261 | 2214 | TIME t; |
436f1c8c TL |
2215 | char *s; |
2216 | int noequal, newbinding; | |
2217 | struct binding *binding; | |
20916cae | 2218 | isc_result_t status; |
007e3ee4 | 2219 | binding_state_t *statep; |
d7837182 | 2220 | |
20916cae TL |
2221 | lease = (struct lease *)0; |
2222 | status = lease_allocate (&lease, MDL); | |
2223 | if (status != ISC_R_SUCCESS) | |
2224 | return 0; | |
9375101b | 2225 | |
d7837182 | 2226 | /* Get the address for which the lease has been issued. */ |
20916cae TL |
2227 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
2228 | lease_dereference (&lease, MDL); | |
2229 | return 0; | |
2230 | } | |
2231 | memcpy (lease -> ip_addr.iabuf, addr, len); | |
2232 | lease -> ip_addr.len = len; | |
d7837182 | 2233 | |
20916cae TL |
2234 | if (!parse_lbrace (cfile)) { |
2235 | lease_dereference (&lease, MDL); | |
2236 | return 0; | |
2237 | } | |
7dfc8ac2 | 2238 | |
d7837182 TL |
2239 | do { |
2240 | token = next_token (&val, cfile); | |
7dfc8ac2 | 2241 | if (token == RBRACE) |
d7837182 | 2242 | break; |
5376e3e9 | 2243 | else if (token == EOF) { |
35454d8a | 2244 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
2245 | break; |
2246 | } | |
ece6ea33 | 2247 | strncpy (tbuf, val, sizeof tbuf); |
d7837182 TL |
2248 | tbuf [(sizeof tbuf) - 1] = 0; |
2249 | ||
2250 | /* Parse any of the times associated with the lease. */ | |
9e9b2261 TL |
2251 | switch (token) { |
2252 | case STARTS: | |
2253 | case ENDS: | |
2254 | case TIMESTAMP: | |
2255 | case TSTP: | |
2256 | case TSFP: | |
8c8e27c5 | 2257 | case CLTT: |
7dfc8ac2 | 2258 | t = parse_date (cfile); |
d7837182 TL |
2259 | switch (token) { |
2260 | case STARTS: | |
2261 | seenbit = 1; | |
20916cae | 2262 | lease -> starts = t; |
d7837182 TL |
2263 | break; |
2264 | ||
2265 | case ENDS: | |
2266 | seenbit = 2; | |
20916cae | 2267 | lease -> ends = t; |
d7837182 TL |
2268 | break; |
2269 | ||
2270 | case TIMESTAMP: | |
2271 | seenbit = 4; | |
20916cae | 2272 | lease -> timestamp = t; |
d7837182 | 2273 | break; |
19d868b2 | 2274 | |
9e9b2261 TL |
2275 | case TSTP: |
2276 | seenbit = 65536; | |
20916cae | 2277 | lease -> tstp = t; |
19d868b2 | 2278 | break; |
9e9b2261 TL |
2279 | |
2280 | case TSFP: | |
2281 | seenbit = 131072; | |
20916cae | 2282 | lease -> tsfp = t; |
d7837182 | 2283 | break; |
9e9b2261 | 2284 | |
8c8e27c5 TL |
2285 | case CLTT: |
2286 | seenbit = 524288; | |
20916cae | 2287 | lease -> cltt = t; |
8c8e27c5 TL |
2288 | break; |
2289 | ||
9e9b2261 | 2290 | default: /* for gcc, we'll never get here. */ |
9d80b480 | 2291 | break; |
9e9b2261 TL |
2292 | } |
2293 | break; | |
d7837182 | 2294 | |
9e9b2261 TL |
2295 | /* Colon-seperated hexadecimal octets... */ |
2296 | case UID: | |
2297 | seenbit = 8; | |
2298 | token = peek_token (&val, cfile); | |
2299 | if (token == STRING) { | |
2300 | unsigned char *tuid; | |
d7837182 | 2301 | token = next_token (&val, cfile); |
20916cae | 2302 | lease -> uid_len = strlen (val); |
436f1c8c | 2303 | tuid = ((unsigned char *) |
20916cae | 2304 | dmalloc (lease -> uid_len, MDL)); |
9e9b2261 TL |
2305 | if (!tuid) { |
2306 | log_error ("no space for uid"); | |
20916cae TL |
2307 | lease_dereference (&lease, MDL); |
2308 | return 0; | |
d7837182 | 2309 | } |
20916cae TL |
2310 | memcpy (tuid, val, lease -> uid_len); |
2311 | lease -> uid = tuid; | |
9e9b2261 | 2312 | } else { |
20916cae TL |
2313 | lease -> uid_len = 0; |
2314 | lease -> uid = (parse_numeric_aggregate | |
2315 | (cfile, (unsigned char *)0, | |
2316 | &lease -> uid_len, ':', | |
2317 | 16, 8)); | |
2318 | if (!lease -> uid) { | |
2319 | lease_dereference (&lease, MDL); | |
2320 | return 0; | |
2321 | } | |
2322 | if (lease -> uid_len == 0) { | |
2323 | lease -> uid = (unsigned char *)0; | |
9e9b2261 TL |
2324 | parse_warn (cfile, "zero-length uid"); |
2325 | seenbit = 0; | |
d0463358 | 2326 | parse_semi (cfile); |
9e9b2261 TL |
2327 | break; |
2328 | } | |
2329 | } | |
d0463358 | 2330 | parse_semi (cfile); |
20916cae | 2331 | if (!lease -> uid) { |
9e9b2261 TL |
2332 | log_fatal ("No memory for lease uid"); |
2333 | } | |
2334 | break; | |
2335 | ||
2336 | case CLASS: | |
2337 | seenbit = 32; | |
2338 | token = next_token (&val, cfile); | |
2339 | if (!is_identifier (token)) { | |
2340 | if (token != SEMI) | |
2341 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
2342 | lease_dereference (&lease, MDL); |
2343 | return 0; | |
9e9b2261 | 2344 | } |
d0463358 | 2345 | parse_semi (cfile); |
9e9b2261 TL |
2346 | /* for now, we aren't using this. */ |
2347 | break; | |
ccf5778a | 2348 | |
9e9b2261 TL |
2349 | case HARDWARE: |
2350 | seenbit = 64; | |
2351 | parse_hardware_param (cfile, | |
20916cae | 2352 | &lease -> hardware_addr); |
9e9b2261 TL |
2353 | break; |
2354 | ||
2355 | case DYNAMIC_BOOTP: | |
007e3ee4 TL |
2356 | seenbit = 256; |
2357 | lease -> binding_state = FTS_BOOTP; | |
2358 | lease -> next_binding_state = FTS_BOOTP; | |
d0463358 | 2359 | parse_semi (cfile); |
9e9b2261 TL |
2360 | break; |
2361 | ||
007e3ee4 TL |
2362 | case TOKEN_ABANDONED: |
2363 | seenbit = 256; | |
2364 | lease -> binding_state = FTS_ABANDONED; | |
2365 | lease -> next_binding_state = FTS_ABANDONED; | |
d0463358 | 2366 | parse_semi (cfile); |
9e9b2261 TL |
2367 | break; |
2368 | ||
007e3ee4 TL |
2369 | case TOKEN_NEXT: |
2370 | seenbit = 128; | |
2371 | statep = &lease -> next_binding_state; | |
301a5b66 TL |
2372 | token = next_token (&val, cfile); |
2373 | if (token != BINDING) { | |
2374 | parse_warn (cfile, "expecting 'binding'"); | |
2375 | skip_to_semi (cfile); | |
2376 | break; | |
2377 | } | |
007e3ee4 TL |
2378 | goto do_binding_state; |
2379 | ||
2380 | case BINDING: | |
9e9b2261 | 2381 | seenbit = 256; |
007e3ee4 TL |
2382 | statep = &lease -> binding_state; |
2383 | ||
2384 | do_binding_state: | |
2385 | token = next_token (&val, cfile); | |
2386 | if (token != STATE) { | |
2387 | parse_warn (cfile, "expecting 'state'"); | |
2388 | skip_to_semi (cfile); | |
2389 | break; | |
2390 | } | |
2391 | token = next_token (&val, cfile); | |
2392 | switch (token) { | |
2393 | case TOKEN_ABANDONED: | |
2394 | *statep = FTS_ABANDONED; | |
2395 | break; | |
2396 | case TOKEN_FREE: | |
2397 | *statep = FTS_FREE; | |
2398 | break; | |
2399 | case TOKEN_ACTIVE: | |
2400 | *statep = FTS_ACTIVE; | |
2401 | break; | |
2402 | case TOKEN_EXPIRED: | |
2403 | *statep = FTS_EXPIRED; | |
2404 | break; | |
2405 | case TOKEN_RELEASED: | |
2406 | *statep = FTS_RELEASED; | |
2407 | break; | |
2408 | case TOKEN_RESET: | |
2409 | *statep = FTS_RESET; | |
2410 | break; | |
2411 | case TOKEN_BACKUP: | |
2412 | *statep = FTS_BACKUP; | |
2413 | break; | |
2414 | case TOKEN_RESERVED: | |
2415 | *statep = FTS_RESERVED; | |
2416 | break; | |
2417 | case TOKEN_BOOTP: | |
2418 | *statep = FTS_BOOTP; | |
2419 | break; | |
2420 | default: | |
2421 | parse_warn (cfile, | |
2422 | "%s: expecting a binding state.", | |
2423 | val); | |
2424 | skip_to_semi (cfile); | |
2425 | break; | |
2426 | } | |
2427 | /* If no next binding state is specified, it's | |
2428 | the same as the current state. */ | |
2429 | if (!(seenmask & 128) && seenbit == 256) | |
2430 | lease -> next_binding_state = | |
2431 | lease -> binding_state; | |
d0463358 | 2432 | parse_semi (cfile); |
9e9b2261 | 2433 | break; |
ccf5778a | 2434 | |
9e9b2261 TL |
2435 | case HOSTNAME: |
2436 | seenbit = 512; | |
2437 | token = peek_token (&val, cfile); | |
2438 | if (token == STRING) | |
20916cae | 2439 | lease -> hostname = parse_string (cfile); |
d0463358 | 2440 | else { |
20916cae TL |
2441 | lease -> hostname = parse_host_name (cfile); |
2442 | if (lease -> hostname) | |
d0463358 TL |
2443 | parse_semi (cfile); |
2444 | } | |
20916cae | 2445 | if (!lease -> hostname) { |
9e9b2261 | 2446 | seenbit = 0; |
20916cae | 2447 | return 0; |
9e9b2261 TL |
2448 | } |
2449 | break; | |
2450 | ||
2451 | case CLIENT_HOSTNAME: | |
2452 | seenbit = 1024; | |
2453 | token = peek_token (&val, cfile); | |
2454 | if (token == STRING) | |
20916cae TL |
2455 | lease -> client_hostname = |
2456 | parse_string (cfile); | |
d0463358 | 2457 | else { |
20916cae | 2458 | lease -> client_hostname = |
9e9b2261 | 2459 | parse_host_name (cfile); |
20916cae | 2460 | if (lease -> client_hostname) |
d0463358 TL |
2461 | parse_semi (cfile); |
2462 | } | |
20916cae | 2463 | if (!lease -> client_hostname) { |
d0463358 | 2464 | seenbit = 0; |
20916cae TL |
2465 | lease_dereference (&lease, MDL); |
2466 | return 0; | |
d0463358 | 2467 | } |
9e9b2261 TL |
2468 | break; |
2469 | ||
2470 | case BILLING: | |
2471 | seenbit = 2048; | |
2472 | token = next_token (&val, cfile); | |
2473 | if (token == CLASS) { | |
88dcab62 | 2474 | token = next_token (&val, cfile); |
9e9b2261 TL |
2475 | if (token != STRING) { |
2476 | parse_warn (cfile, "expecting string"); | |
88dcab62 TL |
2477 | if (token != SEMI) |
2478 | skip_to_semi (cfile); | |
9e9b2261 TL |
2479 | token = BILLING; |
2480 | break; | |
88dcab62 | 2481 | } |
20916cae TL |
2482 | find_class (&lease -> billing_class, val, MDL); |
2483 | if (!lease -> billing_class) | |
9e9b2261 TL |
2484 | parse_warn (cfile, |
2485 | "unknown class %s", val); | |
2486 | parse_semi (cfile); | |
2487 | } else if (token == SUBCLASS) { | |
20916cae TL |
2488 | if (lease -> billing_class) |
2489 | class_dereference | |
2490 | (&lease -> billing_class, MDL); | |
2491 | parse_class_declaration | |
2492 | (&lease -> billing_class, | |
2493 | cfile, (struct group *)0, 3); | |
9e9b2261 TL |
2494 | } else { |
2495 | parse_warn (cfile, "expecting \"class\""); | |
2496 | if (token != SEMI) | |
2497 | skip_to_semi (cfile); | |
2498 | } | |
9e9b2261 | 2499 | break; |
96d7d13e | 2500 | |
9e9b2261 TL |
2501 | case ON: |
2502 | on = (struct executable_statement *)0; | |
2503 | lose = 0; | |
2504 | if (!parse_on_statement (&on, cfile, &lose)) { | |
2505 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
2506 | lease_dereference (&lease, MDL); |
2507 | return 0; | |
7dfc8ac2 | 2508 | } |
436f1c8c | 2509 | seenbit = 0; |
d0463358 | 2510 | if ((on -> data.on.evtypes & ON_EXPIRY) && |
9e9b2261 | 2511 | on -> data.on.statements) { |
436f1c8c | 2512 | seenbit |= 16384; |
9e9b2261 | 2513 | executable_statement_reference |
20916cae | 2514 | (&lease -> on_expiry, |
436f1c8c | 2515 | on -> data.on.statements, MDL); |
d0463358 TL |
2516 | } |
2517 | if ((on -> data.on.evtypes & ON_RELEASE) && | |
2518 | on -> data.on.statements) { | |
436f1c8c | 2519 | seenbit |= 32768; |
9e9b2261 | 2520 | executable_statement_reference |
20916cae | 2521 | (&lease -> on_release, |
436f1c8c | 2522 | on -> data.on.statements, MDL); |
9e9b2261 | 2523 | } |
436f1c8c | 2524 | executable_statement_dereference (&on, MDL); |
9e9b2261 TL |
2525 | break; |
2526 | ||
436f1c8c TL |
2527 | case TOKEN_SET: |
2528 | noequal = 0; | |
2529 | ||
2530 | token = next_token (&val, cfile); | |
2531 | if (token != NAME && token != NUMBER_OR_NAME) { | |
2532 | parse_warn (cfile, | |
2533 | "%s can't be a variable name", | |
2534 | val); | |
2535 | badset: | |
2536 | skip_to_semi (cfile); | |
20916cae TL |
2537 | lease_dereference (&lease, MDL); |
2538 | return 0; | |
436f1c8c TL |
2539 | } |
2540 | ||
2541 | seenbit = 0; | |
2542 | special_set: | |
6ceb9118 TL |
2543 | if (lease -> scope) |
2544 | binding = find_binding (lease -> scope, val); | |
2545 | else | |
2546 | binding = (struct binding *)0; | |
436f1c8c | 2547 | if (!binding) { |
6ceb9118 TL |
2548 | if (!lease -> scope) |
2549 | if (!(binding_scope_allocate | |
2550 | (&lease -> scope, MDL))) | |
2551 | log_fatal ("no memory for scope"); | |
436f1c8c TL |
2552 | binding = dmalloc (sizeof *binding, MDL); |
2553 | if (!binding) | |
2554 | log_fatal ("No memory for lease %s.", | |
2555 | "binding"); | |
2556 | memset (binding, 0, sizeof *binding); | |
2557 | binding -> name = | |
2558 | dmalloc (strlen (val) + 1, MDL); | |
2559 | if (!binding -> name) | |
2560 | log_fatal ("No memory for binding %s.", | |
2561 | "name"); | |
2562 | strcpy (binding -> name, val); | |
2563 | newbinding = 1; | |
11cd757b TL |
2564 | } else if (binding -> value) { |
2565 | binding_value_dereference (&binding -> value, | |
2566 | MDL); | |
436f1c8c TL |
2567 | newbinding = 0; |
2568 | } | |
11cd757b TL |
2569 | if (!binding_value_allocate (&binding -> value, MDL)) |
2570 | log_fatal ("no memory for binding value."); | |
436f1c8c TL |
2571 | |
2572 | if (!noequal) { | |
2573 | token = next_token (&val, cfile); | |
2574 | if (token != EQUAL) { | |
2575 | parse_warn (cfile, | |
2576 | "expecting '=' in set statement."); | |
2577 | goto badset; | |
2578 | } | |
2579 | } | |
2580 | ||
2581 | token = peek_token (&val, cfile); | |
2582 | if (token == STRING) { | |
11cd757b TL |
2583 | unsigned char *tuid; |
2584 | token = next_token (&val, cfile); | |
2585 | binding -> value -> type = binding_data; | |
2586 | binding -> value -> value.data.len = strlen (val); | |
2587 | if (!(buffer_allocate | |
2588 | (&binding -> value -> value.data.buffer, | |
2589 | binding -> value-> value.data.len + 1, | |
2590 | MDL))) | |
2591 | log_fatal ("No memory for binding."); | |
2592 | strcpy ((char *) | |
2593 | (binding -> value -> | |
2594 | value.data.buffer -> data), val); | |
2595 | binding -> value -> value.data.data = | |
2596 | binding -> value -> value.data.buffer -> data; | |
2597 | binding -> value -> value.data.terminated = 1; | |
2598 | } else if (token == NUMBER_OR_NAME) { | |
2599 | binding -> value -> type = binding_data; | |
2600 | s = ((char *) | |
2601 | (parse_numeric_aggregate | |
2602 | (cfile, (unsigned char *)0, | |
2603 | &binding -> value -> value.data.len, | |
2604 | ':', 16, 8))); | |
2605 | if (!s) { | |
2606 | binding_value_dereference | |
2607 | (&binding -> value, MDL); | |
20916cae TL |
2608 | lease_dereference (&lease, MDL); |
2609 | return 0; | |
11cd757b TL |
2610 | } |
2611 | if (binding -> value -> value.data.len) { | |
436f1c8c | 2612 | if (!(buffer_allocate |
11cd757b TL |
2613 | (&binding -> value -> value.data.buffer, |
2614 | binding -> value -> value.data.len + 1, | |
2615 | MDL))) | |
436f1c8c | 2616 | log_fatal ("No memory for binding."); |
11cd757b TL |
2617 | memcpy ((binding -> value -> |
2618 | value.data.buffer -> data), s, | |
2619 | binding -> value -> value.data.len); | |
2620 | dfree (s, MDL); | |
2621 | binding -> value -> value.data.data = | |
2622 | binding -> value -> value.data.buffer -> data; | |
2623 | } | |
2624 | } else if (token == PERCENT) { | |
2625 | token = next_token (&val, cfile); | |
2626 | token = next_token (&val, cfile); | |
2627 | if (token != NUMBER) { | |
2628 | parse_warn (cfile, | |
2629 | "expecting decimal number."); | |
2630 | if (token != SEMI) | |
2631 | skip_to_semi (cfile); | |
2632 | binding_value_dereference | |
2633 | (&binding -> value, MDL); | |
20916cae TL |
2634 | lease_dereference (&lease, MDL); |
2635 | return 0; | |
11cd757b TL |
2636 | } |
2637 | binding -> value -> type = binding_numeric; | |
2638 | binding -> value -> value.intval = atol (val); | |
2639 | } else if (token == NAME) { | |
2640 | token = next_token (&val, cfile); | |
2641 | binding -> value -> type = binding_boolean; | |
2642 | if (!strcasecmp (val, "true")) | |
2643 | binding -> value -> value.boolean = 1; | |
2644 | else if (!strcasecmp (val, "false")) | |
2645 | binding -> value -> value.boolean = 0; | |
2646 | else | |
2647 | goto badbool; | |
436f1c8c | 2648 | } else { |
11cd757b TL |
2649 | badbool: |
2650 | parse_warn (cfile, | |
2651 | "expecting a constant value."); | |
2652 | skip_to_semi (cfile); | |
2653 | binding_value_dereference (&binding -> value, | |
2654 | MDL); | |
20916cae TL |
2655 | lease_dereference (&lease, MDL); |
2656 | return 0; | |
436f1c8c | 2657 | } |
11cd757b | 2658 | |
436f1c8c | 2659 | if (newbinding) { |
6ceb9118 TL |
2660 | binding -> next = lease -> scope -> bindings; |
2661 | lease -> scope -> bindings = binding; | |
436f1c8c TL |
2662 | } |
2663 | parse_semi (cfile); | |
2664 | break; | |
2665 | ||
9e9b2261 | 2666 | default: |
436f1c8c TL |
2667 | if (!strcasecmp (val, "ddns-fwd-name")) { |
2668 | seenbit = 4096; | |
2669 | noequal = 1; | |
2670 | goto special_set; | |
2671 | } else if (!strcasecmp (val, "ddns-rev-name")) { | |
2672 | seenbit = 8192; | |
2673 | noequal = 1; | |
2674 | goto special_set; | |
2675 | } | |
9e9b2261 TL |
2676 | skip_to_semi (cfile); |
2677 | seenbit = 0; | |
20916cae TL |
2678 | lease_dereference (&lease, MDL); |
2679 | return 0; | |
9e9b2261 | 2680 | } |
7dfc8ac2 | 2681 | |
d7837182 | 2682 | if (seenmask & seenbit) { |
35454d8a TL |
2683 | parse_warn (cfile, |
2684 | "Too many %s parameters in lease %s\n", | |
20916cae | 2685 | tbuf, piaddr (lease -> ip_addr)); |
d7837182 TL |
2686 | } else |
2687 | seenmask |= seenbit; | |
7dfc8ac2 | 2688 | |
d7837182 | 2689 | } while (1); |
8afe0787 TL |
2690 | |
2691 | /* If no binding state is specified, make one up. */ | |
2692 | if (!(seenmask & 256)) { | |
e73a0769 TL |
2693 | if (lease -> ends > cur_time || |
2694 | lease -> on_expiry || lease -> on_release) | |
8afe0787 | 2695 | lease -> binding_state = FTS_ACTIVE; |
301a5b66 | 2696 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
2697 | else if (lease -> pool && lease -> pool -> failover_peer) |
2698 | lease -> binding_state = FTS_EXPIRED; | |
301a5b66 | 2699 | #endif |
8afe0787 TL |
2700 | else |
2701 | lease -> binding_state = FTS_FREE; | |
e73a0769 | 2702 | if (lease -> binding_state == FTS_ACTIVE) { |
301a5b66 | 2703 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
2704 | if (lease -> pool && lease -> pool -> failover_peer) |
2705 | lease -> next_binding_state = FTS_EXPIRED; | |
2706 | else | |
301a5b66 | 2707 | #endif |
e73a0769 TL |
2708 | lease -> next_binding_state = FTS_FREE; |
2709 | } else | |
2710 | lease -> next_binding_state = lease -> binding_state; | |
8afe0787 TL |
2711 | } |
2712 | ||
20916cae TL |
2713 | lease_reference (lp, lease, MDL); |
2714 | lease_dereference (&lease, MDL); | |
2715 | return 1; | |
d7837182 TL |
2716 | } |
2717 | ||
2d59f590 TL |
2718 | /* address-range-declaration :== ip-address ip-address SEMI |
2719 | | DYNAMIC_BOOTP ip-address ip-address SEMI */ | |
d7837182 | 2720 | |
20916cae | 2721 | void parse_address_range (cfile, group, type, inpool) |
35454d8a | 2722 | struct parse *cfile; |
f63b4929 TL |
2723 | struct group *group; |
2724 | int type; | |
20916cae | 2725 | struct pool *inpool; |
d7837182 | 2726 | { |
f63b4929 | 2727 | struct iaddr low, high, net; |
d7837182 | 2728 | unsigned char addr [4]; |
b1b7b521 | 2729 | unsigned len = sizeof addr; |
6f8fb41f | 2730 | enum dhcp_token token; |
b1b7b521 | 2731 | const char *val; |
1f814ff2 | 2732 | int dynamic = 0; |
f63b4929 TL |
2733 | struct subnet *subnet; |
2734 | struct shared_network *share; | |
2735 | struct pool *p; | |
20916cae TL |
2736 | struct pool *pool; |
2737 | isc_result_t status; | |
1f814ff2 TL |
2738 | |
2739 | if ((token = peek_token (&val, cfile)) == DYNAMIC_BOOTP) { | |
5376e3e9 | 2740 | token = next_token (&val, cfile); |
ece6ea33 | 2741 | dynamic = 1; |
1f814ff2 | 2742 | } |
d7837182 TL |
2743 | |
2744 | /* Get the bottom address in the range... */ | |
7dfc8ac2 TL |
2745 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2746 | return; | |
089fb364 TL |
2747 | memcpy (low.iabuf, addr, len); |
2748 | low.len = len; | |
d7837182 | 2749 | |
2d59f590 TL |
2750 | /* Only one address? */ |
2751 | token = peek_token (&val, cfile); | |
2752 | if (token == SEMI) | |
2753 | high = low; | |
2754 | else { | |
d7837182 | 2755 | /* Get the top address in the range... */ |
2d59f590 TL |
2756 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2757 | return; | |
2758 | memcpy (high.iabuf, addr, len); | |
2759 | high.len = len; | |
2760 | } | |
d7837182 | 2761 | |
7dfc8ac2 TL |
2762 | token = next_token (&val, cfile); |
2763 | if (token != SEMI) { | |
35454d8a | 2764 | parse_warn (cfile, "semicolon expected."); |
7dfc8ac2 TL |
2765 | skip_to_semi (cfile); |
2766 | return; | |
2767 | } | |
2768 | ||
f63b4929 TL |
2769 | if (type == SUBNET_DECL) { |
2770 | subnet = group -> subnet; | |
2771 | share = subnet -> shared_network; | |
2772 | } else { | |
2773 | share = group -> shared_network; | |
2774 | for (subnet = share -> subnets; | |
2775 | subnet; subnet = subnet -> next_sibling) { | |
2776 | net = subnet_number (low, subnet -> netmask); | |
e5e41be4 | 2777 | if (addr_eq (net, subnet -> net)) |
f63b4929 TL |
2778 | break; |
2779 | } | |
2780 | if (!subnet) { | |
35454d8a | 2781 | parse_warn (cfile, "address range not on network %s", |
f63b4929 | 2782 | group -> shared_network -> name); |
e5e41be4 TL |
2783 | log_error ("Be sure to place pool statement after %s", |
2784 | "related subnet declarations."); | |
f63b4929 TL |
2785 | return; |
2786 | } | |
2787 | } | |
2788 | ||
20916cae | 2789 | if (!inpool) { |
0a1dfb65 | 2790 | struct pool *last = (struct pool *)0; |
9e9b2261 | 2791 | |
f63b4929 TL |
2792 | /* If we're permitting dynamic bootp for this range, |
2793 | then look for a pool with an empty prohibit list and | |
436f1c8c | 2794 | a permit list with one entry that permits all clients. */ |
f63b4929 | 2795 | for (pool = share -> pools; pool; pool = pool -> next) { |
436f1c8c TL |
2796 | if ((!dynamic && !pool -> permit_list && |
2797 | pool -> prohibit_list && | |
2798 | !pool -> prohibit_list -> next && | |
2799 | (pool -> prohibit_list -> type == | |
2800 | permit_dynamic_bootp_clients)) || | |
2801 | (dynamic && !pool -> prohibit_list && | |
f63b4929 TL |
2802 | pool -> permit_list && |
2803 | !pool -> permit_list -> next && | |
2804 | (pool -> permit_list -> type == | |
d9eefc5d | 2805 | permit_all_clients))) { |
436f1c8c | 2806 | break; |
f63b4929 TL |
2807 | } |
2808 | last = pool; | |
2809 | } | |
2810 | ||
2811 | /* If we didn't get a pool, make one. */ | |
2812 | if (!pool) { | |
436f1c8c | 2813 | struct permit *p; |
20916cae TL |
2814 | status = pool_allocate (&pool, MDL); |
2815 | if (status != ISC_R_SUCCESS) | |
2816 | log_fatal ("no memory for ad-hoc pool: %s", | |
2817 | isc_result_totext (status)); | |
436f1c8c TL |
2818 | p = new_permit (MDL); |
2819 | if (!p) | |
2820 | log_fatal ("no memory for ad-hoc permit."); | |
2821 | ||
2822 | /* Dynamic pools permit all clients. Otherwise | |
2823 | we prohibit BOOTP clients. */ | |
f63b4929 | 2824 | if (dynamic) { |
436f1c8c TL |
2825 | p -> type = permit_all_clients; |
2826 | pool -> permit_list = p; | |
2827 | } else { | |
2828 | p -> type = permit_dynamic_bootp_clients; | |
2829 | pool -> prohibit_list = p; | |
f63b4929 | 2830 | } |
436f1c8c | 2831 | |
f63b4929 | 2832 | if (share -> pools) |
20916cae | 2833 | pool_reference (&last -> next, pool, MDL); |
f63b4929 | 2834 | else |
20916cae TL |
2835 | pool_reference (&share -> pools, pool, MDL); |
2836 | shared_network_reference (&pool -> shared_network, | |
2837 | share, MDL); | |
2838 | if (!clone_group (&pool -> group, share -> group, MDL)) | |
2839 | log_fatal ("no memory for anon pool group."); | |
a79ed92b TL |
2840 | } else { |
2841 | pool = (struct pool *)0; | |
0a1dfb65 TL |
2842 | if (last) |
2843 | pool_reference (&pool, last, MDL); | |
2844 | else | |
2845 | pool_reference (&pool, share -> pools, MDL); | |
f63b4929 | 2846 | } |
a79ed92b TL |
2847 | } else { |
2848 | pool = (struct pool *)0; | |
20916cae | 2849 | pool_reference (&pool, inpool, MDL); |
a79ed92b | 2850 | } |
20916cae | 2851 | |
c5261618 TL |
2852 | #if defined (FAILOVER_PROTOCOL) |
2853 | if (pool -> failover_peer && dynamic) { | |
2854 | /* Doctor, do you think I'm overly sensitive | |
2855 | about getting bug reports I can't fix? */ | |
2856 | parse_warn (cfile, "dynamic-bootp flag is %s", | |
2857 | "not permitted for address"); | |
2858 | log_error ("range declarations where there is a failover"); | |
2859 | log_error ("peer in scope. If you wish to declare an"); | |
2860 | log_error ("address range from which dynamic bootp leases"); | |
2861 | log_error ("can be allocated, please declare it within a"); | |
2862 | log_error ("pool declaration that also contains the \"no"); | |
2863 | log_error ("failover\" statement. The failover protocol"); | |
2864 | log_error ("itself does not permit dynamic bootp - this"); | |
2865 | log_error ("is not a limitation specific to the ISC DHCP"); | |
2866 | log_error ("server. Please don't ask me to defend this"); | |
2867 | log_error ("until you have read and really tried %s", | |
2868 | "to understand"); | |
2869 | log_error ("the failover protocol specification."); | |
2870 | ||
2871 | /* We don't actually bomb at this point - instead, | |
2872 | we let parse_lease_file notice the error and | |
2873 | bomb at that point - it's easier. */ | |
f63b4929 | 2874 | } |
c5261618 | 2875 | #endif /* FAILOVER_PROTOCOL */ |
f63b4929 | 2876 | |
d7837182 | 2877 | /* Create the new address range... */ |
f63b4929 | 2878 | new_address_range (low, high, subnet, pool); |
20916cae | 2879 | pool_dereference (&pool, MDL); |
d7837182 TL |
2880 | } |
2881 | ||
c358155d TL |
2882 | /* allow-deny-keyword :== BOOTP |
2883 | | BOOTING | |
2884 | | DYNAMIC_BOOTP | |
2885 | | UNKNOWN_CLIENTS */ | |
2886 | ||
2887 | int parse_allow_deny (oc, cfile, flag) | |
2888 | struct option_cache **oc; | |
2889 | struct parse *cfile; | |
2890 | int flag; | |
2891 | { | |
2892 | enum dhcp_token token; | |
2893 | const char *val; | |
2894 | unsigned char rf = flag; | |
2895 | struct expression *data = (struct expression *)0; | |
2896 | int status; | |
2897 | ||
2898 | if (!make_const_data (&data, &rf, 1, 0, 1)) | |
2899 | return 0; | |
2900 | ||
2901 | token = next_token (&val, cfile); | |
2902 | switch (token) { | |
007e3ee4 | 2903 | case TOKEN_BOOTP: |
c358155d TL |
2904 | status = option_cache (oc, (struct data_string *)0, data, |
2905 | &server_options [SV_ALLOW_BOOTP]); | |
2906 | break; | |
2907 | ||
2908 | case BOOTING: | |
2909 | status = option_cache (oc, (struct data_string *)0, data, | |
2910 | &server_options [SV_ALLOW_BOOTING]); | |
2911 | break; | |
2912 | ||
2913 | case DYNAMIC_BOOTP: | |
2914 | status = option_cache (oc, (struct data_string *)0, data, | |
2915 | &server_options [SV_DYNAMIC_BOOTP]); | |
2916 | break; | |
2917 | ||
2918 | case UNKNOWN_CLIENTS: | |
2919 | status = (option_cache | |
2920 | (oc, (struct data_string *)0, data, | |
2921 | &server_options [SV_BOOT_UNKNOWN_CLIENTS])); | |
2922 | break; | |
2923 | ||
2924 | case DUPLICATES: | |
2925 | status = option_cache (oc, (struct data_string *)0, data, | |
2926 | &server_options [SV_DUPLICATES]); | |
2927 | break; | |
2928 | ||
2929 | case DECLINES: | |
2930 | status = option_cache (oc, (struct data_string *)0, data, | |
2931 | &server_options [SV_DECLINES]); | |
2932 | break; | |
2933 | ||
2934 | default: | |
2935 | parse_warn (cfile, "expecting allow/deny key"); | |
2936 | skip_to_semi (cfile); | |
2937 | return 0; | |
2938 | } | |
2939 | parse_semi (cfile); | |
2940 | return status; | |
2941 | } | |
2942 |