]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* confpars.c |
2 | ||
3 | Parser for dhcpd config file... */ | |
4 | ||
5 | /* | |
fe5b0fdd | 6 | * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1995-2003 by Internet Software Consortium |
d7837182 | 8 | * |
98311e4b DH |
9 | * Permission to use, copy, modify, and distribute this software for any |
10 | * purpose with or without fee is hereby granted, provided that the above | |
11 | * copyright notice and this permission notice appear in all copies. | |
d7837182 | 12 | * |
98311e4b DH |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
d7837182 | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
25 | * http://www.isc.org/ | |
49733f31 | 26 | * |
98311e4b | 27 | * This software has been written for Internet Systems Consortium |
49733f31 | 28 | * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. |
98311e4b | 29 | * To learn more about Internet Systems Consortium, see |
49733f31 TL |
30 | * ``http://www.isc.org/''. To learn more about Vixie Enterprises, |
31 | * see ``http://www.vix.com''. To learn more about Nominum, Inc., see | |
32 | * ``http://www.nominum.com''. | |
d7837182 TL |
33 | */ |
34 | ||
35 | #ifndef lint | |
36 | static char copyright[] = | |
8da06bb1 | 37 | "$Id: confpars.c,v 1.167 2007/06/08 14:58:20 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; |
d7837182 TL |
38 | #endif /* not lint */ |
39 | ||
40 | #include "dhcpd.h" | |
d7837182 TL |
41 | |
42 | static TIME parsed_time; | |
3a16098f | 43 | static unsigned char global_host_once = 1; |
d7837182 | 44 | |
e15d235d TL |
45 | #if defined (TRACING) |
46 | trace_type_t *trace_readconf_type; | |
47 | trace_type_t *trace_readleases_type; | |
e15d235d TL |
48 | |
49 | void parse_trace_setup () | |
50 | { | |
51 | trace_readconf_type = trace_type_register ("readconf", (void *)0, | |
52 | trace_conf_input, | |
53 | trace_conf_stop, MDL); | |
54 | trace_readleases_type = trace_type_register ("readleases", (void *)0, | |
55 | trace_conf_input, | |
56 | trace_conf_stop, MDL); | |
57 | } | |
662df45a | 58 | #endif |
e15d235d | 59 | |
0b69dcc8 | 60 | /* conf-file :== parameters declarations END_OF_FILE |
2d59f590 TL |
61 | parameters :== <nil> | parameter | parameters parameter |
62 | declarations :== <nil> | declaration | declarations declaration */ | |
d7837182 | 63 | |
35454d8a | 64 | isc_result_t readconf () |
20916cae | 65 | { |
e15d235d | 66 | return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0); |
20916cae TL |
67 | } |
68 | ||
e15d235d TL |
69 | isc_result_t read_conf_file (const char *filename, struct group *group, |
70 | int group_type, int leasep) | |
71 | { | |
72 | int file; | |
73 | struct parse *cfile; | |
74 | isc_result_t status; | |
75 | #if defined (TRACING) | |
76 | char *fbuf, *dbuf; | |
77 | off_t flen; | |
78 | int result; | |
79 | unsigned tflen, ulen; | |
80 | trace_type_t *ttype; | |
81 | ||
82 | if (leasep) | |
83 | ttype = trace_readleases_type; | |
84 | else | |
85 | ttype = trace_readconf_type; | |
86 | ||
87 | /* If we're in playback, we need to snarf the contents of the | |
88 | named file out of the playback file rather than trying to | |
89 | open and read it. */ | |
90 | if (trace_playback ()) { | |
91 | dbuf = (char *)0; | |
92 | tflen = 0; | |
93 | status = trace_get_file (ttype, filename, &tflen, &dbuf); | |
94 | if (status != ISC_R_SUCCESS) | |
95 | return status; | |
96 | ulen = tflen; | |
97 | ||
98 | /* What we get back is filename\0contents, where contents is | |
99 | terminated just by the length. So we figure out the length | |
100 | of the filename, and subtract that and the NUL from the | |
101 | total length to get the length of the contents of the file. | |
102 | We make fbuf a pointer to the contents of the file, and | |
103 | leave dbuf as it is so we can free it later. */ | |
104 | tflen = strlen (dbuf); | |
105 | ulen = ulen - tflen - 1; | |
106 | fbuf = dbuf + tflen + 1; | |
107 | goto memfile; | |
108 | } | |
109 | #endif | |
110 | ||
111 | if ((file = open (filename, O_RDONLY)) < 0) { | |
112 | if (leasep) { | |
113 | log_error ("Can't open lease database %s: %m --", | |
114 | path_dhcpd_db); | |
115 | log_error (" check for failed database %s!", | |
116 | "rewrite attempt"); | |
117 | log_error ("Please read the dhcpd.leases manual%s", | |
118 | " page if you"); | |
119 | log_fatal ("don't know what to do about this."); | |
120 | } else { | |
121 | log_fatal ("Can't open %s: %m", filename); | |
122 | } | |
123 | } | |
124 | ||
125 | cfile = (struct parse *)0; | |
126 | #if defined (TRACING) | |
127 | flen = lseek (file, (off_t)0, SEEK_END); | |
128 | if (flen < 0) { | |
129 | boom: | |
130 | log_fatal ("Can't lseek on %s: %m", filename); | |
131 | } | |
132 | if (lseek (file, (off_t)0, SEEK_SET) < 0) | |
133 | goto boom; | |
134 | /* Can't handle files greater than 2^31-1. */ | |
135 | if (flen > 0x7FFFFFFFUL) | |
136 | log_fatal ("%s: file is too long to buffer.", filename); | |
137 | ulen = flen; | |
138 | ||
139 | /* Allocate a buffer that will be what's written to the tracefile, | |
140 | and also will be what we parse from. */ | |
141 | tflen = strlen (filename); | |
142 | dbuf = dmalloc (ulen + tflen + 1, MDL); | |
143 | if (!dbuf) | |
144 | log_fatal ("No memory for %s (%d bytes)", | |
145 | filename, ulen); | |
146 | ||
147 | /* Copy the name into the beginning, nul-terminated. */ | |
148 | strcpy (dbuf, filename); | |
149 | ||
150 | /* Load the file in after the NUL. */ | |
151 | fbuf = dbuf + tflen + 1; | |
152 | result = read (file, fbuf, ulen); | |
153 | if (result < 0) | |
154 | log_fatal ("Can't read in %s: %m", filename); | |
155 | if (result != ulen) | |
156 | log_fatal ("%s: short read of %d bytes instead of %d.", | |
157 | filename, ulen, result); | |
98311e4b | 158 | close (file); |
e15d235d TL |
159 | memfile: |
160 | /* If we're recording, write out the filename and file contents. */ | |
161 | if (trace_record ()) | |
162 | trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL); | |
dc66a995 | 163 | new_parse (&cfile, -1, fbuf, ulen, filename, 0); /* XXX */ |
e15d235d | 164 | #else |
dc66a995 | 165 | new_parse (&cfile, file, (char *)0, 0, filename, 0); |
e15d235d TL |
166 | #endif |
167 | if (leasep) | |
168 | status = lease_file_subparse (cfile); | |
169 | else | |
170 | status = conf_file_subparse (cfile, group, group_type); | |
171 | end_parse (&cfile); | |
172 | #if defined (TRACING) | |
173 | dfree (dbuf, MDL); | |
174 | #endif | |
e15d235d TL |
175 | return status; |
176 | } | |
177 | ||
178 | #if defined (TRACING) | |
179 | void trace_conf_input (trace_type_t *ttype, unsigned len, char *data) | |
180 | { | |
181 | char *fbuf; | |
182 | unsigned flen; | |
183 | unsigned tflen; | |
184 | struct parse *cfile = (struct parse *)0; | |
185 | static int postconf_initialized; | |
186 | static int leaseconf_initialized; | |
187 | ||
188 | /* Do what's done above, except that we don't have to read in the | |
189 | data, because it's already been read for us. */ | |
190 | tflen = strlen (data); | |
191 | flen = len - tflen - 1; | |
192 | fbuf = data + tflen + 1; | |
193 | ||
194 | /* If we're recording, write out the filename and file contents. */ | |
195 | if (trace_record ()) | |
196 | trace_write_packet (ttype, len, data, MDL); | |
dc66a995 | 197 | new_parse (&cfile, -1, fbuf, flen, data, 0); |
e15d235d TL |
198 | if (ttype == trace_readleases_type) |
199 | lease_file_subparse (cfile); | |
200 | else | |
201 | conf_file_subparse (cfile, root_group, ROOT_GROUP); | |
202 | end_parse (&cfile); | |
203 | ||
204 | /* Postconfiguration needs to be done after the config file | |
205 | has been loaded. */ | |
206 | if (!postconf_initialized && ttype == trace_readconf_type) { | |
207 | postconf_initialization (0); | |
208 | postconf_initialized = 1; | |
209 | } | |
210 | ||
211 | if (!leaseconf_initialized && ttype == trace_readleases_type) { | |
212 | db_startup (0); | |
213 | leaseconf_initialized = 1; | |
d758ad8c | 214 | postdb_startup (); |
e15d235d TL |
215 | } |
216 | } | |
217 | ||
218 | void trace_conf_stop (trace_type_t *ttype) { } | |
219 | #endif | |
220 | ||
0b69dcc8 | 221 | /* conf-file :== parameters declarations END_OF_FILE |
20916cae TL |
222 | parameters :== <nil> | parameter | parameters parameter |
223 | declarations :== <nil> | declaration | declarations declaration */ | |
224 | ||
e15d235d TL |
225 | isc_result_t conf_file_subparse (struct parse *cfile, struct group *group, |
226 | int group_type) | |
d7837182 | 227 | { |
b1b7b521 | 228 | const char *val; |
6f8fb41f | 229 | enum dhcp_token token; |
2d59f590 | 230 | int declaration = 0; |
35454d8a | 231 | int status; |
7e8381e5 | 232 | |
d7837182 | 233 | do { |
b3519f23 | 234 | token = peek_token (&val, (unsigned *)0, cfile); |
0b69dcc8 | 235 | if (token == END_OF_FILE) |
d7837182 | 236 | break; |
20916cae | 237 | declaration = parse_statement (cfile, group, group_type, |
ece6ea33 TL |
238 | (struct host_decl *)0, |
239 | declaration); | |
d7837182 | 240 | } while (1); |
b3519f23 | 241 | token = next_token (&val, (unsigned *)0, cfile); |
88ddda34 | 242 | |
35454d8a | 243 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; |
35454d8a | 244 | return status; |
1358b874 TL |
245 | } |
246 | ||
0b69dcc8 | 247 | /* lease-file :== lease-declarations END_OF_FILE |
5376e3e9 | 248 | lease-statments :== <nil> |
2d59f590 TL |
249 | | lease-declaration |
250 | | lease-declarations lease-declaration */ | |
5376e3e9 | 251 | |
e15d235d | 252 | isc_result_t lease_file_subparse (struct parse *cfile) |
1358b874 | 253 | { |
b1b7b521 | 254 | const char *val; |
6f8fb41f | 255 | enum dhcp_token token; |
35454d8a | 256 | isc_result_t status; |
7dfc8ac2 | 257 | |
1358b874 | 258 | do { |
b3519f23 | 259 | token = next_token (&val, (unsigned *)0, cfile); |
0b69dcc8 | 260 | if (token == END_OF_FILE) |
1358b874 | 261 | break; |
52e79d12 | 262 | if (token == LEASE) { |
20916cae TL |
263 | struct lease *lease = (struct lease *)0; |
264 | if (parse_lease_declaration (&lease, cfile)) { | |
1358b874 | 265 | enter_lease (lease); |
20916cae | 266 | lease_dereference (&lease, MDL); |
96d7d13e | 267 | } else |
35454d8a TL |
268 | parse_warn (cfile, |
269 | "possibly corrupt lease file"); | |
98bd7ca0 DH |
270 | } else if (token == IA_NA) { |
271 | parse_ia_na_declaration(cfile); | |
899d754f | 272 | } else if (token == CLASS) { |
06e77c34 DH |
273 | parse_class_declaration(0, cfile, root_group, |
274 | CLASS_TYPE_CLASS); | |
899d754f | 275 | } else if (token == SUBCLASS) { |
06e77c34 DH |
276 | parse_class_declaration(0, cfile, root_group, |
277 | CLASS_TYPE_SUBCLASS); | |
52e79d12 | 278 | } else if (token == HOST) { |
20916cae | 279 | parse_host_declaration (cfile, root_group); |
35454d8a | 280 | } else if (token == GROUP) { |
20916cae | 281 | parse_group_declaration (cfile, root_group); |
a4ba3160 TL |
282 | #if defined (FAILOVER_PROTOCOL) |
283 | } else if (token == FAILOVER) { | |
284 | parse_failover_state_declaration | |
285 | (cfile, (dhcp_failover_state_t *)0); | |
286 | #endif | |
fe5b0fdd | 287 | #ifdef DHCPv6 |
98bd7ca0 DH |
288 | } else if (token == SERVER_DUID) { |
289 | parse_server_duid(cfile); | |
fe5b0fdd | 290 | #endif /* DHCPv6 */ |
52e79d12 TL |
291 | } else { |
292 | log_error ("Corrupt lease file - possible data loss!"); | |
293 | skip_to_semi (cfile); | |
1358b874 TL |
294 | } |
295 | ||
296 | } while (1); | |
35454d8a TL |
297 | |
298 | status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS; | |
35454d8a | 299 | return status; |
d7837182 TL |
300 | } |
301 | ||
2d59f590 TL |
302 | /* statement :== parameter | declaration |
303 | ||
6d103865 | 304 | parameter :== DEFAULT_LEASE_TIME lease_time |
2d59f590 TL |
305 | | MAX_LEASE_TIME lease_time |
306 | | DYNAMIC_BOOTP_LEASE_CUTOFF date | |
307 | | DYNAMIC_BOOTP_LEASE_LENGTH lease_time | |
308 | | BOOT_UNKNOWN_CLIENTS boolean | |
309 | | ONE_LEASE_PER_CLIENT boolean | |
5fea7b10 | 310 | | GET_LEASE_HOSTNAMES boolean |
c256bae9 | 311 | | USE_HOST_DECL_NAME boolean |
2d59f590 TL |
312 | | NEXT_SERVER ip-addr-or-hostname SEMI |
313 | | option_parameter | |
314 | | SERVER-IDENTIFIER ip-addr-or-hostname SEMI | |
315 | | FILENAME string-parameter | |
316 | | SERVER_NAME string-parameter | |
317 | | hardware-parameter | |
318 | | fixed-address-parameter | |
99fd97cc TL |
319 | | ALLOW allow-deny-keyword |
320 | | DENY allow-deny-keyword | |
59b85ebd | 321 | | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean |
763adef1 TL |
322 | | AUTHORITATIVE |
323 | | NOT AUTHORITATIVE | |
2d59f590 TL |
324 | |
325 | declaration :== host-declaration | |
326 | | group-declaration | |
327 | | shared-network-declaration | |
328 | | subnet-declaration | |
329 | | VENDOR_CLASS class-declaration | |
330 | | USER_CLASS class-declaration | |
331 | | RANGE address-range-declaration */ | |
332 | ||
333 | int parse_statement (cfile, group, type, host_decl, declaration) | |
35454d8a | 334 | struct parse *cfile; |
7dfc8ac2 TL |
335 | struct group *group; |
336 | int type; | |
337 | struct host_decl *host_decl; | |
2d59f590 | 338 | int declaration; |
d7837182 | 339 | { |
6f8fb41f | 340 | enum dhcp_token token; |
b1b7b521 | 341 | const char *val; |
7dfc8ac2 | 342 | struct shared_network *share; |
7dfc8ac2 | 343 | char *t, *n; |
ece6ea33 TL |
344 | struct expression *expr; |
345 | struct data_string data; | |
7dfc8ac2 | 346 | struct hardware hardware; |
ece6ea33 | 347 | struct executable_statement *et, *ep; |
f7fdb216 | 348 | struct option *option = NULL; |
ece6ea33 TL |
349 | struct option_cache *cache; |
350 | int lose; | |
74f45f96 | 351 | struct data_string key_id; |
b1b7b521 | 352 | int known; |
20916cae | 353 | isc_result_t status; |
f7fdb216 | 354 | unsigned code; |
d7837182 | 355 | |
b3519f23 | 356 | token = peek_token (&val, (unsigned *)0, cfile); |
e68de775 TL |
357 | |
358 | switch (token) { | |
20916cae | 359 | case INCLUDE: |
b3519f23 TL |
360 | next_token (&val, (unsigned *)0, cfile); |
361 | token = next_token (&val, (unsigned *)0, cfile); | |
20916cae TL |
362 | if (token != STRING) { |
363 | parse_warn (cfile, "filename string expected."); | |
364 | skip_to_semi (cfile); | |
365 | } else { | |
e15d235d | 366 | status = read_conf_file (val, group, type, 0); |
20916cae TL |
367 | if (status != ISC_R_SUCCESS) |
368 | parse_warn (cfile, "%s: bad parse.", val); | |
369 | parse_semi (cfile); | |
370 | } | |
371 | return 1; | |
372 | ||
d7837182 | 373 | case HOST: |
b3519f23 | 374 | next_token (&val, (unsigned *)0, cfile); |
3a16098f DH |
375 | if (type != HOST_DECL && type != CLASS_DECL) { |
376 | if (global_host_once && | |
377 | (type == SUBNET_DECL || type == SHARED_NET_DECL)) { | |
378 | global_host_once = 0; | |
379 | log_error("WARNING: Host declarations are " | |
380 | "global. They are not limited to " | |
381 | "the scope you declared them in."); | |
382 | } | |
383 | ||
2d59f590 | 384 | parse_host_declaration (cfile, group); |
3a16098f | 385 | } else { |
35454d8a TL |
386 | parse_warn (cfile, |
387 | "host declarations not allowed here."); | |
7dfc8ac2 | 388 | skip_to_semi (cfile); |
d7837182 | 389 | } |
7dfc8ac2 TL |
390 | return 1; |
391 | ||
392 | case GROUP: | |
b3519f23 | 393 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 394 | if (type != HOST_DECL && type != CLASS_DECL) |
2d59f590 | 395 | parse_group_declaration (cfile, group); |
7dfc8ac2 | 396 | else { |
35454d8a TL |
397 | parse_warn (cfile, |
398 | "group declarations not allowed here."); | |
7dfc8ac2 | 399 | skip_to_semi (cfile); |
d7837182 | 400 | } |
7dfc8ac2 TL |
401 | return 1; |
402 | ||
1f814ff2 | 403 | case SHARED_NETWORK: |
b3519f23 | 404 | next_token (&val, (unsigned *)0, cfile); |
2d59f590 TL |
405 | if (type == SHARED_NET_DECL || |
406 | type == HOST_DECL || | |
ece6ea33 TL |
407 | type == SUBNET_DECL || |
408 | type == CLASS_DECL) { | |
35454d8a | 409 | parse_warn (cfile, "shared-network parameters not %s.", |
7dfc8ac2 TL |
410 | "allowed here"); |
411 | skip_to_semi (cfile); | |
412 | break; | |
1f814ff2 | 413 | } |
7dfc8ac2 | 414 | |
2d59f590 | 415 | parse_shared_net_declaration (cfile, group); |
7dfc8ac2 TL |
416 | return 1; |
417 | ||
685963dc | 418 | case SUBNET: |
98bd7ca0 | 419 | case SUBNET6: |
b3519f23 | 420 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 TL |
421 | if (type == HOST_DECL || type == SUBNET_DECL || |
422 | type == CLASS_DECL) { | |
35454d8a TL |
423 | parse_warn (cfile, |
424 | "subnet declarations not allowed here."); | |
7dfc8ac2 TL |
425 | skip_to_semi (cfile); |
426 | return 1; | |
427 | } | |
428 | ||
2d59f590 | 429 | /* If we're in a subnet declaration, just do the parse. */ |
98bd7ca0 DH |
430 | if (group->shared_network) { |
431 | if (token == SUBNET) { | |
432 | parse_subnet_declaration(cfile, | |
433 | group->shared_network); | |
434 | } else { | |
435 | parse_subnet6_declaration(cfile, | |
436 | group->shared_network); | |
437 | } | |
7dfc8ac2 TL |
438 | break; |
439 | } | |
440 | ||
441 | /* Otherwise, cons up a fake shared network structure | |
442 | and populate it with the lone subnet... */ | |
443 | ||
20916cae TL |
444 | share = (struct shared_network *)0; |
445 | status = shared_network_allocate (&share, MDL); | |
446 | if (status != ISC_R_SUCCESS) | |
447 | log_fatal ("Can't allocate shared subnet: %s", | |
448 | isc_result_totext (status)); | |
449 | if (!clone_group (&share -> group, group, MDL)) | |
f84d544b | 450 | log_fatal ("Can't allocate group for shared net"); |
6ceb9118 TL |
451 | shared_network_reference (&share -> group -> shared_network, |
452 | share, MDL); | |
7dfc8ac2 | 453 | |
98bd7ca0 DH |
454 | if (token == SUBNET) { |
455 | parse_subnet_declaration(cfile, share); | |
456 | } else { | |
457 | parse_subnet6_declaration(cfile, share); | |
458 | } | |
763adef1 TL |
459 | |
460 | /* share -> subnets is the subnet we just parsed. */ | |
98bd7ca0 DH |
461 | if (share->subnets) { |
462 | interface_reference(&share->interface, | |
463 | share->subnets->interface, | |
464 | MDL); | |
7dfc8ac2 | 465 | |
763adef1 | 466 | /* Make the shared network name from network number. */ |
98bd7ca0 DH |
467 | if (token == SUBNET) { |
468 | n = piaddrmask(&share->subnets->net, | |
469 | &share->subnets->netmask); | |
470 | } else { | |
471 | n = piaddrcidr(&share->subnets->net, | |
472 | share->subnets->prefix_len); | |
473 | } | |
474 | ||
475 | share->name = strdup(n); | |
476 | ||
477 | if (share->name == NULL) | |
478 | log_fatal("Out of memory allocating default " | |
479 | "shared network name (\"%s\").", n); | |
763adef1 TL |
480 | |
481 | /* Copy the authoritative parameter from the subnet, | |
482 | since there is no opportunity to declare it here. */ | |
98bd7ca0 DH |
483 | share->group->authoritative = |
484 | share->subnets->group->authoritative; | |
485 | enter_shared_network(share); | |
d7837182 | 486 | } |
98bd7ca0 | 487 | shared_network_dereference(&share, MDL); |
7dfc8ac2 TL |
488 | return 1; |
489 | ||
24a75c03 | 490 | case VENDOR_CLASS: |
b3519f23 | 491 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 492 | if (type == CLASS_DECL) { |
35454d8a TL |
493 | parse_warn (cfile, |
494 | "class declarations not allowed here."); | |
ece6ea33 TL |
495 | skip_to_semi (cfile); |
496 | break; | |
497 | } | |
06e77c34 | 498 | parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR); |
7dfc8ac2 TL |
499 | return 1; |
500 | ||
24a75c03 | 501 | case USER_CLASS: |
b3519f23 | 502 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 503 | if (type == CLASS_DECL) { |
35454d8a TL |
504 | parse_warn (cfile, |
505 | "class declarations not allowed here."); | |
ece6ea33 TL |
506 | skip_to_semi (cfile); |
507 | break; | |
508 | } | |
06e77c34 | 509 | parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER); |
7dfc8ac2 | 510 | return 1; |
1f814ff2 | 511 | |
ece6ea33 | 512 | case CLASS: |
b3519f23 | 513 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 514 | if (type == CLASS_DECL) { |
35454d8a TL |
515 | parse_warn (cfile, |
516 | "class declarations not allowed here."); | |
59b85ebd | 517 | skip_to_semi (cfile); |
ece6ea33 | 518 | break; |
59b85ebd | 519 | } |
06e77c34 | 520 | parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS); |
ece6ea33 | 521 | return 1; |
59b85ebd | 522 | |
ece6ea33 | 523 | case SUBCLASS: |
b3519f23 | 524 | next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 525 | if (type == CLASS_DECL) { |
35454d8a TL |
526 | parse_warn (cfile, |
527 | "class declarations not allowed here."); | |
ece6ea33 | 528 | skip_to_semi (cfile); |
7dfc8ac2 | 529 | break; |
7dfc8ac2 | 530 | } |
06e77c34 DH |
531 | parse_class_declaration(NULL, cfile, group, |
532 | CLASS_TYPE_SUBCLASS); | |
ece6ea33 | 533 | return 1; |
7dfc8ac2 TL |
534 | |
535 | case HARDWARE: | |
b3519f23 | 536 | next_token (&val, (unsigned *)0, cfile); |
76981d9f | 537 | memset (&hardware, 0, sizeof hardware); |
2178df03 DH |
538 | if (host_decl && memcmp(&hardware, &(host_decl->interface), |
539 | sizeof(hardware)) != 0) { | |
540 | parse_warn(cfile, "Host %s hardware address already " | |
541 | "configured.", host_decl->name); | |
542 | break; | |
543 | } | |
544 | ||
2d59f590 | 545 | parse_hardware_param (cfile, &hardware); |
7dfc8ac2 TL |
546 | if (host_decl) |
547 | host_decl -> interface = hardware; | |
548 | else | |
35454d8a | 549 | parse_warn (cfile, "hardware address parameter %s", |
7dfc8ac2 TL |
550 | "not allowed here."); |
551 | break; | |
552 | ||
553 | case FIXED_ADDR: | |
98bd7ca0 DH |
554 | case FIXED_ADDR6: |
555 | next_token(&val, NULL, cfile); | |
556 | cache = NULL; | |
557 | if (parse_fixed_addr_param(&cache, cfile, token)) { | |
98311e4b | 558 | if (host_decl) { |
98bd7ca0 DH |
559 | if (host_decl->fixed_addr) { |
560 | option_cache_dereference(&cache, MDL); | |
561 | parse_warn(cfile, | |
562 | "Only one fixed address " | |
563 | "declaration per host."); | |
98311e4b | 564 | } else { |
98bd7ca0 | 565 | host_decl->fixed_addr = cache; |
98311e4b DH |
566 | } |
567 | } else { | |
98bd7ca0 DH |
568 | parse_warn(cfile, |
569 | "fixed-address parameter not " | |
570 | "allowed here."); | |
571 | option_cache_dereference(&cache, MDL); | |
20916cae | 572 | } |
6f8fb41f | 573 | } |
7dfc8ac2 TL |
574 | break; |
575 | ||
f63b4929 | 576 | case POOL: |
b3519f23 | 577 | next_token (&val, (unsigned *)0, cfile); |
f63b4929 | 578 | if (type != SUBNET_DECL && type != SHARED_NET_DECL) { |
35454d8a | 579 | parse_warn (cfile, "pool declared outside of network"); |
61252edf EH |
580 | skip_to_semi(cfile); |
581 | } else if (type == POOL_DECL) { | |
35454d8a | 582 | parse_warn (cfile, "pool declared within pool."); |
61252edf EH |
583 | skip_to_semi(cfile); |
584 | } else | |
585 | parse_pool_statement (cfile, group, type); | |
586 | ||
f63b4929 TL |
587 | return declaration; |
588 | ||
7dfc8ac2 | 589 | case RANGE: |
b3519f23 | 590 | next_token (&val, (unsigned *)0, cfile); |
2d59f590 | 591 | if (type != SUBNET_DECL || !group -> subnet) { |
35454d8a TL |
592 | parse_warn (cfile, |
593 | "range declaration not allowed here."); | |
7dfc8ac2 | 594 | skip_to_semi (cfile); |
2d59f590 | 595 | return declaration; |
7dfc8ac2 | 596 | } |
98311e4b DH |
597 | parse_address_range (cfile, group, type, (struct pool *)0, |
598 | (struct lease **)0); | |
2d59f590 | 599 | return declaration; |
7dfc8ac2 | 600 | |
fe5b0fdd | 601 | #ifdef DHCPv6 |
98bd7ca0 DH |
602 | case RANGE6: |
603 | next_token(NULL, NULL, cfile); | |
604 | if ((type != SUBNET_DECL) || (group->subnet == NULL)) { | |
605 | parse_warn (cfile, | |
606 | "range6 declaration not allowed here."); | |
607 | skip_to_semi(cfile); | |
608 | return declaration; | |
609 | } | |
610 | parse_address_range6(cfile, group); | |
611 | return declaration; | |
fe5b0fdd | 612 | #endif /* DHCPv6 */ |
98bd7ca0 | 613 | |
763adef1 | 614 | case TOKEN_NOT: |
b3519f23 TL |
615 | token = next_token (&val, (unsigned *)0, cfile); |
616 | token = next_token (&val, (unsigned *)0, cfile); | |
763adef1 TL |
617 | switch (token) { |
618 | case AUTHORITATIVE: | |
619 | group -> authoritative = 0; | |
620 | goto authoritative; | |
621 | default: | |
35454d8a | 622 | parse_warn (cfile, "expecting assertion"); |
763adef1 TL |
623 | skip_to_semi (cfile); |
624 | break; | |
625 | } | |
626 | break; | |
627 | case AUTHORITATIVE: | |
b3519f23 | 628 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 TL |
629 | group -> authoritative = 1; |
630 | authoritative: | |
1b8223ae | 631 | if (type == HOST_DECL) |
35454d8a | 632 | parse_warn (cfile, "authority makes no sense here."); |
763adef1 TL |
633 | parse_semi (cfile); |
634 | break; | |
635 | ||
8230a054 TL |
636 | /* "server-identifier" is a special hack, equivalent to |
637 | "option dhcp-server-identifier". */ | |
638 | case SERVER_IDENTIFIER: | |
f7fdb216 DH |
639 | code = DHO_DHCP_SERVER_IDENTIFIER; |
640 | if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, | |
641 | &code, 0, MDL)) | |
642 | log_fatal("Server identifier not in hash (%s:%d).", | |
643 | MDL); | |
b3519f23 | 644 | token = next_token (&val, (unsigned *)0, cfile); |
8230a054 TL |
645 | goto finish_option; |
646 | ||
6f8fb41f | 647 | case OPTION: |
b3519f23 TL |
648 | token = next_token (&val, (unsigned *)0, cfile); |
649 | token = peek_token (&val, (unsigned *)0, cfile); | |
822d95c9 TL |
650 | if (token == SPACE) { |
651 | if (type != ROOT_GROUP) { | |
35454d8a TL |
652 | parse_warn (cfile, |
653 | "option space definitions %s", | |
436f1c8c | 654 | "may not be scoped."); |
822d95c9 | 655 | skip_to_semi (cfile); |
822d95c9 TL |
656 | break; |
657 | } | |
658 | parse_option_space_decl (cfile); | |
659 | return declaration; | |
660 | } | |
661 | ||
b1b7b521 | 662 | known = 0; |
f7fdb216 DH |
663 | status = parse_option_name(cfile, 1, &known, &option); |
664 | if (status == ISC_R_SUCCESS) { | |
b3519f23 | 665 | token = peek_token (&val, (unsigned *)0, cfile); |
8230a054 TL |
666 | if (token == CODE) { |
667 | if (type != ROOT_GROUP) { | |
35454d8a | 668 | parse_warn (cfile, |
ab58ff49 | 669 | "option definitions%s", |
822d95c9 | 670 | " may not be scoped."); |
8230a054 | 671 | skip_to_semi (cfile); |
f7fdb216 | 672 | option_dereference(&option, MDL); |
8230a054 TL |
673 | break; |
674 | } | |
b3519f23 | 675 | next_token (&val, (unsigned *)0, cfile); |
f7fdb216 DH |
676 | parse_option_code_definition(cfile, option); |
677 | option_dereference(&option, MDL); | |
8230a054 TL |
678 | return declaration; |
679 | } | |
680 | ||
681 | /* If this wasn't an option code definition, don't | |
682 | allow an unknown option. */ | |
b1b7b521 | 683 | if (!known) { |
35454d8a | 684 | parse_warn (cfile, "unknown option %s.%s", |
8230a054 TL |
685 | option -> universe -> name, |
686 | option -> name); | |
687 | skip_to_semi (cfile); | |
f7fdb216 | 688 | option_dereference(&option, MDL); |
8230a054 TL |
689 | return declaration; |
690 | } | |
691 | ||
692 | finish_option: | |
79a65726 TL |
693 | et = (struct executable_statement *)0; |
694 | if (!parse_option_statement | |
695 | (&et, cfile, 1, option, | |
696 | supersede_option_statement)) | |
6f8fb41f | 697 | return declaration; |
f7fdb216 | 698 | option_dereference(&option, MDL); |
6f8fb41f TL |
699 | goto insert_statement; |
700 | } else | |
701 | return declaration; | |
702 | ||
703 | break; | |
704 | ||
763adef1 | 705 | case FAILOVER: |
98311e4b | 706 | if (type != ROOT_GROUP && type != SHARED_NET_DECL) { |
9e9b2261 TL |
707 | parse_warn (cfile, "failover peers may only be %s", |
708 | "defined in shared-network"); | |
709 | log_error ("declarations and the outer scope."); | |
710 | skip_to_semi (cfile); | |
711 | break; | |
712 | } | |
b3519f23 | 713 | token = next_token (&val, (unsigned *)0, cfile); |
22009f79 | 714 | #if defined (FAILOVER_PROTOCOL) |
763adef1 | 715 | parse_failover_peer (cfile, group, type); |
22009f79 TL |
716 | #else |
717 | parse_warn (cfile, "No failover support."); | |
718 | skip_to_semi (cfile); | |
763adef1 | 719 | #endif |
22009f79 | 720 | break; |
98bd7ca0 | 721 | |
fe5b0fdd | 722 | #ifdef DHCPv6 |
98bd7ca0 DH |
723 | case SERVER_DUID: |
724 | parse_server_duid_conf(cfile); | |
725 | break; | |
fe5b0fdd | 726 | #endif /* DHCPv6 */ |
763adef1 | 727 | |
d7837182 | 728 | default: |
ece6ea33 | 729 | et = (struct executable_statement *)0; |
588af269 TL |
730 | lose = 0; |
731 | if (!parse_executable_statement (&et, cfile, &lose, | |
732 | context_any)) { | |
733 | if (!lose) { | |
734 | if (declaration) | |
35454d8a TL |
735 | parse_warn (cfile, |
736 | "expecting a declaration"); | |
588af269 | 737 | else |
35454d8a | 738 | parse_warn (cfile, |
ab58ff49 | 739 | "expecting a parameter %s", |
35454d8a | 740 | "or declaration"); |
588af269 | 741 | skip_to_semi (cfile); |
ece6ea33 | 742 | } |
ece6ea33 TL |
743 | return declaration; |
744 | } | |
026975bb TL |
745 | if (!et) |
746 | return declaration; | |
ece6ea33 TL |
747 | insert_statement: |
748 | if (group -> statements) { | |
79a65726 TL |
749 | int multi = 0; |
750 | ||
751 | /* If this set of statements is only referenced | |
752 | by this group, just add the current statement | |
753 | to the end of the chain. */ | |
ece6ea33 TL |
754 | for (ep = group -> statements; ep -> next; |
755 | ep = ep -> next) | |
79a65726 TL |
756 | if (ep -> refcnt > 1) /* XXX */ |
757 | multi = 1; | |
758 | if (!multi) { | |
436f1c8c TL |
759 | executable_statement_reference (&ep -> next, |
760 | et, MDL); | |
d758ad8c | 761 | executable_statement_dereference (&et, MDL); |
79a65726 TL |
762 | return declaration; |
763 | } | |
ece6ea33 | 764 | |
79a65726 TL |
765 | /* Otherwise, make a parent chain, and put the |
766 | current group statements first and the new | |
767 | statement in the next pointer. */ | |
768 | ep = (struct executable_statement *)0; | |
436f1c8c | 769 | if (!executable_statement_allocate (&ep, MDL)) |
79a65726 TL |
770 | log_fatal ("No memory for statements."); |
771 | ep -> op = statements_statement; | |
436f1c8c TL |
772 | executable_statement_reference (&ep -> data.statements, |
773 | group -> statements, | |
774 | MDL); | |
775 | executable_statement_reference (&ep -> next, et, MDL); | |
776 | executable_statement_dereference (&group -> statements, | |
777 | MDL); | |
778 | executable_statement_reference (&group -> statements, | |
779 | ep, MDL); | |
d758ad8c TL |
780 | executable_statement_dereference (&ep, MDL); |
781 | } else { | |
436f1c8c TL |
782 | executable_statement_reference (&group -> statements, |
783 | et, MDL); | |
d758ad8c TL |
784 | } |
785 | executable_statement_dereference (&et, MDL); | |
6f8fb41f | 786 | return declaration; |
d7837182 | 787 | } |
1f814ff2 | 788 | |
7dfc8ac2 | 789 | return 0; |
d7837182 TL |
790 | } |
791 | ||
763adef1 TL |
792 | #if defined (FAILOVER_PROTOCOL) |
793 | void parse_failover_peer (cfile, group, type) | |
35454d8a | 794 | struct parse *cfile; |
763adef1 TL |
795 | struct group *group; |
796 | int type; | |
797 | { | |
798 | enum dhcp_token token; | |
b1b7b521 | 799 | const char *val; |
9e9b2261 TL |
800 | dhcp_failover_state_t *peer; |
801 | u_int32_t *tp; | |
763adef1 | 802 | char *name; |
9e9b2261 TL |
803 | u_int32_t split; |
804 | u_int8_t hba [32]; | |
165bce70 | 805 | unsigned hba_len = sizeof hba; |
9e9b2261 TL |
806 | int i; |
807 | struct expression *expr; | |
e9623235 | 808 | isc_result_t status; |
05815916 | 809 | dhcp_failover_config_t *cp; |
763adef1 | 810 | |
b3519f23 | 811 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 812 | if (token != PEER) { |
9e9b2261 | 813 | parse_warn (cfile, "expecting \"peer\""); |
763adef1 TL |
814 | skip_to_semi (cfile); |
815 | return; | |
816 | } | |
817 | ||
b3519f23 | 818 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 819 | if (is_identifier (token) || token == STRING) { |
436f1c8c | 820 | name = dmalloc (strlen (val) + 1, MDL); |
9e9b2261 | 821 | if (!name) |
8ae2d595 | 822 | log_fatal ("no memory for peer name %s", name); |
9e9b2261 | 823 | strcpy (name, val); |
763adef1 | 824 | } else { |
9e9b2261 | 825 | parse_warn (cfile, "expecting failover peer name."); |
763adef1 TL |
826 | skip_to_semi (cfile); |
827 | return; | |
828 | } | |
829 | ||
830 | /* See if there's a peer declaration by this name. */ | |
9e9b2261 | 831 | peer = (dhcp_failover_state_t *)0; |
20916cae | 832 | find_failover_peer (&peer, name, MDL); |
763adef1 | 833 | |
b3519f23 | 834 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 835 | if (token == SEMI) { |
436f1c8c | 836 | dfree (name, MDL); |
763adef1 | 837 | if (type != SHARED_NET_DECL) |
35454d8a | 838 | parse_warn (cfile, "failover peer reference not %s", |
763adef1 TL |
839 | "in shared-network declaration"); |
840 | else { | |
841 | if (!peer) { | |
35454d8a | 842 | parse_warn (cfile, "reference to unknown%s%s", |
763adef1 TL |
843 | " failover peer ", name); |
844 | return; | |
845 | } | |
20916cae TL |
846 | dhcp_failover_state_reference |
847 | (&group -> shared_network -> failover_peer, | |
848 | peer, MDL); | |
763adef1 | 849 | } |
20916cae | 850 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 | 851 | return; |
a4ba3160 | 852 | } else if (token == STATE) { |
763adef1 | 853 | if (!peer) { |
a4ba3160 | 854 | parse_warn (cfile, "state declaration for unknown%s%s", |
763adef1 TL |
855 | " failover peer ", name); |
856 | return; | |
857 | } | |
a4ba3160 | 858 | parse_failover_state_declaration (cfile, peer); |
20916cae | 859 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
860 | return; |
861 | } else if (token != LBRACE) { | |
35454d8a | 862 | parse_warn (cfile, "expecting left brace"); |
763adef1 TL |
863 | skip_to_semi (cfile); |
864 | } | |
865 | ||
866 | /* Make sure this isn't a redeclaration. */ | |
867 | if (peer) { | |
35454d8a | 868 | parse_warn (cfile, "redeclaration of failover peer %s", name); |
763adef1 | 869 | skip_to_rbrace (cfile, 1); |
20916cae | 870 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
871 | return; |
872 | } | |
873 | ||
20916cae TL |
874 | status = dhcp_failover_state_allocate (&peer, MDL); |
875 | if (status != ISC_R_SUCCESS) | |
876 | log_fatal ("Can't allocate failover peer %s: %s", | |
877 | name, isc_result_totext (status)); | |
763adef1 TL |
878 | |
879 | /* Save the name. */ | |
880 | peer -> name = name; | |
881 | ||
882 | do { | |
05815916 TL |
883 | cp = &peer -> me; |
884 | peer: | |
b3519f23 | 885 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 TL |
886 | switch (token) { |
887 | case RBRACE: | |
888 | break; | |
9e9b2261 | 889 | |
763adef1 TL |
890 | case PRIMARY: |
891 | peer -> i_am = primary; | |
892 | break; | |
9e9b2261 | 893 | |
763adef1 TL |
894 | case SECONDARY: |
895 | peer -> i_am = secondary; | |
007e3ee4 TL |
896 | if (peer -> hba) |
897 | parse_warn (cfile, | |
898 | "secondary may not define %s", | |
899 | "load balance settings."); | |
763adef1 | 900 | break; |
9e9b2261 | 901 | |
e9623235 | 902 | case PEER: |
05815916 TL |
903 | cp = &peer -> partner; |
904 | goto peer; | |
e9623235 TL |
905 | |
906 | case ADDRESS: | |
9e9b2261 TL |
907 | expr = (struct expression *)0; |
908 | if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { | |
763adef1 | 909 | skip_to_rbrace (cfile, 1); |
20916cae | 910 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
911 | return; |
912 | } | |
05815916 TL |
913 | option_cache (&cp -> address, |
914 | (struct data_string *)0, expr, | |
d758ad8c | 915 | (struct option *)0, MDL); |
436f1c8c | 916 | expression_dereference (&expr, MDL); |
763adef1 | 917 | break; |
e9623235 | 918 | |
763adef1 | 919 | case PORT: |
b3519f23 | 920 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 921 | if (token != NUMBER) { |
35454d8a | 922 | parse_warn (cfile, "expecting number"); |
763adef1 TL |
923 | skip_to_rbrace (cfile, 1); |
924 | } | |
05815916 | 925 | cp -> port = atoi (val); |
763adef1 | 926 | break; |
9e9b2261 | 927 | |
2426234f DH |
928 | case MAX_LEASE_MISBALANCE: |
929 | tp = &peer->max_lease_misbalance; | |
930 | goto parse_idle; | |
931 | ||
932 | case MAX_LEASE_OWNERSHIP: | |
933 | tp = &peer->max_lease_ownership; | |
934 | goto parse_idle; | |
935 | ||
936 | case MAX_BALANCE: | |
937 | tp = &peer->max_balance; | |
938 | goto parse_idle; | |
939 | ||
940 | case MIN_BALANCE: | |
941 | tp = &peer->min_balance; | |
942 | goto parse_idle; | |
943 | ||
763adef1 | 944 | case MAX_RESPONSE_DELAY: |
05815916 | 945 | tp = &cp -> max_response_delay; |
763adef1 | 946 | parse_idle: |
b3519f23 | 947 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 948 | if (token != NUMBER) { |
35454d8a | 949 | parse_warn (cfile, "expecting number."); |
763adef1 | 950 | skip_to_rbrace (cfile, 1); |
20916cae | 951 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
952 | return; |
953 | } | |
954 | *tp = atoi (val); | |
9e9b2261 TL |
955 | break; |
956 | ||
957 | case MAX_UNACKED_UPDATES: | |
05815916 | 958 | tp = &cp -> max_flying_updates; |
9e9b2261 TL |
959 | goto parse_idle; |
960 | ||
961 | case MCLT: | |
962 | tp = &peer -> mclt; | |
963 | goto parse_idle; | |
964 | ||
965 | case HBA: | |
e9623235 | 966 | hba_len = 32; |
007e3ee4 TL |
967 | if (peer -> i_am == secondary) |
968 | parse_warn (cfile, | |
969 | "secondary may not define %s", | |
970 | "load balance settings."); | |
9e9b2261 | 971 | if (!parse_numeric_aggregate (cfile, hba, &hba_len, |
e9623235 | 972 | COLON, 16, 8)) { |
9e9b2261 | 973 | skip_to_rbrace (cfile, 1); |
20916cae | 974 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
975 | return; |
976 | } | |
e9623235 TL |
977 | if (hba_len != 32) { |
978 | parse_warn (cfile, | |
979 | "HBA must be exactly 32 bytes."); | |
980 | dfree (hba, MDL); | |
981 | break; | |
982 | } | |
9e9b2261 | 983 | make_hba: |
436f1c8c | 984 | peer -> hba = dmalloc (32, MDL); |
9e9b2261 | 985 | if (!peer -> hba) { |
436f1c8c TL |
986 | dfree (peer -> name, MDL); |
987 | dfree (peer, MDL); | |
9e9b2261 TL |
988 | } |
989 | memcpy (peer -> hba, hba, 32); | |
990 | break; | |
991 | ||
992 | case SPLIT: | |
b3519f23 | 993 | token = next_token (&val, (unsigned *)0, cfile); |
007e3ee4 TL |
994 | if (peer -> i_am == secondary) |
995 | parse_warn (cfile, | |
996 | "secondary may not define %s", | |
997 | "load balance settings."); | |
9e9b2261 TL |
998 | if (token != NUMBER) { |
999 | parse_warn (cfile, "expecting number"); | |
20916cae | 1000 | badsplit: |
9e9b2261 | 1001 | skip_to_rbrace (cfile, 1); |
20916cae | 1002 | dhcp_failover_state_dereference (&peer, MDL); |
9e9b2261 TL |
1003 | return; |
1004 | } | |
20916cae | 1005 | split = atoi (val); |
9e9b2261 TL |
1006 | if (split > 255) { |
1007 | parse_warn (cfile, "split must be < 256"); | |
1008 | } else { | |
1009 | memset (hba, 0, sizeof hba); | |
1010 | for (i = 0; i < split; i++) { | |
1011 | if (i < split) | |
1012 | hba [i / 8] |= (1 << (i & 7)); | |
1013 | } | |
1014 | goto make_hba; | |
1015 | } | |
1016 | break; | |
1017 | ||
e9623235 | 1018 | case LOAD: |
b3519f23 | 1019 | token = next_token (&val, (unsigned *)0, cfile); |
e9623235 TL |
1020 | if (token != BALANCE) { |
1021 | parse_warn (cfile, "expecting 'balance'"); | |
1022 | badload: | |
1023 | skip_to_rbrace (cfile, 1); | |
1024 | break; | |
1025 | } | |
b3519f23 | 1026 | token = next_token (&val, (unsigned *)0, cfile); |
e9623235 TL |
1027 | if (token != TOKEN_MAX) { |
1028 | parse_warn (cfile, "expecting 'max'"); | |
1029 | goto badload; | |
1030 | } | |
b3519f23 | 1031 | token = next_token (&val, (unsigned *)0, cfile); |
e9623235 TL |
1032 | if (token != SECONDS) { |
1033 | parse_warn (cfile, "expecting 'secs'"); | |
1034 | goto badload; | |
1035 | } | |
b3519f23 | 1036 | token = next_token (&val, (unsigned *)0, cfile); |
e9623235 TL |
1037 | if (token != NUMBER) { |
1038 | parse_warn (cfile, "expecting number"); | |
1039 | goto badload; | |
1040 | } | |
1041 | peer -> load_balance_max_secs = atoi (val); | |
1042 | break; | |
1043 | ||
763adef1 | 1044 | default: |
35454d8a TL |
1045 | parse_warn (cfile, |
1046 | "invalid statement in peer declaration"); | |
763adef1 | 1047 | skip_to_rbrace (cfile, 1); |
20916cae | 1048 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
1049 | return; |
1050 | } | |
e9623235 TL |
1051 | if (token != RBRACE && !parse_semi (cfile)) { |
1052 | skip_to_rbrace (cfile, 1); | |
20916cae | 1053 | dhcp_failover_state_dereference (&peer, MDL); |
e9623235 TL |
1054 | return; |
1055 | } | |
763adef1 | 1056 | } while (token != RBRACE); |
98311e4b DH |
1057 | |
1058 | /* me.address can be null; the failover link initiate code tries to | |
1059 | * derive a reasonable address to use. | |
1060 | */ | |
1061 | if (!peer -> partner.address) | |
1062 | parse_warn (cfile, "peer address may not be omitted"); | |
1063 | ||
1064 | /* XXX - when/if we get a port number assigned, just set as default */ | |
1065 | if (!peer -> me.port) | |
1066 | parse_warn (cfile, "local port may not be omitted"); | |
1067 | if (!peer -> partner.port) | |
1068 | parse_warn (cfile, "peer port may not be omitted"); | |
1069 | ||
1070 | if (peer -> i_am == primary) { | |
1071 | if (!peer -> hba) { | |
1072 | parse_warn (cfile, | |
007e3ee4 | 1073 | "primary failover server must have hba or split."); |
98311e4b DH |
1074 | } else if (!peer -> mclt) { |
1075 | parse_warn (cfile, | |
1076 | "primary failover server must have mclt."); | |
1077 | } | |
1078 | } | |
007e3ee4 | 1079 | |
2426234f DH |
1080 | if (!peer->max_lease_misbalance) |
1081 | peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE; | |
1082 | if (!peer->max_lease_ownership) | |
1083 | peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP; | |
1084 | if (!peer->max_balance) | |
1085 | peer->max_balance = DEFAULT_MAX_BALANCE_TIME; | |
1086 | if (!peer->min_balance) | |
1087 | peer->min_balance = DEFAULT_MIN_BALANCE_TIME; | |
1088 | if (!peer->me.max_flying_updates) | |
1089 | peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES; | |
1090 | if (!peer->me.max_response_delay) | |
1091 | peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY; | |
1092 | ||
1093 | if (type == SHARED_NET_DECL) | |
1094 | group->shared_network->failover_peer = peer; | |
6f8a0361 TL |
1095 | |
1096 | /* Set the initial state. */ | |
1097 | if (peer -> i_am == primary) { | |
1098 | peer -> me.state = recover; | |
1099 | peer -> me.stos = cur_time; | |
1100 | peer -> partner.state = unknown_state; | |
1101 | peer -> partner.stos = cur_time; | |
1102 | } else { | |
1103 | peer -> me.state = recover; | |
1104 | peer -> me.stos = cur_time; | |
1105 | peer -> partner.state = unknown_state; | |
1106 | peer -> partner.stos = cur_time; | |
1107 | } | |
1108 | ||
e9623235 TL |
1109 | status = enter_failover_peer (peer); |
1110 | if (status != ISC_R_SUCCESS) | |
1111 | parse_warn (cfile, "failover peer %s: %s", | |
1112 | peer -> name, isc_result_totext (status)); | |
20916cae | 1113 | dhcp_failover_state_dereference (&peer, MDL); |
763adef1 TL |
1114 | } |
1115 | ||
a4ba3160 TL |
1116 | void parse_failover_state_declaration (struct parse *cfile, |
1117 | dhcp_failover_state_t *peer) | |
1118 | { | |
1119 | enum dhcp_token token; | |
1120 | const char *val; | |
1121 | char *name; | |
1122 | dhcp_failover_state_t *state; | |
05815916 | 1123 | dhcp_failover_config_t *cp; |
a4ba3160 TL |
1124 | |
1125 | if (!peer) { | |
b3519f23 | 1126 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1127 | if (token != PEER) { |
1128 | parse_warn (cfile, "expecting \"peer\""); | |
1129 | skip_to_semi (cfile); | |
1130 | return; | |
1131 | } | |
1132 | ||
b3519f23 | 1133 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1134 | if (is_identifier (token) || token == STRING) { |
1135 | name = dmalloc (strlen (val) + 1, MDL); | |
1136 | if (!name) | |
1137 | log_fatal ("failover peer name %s: no memory", | |
1138 | name); | |
1139 | strcpy (name, val); | |
1140 | } else { | |
1141 | parse_warn (cfile, "expecting failover peer name."); | |
1142 | skip_to_semi (cfile); | |
1143 | return; | |
1144 | } | |
1145 | ||
1146 | /* See if there's a peer declaration by this name. */ | |
1147 | state = (dhcp_failover_state_t *)0; | |
20916cae | 1148 | find_failover_peer (&state, name, MDL); |
a4ba3160 TL |
1149 | if (!state) { |
1150 | parse_warn (cfile, "unknown failover peer: %s", name); | |
1151 | skip_to_semi (cfile); | |
1152 | return; | |
1153 | } | |
1154 | ||
b3519f23 | 1155 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1156 | if (token != STATE) { |
1157 | parse_warn (cfile, "expecting 'state'"); | |
1158 | if (token != SEMI) | |
1159 | skip_to_semi (cfile); | |
1160 | return; | |
1161 | } | |
20916cae TL |
1162 | } else { |
1163 | state = (dhcp_failover_state_t *)0; | |
1164 | dhcp_failover_state_reference (&state, peer, MDL); | |
1165 | } | |
b3519f23 | 1166 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1167 | if (token != LBRACE) { |
1168 | parse_warn (cfile, "expecting left brace"); | |
1169 | if (token != SEMI) | |
1170 | skip_to_semi (cfile); | |
20916cae | 1171 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
1172 | return; |
1173 | } | |
1174 | do { | |
b3519f23 | 1175 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1176 | switch (token) { |
1177 | case RBRACE: | |
1178 | break; | |
1179 | case MY: | |
05815916 TL |
1180 | cp = &state -> me; |
1181 | do_state: | |
b3519f23 | 1182 | token = next_token (&val, (unsigned *)0, cfile); |
a4ba3160 TL |
1183 | if (token != STATE) { |
1184 | parse_warn (cfile, "expecting 'state'"); | |
20916cae | 1185 | goto bogus; |
a4ba3160 TL |
1186 | } |
1187 | parse_failover_state (cfile, | |
05815916 | 1188 | &cp -> state, &cp -> stos); |
a4ba3160 | 1189 | break; |
05815916 | 1190 | |
a4ba3160 | 1191 | case PARTNER: |
05815916 TL |
1192 | cp = &state -> partner; |
1193 | goto do_state; | |
1194 | ||
d758ad8c TL |
1195 | case MCLT: |
1196 | if (state -> i_am == primary) { | |
1197 | parse_warn (cfile, | |
1198 | "mclt not valid for primary"); | |
1199 | goto bogus; | |
1200 | } | |
1201 | token = next_token (&val, (unsigned *)0, cfile); | |
1202 | if (token != NUMBER) { | |
1203 | parse_warn (cfile, "expecting a number."); | |
1204 | goto bogus; | |
1205 | } | |
1206 | state -> mclt = atoi (val); | |
1207 | parse_semi (cfile); | |
1208 | break; | |
1209 | ||
a4ba3160 TL |
1210 | default: |
1211 | parse_warn (cfile, "expecting state setting."); | |
d758ad8c | 1212 | bogus: |
20916cae TL |
1213 | skip_to_rbrace (cfile, 1); |
1214 | dhcp_failover_state_dereference (&state, MDL); | |
a4ba3160 TL |
1215 | return; |
1216 | } | |
1217 | } while (token != RBRACE); | |
20916cae | 1218 | dhcp_failover_state_dereference (&state, MDL); |
a4ba3160 TL |
1219 | } |
1220 | ||
9e9b2261 | 1221 | void parse_failover_state (cfile, state, stos) |
35454d8a | 1222 | struct parse *cfile; |
9e9b2261 TL |
1223 | enum failover_state *state; |
1224 | TIME *stos; | |
763adef1 TL |
1225 | { |
1226 | enum dhcp_token token; | |
b1b7b521 | 1227 | const char *val; |
9e9b2261 TL |
1228 | enum failover_state state_in; |
1229 | TIME stos_in; | |
763adef1 | 1230 | |
b3519f23 | 1231 | token = next_token (&val, (unsigned *)0, cfile); |
763adef1 | 1232 | switch (token) { |
05815916 TL |
1233 | case UNKNOWN_STATE: |
1234 | state_in = unknown_state; | |
1235 | break; | |
1236 | ||
763adef1 | 1237 | case PARTNER_DOWN: |
9e9b2261 TL |
1238 | state_in = partner_down; |
1239 | break; | |
1240 | ||
763adef1 | 1241 | case NORMAL: |
9e9b2261 TL |
1242 | state_in = normal; |
1243 | break; | |
1244 | ||
763adef1 | 1245 | case COMMUNICATIONS_INTERRUPTED: |
9e9b2261 TL |
1246 | state_in = communications_interrupted; |
1247 | break; | |
1248 | ||
9a092d2e TL |
1249 | case RESOLUTION_INTERRUPTED: |
1250 | state_in = resolution_interrupted; | |
a4ba3160 TL |
1251 | break; |
1252 | ||
05815916 TL |
1253 | case POTENTIAL_CONFLICT: |
1254 | state_in = potential_conflict; | |
1255 | break; | |
1256 | ||
763adef1 | 1257 | case RECOVER: |
9e9b2261 TL |
1258 | state_in = recover; |
1259 | break; | |
a4ba3160 | 1260 | |
3417f5cf TL |
1261 | case RECOVER_WAIT: |
1262 | state_in = recover_wait; | |
1263 | break; | |
1264 | ||
05815916 TL |
1265 | case RECOVER_DONE: |
1266 | state_in = recover_done; | |
1267 | break; | |
1268 | ||
1269 | case SHUTDOWN: | |
1270 | state_in = shut_down; | |
1271 | break; | |
1272 | ||
1273 | case PAUSED: | |
1274 | state_in = paused; | |
1275 | break; | |
1276 | ||
1277 | case STARTUP: | |
1278 | state_in = startup; | |
a4ba3160 | 1279 | break; |
9e9b2261 | 1280 | |
763adef1 | 1281 | default: |
35454d8a | 1282 | parse_warn (cfile, "unknown failover state"); |
9e9b2261 TL |
1283 | skip_to_semi (cfile); |
1284 | return; | |
763adef1 | 1285 | } |
9e9b2261 | 1286 | |
b3519f23 | 1287 | token = next_token (&val, (unsigned *)0, cfile); |
6f8a0361 TL |
1288 | if (token == SEMI) { |
1289 | stos_in = cur_time; | |
1290 | } else { | |
1291 | if (token != AT) { | |
1292 | parse_warn (cfile, "expecting \"at\""); | |
1293 | skip_to_semi (cfile); | |
1294 | return; | |
1295 | } | |
1296 | ||
1297 | stos_in = parse_date (cfile); | |
1298 | if (!stos_in) | |
1299 | return; | |
9e9b2261 TL |
1300 | } |
1301 | ||
6f8a0361 TL |
1302 | /* Now that we've apparently gotten a clean parse, we |
1303 | can trust that this is a state that was fully committed to | |
1304 | disk, so we can install it. */ | |
9e9b2261 TL |
1305 | *stos = stos_in; |
1306 | *state = state_in; | |
763adef1 TL |
1307 | } |
1308 | #endif /* defined (FAILOVER_PROTOCOL) */ | |
1309 | ||
98311e4b DH |
1310 | /* Permit_list_match returns 1 if every element of the permit list in lhs |
1311 | also appears in rhs. Note that this doesn't by itself mean that the | |
1312 | two lists are equal - to check for equality, permit_list_match has to | |
1313 | return 1 with (list1, list2) and with (list2, list1). */ | |
1314 | ||
1315 | int permit_list_match (struct permit *lhs, struct permit *rhs) | |
1316 | { | |
1317 | struct permit *plp, *prp; | |
1318 | int matched; | |
1319 | ||
1320 | if (!lhs) | |
1321 | return 1; | |
1322 | if (!rhs) | |
1323 | return 0; | |
1324 | for (plp = lhs; plp; plp = plp -> next) { | |
1325 | matched = 0; | |
1326 | for (prp = rhs; prp; prp = prp -> next) { | |
1327 | if (prp -> type == plp -> type && | |
1328 | (prp -> type != permit_class || | |
1329 | prp -> class == plp -> class)) { | |
1330 | matched = 1; | |
1331 | break; | |
1332 | } | |
1333 | } | |
1334 | if (!matched) | |
1335 | return 0; | |
1336 | } | |
1337 | return 1; | |
1338 | } | |
1339 | ||
f63b4929 | 1340 | void parse_pool_statement (cfile, group, type) |
35454d8a | 1341 | struct parse *cfile; |
f63b4929 TL |
1342 | struct group *group; |
1343 | int type; | |
1344 | { | |
1345 | enum dhcp_token token; | |
b1b7b521 | 1346 | const char *val; |
f63b4929 | 1347 | int done = 0; |
98311e4b | 1348 | struct pool *pool, **p, *pp; |
f63b4929 TL |
1349 | struct permit *permit; |
1350 | struct permit **permit_head; | |
74f45f96 | 1351 | int declaration = 0; |
e9623235 | 1352 | isc_result_t status; |
98311e4b | 1353 | struct lease *lpchain = (struct lease *)0, *lp; |
f63b4929 | 1354 | |
20916cae TL |
1355 | pool = (struct pool *)0; |
1356 | status = pool_allocate (&pool, MDL); | |
1357 | if (status != ISC_R_SUCCESS) | |
6ceb9118 TL |
1358 | log_fatal ("no memory for pool: %s", |
1359 | isc_result_totext (status)); | |
f63b4929 | 1360 | |
9e9b2261 | 1361 | if (type == SUBNET_DECL) |
20916cae TL |
1362 | shared_network_reference (&pool -> shared_network, |
1363 | group -> subnet -> shared_network, | |
1364 | MDL); | |
75eaa6ff | 1365 | else if (type == SHARED_NET_DECL) |
20916cae TL |
1366 | shared_network_reference (&pool -> shared_network, |
1367 | group -> shared_network, MDL); | |
75eaa6ff EH |
1368 | else { |
1369 | parse_warn(cfile, "Dynamic pools are only valid inside " | |
1370 | "subnet or shared-network statements."); | |
1371 | skip_to_semi(cfile); | |
1372 | return; | |
1373 | } | |
9e9b2261 | 1374 | |
75eaa6ff EH |
1375 | if (pool->shared_network == NULL || |
1376 | !clone_group(&pool->group, pool->shared_network->group, MDL)) | |
1377 | log_fatal("can't clone pool group."); | |
98311e4b | 1378 | |
22009f79 | 1379 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 TL |
1380 | /* Inherit the failover peer from the shared network. */ |
1381 | if (pool -> shared_network -> failover_peer) | |
20916cae TL |
1382 | dhcp_failover_state_reference |
1383 | (&pool -> failover_peer, | |
1384 | pool -> shared_network -> failover_peer, MDL); | |
22009f79 | 1385 | #endif |
9e9b2261 | 1386 | |
20916cae TL |
1387 | if (!parse_lbrace (cfile)) { |
1388 | pool_dereference (&pool, MDL); | |
f63b4929 | 1389 | return; |
20916cae TL |
1390 | } |
1391 | ||
f63b4929 | 1392 | do { |
b3519f23 | 1393 | token = peek_token (&val, (unsigned *)0, cfile); |
e5e41be4 | 1394 | switch (token) { |
8da06bb1 | 1395 | case TOKEN_NO: |
b3519f23 TL |
1396 | next_token (&val, (unsigned *)0, cfile); |
1397 | token = next_token (&val, (unsigned *)0, cfile); | |
9e9b2261 | 1398 | if (token != FAILOVER || |
b3519f23 TL |
1399 | (token = next_token (&val, (unsigned *)0, |
1400 | cfile)) != PEER) { | |
9e9b2261 TL |
1401 | parse_warn (cfile, |
1402 | "expecting \"failover peer\"."); | |
1403 | skip_to_semi (cfile); | |
1404 | continue; | |
1405 | } | |
22009f79 | 1406 | #if defined (FAILOVER_PROTOCOL) |
9e9b2261 | 1407 | if (pool -> failover_peer) |
20916cae TL |
1408 | dhcp_failover_state_dereference |
1409 | (&pool -> failover_peer, MDL); | |
22009f79 | 1410 | #endif |
9e9b2261 TL |
1411 | break; |
1412 | ||
a4ba3160 | 1413 | #if defined (FAILOVER_PROTOCOL) |
e9623235 | 1414 | case FAILOVER: |
b3519f23 TL |
1415 | next_token (&val, (unsigned *)0, cfile); |
1416 | token = next_token (&val, (unsigned *)0, cfile); | |
e9623235 TL |
1417 | if (token != PEER) { |
1418 | parse_warn (cfile, "expecting 'peer'."); | |
1419 | skip_to_semi (cfile); | |
1420 | break; | |
1421 | } | |
b3519f23 | 1422 | token = next_token (&val, (unsigned *)0, cfile); |
e9623235 TL |
1423 | if (token != STRING) { |
1424 | parse_warn (cfile, "expecting string."); | |
1425 | skip_to_semi (cfile); | |
1426 | break; | |
1427 | } | |
1428 | if (pool -> failover_peer) | |
20916cae TL |
1429 | dhcp_failover_state_dereference |
1430 | (&pool -> failover_peer, MDL); | |
e9623235 | 1431 | status = find_failover_peer (&pool -> failover_peer, |
20916cae | 1432 | val, MDL); |
e9623235 TL |
1433 | if (status != ISC_R_SUCCESS) |
1434 | parse_warn (cfile, | |
1435 | "failover peer %s: %s", val, | |
1436 | isc_result_totext (status)); | |
a609e69b TL |
1437 | else |
1438 | pool -> failover_peer -> pool_count++; | |
e9623235 TL |
1439 | parse_semi (cfile); |
1440 | break; | |
a4ba3160 | 1441 | #endif |
e9623235 | 1442 | |
f63b4929 | 1443 | case RANGE: |
b3519f23 | 1444 | next_token (&val, (unsigned *)0, cfile); |
98311e4b DH |
1445 | parse_address_range (cfile, group, type, |
1446 | pool, &lpchain); | |
f63b4929 TL |
1447 | break; |
1448 | case ALLOW: | |
1449 | permit_head = &pool -> permit_list; | |
1450 | get_permit: | |
436f1c8c | 1451 | permit = new_permit (MDL); |
f63b4929 | 1452 | if (!permit) |
8ae2d595 | 1453 | log_fatal ("no memory for permit"); |
b3519f23 TL |
1454 | next_token (&val, (unsigned *)0, cfile); |
1455 | token = next_token (&val, (unsigned *)0, cfile); | |
f63b4929 TL |
1456 | switch (token) { |
1457 | case UNKNOWN: | |
1458 | permit -> type = permit_unknown_clients; | |
1459 | get_clients: | |
b3519f23 TL |
1460 | if (next_token (&val, (unsigned *)0, |
1461 | cfile) != CLIENTS) { | |
35454d8a TL |
1462 | parse_warn (cfile, |
1463 | "expecting \"clients\""); | |
f63b4929 | 1464 | skip_to_semi (cfile); |
436f1c8c | 1465 | free_permit (permit, MDL); |
f63b4929 TL |
1466 | continue; |
1467 | } | |
1468 | break; | |
1469 | ||
98311e4b DH |
1470 | case KNOWN_CLIENTS: |
1471 | permit -> type = permit_known_clients; | |
1472 | break; | |
1473 | ||
ad1a6484 TL |
1474 | case UNKNOWN_CLIENTS: |
1475 | permit -> type = permit_unknown_clients; | |
1476 | break; | |
1477 | ||
f63b4929 TL |
1478 | case KNOWN: |
1479 | permit -> type = permit_known_clients; | |
1480 | goto get_clients; | |
1481 | ||
1482 | case AUTHENTICATED: | |
1483 | permit -> type = permit_authenticated_clients; | |
1484 | goto get_clients; | |
1485 | ||
1486 | case UNAUTHENTICATED: | |
1487 | permit -> type = | |
1488 | permit_unauthenticated_clients; | |
1489 | goto get_clients; | |
1490 | ||
1491 | case ALL: | |
1492 | permit -> type = permit_all_clients; | |
1493 | goto get_clients; | |
1494 | break; | |
1495 | ||
1496 | case DYNAMIC: | |
1497 | permit -> type = permit_dynamic_bootp_clients; | |
b3519f23 TL |
1498 | if (next_token (&val, (unsigned *)0, |
1499 | cfile) != TOKEN_BOOTP) { | |
35454d8a TL |
1500 | parse_warn (cfile, |
1501 | "expecting \"bootp\""); | |
f63b4929 | 1502 | skip_to_semi (cfile); |
436f1c8c | 1503 | free_permit (permit, MDL); |
f63b4929 TL |
1504 | continue; |
1505 | } | |
1506 | goto get_clients; | |
1507 | ||
1508 | case MEMBERS: | |
b3519f23 TL |
1509 | if (next_token (&val, (unsigned *)0, |
1510 | cfile) != OF) { | |
35454d8a | 1511 | parse_warn (cfile, "expecting \"of\""); |
f63b4929 | 1512 | skip_to_semi (cfile); |
436f1c8c | 1513 | free_permit (permit, MDL); |
f63b4929 TL |
1514 | continue; |
1515 | } | |
b3519f23 TL |
1516 | if (next_token (&val, (unsigned *)0, |
1517 | cfile) != STRING) { | |
35454d8a TL |
1518 | parse_warn (cfile, |
1519 | "expecting class name."); | |
f63b4929 | 1520 | skip_to_semi (cfile); |
436f1c8c | 1521 | free_permit (permit, MDL); |
f63b4929 TL |
1522 | continue; |
1523 | } | |
1524 | permit -> type = permit_class; | |
20916cae TL |
1525 | permit -> class = (struct class *)0; |
1526 | find_class (&permit -> class, val, MDL); | |
f63b4929 | 1527 | if (!permit -> class) |
35454d8a TL |
1528 | parse_warn (cfile, |
1529 | "no such class: %s", val); | |
e5e41be4 TL |
1530 | break; |
1531 | ||
f63b4929 | 1532 | default: |
35454d8a | 1533 | parse_warn (cfile, "expecting permit type."); |
f63b4929 TL |
1534 | skip_to_semi (cfile); |
1535 | break; | |
1536 | } | |
1537 | while (*permit_head) | |
1538 | permit_head = &((*permit_head) -> next); | |
1539 | *permit_head = permit; | |
74f45f96 | 1540 | parse_semi (cfile); |
f63b4929 TL |
1541 | break; |
1542 | ||
1543 | case DENY: | |
1544 | permit_head = &pool -> prohibit_list; | |
1545 | goto get_permit; | |
1546 | ||
1547 | case RBRACE: | |
b3519f23 | 1548 | next_token (&val, (unsigned *)0, cfile); |
f63b4929 TL |
1549 | done = 1; |
1550 | break; | |
1551 | ||
1552 | default: | |
74f45f96 TL |
1553 | declaration = parse_statement (cfile, pool -> group, |
1554 | POOL_DECL, | |
1555 | (struct host_decl *)0, | |
1556 | declaration); | |
f63b4929 TL |
1557 | break; |
1558 | } | |
1559 | } while (!done); | |
1560 | ||
9e9b2261 TL |
1561 | #if defined (FAILOVER_PROTOCOL) |
1562 | /* We can't do failover on a pool that supports dynamic bootp, | |
1563 | because BOOTP doesn't support leases, and failover absolutely | |
1564 | depends on lease timing. */ | |
1565 | if (pool -> failover_peer) { | |
98311e4b DH |
1566 | /* This search order matches the search orders later in |
1567 | * execution - deny first, if not denied, check permit | |
1568 | * list. A dynamic bootp client may be known or unknown, | |
1569 | * it may belong to a member of a class, but it definitely | |
1570 | * will not be authenticated since that requires DHCP | |
1571 | * to work. So a dynamic bootp client is definitely not | |
1572 | * an authenticated client, and we can't say for sure about | |
1573 | * anything else. | |
1574 | * | |
1575 | * So we nag the user. | |
1576 | */ | |
1577 | for (permit = pool -> prohibit_list; permit; | |
1578 | permit = permit -> next) { | |
9e9b2261 | 1579 | if (permit -> type == permit_dynamic_bootp_clients || |
98311e4b DH |
1580 | permit -> type == permit_unauthenticated_clients || |
1581 | permit -> type == permit_all_clients) | |
1582 | break; | |
9e9b2261 | 1583 | } |
98311e4b DH |
1584 | if (!permit) { |
1585 | permit = pool -> permit_list; | |
1586 | do { | |
1587 | if (!permit || | |
1588 | permit -> type != | |
1589 | permit_authenticated_clients) { | |
1590 | parse_warn (cfile, | |
1591 | "pools with failover peers %s", | |
1592 | "may not permit dynamic bootp."); | |
1593 | log_error ("Either write a \"%s\" %s", | |
1594 | "no failover", | |
1595 | "statement and use disjoint"); | |
1596 | log_error ("pools, or%s (%s) %s", | |
1597 | " don't permit dynamic bootp", | |
1598 | "\"deny dynamic bootp clients;\"", | |
1599 | "in this pool."); | |
1600 | log_error ("This is a protocol,%s %s", | |
1601 | " limitation, not an ISC DHCP", | |
1602 | "limitation, so"); | |
1603 | log_error ("please don't request an %s", | |
1604 | "enhancement or ask why this is."); | |
9e9b2261 | 1605 | |
98311e4b DH |
1606 | break; |
1607 | } | |
1608 | ||
1609 | permit = permit -> next; | |
1610 | } while (permit); | |
9e9b2261 TL |
1611 | } |
1612 | } | |
9e9b2261 TL |
1613 | #endif /* FAILOVER_PROTOCOL */ |
1614 | ||
98311e4b DH |
1615 | /* See if there's already a pool into which we can merge this one. */ |
1616 | for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) { | |
1617 | struct lease *l; | |
1618 | ||
1619 | if (pp -> group -> statements != pool -> group -> statements) | |
1620 | continue; | |
1621 | #if defined (FAILOVER_PROTOCOL) | |
1622 | if (pool -> failover_peer != pp -> failover_peer) | |
1623 | continue; | |
1624 | #endif | |
1625 | if (!permit_list_match (pp -> permit_list, | |
1626 | pool -> permit_list) || | |
1627 | !permit_list_match (pool -> permit_list, | |
1628 | pp -> permit_list) || | |
1629 | !permit_list_match (pp -> prohibit_list, | |
1630 | pool -> prohibit_list) || | |
1631 | !permit_list_match (pool -> prohibit_list, | |
1632 | pp -> prohibit_list)) | |
1633 | continue; | |
1634 | ||
1635 | /* Okay, we can merge these two pools. All we have to | |
1636 | do is fix up the leases, which all point to their pool. */ | |
1637 | for (lp = lpchain; lp; lp = lp -> next) { | |
1638 | pool_dereference (&lp -> pool, MDL); | |
1639 | pool_reference (&lp -> pool, pp, MDL); | |
1640 | } | |
1641 | break; | |
1642 | } | |
1643 | ||
1644 | /* If we didn't succeed in merging this pool into another, put | |
1645 | it on the list. */ | |
1646 | if (!pp) { | |
1647 | p = &pool -> shared_network -> pools; | |
1648 | for (; *p; p = &((*p) -> next)) | |
1649 | ; | |
1650 | pool_reference (p, pool, MDL); | |
1651 | } | |
1652 | ||
1653 | /* Don't allow a pool declaration with no addresses, since it is | |
1654 | probably a configuration error. */ | |
1655 | if (!lpchain) { | |
1656 | parse_warn (cfile, "Pool declaration with no address range."); | |
1657 | log_error ("Pool declarations must always contain at least"); | |
1658 | log_error ("one range statement."); | |
1659 | } | |
1660 | ||
1661 | /* Dereference the lease chain. */ | |
1662 | lp = (struct lease *)0; | |
1663 | while (lpchain) { | |
1664 | lease_reference (&lp, lpchain, MDL); | |
1665 | lease_dereference (&lpchain, MDL); | |
1666 | if (lp -> next) { | |
1667 | lease_reference (&lpchain, lp -> next, MDL); | |
1668 | lease_dereference (&lp -> next, MDL); | |
1669 | lease_dereference (&lp, MDL); | |
1670 | } | |
1671 | } | |
20916cae | 1672 | pool_dereference (&pool, MDL); |
f63b4929 TL |
1673 | } |
1674 | ||
5376e3e9 TL |
1675 | /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ |
1676 | ||
1677 | int parse_boolean (cfile) | |
35454d8a | 1678 | struct parse *cfile; |
5376e3e9 | 1679 | { |
6f8fb41f | 1680 | enum dhcp_token token; |
b1b7b521 | 1681 | const char *val; |
5376e3e9 TL |
1682 | int rv; |
1683 | ||
b3519f23 | 1684 | token = next_token (&val, (unsigned *)0, cfile); |
5376e3e9 TL |
1685 | if (!strcasecmp (val, "true") |
1686 | || !strcasecmp (val, "on")) | |
b179c997 | 1687 | rv = 1; |
5376e3e9 TL |
1688 | else if (!strcasecmp (val, "false") |
1689 | || !strcasecmp (val, "off")) | |
1690 | rv = 0; | |
1691 | else { | |
35454d8a TL |
1692 | parse_warn (cfile, |
1693 | "boolean value (true/false/on/off) expected"); | |
5376e3e9 TL |
1694 | skip_to_semi (cfile); |
1695 | return 0; | |
1696 | } | |
1697 | parse_semi (cfile); | |
1698 | return rv; | |
1699 | } | |
1700 | ||
7dfc8ac2 TL |
1701 | /* Expect a left brace; if there isn't one, skip over the rest of the |
1702 | statement and return zero; otherwise, return 1. */ | |
1703 | ||
1704 | int parse_lbrace (cfile) | |
35454d8a | 1705 | struct parse *cfile; |
7dfc8ac2 | 1706 | { |
6f8fb41f | 1707 | enum dhcp_token token; |
b1b7b521 | 1708 | const char *val; |
7dfc8ac2 | 1709 | |
b3519f23 | 1710 | token = next_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 1711 | if (token != LBRACE) { |
35454d8a | 1712 | parse_warn (cfile, "expecting left brace."); |
7dfc8ac2 TL |
1713 | skip_to_semi (cfile); |
1714 | return 0; | |
1715 | } | |
1716 | return 1; | |
d7837182 TL |
1717 | } |
1718 | ||
7dfc8ac2 | 1719 | |
2d59f590 | 1720 | /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ |
d7837182 | 1721 | |
2d59f590 | 1722 | void parse_host_declaration (cfile, group) |
35454d8a | 1723 | struct parse *cfile; |
7dfc8ac2 | 1724 | struct group *group; |
d7837182 | 1725 | { |
b1b7b521 | 1726 | const char *val; |
6f8fb41f | 1727 | enum dhcp_token token; |
7dfc8ac2 | 1728 | struct host_decl *host; |
f3c3d674 | 1729 | char *name; |
2d59f590 | 1730 | int declaration = 0; |
612fded7 | 1731 | int dynamicp = 0; |
ff129930 | 1732 | int deleted = 0; |
92ce3f81 | 1733 | isc_result_t status; |
98bd7ca0 DH |
1734 | int known; |
1735 | struct option *option; | |
1736 | struct expression *expr; | |
dfe63f1b | 1737 | const char *tmp_format; |
7dfc8ac2 | 1738 | |
20916cae | 1739 | name = parse_host_name (cfile); |
6c5223f5 TL |
1740 | if (!name) { |
1741 | parse_warn (cfile, "expecting a name for host declaration."); | |
1742 | skip_to_semi (cfile); | |
20916cae | 1743 | return; |
6c5223f5 | 1744 | } |
7dfc8ac2 | 1745 | |
20916cae TL |
1746 | host = (struct host_decl *)0; |
1747 | status = host_allocate (&host, MDL); | |
1748 | if (status != ISC_R_SUCCESS) | |
1749 | log_fatal ("can't allocate host decl struct %s: %s", | |
1750 | name, isc_result_totext (status)); | |
7dfc8ac2 | 1751 | host -> name = name; |
f84d544b TL |
1752 | if (!clone_group (&host -> group, group, MDL)) { |
1753 | log_fatal ("can't clone group for host %s", name); | |
20916cae TL |
1754 | boom: |
1755 | host_dereference (&host, MDL); | |
1756 | return; | |
1757 | } | |
7dfc8ac2 TL |
1758 | |
1759 | if (!parse_lbrace (cfile)) | |
20916cae | 1760 | goto boom; |
d7837182 | 1761 | |
d7837182 | 1762 | do { |
b3519f23 | 1763 | token = peek_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 1764 | if (token == RBRACE) { |
b3519f23 | 1765 | token = next_token (&val, (unsigned *)0, cfile); |
d7837182 TL |
1766 | break; |
1767 | } | |
0b69dcc8 | 1768 | if (token == END_OF_FILE) { |
b3519f23 | 1769 | token = next_token (&val, (unsigned *)0, cfile); |
35454d8a | 1770 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
1771 | break; |
1772 | } | |
612fded7 TL |
1773 | /* If the host declaration was created by the server, |
1774 | remember to save it. */ | |
1775 | if (token == DYNAMIC) { | |
1776 | dynamicp = 1; | |
b3519f23 | 1777 | token = next_token (&val, (unsigned *)0, cfile); |
612fded7 TL |
1778 | if (!parse_semi (cfile)) |
1779 | break; | |
1780 | continue; | |
1781 | } | |
ff129930 TL |
1782 | /* If the host declaration was created by the server, |
1783 | remember to save it. */ | |
007e3ee4 | 1784 | if (token == TOKEN_DELETED) { |
ff129930 | 1785 | deleted = 1; |
b3519f23 | 1786 | token = next_token (&val, (unsigned *)0, cfile); |
ff129930 TL |
1787 | if (!parse_semi (cfile)) |
1788 | break; | |
1789 | continue; | |
1790 | } | |
29c35bed TL |
1791 | |
1792 | if (token == GROUP) { | |
1793 | struct group_object *go; | |
b3519f23 TL |
1794 | token = next_token (&val, (unsigned *)0, cfile); |
1795 | token = next_token (&val, (unsigned *)0, cfile); | |
29c35bed | 1796 | if (token != STRING && !is_identifier (token)) { |
35454d8a TL |
1797 | parse_warn (cfile, |
1798 | "expecting string or identifier."); | |
29c35bed TL |
1799 | skip_to_rbrace (cfile, 1); |
1800 | break; | |
1801 | } | |
20916cae TL |
1802 | go = (struct group_object *)0; |
1803 | if (!group_hash_lookup (&go, group_name_hash, | |
1804 | val, strlen (val), MDL)) { | |
35454d8a TL |
1805 | parse_warn (cfile, "unknown group %s in host %s", |
1806 | val, host -> name); | |
29c35bed TL |
1807 | } else { |
1808 | if (host -> named_group) | |
20916cae TL |
1809 | group_object_dereference |
1810 | (&host -> named_group, MDL); | |
1811 | group_object_reference (&host -> named_group, | |
1812 | go, MDL); | |
1813 | group_object_dereference (&go, MDL); | |
29c35bed TL |
1814 | } |
1815 | if (!parse_semi (cfile)) | |
1816 | break; | |
1817 | continue; | |
1818 | } | |
1819 | ||
1820 | if (token == UID) { | |
b1b7b521 | 1821 | const char *s; |
29c35bed | 1822 | unsigned char *t = 0; |
b1b7b521 | 1823 | unsigned len; |
29c35bed | 1824 | |
b3519f23 | 1825 | token = next_token (&val, (unsigned *)0, cfile); |
436f1c8c | 1826 | data_string_forget (&host -> client_identifier, MDL); |
29c35bed | 1827 | |
2178df03 DH |
1828 | if (host->client_identifier.len != 0) { |
1829 | parse_warn(cfile, "Host %s already has a " | |
1830 | "client identifier.", | |
1831 | host->name); | |
1832 | break; | |
1833 | } | |
1834 | ||
29c35bed | 1835 | /* See if it's a string or a cshl. */ |
b3519f23 | 1836 | token = peek_token (&val, (unsigned *)0, cfile); |
29c35bed | 1837 | if (token == STRING) { |
b3519f23 | 1838 | token = next_token (&val, &len, cfile); |
29c35bed | 1839 | s = val; |
29c35bed TL |
1840 | host -> client_identifier.terminated = 1; |
1841 | } else { | |
1842 | len = 0; | |
1843 | t = parse_numeric_aggregate | |
1844 | (cfile, | |
1845 | (unsigned char *)0, &len, ':', 16, 8); | |
1846 | if (!t) { | |
35454d8a TL |
1847 | parse_warn (cfile, |
1848 | "expecting hex list."); | |
29c35bed TL |
1849 | skip_to_semi (cfile); |
1850 | } | |
b1b7b521 | 1851 | s = (const char *)t; |
29c35bed TL |
1852 | } |
1853 | if (!buffer_allocate | |
1854 | (&host -> client_identifier.buffer, | |
436f1c8c | 1855 | len + host -> client_identifier.terminated, MDL)) |
29c35bed TL |
1856 | log_fatal ("no memory for uid for host %s.", |
1857 | host -> name); | |
1858 | host -> client_identifier.data = | |
1859 | host -> client_identifier.buffer -> data; | |
1860 | host -> client_identifier.len = len; | |
b1b7b521 | 1861 | memcpy (host -> client_identifier.buffer -> data, s, |
29c35bed TL |
1862 | len + host -> client_identifier.terminated); |
1863 | if (t) | |
436f1c8c | 1864 | dfree (t, MDL); |
29c35bed TL |
1865 | |
1866 | if (!parse_semi (cfile)) | |
1867 | break; | |
1868 | continue; | |
1869 | } | |
98bd7ca0 DH |
1870 | if (token == HOST_IDENTIFIER) { |
1871 | if (host->host_id_option != NULL) { | |
1872 | parse_warn(cfile, | |
1873 | "only one host-identifier allowed " | |
1874 | "per host"); | |
1875 | skip_to_rbrace(cfile, 1); | |
1876 | break; | |
1877 | } | |
1878 | next_token(&val, NULL, cfile); | |
1879 | token = next_token(&val, NULL, cfile); | |
1880 | if (token != OPTION) { | |
1881 | parse_warn(cfile, | |
1882 | "host-identifer must be an option"); | |
1883 | skip_to_rbrace(cfile, 1); | |
1884 | break; | |
1885 | } | |
1886 | known = 0; | |
1887 | option = NULL; | |
1888 | status = parse_option_name(cfile, 1, &known, &option); | |
1889 | if ((status != ISC_R_SUCCESS) || (option == NULL)) { | |
1890 | break; | |
1891 | } | |
1892 | if (!known) { | |
1893 | parse_warn(cfile, "unknown option %s.%s", | |
1894 | option->universe->name, | |
1895 | option->name); | |
1896 | skip_to_rbrace(cfile, 1); | |
1897 | break; | |
1898 | } | |
1899 | ||
1900 | /* XXX: we're always using "lookups" */ | |
1901 | expr = NULL; | |
1902 | tmp_format = option->format; | |
1903 | /* | |
1904 | * XXX: using parse_option_token() is not ideal here, | |
1905 | * as it does not handle things like arrays and | |
1906 | * such. | |
1907 | */ | |
dfe63f1b SK |
1908 | if (!parse_option_token(&expr, cfile, &tmp_format, |
1909 | NULL, 1, 1)) { | |
98bd7ca0 DH |
1910 | skip_to_rbrace(cfile, 1); |
1911 | option_dereference(&option, MDL); | |
1912 | break; | |
1913 | } | |
1914 | ||
1915 | /* I think this is guaranteed, but a check | |
1916 | won't hurt. -Shane */ | |
1917 | if (expr->op != expr_const_data) { | |
1918 | parse_warn(cfile, | |
1919 | "options for host-identifier " | |
1920 | "must have a constant value"); | |
1921 | skip_to_rbrace(cfile, 1); | |
1922 | expression_dereference(&expr, MDL); | |
1923 | option_dereference(&option, MDL); | |
1924 | break; | |
1925 | } | |
1926 | ||
1927 | if (!parse_semi(cfile)) { | |
1928 | skip_to_rbrace(cfile, 1); | |
1929 | expression_dereference(&expr, MDL); | |
1930 | option_dereference(&option, MDL); | |
1931 | break; | |
1932 | } | |
1933 | ||
1934 | option_reference(&host->host_id_option, option, MDL); | |
1935 | option_dereference(&option, MDL); | |
1936 | data_string_copy(&host->host_id, | |
1937 | &expr->data.const_data, MDL); | |
1938 | expression_dereference(&expr, MDL); | |
1939 | continue; | |
1940 | } | |
1941 | ||
2d59f590 TL |
1942 | declaration = parse_statement (cfile, host -> group, |
1943 | HOST_DECL, host, | |
1944 | declaration); | |
d7837182 | 1945 | } while (1); |
7dfc8ac2 | 1946 | |
ff129930 | 1947 | if (deleted) { |
20916cae TL |
1948 | struct host_decl *hp = (struct host_decl *)0; |
1949 | if (host_hash_lookup (&hp, host_name_hash, | |
1950 | (unsigned char *)host -> name, | |
1951 | strlen (host -> name), MDL)) { | |
ff129930 | 1952 | delete_host (hp, 0); |
20916cae | 1953 | host_dereference (&hp, MDL); |
ff129930 | 1954 | } |
ff129930 | 1955 | } else { |
29c35bed TL |
1956 | if (host -> named_group && host -> named_group -> group) { |
1957 | if (host -> group -> statements || | |
1958 | (host -> group -> authoritative != | |
b83bf1d1 TL |
1959 | host -> named_group -> group -> authoritative)) { |
1960 | if (host -> group -> next) | |
1961 | group_dereference (&host -> group -> next, | |
1962 | MDL); | |
20916cae TL |
1963 | group_reference (&host -> group -> next, |
1964 | host -> named_group -> group, | |
1965 | MDL); | |
b83bf1d1 | 1966 | } else { |
20916cae TL |
1967 | group_dereference (&host -> group, MDL); |
1968 | group_reference (&host -> group, | |
1969 | host -> named_group -> group, | |
1970 | MDL); | |
29c35bed TL |
1971 | } |
1972 | } | |
1973 | ||
b86799bf TL |
1974 | if (dynamicp) |
1975 | host -> flags |= HOST_DECL_DYNAMIC; | |
1976 | else | |
1977 | host -> flags |= HOST_DECL_STATIC; | |
1978 | ||
92ce3f81 TL |
1979 | status = enter_host (host, dynamicp, 0); |
1980 | if (status != ISC_R_SUCCESS) | |
ab58ff49 TL |
1981 | parse_warn (cfile, "host %s: %s", host -> name, |
1982 | isc_result_totext (status)); | |
ff129930 | 1983 | } |
20916cae | 1984 | host_dereference (&host, MDL); |
d7837182 TL |
1985 | } |
1986 | ||
2d59f590 | 1987 | /* class-declaration :== STRING LBRACE parameters declarations RBRACE |
24a75c03 TL |
1988 | */ |
1989 | ||
20916cae TL |
1990 | int parse_class_declaration (cp, cfile, group, type) |
1991 | struct class **cp; | |
35454d8a | 1992 | struct parse *cfile; |
7dfc8ac2 | 1993 | struct group *group; |
24a75c03 TL |
1994 | int type; |
1995 | { | |
b1b7b521 | 1996 | const char *val; |
6f8fb41f | 1997 | enum dhcp_token token; |
20916cae | 1998 | struct class *class = (struct class *)0, *pc = (struct class *)0; |
f4d0f440 | 1999 | int declaration = 0; |
e5e41be4 | 2000 | int lose = 0; |
ece6ea33 | 2001 | struct data_string data; |
d758ad8c TL |
2002 | char *name; |
2003 | const char *tname; | |
ece6ea33 TL |
2004 | struct executable_statement *stmt = (struct executable_statement *)0; |
2005 | struct expression *expr; | |
de94ca72 | 2006 | int new = 1; |
98311e4b | 2007 | isc_result_t status = ISC_R_FAILURE; |
06e77c34 DH |
2008 | int matchedonce = 0; |
2009 | int submatchedonce = 0; | |
f7fdb216 | 2010 | unsigned code; |
24a75c03 | 2011 | |
b3519f23 | 2012 | token = next_token (&val, (unsigned *)0, cfile); |
24a75c03 | 2013 | if (token != STRING) { |
35454d8a | 2014 | parse_warn (cfile, "Expecting class name"); |
24a75c03 | 2015 | skip_to_semi (cfile); |
20916cae | 2016 | return 0; |
24a75c03 TL |
2017 | } |
2018 | ||
ece6ea33 | 2019 | /* See if there's already a class with the specified name. */ |
20916cae | 2020 | find_class (&pc, val, MDL); |
ece6ea33 | 2021 | |
06e77c34 DH |
2022 | /* If it is a class, we're updating it. If it's any of the other |
2023 | * types (subclass, vendor or user class), the named class is a | |
2024 | * reference to the parent class so its mandatory. | |
2025 | */ | |
2026 | if (pc && (type == CLASS_TYPE_CLASS)) { | |
2027 | class_reference(&class, pc, MDL); | |
de94ca72 | 2028 | new = 0; |
06e77c34 DH |
2029 | class_dereference(&pc, MDL); |
2030 | } else if (!pc && (type != CLASS_TYPE_CLASS)) { | |
2031 | parse_warn(cfile, "no class named %s", val); | |
2032 | skip_to_semi(cfile); | |
20916cae | 2033 | return 0; |
ece6ea33 TL |
2034 | } |
2035 | ||
2036 | /* The old vendor-class and user-class declarations had an implicit | |
2037 | match. We don't do the implicit match anymore. Instead, for | |
2038 | backward compatibility, we have an implicit-vendor-class and an | |
2039 | implicit-user-class. vendor-class and user-class declarations | |
2040 | are turned into subclasses of the implicit classes, and the | |
8b500185 | 2041 | submatch expression of the implicit classes extracts the contents of |
ece6ea33 | 2042 | the vendor class or user class. */ |
06e77c34 | 2043 | if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) { |
ece6ea33 | 2044 | data.len = strlen (val); |
6f8fb41f | 2045 | data.buffer = (struct buffer *)0; |
436f1c8c | 2046 | if (!buffer_allocate (&data.buffer, data.len + 1, MDL)) |
20916cae | 2047 | log_fatal ("no memory for class name."); |
6f8fb41f | 2048 | data.data = &data.buffer -> data [0]; |
ece6ea33 TL |
2049 | data.terminated = 1; |
2050 | ||
d758ad8c | 2051 | tname = type ? "implicit-vendor-class" : "implicit-user-class"; |
06e77c34 | 2052 | } else if (type == CLASS_TYPE_CLASS) { |
d758ad8c | 2053 | tname = val; |
20916cae | 2054 | } else { |
d758ad8c | 2055 | tname = (const char *)0; |
20916cae TL |
2056 | } |
2057 | ||
d758ad8c TL |
2058 | if (tname) { |
2059 | name = dmalloc (strlen (tname) + 1, MDL); | |
2060 | if (!name) | |
2061 | log_fatal ("No memory for class name %s.", tname); | |
2062 | strcpy (name, val); | |
2063 | } else | |
2064 | name = (char *)0; | |
ece6ea33 TL |
2065 | |
2066 | /* If this is a straight subclass, parse the hash string. */ | |
06e77c34 | 2067 | if (type == CLASS_TYPE_SUBCLASS) { |
b3519f23 | 2068 | token = peek_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 2069 | if (token == STRING) { |
b3519f23 | 2070 | token = next_token (&val, &data.len, cfile); |
6f8fb41f | 2071 | data.buffer = (struct buffer *)0; |
20916cae TL |
2072 | if (!buffer_allocate (&data.buffer, |
2073 | data.len + 1, MDL)) { | |
2074 | if (pc) | |
2075 | class_dereference (&pc, MDL); | |
2076 | ||
2077 | return 0; | |
2078 | } | |
ece6ea33 | 2079 | data.terminated = 1; |
6f8fb41f | 2080 | data.data = &data.buffer -> data [0]; |
b3519f23 TL |
2081 | memcpy ((char *)data.buffer -> data, val, |
2082 | data.len + 1); | |
ece6ea33 | 2083 | } else if (token == NUMBER_OR_NAME || token == NUMBER) { |
6f8fb41f | 2084 | memset (&data, 0, sizeof data); |
20916cae | 2085 | if (!parse_cshl (&data, cfile)) { |
06e77c34 DH |
2086 | if (pc) |
2087 | class_dereference (&pc, MDL); | |
20916cae | 2088 | return 0; |
b19f2e1c | 2089 | } |
e68de775 | 2090 | } else { |
35454d8a | 2091 | parse_warn (cfile, "Expecting string or hex list."); |
d758ad8c TL |
2092 | if (pc) |
2093 | class_dereference (&pc, MDL); | |
20916cae | 2094 | return 0; |
ece6ea33 TL |
2095 | } |
2096 | } | |
2097 | ||
2098 | /* See if there's already a class in the hash table matching the | |
2099 | hash data. */ | |
06e77c34 | 2100 | if (type != CLASS_TYPE_CLASS) |
20916cae TL |
2101 | class_hash_lookup (&class, pc -> hash, |
2102 | (const char *)data.data, data.len, MDL); | |
ece6ea33 TL |
2103 | |
2104 | /* If we didn't find an existing class, allocate a new one. */ | |
2105 | if (!class) { | |
2106 | /* Allocate the class structure... */ | |
20916cae | 2107 | status = class_allocate (&class, MDL); |
ece6ea33 | 2108 | if (pc) { |
20916cae TL |
2109 | group_reference (&class -> group, pc -> group, MDL); |
2110 | class_reference (&class -> superclass, pc, MDL); | |
88dcab62 TL |
2111 | class -> lease_limit = pc -> lease_limit; |
2112 | if (class -> lease_limit) { | |
2113 | class -> billed_leases = | |
2114 | dmalloc (class -> lease_limit * | |
436f1c8c | 2115 | sizeof (struct lease *), MDL); |
88dcab62 | 2116 | if (!class -> billed_leases) |
e68de775 | 2117 | log_fatal ("no memory for billing"); |
88dcab62 TL |
2118 | memset (class -> billed_leases, 0, |
2119 | (class -> lease_limit * | |
2120 | sizeof class -> billed_leases)); | |
2121 | } | |
436f1c8c | 2122 | data_string_copy (&class -> hash_string, &data, MDL); |
98311e4b | 2123 | if (!pc -> hash && |
f7fdb216 | 2124 | !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL)) |
98311e4b DH |
2125 | log_fatal ("No memory for subclass hash."); |
2126 | class_hash_add (pc -> hash, | |
2127 | (const char *)class -> hash_string.data, | |
2128 | class -> hash_string.len, | |
2129 | (void *)class, MDL); | |
ece6ea33 | 2130 | } else { |
06e77c34 DH |
2131 | if (class->group) |
2132 | group_dereference(&class->group, MDL); | |
20916cae TL |
2133 | if (!clone_group (&class -> group, group, MDL)) |
2134 | log_fatal ("no memory to clone class group."); | |
ece6ea33 TL |
2135 | } |
2136 | ||
2137 | /* If this is an implicit vendor or user class, add a | |
2138 | statement that causes the vendor or user class ID to | |
2139 | be sent back in the reply. */ | |
06e77c34 | 2140 | if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) { |
20916cae TL |
2141 | stmt = (struct executable_statement *)0; |
2142 | if (!executable_statement_allocate (&stmt, MDL)) | |
8ae2d595 | 2143 | log_fatal ("no memory for class statement."); |
ece6ea33 | 2144 | stmt -> op = supersede_option_statement; |
6f8fb41f | 2145 | if (option_cache_allocate (&stmt -> data.option, |
436f1c8c | 2146 | MDL)) { |
6f8fb41f | 2147 | stmt -> data.option -> data = data; |
f7fdb216 | 2148 | code = (type == CLASS_TYPE_VENDOR) |
ca3a51a5 | 2149 | ? DHO_VENDOR_CLASS_IDENTIFIER |
f7fdb216 DH |
2150 | : DHO_USER_CLASS; |
2151 | option_code_hash_lookup( | |
2152 | &stmt->data.option->option, | |
2153 | dhcp_universe.code_hash, | |
2154 | &code, 0, MDL); | |
6f8fb41f | 2155 | } |
ece6ea33 TL |
2156 | class -> statements = stmt; |
2157 | } | |
de94ca72 TL |
2158 | |
2159 | /* Save the name, if there is one. */ | |
06e77c34 DH |
2160 | if (class->name != NULL) |
2161 | dfree(class->name, MDL); | |
2162 | class->name = name; | |
ece6ea33 | 2163 | } |
7dfc8ac2 | 2164 | |
06e77c34 DH |
2165 | if (type != CLASS_TYPE_CLASS) |
2166 | data_string_forget(&data, MDL); | |
88dcab62 | 2167 | |
20916cae | 2168 | /* Spawned classes don't have to have their own settings. */ |
88dcab62 | 2169 | if (class -> superclass) { |
b3519f23 | 2170 | token = peek_token (&val, (unsigned *)0, cfile); |
e68de775 | 2171 | if (token == SEMI) { |
b3519f23 | 2172 | next_token (&val, (unsigned *)0, cfile); |
20916cae TL |
2173 | if (cp) |
2174 | status = class_reference (cp, class, MDL); | |
2175 | class_dereference (&class, MDL); | |
d758ad8c TL |
2176 | if (pc) |
2177 | class_dereference (&pc, MDL); | |
20916cae | 2178 | return cp ? (status == ISC_R_SUCCESS) : 1; |
e68de775 TL |
2179 | } |
2180 | /* Give the subclass its own group. */ | |
f84d544b TL |
2181 | if (!clone_group (&class -> group, class -> group, MDL)) |
2182 | log_fatal ("can't clone class group."); | |
2183 | ||
88dcab62 TL |
2184 | } |
2185 | ||
20916cae TL |
2186 | if (!parse_lbrace (cfile)) { |
2187 | class_dereference (&class, MDL); | |
2188 | if (pc) | |
2189 | class_dereference (&pc, MDL); | |
2190 | return 0; | |
2191 | } | |
24a75c03 TL |
2192 | |
2193 | do { | |
b3519f23 | 2194 | token = peek_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 2195 | if (token == RBRACE) { |
b3519f23 | 2196 | token = next_token (&val, (unsigned *)0, cfile); |
24a75c03 | 2197 | break; |
0b69dcc8 | 2198 | } else if (token == END_OF_FILE) { |
b3519f23 | 2199 | token = next_token (&val, (unsigned *)0, cfile); |
35454d8a | 2200 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 2201 | break; |
899d754f | 2202 | } else if (token == DYNAMIC) { |
06e77c34 | 2203 | class->flags |= CLASS_DECL_DYNAMIC; |
899d754f JB |
2204 | token = next_token (&val, (unsigned *)0, cfile); |
2205 | if (!parse_semi (cfile)) | |
2206 | break; | |
2207 | continue; | |
2208 | } else if (token == TOKEN_DELETED) { | |
06e77c34 | 2209 | class->flags |= CLASS_DECL_DELETED; |
899d754f JB |
2210 | token = next_token (&val, (unsigned *)0, cfile); |
2211 | if (!parse_semi (cfile)) | |
2212 | break; | |
2213 | continue; | |
ece6ea33 TL |
2214 | } else if (token == MATCH) { |
2215 | if (pc) { | |
35454d8a TL |
2216 | parse_warn (cfile, |
2217 | "invalid match in subclass."); | |
ece6ea33 TL |
2218 | skip_to_semi (cfile); |
2219 | break; | |
2220 | } | |
98311e4b DH |
2221 | token = next_token (&val, (unsigned *)0, cfile); |
2222 | token = peek_token (&val, (unsigned *)0, cfile); | |
2223 | if (token != IF) | |
2224 | goto submatch; | |
06e77c34 DH |
2225 | token = next_token (&val, (unsigned *)0, cfile); |
2226 | if (matchedonce) { | |
2227 | parse_warn(cfile, "A class may only have " | |
2228 | "one 'match if' clause."); | |
2229 | skip_to_semi(cfile); | |
ece6ea33 TL |
2230 | break; |
2231 | } | |
06e77c34 DH |
2232 | matchedonce = 1; |
2233 | if (class->expr) | |
2234 | expression_dereference(&class->expr, MDL); | |
2235 | if (!parse_boolean_expression (&class->expr, cfile, | |
9e383163 TL |
2236 | &lose)) { |
2237 | if (!lose) { | |
2238 | parse_warn (cfile, | |
2239 | "expecting boolean expr."); | |
2240 | skip_to_semi (cfile); | |
2241 | } | |
2242 | } else { | |
6f8fb41f | 2243 | #if defined (DEBUG_EXPRESSION_PARSE) |
9e383163 TL |
2244 | print_expression ("class match", |
2245 | class -> expr); | |
6f8fb41f | 2246 | #endif |
9e383163 TL |
2247 | parse_semi (cfile); |
2248 | } | |
ece6ea33 | 2249 | } else if (token == SPAWN) { |
06e77c34 | 2250 | token = next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 2251 | if (pc) { |
35454d8a TL |
2252 | parse_warn (cfile, |
2253 | "invalid spawn in subclass."); | |
ece6ea33 TL |
2254 | skip_to_semi (cfile); |
2255 | break; | |
2256 | } | |
b19f2e1c | 2257 | class -> spawning = 1; |
b3519f23 | 2258 | token = next_token (&val, (unsigned *)0, cfile); |
ece6ea33 | 2259 | if (token != WITH) { |
35454d8a TL |
2260 | parse_warn (cfile, |
2261 | "expecting with after spawn"); | |
ece6ea33 TL |
2262 | skip_to_semi (cfile); |
2263 | break; | |
2264 | } | |
06d3e394 | 2265 | submatch: |
06e77c34 | 2266 | if (submatchedonce) { |
35454d8a TL |
2267 | parse_warn (cfile, |
2268 | "can't override existing %s.", | |
8b500185 TL |
2269 | "submatch/spawn"); |
2270 | skip_to_semi (cfile); | |
2271 | break; | |
2272 | } | |
06e77c34 DH |
2273 | submatchedonce = 1; |
2274 | if (class->submatch) | |
2275 | expression_dereference(&class->submatch, MDL); | |
9e383163 TL |
2276 | if (!parse_data_expression (&class -> submatch, |
2277 | cfile, &lose)) { | |
2278 | if (!lose) { | |
2279 | parse_warn (cfile, | |
2280 | "expecting data expr."); | |
2281 | skip_to_semi (cfile); | |
2282 | } | |
2283 | } else { | |
6f8fb41f | 2284 | #if defined (DEBUG_EXPRESSION_PARSE) |
9e383163 TL |
2285 | print_expression ("class submatch", |
2286 | class -> submatch); | |
6f8fb41f | 2287 | #endif |
9e383163 TL |
2288 | parse_semi (cfile); |
2289 | } | |
88dcab62 | 2290 | } else if (token == LEASE) { |
b3519f23 TL |
2291 | next_token (&val, (unsigned *)0, cfile); |
2292 | token = next_token (&val, (unsigned *)0, cfile); | |
88dcab62 | 2293 | if (token != LIMIT) { |
35454d8a | 2294 | parse_warn (cfile, "expecting \"limit\""); |
88dcab62 TL |
2295 | if (token != SEMI) |
2296 | skip_to_semi (cfile); | |
2297 | break; | |
2298 | } | |
b3519f23 | 2299 | token = next_token (&val, (unsigned *)0, cfile); |
88dcab62 | 2300 | if (token != NUMBER) { |
35454d8a | 2301 | parse_warn (cfile, "expecting a number"); |
88dcab62 TL |
2302 | if (token != SEMI) |
2303 | skip_to_semi (cfile); | |
2304 | break; | |
2305 | } | |
2306 | class -> lease_limit = atoi (val); | |
06e77c34 DH |
2307 | if (class->billed_leases) |
2308 | dfree(class->billed_leases, MDL); | |
88dcab62 TL |
2309 | class -> billed_leases = |
2310 | dmalloc (class -> lease_limit * | |
436f1c8c | 2311 | sizeof (struct lease *), MDL); |
88dcab62 | 2312 | if (!class -> billed_leases) |
8ae2d595 | 2313 | log_fatal ("no memory for billed leases."); |
88dcab62 TL |
2314 | memset (class -> billed_leases, 0, |
2315 | (class -> lease_limit * | |
2316 | sizeof class -> billed_leases)); | |
2317 | have_billing_classes = 1; | |
2318 | parse_semi (cfile); | |
24a75c03 | 2319 | } else { |
2d59f590 TL |
2320 | declaration = parse_statement (cfile, class -> group, |
2321 | CLASS_DECL, | |
2322 | (struct host_decl *)0, | |
2323 | declaration); | |
24a75c03 TL |
2324 | } |
2325 | } while (1); | |
899d754f | 2326 | |
06e77c34 DH |
2327 | if (class->flags & CLASS_DECL_DELETED) { |
2328 | if (type == CLASS_TYPE_CLASS) { | |
2329 | struct class *theclass = NULL; | |
899d754f | 2330 | |
06e77c34 DH |
2331 | status = find_class(&theclass, class->name, MDL); |
2332 | if (status == ISC_R_SUCCESS) { | |
2333 | delete_class(theclass, 0); | |
2334 | class_dereference(&theclass, MDL); | |
2335 | } | |
2336 | } else { | |
2337 | class_hash_delete(pc->hash, | |
2338 | (char *)class->hash_string.data, | |
2339 | class->hash_string.len, MDL); | |
899d754f | 2340 | } |
06e77c34 | 2341 | } else if (type == CLASS_TYPE_CLASS && new) { |
de94ca72 | 2342 | if (!collections -> classes) |
20916cae | 2343 | class_reference (&collections -> classes, class, MDL); |
de94ca72 | 2344 | else { |
20916cae TL |
2345 | struct class *c; |
2346 | for (c = collections -> classes; | |
2347 | c -> nic; c = c -> nic) | |
de94ca72 | 2348 | ; |
20916cae | 2349 | class_reference (&c -> nic, class, MDL); |
de94ca72 TL |
2350 | } |
2351 | } | |
06e77c34 | 2352 | |
899d754f | 2353 | if (cp) /* should always be 0??? */ |
20916cae TL |
2354 | status = class_reference (cp, class, MDL); |
2355 | class_dereference (&class, MDL); | |
2356 | if (pc) | |
2357 | class_dereference (&pc, MDL); | |
2358 | return cp ? (status == ISC_R_SUCCESS) : 1; | |
24a75c03 TL |
2359 | } |
2360 | ||
2d59f590 TL |
2361 | /* shared-network-declaration :== |
2362 | hostname LBRACE declarations parameters RBRACE */ | |
1f814ff2 | 2363 | |
2d59f590 | 2364 | void parse_shared_net_declaration (cfile, group) |
35454d8a | 2365 | struct parse *cfile; |
7dfc8ac2 | 2366 | struct group *group; |
1f814ff2 | 2367 | { |
b1b7b521 | 2368 | const char *val; |
6f8fb41f | 2369 | enum dhcp_token token; |
1f814ff2 | 2370 | struct shared_network *share; |
1f814ff2 | 2371 | char *name; |
2d59f590 | 2372 | int declaration = 0; |
20916cae | 2373 | isc_result_t status; |
1f814ff2 | 2374 | |
20916cae TL |
2375 | share = (struct shared_network *)0; |
2376 | status = shared_network_allocate (&share, MDL); | |
2377 | if (status != ISC_R_SUCCESS) | |
2378 | log_fatal ("Can't allocate shared subnet: %s", | |
2379 | isc_result_totext (status)); | |
2380 | clone_group (&share -> group, group, MDL); | |
2381 | shared_network_reference (&share -> group -> shared_network, | |
2382 | share, MDL); | |
1f814ff2 TL |
2383 | |
2384 | /* Get the name of the shared network... */ | |
b3519f23 | 2385 | token = peek_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 2386 | if (token == STRING) { |
b3519f23 | 2387 | token = next_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 TL |
2388 | |
2389 | if (val [0] == 0) { | |
35454d8a | 2390 | parse_warn (cfile, "zero-length shared network name"); |
7dfc8ac2 TL |
2391 | val = "<no-name-given>"; |
2392 | } | |
436f1c8c | 2393 | name = dmalloc (strlen (val) + 1, MDL); |
7dfc8ac2 | 2394 | if (!name) |
8ae2d595 | 2395 | log_fatal ("no memory for shared network name"); |
7dfc8ac2 TL |
2396 | strcpy (name, val); |
2397 | } else { | |
2398 | name = parse_host_name (cfile); | |
20916cae | 2399 | if (!name) { |
6c5223f5 TL |
2400 | parse_warn (cfile, |
2401 | "expecting a name for shared-network"); | |
2402 | skip_to_semi (cfile); | |
20916cae | 2403 | shared_network_dereference (&share, MDL); |
7dfc8ac2 | 2404 | return; |
20916cae | 2405 | } |
1f814ff2 | 2406 | } |
1f814ff2 TL |
2407 | share -> name = name; |
2408 | ||
20916cae TL |
2409 | if (!parse_lbrace (cfile)) { |
2410 | shared_network_dereference (&share, MDL); | |
7dfc8ac2 | 2411 | return; |
20916cae | 2412 | } |
7dfc8ac2 | 2413 | |
1f814ff2 | 2414 | do { |
b3519f23 | 2415 | token = peek_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 2416 | if (token == RBRACE) { |
b3519f23 | 2417 | token = next_token (&val, (unsigned *)0, cfile); |
20916cae | 2418 | if (!share -> subnets) |
4bd8800e TL |
2419 | parse_warn (cfile, |
2420 | "empty shared-network decl"); | |
20916cae TL |
2421 | else |
2422 | enter_shared_network (share); | |
2423 | shared_network_dereference (&share, MDL); | |
1f814ff2 | 2424 | return; |
0b69dcc8 | 2425 | } else if (token == END_OF_FILE) { |
b3519f23 | 2426 | token = next_token (&val, (unsigned *)0, cfile); |
35454d8a | 2427 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 2428 | break; |
79931db3 | 2429 | } else if (token == INTERFACE) { |
b3519f23 TL |
2430 | token = next_token (&val, (unsigned *)0, cfile); |
2431 | token = next_token (&val, (unsigned *)0, cfile); | |
79931db3 TL |
2432 | new_shared_network_interface (cfile, share, val); |
2433 | if (!parse_semi (cfile)) | |
2434 | break; | |
2435 | continue; | |
1f814ff2 | 2436 | } |
5376e3e9 | 2437 | |
2d59f590 TL |
2438 | declaration = parse_statement (cfile, share -> group, |
2439 | SHARED_NET_DECL, | |
2440 | (struct host_decl *)0, | |
2441 | declaration); | |
1f814ff2 | 2442 | } while (1); |
20916cae | 2443 | shared_network_dereference (&share, MDL); |
1f814ff2 TL |
2444 | } |
2445 | ||
98bd7ca0 DH |
2446 | |
2447 | static int | |
2448 | common_subnet_parsing(struct parse *cfile, | |
2449 | struct shared_network *share, | |
2450 | struct subnet *subnet) { | |
2451 | enum dhcp_token token; | |
2452 | struct subnet *t, *u; | |
2453 | const char *val; | |
2454 | int declaration = 0; | |
2455 | ||
2456 | enter_subnet(subnet); | |
2457 | ||
2458 | if (!parse_lbrace(cfile)) { | |
2459 | subnet_dereference(&subnet, MDL); | |
2460 | return 0; | |
2461 | } | |
2462 | ||
2463 | do { | |
2464 | token = peek_token(&val, NULL, cfile); | |
2465 | if (token == RBRACE) { | |
2466 | token = next_token(&val, NULL, cfile); | |
2467 | break; | |
2468 | } else if (token == END_OF_FILE) { | |
2469 | token = next_token(&val, NULL, cfile); | |
2470 | parse_warn (cfile, "unexpected end of file"); | |
2471 | break; | |
2472 | } else if (token == INTERFACE) { | |
2473 | token = next_token(&val, NULL, cfile); | |
2474 | token = next_token(&val, NULL, cfile); | |
2475 | new_shared_network_interface(cfile, share, val); | |
2476 | if (!parse_semi(cfile)) | |
2477 | break; | |
2478 | continue; | |
2479 | } | |
2480 | declaration = parse_statement(cfile, subnet->group, | |
2481 | SUBNET_DECL, | |
2482 | NULL, | |
2483 | declaration); | |
2484 | } while (1); | |
2485 | ||
2486 | /* Add the subnet to the list of subnets in this shared net. */ | |
2487 | if (share->subnets == NULL) { | |
2488 | subnet_reference(&share->subnets, subnet, MDL); | |
2489 | } else { | |
2490 | u = NULL; | |
2491 | for (t = share->subnets; t->next_sibling; t = t->next_sibling) { | |
2492 | if (subnet_inner_than(subnet, t, 0)) { | |
2493 | subnet_reference(&subnet->next_sibling, t, MDL); | |
2494 | if (u) { | |
2495 | subnet_dereference(&u->next_sibling, | |
2496 | MDL); | |
2497 | subnet_reference(&u->next_sibling, | |
2498 | subnet, MDL); | |
2499 | } else { | |
2500 | subnet_dereference(&share->subnets, | |
2501 | MDL); | |
2502 | subnet_reference(&share->subnets, | |
2503 | subnet, MDL); | |
2504 | } | |
2505 | subnet_dereference(&subnet, MDL); | |
2506 | return 1; | |
2507 | } | |
2508 | u = t; | |
2509 | } | |
2510 | subnet_reference(&t->next_sibling, subnet, MDL); | |
2511 | } | |
2512 | subnet_dereference(&subnet, MDL); | |
2513 | return 1; | |
2514 | } | |
2515 | ||
2d59f590 TL |
2516 | /* subnet-declaration :== |
2517 | net NETMASK netmask RBRACE parameters declarations LBRACE */ | |
685963dc | 2518 | |
2d59f590 | 2519 | void parse_subnet_declaration (cfile, share) |
35454d8a | 2520 | struct parse *cfile; |
1f814ff2 | 2521 | struct shared_network *share; |
685963dc | 2522 | { |
b1b7b521 | 2523 | const char *val; |
6f8fb41f | 2524 | enum dhcp_token token; |
763adef1 | 2525 | struct subnet *subnet, *t, *u; |
7dfc8ac2 | 2526 | struct iaddr iaddr; |
685963dc | 2527 | unsigned char addr [4]; |
b1b7b521 | 2528 | unsigned len = sizeof addr; |
20916cae | 2529 | isc_result_t status; |
685963dc | 2530 | |
20916cae TL |
2531 | subnet = (struct subnet *)0; |
2532 | status = subnet_allocate (&subnet, MDL); | |
2533 | if (status != ISC_R_SUCCESS) | |
2534 | log_fatal ("Allocation of new subnet failed: %s", | |
2535 | isc_result_totext (status)); | |
2536 | shared_network_reference (&subnet -> shared_network, share, MDL); | |
2537 | if (!clone_group (&subnet -> group, share -> group, MDL)) | |
2538 | log_fatal ("allocation of group for new subnet failed."); | |
2539 | subnet_reference (&subnet -> group -> subnet, subnet, MDL); | |
685963dc TL |
2540 | |
2541 | /* Get the network number... */ | |
20916cae TL |
2542 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
2543 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 2544 | return; |
20916cae | 2545 | } |
7dfc8ac2 TL |
2546 | memcpy (iaddr.iabuf, addr, len); |
2547 | iaddr.len = len; | |
2548 | subnet -> net = iaddr; | |
685963dc | 2549 | |
b3519f23 | 2550 | token = next_token (&val, (unsigned *)0, cfile); |
685963dc | 2551 | if (token != NETMASK) { |
35454d8a | 2552 | parse_warn (cfile, "Expecting netmask"); |
685963dc | 2553 | skip_to_semi (cfile); |
7dfc8ac2 | 2554 | return; |
685963dc TL |
2555 | } |
2556 | ||
2557 | /* Get the netmask... */ | |
20916cae TL |
2558 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
2559 | subnet_dereference (&subnet, MDL); | |
7dfc8ac2 | 2560 | return; |
20916cae | 2561 | } |
7dfc8ac2 TL |
2562 | memcpy (iaddr.iabuf, addr, len); |
2563 | iaddr.len = len; | |
2564 | subnet -> netmask = iaddr; | |
685963dc | 2565 | |
20916cae TL |
2566 | /* Validate the network number/netmask pair. */ |
2567 | if (host_addr (subnet -> net, subnet -> netmask)) { | |
98311e4b DH |
2568 | char *maskstr; |
2569 | ||
2570 | maskstr = strdup (piaddr (subnet -> netmask)); | |
20916cae | 2571 | parse_warn (cfile, |
98311e4b DH |
2572 | "subnet %s netmask %s: bad subnet number/mask combination.", |
2573 | piaddr (subnet -> net), maskstr); | |
2574 | free(maskstr); | |
20916cae TL |
2575 | subnet_dereference (&subnet, MDL); |
2576 | skip_to_semi (cfile); | |
2577 | return; | |
2578 | } | |
2579 | ||
98bd7ca0 DH |
2580 | common_subnet_parsing(cfile, share, subnet); |
2581 | } | |
685963dc | 2582 | |
98bd7ca0 DH |
2583 | /* subnet6-declaration :== |
2584 | net / bits RBRACE parameters declarations LBRACE */ | |
2585 | ||
2586 | void | |
2587 | parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) { | |
2588 | struct subnet *subnet; | |
2589 | isc_result_t status; | |
2590 | enum dhcp_token token; | |
2591 | const char *val; | |
2592 | char *endp; | |
2593 | int ofs; | |
2594 | const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, | |
2595 | 0xF0, 0xF8, 0xFC, 0xFE }; | |
2596 | struct iaddr iaddr; | |
2597 | struct ipv6_pool *pool; | |
2598 | ||
fe5b0fdd DH |
2599 | #if !defined(DHCPv6) |
2600 | parse_warn(cfile, "No DHCPv6 support."); | |
2601 | skip_to_semi(cfile); | |
2602 | #else /* defined(DHCPv6) */ | |
98bd7ca0 DH |
2603 | subnet = NULL; |
2604 | status = subnet_allocate(&subnet, MDL); | |
2605 | if (status != ISC_R_SUCCESS) { | |
2606 | log_fatal("Allocation of new subnet failed: %s", | |
2607 | isc_result_totext(status)); | |
2608 | } | |
2609 | shared_network_reference(&subnet->shared_network, share, MDL); | |
2610 | if (!clone_group(&subnet->group, share->group, MDL)) { | |
2611 | log_fatal("Allocation of group for new subnet failed."); | |
2612 | } | |
2613 | subnet_reference(&subnet->group->subnet, subnet, MDL); | |
2614 | ||
2615 | if (!parse_ip6_addr(cfile, &subnet->net)) { | |
2616 | subnet_dereference(&subnet, MDL); | |
7dfc8ac2 | 2617 | return; |
20916cae | 2618 | } |
7dfc8ac2 | 2619 | |
98bd7ca0 DH |
2620 | token = next_token(&val, NULL, cfile); |
2621 | if (token != SLASH) { | |
2622 | parse_warn(cfile, "Expecting a '/'."); | |
2623 | skip_to_semi(cfile); | |
2624 | return; | |
2625 | } | |
1f814ff2 | 2626 | |
98bd7ca0 DH |
2627 | token = next_token(&val, NULL, cfile); |
2628 | if (token != NUMBER) { | |
2629 | parse_warn(cfile, "Expecting a number."); | |
2630 | skip_to_semi(cfile); | |
2631 | return; | |
2632 | } | |
2633 | ||
2634 | subnet->prefix_len = strtol(val, &endp, 10); | |
2635 | if ((subnet->prefix_len < 0) || | |
2636 | (subnet->prefix_len > 128) || | |
2637 | (*endp != '\0')) { | |
2638 | parse_warn(cfile, "Expecting a number between 0 and 128."); | |
2639 | skip_to_semi(cfile); | |
2640 | return; | |
2641 | } | |
2642 | ||
2643 | /* | |
2644 | * Create a netmask. | |
2645 | */ | |
2646 | subnet->netmask.len = 16; | |
2647 | ofs = subnet->prefix_len / 8; | |
2648 | if (ofs < subnet->netmask.len) { | |
2649 | subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8]; | |
2650 | } | |
2651 | while (--ofs >= 0) { | |
2652 | subnet->netmask.iabuf[ofs] = 0xFF; | |
2653 | } | |
2654 | ||
2655 | /* Validate the network number/netmask pair. */ | |
2656 | iaddr = subnet_number(subnet->net, subnet->netmask); | |
2657 | if (memcmp(&iaddr, &subnet->net, 16) != 0) { | |
2658 | parse_warn(cfile, | |
2659 | "subnet %s/%d: prefix not long enough for address.", | |
2660 | piaddr(subnet->net), subnet->prefix_len); | |
2661 | subnet_dereference(&subnet, MDL); | |
2662 | skip_to_semi(cfile); | |
2663 | return; | |
2664 | } | |
2665 | ||
2666 | if (!common_subnet_parsing(cfile, share, subnet)) { | |
2667 | return; | |
7dfc8ac2 | 2668 | } |
fe5b0fdd | 2669 | #endif /* defined(DHCPv6) */ |
685963dc TL |
2670 | } |
2671 | ||
2d59f590 | 2672 | /* group-declaration :== RBRACE parameters declarations LBRACE */ |
7dfc8ac2 | 2673 | |
2d59f590 | 2674 | void parse_group_declaration (cfile, group) |
35454d8a | 2675 | struct parse *cfile; |
7dfc8ac2 | 2676 | struct group *group; |
685963dc | 2677 | { |
b1b7b521 | 2678 | const char *val; |
6f8fb41f | 2679 | enum dhcp_token token; |
7dfc8ac2 | 2680 | struct group *g; |
2d59f590 | 2681 | int declaration = 0; |
29c35bed TL |
2682 | struct group_object *t; |
2683 | isc_result_t status; | |
d9eefc5d | 2684 | char *name = NULL; |
29c35bed TL |
2685 | int deletedp = 0; |
2686 | int dynamicp = 0; | |
2687 | int staticp = 0; | |
685963dc | 2688 | |
20916cae TL |
2689 | g = (struct group *)0; |
2690 | if (!clone_group (&g, group, MDL)) | |
2691 | log_fatal ("no memory for explicit group."); | |
685963dc | 2692 | |
b3519f23 | 2693 | token = peek_token (&val, (unsigned *)0, cfile); |
29c35bed | 2694 | if (is_identifier (token) || token == STRING) { |
b3519f23 | 2695 | next_token (&val, (unsigned *)0, cfile); |
29c35bed | 2696 | |
436f1c8c | 2697 | name = dmalloc (strlen (val) + 1, MDL); |
29c35bed TL |
2698 | if (!name) |
2699 | log_fatal ("no memory for group decl name %s", val); | |
2700 | strcpy (name, val); | |
2701 | } | |
2702 | ||
20916cae TL |
2703 | if (!parse_lbrace (cfile)) { |
2704 | group_dereference (&g, MDL); | |
7dfc8ac2 | 2705 | return; |
20916cae | 2706 | } |
d7837182 | 2707 | |
7dfc8ac2 | 2708 | do { |
b3519f23 | 2709 | token = peek_token (&val, (unsigned *)0, cfile); |
5376e3e9 | 2710 | if (token == RBRACE) { |
b3519f23 | 2711 | token = next_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 2712 | break; |
0b69dcc8 | 2713 | } else if (token == END_OF_FILE) { |
b3519f23 | 2714 | token = next_token (&val, (unsigned *)0, cfile); |
35454d8a | 2715 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 | 2716 | break; |
007e3ee4 | 2717 | } else if (token == TOKEN_DELETED) { |
b3519f23 | 2718 | token = next_token (&val, (unsigned *)0, cfile); |
29c35bed TL |
2719 | parse_semi (cfile); |
2720 | deletedp = 1; | |
2721 | } else if (token == DYNAMIC) { | |
b3519f23 | 2722 | token = next_token (&val, (unsigned *)0, cfile); |
29c35bed TL |
2723 | parse_semi (cfile); |
2724 | dynamicp = 1; | |
2725 | } else if (token == STATIC) { | |
b3519f23 | 2726 | token = next_token (&val, (unsigned *)0, cfile); |
29c35bed TL |
2727 | parse_semi (cfile); |
2728 | staticp = 1; | |
5376e3e9 | 2729 | } |
2d59f590 TL |
2730 | declaration = parse_statement (cfile, g, GROUP_DECL, |
2731 | (struct host_decl *)0, | |
2732 | declaration); | |
7dfc8ac2 | 2733 | } while (1); |
29c35bed TL |
2734 | |
2735 | if (name) { | |
2736 | if (deletedp) { | |
2737 | if (group_name_hash) { | |
20916cae TL |
2738 | t = (struct group_object *)0; |
2739 | if (group_hash_lookup (&t, group_name_hash, | |
2740 | name, | |
2741 | strlen (name), MDL)) { | |
29c35bed TL |
2742 | delete_group (t, 0); |
2743 | } | |
2744 | } | |
2745 | } else { | |
20916cae TL |
2746 | t = (struct group_object *)0; |
2747 | status = group_object_allocate (&t, MDL); | |
2748 | if (status != ISC_R_SUCCESS) | |
2749 | log_fatal ("no memory for group decl %s: %s", | |
2750 | val, isc_result_totext (status)); | |
2751 | group_reference (&t -> group, g, MDL); | |
29c35bed TL |
2752 | t -> name = name; |
2753 | t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) | | |
2754 | (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) | | |
2755 | (deletedp ? GROUP_OBJECT_DELETED : 0)); | |
2756 | supersede_group (t, 0); | |
2757 | } | |
20916cae TL |
2758 | if (t) |
2759 | group_object_dereference (&t, MDL); | |
29c35bed | 2760 | } |
d7837182 TL |
2761 | } |
2762 | ||
2d59f590 TL |
2763 | /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI |
2764 | ip-addrs-or-hostnames :== ip-addr-or-hostname | |
2765 | | ip-addrs-or-hostnames ip-addr-or-hostname */ | |
d7837182 | 2766 | |
98bd7ca0 DH |
2767 | int |
2768 | parse_fixed_addr_param(struct option_cache **oc, | |
2769 | struct parse *cfile, | |
2770 | enum dhcp_token type) { | |
2771 | int parse_ok; | |
b1b7b521 | 2772 | const char *val; |
6f8fb41f | 2773 | enum dhcp_token token; |
98bd7ca0 | 2774 | struct expression *expr = NULL; |
6f8fb41f TL |
2775 | struct expression *tmp, *new; |
2776 | int status; | |
1f814ff2 TL |
2777 | |
2778 | do { | |
98bd7ca0 DH |
2779 | tmp = NULL; |
2780 | if (type == FIXED_ADDR) { | |
2781 | parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1); | |
2782 | } else { | |
2783 | /* INSIST(type == FIXED_ADDR6); */ | |
2784 | parse_ok = parse_ip6_addr_expr(&tmp, cfile); | |
2785 | } | |
2786 | if (parse_ok) { | |
2787 | if (expr != NULL) { | |
2788 | new = NULL; | |
2789 | status = make_concat(&new, expr, tmp); | |
2790 | expression_dereference(&expr, MDL); | |
2791 | expression_dereference(&tmp, MDL); | |
2792 | if (!status) { | |
028a8588 | 2793 | return 0; |
98bd7ca0 | 2794 | } |
028a8588 | 2795 | expr = new; |
98bd7ca0 | 2796 | } else { |
028a8588 | 2797 | expr = tmp; |
98bd7ca0 | 2798 | } |
6f8fb41f | 2799 | } else { |
98bd7ca0 | 2800 | if (expr != NULL) { |
436f1c8c | 2801 | expression_dereference (&expr, MDL); |
98bd7ca0 | 2802 | } |
6f8fb41f TL |
2803 | return 0; |
2804 | } | |
98bd7ca0 DH |
2805 | token = peek_token(&val, NULL, cfile); |
2806 | if (token == COMMA) { | |
2807 | token = next_token(&val, NULL, cfile); | |
2808 | } | |
1f814ff2 | 2809 | } while (token == COMMA); |
7dfc8ac2 | 2810 | |
98bd7ca0 DH |
2811 | if (!parse_semi(cfile)) { |
2812 | if (expr) { | |
436f1c8c | 2813 | expression_dereference (&expr, MDL); |
98bd7ca0 | 2814 | } |
6f8fb41f TL |
2815 | return 0; |
2816 | } | |
98bd7ca0 DH |
2817 | |
2818 | status = option_cache(oc, NULL, expr, NULL, MDL); | |
2819 | expression_dereference(&expr, MDL); | |
6f8fb41f | 2820 | return status; |
d7837182 TL |
2821 | } |
2822 | ||
2d59f590 TL |
2823 | /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE |
2824 | ||
2825 | lease_parameters :== <nil> | |
2826 | | lease_parameter | |
2827 | | lease_parameters lease_parameter | |
2828 | ||
2829 | lease_parameter :== STARTS date | |
2830 | | ENDS date | |
2831 | | TIMESTAMP date | |
2832 | | HARDWARE hardware-parameter | |
2833 | | UID hex_numbers SEMI | |
ccf5778a TL |
2834 | | HOSTNAME hostname SEMI |
2835 | | CLIENT_HOSTNAME hostname SEMI | |
2d59f590 TL |
2836 | | CLASS identifier SEMI |
2837 | | DYNAMIC_BOOTP SEMI */ | |
2838 | ||
20916cae | 2839 | int parse_lease_declaration (struct lease **lp, struct parse *cfile) |
d7837182 | 2840 | { |
b1b7b521 | 2841 | const char *val; |
6f8fb41f | 2842 | enum dhcp_token token; |
d7837182 | 2843 | unsigned char addr [4]; |
b1b7b521 | 2844 | unsigned len = sizeof addr; |
d7837182 TL |
2845 | int seenmask = 0; |
2846 | int seenbit; | |
2847 | char tbuf [32]; | |
20916cae | 2848 | struct lease *lease; |
96d7d13e | 2849 | struct executable_statement *on; |
436f1c8c TL |
2850 | struct expression *exp; |
2851 | struct data_string ds; | |
96d7d13e | 2852 | int lose; |
9e9b2261 | 2853 | TIME t; |
436f1c8c TL |
2854 | char *s; |
2855 | int noequal, newbinding; | |
2856 | struct binding *binding; | |
20916cae | 2857 | isc_result_t status; |
6c5223f5 TL |
2858 | struct option_cache *oc; |
2859 | pair *p; | |
e15d235d | 2860 | binding_state_t new_state; |
b3519f23 | 2861 | unsigned buflen = 0; |
f545ef7f | 2862 | struct class *class; |
d7837182 | 2863 | |
20916cae TL |
2864 | lease = (struct lease *)0; |
2865 | status = lease_allocate (&lease, MDL); | |
2866 | if (status != ISC_R_SUCCESS) | |
2867 | return 0; | |
9375101b | 2868 | |
d7837182 | 2869 | /* Get the address for which the lease has been issued. */ |
20916cae TL |
2870 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { |
2871 | lease_dereference (&lease, MDL); | |
2872 | return 0; | |
2873 | } | |
2874 | memcpy (lease -> ip_addr.iabuf, addr, len); | |
2875 | lease -> ip_addr.len = len; | |
d7837182 | 2876 | |
20916cae TL |
2877 | if (!parse_lbrace (cfile)) { |
2878 | lease_dereference (&lease, MDL); | |
2879 | return 0; | |
2880 | } | |
7dfc8ac2 | 2881 | |
d7837182 | 2882 | do { |
b3519f23 | 2883 | token = next_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 2884 | if (token == RBRACE) |
d7837182 | 2885 | break; |
0b69dcc8 | 2886 | else if (token == END_OF_FILE) { |
35454d8a | 2887 | parse_warn (cfile, "unexpected end of file"); |
5376e3e9 TL |
2888 | break; |
2889 | } | |
ece6ea33 | 2890 | strncpy (tbuf, val, sizeof tbuf); |
d7837182 TL |
2891 | tbuf [(sizeof tbuf) - 1] = 0; |
2892 | ||
2893 | /* Parse any of the times associated with the lease. */ | |
9e9b2261 TL |
2894 | switch (token) { |
2895 | case STARTS: | |
2896 | case ENDS: | |
2897 | case TIMESTAMP: | |
2898 | case TSTP: | |
2899 | case TSFP: | |
88cd8aca | 2900 | case ATSFP: |
8c8e27c5 | 2901 | case CLTT: |
7dfc8ac2 | 2902 | t = parse_date (cfile); |
d7837182 TL |
2903 | switch (token) { |
2904 | case STARTS: | |
2905 | seenbit = 1; | |
20916cae | 2906 | lease -> starts = t; |
d7837182 TL |
2907 | break; |
2908 | ||
2909 | case ENDS: | |
2910 | seenbit = 2; | |
20916cae | 2911 | lease -> ends = t; |
d7837182 TL |
2912 | break; |
2913 | ||
9e9b2261 TL |
2914 | case TSTP: |
2915 | seenbit = 65536; | |
20916cae | 2916 | lease -> tstp = t; |
19d868b2 | 2917 | break; |
9e9b2261 TL |
2918 | |
2919 | case TSFP: | |
2920 | seenbit = 131072; | |
20916cae | 2921 | lease -> tsfp = t; |
d7837182 | 2922 | break; |
88cd8aca DH |
2923 | |
2924 | case ATSFP: | |
2925 | seenbit = 262144; | |
2926 | lease->atsfp = t; | |
2927 | break; | |
9e9b2261 | 2928 | |
8c8e27c5 TL |
2929 | case CLTT: |
2930 | seenbit = 524288; | |
20916cae | 2931 | lease -> cltt = t; |
8c8e27c5 TL |
2932 | break; |
2933 | ||
9e9b2261 | 2934 | default: /* for gcc, we'll never get here. */ |
98311e4b DH |
2935 | log_fatal ("Impossible error at %s:%d.", MDL); |
2936 | return 0; | |
9e9b2261 TL |
2937 | } |
2938 | break; | |
d7837182 | 2939 | |
c57db45c | 2940 | /* Colon-separated hexadecimal octets... */ |
9e9b2261 TL |
2941 | case UID: |
2942 | seenbit = 8; | |
b3519f23 | 2943 | token = peek_token (&val, (unsigned *)0, cfile); |
9e9b2261 TL |
2944 | if (token == STRING) { |
2945 | unsigned char *tuid; | |
b3519f23 | 2946 | token = next_token (&val, &buflen, cfile); |
a3cd7f28 | 2947 | if (buflen < sizeof lease -> uid_buf) { |
b3519f23 | 2948 | tuid = lease -> uid_buf; |
a3cd7f28 TL |
2949 | lease -> uid_max = |
2950 | sizeof lease -> uid_buf; | |
2951 | } else { | |
b3519f23 TL |
2952 | tuid = ((unsigned char *) |
2953 | dmalloc (buflen, MDL)); | |
2954 | if (!tuid) { | |
2955 | log_error ("no space for uid"); | |
2956 | lease_dereference (&lease, | |
2957 | MDL); | |
2958 | return 0; | |
2959 | } | |
a3cd7f28 | 2960 | lease -> uid_max = buflen; |
d7837182 | 2961 | } |
7ebf32da | 2962 | lease -> uid_len = buflen; |
20916cae TL |
2963 | memcpy (tuid, val, lease -> uid_len); |
2964 | lease -> uid = tuid; | |
9e9b2261 | 2965 | } else { |
b3519f23 | 2966 | buflen = 0; |
20916cae TL |
2967 | lease -> uid = (parse_numeric_aggregate |
2968 | (cfile, (unsigned char *)0, | |
b3519f23 | 2969 | &buflen, ':', 16, 8)); |
20916cae TL |
2970 | if (!lease -> uid) { |
2971 | lease_dereference (&lease, MDL); | |
2972 | return 0; | |
2973 | } | |
7ebf32da | 2974 | lease -> uid_len = buflen; |
a3cd7f28 | 2975 | lease -> uid_max = buflen; |
20916cae TL |
2976 | if (lease -> uid_len == 0) { |
2977 | lease -> uid = (unsigned char *)0; | |
9e9b2261 TL |
2978 | parse_warn (cfile, "zero-length uid"); |
2979 | seenbit = 0; | |
d0463358 | 2980 | parse_semi (cfile); |
9e9b2261 TL |
2981 | break; |
2982 | } | |
2983 | } | |
d0463358 | 2984 | parse_semi (cfile); |
20916cae | 2985 | if (!lease -> uid) { |
9e9b2261 TL |
2986 | log_fatal ("No memory for lease uid"); |
2987 | } | |
2988 | break; | |
a55ccdd0 | 2989 | |
9e9b2261 TL |
2990 | case CLASS: |
2991 | seenbit = 32; | |
b3519f23 | 2992 | token = next_token (&val, (unsigned *)0, cfile); |
9e9b2261 TL |
2993 | if (!is_identifier (token)) { |
2994 | if (token != SEMI) | |
2995 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
2996 | lease_dereference (&lease, MDL); |
2997 | return 0; | |
9e9b2261 | 2998 | } |
d0463358 | 2999 | parse_semi (cfile); |
9e9b2261 TL |
3000 | /* for now, we aren't using this. */ |
3001 | break; | |
ccf5778a | 3002 | |
9e9b2261 TL |
3003 | case HARDWARE: |
3004 | seenbit = 64; | |
3005 | parse_hardware_param (cfile, | |
20916cae | 3006 | &lease -> hardware_addr); |
9e9b2261 TL |
3007 | break; |
3008 | ||
a55ccdd0 DH |
3009 | case TOKEN_RESERVED: |
3010 | seenbit = 0; | |
3011 | lease->flags |= RESERVED_LEASE; | |
3012 | parse_semi(cfile); | |
3013 | break; | |
3014 | ||
9e9b2261 | 3015 | case DYNAMIC_BOOTP: |
a55ccdd0 | 3016 | seenbit = 0; |
98311e4b | 3017 | lease -> flags |= BOOTP_LEASE; |
d0463358 | 3018 | parse_semi (cfile); |
9e9b2261 | 3019 | break; |
a55ccdd0 DH |
3020 | |
3021 | /* XXX: Reverse compatibility? */ | |
007e3ee4 TL |
3022 | case TOKEN_ABANDONED: |
3023 | seenbit = 256; | |
3024 | lease -> binding_state = FTS_ABANDONED; | |
3025 | lease -> next_binding_state = FTS_ABANDONED; | |
d0463358 | 3026 | parse_semi (cfile); |
9e9b2261 TL |
3027 | break; |
3028 | ||
007e3ee4 TL |
3029 | case TOKEN_NEXT: |
3030 | seenbit = 128; | |
b3519f23 | 3031 | token = next_token (&val, (unsigned *)0, cfile); |
301a5b66 TL |
3032 | if (token != BINDING) { |
3033 | parse_warn (cfile, "expecting 'binding'"); | |
3034 | skip_to_semi (cfile); | |
3035 | break; | |
3036 | } | |
007e3ee4 TL |
3037 | goto do_binding_state; |
3038 | ||
3039 | case BINDING: | |
9e9b2261 | 3040 | seenbit = 256; |
007e3ee4 TL |
3041 | |
3042 | do_binding_state: | |
b3519f23 | 3043 | token = next_token (&val, (unsigned *)0, cfile); |
007e3ee4 TL |
3044 | if (token != STATE) { |
3045 | parse_warn (cfile, "expecting 'state'"); | |
3046 | skip_to_semi (cfile); | |
3047 | break; | |
3048 | } | |
b3519f23 | 3049 | token = next_token (&val, (unsigned *)0, cfile); |
007e3ee4 TL |
3050 | switch (token) { |
3051 | case TOKEN_ABANDONED: | |
e15d235d | 3052 | new_state = FTS_ABANDONED; |
007e3ee4 TL |
3053 | break; |
3054 | case TOKEN_FREE: | |
e15d235d | 3055 | new_state = FTS_FREE; |
007e3ee4 TL |
3056 | break; |
3057 | case TOKEN_ACTIVE: | |
e15d235d | 3058 | new_state = FTS_ACTIVE; |
007e3ee4 TL |
3059 | break; |
3060 | case TOKEN_EXPIRED: | |
e15d235d | 3061 | new_state = FTS_EXPIRED; |
007e3ee4 TL |
3062 | break; |
3063 | case TOKEN_RELEASED: | |
e15d235d | 3064 | new_state = FTS_RELEASED; |
007e3ee4 TL |
3065 | break; |
3066 | case TOKEN_RESET: | |
e15d235d | 3067 | new_state = FTS_RESET; |
007e3ee4 TL |
3068 | break; |
3069 | case TOKEN_BACKUP: | |
e15d235d | 3070 | new_state = FTS_BACKUP; |
007e3ee4 | 3071 | break; |
a55ccdd0 DH |
3072 | |
3073 | /* RESERVED and BOOTP states preserved for | |
3074 | * compatiblity with older versions. | |
3075 | */ | |
007e3ee4 | 3076 | case TOKEN_RESERVED: |
98311e4b | 3077 | new_state = FTS_ACTIVE; |
a55ccdd0 | 3078 | lease->flags |= RESERVED_LEASE; |
007e3ee4 TL |
3079 | break; |
3080 | case TOKEN_BOOTP: | |
98311e4b | 3081 | new_state = FTS_ACTIVE; |
a55ccdd0 | 3082 | lease->flags |= BOOTP_LEASE; |
007e3ee4 | 3083 | break; |
a55ccdd0 | 3084 | |
007e3ee4 TL |
3085 | default: |
3086 | parse_warn (cfile, | |
3087 | "%s: expecting a binding state.", | |
3088 | val); | |
3089 | skip_to_semi (cfile); | |
98311e4b | 3090 | return 0; |
007e3ee4 | 3091 | } |
e15d235d TL |
3092 | |
3093 | if (seenbit == 256) { | |
3094 | lease -> binding_state = new_state; | |
3095 | ||
3096 | /* If no next binding state is specified, it's | |
3097 | the same as the current state. */ | |
3098 | if (!(seenmask & 128)) | |
3099 | lease -> next_binding_state = new_state; | |
3100 | } else | |
3101 | lease -> next_binding_state = new_state; | |
3102 | ||
d0463358 | 3103 | parse_semi (cfile); |
9e9b2261 | 3104 | break; |
ccf5778a | 3105 | |
9e9b2261 TL |
3106 | case CLIENT_HOSTNAME: |
3107 | seenbit = 1024; | |
b3519f23 TL |
3108 | token = peek_token (&val, (unsigned *)0, cfile); |
3109 | if (token == STRING) { | |
3110 | if (!parse_string (cfile, | |
3111 | &lease -> client_hostname, | |
3112 | (unsigned *)0)) { | |
3113 | lease_dereference (&lease, MDL); | |
3114 | return 0; | |
3115 | } | |
3116 | } else { | |
20916cae | 3117 | lease -> client_hostname = |
9e9b2261 | 3118 | parse_host_name (cfile); |
20916cae | 3119 | if (lease -> client_hostname) |
d0463358 | 3120 | parse_semi (cfile); |
b3519f23 TL |
3121 | else { |
3122 | parse_warn (cfile, | |
3123 | "expecting a hostname."); | |
3124 | skip_to_semi (cfile); | |
3125 | lease_dereference (&lease, MDL); | |
3126 | return 0; | |
3127 | } | |
d0463358 | 3128 | } |
9e9b2261 TL |
3129 | break; |
3130 | ||
3131 | case BILLING: | |
3132 | seenbit = 2048; | |
f545ef7f | 3133 | class = (struct class *)0; |
b3519f23 | 3134 | token = next_token (&val, (unsigned *)0, cfile); |
9e9b2261 | 3135 | if (token == CLASS) { |
b3519f23 TL |
3136 | token = next_token (&val, |
3137 | (unsigned *)0, cfile); | |
9e9b2261 TL |
3138 | if (token != STRING) { |
3139 | parse_warn (cfile, "expecting string"); | |
88dcab62 TL |
3140 | if (token != SEMI) |
3141 | skip_to_semi (cfile); | |
9e9b2261 TL |
3142 | token = BILLING; |
3143 | break; | |
88dcab62 | 3144 | } |
aaafa64a | 3145 | if (lease -> billing_class) |
ed1dc2c5 TL |
3146 | class_dereference (&lease -> billing_class, |
3147 | MDL); | |
f545ef7f TL |
3148 | find_class (&class, val, MDL); |
3149 | if (!class) | |
9e9b2261 TL |
3150 | parse_warn (cfile, |
3151 | "unknown class %s", val); | |
3152 | parse_semi (cfile); | |
3153 | } else if (token == SUBCLASS) { | |
20916cae | 3154 | if (lease -> billing_class) |
ed1dc2c5 TL |
3155 | class_dereference (&lease -> billing_class, |
3156 | MDL); | |
06e77c34 DH |
3157 | parse_class_declaration(&class, cfile, NULL, |
3158 | CLASS_TYPE_SUBCLASS); | |
9e9b2261 TL |
3159 | } else { |
3160 | parse_warn (cfile, "expecting \"class\""); | |
3161 | if (token != SEMI) | |
3162 | skip_to_semi (cfile); | |
3163 | } | |
f545ef7f | 3164 | if (class) { |
ed1dc2c5 TL |
3165 | class_reference (&lease -> billing_class, |
3166 | class, MDL); | |
f545ef7f TL |
3167 | class_dereference (&class, MDL); |
3168 | } | |
9e9b2261 | 3169 | break; |
96d7d13e | 3170 | |
9e9b2261 TL |
3171 | case ON: |
3172 | on = (struct executable_statement *)0; | |
3173 | lose = 0; | |
3174 | if (!parse_on_statement (&on, cfile, &lose)) { | |
3175 | skip_to_rbrace (cfile, 1); | |
20916cae TL |
3176 | lease_dereference (&lease, MDL); |
3177 | return 0; | |
7dfc8ac2 | 3178 | } |
436f1c8c | 3179 | seenbit = 0; |
d0463358 | 3180 | if ((on -> data.on.evtypes & ON_EXPIRY) && |
9e9b2261 | 3181 | on -> data.on.statements) { |
436f1c8c | 3182 | seenbit |= 16384; |
9e9b2261 | 3183 | executable_statement_reference |
20916cae | 3184 | (&lease -> on_expiry, |
436f1c8c | 3185 | on -> data.on.statements, MDL); |
d0463358 TL |
3186 | } |
3187 | if ((on -> data.on.evtypes & ON_RELEASE) && | |
3188 | on -> data.on.statements) { | |
436f1c8c | 3189 | seenbit |= 32768; |
9e9b2261 | 3190 | executable_statement_reference |
20916cae | 3191 | (&lease -> on_release, |
436f1c8c | 3192 | on -> data.on.statements, MDL); |
9e9b2261 | 3193 | } |
436f1c8c | 3194 | executable_statement_dereference (&on, MDL); |
9e9b2261 TL |
3195 | break; |
3196 | ||
9e383163 | 3197 | case OPTION: |
a609e69b | 3198 | case SUPERSEDE: |
9e383163 TL |
3199 | noequal = 0; |
3200 | seenbit = 0; | |
3201 | oc = (struct option_cache *)0; | |
3202 | if (parse_option_decl (&oc, cfile)) { | |
6c5223f5 TL |
3203 | if (oc -> option -> universe != |
3204 | &agent_universe) { | |
3205 | parse_warn (cfile, | |
3206 | "agent option expected."); | |
3207 | option_cache_dereference (&oc, MDL); | |
3208 | break; | |
3209 | } | |
3210 | if (!lease -> agent_options && | |
3211 | !(option_chain_head_allocate | |
3212 | (&lease -> agent_options, MDL))) { | |
3213 | log_error ("no memory to stash agent option"); | |
3214 | break; | |
3215 | } | |
3216 | for (p = &lease -> agent_options -> first; | |
3217 | *p; p = &((*p) -> cdr)) | |
3218 | ; | |
3219 | *p = cons (0, 0); | |
3220 | option_cache_reference (((struct option_cache **) | |
3221 | &((*p) -> car)), oc, MDL); | |
3222 | option_cache_dereference (&oc, MDL); | |
9e383163 TL |
3223 | } |
3224 | break; | |
3225 | ||
436f1c8c TL |
3226 | case TOKEN_SET: |
3227 | noequal = 0; | |
3228 | ||
b3519f23 | 3229 | token = next_token (&val, (unsigned *)0, cfile); |
436f1c8c TL |
3230 | if (token != NAME && token != NUMBER_OR_NAME) { |
3231 | parse_warn (cfile, | |
3232 | "%s can't be a variable name", | |
3233 | val); | |
3234 | badset: | |
3235 | skip_to_semi (cfile); | |
20916cae TL |
3236 | lease_dereference (&lease, MDL); |
3237 | return 0; | |
436f1c8c TL |
3238 | } |
3239 | ||
3240 | seenbit = 0; | |
3241 | special_set: | |
6ceb9118 TL |
3242 | if (lease -> scope) |
3243 | binding = find_binding (lease -> scope, val); | |
3244 | else | |
3245 | binding = (struct binding *)0; | |
436f1c8c | 3246 | if (!binding) { |
6ceb9118 TL |
3247 | if (!lease -> scope) |
3248 | if (!(binding_scope_allocate | |
3249 | (&lease -> scope, MDL))) | |
3250 | log_fatal ("no memory for scope"); | |
d758ad8c TL |
3251 | binding = dmalloc (sizeof *binding, MDL); |
3252 | if (!binding) | |
3253 | log_fatal ("No memory for lease %s.", | |
3254 | "binding"); | |
3255 | memset (binding, 0, sizeof *binding); | |
3256 | binding -> name = | |
3257 | dmalloc (strlen (val) + 1, MDL); | |
3258 | if (!binding -> name) | |
3259 | log_fatal ("No memory for binding %s.", | |
3260 | "name"); | |
3261 | strcpy (binding -> name, val); | |
3262 | newbinding = 1; | |
98311e4b DH |
3263 | } else { |
3264 | if (binding -> value) | |
3265 | binding_value_dereference (&binding -> value, | |
11cd757b | 3266 | MDL); |
436f1c8c TL |
3267 | newbinding = 0; |
3268 | } | |
98311e4b | 3269 | |
11cd757b TL |
3270 | if (!binding_value_allocate (&binding -> value, MDL)) |
3271 | log_fatal ("no memory for binding value."); | |
436f1c8c TL |
3272 | |
3273 | if (!noequal) { | |
b3519f23 | 3274 | token = next_token (&val, (unsigned *)0, cfile); |
436f1c8c TL |
3275 | if (token != EQUAL) { |
3276 | parse_warn (cfile, | |
3277 | "expecting '=' in set statement."); | |
3278 | goto badset; | |
3279 | } | |
3280 | } | |
3281 | ||
b3519f23 | 3282 | token = peek_token (&val, (unsigned *)0, cfile); |
436f1c8c | 3283 | if (token == STRING) { |
11cd757b | 3284 | unsigned char *tuid; |
b3519f23 | 3285 | token = next_token (&val, &buflen, cfile); |
11cd757b | 3286 | binding -> value -> type = binding_data; |
b3519f23 | 3287 | binding -> value -> value.data.len = buflen; |
11cd757b TL |
3288 | if (!(buffer_allocate |
3289 | (&binding -> value -> value.data.buffer, | |
b3519f23 | 3290 | buflen + 1, MDL))) |
11cd757b | 3291 | log_fatal ("No memory for binding."); |
b3519f23 | 3292 | memcpy ((char *) |
11cd757b | 3293 | (binding -> value -> |
b3519f23 TL |
3294 | value.data.buffer -> data), |
3295 | val, buflen + 1); | |
11cd757b TL |
3296 | binding -> value -> value.data.data = |
3297 | binding -> value -> value.data.buffer -> data; | |
3298 | binding -> value -> value.data.terminated = 1; | |
3299 | } else if (token == NUMBER_OR_NAME) { | |
3300 | binding -> value -> type = binding_data; | |
3301 | s = ((char *) | |
3302 | (parse_numeric_aggregate | |
3303 | (cfile, (unsigned char *)0, | |
3304 | &binding -> value -> value.data.len, | |
3305 | ':', 16, 8))); | |
3306 | if (!s) { | |
3307 | binding_value_dereference | |
3308 | (&binding -> value, MDL); | |
20916cae TL |
3309 | lease_dereference (&lease, MDL); |
3310 | return 0; | |
11cd757b TL |
3311 | } |
3312 | if (binding -> value -> value.data.len) { | |
436f1c8c | 3313 | if (!(buffer_allocate |
11cd757b TL |
3314 | (&binding -> value -> value.data.buffer, |
3315 | binding -> value -> value.data.len + 1, | |
3316 | MDL))) | |
436f1c8c | 3317 | log_fatal ("No memory for binding."); |
11cd757b TL |
3318 | memcpy ((binding -> value -> |
3319 | value.data.buffer -> data), s, | |
3320 | binding -> value -> value.data.len); | |
3321 | dfree (s, MDL); | |
3322 | binding -> value -> value.data.data = | |
3323 | binding -> value -> value.data.buffer -> data; | |
3324 | } | |
3325 | } else if (token == PERCENT) { | |
b3519f23 TL |
3326 | token = next_token (&val, (unsigned *)0, cfile); |
3327 | token = next_token (&val, (unsigned *)0, cfile); | |
11cd757b TL |
3328 | if (token != NUMBER) { |
3329 | parse_warn (cfile, | |
3330 | "expecting decimal number."); | |
3331 | if (token != SEMI) | |
3332 | skip_to_semi (cfile); | |
3333 | binding_value_dereference | |
3334 | (&binding -> value, MDL); | |
20916cae TL |
3335 | lease_dereference (&lease, MDL); |
3336 | return 0; | |
11cd757b TL |
3337 | } |
3338 | binding -> value -> type = binding_numeric; | |
3339 | binding -> value -> value.intval = atol (val); | |
3340 | } else if (token == NAME) { | |
b3519f23 TL |
3341 | token = next_token (&val, |
3342 | (unsigned *)0, cfile); | |
11cd757b TL |
3343 | binding -> value -> type = binding_boolean; |
3344 | if (!strcasecmp (val, "true")) | |
3345 | binding -> value -> value.boolean = 1; | |
3346 | else if (!strcasecmp (val, "false")) | |
3347 | binding -> value -> value.boolean = 0; | |
3348 | else | |
3349 | goto badbool; | |
436f1c8c | 3350 | } else { |
11cd757b TL |
3351 | badbool: |
3352 | parse_warn (cfile, | |
3353 | "expecting a constant value."); | |
3354 | skip_to_semi (cfile); | |
3355 | binding_value_dereference (&binding -> value, | |
3356 | MDL); | |
20916cae TL |
3357 | lease_dereference (&lease, MDL); |
3358 | return 0; | |
436f1c8c | 3359 | } |
11cd757b | 3360 | |
436f1c8c | 3361 | if (newbinding) { |
6ceb9118 TL |
3362 | binding -> next = lease -> scope -> bindings; |
3363 | lease -> scope -> bindings = binding; | |
436f1c8c TL |
3364 | } |
3365 | parse_semi (cfile); | |
3366 | break; | |
3367 | ||
9e9b2261 | 3368 | default: |
436f1c8c TL |
3369 | if (!strcasecmp (val, "ddns-fwd-name")) { |
3370 | seenbit = 4096; | |
3371 | noequal = 1; | |
3372 | goto special_set; | |
3373 | } else if (!strcasecmp (val, "ddns-rev-name")) { | |
3374 | seenbit = 8192; | |
3375 | noequal = 1; | |
3376 | goto special_set; | |
3377 | } | |
9e9b2261 TL |
3378 | skip_to_semi (cfile); |
3379 | seenbit = 0; | |
20916cae TL |
3380 | lease_dereference (&lease, MDL); |
3381 | return 0; | |
9e9b2261 | 3382 | } |
7dfc8ac2 | 3383 | |
d7837182 | 3384 | if (seenmask & seenbit) { |
35454d8a TL |
3385 | parse_warn (cfile, |
3386 | "Too many %s parameters in lease %s\n", | |
20916cae | 3387 | tbuf, piaddr (lease -> ip_addr)); |
d7837182 TL |
3388 | } else |
3389 | seenmask |= seenbit; | |
7dfc8ac2 | 3390 | |
d7837182 | 3391 | } while (1); |
8afe0787 TL |
3392 | |
3393 | /* If no binding state is specified, make one up. */ | |
3394 | if (!(seenmask & 256)) { | |
e73a0769 TL |
3395 | if (lease -> ends > cur_time || |
3396 | lease -> on_expiry || lease -> on_release) | |
8afe0787 | 3397 | lease -> binding_state = FTS_ACTIVE; |
301a5b66 | 3398 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
3399 | else if (lease -> pool && lease -> pool -> failover_peer) |
3400 | lease -> binding_state = FTS_EXPIRED; | |
301a5b66 | 3401 | #endif |
8afe0787 TL |
3402 | else |
3403 | lease -> binding_state = FTS_FREE; | |
e73a0769 | 3404 | if (lease -> binding_state == FTS_ACTIVE) { |
301a5b66 | 3405 | #if defined (FAILOVER_PROTOCOL) |
e73a0769 TL |
3406 | if (lease -> pool && lease -> pool -> failover_peer) |
3407 | lease -> next_binding_state = FTS_EXPIRED; | |
3408 | else | |
301a5b66 | 3409 | #endif |
e73a0769 TL |
3410 | lease -> next_binding_state = FTS_FREE; |
3411 | } else | |
3412 | lease -> next_binding_state = lease -> binding_state; | |
8afe0787 TL |
3413 | } |
3414 | ||
6f8a0361 TL |
3415 | if (!(seenmask & 65536)) |
3416 | lease -> tstp = lease -> ends; | |
3417 | ||
20916cae TL |
3418 | lease_reference (lp, lease, MDL); |
3419 | lease_dereference (&lease, MDL); | |
3420 | return 1; | |
d7837182 TL |
3421 | } |
3422 | ||
2d59f590 TL |
3423 | /* address-range-declaration :== ip-address ip-address SEMI |
3424 | | DYNAMIC_BOOTP ip-address ip-address SEMI */ | |
d7837182 | 3425 | |
98311e4b | 3426 | void parse_address_range (cfile, group, type, inpool, lpchain) |
35454d8a | 3427 | struct parse *cfile; |
f63b4929 TL |
3428 | struct group *group; |
3429 | int type; | |
20916cae | 3430 | struct pool *inpool; |
98311e4b | 3431 | struct lease **lpchain; |
d7837182 | 3432 | { |
f63b4929 | 3433 | struct iaddr low, high, net; |
d7837182 | 3434 | unsigned char addr [4]; |
b1b7b521 | 3435 | unsigned len = sizeof addr; |
6f8fb41f | 3436 | enum dhcp_token token; |
b1b7b521 | 3437 | const char *val; |
1f814ff2 | 3438 | int dynamic = 0; |
f63b4929 TL |
3439 | struct subnet *subnet; |
3440 | struct shared_network *share; | |
3441 | struct pool *p; | |
20916cae TL |
3442 | struct pool *pool; |
3443 | isc_result_t status; | |
1f814ff2 | 3444 | |
b3519f23 TL |
3445 | if ((token = peek_token (&val, |
3446 | (unsigned *)0, cfile)) == DYNAMIC_BOOTP) { | |
3447 | token = next_token (&val, (unsigned *)0, cfile); | |
ece6ea33 | 3448 | dynamic = 1; |
1f814ff2 | 3449 | } |
d7837182 TL |
3450 | |
3451 | /* Get the bottom address in the range... */ | |
7dfc8ac2 TL |
3452 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
3453 | return; | |
089fb364 TL |
3454 | memcpy (low.iabuf, addr, len); |
3455 | low.len = len; | |
d7837182 | 3456 | |
2d59f590 | 3457 | /* Only one address? */ |
b3519f23 | 3458 | token = peek_token (&val, (unsigned *)0, cfile); |
2d59f590 TL |
3459 | if (token == SEMI) |
3460 | high = low; | |
3461 | else { | |
d7837182 | 3462 | /* Get the top address in the range... */ |
2d59f590 TL |
3463 | if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) |
3464 | return; | |
3465 | memcpy (high.iabuf, addr, len); | |
3466 | high.len = len; | |
3467 | } | |
d7837182 | 3468 | |
b3519f23 | 3469 | token = next_token (&val, (unsigned *)0, cfile); |
7dfc8ac2 | 3470 | if (token != SEMI) { |
35454d8a | 3471 | parse_warn (cfile, "semicolon expected."); |
7dfc8ac2 TL |
3472 | skip_to_semi (cfile); |
3473 | return; | |
3474 | } | |
3475 | ||
f63b4929 TL |
3476 | if (type == SUBNET_DECL) { |
3477 | subnet = group -> subnet; | |
3478 | share = subnet -> shared_network; | |
3479 | } else { | |
3480 | share = group -> shared_network; | |
3481 | for (subnet = share -> subnets; | |
3482 | subnet; subnet = subnet -> next_sibling) { | |
3483 | net = subnet_number (low, subnet -> netmask); | |
e5e41be4 | 3484 | if (addr_eq (net, subnet -> net)) |
f63b4929 TL |
3485 | break; |
3486 | } | |
3487 | if (!subnet) { | |
35454d8a | 3488 | parse_warn (cfile, "address range not on network %s", |
f63b4929 | 3489 | group -> shared_network -> name); |
e5e41be4 TL |
3490 | log_error ("Be sure to place pool statement after %s", |
3491 | "related subnet declarations."); | |
f63b4929 TL |
3492 | return; |
3493 | } | |
3494 | } | |
3495 | ||
20916cae | 3496 | if (!inpool) { |
0a1dfb65 | 3497 | struct pool *last = (struct pool *)0; |
9e9b2261 | 3498 | |
f63b4929 TL |
3499 | /* If we're permitting dynamic bootp for this range, |
3500 | then look for a pool with an empty prohibit list and | |
436f1c8c | 3501 | a permit list with one entry that permits all clients. */ |
f63b4929 | 3502 | for (pool = share -> pools; pool; pool = pool -> next) { |
436f1c8c TL |
3503 | if ((!dynamic && !pool -> permit_list && |
3504 | pool -> prohibit_list && | |
3505 | !pool -> prohibit_list -> next && | |
3506 | (pool -> prohibit_list -> type == | |
3507 | permit_dynamic_bootp_clients)) || | |
3508 | (dynamic && !pool -> prohibit_list && | |
f63b4929 TL |
3509 | pool -> permit_list && |
3510 | !pool -> permit_list -> next && | |
3511 | (pool -> permit_list -> type == | |
d9eefc5d | 3512 | permit_all_clients))) { |
436f1c8c | 3513 | break; |
f63b4929 TL |
3514 | } |
3515 | last = pool; | |
3516 | } | |
3517 | ||
3518 | /* If we didn't get a pool, make one. */ | |
3519 | if (!pool) { | |
436f1c8c | 3520 | struct permit *p; |
20916cae TL |
3521 | status = pool_allocate (&pool, MDL); |
3522 | if (status != ISC_R_SUCCESS) | |
3523 | log_fatal ("no memory for ad-hoc pool: %s", | |
3524 | isc_result_totext (status)); | |
436f1c8c TL |
3525 | p = new_permit (MDL); |
3526 | if (!p) | |
3527 | log_fatal ("no memory for ad-hoc permit."); | |
3528 | ||
3529 | /* Dynamic pools permit all clients. Otherwise | |
3530 | we prohibit BOOTP clients. */ | |
f63b4929 | 3531 | if (dynamic) { |
436f1c8c TL |
3532 | p -> type = permit_all_clients; |
3533 | pool -> permit_list = p; | |
3534 | } else { | |
3535 | p -> type = permit_dynamic_bootp_clients; | |
3536 | pool -> prohibit_list = p; | |
f63b4929 | 3537 | } |
436f1c8c | 3538 | |
f63b4929 | 3539 | if (share -> pools) |
20916cae | 3540 | pool_reference (&last -> next, pool, MDL); |
f63b4929 | 3541 | else |
20916cae TL |
3542 | pool_reference (&share -> pools, pool, MDL); |
3543 | shared_network_reference (&pool -> shared_network, | |
3544 | share, MDL); | |
3545 | if (!clone_group (&pool -> group, share -> group, MDL)) | |
3546 | log_fatal ("no memory for anon pool group."); | |
a79ed92b TL |
3547 | } else { |
3548 | pool = (struct pool *)0; | |
0a1dfb65 TL |
3549 | if (last) |
3550 | pool_reference (&pool, last, MDL); | |
3551 | else | |
3552 | pool_reference (&pool, share -> pools, MDL); | |
f63b4929 | 3553 | } |
a79ed92b TL |
3554 | } else { |
3555 | pool = (struct pool *)0; | |
20916cae | 3556 | pool_reference (&pool, inpool, MDL); |
a79ed92b | 3557 | } |
20916cae | 3558 | |
c5261618 TL |
3559 | #if defined (FAILOVER_PROTOCOL) |
3560 | if (pool -> failover_peer && dynamic) { | |
3561 | /* Doctor, do you think I'm overly sensitive | |
3562 | about getting bug reports I can't fix? */ | |
3563 | parse_warn (cfile, "dynamic-bootp flag is %s", | |
3564 | "not permitted for address"); | |
3565 | log_error ("range declarations where there is a failover"); | |
3566 | log_error ("peer in scope. If you wish to declare an"); | |
3567 | log_error ("address range from which dynamic bootp leases"); | |
3568 | log_error ("can be allocated, please declare it within a"); | |
3569 | log_error ("pool declaration that also contains the \"no"); | |
3570 | log_error ("failover\" statement. The failover protocol"); | |
3571 | log_error ("itself does not permit dynamic bootp - this"); | |
3572 | log_error ("is not a limitation specific to the ISC DHCP"); | |
3573 | log_error ("server. Please don't ask me to defend this"); | |
3574 | log_error ("until you have read and really tried %s", | |
3575 | "to understand"); | |
3576 | log_error ("the failover protocol specification."); | |
3577 | ||
3578 | /* We don't actually bomb at this point - instead, | |
3579 | we let parse_lease_file notice the error and | |
3580 | bomb at that point - it's easier. */ | |
f63b4929 | 3581 | } |
c5261618 | 3582 | #endif /* FAILOVER_PROTOCOL */ |
f63b4929 | 3583 | |
d7837182 | 3584 | /* Create the new address range... */ |
98311e4b | 3585 | new_address_range (cfile, low, high, subnet, pool, lpchain); |
20916cae | 3586 | pool_dereference (&pool, MDL); |
d7837182 TL |
3587 | } |
3588 | ||
fe5b0fdd | 3589 | #ifdef DHCPv6 |
98bd7ca0 DH |
3590 | static void |
3591 | add_ipv6_pool_to_shared_network(struct shared_network *share, | |
3592 | struct iaddr *lo_addr, | |
3593 | int bits) { | |
3594 | struct ipv6_pool *pool; | |
3595 | struct in6_addr tmp_in6_addr; | |
3596 | int num_pools; | |
3597 | struct ipv6_pool **tmp; | |
3598 | ||
3599 | /* | |
3600 | * Create our pool. | |
3601 | */ | |
3602 | if (lo_addr->len != sizeof(tmp_in6_addr)) { | |
3603 | log_fatal("Internal error: Attempt to add non-IPv6 address " | |
3604 | "to IPv6 shared network."); | |
3605 | } | |
3606 | memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr)); | |
3607 | pool = NULL; | |
3608 | if (ipv6_pool_allocate(&pool, &tmp_in6_addr, | |
3609 | bits, MDL) != ISC_R_SUCCESS) { | |
3610 | log_fatal("Out of memory"); | |
3611 | } | |
3612 | ||
3613 | /* | |
3614 | * Add to our global IPv6 pool set. | |
3615 | */ | |
3616 | if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { | |
3617 | log_fatal ("Out of memory"); | |
3618 | } | |
3619 | ||
3620 | /* | |
3621 | * Link our pool to our shared_network. | |
3622 | */ | |
3623 | pool->shared_network = NULL; | |
3624 | shared_network_reference(&pool->shared_network, share, MDL); | |
3625 | ||
3626 | /* | |
3627 | * Increase our array size for ipv6_pools in the shared_network. | |
3628 | */ | |
3629 | if (share->ipv6_pools == NULL) { | |
3630 | num_pools = 0; | |
3631 | } else { | |
3632 | num_pools = 0; | |
3633 | while (share->ipv6_pools[num_pools] != NULL) { | |
3634 | num_pools++; | |
3635 | } | |
3636 | } | |
3637 | tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL); | |
3638 | if (tmp == NULL) { | |
3639 | log_fatal("Out of memory"); | |
3640 | } | |
3641 | if (num_pools > 0) { | |
3642 | memcpy(tmp, share->ipv6_pools, | |
3643 | sizeof(struct ipv6_pool *) * num_pools); | |
3644 | } | |
3645 | if (share->ipv6_pools != NULL) { | |
3646 | dfree(share->ipv6_pools, MDL); | |
3647 | } | |
3648 | share->ipv6_pools = tmp; | |
3649 | ||
3650 | /* | |
3651 | * Record this pool in our array of pools for this shared network. | |
3652 | */ | |
3653 | ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL); | |
3654 | share->ipv6_pools[num_pools+1] = NULL; | |
3655 | } | |
3656 | ||
3657 | /* address-range6-declaration :== ip-address6 ip-address6 SEMI | |
3658 | | ip-address6 SLASH number SEMI */ | |
3659 | ||
3660 | void | |
3661 | parse_address_range6(struct parse *cfile, struct group *group) { | |
3662 | struct iaddr lo, hi; | |
3663 | int bits; | |
3664 | enum dhcp_token token; | |
3665 | const char *val; | |
3666 | struct shared_network *share; | |
3667 | struct iaddrcidrnetlist *nets; | |
3668 | struct iaddrcidrnetlist *p; | |
3669 | ||
3670 | /* | |
3671 | * We'll use the shared_network from our group. | |
3672 | */ | |
3673 | share = group->shared_network; | |
3674 | if (share == NULL) { | |
3675 | share = group->subnet->shared_network; | |
3676 | } | |
3677 | ||
3678 | /* | |
3679 | * Read starting address. | |
3680 | */ | |
3681 | if (!parse_ip6_addr(cfile, &lo)) { | |
3682 | return; | |
3683 | } | |
3684 | ||
3685 | /* | |
3686 | * See if we we're using range or CIDR notation. | |
3687 | */ | |
3688 | token = peek_token(&val, NULL, cfile); | |
3689 | if (token == SLASH) { | |
3690 | /* | |
3691 | * '/' means CIDR notation, so read the bits we want. | |
3692 | */ | |
3693 | next_token(NULL, NULL, cfile); | |
3694 | token = next_token(&val, NULL, cfile); | |
3695 | if (token != NUMBER) { | |
3696 | parse_warn(cfile, "expecting number"); | |
3697 | skip_to_semi(cfile); | |
3698 | return; | |
3699 | } | |
3700 | bits = atoi(val); | |
3701 | if ((bits < 0) || (bits > 128)) { | |
3702 | parse_warn(cfile, "networks have 0 to 128 bits"); | |
3703 | skip_to_semi(cfile); | |
3704 | return; | |
3705 | } | |
3706 | ||
3707 | add_ipv6_pool_to_shared_network(share, &lo, bits); | |
3708 | ||
3709 | } else { | |
3710 | /* | |
3711 | * No '/', so we are looking for the end address of | |
3712 | * the IPv6 pool. | |
3713 | */ | |
3714 | if (!parse_ip6_addr(cfile, &hi)) { | |
3715 | return; | |
3716 | } | |
3717 | ||
3718 | /* | |
3719 | * Convert our range to a set of CIDR networks. | |
3720 | */ | |
3721 | nets = NULL; | |
3722 | if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) { | |
3723 | log_fatal("Error converting range to CIDR networks"); | |
3724 | } | |
3725 | ||
3726 | for (p=nets; p != NULL; p=p->next) { | |
3727 | add_ipv6_pool_to_shared_network(share, | |
3728 | &p->cidrnet.lo_addr, | |
3729 | p->cidrnet.bits); | |
3730 | } | |
3731 | ||
3732 | free_iaddrcidrnetlist(&nets); | |
3733 | ||
3734 | } | |
3735 | ||
3736 | token = next_token(NULL, NULL, cfile); | |
3737 | if (token != SEMI) { | |
3738 | parse_warn(cfile, "semicolon expected."); | |
3739 | skip_to_semi(cfile); | |
3740 | return; | |
3741 | } | |
3742 | } | |
fe5b0fdd | 3743 | #endif /* DHCPv6 */ |
98bd7ca0 | 3744 | |
c358155d TL |
3745 | /* allow-deny-keyword :== BOOTP |
3746 | | BOOTING | |
3747 | | DYNAMIC_BOOTP | |
1db5e2c0 | 3748 | | UNKNOWN_CLIENTS */ |
c358155d TL |
3749 | |
3750 | int parse_allow_deny (oc, cfile, flag) | |
3751 | struct option_cache **oc; | |
3752 | struct parse *cfile; | |
3753 | int flag; | |
3754 | { | |
3755 | enum dhcp_token token; | |
3756 | const char *val; | |
3757 | unsigned char rf = flag; | |
f7fdb216 DH |
3758 | unsigned code; |
3759 | struct option *option = NULL; | |
c358155d TL |
3760 | struct expression *data = (struct expression *)0; |
3761 | int status; | |
3762 | ||
d758ad8c | 3763 | if (!make_const_data (&data, &rf, 1, 0, 1, MDL)) |
c358155d TL |
3764 | return 0; |
3765 | ||
b3519f23 | 3766 | token = next_token (&val, (unsigned *)0, cfile); |
c358155d | 3767 | switch (token) { |
007e3ee4 | 3768 | case TOKEN_BOOTP: |
f7fdb216 | 3769 | code = SV_ALLOW_BOOTP; |
c358155d TL |
3770 | break; |
3771 | ||
3772 | case BOOTING: | |
f7fdb216 | 3773 | code = SV_ALLOW_BOOTING; |
c358155d TL |
3774 | break; |
3775 | ||
3776 | case DYNAMIC_BOOTP: | |
f7fdb216 | 3777 | code = SV_DYNAMIC_BOOTP; |
c358155d TL |
3778 | break; |
3779 | ||
3780 | case UNKNOWN_CLIENTS: | |
f7fdb216 | 3781 | code = SV_BOOT_UNKNOWN_CLIENTS; |
c358155d TL |
3782 | break; |
3783 | ||
3784 | case DUPLICATES: | |
f7fdb216 | 3785 | code = SV_DUPLICATES; |
c358155d TL |
3786 | break; |
3787 | ||
3788 | case DECLINES: | |
f7fdb216 | 3789 | code= SV_DECLINES; |
c358155d TL |
3790 | break; |
3791 | ||
6fdcc1a0 | 3792 | case CLIENT_UPDATES: |
f7fdb216 | 3793 | code = SV_CLIENT_UPDATES; |
6fdcc1a0 TL |
3794 | break; |
3795 | ||
6d103865 SK |
3796 | case LEASEQUERY: |
3797 | code = SV_LEASEQUERY; | |
3798 | break; | |
3799 | ||
c358155d TL |
3800 | default: |
3801 | parse_warn (cfile, "expecting allow/deny key"); | |
3802 | skip_to_semi (cfile); | |
3803 | return 0; | |
3804 | } | |
f7fdb216 DH |
3805 | /* Reference on option is passed to option cache. */ |
3806 | if (!option_code_hash_lookup(&option, server_universe.code_hash, | |
3807 | &code, 0, MDL)) | |
3808 | log_fatal("Unable to find server option %u (%s:%d).", | |
3809 | code, MDL); | |
3810 | status = option_cache(oc, NULL, data, option, MDL); | |
d758ad8c | 3811 | expression_dereference (&data, MDL); |
c358155d TL |
3812 | parse_semi (cfile); |
3813 | return status; | |
3814 | } | |
3815 | ||
98bd7ca0 DH |
3816 | void |
3817 | parse_ia_na_declaration(struct parse *cfile) { | |
3818 | enum dhcp_token token; | |
3819 | struct ia_na *ia_na; | |
3820 | const char *val; | |
d9b43370 | 3821 | struct ia_na *old_ia_na; |
98bd7ca0 DH |
3822 | int len; |
3823 | u_int32_t iaid; | |
3824 | struct iaddr iaddr; | |
3825 | binding_state_t state; | |
3826 | TIME end_time; | |
3827 | struct iaaddr *iaaddr; | |
3828 | struct ipv6_pool *pool; | |
3829 | char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; | |
3830 | struct data_string uid; | |
3831 | ||
fe5b0fdd DH |
3832 | #if !defined(DHCPv6) |
3833 | parse_warn(cfile, "No DHCPv6 support."); | |
3834 | skip_to_semi(cfile); | |
3835 | #else /* defined(DHCPv6) */ | |
98bd7ca0 DH |
3836 | token = next_token(&val, &len, cfile); |
3837 | if (token != STRING) { | |
3838 | parse_warn(cfile, "corrupt lease file; " | |
3839 | "expecting an iaid+ia_na string"); | |
3840 | skip_to_semi(cfile); | |
3841 | return; | |
3842 | } | |
3843 | if (len < 5) { | |
3844 | parse_warn(cfile, "corrupt lease file; " | |
3845 | "iaid+ia_na string too short"); | |
3846 | skip_to_semi(cfile); | |
3847 | return; | |
3848 | } | |
3849 | ||
3850 | memcpy(&iaid, val, 4); | |
3851 | ia_na = NULL; | |
3852 | if (ia_na_allocate(&ia_na, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) { | |
3853 | log_fatal("Out of memory."); | |
3854 | } | |
3855 | ||
3856 | token = next_token(&val, NULL, cfile); | |
3857 | if (token != LBRACE) { | |
3858 | parse_warn(cfile, "corrupt lease file; expecting left brace"); | |
3859 | skip_to_semi(cfile); | |
3860 | return; | |
3861 | } | |
3862 | ||
3863 | for (;;) { | |
3864 | token = next_token(&val, NULL, cfile); | |
3865 | if (token == RBRACE) break; | |
3866 | ||
3867 | if (token != IAADDR) { | |
3868 | parse_warn(cfile, "corrupt lease file; " | |
3869 | "expecting IAADDR or right brace"); | |
3870 | skip_to_semi(cfile); | |
3871 | return; | |
3872 | } | |
3873 | ||
3874 | if (!parse_ip6_addr(cfile, &iaddr)) { | |
3875 | parse_warn(cfile, "corrupt lease file; " | |
3876 | "expecting IPv6 address"); | |
3877 | skip_to_semi(cfile); | |
3878 | return; | |
3879 | } | |
3880 | ||
3881 | token = next_token(&val, NULL, cfile); | |
3882 | if (token != LBRACE) { | |
3883 | parse_warn(cfile, "corrupt lease file; " | |
3884 | "expecting left brace"); | |
3885 | skip_to_semi(cfile); | |
3886 | return; | |
3887 | } | |
3888 | ||
3889 | state = FTS_LAST+1; | |
3890 | end_time = -1; | |
3891 | for (;;) { | |
3892 | token = next_token(&val, NULL, cfile); | |
3893 | if (token == RBRACE) break; | |
3894 | ||
3895 | if (token == BINDING) { | |
3896 | token = next_token(&val, NULL, cfile); | |
3897 | if (token != STATE) { | |
3898 | parse_warn(cfile, "corrupt lease file; " | |
3899 | "expecting state"); | |
3900 | skip_to_semi(cfile); | |
3901 | return; | |
3902 | } | |
3903 | token = next_token(&val, NULL, cfile); | |
3904 | switch (token) { | |
3905 | case TOKEN_ABANDONED: | |
3906 | state = FTS_ABANDONED; | |
3907 | break; | |
3908 | case TOKEN_FREE: | |
3909 | state = FTS_FREE; | |
3910 | break; | |
3911 | case TOKEN_ACTIVE: | |
3912 | state = FTS_ACTIVE; | |
3913 | break; | |
3914 | case TOKEN_EXPIRED: | |
3915 | state = FTS_EXPIRED; | |
3916 | break; | |
3917 | case TOKEN_RELEASED: | |
3918 | state = FTS_RELEASED; | |
3919 | break; | |
3920 | default: | |
3921 | parse_warn(cfile, | |
3922 | "corrupt lease " | |
3923 | "file; " | |
3924 | "expecting a " | |
3925 | "binding state."); | |
3926 | skip_to_semi(cfile); | |
3927 | return; | |
3928 | } | |
3929 | ||
3930 | token = next_token(&val, NULL, cfile); | |
3931 | if (token != SEMI) { | |
3932 | parse_warn(cfile, "corrupt lease file; " | |
3933 | "expecting " | |
3934 | "semicolon."); | |
3935 | } | |
3936 | ||
3937 | } else if (token == ENDS) { | |
3938 | end_time = parse_date(cfile); | |
3939 | } else { | |
3940 | parse_warn(cfile, "corrupt lease file; " | |
3941 | "expecting binding or ends, " | |
3942 | "got '%s'", val); | |
3943 | skip_to_semi(cfile); | |
3944 | return; | |
3945 | } | |
3946 | } | |
3947 | ||
3948 | if (state == FTS_LAST+1) { | |
3949 | parse_warn(cfile, "corrupt lease file; " | |
3950 | "missing state in iaaddr"); | |
3951 | return; | |
3952 | } | |
3953 | if (end_time == -1) { | |
3954 | parse_warn(cfile, "corrupt lease file; " | |
3955 | "missing end time in iaaddr"); | |
3956 | return; | |
3957 | } | |
3958 | ||
3959 | iaaddr = NULL; | |
3960 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
3961 | log_fatal("Out of memory."); | |
3962 | } | |
3963 | memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr)); | |
3964 | iaaddr->state = state; | |
3965 | iaaddr->valid_lifetime_end_time = end_time; | |
3966 | ||
3967 | /* add to our various structures */ | |
3968 | ia_na_add_iaaddr(ia_na, iaaddr, MDL); | |
3969 | pool = NULL; | |
3970 | if (find_ipv6_pool(&pool, &iaaddr->addr) != ISC_R_SUCCESS) { | |
3971 | inet_ntop(AF_INET6, &iaaddr->addr, | |
3972 | addr_buf, sizeof(addr_buf)); | |
3973 | parse_warn(cfile, "no pool found for address %s", | |
3974 | addr_buf); | |
3975 | return; | |
3976 | } | |
3977 | add_lease6(pool, iaaddr, end_time); | |
3978 | switch (state) { | |
3979 | case FTS_ABANDONED: | |
d9b43370 | 3980 | release_lease6(pool, iaaddr); |
98bd7ca0 DH |
3981 | break; |
3982 | case FTS_EXPIRED: | |
3983 | decline_lease6(pool, iaaddr); | |
3984 | iaaddr->state = FTS_EXPIRED; | |
3985 | break; | |
3986 | case FTS_RELEASED: | |
d9b43370 | 3987 | release_lease6(pool, iaaddr); |
98bd7ca0 DH |
3988 | break; |
3989 | } | |
3990 | ipv6_pool_dereference(&pool, MDL); | |
3991 | iaaddr_dereference(&iaaddr, MDL); | |
3992 | } | |
3993 | ||
d9b43370 SK |
3994 | /* |
3995 | * If we have an existing record for this IA_NA, remove it. | |
3996 | */ | |
3997 | old_ia_na = NULL; | |
3998 | if (ia_na_hash_lookup(&old_ia_na, ia_active, | |
3999 | (char *)ia_na->iaid_duid.data, | |
4000 | ia_na->iaid_duid.len, MDL)) { | |
4001 | ia_na_hash_delete(ia_active, | |
4002 | (char *)ia_na->iaid_duid.data, | |
4003 | ia_na->iaid_duid.len, MDL); | |
4004 | ia_na_remove_all_iaaddr(old_ia_na, MDL); | |
4005 | ia_na_dereference(&old_ia_na, MDL); | |
4006 | } | |
4007 | ||
4008 | /* | |
4009 | * If we have addresses, add this, otherwise don't bother. | |
4010 | */ | |
4011 | if (ia_na->num_iaaddr > 0) { | |
4012 | ia_na_hash_add(ia_active, (char *)ia_na->iaid_duid.data, | |
4013 | ia_na->iaid_duid.len, ia_na, MDL); | |
4014 | } | |
4015 | ia_na_dereference(&ia_na, MDL); | |
fe5b0fdd | 4016 | #endif /* defined(DHCPv6) */ |
98bd7ca0 DH |
4017 | } |
4018 | ||
fe5b0fdd | 4019 | #ifdef DHCPv6 |
98bd7ca0 DH |
4020 | /* |
4021 | * When we parse a server-duid statement in a lease file, we are | |
4022 | * looking at the saved server DUID from a previous run. In this case | |
4023 | * we expect it to be followed by the binary representation of the | |
4024 | * DUID stored in a string: | |
4025 | * | |
4026 | * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y"; | |
4027 | */ | |
4028 | void | |
4029 | parse_server_duid(struct parse *cfile) { | |
4030 | enum dhcp_token token; | |
4031 | const char *val; | |
4032 | int len; | |
4033 | struct data_string duid; | |
4034 | ||
4035 | token = next_token(&val, &len, cfile); | |
4036 | if (token != STRING) { | |
4037 | parse_warn(cfile, "corrupt lease file; expecting a DUID"); | |
4038 | skip_to_semi(cfile); | |
4039 | return; | |
4040 | } | |
4041 | ||
4042 | memset(&duid, 0, sizeof(duid)); | |
4043 | duid.len = len; | |
4044 | if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { | |
4045 | log_fatal("Out of memory storing DUID"); | |
4046 | } | |
4047 | duid.data = (char *)duid.buffer->data; | |
4048 | memcpy(duid.buffer->data, val, len); | |
4049 | ||
4050 | set_server_duid(&duid); | |
4051 | ||
4052 | data_string_forget(&duid, MDL); | |
4053 | ||
4054 | token = next_token(&val, &len, cfile); | |
4055 | if (token != SEMI) { | |
4056 | parse_warn(cfile, "corrupt lease file; expecting a semicolon"); | |
4057 | skip_to_semi(cfile); | |
4058 | return; | |
4059 | } | |
4060 | } | |
4061 | ||
4062 | /* | |
4063 | * When we parse a server-duid statement in a config file, we will | |
4064 | * have the type of the server DUID to generate, and possibly the | |
4065 | * actual value defined. | |
4066 | * | |
4067 | * server-duid llt; | |
4068 | * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B; | |
4069 | * server-duid ll; | |
4070 | * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B; | |
4071 | * server-duid en 2495 "enterprise-specific-identifer-1234"; | |
4072 | */ | |
4073 | void | |
4074 | parse_server_duid_conf(struct parse *cfile) { | |
4075 | enum dhcp_token token; | |
4076 | const char *val; | |
4077 | int len; | |
4078 | u_int32_t enterprise_number; | |
4079 | int ll_type; | |
4080 | struct data_string ll_addr; | |
4081 | u_int32_t llt_time; | |
4082 | struct data_string duid; | |
4083 | int duid_type_num; | |
4084 | ||
4085 | /* | |
4086 | * Consume the SERVER_DUID token. | |
4087 | */ | |
4088 | token = next_token(NULL, NULL, cfile); | |
4089 | ||
4090 | /* | |
4091 | * Obtain the DUID type. | |
4092 | */ | |
4093 | token = next_token(&val, NULL, cfile); | |
4094 | ||
4095 | /* | |
4096 | * Enterprise is the easiest - enterprise number and raw data | |
4097 | * are required. | |
4098 | */ | |
4099 | if (token == EN) { | |
4100 | /* | |
4101 | * Get enterprise number and identifier. | |
4102 | */ | |
4103 | token = next_token(&val, NULL, cfile); | |
4104 | if (token != NUMBER) { | |
4105 | parse_warn(cfile, "enterprise number expected"); | |
4106 | skip_to_semi(cfile); | |
4107 | return; | |
4108 | } | |
4109 | enterprise_number = atoi(val); | |
4110 | ||
4111 | token = next_token(&val, &len, cfile); | |
4112 | if (token != STRING) { | |
4113 | parse_warn(cfile, "identifier expected"); | |
4114 | skip_to_semi(cfile); | |
4115 | return; | |
4116 | } | |
4117 | ||
4118 | /* | |
4119 | * Save the DUID. | |
4120 | */ | |
4121 | memset(&duid, 0, sizeof(duid)); | |
4122 | duid.len = 2 + 4 + len; | |
4123 | if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { | |
4124 | log_fatal("Out of memory storing DUID"); | |
4125 | } | |
4126 | duid.data = (char *)duid.buffer->data; | |
4127 | putUShort(duid.buffer->data, DUID_EN); | |
4128 | putULong(duid.buffer->data + 2, enterprise_number); | |
4129 | memcpy(duid.buffer->data + 6, val, len); | |
4130 | ||
4131 | set_server_duid(&duid); | |
4132 | data_string_forget(&duid, MDL); | |
4133 | } | |
4134 | ||
4135 | /* | |
4136 | * Next easiest is the link-layer DUID. It consists only of | |
4137 | * the LL directive, or optionally the specific value to use. | |
4138 | * | |
4139 | * If we have LL only, then we set the type. If we have the | |
4140 | * value, then we set the actual DUID. | |
4141 | */ | |
4142 | else if (token == LL) { | |
4143 | if (peek_token(NULL, NULL, cfile) == SEMI) { | |
4144 | set_server_duid_type(DUID_LL); | |
4145 | } else { | |
4146 | /* | |
4147 | * Get our hardware type and address. | |
4148 | */ | |
4149 | token = next_token(NULL, NULL, cfile); | |
4150 | switch (token) { | |
4151 | case ETHERNET: | |
4152 | ll_type = HTYPE_ETHER; | |
4153 | break; | |
4154 | case TOKEN_RING: | |
4155 | ll_type = HTYPE_IEEE802; | |
4156 | break; | |
4157 | case FDDI: | |
4158 | ll_type = HTYPE_FDDI; | |
4159 | break; | |
4160 | default: | |
4161 | parse_warn(cfile, "hardware type expected"); | |
4162 | skip_to_semi(cfile); | |
4163 | return; | |
4164 | } | |
4165 | memset(&ll_addr, 0, sizeof(ll_addr)); | |
4166 | if (!parse_cshl(&ll_addr, cfile)) { | |
4167 | return; | |
4168 | } | |
4169 | ||
4170 | /* | |
4171 | * Save the DUID. | |
4172 | */ | |
4173 | memset(&duid, 0, sizeof(duid)); | |
4174 | duid.len = 2 + 2 + ll_addr.len; | |
4175 | if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { | |
4176 | log_fatal("Out of memory storing DUID"); | |
4177 | } | |
4178 | duid.data = (char *)duid.buffer->data; | |
4179 | putUShort(duid.buffer->data, DUID_LL); | |
4180 | putULong(duid.buffer->data + 2, ll_type); | |
4181 | memcpy(duid.buffer->data + 4, | |
4182 | ll_addr.data, ll_addr.len); | |
4183 | ||
4184 | set_server_duid(&duid); | |
4185 | data_string_forget(&duid, MDL); | |
4186 | data_string_forget(&ll_addr, MDL); | |
4187 | } | |
4188 | } | |
4189 | ||
4190 | /* | |
4191 | * Finally the link-layer DUID plus time. It consists only of | |
4192 | * the LLT directive, or optionally the specific value to use. | |
4193 | * | |
4194 | * If we have LLT only, then we set the type. If we have the | |
4195 | * value, then we set the actual DUID. | |
4196 | */ | |
4197 | else if (token == LLT) { | |
4198 | if (peek_token(NULL, NULL, cfile) == SEMI) { | |
4199 | set_server_duid_type(DUID_LLT); | |
4200 | } else { | |
4201 | /* | |
4202 | * Get our hardware type, timestamp, and address. | |
4203 | */ | |
4204 | token = next_token(NULL, NULL, cfile); | |
4205 | switch (token) { | |
4206 | case ETHERNET: | |
4207 | ll_type = HTYPE_ETHER; | |
4208 | break; | |
4209 | case TOKEN_RING: | |
4210 | ll_type = HTYPE_IEEE802; | |
4211 | break; | |
4212 | case FDDI: | |
4213 | ll_type = HTYPE_FDDI; | |
4214 | break; | |
4215 | default: | |
4216 | parse_warn(cfile, "hardware type expected"); | |
4217 | skip_to_semi(cfile); | |
4218 | return; | |
4219 | } | |
4220 | ||
4221 | token = next_token(&val, NULL, cfile); | |
4222 | if (token != NUMBER) { | |
4223 | parse_warn(cfile, "timestamp expected"); | |
4224 | skip_to_semi(cfile); | |
4225 | return; | |
4226 | } | |
4227 | llt_time = atoi(val); | |
4228 | ||
4229 | memset(&ll_addr, 0, sizeof(ll_addr)); | |
4230 | if (!parse_cshl(&ll_addr, cfile)) { | |
4231 | return; | |
4232 | } | |
4233 | ||
4234 | /* | |
4235 | * Save the DUID. | |
4236 | */ | |
4237 | memset(&duid, 0, sizeof(duid)); | |
4238 | duid.len = 2 + 2 + 4 + ll_addr.len; | |
4239 | if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { | |
4240 | log_fatal("Out of memory storing DUID"); | |
4241 | } | |
4242 | duid.data = (char *)duid.buffer->data; | |
4243 | putUShort(duid.buffer->data, DUID_LLT); | |
4244 | putULong(duid.buffer->data + 2, ll_type); | |
4245 | putULong(duid.buffer->data + 4, llt_time); | |
4246 | memcpy(duid.buffer->data + 8, | |
4247 | ll_addr.data, ll_addr.len); | |
4248 | ||
4249 | set_server_duid(&duid); | |
4250 | data_string_forget(&duid, MDL); | |
4251 | data_string_forget(&ll_addr, MDL); | |
4252 | } | |
4253 | } | |
4254 | ||
4255 | /* | |
4256 | * If users want they can use a number for DUID types. | |
4257 | * This is useful for supporting future, not-yet-defined | |
4258 | * DUID types. | |
4259 | * | |
4260 | * In this case, they have to put in the complete value. | |
4261 | * | |
4262 | * This also works for existing DUID types of course. | |
4263 | */ | |
4264 | else if (token == NUMBER) { | |
4265 | duid_type_num = atoi(val); | |
4266 | ||
4267 | token = next_token(&val, &len, cfile); | |
4268 | if (token != STRING) { | |
4269 | parse_warn(cfile, "identifier expected"); | |
4270 | skip_to_semi(cfile); | |
4271 | return; | |
4272 | } | |
4273 | ||
4274 | /* | |
4275 | * Save the DUID. | |
4276 | */ | |
4277 | memset(&duid, 0, sizeof(duid)); | |
4278 | duid.len = 2 + len; | |
4279 | if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { | |
4280 | log_fatal("Out of memory storing DUID"); | |
4281 | } | |
4282 | duid.data = (char *)duid.buffer->data; | |
4283 | putUShort(duid.buffer->data, duid_type_num); | |
4284 | memcpy(duid.buffer->data + 2, val, len); | |
4285 | ||
4286 | set_server_duid(&duid); | |
4287 | data_string_forget(&duid, MDL); | |
4288 | } | |
4289 | ||
4290 | /* | |
4291 | * Anything else is an error. | |
4292 | */ | |
4293 | else { | |
4294 | parse_warn(cfile, "DUID type of LLT, EN, or LL expected"); | |
4295 | skip_to_semi(cfile); | |
4296 | return; | |
4297 | } | |
4298 | ||
4299 | /* | |
4300 | * Finally consume our trailing semicolon. | |
4301 | */ | |
4302 | token = next_token(NULL, NULL, cfile); | |
4303 | if (token != SEMI) { | |
4304 | parse_warn(cfile, "semicolon expected"); | |
4305 | skip_to_semi(cfile); | |
4306 | } | |
4307 | } | |
fe5b0fdd DH |
4308 | |
4309 | #endif /* DHCPv6 */ | |
4310 |