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