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