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