]>
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[] = | |
b83bf1d1 | 46 | "$Id: confpars.c,v 1.122 2000/08/15 22:23:33 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 | |
2d59f590 | 587 | if (declaration) { |
35454d8a TL |
588 | parse_warn (cfile, |
589 | "parameters not allowed after first declaration."); | |
7dfc8ac2 | 590 | return 1; |
1f814ff2 | 591 | } |
7dfc8ac2 TL |
592 | |
593 | return 0; | |
d7837182 TL |
594 | } |
595 | ||
763adef1 TL |
596 | #if defined (FAILOVER_PROTOCOL) |
597 | void parse_failover_peer (cfile, group, type) | |
35454d8a | 598 | struct parse *cfile; |
763adef1 TL |
599 | struct group *group; |
600 | int type; | |
601 | { | |
602 | enum dhcp_token token; | |
b1b7b521 | 603 | const char *val; |
9e9b2261 TL |
604 | dhcp_failover_state_t *peer; |
605 | u_int32_t *tp; | |
763adef1 | 606 | char *name; |
9e9b2261 TL |
607 | u_int32_t split; |
608 | u_int8_t hba [32]; | |
165bce70 | 609 | unsigned hba_len = sizeof hba; |
9e9b2261 TL |
610 | int i; |
611 | struct expression *expr; | |
e9623235 TL |
612 | isc_result_t status; |
613 | struct option_cache **paddr; | |
614 | int *pport; | |
763adef1 TL |
615 | |
616 | token = next_token (&val, cfile); | |
617 | if (token != PEER) { | |
9e9b2261 | 618 | parse_warn (cfile, "expecting \"peer\""); |
763adef1 TL |
619 | skip_to_semi (cfile); |
620 | return; | |
621 | } | |
622 | ||
623 | token = next_token (&val, cfile); | |
624 | if (is_identifier (token) || token == STRING) { | |
436f1c8c | 625 | name = dmalloc (strlen (val) + 1, MDL); |
9e9b2261 | 626 | if (!name) |
8ae2d595 | 627 | log_fatal ("no memory for peer name %s", name); |
9e9b2261 | 628 | strcpy (name, val); |
763adef1 | 629 | } else { |
9e9b2261 | 630 | parse_warn (cfile, "expecting failover peer name."); |
763adef1 TL |
631 | skip_to_semi (cfile); |
632 | return; | |
633 | } | |
634 | ||
635 | /* See if there's a peer declaration by this name. */ | |
9e9b2261 | 636 | peer = (dhcp_failover_state_t *)0; |
20916cae | 637 | find_failover_peer (&peer, name, MDL); |
763adef1 TL |
638 | |
639 | token = next_token (&val, cfile); | |
640 | if (token == SEMI) { | |
436f1c8c | 641 | dfree (name, MDL); |
763adef1 | 642 | if (type != SHARED_NET_DECL) |
35454d8a | 643 | parse_warn (cfile, "failover peer reference not %s", |
763adef1 TL |
644 | "in shared-network declaration"); |
645 | else { | |
646 | if (!peer) { | |
35454d8a | 647 | parse_warn (cfile, "reference to unknown%s%s", |
763adef1 TL |
648 | " failover peer ", name); |
649 | return; | |
650 | } | |
20916cae TL |
651 | dhcp_failover_state_reference |
652 | (&group -> shared_network -> failover_peer, | |
653 | peer, MDL); | |
763adef1 | 654 | } |
20916cae | 655 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 | 656 | return; |
a4ba3160 | 657 | } else if (token == STATE) { |
763adef1 | 658 | if (!peer) { |
a4ba3160 | 659 | parse_warn (cfile, "state declaration for unknown%s%s", |
763adef1 TL |
660 | " failover peer ", name); |
661 | return; | |
662 | } | |
a4ba3160 | 663 | parse_failover_state_declaration (cfile, peer); |
20916cae | 664 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
665 | return; |
666 | } else if (token != LBRACE) { | |
35454d8a | 667 | parse_warn (cfile, "expecting left brace"); |
763adef1 TL |
668 | skip_to_semi (cfile); |
669 | } | |
670 | ||
671 | /* Make sure this isn't a redeclaration. */ | |
672 | if (peer) { | |
35454d8a | 673 | parse_warn (cfile, "redeclaration of failover peer %s", name); |
763adef1 | 674 | skip_to_rbrace (cfile, 1); |
20916cae | 675 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
676 | return; |
677 | } | |
678 | ||
20916cae TL |
679 | status = dhcp_failover_state_allocate (&peer, MDL); |
680 | if (status != ISC_R_SUCCESS) | |
681 | log_fatal ("Can't allocate failover peer %s: %s", | |
682 | name, isc_result_totext (status)); | |
763adef1 TL |
683 | |
684 | /* Save the name. */ | |
685 | peer -> name = name; | |
686 | ||
a4ba3160 | 687 | /* Set the initial state. */ |
b83bf1d1 | 688 | peer -> my_state = potential_conflict; |
a4ba3160 TL |
689 | peer -> my_stos = cur_time; |
690 | peer -> partner_state = unknown_state; | |
691 | peer -> partner_stos = cur_time; | |
692 | ||
763adef1 TL |
693 | do { |
694 | token = next_token (&val, cfile); | |
695 | switch (token) { | |
696 | case RBRACE: | |
697 | break; | |
9e9b2261 | 698 | |
763adef1 TL |
699 | case PRIMARY: |
700 | peer -> i_am = primary; | |
701 | break; | |
9e9b2261 | 702 | |
763adef1 TL |
703 | case SECONDARY: |
704 | peer -> i_am = secondary; | |
007e3ee4 TL |
705 | if (peer -> hba) |
706 | parse_warn (cfile, | |
707 | "secondary may not define %s", | |
708 | "load balance settings."); | |
763adef1 | 709 | break; |
9e9b2261 | 710 | |
e9623235 TL |
711 | case PEER: |
712 | token = next_token (&val, cfile); | |
713 | switch (token) { | |
714 | case ADDRESS: | |
715 | paddr = &peer -> address; | |
716 | goto doaddr; | |
717 | case PORT: | |
718 | pport = &peer -> port; | |
719 | goto doport; | |
720 | default: | |
721 | parse_warn (cfile, | |
722 | "expecting 'address' or 'port'"); | |
723 | skip_to_rbrace (cfile, 1); | |
20916cae | 724 | dhcp_failover_state_dereference (&peer, MDL); |
e9623235 TL |
725 | return; |
726 | } | |
727 | break; | |
728 | ||
729 | case ADDRESS: | |
730 | paddr = &peer -> server_addr; | |
731 | doaddr: | |
9e9b2261 TL |
732 | expr = (struct expression *)0; |
733 | if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { | |
763adef1 | 734 | skip_to_rbrace (cfile, 1); |
20916cae | 735 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
736 | return; |
737 | } | |
e9623235 | 738 | option_cache (paddr, (struct data_string *)0, expr, |
9e9b2261 | 739 | (struct option *)0); |
436f1c8c | 740 | expression_dereference (&expr, MDL); |
763adef1 | 741 | break; |
e9623235 | 742 | |
763adef1 | 743 | case PORT: |
e9623235 TL |
744 | pport = &peer -> listen_port; |
745 | doport: | |
763adef1 TL |
746 | token = next_token (&val, cfile); |
747 | if (token != NUMBER) { | |
35454d8a | 748 | parse_warn (cfile, "expecting number"); |
763adef1 TL |
749 | skip_to_rbrace (cfile, 1); |
750 | } | |
e9623235 | 751 | *pport = atoi (val); |
763adef1 | 752 | break; |
9e9b2261 | 753 | |
763adef1 TL |
754 | case MAX_TRANSMIT_IDLE: |
755 | tp = &peer -> max_transmit_idle; | |
756 | goto parse_idle; | |
9e9b2261 | 757 | |
763adef1 | 758 | case MAX_RESPONSE_DELAY: |
81b53730 | 759 | tp = &peer -> max_response_delay; |
763adef1 TL |
760 | parse_idle: |
761 | token = next_token (&val, cfile); | |
762 | if (token != NUMBER) { | |
35454d8a | 763 | parse_warn (cfile, "expecting number."); |
763adef1 | 764 | skip_to_rbrace (cfile, 1); |
20916cae | 765 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
766 | return; |
767 | } | |
768 | *tp = atoi (val); | |
9e9b2261 TL |
769 | break; |
770 | ||
771 | case MAX_UNACKED_UPDATES: | |
772 | tp = &peer -> max_flying_updates; | |
773 | goto parse_idle; | |
774 | ||
775 | case MCLT: | |
776 | tp = &peer -> mclt; | |
777 | goto parse_idle; | |
778 | ||
779 | case HBA: | |
e9623235 | 780 | hba_len = 32; |
007e3ee4 TL |
781 | if (peer -> i_am == secondary) |
782 | parse_warn (cfile, | |
783 | "secondary may not define %s", | |
784 | "load balance settings."); | |
9e9b2261 | 785 | if (!parse_numeric_aggregate (cfile, hba, &hba_len, |
e9623235 | 786 | COLON, 16, 8)) { |
9e9b2261 | 787 | skip_to_rbrace (cfile, 1); |
20916cae | 788 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
789 | return; |
790 | } | |
e9623235 TL |
791 | if (hba_len != 32) { |
792 | parse_warn (cfile, | |
793 | "HBA must be exactly 32 bytes."); | |
794 | dfree (hba, MDL); | |
795 | break; | |
796 | } | |
9e9b2261 | 797 | make_hba: |
436f1c8c | 798 | peer -> hba = dmalloc (32, MDL); |
9e9b2261 | 799 | if (!peer -> hba) { |
436f1c8c TL |
800 | dfree (peer -> name, MDL); |
801 | dfree (peer, MDL); | |
9e9b2261 TL |
802 | } |
803 | memcpy (peer -> hba, hba, 32); | |
804 | break; | |
805 | ||
806 | case SPLIT: | |
807 | token = next_token (&val, cfile); | |
007e3ee4 TL |
808 | if (peer -> i_am == secondary) |
809 | parse_warn (cfile, | |
810 | "secondary may not define %s", | |
811 | "load balance settings."); | |
9e9b2261 TL |
812 | if (token != NUMBER) { |
813 | parse_warn (cfile, "expecting number"); | |
20916cae | 814 | badsplit: |
9e9b2261 | 815 | skip_to_rbrace (cfile, 1); |
20916cae | 816 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
817 | return; |
818 | } | |
20916cae TL |
819 | split = atoi (val); |
820 | if (!parse_semi (cfile)) | |
821 | goto badsplit; | |
9e9b2261 TL |
822 | if (split > 255) { |
823 | parse_warn (cfile, "split must be < 256"); | |
824 | } else { | |
825 | memset (hba, 0, sizeof hba); | |
826 | for (i = 0; i < split; i++) { | |
827 | if (i < split) | |
828 | hba [i / 8] |= (1 << (i & 7)); | |
829 | } | |
830 | goto make_hba; | |
831 | } | |
832 | break; | |
833 | ||
e9623235 TL |
834 | case LOAD: |
835 | token = next_token (&val, cfile); | |
836 | if (token != BALANCE) { | |
837 | parse_warn (cfile, "expecting 'balance'"); | |
838 | badload: | |
839 | skip_to_rbrace (cfile, 1); | |
840 | break; | |
841 | } | |
842 | token = next_token (&val, cfile); | |
843 | if (token != TOKEN_MAX) { | |
844 | parse_warn (cfile, "expecting 'max'"); | |
845 | goto badload; | |
846 | } | |
847 | token = next_token (&val, cfile); | |
848 | if (token != SECONDS) { | |
849 | parse_warn (cfile, "expecting 'secs'"); | |
850 | goto badload; | |
851 | } | |
852 | token = next_token (&val, cfile); | |
853 | if (token != NUMBER) { | |
854 | parse_warn (cfile, "expecting number"); | |
855 | goto badload; | |
856 | } | |
857 | peer -> load_balance_max_secs = atoi (val); | |
858 | break; | |
859 | ||
763adef1 | 860 | default: |
35454d8a TL |
861 | parse_warn (cfile, |
862 | "invalid statement in peer declaration"); | |
763adef1 | 863 | skip_to_rbrace (cfile, 1); |
20916cae | 864 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
865 | return; |
866 | } | |
e9623235 TL |
867 | if (token != RBRACE && !parse_semi (cfile)) { |
868 | skip_to_rbrace (cfile, 1); | |
20916cae | 869 | dhcp_failover_state_dereference (&peer, MDL); |
e9623235 TL |
870 | return; |
871 | } | |
763adef1 TL |
872 | } while (token != RBRACE); |
873 | ||
007e3ee4 TL |
874 | if (peer -> i_am == primary && !peer -> hba) { |
875 | parse_warn (cfile, | |
876 | "primary failover server must have hba or split."); | |
877 | } | |
878 | ||
763adef1 TL |
879 | if (type == SHARED_NET_DECL) { |
880 | group -> shared_network -> failover_peer = peer; | |
881 | } | |
e9623235 TL |
882 | status = enter_failover_peer (peer); |
883 | if (status != ISC_R_SUCCESS) | |
884 | parse_warn (cfile, "failover peer %s: %s", | |
885 | peer -> name, isc_result_totext (status)); | |
20916cae | 886 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
887 | } |
888 | ||
a4ba3160 TL |
889 | void parse_failover_state_declaration (struct parse *cfile, |
890 | dhcp_failover_state_t *peer) | |
891 | { | |
892 | enum dhcp_token token; | |
893 | const char *val; | |
894 | char *name; | |
895 | dhcp_failover_state_t *state; | |
896 | ||
897 | if (!peer) { | |
898 | token = next_token (&val, cfile); | |
899 | if (token != PEER) { | |
900 | parse_warn (cfile, "expecting \"peer\""); | |
901 | skip_to_semi (cfile); | |
902 | return; | |
903 | } | |
904 | ||
905 | token = next_token (&val, cfile); | |
906 | if (is_identifier (token) || token == STRING) { | |
907 | name = dmalloc (strlen (val) + 1, MDL); | |
908 | if (!name) | |
909 | log_fatal ("failover peer name %s: no memory", | |
910 | name); | |
911 | strcpy (name, val); | |
912 | } else { | |
913 | parse_warn (cfile, "expecting failover peer name."); | |
914 | skip_to_semi (cfile); | |
915 | return; | |
916 | } | |
917 | ||
918 | /* See if there's a peer declaration by this name. */ | |
919 | state = (dhcp_failover_state_t *)0; | |
20916cae | 920 | find_failover_peer (&state, name, MDL); |
a4ba3160 TL |
921 | if (!state) { |
922 | parse_warn (cfile, "unknown failover peer: %s", name); | |
923 | skip_to_semi (cfile); | |
924 | return; | |
925 | } | |
926 | ||
927 | token = next_token (&val, cfile); | |
928 | if (token != STATE) { | |
929 | parse_warn (cfile, "expecting 'state'"); | |
930 | if (token != SEMI) | |
931 | skip_to_semi (cfile); | |
932 | return; | |
933 | } | |
20916cae TL |
934 | } else { |
935 | state = (dhcp_failover_state_t *)0; | |
936 | dhcp_failover_state_reference (&state, peer, MDL); | |
937 | } | |
a4ba3160 TL |
938 | token = next_token (&val, cfile); |
939 | if (token != LBRACE) { | |
940 | parse_warn (cfile, "expecting left brace"); | |
941 | if (token != SEMI) | |
942 | skip_to_semi (cfile); | |
20916cae | 943 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
944 | return; |
945 | } | |
946 | do { | |
947 | token = next_token (&val, cfile); | |
948 | switch (token) { | |
949 | case RBRACE: | |
950 | break; | |
951 | case MY: | |
952 | token = next_token (&val, cfile); | |
953 | if (token != STATE) { | |
954 | parse_warn (cfile, "expecting 'state'"); | |
20916cae | 955 | goto bogus; |
a4ba3160 TL |
956 | } |
957 | parse_failover_state (cfile, | |
958 | &state -> my_state, | |
959 | &state -> my_stos); | |
960 | break; | |
961 | case PARTNER: | |
962 | token = next_token (&val, cfile); | |
963 | if (token != STATE) { | |
964 | parse_warn (cfile, "expecting 'state'"); | |
20916cae | 965 | goto bogus; |
a4ba3160 TL |
966 | } |
967 | parse_failover_state (cfile, | |
968 | &state -> partner_state, | |
969 | &state -> partner_stos); | |
970 | break; | |
971 | default: | |
20916cae | 972 | bogus: |
a4ba3160 | 973 | parse_warn (cfile, "expecting state setting."); |
20916cae TL |
974 | skip_to_rbrace (cfile, 1); |
975 | dhcp_failover_state_dereference (&state, MDL); | |
a4ba3160 TL |
976 | return; |
977 | } | |
978 | } while (token != RBRACE); | |
20916cae | 979 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
980 | } |
981 | ||
9e9b2261 | 982 | void parse_failover_state (cfile, state, stos) |
35454d8a | 983 | struct parse *cfile; |
9e9b2261 TL |
984 | enum failover_state *state; |
985 | TIME *stos; | |
763adef1 TL |
986 | { |
987 | enum dhcp_token token; | |
b1b7b521 | 988 | const char *val; |
9e9b2261 TL |
989 | enum failover_state state_in; |
990 | TIME stos_in; | |
763adef1 TL |
991 | |
992 | token = next_token (&val, cfile); | |
993 | switch (token) { | |
994 | case PARTNER_DOWN: | |
9e9b2261 TL |
995 | state_in = partner_down; |
996 | break; | |
997 | ||
763adef1 | 998 | case NORMAL: |
9e9b2261 TL |
999 | state_in = normal; |
1000 | break; | |
1001 | ||
763adef1 | 1002 | case COMMUNICATIONS_INTERRUPTED: |
9e9b2261 TL |
1003 | state_in = communications_interrupted; |
1004 | break; | |
1005 | ||
763adef1 | 1006 | case POTENTIAL_CONFLICT: |
9e9b2261 TL |
1007 | state_in = potential_conflict; |
1008 | break; | |
1009 | ||
a4ba3160 TL |
1010 | case POTENTIAL_CONFLICT_NIC: |
1011 | state_in = potential_conflict; | |
1012 | break; | |
1013 | ||
763adef1 | 1014 | case RECOVER: |
9e9b2261 TL |
1015 | state_in = recover; |
1016 | break; | |
a4ba3160 TL |
1017 | |
1018 | case UNKNOWN_STATE: | |
1019 | state_in = unknown_state; | |
1020 | break; | |
9e9b2261 | 1021 | |
763adef1 | 1022 | default: |
35454d8a | 1023 | parse_warn (cfile, "unknown failover state"); |
9e9b2261 TL |
1024 | skip_to_semi (cfile); |
1025 | return; | |
763adef1 | 1026 | } |
9e9b2261 TL |
1027 | |
1028 | token = next_token (&val, cfile); | |
1029 | if (token != AT) { | |
1030 | parse_warn (cfile, "expecting \"at\""); | |
1031 | skip_to_semi (cfile); | |
1032 | return; | |
1033 | } | |
1034 | ||
1035 | stos_in = parse_date (cfile); | |
1036 | if (!stos_in) | |
1037 | return; | |
1038 | ||
1039 | /* Now that we've apparently gotten a clean parse, we can trust | |
1040 | that this is a state that was fully committed to disk, so | |
1041 | we can install it. */ | |
1042 | *stos = stos_in; | |
1043 | *state = state_in; | |
763adef1 TL |
1044 | } |
1045 | #endif /* defined (FAILOVER_PROTOCOL) */ | |
1046 | ||
f63b4929 | 1047 | void parse_pool_statement (cfile, group, type) |
35454d8a | 1048 | struct parse *cfile; |
f63b4929 TL |
1049 | struct group *group; |
1050 | int type; | |
1051 | { | |
1052 | enum dhcp_token token; | |
b1b7b521 | 1053 | const char *val; |
f63b4929 TL |
1054 | int done = 0; |
1055 | struct pool *pool, **p; | |
1056 | struct permit *permit; | |
1057 | struct permit **permit_head; | |
74f45f96 | 1058 | int declaration = 0; |
e9623235 | 1059 | isc_result_t status; |
f63b4929 | 1060 | |
20916cae TL |
1061 | pool = (struct pool *)0; |
1062 | status = pool_allocate (&pool, MDL); | |
1063 | if (status != ISC_R_SUCCESS) | |
6ceb9118 TL |
1064 | log_fatal ("no memory for pool: %s", |
1065 | isc_result_totext (status)); | |
f63b4929 | 1066 | |
f84d544b | 1067 | if (!clone_group (&pool -> group, group, MDL)) |
6ceb9118 | 1068 | log_fatal ("can't clone pool group."); |
74f45f96 | 1069 | |
9e9b2261 | 1070 | if (type == SUBNET_DECL) |
20916cae TL |
1071 | shared_network_reference (&pool -> shared_network, |
1072 | group -> subnet -> shared_network, | |
1073 | MDL); | |
9e9b2261 | 1074 | else |
20916cae TL |
1075 | shared_network_reference (&pool -> shared_network, |
1076 | group -> shared_network, MDL); | |
9e9b2261 | 1077 | |
22009f79 | 1078 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 TL |
1079 | /* Inherit the failover peer from the shared network. */ |
1080 | if (pool -> shared_network -> failover_peer) | |
20916cae TL |
1081 | dhcp_failover_state_reference |
1082 | (&pool -> failover_peer, | |
1083 | pool -> shared_network -> failover_peer, MDL); | |
22009f79 | 1084 | #endif |
9e9b2261 | 1085 | |
20916cae TL |
1086 | if (!parse_lbrace (cfile)) { |
1087 | pool_dereference (&pool, MDL); | |
f63b4929 | 1088 | return; |
20916cae TL |
1089 | } |
1090 | ||
f63b4929 | 1091 | do { |
e5e41be4 TL |
1092 | token = peek_token (&val, cfile); |
1093 | switch (token) { | |
9e9b2261 TL |
1094 | case NO: |
1095 | next_token (&val, cfile); | |
1096 | token = next_token (&val, cfile); | |
1097 | if (token != FAILOVER || | |
1098 | (token = next_token (&val, cfile)) != PEER) { | |
1099 | parse_warn (cfile, | |
1100 | "expecting \"failover peer\"."); | |
1101 | skip_to_semi (cfile); | |
1102 | continue; | |
1103 | } | |
22009f79 | 1104 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 | 1105 | if (pool -> failover_peer) |
20916cae TL |
1106 | dhcp_failover_state_dereference |
1107 | (&pool -> failover_peer, MDL); | |
22009f79 | 1108 | #endif |
9e9b2261 TL |
1109 | break; |
1110 | ||
a4ba3160 | 1111 | #if defined (FAILOVER_PROTOCOL) |
e9623235 TL |
1112 | case FAILOVER: |
1113 | next_token (&val, cfile); | |
1114 | token = next_token (&val, cfile); | |
1115 | if (token != PEER) { | |
1116 | parse_warn (cfile, "expecting 'peer'."); | |
1117 | skip_to_semi (cfile); | |
1118 | break; | |
1119 | } | |
1120 | token = next_token (&val, cfile); | |
1121 | if (token != STRING) { | |
1122 | parse_warn (cfile, "expecting string."); | |
1123 | skip_to_semi (cfile); | |
1124 | break; | |
1125 | } | |
1126 | if (pool -> failover_peer) | |
20916cae TL |
1127 | dhcp_failover_state_dereference |
1128 | (&pool -> failover_peer, MDL); | |
e9623235 | 1129 | status = find_failover_peer (&pool -> failover_peer, |
20916cae | 1130 | val, MDL); |
e9623235 TL |
1131 | if (status != ISC_R_SUCCESS) |
1132 | parse_warn (cfile, | |
1133 | "failover peer %s: %s", val, | |
1134 | isc_result_totext (status)); | |
1135 | parse_semi (cfile); | |
1136 | break; | |
a4ba3160 | 1137 | #endif |
e9623235 | 1138 | |
f63b4929 TL |
1139 | case RANGE: |
1140 | next_token (&val, cfile); | |
1141 | parse_address_range (cfile, group, type, pool); | |
1142 | break; | |
1143 | case ALLOW: | |
1144 | permit_head = &pool -> permit_list; | |
1145 | get_permit: | |
436f1c8c | 1146 | permit = new_permit (MDL); |
f63b4929 | 1147 | if (!permit) |
8ae2d595 | 1148 | log_fatal ("no memory for permit"); |
f63b4929 TL |
1149 | next_token (&val, cfile); |
1150 | token = next_token (&val, cfile); | |
1151 | switch (token) { | |
1152 | case UNKNOWN: | |
1153 | permit -> type = permit_unknown_clients; | |
1154 | get_clients: | |
1155 | if (next_token (&val, cfile) != CLIENTS) { | |
35454d8a TL |
1156 | parse_warn (cfile, |
1157 | "expecting \"clients\""); | |
f63b4929 | 1158 | skip_to_semi (cfile); |
436f1c8c | 1159 | free_permit (permit, MDL); |
f63b4929 TL |
1160 | continue; |
1161 | } | |
1162 | break; | |
1163 | ||
ad1a6484 TL |
1164 | case UNKNOWN_CLIENTS: |
1165 | permit -> type = permit_unknown_clients; | |
1166 | break; | |
1167 | ||
f63b4929 TL |
1168 | case KNOWN: |
1169 | permit -> type = permit_known_clients; | |
1170 | goto get_clients; | |
1171 | ||
1172 | case AUTHENTICATED: | |
1173 | permit -> type = permit_authenticated_clients; | |
1174 | goto get_clients; | |
1175 | ||
1176 | case UNAUTHENTICATED: | |
1177 | permit -> type = | |
1178 | permit_unauthenticated_clients; | |
1179 | goto get_clients; | |
1180 | ||
1181 | case ALL: | |
1182 | permit -> type = permit_all_clients; | |
1183 | goto get_clients; | |
1184 | break; | |
1185 | ||
1186 | case DYNAMIC: | |
1187 | permit -> type = permit_dynamic_bootp_clients; | |
007e3ee4 | 1188 | if (next_token (&val, cfile) != TOKEN_BOOTP) { |
35454d8a TL |
1189 | parse_warn (cfile, |
1190 | "expecting \"bootp\""); | |
f63b4929 | 1191 | skip_to_semi (cfile); |
436f1c8c | 1192 | free_permit (permit, MDL); |
f63b4929 TL |
1193 | continue; |
1194 | } | |
1195 | goto get_clients; | |
1196 | ||
1197 | case MEMBERS: | |
1198 | if (next_token (&val, cfile) != OF) { | |
35454d8a | 1199 | parse_warn (cfile, "expecting \"of\""); |
f63b4929 | 1200 | skip_to_semi (cfile); |
436f1c8c | 1201 | free_permit (permit, MDL); |
f63b4929 TL |
1202 | continue; |
1203 | } | |
1204 | if (next_token (&val, cfile) != STRING) { | |
35454d8a TL |
1205 | parse_warn (cfile, |
1206 | "expecting class name."); | |
f63b4929 | 1207 | skip_to_semi (cfile); |
436f1c8c | 1208 | free_permit (permit, MDL); |
f63b4929 TL |
1209 | continue; |
1210 | } | |
1211 | permit -> type = permit_class; | |
20916cae TL |
1212 | permit -> class = (struct class *)0; |
1213 | find_class (&permit -> class, val, MDL); | |
f63b4929 | 1214 | if (!permit -> class) |
35454d8a TL |
1215 | parse_warn (cfile, |
1216 | "no such class: %s", val); | |
e5e41be4 TL |
1217 | break; |
1218 | ||
f63b4929 | 1219 | default: |
35454d8a | 1220 | parse_warn (cfile, "expecting permit type."); |
f63b4929 TL |
1221 | skip_to_semi (cfile); |
1222 | break; | |
1223 | } | |
1224 | while (*permit_head) | |
1225 | permit_head = &((*permit_head) -> next); | |
1226 | *permit_head = permit; | |
74f45f96 | 1227 | parse_semi (cfile); |
f63b4929 TL |
1228 | break; |
1229 | ||
1230 | case DENY: | |
1231 | permit_head = &pool -> prohibit_list; | |
1232 | goto get_permit; | |
1233 | ||
1234 | case RBRACE: | |
1235 | next_token (&val, cfile); | |
1236 | done = 1; | |
1237 | break; | |
1238 | ||
1239 | default: | |
74f45f96 TL |
1240 | declaration = parse_statement (cfile, pool -> group, |
1241 | POOL_DECL, | |
1242 | (struct host_decl *)0, | |
1243 | declaration); | |
f63b4929 TL |
1244 | break; |
1245 | } | |
1246 | } while (!done); | |
1247 | ||
9e9b2261 TL |
1248 | #if defined (FAILOVER_PROTOCOL) |
1249 | /* We can't do failover on a pool that supports dynamic bootp, | |
1250 | because BOOTP doesn't support leases, and failover absolutely | |
1251 | depends on lease timing. */ | |
1252 | if (pool -> failover_peer) { | |
1253 | for (permit = pool -> permit_list; | |
1254 | permit; permit = permit -> next) { | |
1255 | if (permit -> type == permit_dynamic_bootp_clients || | |
1256 | permit -> type == permit_all_clients) { | |
1257 | dynamic_bootp_clash: | |
1258 | parse_warn (cfile, | |
1259 | "pools with failover peers %s", | |
1260 | "may not permit dynamic bootp."); | |
e9623235 | 1261 | log_error ("Either write a \"no failover\" %s", |
9e9b2261 TL |
1262 | "statement and use disjoint"); |
1263 | log_error ("pools, or don't permit dynamic%s", | |
e9623235 | 1264 | " bootp."); |
9e9b2261 | 1265 | log_error ("This is a protocol limitation,%s", |
e9623235 | 1266 | " not an ISC DHCP limitation, so"); |
9e9b2261 TL |
1267 | log_error ("please don't request an %s", |
1268 | "enhancement or ask why this is."); | |
1269 | goto clash_testing_done; | |
1270 | } | |
1271 | } | |
1272 | if (!pool -> permit_list) { | |
1273 | if (!pool -> prohibit_list) | |
1274 | goto dynamic_bootp_clash; | |
1275 | ||
1276 | for (permit = pool -> prohibit_list; permit; | |
1277 | permit = permit -> next) { | |
1278 | if (permit -> type == | |
1279 | permit_dynamic_bootp_clients || | |
1280 | permit -> type == permit_all_clients) | |
1281 | goto clash_testing_done; | |
1282 | } | |
1283 | } | |
1284 | } | |
1285 | clash_testing_done: | |
1286 | #endif /* FAILOVER_PROTOCOL */ | |
1287 | ||
f63b4929 TL |
1288 | p = &pool -> shared_network -> pools; |
1289 | for (; *p; p = &((*p) -> next)) | |
1290 | ; | |
20916cae TL |
1291 | pool_reference (p, pool, MDL); |
1292 | pool_dereference (&pool, MDL); | |
f63b4929 TL |
1293 | } |
1294 | ||
5376e3e9 TL |
1295 | /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ |
1296 | ||
1297 | int parse_boolean (cfile) | |
35454d8a | 1298 | struct parse *cfile; |
5376e3e9 | 1299 | { |
6f8fb41f | 1300 | enum dhcp_token token; |
b1b7b521 | 1301 | const char *val; |
5376e3e9 TL |
1302 | int rv; |
1303 | ||
1304 | token = next_token (&val, cfile); | |
1305 | if (!strcasecmp (val, "true") | |
1306 | || !strcasecmp (val, "on")) | |
b179c997 | 1307 | rv = 1; |
5376e3e9 TL |
1308 | else if (!strcasecmp (val, "false") |
1309 | || !strcasecmp (val, "off")) | |
1310 | rv = 0; | |
1311 | else { | |
35454d8a TL |
1312 | parse_warn (cfile, |
1313 | "boolean value (true/false/on/off) expected"); | |
5376e3e9 TL |
1314 | skip_to_semi (cfile); |
1315 | return 0; | |
1316 | } | |
1317 | parse_semi (cfile); | |
1318 | return rv; | |
1319 | } | |
1320 | ||
7dfc8ac2 TL |
1321 | /* Expect a left brace; if there isn't one, skip over the rest of the |
1322 | statement and return zero; otherwise, return 1. */ | |
1323 | ||
1324 | int parse_lbrace (cfile) | |
35454d8a | 1325 | struct parse *cfile; |
7dfc8ac2 | 1326 | { |
6f8fb41f | 1327 | enum dhcp_token token; |
b1b7b521 | 1328 | const char *val; |
7dfc8ac2 TL |
1329 | |
1330 | token = next_token (&val, cfile); | |
1331 | if (token != LBRACE) { | |
35454d8a | 1332 | parse_warn (cfile, "expecting left brace."); |
7dfc8ac2 TL |
1333 | skip_to_semi (cfile); |
1334 | return 0; | |
1335 | } | |
1336 | return 1; | |
d7837182 TL |
1337 | } |
1338 | ||
7dfc8ac2 | 1339 | |
2d59f590 | 1340 | /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ |
d7837182 | 1341 | |
2d59f590 | 1342 | void parse_host_declaration (cfile, group) |
35454d8a | 1343 | struct parse *cfile; |
7dfc8ac2 | 1344 | struct group *group; |
d7837182 | 1345 | { |
b1b7b521 | 1346 | const char *val; |
6f8fb41f | 1347 | enum dhcp_token token; |
7dfc8ac2 | 1348 | struct host_decl *host; |
f3c3d674 | 1349 | char *name; |
2d59f590 | 1350 | int declaration = 0; |
612fded7 | 1351 | int dynamicp = 0; |
ff129930 | 1352 | int deleted = 0; |
92ce3f81 | 1353 | isc_result_t status; |
7dfc8ac2 | 1354 | |
20916cae TL |
1355 | name = parse_host_name (cfile); |
1356 | if (!name) | |
1357 | return; | |
7dfc8ac2 | 1358 | |
20916cae TL |
1359 | host = (struct host_decl *)0; |
1360 | status = host_allocate (&host, MDL); | |
1361 | if (status != ISC_R_SUCCESS) | |
1362 | log_fatal ("can't allocate host decl struct %s: %s", | |
1363 | name, isc_result_totext (status)); | |
7dfc8ac2 | 1364 | host -> name = name; |
f84d544b TL |
1365 | if (!clone_group (&host -> group, group, MDL)) { |
1366 | log_fatal ("can't clone group for host %s", name); | |
20916cae TL |
1367 | boom: |
1368 | host_dereference (&host, MDL); | |
1369 | return; | |
1370 | } | |
7dfc8ac2 TL |
1371 | |
1372 | if (!parse_lbrace (cfile)) | |
20916cae | 1373 | goto boom; |
d7837182 | 1374 | |
d7837182 TL |
1375 | do { |
1376 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 1377 | if (token == RBRACE) { |
d7837182 TL |
1378 | token = next_token (&val, cfile); |
1379 | break; | |
1380 | } | |
5376e3e9 TL |
1381 | if (token == EOF) { |
1382 | token = next_token (&val, cfile); | |
35454d8a | 1383 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
1384 | break; |
1385 | } | |
612fded7 TL |
1386 | /* If the host declaration was created by the server, |
1387 | remember to save it. */ | |
1388 | if (token == DYNAMIC) { | |
1389 | dynamicp = 1; | |
1390 | token = next_token (&val, cfile); | |
1391 | if (!parse_semi (cfile)) | |
1392 | break; | |
1393 | continue; | |
1394 | } | |
ff129930 TL |
1395 | /* If the host declaration was created by the server, |
1396 | remember to save it. */ | |
007e3ee4 | 1397 | if (token == TOKEN_DELETED) { |
ff129930 TL |
1398 | deleted = 1; |
1399 | token = next_token (&val, cfile); | |
1400 | if (!parse_semi (cfile)) | |
1401 | break; | |
1402 | continue; | |
1403 | } | |
29c35bed TL |
1404 | |
1405 | if (token == GROUP) { | |
1406 | struct group_object *go; | |
1407 | token = next_token (&val, cfile); | |
1408 | token = next_token (&val, cfile); | |
1409 | if (token != STRING && !is_identifier (token)) { | |
35454d8a TL |
1410 | parse_warn (cfile, |
1411 | "expecting string or identifier."); | |
29c35bed TL |
1412 | skip_to_rbrace (cfile, 1); |
1413 | break; | |
1414 | } | |
20916cae TL |
1415 | go = (struct group_object *)0; |
1416 | if (!group_hash_lookup (&go, group_name_hash, | |
1417 | val, strlen (val), MDL)) { | |
35454d8a TL |
1418 | parse_warn (cfile, "unknown group %s in host %s", |
1419 | val, host -> name); | |
29c35bed TL |
1420 | } else { |
1421 | if (host -> named_group) | |
20916cae TL |
1422 | group_object_dereference |
1423 | (&host -> named_group, MDL); | |
1424 | group_object_reference (&host -> named_group, | |
1425 | go, MDL); | |
1426 | group_object_dereference (&go, MDL); | |
29c35bed TL |
1427 | } |
1428 | if (!parse_semi (cfile)) | |
1429 | break; | |
1430 | continue; | |
1431 | } | |
1432 | ||
1433 | if (token == UID) { | |
b1b7b521 | 1434 | const char *s; |
29c35bed | 1435 | unsigned char *t = 0; |
b1b7b521 | 1436 | unsigned len; |
29c35bed TL |
1437 | |
1438 | token = next_token (&val, cfile); | |
436f1c8c | 1439 | data_string_forget (&host -> client_identifier, MDL); |
29c35bed TL |
1440 | |
1441 | /* See if it's a string or a cshl. */ | |
1442 | token = peek_token (&val, cfile); | |
1443 | if (token == STRING) { | |
1444 | token = next_token (&val, cfile); | |
1445 | s = val; | |
1446 | len = strlen (val); | |
1447 | host -> client_identifier.terminated = 1; | |
1448 | } else { | |
1449 | len = 0; | |
1450 | t = parse_numeric_aggregate | |
1451 | (cfile, | |
1452 | (unsigned char *)0, &len, ':', 16, 8); | |
1453 | if (!t) { | |
35454d8a TL |
1454 | parse_warn (cfile, |
1455 | "expecting hex list."); | |
29c35bed TL |
1456 | skip_to_semi (cfile); |
1457 | } | |
b1b7b521 | 1458 | s = (const char *)t; |
29c35bed TL |
1459 | } |
1460 | if (!buffer_allocate | |
1461 | (&host -> client_identifier.buffer, | |
436f1c8c | 1462 | len + host -> client_identifier.terminated, MDL)) |
29c35bed TL |
1463 | log_fatal ("no memory for uid for host %s.", |
1464 | host -> name); | |
1465 | host -> client_identifier.data = | |
1466 | host -> client_identifier.buffer -> data; | |
1467 | host -> client_identifier.len = len; | |
b1b7b521 | 1468 | memcpy (host -> client_identifier.buffer -> data, s, |
29c35bed TL |
1469 | len + host -> client_identifier.terminated); |
1470 | if (t) | |
436f1c8c | 1471 | dfree (t, MDL); |
29c35bed TL |
1472 | |
1473 | if (!parse_semi (cfile)) | |
1474 | break; | |
1475 | continue; | |
1476 | } | |
2d59f590 TL |
1477 | declaration = parse_statement (cfile, host -> group, |
1478 | HOST_DECL, host, | |
1479 | declaration); | |
d7837182 | 1480 | } while (1); |
7dfc8ac2 | 1481 | |
ff129930 | 1482 | if (deleted) { |
20916cae TL |
1483 | struct host_decl *hp = (struct host_decl *)0; |
1484 | if (host_hash_lookup (&hp, host_name_hash, | |
1485 | (unsigned char *)host -> name, | |
1486 | strlen (host -> name), MDL)) { | |
ff129930 | 1487 | delete_host (hp, 0); |
20916cae | 1488 | host_dereference (&hp, MDL); |
ff129930 | 1489 | } |
ff129930 | 1490 | } else { |
29c35bed TL |
1491 | if (host -> named_group && host -> named_group -> group) { |
1492 | if (host -> group -> statements || | |
1493 | (host -> group -> authoritative != | |
b83bf1d1 TL |
1494 | host -> named_group -> group -> authoritative)) { |
1495 | if (host -> group -> next) | |
1496 | group_dereference (&host -> group -> next, | |
1497 | MDL); | |
20916cae TL |
1498 | group_reference (&host -> group -> next, |
1499 | host -> named_group -> group, | |
1500 | MDL); | |
b83bf1d1 | 1501 | } else { |
20916cae TL |
1502 | group_dereference (&host -> group, MDL); |
1503 | group_reference (&host -> group, | |
1504 | host -> named_group -> group, | |
1505 | MDL); | |
29c35bed TL |
1506 | } |
1507 | } | |
1508 | ||
b86799bf TL |
1509 | if (dynamicp) |
1510 | host -> flags |= HOST_DECL_DYNAMIC; | |
1511 | else | |
1512 | host -> flags |= HOST_DECL_STATIC; | |
1513 | ||
92ce3f81 TL |
1514 | status = enter_host (host, dynamicp, 0); |
1515 | if (status != ISC_R_SUCCESS) | |
ab58ff49 TL |
1516 | parse_warn (cfile, "host %s: %s", host -> name, |
1517 | isc_result_totext (status)); | |
ff129930 | 1518 | } |
20916cae | 1519 | host_dereference (&host, MDL); |
d7837182 TL |
1520 | } |
1521 | ||
2d59f590 | 1522 | /* class-declaration :== STRING LBRACE parameters declarations RBRACE |
24a75c03 TL |
1523 | */ |
1524 | ||
20916cae TL |
1525 | int parse_class_declaration (cp, cfile, group, type) |
1526 | struct class **cp; | |
35454d8a | 1527 | struct parse *cfile; |
7dfc8ac2 | 1528 | struct group *group; |
24a75c03 TL |
1529 | int type; |
1530 | { | |
b1b7b521 | 1531 | const char *val; |
6f8fb41f | 1532 | enum dhcp_token token; |
20916cae | 1533 | struct class *class = (struct class *)0, *pc = (struct class *)0; |
f4d0f440 | 1534 | int declaration = 0; |
e5e41be4 | 1535 | int lose = 0; |
ece6ea33 | 1536 | struct data_string data; |
b1b7b521 | 1537 | const char *name; |
ece6ea33 TL |
1538 | struct executable_statement *stmt = (struct executable_statement *)0; |
1539 | struct expression *expr; | |
de94ca72 | 1540 | int new = 1; |
20916cae | 1541 | isc_result_t status; |
24a75c03 TL |
1542 | |
1543 | token = next_token (&val, cfile); | |
1544 | if (token != STRING) { | |
35454d8a | 1545 | parse_warn (cfile, "Expecting class name"); |
24a75c03 | 1546 | skip_to_semi (cfile); |
20916cae | 1547 | return 0; |
24a75c03 TL |
1548 | } |
1549 | ||
ece6ea33 | 1550 | /* See if there's already a class with the specified name. */ |
20916cae | 1551 | find_class (&pc, val, MDL); |
ece6ea33 TL |
1552 | |
1553 | /* If this isn't a subclass, we're updating an existing class. */ | |
1554 | if (pc && type != 0 && type != 1 && type != 3) { | |
20916cae | 1555 | class_reference (&class, pc, MDL); |
de94ca72 | 1556 | new = 0; |
20916cae | 1557 | class_dereference (&pc, MDL); |
ece6ea33 TL |
1558 | } |
1559 | ||
1560 | /* If this _is_ a subclass, there _must_ be a class with the | |
1561 | same name. */ | |
1562 | if (!pc && (type == 0 || type == 1 || type == 3)) { | |
35454d8a | 1563 | parse_warn (cfile, "no class named %s", val); |
ece6ea33 | 1564 | skip_to_semi (cfile); |
20916cae | 1565 | return 0; |
ece6ea33 TL |
1566 | } |
1567 | ||
1568 | /* The old vendor-class and user-class declarations had an implicit | |
1569 | match. We don't do the implicit match anymore. Instead, for | |
1570 | backward compatibility, we have an implicit-vendor-class and an | |
1571 | implicit-user-class. vendor-class and user-class declarations | |
1572 | are turned into subclasses of the implicit classes, and the | |
8b500185 | 1573 | submatch expression of the implicit classes extracts the contents of |
ece6ea33 TL |
1574 | the vendor class or user class. */ |
1575 | if (type == 0 || type == 1) { | |
1576 | data.len = strlen (val); | |
6f8fb41f | 1577 | data.buffer = (struct buffer *)0; |
436f1c8c | 1578 | if (!buffer_allocate (&data.buffer, data.len + 1, MDL)) |
20916cae | 1579 | log_fatal ("no memory for class name."); |
6f8fb41f | 1580 | data.data = &data.buffer -> data [0]; |
ece6ea33 TL |
1581 | data.terminated = 1; |
1582 | ||
1583 | name = type ? "implicit-vendor-class" : "implicit-user-class"; | |
1584 | } else if (type == 2) { | |
20916cae TL |
1585 | name = val; |
1586 | } else { | |
1587 | name = (char *)0; | |
1588 | } | |
1589 | ||
1590 | if (name) { | |
b1b7b521 | 1591 | char *tname; |
436f1c8c | 1592 | if (!(tname = dmalloc (strlen (val) + 1, MDL))) |
8ae2d595 | 1593 | log_fatal ("No memory for class name %s.", val); |
b1b7b521 TL |
1594 | strcpy (tname, val); |
1595 | name = tname; | |
ece6ea33 TL |
1596 | } |
1597 | ||
1598 | /* If this is a straight subclass, parse the hash string. */ | |
1599 | if (type == 3) { | |
1600 | token = peek_token (&val, cfile); | |
1601 | if (token == STRING) { | |
1602 | token = next_token (&val, cfile); | |
1603 | data.len = strlen (val); | |
6f8fb41f | 1604 | data.buffer = (struct buffer *)0; |
20916cae TL |
1605 | if (!buffer_allocate (&data.buffer, |
1606 | data.len + 1, MDL)) { | |
1607 | if (pc) | |
1608 | class_dereference (&pc, MDL); | |
1609 | ||
1610 | return 0; | |
1611 | } | |
ece6ea33 | 1612 | data.terminated = 1; |
6f8fb41f | 1613 | data.data = &data.buffer -> data [0]; |
b1b7b521 | 1614 | strcpy ((char *)data.buffer -> data, val); |
ece6ea33 | 1615 | } else if (token == NUMBER_OR_NAME || token == NUMBER) { |
6f8fb41f | 1616 | memset (&data, 0, sizeof data); |
20916cae TL |
1617 | if (!parse_cshl (&data, cfile)) { |
1618 | class_dereference (&pc, MDL); | |
1619 | } | |
1620 | return 0; | |
e68de775 | 1621 | } else { |
35454d8a | 1622 | parse_warn (cfile, "Expecting string or hex list."); |
20916cae TL |
1623 | class_dereference (&pc, MDL); |
1624 | return 0; | |
ece6ea33 TL |
1625 | } |
1626 | } | |
1627 | ||
1628 | /* See if there's already a class in the hash table matching the | |
1629 | hash data. */ | |
1630 | if (type == 0 || type == 1 || type == 3) | |
20916cae TL |
1631 | class_hash_lookup (&class, pc -> hash, |
1632 | (const char *)data.data, data.len, MDL); | |
ece6ea33 TL |
1633 | |
1634 | /* If we didn't find an existing class, allocate a new one. */ | |
1635 | if (!class) { | |
1636 | /* Allocate the class structure... */ | |
20916cae | 1637 | status = class_allocate (&class, MDL); |
ece6ea33 | 1638 | if (pc) { |
20916cae TL |
1639 | group_reference (&class -> group, pc -> group, MDL); |
1640 | class_reference (&class -> superclass, pc, MDL); | |
88dcab62 TL |
1641 | class -> lease_limit = pc -> lease_limit; |
1642 | if (class -> lease_limit) { | |
1643 | class -> billed_leases = | |
1644 | dmalloc (class -> lease_limit * | |
436f1c8c | 1645 | sizeof (struct lease *), MDL); |
88dcab62 | 1646 | if (!class -> billed_leases) |
e68de775 | 1647 | log_fatal ("no memory for billing"); |
88dcab62 TL |
1648 | memset (class -> billed_leases, 0, |
1649 | (class -> lease_limit * | |
1650 | sizeof class -> billed_leases)); | |
1651 | } | |
436f1c8c | 1652 | data_string_copy (&class -> hash_string, &data, MDL); |
88dcab62 | 1653 | if (!pc -> hash) |
20916cae TL |
1654 | pc -> hash = |
1655 | new_hash ((hash_reference) | |
1656 | omapi_object_reference, | |
1657 | (hash_dereference) | |
1658 | omapi_object_dereference, 0); | |
ece6ea33 | 1659 | add_hash (pc -> hash, |
88dcab62 TL |
1660 | class -> hash_string.data, |
1661 | class -> hash_string.len, | |
20916cae | 1662 | (void *)class, MDL); |
ece6ea33 | 1663 | } else { |
20916cae TL |
1664 | if (!clone_group (&class -> group, group, MDL)) |
1665 | log_fatal ("no memory to clone class group."); | |
ece6ea33 TL |
1666 | } |
1667 | ||
1668 | /* If this is an implicit vendor or user class, add a | |
1669 | statement that causes the vendor or user class ID to | |
1670 | be sent back in the reply. */ | |
1671 | if (type == 0 || type == 1) { | |
20916cae TL |
1672 | stmt = (struct executable_statement *)0; |
1673 | if (!executable_statement_allocate (&stmt, MDL)) | |
8ae2d595 | 1674 | log_fatal ("no memory for class statement."); |
ece6ea33 | 1675 | stmt -> op = supersede_option_statement; |
6f8fb41f | 1676 | if (option_cache_allocate (&stmt -> data.option, |
436f1c8c | 1677 | MDL)) { |
6f8fb41f TL |
1678 | stmt -> data.option -> data = data; |
1679 | stmt -> data.option -> option = | |
1680 | dhcp_universe.options | |
1681 | [type | |
ca3a51a5 TL |
1682 | ? DHO_VENDOR_CLASS_IDENTIFIER |
1683 | : DHO_USER_CLASS]; | |
6f8fb41f | 1684 | } |
ece6ea33 TL |
1685 | class -> statements = stmt; |
1686 | } | |
de94ca72 TL |
1687 | |
1688 | /* Save the name, if there is one. */ | |
1689 | class -> name = name; | |
ece6ea33 | 1690 | } |
7dfc8ac2 | 1691 | |
88dcab62 | 1692 | if (type == 0 || type == 1 || type == 3) |
436f1c8c | 1693 | data_string_forget (&data, MDL); |
88dcab62 | 1694 | |
20916cae | 1695 | /* Spawned classes don't have to have their own settings. */ |
88dcab62 | 1696 | if (class -> superclass) { |
e68de775 TL |
1697 | token = peek_token (&val, cfile); |
1698 | if (token == SEMI) { | |
1699 | next_token (&val, cfile); | |
20916cae TL |
1700 | if (cp) |
1701 | status = class_reference (cp, class, MDL); | |
1702 | class_dereference (&class, MDL); | |
1703 | return cp ? (status == ISC_R_SUCCESS) : 1; | |
e68de775 TL |
1704 | } |
1705 | /* Give the subclass its own group. */ | |
f84d544b TL |
1706 | if (!clone_group (&class -> group, class -> group, MDL)) |
1707 | log_fatal ("can't clone class group."); | |
1708 | ||
88dcab62 TL |
1709 | } |
1710 | ||
20916cae TL |
1711 | if (!parse_lbrace (cfile)) { |
1712 | class_dereference (&class, MDL); | |
1713 | if (pc) | |
1714 | class_dereference (&pc, MDL); | |
1715 | return 0; | |
1716 | } | |
24a75c03 TL |
1717 | |
1718 | do { | |
1719 | token = peek_token (&val, cfile); | |
7dfc8ac2 | 1720 | if (token == RBRACE) { |
24a75c03 TL |
1721 | token = next_token (&val, cfile); |
1722 | break; | |
5376e3e9 TL |
1723 | } else if (token == EOF) { |
1724 | token = next_token (&val, cfile); | |
35454d8a | 1725 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1726 | break; |
ece6ea33 TL |
1727 | } else if (token == MATCH) { |
1728 | if (pc) { | |
35454d8a TL |
1729 | parse_warn (cfile, |
1730 | "invalid match in subclass."); | |
ece6ea33 TL |
1731 | skip_to_semi (cfile); |
1732 | break; | |
1733 | } | |
1734 | if (class -> expr) { | |
35454d8a | 1735 | parse_warn (cfile, "can't override match."); |
ece6ea33 TL |
1736 | skip_to_semi (cfile); |
1737 | break; | |
1738 | } | |
1739 | token = next_token (&val, cfile); | |
e68de775 | 1740 | token = peek_token (&val, cfile); |
8b500185 TL |
1741 | if (token != IF) |
1742 | goto submatch; | |
e68de775 | 1743 | token = next_token (&val, cfile); |
6f8fb41f TL |
1744 | parse_boolean_expression (&class -> expr, cfile, |
1745 | &lose); | |
ece6ea33 TL |
1746 | if (lose) |
1747 | break; | |
6f8fb41f TL |
1748 | #if defined (DEBUG_EXPRESSION_PARSE) |
1749 | print_expression ("class match", class -> expr); | |
1750 | #endif | |
de94ca72 | 1751 | parse_semi (cfile); |
ece6ea33 TL |
1752 | } else if (token == SPAWN) { |
1753 | if (pc) { | |
35454d8a TL |
1754 | parse_warn (cfile, |
1755 | "invalid spawn in subclass."); | |
ece6ea33 TL |
1756 | skip_to_semi (cfile); |
1757 | break; | |
1758 | } | |
ece6ea33 TL |
1759 | token = next_token (&val, cfile); |
1760 | token = next_token (&val, cfile); | |
1761 | if (token != WITH) { | |
35454d8a TL |
1762 | parse_warn (cfile, |
1763 | "expecting with after spawn"); | |
ece6ea33 TL |
1764 | skip_to_semi (cfile); |
1765 | break; | |
1766 | } | |
8b500185 TL |
1767 | class -> spawning = 1; |
1768 | submatch: | |
1769 | if (class -> submatch) { | |
35454d8a TL |
1770 | parse_warn (cfile, |
1771 | "can't override existing %s.", | |
8b500185 TL |
1772 | "submatch/spawn"); |
1773 | skip_to_semi (cfile); | |
1774 | break; | |
1775 | } | |
1776 | parse_data_expression (&class -> submatch, | |
1777 | cfile, &lose); | |
ece6ea33 TL |
1778 | if (lose) |
1779 | break; | |
6f8fb41f | 1780 | #if defined (DEBUG_EXPRESSION_PARSE) |
8b500185 TL |
1781 | print_expression ("class submatch", |
1782 | class -> submatch); | |
6f8fb41f | 1783 | #endif |
de94ca72 | 1784 | parse_semi (cfile); |
88dcab62 TL |
1785 | } else if (token == LEASE) { |
1786 | next_token (&val, cfile); | |
1787 | token = next_token (&val, cfile); | |
1788 | if (token != LIMIT) { | |
35454d8a | 1789 | parse_warn (cfile, "expecting \"limit\""); |
88dcab62 TL |
1790 | if (token != SEMI) |
1791 | skip_to_semi (cfile); | |
1792 | break; | |
1793 | } | |
1794 | token = next_token (&val, cfile); | |
1795 | if (token != NUMBER) { | |
35454d8a | 1796 | parse_warn (cfile, "expecting a number"); |
88dcab62 TL |
1797 | if (token != SEMI) |
1798 | skip_to_semi (cfile); | |
1799 | break; | |
1800 | } | |
1801 | class -> lease_limit = atoi (val); | |
1802 | class -> billed_leases = | |
1803 | dmalloc (class -> lease_limit * | |
436f1c8c | 1804 | sizeof (struct lease *), MDL); |
88dcab62 | 1805 | if (!class -> billed_leases) |
8ae2d595 | 1806 | log_fatal ("no memory for billed leases."); |
88dcab62 TL |
1807 | memset (class -> billed_leases, 0, |
1808 | (class -> lease_limit * | |
1809 | sizeof class -> billed_leases)); | |
1810 | have_billing_classes = 1; | |
1811 | parse_semi (cfile); | |
24a75c03 | 1812 | } else { |
2d59f590 TL |
1813 | declaration = parse_statement (cfile, class -> group, |
1814 | CLASS_DECL, | |
1815 | (struct host_decl *)0, | |
1816 | declaration); | |
24a75c03 TL |
1817 | } |
1818 | } while (1); | |
de94ca72 TL |
1819 | if (type == 2 && new) { |
1820 | if (!collections -> classes) | |
20916cae | 1821 | class_reference (&collections -> classes, class, MDL); |
de94ca72 | 1822 | else { |
20916cae TL |
1823 | struct class *c; |
1824 | for (c = collections -> classes; | |
1825 | c -> nic; c = c -> nic) | |
de94ca72 | 1826 | ; |
20916cae | 1827 | class_reference (&c -> nic, class, MDL); |
de94ca72 TL |
1828 | } |
1829 | } | |
20916cae TL |
1830 | if (cp) |
1831 | status = class_reference (cp, class, MDL); | |
1832 | class_dereference (&class, MDL); | |
1833 | if (pc) | |
1834 | class_dereference (&pc, MDL); | |
1835 | return cp ? (status == ISC_R_SUCCESS) : 1; | |
24a75c03 TL |
1836 | } |
1837 | ||
2d59f590 TL |
1838 | /* shared-network-declaration :== |
1839 | hostname LBRACE declarations parameters RBRACE */ | |
1f814ff2 | 1840 | |
2d59f590 | 1841 | void parse_shared_net_declaration (cfile, group) |
35454d8a | 1842 | struct parse *cfile; |
7dfc8ac2 | 1843 | struct group *group; |
1f814ff2 | 1844 | { |
b1b7b521 | 1845 | const char *val; |
6f8fb41f | 1846 | enum dhcp_token token; |
1f814ff2 | 1847 | struct shared_network *share; |
1f814ff2 | 1848 | char *name; |
2d59f590 | 1849 | int declaration = 0; |
20916cae | 1850 | isc_result_t status; |
1f814ff2 | 1851 | |
20916cae TL |
1852 | share = (struct shared_network *)0; |
1853 | status = shared_network_allocate (&share, MDL); | |
1854 | if (status != ISC_R_SUCCESS) | |
1855 | log_fatal ("Can't allocate shared subnet: %s", | |
1856 | isc_result_totext (status)); | |
1857 | clone_group (&share -> group, group, MDL); | |
1858 | shared_network_reference (&share -> group -> shared_network, | |
1859 | share, MDL); | |
1f814ff2 TL |
1860 | |
1861 | /* Get the name of the shared network... */ | |
7dfc8ac2 TL |
1862 | token = peek_token (&val, cfile); |
1863 | if (token == STRING) { | |
1864 | token = next_token (&val, cfile); | |
1865 | ||
1866 | if (val [0] == 0) { | |
35454d8a | 1867 | parse_warn (cfile, "zero-length shared network name"); |
7dfc8ac2 TL |
1868 | val = "<no-name-given>"; |
1869 | } | |
436f1c8c | 1870 | name = dmalloc (strlen (val) + 1, MDL); |
7dfc8ac2 | 1871 | if (!name) |
8ae2d595 | 1872 | log_fatal ("no memory for shared network name"); |
7dfc8ac2 TL |
1873 | strcpy (name, val); |
1874 | } else { | |
1875 | name = parse_host_name (cfile); | |
20916cae TL |
1876 | if (!name) { |
1877 | shared_network_dereference (&share, MDL); | |
7dfc8ac2 | 1878 | return; |
20916cae | 1879 | } |
1f814ff2 | 1880 | } |
1f814ff2 TL |
1881 | share -> name = name; |
1882 | ||
20916cae TL |
1883 | if (!parse_lbrace (cfile)) { |
1884 | shared_network_dereference (&share, MDL); | |
7dfc8ac2 | 1885 | return; |
20916cae | 1886 | } |
7dfc8ac2 | 1887 | |
1f814ff2 | 1888 | do { |
7dfc8ac2 TL |
1889 | token = peek_token (&val, cfile); |
1890 | if (token == RBRACE) { | |
1891 | token = next_token (&val, cfile); | |
20916cae | 1892 | if (!share -> subnets) |
4bd8800e TL |
1893 | parse_warn (cfile, |
1894 | "empty shared-network decl"); | |
20916cae TL |
1895 | else |
1896 | enter_shared_network (share); | |
1897 | shared_network_dereference (&share, MDL); | |
1f814ff2 | 1898 | return; |
5376e3e9 TL |
1899 | } else if (token == EOF) { |
1900 | token = next_token (&val, cfile); | |
35454d8a | 1901 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1902 | break; |
79931db3 TL |
1903 | } else if (token == INTERFACE) { |
1904 | token = next_token (&val, cfile); | |
1905 | token = next_token (&val, cfile); | |
1906 | new_shared_network_interface (cfile, share, val); | |
1907 | if (!parse_semi (cfile)) | |
1908 | break; | |
1909 | continue; | |
1f814ff2 | 1910 | } |
5376e3e9 | 1911 | |
2d59f590 TL |
1912 | declaration = parse_statement (cfile, share -> group, |
1913 | SHARED_NET_DECL, | |
1914 | (struct host_decl *)0, | |
1915 | declaration); | |
1f814ff2 | 1916 | } while (1); |
20916cae | 1917 | shared_network_dereference (&share, MDL); |
1f814ff2 TL |
1918 | } |
1919 | ||
2d59f590 TL |
1920 | /* subnet-declaration :== |
1921 | net NETMASK netmask RBRACE parameters declarations LBRACE */ | |
685963dc | 1922 | |
2d59f590 | 1923 | void parse_subnet_declaration (cfile, share) |
35454d8a | 1924 | struct parse *cfile; |
1f814ff2 | 1925 | struct shared_network *share; |
685963dc | 1926 | { |
b1b7b521 | 1927 | const char *val; |
6f8fb41f | 1928 | enum dhcp_token token; |
763adef1 | 1929 | struct subnet *subnet, *t, *u; |
7dfc8ac2 | 1930 | struct iaddr iaddr; |
685963dc | 1931 | unsigned char addr [4]; |
b1b7b521 | 1932 | unsigned len = sizeof addr; |
2d59f590 | 1933 | int declaration = 0; |
79931db3 | 1934 | struct interface_info *ip; |
20916cae | 1935 | isc_result_t status; |
685963dc | 1936 | |
20916cae TL |
1937 | subnet = (struct subnet *)0; |
1938 | status = subnet_allocate (&subnet, MDL); | |
1939 | if (status != ISC_R_SUCCESS) | |
1940 | log_fatal ("Allocation of new subnet failed: %s", | |
1941 | isc_result_totext (status)); | |
1942 | shared_network_reference (&subnet -> shared_network, share, MDL); | |
1943 | if (!clone_group (&subnet -> group, share -> group, MDL)) | |
1944 | log_fatal ("allocation of group for new subnet failed."); | |
1945 | subnet_reference (&subnet -> group -> subnet, subnet, MDL); | |
685963dc TL |
1946 | |
1947 | /* Get the network number... */ | |
20916cae TL |
1948 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
1949 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1950 | return; |
20916cae | 1951 | } |
7dfc8ac2 TL |
1952 | memcpy (iaddr.iabuf, addr, len); |
1953 | iaddr.len = len; | |
1954 | subnet -> net = iaddr; | |
685963dc TL |
1955 | |
1956 | token = next_token (&val, cfile); | |
1957 | if (token != NETMASK) { | |
35454d8a | 1958 | parse_warn (cfile, "Expecting netmask"); |
685963dc | 1959 | skip_to_semi (cfile); |
7dfc8ac2 | 1960 | return; |
685963dc TL |
1961 | } |
1962 | ||
1963 | /* Get the netmask... */ | |
20916cae TL |
1964 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
1965 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1966 | return; |
20916cae | 1967 | } |
7dfc8ac2 TL |
1968 | memcpy (iaddr.iabuf, addr, len); |
1969 | iaddr.len = len; | |
1970 | subnet -> netmask = iaddr; | |
685963dc | 1971 | |
20916cae TL |
1972 | /* Validate the network number/netmask pair. */ |
1973 | if (host_addr (subnet -> net, subnet -> netmask)) { | |
1974 | parse_warn (cfile, | |
1975 | "subnet %s: bad subnet number/mask combination.", | |
1976 | piaddr (subnet -> net)); | |
1977 | subnet_dereference (&subnet, MDL); | |
1978 | skip_to_semi (cfile); | |
1979 | return; | |
1980 | } | |
1981 | ||
685963dc TL |
1982 | enter_subnet (subnet); |
1983 | ||
20916cae TL |
1984 | if (!parse_lbrace (cfile)) { |
1985 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 1986 | return; |
20916cae | 1987 | } |
7dfc8ac2 | 1988 | |
685963dc TL |
1989 | do { |
1990 | token = peek_token (&val, cfile); | |
7dfc8ac2 TL |
1991 | if (token == RBRACE) { |
1992 | token = next_token (&val, cfile); | |
685963dc | 1993 | break; |
5376e3e9 TL |
1994 | } else if (token == EOF) { |
1995 | token = next_token (&val, cfile); | |
35454d8a | 1996 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 1997 | break; |
79931db3 TL |
1998 | } else if (token == INTERFACE) { |
1999 | token = next_token (&val, cfile); | |
2000 | token = next_token (&val, cfile); | |
2001 | new_shared_network_interface (cfile, share, val); | |
2002 | if (!parse_semi (cfile)) | |
2003 | break; | |
2004 | continue; | |
7dfc8ac2 | 2005 | } |
2d59f590 TL |
2006 | declaration = parse_statement (cfile, subnet -> group, |
2007 | SUBNET_DECL, | |
2008 | (struct host_decl *)0, | |
2009 | declaration); | |
685963dc | 2010 | } while (1); |
1f814ff2 | 2011 | |
6cdd0d0d | 2012 | /* Add the subnet to the list of subnets in this shared net. */ |
7dfc8ac2 | 2013 | if (!share -> subnets) |
20916cae | 2014 | subnet_reference (&share -> subnets, subnet, MDL); |
7dfc8ac2 | 2015 | else { |
763adef1 | 2016 | u = (struct subnet *)0; |
7dfc8ac2 | 2017 | for (t = share -> subnets; |
763adef1 TL |
2018 | t -> next_sibling; t = t -> next_sibling) { |
2019 | if (subnet_inner_than (subnet, t, 0)) { | |
20916cae TL |
2020 | subnet_reference (&subnet -> next_sibling, |
2021 | t, MDL); | |
2022 | if (u) { | |
2023 | subnet_dereference (&u -> next_sibling, | |
2024 | MDL); | |
2025 | subnet_reference (&u -> next_sibling, | |
2026 | subnet, MDL); | |
2027 | } else { | |
2028 | subnet_dereference (&share -> subnets, | |
2029 | MDL); | |
2030 | subnet_reference (&share -> subnets, | |
2031 | subnet, MDL); | |
2032 | } | |
2033 | subnet_dereference (&subnet, MDL); | |
763adef1 TL |
2034 | return; |
2035 | } | |
2036 | u = t; | |
2037 | } | |
20916cae | 2038 | subnet_reference (&t -> next_sibling, subnet, MDL); |
7dfc8ac2 | 2039 | } |
20916cae | 2040 | subnet_dereference (&subnet, MDL); |
685963dc TL |
2041 | } |
2042 | ||
2d59f590 | 2043 | /* group-declaration :== RBRACE parameters declarations LBRACE */ |
7dfc8ac2 | 2044 | |
2d59f590 | 2045 | void parse_group_declaration (cfile, group) |
35454d8a | 2046 | struct parse *cfile; |
7dfc8ac2 | 2047 | struct group *group; |
685963dc | 2048 | { |
b1b7b521 | 2049 | const char *val; |
6f8fb41f | 2050 | enum dhcp_token token; |
7dfc8ac2 | 2051 | struct group *g; |
2d59f590 | 2052 | int declaration = 0; |
29c35bed TL |
2053 | struct group_object *t; |
2054 | isc_result_t status; | |
d9eefc5d | 2055 | char *name = NULL; |
29c35bed TL |
2056 | int deletedp = 0; |
2057 | int dynamicp = 0; | |
2058 | int staticp = 0; | |
685963dc | 2059 | |
20916cae TL |
2060 | g = (struct group *)0; |
2061 | if (!clone_group (&g, group, MDL)) | |
2062 | log_fatal ("no memory for explicit group."); | |
685963dc | 2063 | |
29c35bed TL |
2064 | token = peek_token (&val, cfile); |
2065 | if (is_identifier (token) || token == STRING) { | |
2066 | next_token (&val, cfile); | |
2067 | ||
436f1c8c | 2068 | name = dmalloc (strlen (val) + 1, MDL); |
29c35bed TL |
2069 | if (!name) |
2070 | log_fatal ("no memory for group decl name %s", val); | |
2071 | strcpy (name, val); | |
2072 | } | |
2073 | ||
20916cae TL |
2074 | if (!parse_lbrace (cfile)) { |
2075 | group_dereference (&g, MDL); | |
7dfc8ac2 | 2076 | return; |
20916cae | 2077 | } |
d7837182 | 2078 | |
7dfc8ac2 TL |
2079 | do { |
2080 | token = peek_token (&val, cfile); | |
5376e3e9 TL |
2081 | if (token == RBRACE) { |
2082 | token = next_token (&val, cfile); | |
7dfc8ac2 | 2083 | break; |
5376e3e9 TL |
2084 | } else if (token == EOF) { |
2085 | token = next_token (&val, cfile); | |
35454d8a | 2086 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 2087 | break; |
007e3ee4 | 2088 | } else if (token == TOKEN_DELETED) { |
29c35bed TL |
2089 | token = next_token (&val, cfile); |
2090 | parse_semi (cfile); | |
2091 | deletedp = 1; | |
2092 | } else if (token == DYNAMIC) { | |
2093 | token = next_token (&val, cfile); | |
2094 | parse_semi (cfile); | |
2095 | dynamicp = 1; | |
2096 | } else if (token == STATIC) { | |
2097 | token = next_token (&val, cfile); | |
2098 | parse_semi (cfile); | |
2099 | staticp = 1; | |
5376e3e9 | 2100 | } |
2d59f590 TL |
2101 | declaration = parse_statement (cfile, g, GROUP_DECL, |
2102 | (struct host_decl *)0, | |
2103 | declaration); | |
7dfc8ac2 | 2104 | } while (1); |
29c35bed TL |
2105 | |
2106 | if (name) { | |
2107 | if (deletedp) { | |
2108 | if (group_name_hash) { | |
20916cae TL |
2109 | t = (struct group_object *)0; |
2110 | if (group_hash_lookup (&t, group_name_hash, | |
2111 | name, | |
2112 | strlen (name), MDL)) { | |
29c35bed TL |
2113 | delete_group (t, 0); |
2114 | } | |
2115 | } | |
2116 | } else { | |
20916cae TL |
2117 | t = (struct group_object *)0; |
2118 | status = group_object_allocate (&t, MDL); | |
2119 | if (status != ISC_R_SUCCESS) | |
2120 | log_fatal ("no memory for group decl %s: %s", | |
2121 | val, isc_result_totext (status)); | |
2122 | group_reference (&t -> group, g, MDL); | |
29c35bed TL |
2123 | t -> name = name; |
2124 | t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) | | |
2125 | (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) | | |
2126 | (deletedp ? GROUP_OBJECT_DELETED : 0)); | |
2127 | supersede_group (t, 0); | |
2128 | } | |
20916cae TL |
2129 | if (t) |
2130 | group_object_dereference (&t, MDL); | |
29c35bed | 2131 | } |
d7837182 TL |
2132 | } |
2133 | ||
2d59f590 TL |
2134 | /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI |
2135 | ip-addrs-or-hostnames :== ip-addr-or-hostname | |
2136 | | ip-addrs-or-hostnames ip-addr-or-hostname */ | |
d7837182 | 2137 | |
6f8fb41f TL |
2138 | int parse_fixed_addr_param (oc, cfile) |
2139 | struct option_cache **oc; | |
35454d8a | 2140 | struct parse *cfile; |
d7837182 | 2141 | { |
b1b7b521 | 2142 | const char *val; |
6f8fb41f | 2143 | enum dhcp_token token; |
ece6ea33 | 2144 | struct expression *expr = (struct expression *)0; |
6f8fb41f TL |
2145 | struct expression *tmp, *new; |
2146 | int status; | |
1f814ff2 TL |
2147 | |
2148 | do { | |
6f8fb41f TL |
2149 | tmp = (struct expression *)0; |
2150 | if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) { | |
028a8588 TL |
2151 | if (expr) { |
2152 | new = (struct expression *)0; | |
2153 | status = make_concat (&new, expr, tmp); | |
436f1c8c TL |
2154 | expression_dereference (&expr, MDL); |
2155 | expression_dereference (&tmp, MDL); | |
1dd632af | 2156 | if (!status) |
028a8588 TL |
2157 | return 0; |
2158 | expr = new; | |
2159 | } else | |
2160 | expr = tmp; | |
6f8fb41f TL |
2161 | } else { |
2162 | if (expr) | |
436f1c8c | 2163 | expression_dereference (&expr, MDL); |
6f8fb41f TL |
2164 | return 0; |
2165 | } | |
1f814ff2 | 2166 | token = peek_token (&val, cfile); |
5376e3e9 | 2167 | if (token == COMMA) |
1f814ff2 TL |
2168 | token = next_token (&val, cfile); |
2169 | } while (token == COMMA); | |
7dfc8ac2 | 2170 | |
6f8fb41f TL |
2171 | if (!parse_semi (cfile)) { |
2172 | if (expr) | |
436f1c8c | 2173 | expression_dereference (&expr, MDL); |
6f8fb41f TL |
2174 | return 0; |
2175 | } | |
2176 | status = option_cache (oc, (struct data_string *)0, expr, | |
2177 | (struct option *)0); | |
436f1c8c | 2178 | expression_dereference (&expr, MDL); |
6f8fb41f | 2179 | return status; |
d7837182 TL |
2180 | } |
2181 | ||
5376e3e9 | 2182 | /* timestamp :== date |
d7837182 TL |
2183 | |
2184 | Timestamps are actually not used in dhcpd.conf, which is a static file, | |
5376e3e9 TL |
2185 | but rather in the database file and the journal file. (Okay, actually |
2186 | they're not even used there yet). */ | |
d7837182 | 2187 | |
7dfc8ac2 | 2188 | TIME parse_timestamp (cfile) |
35454d8a | 2189 | struct parse *cfile; |
d7837182 | 2190 | { |
089fb364 | 2191 | TIME rv; |
089fb364 | 2192 | |
7dfc8ac2 | 2193 | rv = parse_date (cfile); |
089fb364 | 2194 | return rv; |
d7837182 TL |
2195 | } |
2196 | ||
2d59f590 TL |
2197 | /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE |
2198 | ||
2199 | lease_parameters :== <nil> | |
2200 | | lease_parameter | |
2201 | | lease_parameters lease_parameter | |
2202 | ||
2203 | lease_parameter :== STARTS date | |
2204 | | ENDS date | |
2205 | | TIMESTAMP date | |
2206 | | HARDWARE hardware-parameter | |
2207 | | UID hex_numbers SEMI | |
ccf5778a TL |
2208 | | HOSTNAME hostname SEMI |
2209 | | CLIENT_HOSTNAME hostname SEMI | |
2d59f590 TL |
2210 | | CLASS identifier SEMI |
2211 | | DYNAMIC_BOOTP SEMI */ | |
2212 | ||
20916cae | 2213 | int parse_lease_declaration (struct lease **lp, struct parse *cfile) |
d7837182 | 2214 | { |
b1b7b521 | 2215 | const char *val; |
6f8fb41f | 2216 | enum dhcp_token token; |
d7837182 | 2217 | unsigned char addr [4]; |
b1b7b521 | 2218 | unsigned len = sizeof addr; |
d7837182 TL |
2219 | int seenmask = 0; |
2220 | int seenbit; | |
2221 | char tbuf [32]; | |
20916cae | 2222 | struct lease *lease; |
96d7d13e | 2223 | struct executable_statement *on; |
436f1c8c TL |
2224 | struct expression *exp; |
2225 | struct data_string ds; | |
96d7d13e | 2226 | int lose; |
9e9b2261 | 2227 | TIME t; |
436f1c8c TL |
2228 | char *s; |
2229 | int noequal, newbinding; | |
2230 | struct binding *binding; | |
20916cae | 2231 | isc_result_t status; |
007e3ee4 | 2232 | binding_state_t *statep; |
d7837182 | 2233 | |
20916cae TL |
2234 | lease = (struct lease *)0; |
2235 | status = lease_allocate (&lease, MDL); | |
2236 | if (status != ISC_R_SUCCESS) | |
2237 | return 0; | |
9375101b | 2238 | |
d7837182 | 2239 | /* Get the address for which the lease has been issued. */ |
20916cae TL |
2240 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
2241 | lease_dereference (&lease, MDL); | |
2242 | return 0; | |
2243 | } | |
2244 | memcpy (lease -> ip_addr.iabuf, addr, len); | |
2245 | lease -> ip_addr.len = len; | |
d7837182 | 2246 | |
20916cae TL |
2247 | if (!parse_lbrace (cfile)) { |
2248 | lease_dereference (&lease, MDL); | |
2249 | return 0; | |
2250 | } | |
7dfc8ac2 | 2251 | |
d7837182 TL |
2252 | do { |
2253 | token = next_token (&val, cfile); | |
7dfc8ac2 | 2254 | if (token == RBRACE) |
d7837182 | 2255 | break; |
5376e3e9 | 2256 | else if (token == EOF) { |
35454d8a | 2257 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
2258 | break; |
2259 | } | |
ece6ea33 | 2260 | strncpy (tbuf, val, sizeof tbuf); |
d7837182 TL |
2261 | tbuf [(sizeof tbuf) - 1] = 0; |
2262 | ||
2263 | /* Parse any of the times associated with the lease. */ | |
9e9b2261 TL |
2264 | switch (token) { |
2265 | case STARTS: | |
2266 | case ENDS: | |
2267 | case TIMESTAMP: | |
2268 | case TSTP: | |
2269 | case TSFP: | |
8c8e27c5 | 2270 | case CLTT: |
7dfc8ac2 | 2271 | t = parse_date (cfile); |
d7837182 TL |
2272 | switch (token) { |
2273 | case STARTS: | |
2274 | seenbit = 1; | |
20916cae | 2275 | lease -> starts = t; |
d7837182 TL |
2276 | break; |
2277 | ||
2278 | case ENDS: | |
2279 | seenbit = 2; | |
20916cae | 2280 | lease -> ends = t; |
d7837182 TL |
2281 | break; |
2282 | ||
2283 | case TIMESTAMP: | |
2284 | seenbit = 4; | |
20916cae | 2285 | lease -> timestamp = t; |
d7837182 | 2286 | break; |
19d868b2 | 2287 | |
9e9b2261 TL |
2288 | case TSTP: |
2289 | seenbit = 65536; | |
20916cae | 2290 | lease -> tstp = t; |
19d868b2 | 2291 | break; |
9e9b2261 TL |
2292 | |
2293 | case TSFP: | |
2294 | seenbit = 131072; | |
20916cae | 2295 | lease -> tsfp = t; |
d7837182 | 2296 | break; |
9e9b2261 | 2297 | |
8c8e27c5 TL |
2298 | case CLTT: |
2299 | seenbit = 524288; | |
20916cae | 2300 | lease -> cltt = t; |
8c8e27c5 TL |
2301 | break; |
2302 | ||
9e9b2261 | 2303 | default: /* for gcc, we'll never get here. */ |
9d80b480 | 2304 | break; |
9e9b2261 TL |
2305 | } |
2306 | break; | |
d7837182 | 2307 | |
9e9b2261 TL |
2308 | /* Colon-seperated hexadecimal octets... */ |
2309 | case UID: | |
2310 | seenbit = 8; | |
2311 | token = peek_token (&val, cfile); | |
2312 | if (token == STRING) { | |
2313 | unsigned char *tuid; | |
d7837182 | 2314 | token = next_token (&val, cfile); |
20916cae | 2315 | lease -> uid_len = strlen (val); |
436f1c8c | 2316 | tuid = ((unsigned char *) |
20916cae | 2317 | dmalloc (lease -> uid_len, MDL)); |
9e9b2261 TL |
2318 | if (!tuid) { |
2319 | log_error ("no space for uid"); | |
20916cae TL |
2320 | lease_dereference (&lease, MDL); |
2321 | return 0; | |
d7837182 | 2322 | } |
20916cae TL |
2323 | memcpy (tuid, val, lease -> uid_len); |
2324 | lease -> uid = tuid; | |
9e9b2261 | 2325 | } else { |
20916cae TL |
2326 | lease -> uid_len = 0; |
2327 | lease -> uid = (parse_numeric_aggregate | |
2328 | (cfile, (unsigned char *)0, | |
2329 | &lease -> uid_len, ':', | |
2330 | 16, 8)); | |
2331 | if (!lease -> uid) { | |
2332 | lease_dereference (&lease, MDL); | |
2333 | return 0; | |
2334 | } | |
2335 | if (lease -> uid_len == 0) { | |
2336 | lease -> uid = (unsigned char *)0; | |
9e9b2261 TL |
2337 | parse_warn (cfile, "zero-length uid"); |
2338 | seenbit = 0; | |
d0463358 | 2339 | parse_semi (cfile); |
9e9b2261 TL |
2340 | break; |
2341 | } | |
2342 | } | |
d0463358 | 2343 | parse_semi (cfile); |
20916cae | 2344 | if (!lease -> uid) { |
9e9b2261 TL |
2345 | log_fatal ("No memory for lease uid"); |
2346 | } | |
2347 | break; | |
2348 | ||
2349 | case CLASS: | |
2350 | seenbit = 32; | |
2351 | token = next_token (&val, cfile); | |
2352 | if (!is_identifier (token)) { | |
2353 | if (token != SEMI) | |
2354 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
2355 | lease_dereference (&lease, MDL); |
2356 | return 0; | |
9e9b2261 | 2357 | } |
d0463358 | 2358 | parse_semi (cfile); |
9e9b2261 TL |
2359 | /* for now, we aren't using this. */ |
2360 | break; | |
ccf5778a | 2361 | |
9e9b2261 TL |
2362 | case HARDWARE: |
2363 | seenbit = 64; | |
2364 | parse_hardware_param (cfile, | |
20916cae | 2365 | &lease -> hardware_addr); |
9e9b2261 TL |
2366 | break; |
2367 | ||
2368 | case DYNAMIC_BOOTP: | |
007e3ee4 TL |
2369 | seenbit = 256; |
2370 | lease -> binding_state = FTS_BOOTP; | |
2371 | lease -> next_binding_state = FTS_BOOTP; | |
d0463358 | 2372 | parse_semi (cfile); |
9e9b2261 TL |
2373 | break; |
2374 | ||
007e3ee4 TL |
2375 | case TOKEN_ABANDONED: |
2376 | seenbit = 256; | |
2377 | lease -> binding_state = FTS_ABANDONED; | |
2378 | lease -> next_binding_state = FTS_ABANDONED; | |
d0463358 | 2379 | parse_semi (cfile); |
9e9b2261 TL |
2380 | break; |
2381 | ||
007e3ee4 TL |
2382 | case TOKEN_NEXT: |
2383 | seenbit = 128; | |
2384 | statep = &lease -> next_binding_state; | |
301a5b66 TL |
2385 | token = next_token (&val, cfile); |
2386 | if (token != BINDING) { | |
2387 | parse_warn (cfile, "expecting 'binding'"); | |
2388 | skip_to_semi (cfile); | |
2389 | break; | |
2390 | } | |
007e3ee4 TL |
2391 | goto do_binding_state; |
2392 | ||
2393 | case BINDING: | |
9e9b2261 | 2394 | seenbit = 256; |
007e3ee4 TL |
2395 | statep = &lease -> binding_state; |
2396 | ||
2397 | do_binding_state: | |
2398 | token = next_token (&val, cfile); | |
2399 | if (token != STATE) { | |
2400 | parse_warn (cfile, "expecting 'state'"); | |
2401 | skip_to_semi (cfile); | |
2402 | break; | |
2403 | } | |
2404 | token = next_token (&val, cfile); | |
2405 | switch (token) { | |
2406 | case TOKEN_ABANDONED: | |
2407 | *statep = FTS_ABANDONED; | |
2408 | break; | |
2409 | case TOKEN_FREE: | |
2410 | *statep = FTS_FREE; | |
2411 | break; | |
2412 | case TOKEN_ACTIVE: | |
2413 | *statep = FTS_ACTIVE; | |
2414 | break; | |
2415 | case TOKEN_EXPIRED: | |
2416 | *statep = FTS_EXPIRED; | |
2417 | break; | |
2418 | case TOKEN_RELEASED: | |
2419 | *statep = FTS_RELEASED; | |
2420 | break; | |
2421 | case TOKEN_RESET: | |
2422 | *statep = FTS_RESET; | |
2423 | break; | |
2424 | case TOKEN_BACKUP: | |
2425 | *statep = FTS_BACKUP; | |
2426 | break; | |
2427 | case TOKEN_RESERVED: | |
2428 | *statep = FTS_RESERVED; | |
2429 | break; | |
2430 | case TOKEN_BOOTP: | |
2431 | *statep = FTS_BOOTP; | |
2432 | break; | |
2433 | default: | |
2434 | parse_warn (cfile, | |
2435 | "%s: expecting a binding state.", | |
2436 | val); | |
2437 | skip_to_semi (cfile); | |
2438 | break; | |
2439 | } | |
2440 | /* If no next binding state is specified, it's | |
2441 | the same as the current state. */ | |
2442 | if (!(seenmask & 128) && seenbit == 256) | |
2443 | lease -> next_binding_state = | |
2444 | lease -> binding_state; | |
d0463358 | 2445 | parse_semi (cfile); |
9e9b2261 | 2446 | break; |
ccf5778a | 2447 | |
9e9b2261 TL |
2448 | case HOSTNAME: |
2449 | seenbit = 512; | |
2450 | token = peek_token (&val, cfile); | |
2451 | if (token == STRING) | |
20916cae | 2452 | lease -> hostname = parse_string (cfile); |
d0463358 | 2453 | else { |
20916cae TL |
2454 | lease -> hostname = parse_host_name (cfile); |
2455 | if (lease -> hostname) | |
d0463358 TL |
2456 | parse_semi (cfile); |
2457 | } | |
20916cae | 2458 | if (!lease -> hostname) { |
9e9b2261 | 2459 | seenbit = 0; |
20916cae | 2460 | return 0; |
9e9b2261 TL |
2461 | } |
2462 | break; | |
2463 | ||
2464 | case CLIENT_HOSTNAME: | |
2465 | seenbit = 1024; | |
2466 | token = peek_token (&val, cfile); | |
2467 | if (token == STRING) | |
20916cae TL |
2468 | lease -> client_hostname = |
2469 | parse_string (cfile); | |
d0463358 | 2470 | else { |
20916cae | 2471 | lease -> client_hostname = |
9e9b2261 | 2472 | parse_host_name (cfile); |
20916cae | 2473 | if (lease -> client_hostname) |
d0463358 TL |
2474 | parse_semi (cfile); |
2475 | } | |
20916cae | 2476 | if (!lease -> client_hostname) { |
d0463358 | 2477 | seenbit = 0; |
20916cae TL |
2478 | lease_dereference (&lease, MDL); |
2479 | return 0; | |
d0463358 | 2480 | } |
9e9b2261 TL |
2481 | break; |
2482 | ||
2483 | case BILLING: | |
2484 | seenbit = 2048; | |
2485 | token = next_token (&val, cfile); | |
2486 | if (token == CLASS) { | |
88dcab62 | 2487 | token = next_token (&val, cfile); |
9e9b2261 TL |
2488 | if (token != STRING) { |
2489 | parse_warn (cfile, "expecting string"); | |
88dcab62 TL |
2490 | if (token != SEMI) |
2491 | skip_to_semi (cfile); | |
9e9b2261 TL |
2492 | token = BILLING; |
2493 | break; | |
88dcab62 | 2494 | } |
20916cae TL |
2495 | find_class (&lease -> billing_class, val, MDL); |
2496 | if (!lease -> billing_class) | |
9e9b2261 TL |
2497 | parse_warn (cfile, |
2498 | "unknown class %s", val); | |
2499 | parse_semi (cfile); | |
2500 | } else if (token == SUBCLASS) { | |
20916cae TL |
2501 | if (lease -> billing_class) |
2502 | class_dereference | |
2503 | (&lease -> billing_class, MDL); | |
2504 | parse_class_declaration | |
2505 | (&lease -> billing_class, | |
2506 | cfile, (struct group *)0, 3); | |
9e9b2261 TL |
2507 | } else { |
2508 | parse_warn (cfile, "expecting \"class\""); | |
2509 | if (token != SEMI) | |
2510 | skip_to_semi (cfile); | |
2511 | } | |
9e9b2261 | 2512 | break; |
96d7d13e | 2513 | |
9e9b2261 TL |
2514 | case ON: |
2515 | on = (struct executable_statement *)0; | |
2516 | lose = 0; | |
2517 | if (!parse_on_statement (&on, cfile, &lose)) { | |
2518 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
2519 | lease_dereference (&lease, MDL); |
2520 | return 0; | |
7dfc8ac2 | 2521 | } |
436f1c8c | 2522 | seenbit = 0; |
d0463358 | 2523 | if ((on -> data.on.evtypes & ON_EXPIRY) && |
9e9b2261 | 2524 | on -> data.on.statements) { |
436f1c8c | 2525 | seenbit |= 16384; |
9e9b2261 | 2526 | executable_statement_reference |
20916cae | 2527 | (&lease -> on_expiry, |
436f1c8c | 2528 | on -> data.on.statements, MDL); |
d0463358 TL |
2529 | } |
2530 | if ((on -> data.on.evtypes & ON_RELEASE) && | |
2531 | on -> data.on.statements) { | |
436f1c8c | 2532 | seenbit |= 32768; |
9e9b2261 | 2533 | executable_statement_reference |
20916cae | 2534 | (&lease -> on_release, |
436f1c8c | 2535 | on -> data.on.statements, MDL); |
9e9b2261 | 2536 | } |
436f1c8c | 2537 | executable_statement_dereference (&on, MDL); |
9e9b2261 TL |
2538 | break; |
2539 | ||
436f1c8c TL |
2540 | case TOKEN_SET: |
2541 | noequal = 0; | |
2542 | ||
2543 | token = next_token (&val, cfile); | |
2544 | if (token != NAME && token != NUMBER_OR_NAME) { | |
2545 | parse_warn (cfile, | |
2546 | "%s can't be a variable name", | |
2547 | val); | |
2548 | badset: | |
2549 | skip_to_semi (cfile); | |
20916cae TL |
2550 | lease_dereference (&lease, MDL); |
2551 | return 0; | |
436f1c8c TL |
2552 | } |
2553 | ||
2554 | seenbit = 0; | |
2555 | special_set: | |
6ceb9118 TL |
2556 | if (lease -> scope) |
2557 | binding = find_binding (lease -> scope, val); | |
2558 | else | |
2559 | binding = (struct binding *)0; | |
436f1c8c | 2560 | if (!binding) { |
6ceb9118 TL |
2561 | if (!lease -> scope) |
2562 | if (!(binding_scope_allocate | |
2563 | (&lease -> scope, MDL))) | |
2564 | log_fatal ("no memory for scope"); | |
436f1c8c TL |
2565 | binding = dmalloc (sizeof *binding, MDL); |
2566 | if (!binding) | |
2567 | log_fatal ("No memory for lease %s.", | |
2568 | "binding"); | |
2569 | memset (binding, 0, sizeof *binding); | |
2570 | binding -> name = | |
2571 | dmalloc (strlen (val) + 1, MDL); | |
2572 | if (!binding -> name) | |
2573 | log_fatal ("No memory for binding %s.", | |
2574 | "name"); | |
2575 | strcpy (binding -> name, val); | |
2576 | newbinding = 1; | |
11cd757b TL |
2577 | } else if (binding -> value) { |
2578 | binding_value_dereference (&binding -> value, | |
2579 | MDL); | |
436f1c8c TL |
2580 | newbinding = 0; |
2581 | } | |
11cd757b TL |
2582 | if (!binding_value_allocate (&binding -> value, MDL)) |
2583 | log_fatal ("no memory for binding value."); | |
436f1c8c TL |
2584 | |
2585 | if (!noequal) { | |
2586 | token = next_token (&val, cfile); | |
2587 | if (token != EQUAL) { | |
2588 | parse_warn (cfile, | |
2589 | "expecting '=' in set statement."); | |
2590 | goto badset; | |
2591 | } | |
2592 | } | |
2593 | ||
2594 | token = peek_token (&val, cfile); | |
2595 | if (token == STRING) { | |
11cd757b TL |
2596 | unsigned char *tuid; |
2597 | token = next_token (&val, cfile); | |
2598 | binding -> value -> type = binding_data; | |
2599 | binding -> value -> value.data.len = strlen (val); | |
2600 | if (!(buffer_allocate | |
2601 | (&binding -> value -> value.data.buffer, | |
2602 | binding -> value-> value.data.len + 1, | |
2603 | MDL))) | |
2604 | log_fatal ("No memory for binding."); | |
2605 | strcpy ((char *) | |
2606 | (binding -> value -> | |
2607 | value.data.buffer -> data), val); | |
2608 | binding -> value -> value.data.data = | |
2609 | binding -> value -> value.data.buffer -> data; | |
2610 | binding -> value -> value.data.terminated = 1; | |
2611 | } else if (token == NUMBER_OR_NAME) { | |
2612 | binding -> value -> type = binding_data; | |
2613 | s = ((char *) | |
2614 | (parse_numeric_aggregate | |
2615 | (cfile, (unsigned char *)0, | |
2616 | &binding -> value -> value.data.len, | |
2617 | ':', 16, 8))); | |
2618 | if (!s) { | |
2619 | binding_value_dereference | |
2620 | (&binding -> value, MDL); | |
20916cae TL |
2621 | lease_dereference (&lease, MDL); |
2622 | return 0; | |
11cd757b TL |
2623 | } |
2624 | if (binding -> value -> value.data.len) { | |
436f1c8c | 2625 | if (!(buffer_allocate |
11cd757b TL |
2626 | (&binding -> value -> value.data.buffer, |
2627 | binding -> value -> value.data.len + 1, | |
2628 | MDL))) | |
436f1c8c | 2629 | log_fatal ("No memory for binding."); |
11cd757b TL |
2630 | memcpy ((binding -> value -> |
2631 | value.data.buffer -> data), s, | |
2632 | binding -> value -> value.data.len); | |
2633 | dfree (s, MDL); | |
2634 | binding -> value -> value.data.data = | |
2635 | binding -> value -> value.data.buffer -> data; | |
2636 | } | |
2637 | } else if (token == PERCENT) { | |
2638 | token = next_token (&val, cfile); | |
2639 | token = next_token (&val, cfile); | |
2640 | if (token != NUMBER) { | |
2641 | parse_warn (cfile, | |
2642 | "expecting decimal number."); | |
2643 | if (token != SEMI) | |
2644 | skip_to_semi (cfile); | |
2645 | binding_value_dereference | |
2646 | (&binding -> value, MDL); | |
20916cae TL |
2647 | lease_dereference (&lease, MDL); |
2648 | return 0; | |
11cd757b TL |
2649 | } |
2650 | binding -> value -> type = binding_numeric; | |
2651 | binding -> value -> value.intval = atol (val); | |
2652 | } else if (token == NAME) { | |
2653 | token = next_token (&val, cfile); | |
2654 | binding -> value -> type = binding_boolean; | |
2655 | if (!strcasecmp (val, "true")) | |
2656 | binding -> value -> value.boolean = 1; | |
2657 | else if (!strcasecmp (val, "false")) | |
2658 | binding -> value -> value.boolean = 0; | |
2659 | else | |
2660 | goto badbool; | |
436f1c8c | 2661 | } else { |
11cd757b TL |
2662 | badbool: |
2663 | parse_warn (cfile, | |
2664 | "expecting a constant value."); | |
2665 | skip_to_semi (cfile); | |
2666 | binding_value_dereference (&binding -> value, | |
2667 | MDL); | |
20916cae TL |
2668 | lease_dereference (&lease, MDL); |
2669 | return 0; | |
436f1c8c | 2670 | } |
11cd757b | 2671 | |
436f1c8c | 2672 | if (newbinding) { |
6ceb9118 TL |
2673 | binding -> next = lease -> scope -> bindings; |
2674 | lease -> scope -> bindings = binding; | |
436f1c8c TL |
2675 | } |
2676 | parse_semi (cfile); | |
2677 | break; | |
2678 | ||
9e9b2261 | 2679 | default: |
436f1c8c TL |
2680 | if (!strcasecmp (val, "ddns-fwd-name")) { |
2681 | seenbit = 4096; | |
2682 | noequal = 1; | |
2683 | goto special_set; | |
2684 | } else if (!strcasecmp (val, "ddns-rev-name")) { | |
2685 | seenbit = 8192; | |
2686 | noequal = 1; | |
2687 | goto special_set; | |
2688 | } | |
9e9b2261 TL |
2689 | skip_to_semi (cfile); |
2690 | seenbit = 0; | |
20916cae TL |
2691 | lease_dereference (&lease, MDL); |
2692 | return 0; | |
9e9b2261 | 2693 | } |
7dfc8ac2 | 2694 | |
d7837182 | 2695 | if (seenmask & seenbit) { |
35454d8a TL |
2696 | parse_warn (cfile, |
2697 | "Too many %s parameters in lease %s\n", | |
20916cae | 2698 | tbuf, piaddr (lease -> ip_addr)); |
d7837182 TL |
2699 | } else |
2700 | seenmask |= seenbit; | |
7dfc8ac2 | 2701 | |
d7837182 | 2702 | } while (1); |
8afe0787 TL |
2703 | |
2704 | /* If no binding state is specified, make one up. */ | |
2705 | if (!(seenmask & 256)) { | |
e73a0769 TL |
2706 | if (lease -> ends > cur_time || |
2707 | lease -> on_expiry || lease -> on_release) | |
8afe0787 | 2708 | lease -> binding_state = FTS_ACTIVE; |
301a5b66 | 2709 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
2710 | else if (lease -> pool && lease -> pool -> failover_peer) |
2711 | lease -> binding_state = FTS_EXPIRED; | |
301a5b66 | 2712 | #endif |
8afe0787 TL |
2713 | else |
2714 | lease -> binding_state = FTS_FREE; | |
e73a0769 | 2715 | if (lease -> binding_state == FTS_ACTIVE) { |
301a5b66 | 2716 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
2717 | if (lease -> pool && lease -> pool -> failover_peer) |
2718 | lease -> next_binding_state = FTS_EXPIRED; | |
2719 | else | |
301a5b66 | 2720 | #endif |
e73a0769 TL |
2721 | lease -> next_binding_state = FTS_FREE; |
2722 | } else | |
2723 | lease -> next_binding_state = lease -> binding_state; | |
8afe0787 TL |
2724 | } |
2725 | ||
20916cae TL |
2726 | lease_reference (lp, lease, MDL); |
2727 | lease_dereference (&lease, MDL); | |
2728 | return 1; | |
d7837182 TL |
2729 | } |
2730 | ||
2d59f590 TL |
2731 | /* address-range-declaration :== ip-address ip-address SEMI |
2732 | | DYNAMIC_BOOTP ip-address ip-address SEMI */ | |
d7837182 | 2733 | |
20916cae | 2734 | void parse_address_range (cfile, group, type, inpool) |
35454d8a | 2735 | struct parse *cfile; |
f63b4929 TL |
2736 | struct group *group; |
2737 | int type; | |
20916cae | 2738 | struct pool *inpool; |
d7837182 | 2739 | { |
f63b4929 | 2740 | struct iaddr low, high, net; |
d7837182 | 2741 | unsigned char addr [4]; |
b1b7b521 | 2742 | unsigned len = sizeof addr; |
6f8fb41f | 2743 | enum dhcp_token token; |
b1b7b521 | 2744 | const char *val; |
1f814ff2 | 2745 | int dynamic = 0; |
f63b4929 TL |
2746 | struct subnet *subnet; |
2747 | struct shared_network *share; | |
2748 | struct pool *p; | |
20916cae TL |
2749 | struct pool *pool; |
2750 | isc_result_t status; | |
1f814ff2 TL |
2751 | |
2752 | if ((token = peek_token (&val, cfile)) == DYNAMIC_BOOTP) { | |
5376e3e9 | 2753 | token = next_token (&val, cfile); |
ece6ea33 | 2754 | dynamic = 1; |
1f814ff2 | 2755 | } |
d7837182 TL |
2756 | |
2757 | /* Get the bottom address in the range... */ | |
7dfc8ac2 TL |
2758 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2759 | return; | |
089fb364 TL |
2760 | memcpy (low.iabuf, addr, len); |
2761 | low.len = len; | |
d7837182 | 2762 | |
2d59f590 TL |
2763 | /* Only one address? */ |
2764 | token = peek_token (&val, cfile); | |
2765 | if (token == SEMI) | |
2766 | high = low; | |
2767 | else { | |
d7837182 | 2768 | /* Get the top address in the range... */ |
2d59f590 TL |
2769 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
2770 | return; | |
2771 | memcpy (high.iabuf, addr, len); | |
2772 | high.len = len; | |
2773 | } | |
d7837182 | 2774 | |
7dfc8ac2 TL |
2775 | token = next_token (&val, cfile); |
2776 | if (token != SEMI) { | |
35454d8a | 2777 | parse_warn (cfile, "semicolon expected."); |
7dfc8ac2 TL |
2778 | skip_to_semi (cfile); |
2779 | return; | |
2780 | } | |
2781 | ||
f63b4929 TL |
2782 | if (type == SUBNET_DECL) { |
2783 | subnet = group -> subnet; | |
2784 | share = subnet -> shared_network; | |
2785 | } else { | |
2786 | share = group -> shared_network; | |
2787 | for (subnet = share -> subnets; | |
2788 | subnet; subnet = subnet -> next_sibling) { | |
2789 | net = subnet_number (low, subnet -> netmask); | |
e5e41be4 | 2790 | if (addr_eq (net, subnet -> net)) |
f63b4929 TL |
2791 | break; |
2792 | } | |
2793 | if (!subnet) { | |
35454d8a | 2794 | parse_warn (cfile, "address range not on network %s", |
f63b4929 | 2795 | group -> shared_network -> name); |
e5e41be4 TL |
2796 | log_error ("Be sure to place pool statement after %s", |
2797 | "related subnet declarations."); | |
f63b4929 TL |
2798 | return; |
2799 | } | |
2800 | } | |
2801 | ||
20916cae | 2802 | if (!inpool) { |
0a1dfb65 | 2803 | struct pool *last = (struct pool *)0; |
9e9b2261 | 2804 | |
f63b4929 TL |
2805 | /* If we're permitting dynamic bootp for this range, |
2806 | then look for a pool with an empty prohibit list and | |
436f1c8c | 2807 | a permit list with one entry that permits all clients. */ |
f63b4929 | 2808 | for (pool = share -> pools; pool; pool = pool -> next) { |
436f1c8c TL |
2809 | if ((!dynamic && !pool -> permit_list && |
2810 | pool -> prohibit_list && | |
2811 | !pool -> prohibit_list -> next && | |
2812 | (pool -> prohibit_list -> type == | |
2813 | permit_dynamic_bootp_clients)) || | |
2814 | (dynamic && !pool -> prohibit_list && | |
f63b4929 TL |
2815 | pool -> permit_list && |
2816 | !pool -> permit_list -> next && | |
2817 | (pool -> permit_list -> type == | |
d9eefc5d | 2818 | permit_all_clients))) { |
436f1c8c | 2819 | break; |
f63b4929 TL |
2820 | } |
2821 | last = pool; | |
2822 | } | |
2823 | ||
2824 | /* If we didn't get a pool, make one. */ | |
2825 | if (!pool) { | |
436f1c8c | 2826 | struct permit *p; |
20916cae TL |
2827 | status = pool_allocate (&pool, MDL); |
2828 | if (status != ISC_R_SUCCESS) | |
2829 | log_fatal ("no memory for ad-hoc pool: %s", | |
2830 | isc_result_totext (status)); | |
436f1c8c TL |
2831 | p = new_permit (MDL); |
2832 | if (!p) | |
2833 | log_fatal ("no memory for ad-hoc permit."); | |
2834 | ||
2835 | /* Dynamic pools permit all clients. Otherwise | |
2836 | we prohibit BOOTP clients. */ | |
f63b4929 | 2837 | if (dynamic) { |
436f1c8c TL |
2838 | p -> type = permit_all_clients; |
2839 | pool -> permit_list = p; | |
2840 | } else { | |
2841 | p -> type = permit_dynamic_bootp_clients; | |
2842 | pool -> prohibit_list = p; | |
f63b4929 | 2843 | } |
436f1c8c | 2844 | |
f63b4929 | 2845 | if (share -> pools) |
20916cae | 2846 | pool_reference (&last -> next, pool, MDL); |
f63b4929 | 2847 | else |
20916cae TL |
2848 | pool_reference (&share -> pools, pool, MDL); |
2849 | shared_network_reference (&pool -> shared_network, | |
2850 | share, MDL); | |
2851 | if (!clone_group (&pool -> group, share -> group, MDL)) | |
2852 | log_fatal ("no memory for anon pool group."); | |
a79ed92b TL |
2853 | } else { |
2854 | pool = (struct pool *)0; | |
0a1dfb65 TL |
2855 | if (last) |
2856 | pool_reference (&pool, last, MDL); | |
2857 | else | |
2858 | pool_reference (&pool, share -> pools, MDL); | |
f63b4929 | 2859 | } |
a79ed92b TL |
2860 | } else { |
2861 | pool = (struct pool *)0; | |
20916cae | 2862 | pool_reference (&pool, inpool, MDL); |
a79ed92b | 2863 | } |
20916cae | 2864 | |
c5261618 TL |
2865 | #if defined (FAILOVER_PROTOCOL) |
2866 | if (pool -> failover_peer && dynamic) { | |
2867 | /* Doctor, do you think I'm overly sensitive | |
2868 | about getting bug reports I can't fix? */ | |
2869 | parse_warn (cfile, "dynamic-bootp flag is %s", | |
2870 | "not permitted for address"); | |
2871 | log_error ("range declarations where there is a failover"); | |
2872 | log_error ("peer in scope. If you wish to declare an"); | |
2873 | log_error ("address range from which dynamic bootp leases"); | |
2874 | log_error ("can be allocated, please declare it within a"); | |
2875 | log_error ("pool declaration that also contains the \"no"); | |
2876 | log_error ("failover\" statement. The failover protocol"); | |
2877 | log_error ("itself does not permit dynamic bootp - this"); | |
2878 | log_error ("is not a limitation specific to the ISC DHCP"); | |
2879 | log_error ("server. Please don't ask me to defend this"); | |
2880 | log_error ("until you have read and really tried %s", | |
2881 | "to understand"); | |
2882 | log_error ("the failover protocol specification."); | |
2883 | ||
2884 | /* We don't actually bomb at this point - instead, | |
2885 | we let parse_lease_file notice the error and | |
2886 | bomb at that point - it's easier. */ | |
f63b4929 | 2887 | } |
c5261618 | 2888 | #endif /* FAILOVER_PROTOCOL */ |
f63b4929 | 2889 | |
d7837182 | 2890 | /* Create the new address range... */ |
f63b4929 | 2891 | new_address_range (low, high, subnet, pool); |
20916cae | 2892 | pool_dereference (&pool, MDL); |
d7837182 TL |
2893 | } |
2894 | ||
c358155d TL |
2895 | /* allow-deny-keyword :== BOOTP |
2896 | | BOOTING | |
2897 | | DYNAMIC_BOOTP | |
2898 | | UNKNOWN_CLIENTS */ | |
2899 | ||
2900 | int parse_allow_deny (oc, cfile, flag) | |
2901 | struct option_cache **oc; | |
2902 | struct parse *cfile; | |
2903 | int flag; | |
2904 | { | |
2905 | enum dhcp_token token; | |
2906 | const char *val; | |
2907 | unsigned char rf = flag; | |
2908 | struct expression *data = (struct expression *)0; | |
2909 | int status; | |
2910 | ||
2911 | if (!make_const_data (&data, &rf, 1, 0, 1)) | |
2912 | return 0; | |
2913 | ||
2914 | token = next_token (&val, cfile); | |
2915 | switch (token) { | |
007e3ee4 | 2916 | case TOKEN_BOOTP: |
c358155d TL |
2917 | status = option_cache (oc, (struct data_string *)0, data, |
2918 | &server_options [SV_ALLOW_BOOTP]); | |
2919 | break; | |
2920 | ||
2921 | case BOOTING: | |
2922 | status = option_cache (oc, (struct data_string *)0, data, | |
2923 | &server_options [SV_ALLOW_BOOTING]); | |
2924 | break; | |
2925 | ||
2926 | case DYNAMIC_BOOTP: | |
2927 | status = option_cache (oc, (struct data_string *)0, data, | |
2928 | &server_options [SV_DYNAMIC_BOOTP]); | |
2929 | break; | |
2930 | ||
2931 | case UNKNOWN_CLIENTS: | |
2932 | status = (option_cache | |
2933 | (oc, (struct data_string *)0, data, | |
2934 | &server_options [SV_BOOT_UNKNOWN_CLIENTS])); | |
2935 | break; | |
2936 | ||
2937 | case DUPLICATES: | |
2938 | status = option_cache (oc, (struct data_string *)0, data, | |
2939 | &server_options [SV_DUPLICATES]); | |
2940 | break; | |
2941 | ||
2942 | case DECLINES: | |
2943 | status = option_cache (oc, (struct data_string *)0, data, | |
2944 | &server_options [SV_DECLINES]); | |
2945 | break; | |
2946 | ||
2947 | default: | |
2948 | parse_warn (cfile, "expecting allow/deny key"); | |
2949 | skip_to_semi (cfile); | |
2950 | return 0; | |
2951 | } | |
2952 | parse_semi (cfile); | |
2953 | return status; | |
2954 | } | |
2955 |