clparse.c revision 1.3 1 1.2 christos /* $NetBSD: clparse.c,v 1.3 2020/08/03 21:10:56 christos Exp $ */
2 1.1 christos
3 1.1 christos /* clparse.c
4 1.1 christos
5 1.1 christos Parser for dhclient config and lease files... */
6 1.1 christos
7 1.1 christos /*
8 1.3 christos * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC")
9 1.1 christos * Copyright (c) 1996-2003 by Internet Software Consortium
10 1.1 christos *
11 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public
12 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this
13 1.1 christos * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 1.1 christos *
15 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 1.1 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 1.1 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 1.1 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 1.1 christos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 1.1 christos *
23 1.1 christos * Internet Systems Consortium, Inc.
24 1.1 christos * 950 Charter Street
25 1.1 christos * Redwood City, CA 94063
26 1.1 christos * <info (at) isc.org>
27 1.1 christos * https://www.isc.org/
28 1.1 christos *
29 1.1 christos */
30 1.1 christos
31 1.1 christos #include <sys/cdefs.h>
32 1.2 christos __RCSID("$NetBSD: clparse.c,v 1.3 2020/08/03 21:10:56 christos Exp $");
33 1.1 christos
34 1.1 christos #include "dhcpd.h"
35 1.1 christos #include <errno.h>
36 1.1 christos
37 1.1 christos struct client_config top_level_config;
38 1.1 christos
39 1.1 christos #define NUM_DEFAULT_REQUESTED_OPTS 9
40 1.1 christos /* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
41 1.1 christos struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
42 1.1 christos
43 1.1 christos static void parse_client_default_duid(struct parse *cfile);
44 1.1 christos static void parse_client6_lease_statement(struct parse *cfile);
45 1.1 christos #ifdef DHCPv6
46 1.1 christos static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
47 1.1 christos static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
48 1.1 christos static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
49 1.1 christos static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
50 1.1 christos static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
51 1.1 christos #endif /* DHCPv6 */
52 1.1 christos
53 1.1 christos static void parse_lease_id_format (struct parse *cfile);
54 1.1 christos
55 1.3 christos extern void discard_duplicate (struct client_lease** lease_list,
56 1.3 christos struct client_lease* lease);
57 1.3 christos
58 1.1 christos /* client-conf-file :== client-declarations END_OF_FILE
59 1.1 christos client-declarations :== <nil>
60 1.1 christos | client-declaration
61 1.1 christos | client-declarations client-declaration */
62 1.1 christos
63 1.1 christos isc_result_t read_client_conf ()
64 1.1 christos {
65 1.1 christos struct client_config *config;
66 1.1 christos struct interface_info *ip;
67 1.1 christos isc_result_t status;
68 1.1 christos unsigned code;
69 1.1 christos
70 1.1 christos /*
71 1.1 christos * TODO: LATER constant is very undescriptive. We should review it and
72 1.1 christos * change it to something more descriptive or even better remove it
73 1.1 christos * completely as it is currently not used.
74 1.1 christos */
75 1.1 christos #ifdef LATER
76 1.1 christos struct parse *parse = NULL;
77 1.1 christos #endif
78 1.1 christos
79 1.1 christos /* Initialize the default request list. */
80 1.1 christos memset(default_requested_options, 0, sizeof(default_requested_options));
81 1.1 christos
82 1.1 christos /* 1 */
83 1.1 christos code = DHO_SUBNET_MASK;
84 1.1 christos option_code_hash_lookup(&default_requested_options[0],
85 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
86 1.1 christos
87 1.1 christos /* 2 */
88 1.1 christos code = DHO_BROADCAST_ADDRESS;
89 1.1 christos option_code_hash_lookup(&default_requested_options[1],
90 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
91 1.1 christos
92 1.1 christos /* 3 */
93 1.1 christos code = DHO_TIME_OFFSET;
94 1.1 christos option_code_hash_lookup(&default_requested_options[2],
95 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
96 1.1 christos
97 1.1 christos /* 4 */
98 1.1 christos code = DHO_ROUTERS;
99 1.1 christos option_code_hash_lookup(&default_requested_options[3],
100 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
101 1.1 christos
102 1.1 christos /* 5 */
103 1.1 christos code = DHO_DOMAIN_NAME;
104 1.1 christos option_code_hash_lookup(&default_requested_options[4],
105 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
106 1.1 christos
107 1.1 christos /* 6 */
108 1.1 christos code = DHO_DOMAIN_NAME_SERVERS;
109 1.1 christos option_code_hash_lookup(&default_requested_options[5],
110 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
111 1.1 christos
112 1.1 christos /* 7 */
113 1.1 christos code = DHO_HOST_NAME;
114 1.1 christos option_code_hash_lookup(&default_requested_options[6],
115 1.1 christos dhcp_universe.code_hash, &code, 0, MDL);
116 1.1 christos
117 1.1 christos /* 8 */
118 1.1 christos code = D6O_NAME_SERVERS;
119 1.1 christos option_code_hash_lookup(&default_requested_options[7],
120 1.1 christos dhcpv6_universe.code_hash, &code, 0, MDL);
121 1.1 christos
122 1.1 christos /* 9 */
123 1.1 christos code = D6O_DOMAIN_SEARCH;
124 1.1 christos option_code_hash_lookup(&default_requested_options[8],
125 1.1 christos dhcpv6_universe.code_hash, &code, 0, MDL);
126 1.1 christos
127 1.1 christos for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
128 1.1 christos if (default_requested_options[code] == NULL)
129 1.1 christos log_fatal("Unable to find option definition for "
130 1.1 christos "index %u during default parameter request "
131 1.1 christos "assembly.", code);
132 1.1 christos }
133 1.1 christos
134 1.1 christos #ifdef DHCP4o6
135 1.1 christos /* DHCPv4-over-DHCPv6 extra requested options in code order */
136 1.1 christos if (dhcpv4_over_dhcpv6 == 1) {
137 1.1 christos /* The DHCP4o6 server option should be requested */
138 1.1 christos code = D6O_DHCP4_O_DHCP6_SERVER;
139 1.1 christos option_code_hash_lookup(&default_requested_options[9],
140 1.1 christos dhcpv6_universe.code_hash,
141 1.1 christos &code, 0, MDL);
142 1.1 christos if (default_requested_options[9] == NULL) {
143 1.1 christos log_fatal("Unable to find option definition for "
144 1.1 christos "index %u during default parameter request "
145 1.1 christos "assembly.", code);
146 1.1 christos }
147 1.1 christos } else if (dhcpv4_over_dhcpv6 > 1) {
148 1.1 christos /* Called from run_stateless so the IRT should
149 1.1 christos be requested too */
150 1.1 christos code = D6O_INFORMATION_REFRESH_TIME;
151 1.1 christos option_code_hash_lookup(&default_requested_options[9],
152 1.1 christos dhcpv6_universe.code_hash,
153 1.1 christos &code, 0, MDL);
154 1.1 christos if (default_requested_options[9] == NULL) {
155 1.1 christos log_fatal("Unable to find option definition for "
156 1.1 christos "index %u during default parameter request "
157 1.1 christos "assembly.", code);
158 1.1 christos }
159 1.1 christos code = D6O_DHCP4_O_DHCP6_SERVER;
160 1.1 christos option_code_hash_lookup(&default_requested_options[10],
161 1.1 christos dhcpv6_universe.code_hash,
162 1.1 christos &code, 0, MDL);
163 1.1 christos if (default_requested_options[10] == NULL) {
164 1.1 christos log_fatal("Unable to find option definition for "
165 1.1 christos "index %u during default parameter request "
166 1.1 christos "assembly.", code);
167 1.1 christos }
168 1.1 christos }
169 1.1 christos #endif
170 1.1 christos
171 1.1 christos /* Initialize the top level client configuration. */
172 1.1 christos memset (&top_level_config, 0, sizeof top_level_config);
173 1.1 christos
174 1.1 christos /* Set some defaults... */
175 1.1 christos top_level_config.timeout = 60;
176 1.1 christos top_level_config.select_interval = 0;
177 1.1 christos top_level_config.reboot_timeout = 10;
178 1.1 christos top_level_config.retry_interval = 300;
179 1.1 christos top_level_config.backoff_cutoff = 15;
180 1.1 christos top_level_config.initial_interval = 3;
181 1.1 christos top_level_config.lease_id_format = TOKEN_OCTAL;
182 1.1 christos
183 1.1 christos /*
184 1.1 christos * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
185 1.1 christos * random time between 1 and 10 seconds. However, we choose to not
186 1.1 christos * implement this default. If user is inclined to really have that
187 1.1 christos * delay, he is welcome to do so, using 'initial-delay X;' parameter
188 1.1 christos * in config file.
189 1.1 christos */
190 1.1 christos top_level_config.initial_delay = 0;
191 1.1 christos
192 1.1 christos top_level_config.bootp_policy = P_ACCEPT;
193 1.1 christos top_level_config.script_name = path_dhclient_script;
194 1.1 christos top_level_config.requested_options = default_requested_options;
195 1.1 christos top_level_config.omapi_port = -1;
196 1.1 christos top_level_config.do_forward_update = 1;
197 1.1 christos /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
198 1.1 christos */
199 1.1 christos top_level_config.requested_lease = 7200;
200 1.1 christos
201 1.1 christos group_allocate (&top_level_config.on_receipt, MDL);
202 1.1 christos if (!top_level_config.on_receipt)
203 1.1 christos log_fatal ("no memory for top-level on_receipt group");
204 1.1 christos
205 1.1 christos group_allocate (&top_level_config.on_transmission, MDL);
206 1.1 christos if (!top_level_config.on_transmission)
207 1.1 christos log_fatal ("no memory for top-level on_transmission group");
208 1.1 christos
209 1.1 christos status = read_client_conf_file (path_dhclient_conf,
210 1.1 christos (struct interface_info *)0,
211 1.1 christos &top_level_config);
212 1.1 christos
213 1.1 christos if (status != ISC_R_SUCCESS) {
214 1.1 christos ;
215 1.1 christos #ifdef LATER
216 1.1 christos /* Set up the standard name service updater routine. */
217 1.1 christos status = new_parse(&parse, -1, default_client_config,
218 1.1 christos sizeof(default_client_config) - 1,
219 1.1 christos "default client configuration", 0);
220 1.1 christos if (status != ISC_R_SUCCESS)
221 1.1 christos log_fatal ("can't begin default client config!");
222 1.1 christos }
223 1.1 christos
224 1.1 christos if (parse != NULL) {
225 1.1 christos do {
226 1.1 christos token = peek_token(&val, NULL, cfile);
227 1.1 christos if (token == END_OF_FILE)
228 1.1 christos break;
229 1.1 christos parse_client_statement(cfile, NULL, &top_level_config);
230 1.1 christos } while (1);
231 1.1 christos end_parse(&parse);
232 1.1 christos #endif
233 1.1 christos }
234 1.1 christos
235 1.1 christos /* Set up state and config structures for clients that don't
236 1.1 christos have per-interface configuration statements. */
237 1.1 christos config = (struct client_config *)0;
238 1.1 christos for (ip = interfaces; ip; ip = ip -> next) {
239 1.1 christos if (!ip -> client) {
240 1.1 christos ip -> client = (struct client_state *)
241 1.1 christos dmalloc (sizeof (struct client_state), MDL);
242 1.1 christos if (!ip -> client)
243 1.1 christos log_fatal ("no memory for client state.");
244 1.1 christos memset (ip -> client, 0, sizeof *(ip -> client));
245 1.1 christos ip -> client -> interface = ip;
246 1.1 christos }
247 1.1 christos
248 1.1 christos if (!ip -> client -> config) {
249 1.1 christos if (!config) {
250 1.1 christos config = (struct client_config *)
251 1.1 christos dmalloc (sizeof (struct client_config),
252 1.1 christos MDL);
253 1.1 christos if (!config)
254 1.1 christos log_fatal ("no memory for client config.");
255 1.1 christos memcpy (config, &top_level_config,
256 1.1 christos sizeof top_level_config);
257 1.1 christos }
258 1.1 christos ip -> client -> config = config;
259 1.1 christos }
260 1.1 christos }
261 1.1 christos return status;
262 1.1 christos }
263 1.1 christos
264 1.1 christos int read_client_conf_file (const char *name, struct interface_info *ip,
265 1.1 christos struct client_config *client)
266 1.1 christos {
267 1.1 christos int file;
268 1.1 christos struct parse *cfile;
269 1.1 christos const char *val;
270 1.1 christos int token;
271 1.1 christos isc_result_t status;
272 1.1 christos
273 1.1 christos if ((file = open (name, O_RDONLY)) < 0)
274 1.1 christos return uerr2isc (errno);
275 1.1 christos
276 1.1 christos cfile = NULL;
277 1.1 christos status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
278 1.1 christos if (status != ISC_R_SUCCESS || cfile == NULL)
279 1.1 christos return status;
280 1.1 christos
281 1.1 christos do {
282 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
283 1.1 christos if (token == END_OF_FILE)
284 1.1 christos break;
285 1.1 christos parse_client_statement (cfile, ip, client);
286 1.1 christos } while (1);
287 1.1 christos skip_token(&val, (unsigned *)0, cfile);
288 1.1 christos status = (cfile -> warnings_occurred
289 1.1 christos ? DHCP_R_BADPARSE
290 1.1 christos : ISC_R_SUCCESS);
291 1.1 christos end_parse (&cfile);
292 1.1 christos return status;
293 1.1 christos }
294 1.1 christos
295 1.1 christos
296 1.1 christos /* lease-file :== client-lease-statements END_OF_FILE
297 1.1 christos client-lease-statements :== <nil>
298 1.1 christos | client-lease-statements LEASE client-lease-statement
299 1.1 christos * This routine looks through a lease file and only tries to parse
300 1.1 christos * the duid statements.
301 1.1 christos */
302 1.1 christos
303 1.1 christos void read_client_duid ()
304 1.1 christos {
305 1.1 christos int file;
306 1.1 christos isc_result_t status;
307 1.1 christos struct parse *cfile;
308 1.1 christos const char *val;
309 1.1 christos int token;
310 1.1 christos
311 1.1 christos /* Open the lease file. If we can't open it, just return -
312 1.1 christos we can safely trust the server to remember our state. */
313 1.1 christos if ((file = open (path_dhclient_duid, O_RDONLY)) < 0)
314 1.1 christos return;
315 1.1 christos
316 1.1 christos cfile = NULL;
317 1.1 christos status = new_parse(&cfile, file, NULL, 0, path_dhclient_duid, 0);
318 1.1 christos if (status != ISC_R_SUCCESS || cfile == NULL)
319 1.1 christos return;
320 1.1 christos
321 1.1 christos while ((token = next_token(&val, NULL, cfile)) != END_OF_FILE) {
322 1.1 christos /*
323 1.1 christos * All we care about is DUIDs - if we get anything else
324 1.1 christos * just toss it and continue looking for DUIDs until we
325 1.1 christos * run out of file.
326 1.1 christos */
327 1.1 christos if (token == DEFAULT_DUID) {
328 1.1 christos parse_client_default_duid(cfile);
329 1.1 christos }
330 1.1 christos }
331 1.1 christos
332 1.1 christos end_parse(&cfile);
333 1.1 christos }
334 1.1 christos
335 1.1 christos /* lease-file :== client-lease-statements END_OF_FILE
336 1.1 christos client-lease-statements :== <nil>
337 1.1 christos | client-lease-statements LEASE client-lease-statement */
338 1.1 christos
339 1.1 christos void read_client_leases ()
340 1.1 christos {
341 1.1 christos int file;
342 1.1 christos isc_result_t status;
343 1.1 christos struct parse *cfile;
344 1.1 christos const char *val;
345 1.1 christos int token;
346 1.1 christos
347 1.1 christos /* Open the lease file. If we can't open it, just return -
348 1.1 christos we can safely trust the server to remember our state. */
349 1.1 christos if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
350 1.1 christos return;
351 1.1 christos
352 1.1 christos cfile = NULL;
353 1.1 christos status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
354 1.1 christos if (status != ISC_R_SUCCESS || cfile == NULL)
355 1.1 christos return;
356 1.1 christos
357 1.1 christos do {
358 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
359 1.1 christos if (token == END_OF_FILE)
360 1.1 christos break;
361 1.1 christos
362 1.1 christos switch (token) {
363 1.1 christos case DEFAULT_DUID:
364 1.1 christos parse_client_default_duid(cfile);
365 1.1 christos break;
366 1.1 christos
367 1.1 christos case LEASE:
368 1.1 christos parse_client_lease_statement(cfile, 0);
369 1.1 christos break;
370 1.1 christos
371 1.1 christos case LEASE6:
372 1.1 christos parse_client6_lease_statement(cfile);
373 1.1 christos break;
374 1.1 christos
375 1.1 christos default:
376 1.1 christos log_error ("Corrupt lease file - possible data loss!");
377 1.1 christos skip_to_semi (cfile);
378 1.1 christos break;
379 1.1 christos }
380 1.1 christos } while (1);
381 1.1 christos
382 1.1 christos end_parse (&cfile);
383 1.1 christos }
384 1.1 christos
385 1.1 christos /* client-declaration :==
386 1.1 christos SEND option-decl |
387 1.1 christos DEFAULT option-decl |
388 1.1 christos SUPERSEDE option-decl |
389 1.1 christos PREPEND option-decl |
390 1.1 christos APPEND option-decl |
391 1.1 christos hardware-declaration |
392 1.1 christos ALSO REQUEST option-list |
393 1.1 christos ALSO REQUIRE option-list |
394 1.1 christos REQUEST option-list |
395 1.1 christos REQUIRE option-list |
396 1.1 christos TIMEOUT number |
397 1.1 christos RETRY number |
398 1.1 christos REBOOT number |
399 1.1 christos SELECT_TIMEOUT number |
400 1.1 christos SCRIPT string |
401 1.1 christos VENDOR_SPACE string |
402 1.1 christos interface-declaration |
403 1.1 christos LEASE client-lease-statement |
404 1.1 christos ALIAS client-lease-statement |
405 1.1 christos KEY key-definition */
406 1.1 christos
407 1.1 christos void parse_client_statement (cfile, ip, config)
408 1.1 christos struct parse *cfile;
409 1.1 christos struct interface_info *ip;
410 1.1 christos struct client_config *config;
411 1.1 christos {
412 1.1 christos int token;
413 1.1 christos const char *val;
414 1.1 christos struct option *option = NULL;
415 1.1 christos struct executable_statement *stmt;
416 1.1 christos int lose;
417 1.1 christos char *name;
418 1.1 christos enum policy policy;
419 1.1 christos int known;
420 1.1 christos int tmp, i;
421 1.1 christos isc_result_t status;
422 1.1 christos struct option ***append_list, **new_list, **cat_list;
423 1.1 christos
424 1.1 christos switch (peek_token (&val, (unsigned *)0, cfile)) {
425 1.1 christos case INCLUDE:
426 1.1 christos skip_token(&val, (unsigned *)0, cfile);
427 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
428 1.1 christos if (token != STRING) {
429 1.1 christos parse_warn (cfile, "filename string expected.");
430 1.1 christos skip_to_semi (cfile);
431 1.1 christos } else {
432 1.1 christos status = read_client_conf_file (val, ip, config);
433 1.1 christos if (status != ISC_R_SUCCESS)
434 1.1 christos parse_warn (cfile, "%s: bad parse.", val);
435 1.1 christos parse_semi (cfile);
436 1.1 christos }
437 1.1 christos return;
438 1.1 christos
439 1.1 christos case KEY:
440 1.1 christos skip_token(&val, (unsigned *)0, cfile);
441 1.1 christos if (ip) {
442 1.1 christos /* This may seem arbitrary, but there's a reason for
443 1.1 christos doing it: the authentication key database is not
444 1.1 christos scoped. If we allow the user to declare a key other
445 1.1 christos than in the outer scope, the user is very likely to
446 1.1 christos believe that the key will only be used in that
447 1.1 christos scope. If the user only wants the key to be used on
448 1.1 christos one interface, because it's known that the other
449 1.1 christos interface may be connected to an insecure net and
450 1.1 christos the secret key is considered sensitive, we don't
451 1.1 christos want to lull them into believing they've gotten
452 1.1 christos their way. This is a bit contrived, but people
453 1.1 christos tend not to be entirely rational about security. */
454 1.1 christos parse_warn (cfile, "key definition not allowed here.");
455 1.1 christos skip_to_semi (cfile);
456 1.1 christos break;
457 1.1 christos }
458 1.1 christos parse_key (cfile);
459 1.1 christos return;
460 1.1 christos
461 1.1 christos case TOKEN_ALSO:
462 1.1 christos /* consume ALSO */
463 1.1 christos skip_token(&val, NULL, cfile);
464 1.1 christos
465 1.1 christos /* consume type of ALSO list. */
466 1.1 christos token = next_token(&val, NULL, cfile);
467 1.1 christos
468 1.1 christos if (token == REQUEST) {
469 1.1 christos append_list = &config->requested_options;
470 1.1 christos } else if (token == REQUIRE) {
471 1.1 christos append_list = &config->required_options;
472 1.1 christos } else {
473 1.1 christos parse_warn(cfile, "expected REQUEST or REQUIRE list");
474 1.1 christos skip_to_semi(cfile);
475 1.1 christos return;
476 1.1 christos }
477 1.1 christos
478 1.1 christos /* If there is no list, cut the concat short. */
479 1.1 christos if (*append_list == NULL) {
480 1.1 christos parse_option_list(cfile, append_list);
481 1.1 christos return;
482 1.1 christos }
483 1.1 christos
484 1.1 christos /* Count the length of the existing list. */
485 1.1 christos for (i = 0 ; (*append_list)[i] != NULL ; i++)
486 1.1 christos ; /* This space intentionally left blank. */
487 1.1 christos
488 1.1 christos /* If there's no codes on the list, cut the concat short. */
489 1.1 christos if (i == 0) {
490 1.1 christos parse_option_list(cfile, append_list);
491 1.1 christos return;
492 1.1 christos }
493 1.1 christos
494 1.1 christos tmp = parse_option_list(cfile, &new_list);
495 1.1 christos
496 1.1 christos if (tmp == 0 || new_list == NULL)
497 1.1 christos return;
498 1.1 christos
499 1.1 christos /* Allocate 'i + tmp' buckets plus a terminator. */
500 1.1 christos cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
501 1.1 christos MDL);
502 1.1 christos
503 1.1 christos if (cat_list == NULL) {
504 1.1 christos log_error("Unable to allocate memory for new "
505 1.1 christos "request list.");
506 1.1 christos skip_to_semi(cfile);
507 1.1 christos return;
508 1.1 christos }
509 1.1 christos
510 1.1 christos for (i = 0 ; (*append_list)[i] != NULL ; i++)
511 1.1 christos option_reference(&cat_list[i], (*append_list)[i], MDL);
512 1.1 christos
513 1.1 christos tmp = i;
514 1.1 christos
515 1.1 christos for (i = 0 ; new_list[i] != 0 ; i++)
516 1.1 christos option_reference(&cat_list[tmp++], new_list[i], MDL);
517 1.1 christos
518 1.1 christos cat_list[tmp] = 0;
519 1.1 christos
520 1.1 christos /* XXX: We cannot free the old list, because it may have been
521 1.1 christos * XXX: assigned from an outer configuration scope (or may be
522 1.1 christos * XXX: the static default setting).
523 1.1 christos */
524 1.1 christos *append_list = cat_list;
525 1.1 christos
526 1.1 christos return;
527 1.1 christos
528 1.1 christos /* REQUIRE can either start a policy statement or a
529 1.1 christos comma-separated list of names of required options. */
530 1.1 christos case REQUIRE:
531 1.1 christos skip_token(&val, (unsigned *)0, cfile);
532 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
533 1.1 christos if (token == AUTHENTICATION) {
534 1.1 christos policy = P_REQUIRE;
535 1.1 christos goto do_policy;
536 1.1 christos }
537 1.1 christos parse_option_list (cfile, &config -> required_options);
538 1.1 christos return;
539 1.1 christos
540 1.1 christos case IGNORE:
541 1.1 christos skip_token(&val, (unsigned *)0, cfile);
542 1.1 christos policy = P_IGNORE;
543 1.1 christos goto do_policy;
544 1.1 christos
545 1.1 christos case ACCEPT:
546 1.1 christos skip_token(&val, (unsigned *)0, cfile);
547 1.1 christos policy = P_ACCEPT;
548 1.1 christos goto do_policy;
549 1.1 christos
550 1.1 christos case PREFER:
551 1.1 christos skip_token(&val, (unsigned *)0, cfile);
552 1.1 christos policy = P_PREFER;
553 1.1 christos goto do_policy;
554 1.1 christos
555 1.1 christos case DONT:
556 1.1 christos skip_token(&val, (unsigned *)0, cfile);
557 1.1 christos policy = P_DONT;
558 1.1 christos goto do_policy;
559 1.1 christos
560 1.1 christos do_policy:
561 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
562 1.1 christos if (token == AUTHENTICATION) {
563 1.1 christos if (policy != P_PREFER &&
564 1.1 christos policy != P_REQUIRE &&
565 1.1 christos policy != P_DONT) {
566 1.1 christos parse_warn (cfile,
567 1.1 christos "invalid authentication policy.");
568 1.1 christos skip_to_semi (cfile);
569 1.1 christos return;
570 1.1 christos }
571 1.1 christos config -> auth_policy = policy;
572 1.1 christos } else if (token != TOKEN_BOOTP) {
573 1.1 christos if (policy != P_PREFER &&
574 1.1 christos policy != P_IGNORE &&
575 1.1 christos policy != P_ACCEPT) {
576 1.1 christos parse_warn (cfile, "invalid bootp policy.");
577 1.1 christos skip_to_semi (cfile);
578 1.1 christos return;
579 1.1 christos }
580 1.1 christos config -> bootp_policy = policy;
581 1.1 christos } else {
582 1.1 christos parse_warn (cfile, "expecting a policy type.");
583 1.1 christos skip_to_semi (cfile);
584 1.1 christos return;
585 1.1 christos }
586 1.1 christos break;
587 1.1 christos
588 1.1 christos case OPTION:
589 1.1 christos skip_token(&val, (unsigned *)0, cfile);
590 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
591 1.1 christos if (token == SPACE) {
592 1.1 christos if (ip) {
593 1.1 christos parse_warn (cfile,
594 1.1 christos "option space definitions %s",
595 1.1 christos " may not be scoped.");
596 1.1 christos skip_to_semi (cfile);
597 1.1 christos break;
598 1.1 christos }
599 1.1 christos parse_option_space_decl (cfile);
600 1.1 christos return;
601 1.1 christos }
602 1.1 christos
603 1.1 christos known = 0;
604 1.1 christos status = parse_option_name(cfile, 1, &known, &option);
605 1.1 christos if (status != ISC_R_SUCCESS || option == NULL)
606 1.1 christos return;
607 1.1 christos
608 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
609 1.1 christos if (token != CODE) {
610 1.1 christos parse_warn (cfile, "expecting \"code\" keyword.");
611 1.1 christos skip_to_semi (cfile);
612 1.1 christos option_dereference(&option, MDL);
613 1.1 christos return;
614 1.1 christos }
615 1.1 christos if (ip) {
616 1.1 christos parse_warn (cfile,
617 1.1 christos "option definitions may only appear in %s",
618 1.1 christos "the outermost scope.");
619 1.1 christos skip_to_semi (cfile);
620 1.1 christos option_dereference(&option, MDL);
621 1.1 christos return;
622 1.1 christos }
623 1.1 christos
624 1.1 christos /*
625 1.1 christos * If the option was known, remove it from the code and name
626 1.1 christos * hash tables before redefining it.
627 1.1 christos */
628 1.1 christos if (known) {
629 1.1 christos option_name_hash_delete(option->universe->name_hash,
630 1.1 christos option->name, 0, MDL);
631 1.1 christos option_code_hash_delete(option->universe->code_hash,
632 1.1 christos &option->code, 0, MDL);
633 1.1 christos }
634 1.1 christos
635 1.1 christos parse_option_code_definition(cfile, option);
636 1.1 christos option_dereference(&option, MDL);
637 1.1 christos return;
638 1.1 christos
639 1.1 christos case MEDIA:
640 1.1 christos skip_token(&val, (unsigned *)0, cfile);
641 1.1 christos parse_string_list (cfile, &config -> media, 1);
642 1.1 christos return;
643 1.1 christos
644 1.1 christos case HARDWARE:
645 1.1 christos skip_token(&val, (unsigned *)0, cfile);
646 1.1 christos if (ip) {
647 1.1 christos parse_hardware_param (cfile, &ip -> hw_address);
648 1.1 christos } else {
649 1.1 christos parse_warn (cfile, "hardware address parameter %s",
650 1.1 christos "not allowed here.");
651 1.1 christos skip_to_semi (cfile);
652 1.1 christos }
653 1.1 christos return;
654 1.1 christos
655 1.1 christos case ANYCAST_MAC:
656 1.1 christos skip_token(&val, NULL, cfile);
657 1.1 christos if (ip != NULL) {
658 1.1 christos parse_hardware_param(cfile, &ip->anycast_mac_addr);
659 1.1 christos } else {
660 1.1 christos parse_warn(cfile, "anycast mac address parameter "
661 1.1 christos "not allowed here.");
662 1.1 christos skip_to_semi (cfile);
663 1.1 christos }
664 1.1 christos return;
665 1.1 christos
666 1.1 christos case REQUEST:
667 1.1 christos skip_token(&val, (unsigned *)0, cfile);
668 1.1 christos if (config -> requested_options == default_requested_options)
669 1.1 christos config -> requested_options = NULL;
670 1.1 christos parse_option_list (cfile, &config -> requested_options);
671 1.1 christos return;
672 1.1 christos
673 1.1 christos case TIMEOUT:
674 1.1 christos skip_token(&val, (unsigned *)0, cfile);
675 1.1 christos parse_lease_time (cfile, &config -> timeout);
676 1.1 christos return;
677 1.1 christos
678 1.1 christos case RETRY:
679 1.1 christos skip_token(&val, (unsigned *)0, cfile);
680 1.1 christos parse_lease_time (cfile, &config -> retry_interval);
681 1.1 christos return;
682 1.1 christos
683 1.1 christos case SELECT_TIMEOUT:
684 1.1 christos skip_token(&val, (unsigned *)0, cfile);
685 1.1 christos parse_lease_time (cfile, &config -> select_interval);
686 1.1 christos return;
687 1.1 christos
688 1.1 christos case OMAPI:
689 1.1 christos skip_token(&val, (unsigned *)0, cfile);
690 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
691 1.1 christos if (token != PORT) {
692 1.1 christos parse_warn (cfile,
693 1.1 christos "unexpected omapi subtype: %s", val);
694 1.1 christos skip_to_semi (cfile);
695 1.1 christos return;
696 1.1 christos }
697 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
698 1.1 christos if (token != NUMBER) {
699 1.1 christos parse_warn (cfile, "invalid port number: `%s'", val);
700 1.1 christos skip_to_semi (cfile);
701 1.1 christos return;
702 1.1 christos }
703 1.1 christos tmp = atoi (val);
704 1.1 christos if (tmp < 0 || tmp > 65535)
705 1.1 christos parse_warn (cfile, "invalid omapi port %d.", tmp);
706 1.1 christos else if (config != &top_level_config)
707 1.1 christos parse_warn (cfile,
708 1.1 christos "omapi port only works at top level.");
709 1.1 christos else
710 1.1 christos config -> omapi_port = tmp;
711 1.1 christos parse_semi (cfile);
712 1.1 christos return;
713 1.1 christos
714 1.1 christos case DO_FORWARD_UPDATE:
715 1.1 christos skip_token(&val, (unsigned *)0, cfile);
716 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
717 1.1 christos if (!strcasecmp (val, "on") ||
718 1.1 christos !strcasecmp (val, "true"))
719 1.1 christos config -> do_forward_update = 1;
720 1.1 christos else if (!strcasecmp (val, "off") ||
721 1.1 christos !strcasecmp (val, "false"))
722 1.1 christos config -> do_forward_update = 0;
723 1.1 christos else {
724 1.1 christos parse_warn (cfile, "expecting boolean value.");
725 1.1 christos skip_to_semi (cfile);
726 1.1 christos return;
727 1.1 christos }
728 1.1 christos parse_semi (cfile);
729 1.1 christos return;
730 1.1 christos
731 1.1 christos case REBOOT:
732 1.1 christos skip_token(&val, (unsigned *)0, cfile);
733 1.1 christos parse_lease_time (cfile, &config -> reboot_timeout);
734 1.1 christos return;
735 1.1 christos
736 1.1 christos case BACKOFF_CUTOFF:
737 1.1 christos skip_token(&val, (unsigned *)0, cfile);
738 1.1 christos parse_lease_time (cfile, &config -> backoff_cutoff);
739 1.1 christos return;
740 1.1 christos
741 1.1 christos case INITIAL_INTERVAL:
742 1.1 christos skip_token(&val, (unsigned *)0, cfile);
743 1.1 christos parse_lease_time (cfile, &config -> initial_interval);
744 1.1 christos return;
745 1.1 christos
746 1.1 christos case INITIAL_DELAY:
747 1.1 christos skip_token(&val, (unsigned *)0, cfile);
748 1.1 christos parse_lease_time (cfile, &config -> initial_delay);
749 1.1 christos return;
750 1.1 christos
751 1.1 christos case SCRIPT:
752 1.1 christos skip_token(&val, (unsigned *)0, cfile);
753 1.1 christos parse_string (cfile, &config -> script_name, (unsigned *)0);
754 1.1 christos return;
755 1.1 christos
756 1.1 christos case VENDOR:
757 1.1 christos skip_token(&val, (unsigned *)0, cfile);
758 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
759 1.1 christos if (token != OPTION) {
760 1.1 christos parse_warn (cfile, "expecting 'vendor option space'");
761 1.1 christos skip_to_semi (cfile);
762 1.1 christos return;
763 1.1 christos }
764 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
765 1.1 christos if (token != SPACE) {
766 1.1 christos parse_warn (cfile, "expecting 'vendor option space'");
767 1.1 christos skip_to_semi (cfile);
768 1.1 christos return;
769 1.1 christos }
770 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
771 1.1 christos if (!is_identifier (token)) {
772 1.1 christos parse_warn (cfile, "expecting an identifier.");
773 1.1 christos skip_to_semi (cfile);
774 1.1 christos return;
775 1.1 christos }
776 1.1 christos config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
777 1.1 christos if (!config -> vendor_space_name)
778 1.1 christos log_fatal ("no memory for vendor option space name.");
779 1.1 christos strcpy (config -> vendor_space_name, val);
780 1.1 christos for (i = 0; i < universe_count; i++)
781 1.1 christos if (!strcmp (universes [i] -> name,
782 1.1 christos config -> vendor_space_name))
783 1.1 christos break;
784 1.1 christos if (i == universe_count) {
785 1.1 christos log_error ("vendor option space %s not found.",
786 1.1 christos config -> vendor_space_name);
787 1.1 christos }
788 1.1 christos parse_semi (cfile);
789 1.1 christos return;
790 1.1 christos
791 1.1 christos case INTERFACE:
792 1.1 christos skip_token(&val, (unsigned *)0, cfile);
793 1.1 christos if (ip)
794 1.1 christos parse_warn (cfile, "nested interface declaration.");
795 1.1 christos parse_interface_declaration (cfile, config, (char *)0);
796 1.1 christos return;
797 1.1 christos
798 1.1 christos case PSEUDO:
799 1.1 christos skip_token(&val, (unsigned *)0, cfile);
800 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
801 1.1 christos name = dmalloc (strlen (val) + 1, MDL);
802 1.1 christos if (!name)
803 1.1 christos log_fatal ("no memory for pseudo interface name");
804 1.1 christos strcpy (name, val);
805 1.1 christos parse_interface_declaration (cfile, config, name);
806 1.1 christos return;
807 1.1 christos
808 1.1 christos case LEASE:
809 1.1 christos skip_token(&val, (unsigned *)0, cfile);
810 1.1 christos parse_client_lease_statement (cfile, 1);
811 1.1 christos return;
812 1.1 christos
813 1.1 christos case ALIAS:
814 1.1 christos skip_token(&val, (unsigned *)0, cfile);
815 1.1 christos parse_client_lease_statement (cfile, 2);
816 1.1 christos return;
817 1.1 christos
818 1.1 christos case REJECT:
819 1.1 christos skip_token(&val, (unsigned *)0, cfile);
820 1.1 christos parse_reject_statement (cfile, config);
821 1.1 christos return;
822 1.1 christos
823 1.1 christos case LEASE_ID_FORMAT:
824 1.1 christos skip_token(&val, (unsigned *)0, cfile);
825 1.1 christos parse_lease_id_format(cfile);
826 1.1 christos break;
827 1.1 christos
828 1.1 christos
829 1.1 christos default:
830 1.1 christos lose = 0;
831 1.1 christos stmt = (struct executable_statement *)0;
832 1.1 christos if (!parse_executable_statement (&stmt,
833 1.1 christos cfile, &lose, context_any)) {
834 1.1 christos if (!lose) {
835 1.1 christos parse_warn (cfile, "expecting a statement.");
836 1.1 christos skip_to_semi (cfile);
837 1.1 christos }
838 1.1 christos } else {
839 1.1 christos struct executable_statement **eptr, *sptr;
840 1.1 christos if (stmt &&
841 1.1 christos (stmt -> op == send_option_statement ||
842 1.1 christos (stmt -> op == on_statement &&
843 1.1 christos (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
844 1.1 christos eptr = &config -> on_transmission -> statements;
845 1.1 christos if (stmt -> op == on_statement) {
846 1.1 christos sptr = (struct executable_statement *)0;
847 1.1 christos executable_statement_reference
848 1.1 christos (&sptr,
849 1.1 christos stmt -> data.on.statements, MDL);
850 1.1 christos executable_statement_dereference (&stmt,
851 1.1 christos MDL);
852 1.1 christos executable_statement_reference (&stmt,
853 1.1 christos sptr,
854 1.1 christos MDL);
855 1.1 christos executable_statement_dereference (&sptr,
856 1.1 christos MDL);
857 1.1 christos }
858 1.1 christos } else
859 1.1 christos eptr = &config -> on_receipt -> statements;
860 1.1 christos
861 1.1 christos if (stmt) {
862 1.1 christos for (; *eptr; eptr = &(*eptr) -> next)
863 1.1 christos ;
864 1.1 christos executable_statement_reference (eptr,
865 1.1 christos stmt, MDL);
866 1.1 christos }
867 1.1 christos return;
868 1.1 christos }
869 1.1 christos break;
870 1.1 christos }
871 1.1 christos parse_semi (cfile);
872 1.1 christos }
873 1.1 christos
874 1.1 christos /* option-list :== option_name |
875 1.1 christos option_list COMMA option_name */
876 1.1 christos
877 1.1 christos int
878 1.1 christos parse_option_list(struct parse *cfile, struct option ***list)
879 1.1 christos {
880 1.1 christos int ix;
881 1.1 christos int token;
882 1.1 christos const char *val;
883 1.1 christos pair p = (pair)0, q = (pair)0, r;
884 1.1 christos struct option *option = NULL;
885 1.1 christos isc_result_t status;
886 1.1 christos
887 1.1 christos ix = 0;
888 1.1 christos do {
889 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
890 1.1 christos if (token == SEMI) {
891 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
892 1.1 christos break;
893 1.1 christos }
894 1.1 christos if (!is_identifier (token)) {
895 1.1 christos parse_warn (cfile, "%s: expected option name.", val);
896 1.1 christos skip_token(&val, (unsigned *)0, cfile);
897 1.1 christos skip_to_semi (cfile);
898 1.1 christos return 0;
899 1.1 christos }
900 1.1 christos status = parse_option_name(cfile, 0, NULL, &option);
901 1.1 christos if (status != ISC_R_SUCCESS || option == NULL) {
902 1.1 christos parse_warn (cfile, "%s: expected option name.", val);
903 1.1 christos return 0;
904 1.1 christos }
905 1.1 christos r = new_pair (MDL);
906 1.1 christos if (!r)
907 1.1 christos log_fatal ("can't allocate pair for option code.");
908 1.1 christos /* XXX: we should probably carry a reference across this */
909 1.1 christos r->car = (caddr_t)option;
910 1.1 christos option_dereference(&option, MDL);
911 1.1 christos r -> cdr = (pair)0;
912 1.1 christos if (p)
913 1.1 christos q -> cdr = r;
914 1.1 christos else
915 1.1 christos p = r;
916 1.1 christos q = r;
917 1.1 christos ++ix;
918 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
919 1.1 christos } while (token == COMMA);
920 1.1 christos if (token != SEMI) {
921 1.1 christos parse_warn (cfile, "expecting semicolon.");
922 1.1 christos skip_to_semi (cfile);
923 1.1 christos return 0;
924 1.1 christos }
925 1.1 christos /* XXX we can't free the list here, because we may have copied
926 1.1 christos XXX it from an outer config state. */
927 1.1 christos *list = NULL;
928 1.1 christos if (ix) {
929 1.1 christos *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
930 1.1 christos if (!*list)
931 1.1 christos log_error ("no memory for option list.");
932 1.1 christos else {
933 1.1 christos ix = 0;
934 1.1 christos for (q = p; q; q = q -> cdr)
935 1.1 christos option_reference(&(*list)[ix++],
936 1.1 christos (struct option *)q->car, MDL);
937 1.1 christos (*list)[ix] = NULL;
938 1.1 christos }
939 1.1 christos while (p) {
940 1.1 christos q = p -> cdr;
941 1.1 christos free_pair (p, MDL);
942 1.1 christos p = q;
943 1.1 christos }
944 1.1 christos }
945 1.1 christos
946 1.1 christos return ix;
947 1.1 christos }
948 1.1 christos
949 1.1 christos /* interface-declaration :==
950 1.1 christos INTERFACE string LBRACE client-declarations RBRACE */
951 1.1 christos
952 1.1 christos void parse_interface_declaration (cfile, outer_config, name)
953 1.1 christos struct parse *cfile;
954 1.1 christos struct client_config *outer_config;
955 1.1 christos char *name;
956 1.1 christos {
957 1.1 christos int token;
958 1.1 christos const char *val;
959 1.1 christos struct client_state *client, **cp;
960 1.1 christos struct interface_info *ip = (struct interface_info *)0;
961 1.1 christos
962 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
963 1.1 christos if (token != STRING) {
964 1.1 christos parse_warn (cfile, "expecting interface name (in quotes).");
965 1.1 christos skip_to_semi (cfile);
966 1.1 christos return;
967 1.1 christos }
968 1.1 christos
969 1.1 christos if (!interface_or_dummy (&ip, val))
970 1.1 christos log_fatal ("Can't allocate interface %s.", val);
971 1.1 christos
972 1.1 christos /* If we were given a name, this is a pseudo-interface. */
973 1.1 christos if (name) {
974 1.1 christos make_client_state (&client);
975 1.1 christos client -> name = name;
976 1.1 christos client -> interface = ip;
977 1.1 christos for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
978 1.1 christos ;
979 1.1 christos *cp = client;
980 1.1 christos } else {
981 1.1 christos if (!ip -> client) {
982 1.1 christos make_client_state (&ip -> client);
983 1.1 christos ip -> client -> interface = ip;
984 1.1 christos }
985 1.1 christos client = ip -> client;
986 1.1 christos }
987 1.1 christos
988 1.1 christos if (!client -> config)
989 1.1 christos make_client_config (client, outer_config);
990 1.1 christos
991 1.1 christos ip -> flags &= ~INTERFACE_AUTOMATIC;
992 1.1 christos interfaces_requested = 1;
993 1.1 christos
994 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
995 1.1 christos if (token != LBRACE) {
996 1.1 christos parse_warn (cfile, "expecting left brace.");
997 1.1 christos skip_to_semi (cfile);
998 1.1 christos return;
999 1.1 christos }
1000 1.1 christos
1001 1.1 christos do {
1002 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
1003 1.1 christos if (token == END_OF_FILE) {
1004 1.1 christos parse_warn (cfile,
1005 1.1 christos "unterminated interface declaration.");
1006 1.1 christos return;
1007 1.1 christos }
1008 1.1 christos if (token == RBRACE)
1009 1.1 christos break;
1010 1.1 christos parse_client_statement (cfile, ip, client -> config);
1011 1.1 christos } while (1);
1012 1.1 christos skip_token(&val, (unsigned *)0, cfile);
1013 1.1 christos }
1014 1.1 christos
1015 1.1 christos int interface_or_dummy (struct interface_info **pi, const char *name)
1016 1.1 christos {
1017 1.1 christos struct interface_info *i;
1018 1.1 christos struct interface_info *ip = (struct interface_info *)0;
1019 1.1 christos isc_result_t status;
1020 1.1 christos
1021 1.1 christos /* Find the interface (if any) that matches the name. */
1022 1.1 christos for (i = interfaces; i; i = i -> next) {
1023 1.1 christos if (!strcmp (i -> name, name)) {
1024 1.1 christos interface_reference (&ip, i, MDL);
1025 1.1 christos break;
1026 1.1 christos }
1027 1.1 christos }
1028 1.1 christos
1029 1.1 christos /* If it's not a real interface, see if it's on the dummy list. */
1030 1.1 christos if (!ip) {
1031 1.1 christos for (ip = dummy_interfaces; ip; ip = ip -> next) {
1032 1.1 christos if (!strcmp (ip -> name, name)) {
1033 1.1 christos interface_reference (&ip, i, MDL);
1034 1.1 christos break;
1035 1.1 christos }
1036 1.1 christos }
1037 1.1 christos }
1038 1.1 christos
1039 1.1 christos /* If we didn't find an interface, make a dummy interface as
1040 1.1 christos a placeholder. */
1041 1.1 christos if (!ip) {
1042 1.1 christos if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
1043 1.1 christos log_fatal ("Can't record interface %s: %s",
1044 1.1 christos name, isc_result_totext (status));
1045 1.1 christos
1046 1.1 christos if (strlen(name) >= sizeof(ip->name)) {
1047 1.1 christos interface_dereference(&ip, MDL);
1048 1.1 christos return 0;
1049 1.1 christos }
1050 1.1 christos strcpy(ip->name, name);
1051 1.1 christos
1052 1.1 christos if (dummy_interfaces) {
1053 1.1 christos interface_reference (&ip -> next,
1054 1.1 christos dummy_interfaces, MDL);
1055 1.1 christos interface_dereference (&dummy_interfaces, MDL);
1056 1.1 christos }
1057 1.1 christos interface_reference (&dummy_interfaces, ip, MDL);
1058 1.1 christos }
1059 1.1 christos if (pi)
1060 1.1 christos status = interface_reference (pi, ip, MDL);
1061 1.1 christos else
1062 1.1 christos status = ISC_R_FAILURE;
1063 1.1 christos interface_dereference (&ip, MDL);
1064 1.1 christos if (status != ISC_R_SUCCESS)
1065 1.1 christos return 0;
1066 1.1 christos return 1;
1067 1.1 christos }
1068 1.1 christos
1069 1.1 christos void make_client_state (state)
1070 1.1 christos struct client_state **state;
1071 1.1 christos {
1072 1.1 christos *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
1073 1.1 christos if (!*state)
1074 1.1 christos log_fatal ("no memory for client state\n");
1075 1.1 christos memset (*state, 0, sizeof **state);
1076 1.1 christos }
1077 1.1 christos
1078 1.1 christos void make_client_config (client, config)
1079 1.1 christos struct client_state *client;
1080 1.1 christos struct client_config *config;
1081 1.1 christos {
1082 1.1 christos client -> config = (((struct client_config *)
1083 1.1 christos dmalloc (sizeof (struct client_config), MDL)));
1084 1.1 christos if (!client -> config)
1085 1.1 christos log_fatal ("no memory for client config\n");
1086 1.1 christos memcpy (client -> config, config, sizeof *config);
1087 1.1 christos if (!clone_group (&client -> config -> on_receipt,
1088 1.1 christos config -> on_receipt, MDL) ||
1089 1.1 christos !clone_group (&client -> config -> on_transmission,
1090 1.1 christos config -> on_transmission, MDL))
1091 1.1 christos log_fatal ("no memory for client state groups.");
1092 1.1 christos }
1093 1.1 christos
1094 1.1 christos /* client-lease-statement :==
1095 1.1 christos LBRACE client-lease-declarations RBRACE
1096 1.1 christos
1097 1.1 christos client-lease-declarations :==
1098 1.1 christos <nil> |
1099 1.1 christos client-lease-declaration |
1100 1.1 christos client-lease-declarations client-lease-declaration */
1101 1.1 christos
1102 1.1 christos
1103 1.1 christos void parse_client_lease_statement (cfile, is_static)
1104 1.1 christos struct parse *cfile;
1105 1.1 christos int is_static;
1106 1.1 christos {
1107 1.3 christos struct client_lease *lease;
1108 1.1 christos struct interface_info *ip = (struct interface_info *)0;
1109 1.1 christos int token;
1110 1.1 christos const char *val;
1111 1.1 christos struct client_state *client = (struct client_state *)0;
1112 1.1 christos
1113 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
1114 1.1 christos if (token != LBRACE) {
1115 1.1 christos parse_warn (cfile, "expecting left brace.");
1116 1.1 christos skip_to_semi (cfile);
1117 1.1 christos return;
1118 1.1 christos }
1119 1.1 christos
1120 1.1 christos lease = ((struct client_lease *)
1121 1.1 christos dmalloc (sizeof (struct client_lease), MDL));
1122 1.1 christos if (!lease)
1123 1.1 christos log_fatal ("no memory for lease.\n");
1124 1.1 christos memset (lease, 0, sizeof *lease);
1125 1.1 christos lease -> is_static = is_static;
1126 1.1 christos if (!option_state_allocate (&lease -> options, MDL))
1127 1.1 christos log_fatal ("no memory for lease options.\n");
1128 1.1 christos
1129 1.1 christos do {
1130 1.1 christos token = peek_token (&val, (unsigned *)0, cfile);
1131 1.1 christos if (token == END_OF_FILE) {
1132 1.1 christos parse_warn (cfile, "unterminated lease declaration.");
1133 1.1 christos return;
1134 1.1 christos }
1135 1.1 christos if (token == RBRACE)
1136 1.1 christos break;
1137 1.1 christos parse_client_lease_declaration (cfile, lease, &ip, &client);
1138 1.1 christos } while (1);
1139 1.1 christos skip_token(&val, (unsigned *)0, cfile);
1140 1.1 christos
1141 1.1 christos /* If the lease declaration didn't include an interface
1142 1.1 christos declaration that we recognized, it's of no use to us. */
1143 1.1 christos if (!ip) {
1144 1.1 christos destroy_client_lease (lease);
1145 1.1 christos return;
1146 1.1 christos }
1147 1.1 christos
1148 1.1 christos /* Make sure there's a client state structure... */
1149 1.1 christos if (!ip -> client) {
1150 1.1 christos make_client_state (&ip -> client);
1151 1.1 christos ip -> client -> interface = ip;
1152 1.1 christos }
1153 1.1 christos if (!client)
1154 1.1 christos client = ip -> client;
1155 1.1 christos
1156 1.1 christos /* If this is an alias lease, it doesn't need to be sorted in. */
1157 1.1 christos if (is_static == 2) {
1158 1.1 christos ip -> client -> alias = lease;
1159 1.1 christos return;
1160 1.1 christos }
1161 1.1 christos
1162 1.1 christos /* The new lease may supersede a lease that's not the
1163 1.1 christos active lease but is still on the lease list, so scan the
1164 1.1 christos lease list looking for a lease with the same address, and
1165 1.3 christos if we find it, toss it. We only allow supercession if
1166 1.3 christos the leases originated from the same source. In other words,
1167 1.3 christos either both are from the config file or both are from the lease
1168 1.3 christos file. This keeps us from discarding fallback leases */
1169 1.3 christos discard_duplicate (&client->leases, lease);
1170 1.1 christos
1171 1.1 christos /* If this is a preloaded lease, just put it on the list of recorded
1172 1.1 christos leases - don't make it the active lease. */
1173 1.1 christos if (is_static) {
1174 1.1 christos lease -> next = client -> leases;
1175 1.1 christos client -> leases = lease;
1176 1.1 christos return;
1177 1.1 christos }
1178 1.1 christos
1179 1.1 christos /* The last lease in the lease file on a particular interface is
1180 1.1 christos the active lease for that interface. Of course, we don't know
1181 1.1 christos what the last lease in the file is until we've parsed the whole
1182 1.1 christos file, so at this point, we assume that the lease we just parsed
1183 1.1 christos is the active lease for its interface. If there's already
1184 1.1 christos an active lease for the interface, and this lease is for the same
1185 1.1 christos ip address, then we just toss the old active lease and replace
1186 1.1 christos it with this one. If this lease is for a different address,
1187 1.1 christos then if the old active lease has expired, we dump it; if not,
1188 1.1 christos we put it on the list of leases for this interface which are
1189 1.1 christos still valid but no longer active. */
1190 1.1 christos if (client -> active) {
1191 1.1 christos if (client -> active -> expiry < cur_time)
1192 1.1 christos destroy_client_lease (client -> active);
1193 1.1 christos else if (client -> active -> address.len ==
1194 1.1 christos lease -> address.len &&
1195 1.1 christos !memcmp (client -> active -> address.iabuf,
1196 1.1 christos lease -> address.iabuf,
1197 1.1 christos lease -> address.len))
1198 1.1 christos destroy_client_lease (client -> active);
1199 1.1 christos else {
1200 1.1 christos client -> active -> next = client -> leases;
1201 1.1 christos client -> leases = client -> active;
1202 1.1 christos }
1203 1.1 christos }
1204 1.1 christos client -> active = lease;
1205 1.1 christos
1206 1.1 christos /* phew. */
1207 1.1 christos }
1208 1.1 christos
1209 1.1 christos /* client-lease-declaration :==
1210 1.1 christos BOOTP |
1211 1.1 christos INTERFACE string |
1212 1.1 christos FIXED_ADDR ip_address |
1213 1.1 christos FILENAME string |
1214 1.1 christos SERVER_NAME string |
1215 1.1 christos OPTION option-decl |
1216 1.1 christos RENEW time-decl |
1217 1.1 christos REBIND time-decl |
1218 1.1 christos EXPIRE time-decl |
1219 1.1 christos KEY id */
1220 1.1 christos
1221 1.1 christos void parse_client_lease_declaration (cfile, lease, ipp, clientp)
1222 1.1 christos struct parse *cfile;
1223 1.1 christos struct client_lease *lease;
1224 1.1 christos struct interface_info **ipp;
1225 1.1 christos struct client_state **clientp;
1226 1.1 christos {
1227 1.1 christos int token;
1228 1.1 christos const char *val;
1229 1.1 christos struct interface_info *ip;
1230 1.1 christos struct option_cache *oc;
1231 1.1 christos struct client_state *client = (struct client_state *)0;
1232 1.1 christos
1233 1.1 christos switch (next_token (&val, (unsigned *)0, cfile)) {
1234 1.1 christos case KEY:
1235 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
1236 1.1 christos if (token != STRING && !is_identifier (token)) {
1237 1.1 christos parse_warn (cfile, "expecting key name.");
1238 1.1 christos skip_to_semi (cfile);
1239 1.1 christos break;
1240 1.1 christos }
1241 1.1 christos if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1242 1.1 christos ISC_R_SUCCESS)
1243 1.1 christos parse_warn (cfile, "unknown key %s", val);
1244 1.1 christos parse_semi (cfile);
1245 1.1 christos break;
1246 1.1 christos case TOKEN_BOOTP:
1247 1.1 christos lease -> is_bootp = 1;
1248 1.1 christos break;
1249 1.1 christos
1250 1.1 christos case INTERFACE:
1251 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
1252 1.1 christos if (token != STRING) {
1253 1.1 christos parse_warn (cfile,
1254 1.1 christos "expecting interface name (in quotes).");
1255 1.1 christos skip_to_semi (cfile);
1256 1.1 christos break;
1257 1.1 christos }
1258 1.1 christos if (!interface_or_dummy (ipp, val))
1259 1.1 christos log_fatal ("Can't allocate interface %s.", val);
1260 1.1 christos break;
1261 1.1 christos
1262 1.1 christos case NAME:
1263 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
1264 1.1 christos ip = *ipp;
1265 1.1 christos if (!ip) {
1266 1.1 christos parse_warn (cfile, "state name precedes interface.");
1267 1.1 christos break;
1268 1.1 christos }
1269 1.1 christos for (client = ip -> client; client; client = client -> next)
1270 1.1 christos if (client -> name && !strcmp (client -> name, val))
1271 1.1 christos break;
1272 1.1 christos if (!client)
1273 1.1 christos parse_warn (cfile,
1274 1.1 christos "lease specified for unknown pseudo.");
1275 1.1 christos *clientp = client;
1276 1.1 christos break;
1277 1.1 christos
1278 1.1 christos case FIXED_ADDR:
1279 1.1 christos if (!parse_ip_addr (cfile, &lease -> address))
1280 1.1 christos return;
1281 1.1 christos break;
1282 1.1 christos
1283 1.1 christos case MEDIUM:
1284 1.1 christos parse_string_list (cfile, &lease -> medium, 0);
1285 1.1 christos return;
1286 1.1 christos
1287 1.1 christos case FILENAME:
1288 1.1 christos parse_string (cfile, &lease -> filename, (unsigned *)0);
1289 1.1 christos return;
1290 1.1 christos
1291 1.1 christos case SERVER_NAME:
1292 1.1 christos parse_string (cfile, &lease -> server_name, (unsigned *)0);
1293 1.1 christos return;
1294 1.1 christos
1295 1.1 christos case RENEW:
1296 1.1 christos lease -> renewal = parse_date (cfile);
1297 1.1 christos return;
1298 1.1 christos
1299 1.1 christos case REBIND:
1300 1.1 christos lease -> rebind = parse_date (cfile);
1301 1.1 christos return;
1302 1.1 christos
1303 1.1 christos case EXPIRE:
1304 1.1 christos lease -> expiry = parse_date (cfile);
1305 1.1 christos return;
1306 1.1 christos
1307 1.1 christos case OPTION:
1308 1.1 christos oc = (struct option_cache *)0;
1309 1.1 christos if (parse_option_decl (&oc, cfile)) {
1310 1.1 christos save_option(oc->option->universe, lease->options, oc);
1311 1.1 christos option_cache_dereference (&oc, MDL);
1312 1.1 christos }
1313 1.1 christos return;
1314 1.1 christos
1315 1.1 christos default:
1316 1.1 christos parse_warn (cfile, "expecting lease declaration.");
1317 1.1 christos skip_to_semi (cfile);
1318 1.1 christos break;
1319 1.1 christos }
1320 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
1321 1.1 christos if (token != SEMI) {
1322 1.1 christos parse_warn (cfile, "expecting semicolon.");
1323 1.1 christos skip_to_semi (cfile);
1324 1.1 christos }
1325 1.1 christos }
1326 1.1 christos
1327 1.1 christos /* Parse a default-duid ""; statement.
1328 1.1 christos */
1329 1.1 christos static void
1330 1.1 christos parse_client_default_duid(struct parse *cfile)
1331 1.1 christos {
1332 1.1 christos struct data_string new_duid;
1333 1.1 christos u_int8_t buf[128];
1334 1.1 christos unsigned len;
1335 1.1 christos
1336 1.1 christos len = parse_X(cfile, buf, sizeof(buf));
1337 1.1 christos if (len <= 2) {
1338 1.1 christos parse_warn(cfile, "Invalid DUID contents.");
1339 1.1 christos skip_to_semi(cfile);
1340 1.1 christos return;
1341 1.1 christos }
1342 1.1 christos
1343 1.1 christos memset(&new_duid, 0, sizeof(new_duid));
1344 1.1 christos if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
1345 1.1 christos parse_warn(cfile, "Out of memory parsing default DUID.");
1346 1.1 christos skip_to_semi(cfile);
1347 1.1 christos return;
1348 1.1 christos }
1349 1.1 christos new_duid.data = new_duid.buffer->data;
1350 1.1 christos new_duid.len = len;
1351 1.1 christos
1352 1.1 christos memcpy(new_duid.buffer->data, buf, len);
1353 1.1 christos
1354 1.1 christos /* Rotate the last entry into place. */
1355 1.1 christos if (default_duid.buffer != NULL)
1356 1.1 christos data_string_forget(&default_duid, MDL);
1357 1.1 christos data_string_copy(&default_duid, &new_duid, MDL);
1358 1.1 christos data_string_forget(&new_duid, MDL);
1359 1.1 christos
1360 1.1 christos parse_semi(cfile);
1361 1.1 christos }
1362 1.1 christos
1363 1.1 christos /* Parse a lease6 {} construct. The v6 client is a little different
1364 1.1 christos * than the v4 client today, in that it only retains one lease, the
1365 1.1 christos * active lease, and discards any less recent information. It may
1366 1.1 christos * be useful in the future to cache additional information, but it
1367 1.1 christos * is not worth the effort for the moment.
1368 1.1 christos */
1369 1.1 christos static void
1370 1.1 christos parse_client6_lease_statement(struct parse *cfile)
1371 1.1 christos {
1372 1.1 christos #if !defined(DHCPv6)
1373 1.1 christos parse_warn(cfile, "No DHCPv6 support.");
1374 1.1 christos skip_to_semi(cfile);
1375 1.1 christos #else /* defined(DHCPv6) */
1376 1.1 christos struct option_cache *oc = NULL;
1377 1.1 christos struct dhc6_lease *lease;
1378 1.1 christos struct dhc6_ia **ia;
1379 1.1 christos struct client_state *client = NULL;
1380 1.1 christos struct interface_info *iface = NULL;
1381 1.1 christos struct data_string ds;
1382 1.1 christos const char *val;
1383 1.1 christos unsigned len;
1384 1.1 christos int token, has_ia, no_semi, has_name;
1385 1.1 christos
1386 1.1 christos token = next_token(NULL, NULL, cfile);
1387 1.1 christos if (token != LBRACE) {
1388 1.1 christos parse_warn(cfile, "Expecting open curly brace.");
1389 1.1 christos skip_to_semi(cfile);
1390 1.1 christos return;
1391 1.1 christos }
1392 1.1 christos
1393 1.1 christos lease = dmalloc(sizeof(*lease), MDL);
1394 1.1 christos if (lease == NULL) {
1395 1.1 christos parse_warn(cfile, "Unable to allocate lease state.");
1396 1.1 christos skip_to_rbrace(cfile, 1);
1397 1.1 christos return;
1398 1.1 christos }
1399 1.1 christos
1400 1.1 christos option_state_allocate(&lease->options, MDL);
1401 1.1 christos if (lease->options == NULL) {
1402 1.1 christos parse_warn(cfile, "Unable to allocate option cache.");
1403 1.1 christos skip_to_rbrace(cfile, 1);
1404 1.1 christos dfree(lease, MDL);
1405 1.1 christos return;
1406 1.1 christos }
1407 1.1 christos
1408 1.1 christos has_ia = 0;
1409 1.1 christos has_name = 0;
1410 1.1 christos ia = &lease->bindings;
1411 1.1 christos token = next_token(&val, NULL, cfile);
1412 1.1 christos while (token != RBRACE) {
1413 1.1 christos no_semi = 0;
1414 1.1 christos
1415 1.1 christos switch(token) {
1416 1.1 christos case IA_NA:
1417 1.1 christos *ia = parse_client6_ia_na_statement(cfile);
1418 1.1 christos if (*ia != NULL) {
1419 1.1 christos ia = &(*ia)->next;
1420 1.1 christos has_ia = 1;
1421 1.1 christos }
1422 1.1 christos
1423 1.1 christos no_semi = 1;
1424 1.1 christos
1425 1.1 christos break;
1426 1.1 christos
1427 1.1 christos case IA_TA:
1428 1.1 christos *ia = parse_client6_ia_ta_statement(cfile);
1429 1.1 christos if (*ia != NULL) {
1430 1.1 christos ia = &(*ia)->next;
1431 1.1 christos has_ia = 1;
1432 1.1 christos }
1433 1.1 christos
1434 1.1 christos no_semi = 1;
1435 1.1 christos
1436 1.1 christos break;
1437 1.1 christos
1438 1.1 christos case IA_PD:
1439 1.1 christos *ia = parse_client6_ia_pd_statement(cfile);
1440 1.1 christos if (*ia != NULL) {
1441 1.1 christos ia = &(*ia)->next;
1442 1.1 christos has_ia = 1;
1443 1.1 christos }
1444 1.1 christos
1445 1.1 christos no_semi = 1;
1446 1.1 christos
1447 1.1 christos break;
1448 1.1 christos
1449 1.1 christos case INTERFACE:
1450 1.1 christos if (iface != NULL) {
1451 1.1 christos parse_warn(cfile, "Multiple interface names?");
1452 1.1 christos skip_to_semi(cfile);
1453 1.1 christos no_semi = 1;
1454 1.1 christos break;
1455 1.1 christos }
1456 1.1 christos
1457 1.1 christos token = next_token(&val, &len, cfile);
1458 1.1 christos if (token != STRING) {
1459 1.1 christos strerror:
1460 1.1 christos parse_warn(cfile, "Expecting a string.");
1461 1.1 christos skip_to_semi(cfile);
1462 1.1 christos no_semi = 1;
1463 1.1 christos break;
1464 1.1 christos }
1465 1.1 christos
1466 1.1 christos for (iface = interfaces ; iface != NULL ;
1467 1.1 christos iface = iface->next) {
1468 1.1 christos if (strcmp(iface->name, val) == 0)
1469 1.1 christos break;
1470 1.1 christos }
1471 1.1 christos
1472 1.1 christos if (iface == NULL) {
1473 1.1 christos parse_warn(cfile, "Unknown interface.");
1474 1.1 christos break;
1475 1.1 christos }
1476 1.1 christos
1477 1.1 christos break;
1478 1.1 christos
1479 1.1 christos case NAME:
1480 1.1 christos has_name = 1;
1481 1.1 christos
1482 1.1 christos if (client != NULL) {
1483 1.1 christos parse_warn(cfile, "Multiple state names?");
1484 1.1 christos skip_to_semi(cfile);
1485 1.1 christos no_semi = 1;
1486 1.1 christos break;
1487 1.1 christos }
1488 1.1 christos
1489 1.1 christos if (iface == NULL) {
1490 1.1 christos parse_warn(cfile, "Client name without "
1491 1.1 christos "interface.");
1492 1.1 christos skip_to_semi(cfile);
1493 1.1 christos no_semi = 1;
1494 1.1 christos break;
1495 1.1 christos }
1496 1.1 christos
1497 1.1 christos token = next_token(&val, &len, cfile);
1498 1.1 christos if (token != STRING)
1499 1.1 christos goto strerror;
1500 1.1 christos
1501 1.1 christos for (client = iface->client ; client != NULL ;
1502 1.1 christos client = client->next) {
1503 1.1 christos if ((client->name != NULL) &&
1504 1.1 christos (strcmp(client->name, val) == 0))
1505 1.1 christos break;
1506 1.1 christos }
1507 1.1 christos
1508 1.1 christos if (client == NULL) {
1509 1.1 christos parse_warn(cfile, "Unknown client state %s.",
1510 1.1 christos val);
1511 1.1 christos break;
1512 1.1 christos }
1513 1.1 christos
1514 1.1 christos break;
1515 1.1 christos
1516 1.1 christos case OPTION:
1517 1.1 christos if (parse_option_decl(&oc, cfile)) {
1518 1.1 christos save_option(oc->option->universe,
1519 1.1 christos lease->options, oc);
1520 1.1 christos option_cache_dereference(&oc, MDL);
1521 1.1 christos }
1522 1.1 christos no_semi = 1;
1523 1.1 christos break;
1524 1.1 christos
1525 1.1 christos case TOKEN_RELEASED:
1526 1.1 christos case TOKEN_ABANDONED:
1527 1.1 christos lease->released = ISC_TRUE;
1528 1.1 christos break;
1529 1.1 christos
1530 1.1 christos default:
1531 1.1 christos parse_warn(cfile, "Unexpected token, %s.", val);
1532 1.1 christos no_semi = 1;
1533 1.1 christos skip_to_semi(cfile);
1534 1.1 christos break;
1535 1.1 christos }
1536 1.1 christos
1537 1.1 christos if (!no_semi)
1538 1.1 christos parse_semi(cfile);
1539 1.1 christos
1540 1.1 christos token = next_token(&val, NULL, cfile);
1541 1.1 christos
1542 1.1 christos if (token == END_OF_FILE) {
1543 1.1 christos parse_warn(cfile, "Unexpected end of file.");
1544 1.1 christos break;
1545 1.1 christos }
1546 1.1 christos }
1547 1.1 christos
1548 1.1 christos if (!has_ia) {
1549 1.1 christos log_debug("Lease with no IA's discarded from lease db.");
1550 1.1 christos dhc6_lease_destroy(&lease, MDL);
1551 1.1 christos return;
1552 1.1 christos }
1553 1.1 christos
1554 1.1 christos if (iface == NULL)
1555 1.1 christos parse_warn(cfile, "Lease has no interface designation.");
1556 1.1 christos else if (!has_name && (client == NULL)) {
1557 1.1 christos for (client = iface->client ; client != NULL ;
1558 1.1 christos client = client->next) {
1559 1.1 christos if (client->name == NULL)
1560 1.1 christos break;
1561 1.1 christos }
1562 1.1 christos }
1563 1.1 christos
1564 1.1 christos if (client == NULL) {
1565 1.1 christos parse_warn(cfile, "No matching client state.");
1566 1.1 christos dhc6_lease_destroy(&lease, MDL);
1567 1.1 christos return;
1568 1.1 christos }
1569 1.1 christos
1570 1.1 christos /* Fetch Preference option from option cache. */
1571 1.1 christos memset(&ds, 0, sizeof(ds));
1572 1.1 christos oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
1573 1.1 christos if ((oc != NULL) &&
1574 1.1 christos evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
1575 1.1 christos NULL, &global_scope, oc, MDL)) {
1576 1.1 christos if (ds.len != 1) {
1577 1.1 christos log_error("Invalid length of DHCPv6 Preference option "
1578 1.1 christos "(%d != 1)", ds.len);
1579 1.1 christos data_string_forget(&ds, MDL);
1580 1.1 christos dhc6_lease_destroy(&lease, MDL);
1581 1.1 christos return;
1582 1.1 christos } else
1583 1.1 christos lease->pref = ds.data[0];
1584 1.1 christos
1585 1.1 christos data_string_forget(&ds, MDL);
1586 1.1 christos }
1587 1.1 christos
1588 1.1 christos /* Fetch server-id option from option cache. */
1589 1.1 christos oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
1590 1.1 christos if ((oc == NULL) ||
1591 1.1 christos !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
1592 1.1 christos lease->options, NULL, &global_scope, oc,
1593 1.1 christos MDL) ||
1594 1.1 christos (lease->server_id.len == 0)) {
1595 1.1 christos /* This should be impossible... */
1596 1.1 christos log_error("Invalid SERVERID option cache.");
1597 1.1 christos dhc6_lease_destroy(&lease, MDL);
1598 1.1 christos return;
1599 1.1 christos }
1600 1.1 christos
1601 1.1 christos if (client->active_lease != NULL)
1602 1.1 christos dhc6_lease_destroy(&client->active_lease, MDL);
1603 1.1 christos
1604 1.1 christos client->active_lease = lease;
1605 1.1 christos #endif /* defined(DHCPv6) */
1606 1.1 christos }
1607 1.1 christos
1608 1.1 christos /* Parse an ia_na object from the client lease.
1609 1.1 christos */
1610 1.1 christos #ifdef DHCPv6
1611 1.1 christos static struct dhc6_ia *
1612 1.1 christos parse_client6_ia_na_statement(struct parse *cfile)
1613 1.1 christos {
1614 1.1 christos struct option_cache *oc = NULL;
1615 1.1 christos struct dhc6_ia *ia;
1616 1.1 christos struct dhc6_addr **addr;
1617 1.1 christos const char *val;
1618 1.1 christos int token, no_semi, len;
1619 1.1 christos u_int8_t buf[5];
1620 1.1 christos
1621 1.1 christos ia = dmalloc(sizeof(*ia), MDL);
1622 1.1 christos if (ia == NULL) {
1623 1.1 christos parse_warn(cfile, "Out of memory allocating IA_NA state.");
1624 1.1 christos skip_to_semi(cfile);
1625 1.1 christos return NULL;
1626 1.1 christos }
1627 1.1 christos ia->ia_type = D6O_IA_NA;
1628 1.1 christos
1629 1.1 christos /* Get IAID. */
1630 1.1 christos len = parse_X(cfile, buf, 5);
1631 1.1 christos if (len == 4) {
1632 1.1 christos memcpy(ia->iaid, buf, 4);
1633 1.1 christos } else {
1634 1.1 christos parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1635 1.1 christos skip_to_semi(cfile);
1636 1.1 christos dfree(ia, MDL);
1637 1.1 christos return NULL;
1638 1.1 christos }
1639 1.1 christos
1640 1.1 christos token = next_token(NULL, NULL, cfile);
1641 1.1 christos if (token != LBRACE) {
1642 1.1 christos parse_warn(cfile, "Expecting open curly brace.");
1643 1.1 christos skip_to_semi(cfile);
1644 1.1 christos dfree(ia, MDL);
1645 1.1 christos return NULL;
1646 1.1 christos }
1647 1.1 christos
1648 1.1 christos option_state_allocate(&ia->options, MDL);
1649 1.1 christos if (ia->options == NULL) {
1650 1.1 christos parse_warn(cfile, "Unable to allocate option state.");
1651 1.1 christos skip_to_rbrace(cfile, 1);
1652 1.1 christos dfree(ia, MDL);
1653 1.1 christos return NULL;
1654 1.1 christos }
1655 1.1 christos
1656 1.1 christos addr = &ia->addrs;
1657 1.1 christos token = next_token(&val, NULL, cfile);
1658 1.1 christos while (token != RBRACE) {
1659 1.1 christos no_semi = 0;
1660 1.1 christos
1661 1.1 christos switch (token) {
1662 1.1 christos case STARTS:
1663 1.1 christos token = next_token(&val, NULL, cfile);
1664 1.1 christos if (token == NUMBER) {
1665 1.1 christos ia->starts = atoi(val);
1666 1.1 christos } else {
1667 1.1 christos parse_warn(cfile, "Expecting a number.");
1668 1.1 christos skip_to_semi(cfile);
1669 1.1 christos no_semi = 1;
1670 1.1 christos }
1671 1.1 christos break;
1672 1.1 christos
1673 1.1 christos case RENEW:
1674 1.1 christos token = next_token(&val, NULL, cfile);
1675 1.1 christos if (token == NUMBER) {
1676 1.1 christos ia->renew = atoi(val);
1677 1.1 christos } else {
1678 1.1 christos parse_warn(cfile, "Expecting a number.");
1679 1.1 christos skip_to_semi(cfile);
1680 1.1 christos no_semi = 1;
1681 1.1 christos }
1682 1.1 christos break;
1683 1.1 christos
1684 1.1 christos case REBIND:
1685 1.1 christos token = next_token(&val, NULL, cfile);
1686 1.1 christos if (token == NUMBER) {
1687 1.1 christos ia->rebind = atoi(val);
1688 1.1 christos } else {
1689 1.1 christos parse_warn(cfile, "Expecting a number.");
1690 1.1 christos skip_to_semi(cfile);
1691 1.1 christos no_semi = 1;
1692 1.1 christos }
1693 1.1 christos break;
1694 1.1 christos
1695 1.1 christos case IAADDR:
1696 1.1 christos *addr = parse_client6_iaaddr_statement(cfile);
1697 1.1 christos
1698 1.1 christos if (*addr != NULL)
1699 1.1 christos addr = &(*addr)->next;
1700 1.1 christos
1701 1.1 christos no_semi = 1;
1702 1.1 christos
1703 1.1 christos break;
1704 1.1 christos
1705 1.1 christos case OPTION:
1706 1.1 christos if (parse_option_decl(&oc, cfile)) {
1707 1.1 christos save_option(oc->option->universe,
1708 1.1 christos ia->options, oc);
1709 1.1 christos option_cache_dereference(&oc, MDL);
1710 1.1 christos }
1711 1.1 christos no_semi = 1;
1712 1.1 christos break;
1713 1.1 christos
1714 1.1 christos default:
1715 1.1 christos parse_warn(cfile, "Unexpected token.");
1716 1.1 christos no_semi = 1;
1717 1.1 christos skip_to_semi(cfile);
1718 1.1 christos break;
1719 1.1 christos }
1720 1.1 christos
1721 1.1 christos if (!no_semi)
1722 1.1 christos parse_semi(cfile);
1723 1.1 christos
1724 1.1 christos token = next_token(&val, NULL, cfile);
1725 1.1 christos
1726 1.1 christos if (token == END_OF_FILE) {
1727 1.1 christos parse_warn(cfile, "Unexpected end of file.");
1728 1.1 christos break;
1729 1.1 christos }
1730 1.1 christos }
1731 1.1 christos
1732 1.1 christos return ia;
1733 1.1 christos }
1734 1.1 christos #endif /* DHCPv6 */
1735 1.1 christos
1736 1.1 christos /* Parse an ia_ta object from the client lease.
1737 1.1 christos */
1738 1.1 christos #ifdef DHCPv6
1739 1.1 christos static struct dhc6_ia *
1740 1.1 christos parse_client6_ia_ta_statement(struct parse *cfile)
1741 1.1 christos {
1742 1.1 christos struct option_cache *oc = NULL;
1743 1.1 christos struct dhc6_ia *ia;
1744 1.1 christos struct dhc6_addr **addr;
1745 1.1 christos const char *val;
1746 1.1 christos int token, no_semi, len;
1747 1.1 christos u_int8_t buf[5];
1748 1.1 christos
1749 1.1 christos ia = dmalloc(sizeof(*ia), MDL);
1750 1.1 christos if (ia == NULL) {
1751 1.1 christos parse_warn(cfile, "Out of memory allocating IA_TA state.");
1752 1.1 christos skip_to_semi(cfile);
1753 1.1 christos return NULL;
1754 1.1 christos }
1755 1.1 christos ia->ia_type = D6O_IA_TA;
1756 1.1 christos
1757 1.1 christos /* Get IAID. */
1758 1.1 christos len = parse_X(cfile, buf, 5);
1759 1.1 christos if (len == 4) {
1760 1.1 christos memcpy(ia->iaid, buf, 4);
1761 1.1 christos } else {
1762 1.1 christos parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1763 1.1 christos skip_to_semi(cfile);
1764 1.1 christos dfree(ia, MDL);
1765 1.1 christos return NULL;
1766 1.1 christos }
1767 1.1 christos
1768 1.1 christos token = next_token(NULL, NULL, cfile);
1769 1.1 christos if (token != LBRACE) {
1770 1.1 christos parse_warn(cfile, "Expecting open curly brace.");
1771 1.1 christos skip_to_semi(cfile);
1772 1.1 christos dfree(ia, MDL);
1773 1.1 christos return NULL;
1774 1.1 christos }
1775 1.1 christos
1776 1.1 christos option_state_allocate(&ia->options, MDL);
1777 1.1 christos if (ia->options == NULL) {
1778 1.1 christos parse_warn(cfile, "Unable to allocate option state.");
1779 1.1 christos skip_to_rbrace(cfile, 1);
1780 1.1 christos dfree(ia, MDL);
1781 1.1 christos return NULL;
1782 1.1 christos }
1783 1.1 christos
1784 1.1 christos addr = &ia->addrs;
1785 1.1 christos token = next_token(&val, NULL, cfile);
1786 1.1 christos while (token != RBRACE) {
1787 1.1 christos no_semi = 0;
1788 1.1 christos
1789 1.1 christos switch (token) {
1790 1.1 christos case STARTS:
1791 1.1 christos token = next_token(&val, NULL, cfile);
1792 1.1 christos if (token == NUMBER) {
1793 1.1 christos ia->starts = atoi(val);
1794 1.1 christos } else {
1795 1.1 christos parse_warn(cfile, "Expecting a number.");
1796 1.1 christos skip_to_semi(cfile);
1797 1.1 christos no_semi = 1;
1798 1.1 christos }
1799 1.1 christos break;
1800 1.1 christos
1801 1.1 christos /* No RENEW or REBIND */
1802 1.1 christos
1803 1.1 christos case IAADDR:
1804 1.1 christos *addr = parse_client6_iaaddr_statement(cfile);
1805 1.1 christos
1806 1.1 christos if (*addr != NULL)
1807 1.1 christos addr = &(*addr)->next;
1808 1.1 christos
1809 1.1 christos no_semi = 1;
1810 1.1 christos
1811 1.1 christos break;
1812 1.1 christos
1813 1.1 christos case OPTION:
1814 1.1 christos if (parse_option_decl(&oc, cfile)) {
1815 1.1 christos save_option(oc->option->universe,
1816 1.1 christos ia->options, oc);
1817 1.1 christos option_cache_dereference(&oc, MDL);
1818 1.1 christos }
1819 1.1 christos no_semi = 1;
1820 1.1 christos break;
1821 1.1 christos
1822 1.1 christos default:
1823 1.1 christos parse_warn(cfile, "Unexpected token.");
1824 1.1 christos no_semi = 1;
1825 1.1 christos skip_to_semi(cfile);
1826 1.1 christos break;
1827 1.1 christos }
1828 1.1 christos
1829 1.1 christos if (!no_semi)
1830 1.1 christos parse_semi(cfile);
1831 1.1 christos
1832 1.1 christos token = next_token(&val, NULL, cfile);
1833 1.1 christos
1834 1.1 christos if (token == END_OF_FILE) {
1835 1.1 christos parse_warn(cfile, "Unexpected end of file.");
1836 1.1 christos break;
1837 1.1 christos }
1838 1.1 christos }
1839 1.1 christos
1840 1.1 christos return ia;
1841 1.1 christos }
1842 1.1 christos #endif /* DHCPv6 */
1843 1.1 christos
1844 1.1 christos /* Parse an ia_pd object from the client lease.
1845 1.1 christos */
1846 1.1 christos #ifdef DHCPv6
1847 1.1 christos static struct dhc6_ia *
1848 1.1 christos parse_client6_ia_pd_statement(struct parse *cfile)
1849 1.1 christos {
1850 1.1 christos struct option_cache *oc = NULL;
1851 1.1 christos struct dhc6_ia *ia;
1852 1.1 christos struct dhc6_addr **pref;
1853 1.1 christos const char *val;
1854 1.1 christos int token, no_semi, len;
1855 1.1 christos u_int8_t buf[5];
1856 1.1 christos
1857 1.1 christos ia = dmalloc(sizeof(*ia), MDL);
1858 1.1 christos if (ia == NULL) {
1859 1.1 christos parse_warn(cfile, "Out of memory allocating IA_PD state.");
1860 1.1 christos skip_to_semi(cfile);
1861 1.1 christos return NULL;
1862 1.1 christos }
1863 1.1 christos ia->ia_type = D6O_IA_PD;
1864 1.1 christos
1865 1.1 christos /* Get IAID. */
1866 1.1 christos len = parse_X(cfile, buf, 5);
1867 1.1 christos if (len == 4) {
1868 1.1 christos memcpy(ia->iaid, buf, 4);
1869 1.1 christos } else {
1870 1.1 christos parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1871 1.1 christos skip_to_semi(cfile);
1872 1.1 christos dfree(ia, MDL);
1873 1.1 christos return NULL;
1874 1.1 christos }
1875 1.1 christos
1876 1.1 christos token = next_token(NULL, NULL, cfile);
1877 1.1 christos if (token != LBRACE) {
1878 1.1 christos parse_warn(cfile, "Expecting open curly brace.");
1879 1.1 christos skip_to_semi(cfile);
1880 1.1 christos dfree(ia, MDL);
1881 1.1 christos return NULL;
1882 1.1 christos }
1883 1.1 christos
1884 1.1 christos option_state_allocate(&ia->options, MDL);
1885 1.1 christos if (ia->options == NULL) {
1886 1.1 christos parse_warn(cfile, "Unable to allocate option state.");
1887 1.1 christos skip_to_rbrace(cfile, 1);
1888 1.1 christos dfree(ia, MDL);
1889 1.1 christos return NULL;
1890 1.1 christos }
1891 1.1 christos
1892 1.1 christos pref = &ia->addrs;
1893 1.1 christos token = next_token(&val, NULL, cfile);
1894 1.1 christos while (token != RBRACE) {
1895 1.1 christos no_semi = 0;
1896 1.1 christos
1897 1.1 christos switch (token) {
1898 1.1 christos case STARTS:
1899 1.1 christos token = next_token(&val, NULL, cfile);
1900 1.1 christos if (token == NUMBER) {
1901 1.1 christos ia->starts = atoi(val);
1902 1.1 christos } else {
1903 1.1 christos parse_warn(cfile, "Expecting a number.");
1904 1.1 christos skip_to_semi(cfile);
1905 1.1 christos no_semi = 1;
1906 1.1 christos }
1907 1.1 christos break;
1908 1.1 christos
1909 1.1 christos case RENEW:
1910 1.1 christos token = next_token(&val, NULL, cfile);
1911 1.1 christos if (token == NUMBER) {
1912 1.1 christos ia->renew = atoi(val);
1913 1.1 christos } else {
1914 1.1 christos parse_warn(cfile, "Expecting a number.");
1915 1.1 christos skip_to_semi(cfile);
1916 1.1 christos no_semi = 1;
1917 1.1 christos }
1918 1.1 christos break;
1919 1.1 christos
1920 1.1 christos case REBIND:
1921 1.1 christos token = next_token(&val, NULL, cfile);
1922 1.1 christos if (token == NUMBER) {
1923 1.1 christos ia->rebind = atoi(val);
1924 1.1 christos } else {
1925 1.1 christos parse_warn(cfile, "Expecting a number.");
1926 1.1 christos skip_to_semi(cfile);
1927 1.1 christos no_semi = 1;
1928 1.1 christos }
1929 1.1 christos break;
1930 1.1 christos
1931 1.1 christos case IAPREFIX:
1932 1.1 christos *pref = parse_client6_iaprefix_statement(cfile);
1933 1.1 christos
1934 1.1 christos if (*pref != NULL)
1935 1.1 christos pref = &(*pref)->next;
1936 1.1 christos
1937 1.1 christos no_semi = 1;
1938 1.1 christos
1939 1.1 christos break;
1940 1.1 christos
1941 1.1 christos case OPTION:
1942 1.1 christos if (parse_option_decl(&oc, cfile)) {
1943 1.1 christos save_option(oc->option->universe,
1944 1.1 christos ia->options, oc);
1945 1.1 christos option_cache_dereference(&oc, MDL);
1946 1.1 christos }
1947 1.1 christos no_semi = 1;
1948 1.1 christos break;
1949 1.1 christos
1950 1.1 christos default:
1951 1.1 christos parse_warn(cfile, "Unexpected token.");
1952 1.1 christos no_semi = 1;
1953 1.1 christos skip_to_semi(cfile);
1954 1.1 christos break;
1955 1.1 christos }
1956 1.1 christos
1957 1.1 christos if (!no_semi)
1958 1.1 christos parse_semi(cfile);
1959 1.1 christos
1960 1.1 christos token = next_token(&val, NULL, cfile);
1961 1.1 christos
1962 1.1 christos if (token == END_OF_FILE) {
1963 1.1 christos parse_warn(cfile, "Unexpected end of file.");
1964 1.1 christos break;
1965 1.1 christos }
1966 1.1 christos }
1967 1.1 christos
1968 1.1 christos return ia;
1969 1.1 christos }
1970 1.1 christos #endif /* DHCPv6 */
1971 1.1 christos
1972 1.1 christos /* Parse an iaaddr {} structure. */
1973 1.1 christos #ifdef DHCPv6
1974 1.1 christos static struct dhc6_addr *
1975 1.1 christos parse_client6_iaaddr_statement(struct parse *cfile)
1976 1.1 christos {
1977 1.1 christos struct option_cache *oc = NULL;
1978 1.1 christos struct dhc6_addr *addr;
1979 1.1 christos const char *val;
1980 1.1 christos int token, no_semi;
1981 1.1 christos
1982 1.1 christos addr = dmalloc(sizeof(*addr), MDL);
1983 1.1 christos if (addr == NULL) {
1984 1.1 christos parse_warn(cfile, "Unable to allocate IAADDR state.");
1985 1.1 christos skip_to_semi(cfile);
1986 1.1 christos return NULL;
1987 1.1 christos }
1988 1.1 christos
1989 1.1 christos /* Get IP address. */
1990 1.1 christos if (!parse_ip6_addr(cfile, &addr->address)) {
1991 1.1 christos skip_to_semi(cfile);
1992 1.1 christos dfree(addr, MDL);
1993 1.1 christos return NULL;
1994 1.1 christos }
1995 1.1 christos
1996 1.1 christos token = next_token(NULL, NULL, cfile);
1997 1.1 christos if (token != LBRACE) {
1998 1.1 christos parse_warn(cfile, "Expecting open curly bracket.");
1999 1.1 christos skip_to_semi(cfile);
2000 1.1 christos dfree(addr, MDL);
2001 1.1 christos return NULL;
2002 1.1 christos }
2003 1.1 christos
2004 1.1 christos option_state_allocate(&addr->options, MDL);
2005 1.1 christos if (addr->options == NULL) {
2006 1.1 christos parse_warn(cfile, "Unable to allocate option state.");
2007 1.1 christos skip_to_semi(cfile);
2008 1.1 christos dfree(addr, MDL);
2009 1.1 christos return NULL;
2010 1.1 christos }
2011 1.1 christos
2012 1.1 christos token = next_token(&val, NULL, cfile);
2013 1.1 christos while (token != RBRACE) {
2014 1.1 christos no_semi = 0;
2015 1.1 christos
2016 1.1 christos switch (token) {
2017 1.1 christos case STARTS:
2018 1.1 christos token = next_token(&val, NULL, cfile);
2019 1.1 christos if (token == NUMBER) {
2020 1.1 christos addr->starts = atoi(val);
2021 1.1 christos } else {
2022 1.1 christos parse_warn(cfile, "Expecting a number.");
2023 1.1 christos skip_to_semi(cfile);
2024 1.1 christos no_semi = 1;
2025 1.1 christos }
2026 1.1 christos break;
2027 1.1 christos
2028 1.1 christos case PREFERRED_LIFE:
2029 1.1 christos token = next_token(&val, NULL, cfile);
2030 1.1 christos if (token == NUMBER) {
2031 1.1 christos addr->preferred_life = atoi(val);
2032 1.1 christos } else {
2033 1.1 christos parse_warn(cfile, "Expecting a number.");
2034 1.1 christos skip_to_semi(cfile);
2035 1.1 christos no_semi = 1;
2036 1.1 christos }
2037 1.1 christos break;
2038 1.1 christos
2039 1.1 christos case MAX_LIFE:
2040 1.1 christos token = next_token(&val, NULL, cfile);
2041 1.1 christos if (token == NUMBER) {
2042 1.1 christos addr->max_life = atoi(val);
2043 1.1 christos } else {
2044 1.1 christos parse_warn(cfile, "Expecting a number.");
2045 1.1 christos skip_to_semi(cfile);
2046 1.1 christos no_semi = 1;
2047 1.1 christos }
2048 1.1 christos break;
2049 1.1 christos
2050 1.1 christos case OPTION:
2051 1.1 christos if (parse_option_decl(&oc, cfile)) {
2052 1.1 christos save_option(oc->option->universe,
2053 1.1 christos addr->options, oc);
2054 1.1 christos option_cache_dereference(&oc, MDL);
2055 1.1 christos }
2056 1.1 christos no_semi = 1;
2057 1.1 christos break;
2058 1.1 christos
2059 1.1 christos default:
2060 1.1 christos parse_warn(cfile, "Unexpected token.");
2061 1.1 christos skip_to_rbrace(cfile, 1);
2062 1.1 christos no_semi = 1;
2063 1.1 christos break;
2064 1.1 christos }
2065 1.1 christos
2066 1.1 christos if (!no_semi)
2067 1.1 christos parse_semi(cfile);
2068 1.1 christos
2069 1.1 christos token = next_token(&val, NULL, cfile);
2070 1.1 christos if (token == END_OF_FILE) {
2071 1.1 christos parse_warn(cfile, "Unexpected end of file.");
2072 1.1 christos break;
2073 1.1 christos }
2074 1.1 christos }
2075 1.1 christos
2076 1.1 christos return addr;
2077 1.1 christos }
2078 1.1 christos #endif /* DHCPv6 */
2079 1.1 christos
2080 1.1 christos /* Parse an iaprefix {} structure. */
2081 1.1 christos #ifdef DHCPv6
2082 1.1 christos static struct dhc6_addr *
2083 1.1 christos parse_client6_iaprefix_statement(struct parse *cfile)
2084 1.1 christos {
2085 1.1 christos struct option_cache *oc = NULL;
2086 1.1 christos struct dhc6_addr *pref;
2087 1.1 christos const char *val;
2088 1.1 christos int token, no_semi;
2089 1.1 christos
2090 1.1 christos pref = dmalloc(sizeof(*pref), MDL);
2091 1.1 christos if (pref == NULL) {
2092 1.1 christos parse_warn(cfile, "Unable to allocate IAPREFIX state.");
2093 1.1 christos skip_to_semi(cfile);
2094 1.1 christos return NULL;
2095 1.1 christos }
2096 1.1 christos
2097 1.1 christos /* Get IP prefix. */
2098 1.1 christos if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
2099 1.1 christos skip_to_semi(cfile);
2100 1.1 christos dfree(pref, MDL);
2101 1.1 christos return NULL;
2102 1.1 christos }
2103 1.1 christos
2104 1.1 christos token = next_token(NULL, NULL, cfile);
2105 1.1 christos if (token != LBRACE) {
2106 1.1 christos parse_warn(cfile, "Expecting open curly bracket.");
2107 1.1 christos skip_to_semi(cfile);
2108 1.1 christos dfree(pref, MDL);
2109 1.1 christos return NULL;
2110 1.1 christos }
2111 1.1 christos
2112 1.1 christos option_state_allocate(&pref->options, MDL);
2113 1.1 christos if (pref->options == NULL) {
2114 1.1 christos parse_warn(cfile, "Unable to allocate option state.");
2115 1.1 christos skip_to_semi(cfile);
2116 1.1 christos dfree(pref, MDL);
2117 1.1 christos return NULL;
2118 1.1 christos }
2119 1.1 christos
2120 1.1 christos token = next_token(&val, NULL, cfile);
2121 1.1 christos while (token != RBRACE) {
2122 1.1 christos no_semi = 0;
2123 1.1 christos
2124 1.1 christos switch (token) {
2125 1.1 christos case STARTS:
2126 1.1 christos token = next_token(&val, NULL, cfile);
2127 1.1 christos if (token == NUMBER) {
2128 1.1 christos pref->starts = atoi(val);
2129 1.1 christos } else {
2130 1.1 christos parse_warn(cfile, "Expecting a number.");
2131 1.1 christos skip_to_semi(cfile);
2132 1.1 christos no_semi = 1;
2133 1.1 christos }
2134 1.1 christos break;
2135 1.1 christos
2136 1.1 christos case PREFERRED_LIFE:
2137 1.1 christos token = next_token(&val, NULL, cfile);
2138 1.1 christos if (token == NUMBER) {
2139 1.1 christos pref->preferred_life = atoi(val);
2140 1.1 christos } else {
2141 1.1 christos parse_warn(cfile, "Expecting a number.");
2142 1.1 christos skip_to_semi(cfile);
2143 1.1 christos no_semi = 1;
2144 1.1 christos }
2145 1.1 christos break;
2146 1.1 christos
2147 1.1 christos case MAX_LIFE:
2148 1.1 christos token = next_token(&val, NULL, cfile);
2149 1.1 christos if (token == NUMBER) {
2150 1.1 christos pref->max_life = atoi(val);
2151 1.1 christos } else {
2152 1.1 christos parse_warn(cfile, "Expecting a number.");
2153 1.1 christos skip_to_semi(cfile);
2154 1.1 christos no_semi = 1;
2155 1.1 christos }
2156 1.1 christos break;
2157 1.1 christos
2158 1.1 christos case OPTION:
2159 1.1 christos if (parse_option_decl(&oc, cfile)) {
2160 1.1 christos save_option(oc->option->universe,
2161 1.1 christos pref->options, oc);
2162 1.1 christos option_cache_dereference(&oc, MDL);
2163 1.1 christos }
2164 1.1 christos no_semi = 1;
2165 1.1 christos break;
2166 1.1 christos
2167 1.1 christos default:
2168 1.1 christos parse_warn(cfile, "Unexpected token.");
2169 1.1 christos skip_to_rbrace(cfile, 1);
2170 1.1 christos no_semi = 1;
2171 1.1 christos break;
2172 1.1 christos }
2173 1.1 christos
2174 1.1 christos if (!no_semi)
2175 1.1 christos parse_semi(cfile);
2176 1.1 christos
2177 1.1 christos token = next_token(&val, NULL, cfile);
2178 1.1 christos if (token == END_OF_FILE) {
2179 1.1 christos parse_warn(cfile, "Unexpected end of file.");
2180 1.1 christos break;
2181 1.1 christos }
2182 1.1 christos }
2183 1.1 christos
2184 1.1 christos return pref;
2185 1.1 christos }
2186 1.1 christos #endif /* DHCPv6 */
2187 1.1 christos
2188 1.1 christos void parse_string_list (cfile, lp, multiple)
2189 1.1 christos struct parse *cfile;
2190 1.1 christos struct string_list **lp;
2191 1.1 christos int multiple;
2192 1.1 christos {
2193 1.1 christos int token;
2194 1.1 christos const char *val;
2195 1.1 christos struct string_list *cur, *tmp;
2196 1.1 christos
2197 1.1 christos /* Find the last medium in the media list. */
2198 1.1 christos if (*lp) {
2199 1.1 christos for (cur = *lp; cur -> next; cur = cur -> next)
2200 1.1 christos ;
2201 1.1 christos } else {
2202 1.1 christos cur = (struct string_list *)0;
2203 1.1 christos }
2204 1.1 christos
2205 1.1 christos do {
2206 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
2207 1.1 christos if (token != STRING) {
2208 1.1 christos parse_warn (cfile, "Expecting media options.");
2209 1.1 christos skip_to_semi (cfile);
2210 1.1 christos return;
2211 1.1 christos }
2212 1.1 christos
2213 1.1 christos tmp = ((struct string_list *)
2214 1.1 christos dmalloc (strlen (val) + sizeof (struct string_list),
2215 1.1 christos MDL));
2216 1.1 christos if (!tmp)
2217 1.1 christos log_fatal ("no memory for string list entry.");
2218 1.1 christos
2219 1.1 christos strcpy (tmp -> string, val);
2220 1.1 christos tmp -> next = (struct string_list *)0;
2221 1.1 christos
2222 1.1 christos /* Store this medium at the end of the media list. */
2223 1.1 christos if (cur)
2224 1.1 christos cur -> next = tmp;
2225 1.1 christos else
2226 1.1 christos *lp = tmp;
2227 1.1 christos cur = tmp;
2228 1.1 christos
2229 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
2230 1.1 christos } while (multiple && token == COMMA);
2231 1.1 christos
2232 1.1 christos if (token != SEMI) {
2233 1.1 christos parse_warn (cfile, "expecting semicolon.");
2234 1.1 christos skip_to_semi (cfile);
2235 1.1 christos }
2236 1.1 christos }
2237 1.1 christos
2238 1.1 christos void parse_reject_statement (cfile, config)
2239 1.1 christos struct parse *cfile;
2240 1.1 christos struct client_config *config;
2241 1.1 christos {
2242 1.1 christos int token;
2243 1.1 christos const char *val;
2244 1.1 christos struct iaddrmatch match;
2245 1.1 christos struct iaddrmatchlist *list;
2246 1.1 christos int i;
2247 1.1 christos
2248 1.1 christos do {
2249 1.1 christos if (!parse_ip_addr_with_subnet (cfile, &match)) {
2250 1.1 christos /* no warn: parser will have reported what's wrong */
2251 1.1 christos skip_to_semi (cfile);
2252 1.1 christos return;
2253 1.1 christos }
2254 1.1 christos
2255 1.1 christos /* check mask is not all zeros (because that would
2256 1.1 christos * reject EVERY address). This check could be
2257 1.1 christos * simplified if we assume that the mask *always*
2258 1.1 christos * represents a prefix .. but perhaps it might be
2259 1.1 christos * useful to have a mask which is not a proper prefix
2260 1.1 christos * (perhaps for ipv6?). The following is almost as
2261 1.1 christos * efficient as inspection of match.mask.iabuf[0] when
2262 1.1 christos * it IS a true prefix, and is more general when it is
2263 1.1 christos * not.
2264 1.1 christos */
2265 1.1 christos
2266 1.1 christos for (i=0 ; i < match.mask.len ; i++) {
2267 1.1 christos if (match.mask.iabuf[i]) {
2268 1.1 christos break;
2269 1.1 christos }
2270 1.1 christos }
2271 1.1 christos
2272 1.1 christos if (i == match.mask.len) {
2273 1.1 christos /* oops we found all zeros */
2274 1.1 christos parse_warn(cfile, "zero-length prefix is not permitted "
2275 1.1 christos "for reject statement");
2276 1.1 christos skip_to_semi(cfile);
2277 1.1 christos return;
2278 1.1 christos }
2279 1.1 christos
2280 1.1 christos list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
2281 1.1 christos if (!list)
2282 1.1 christos log_fatal ("no memory for reject list!");
2283 1.1 christos
2284 1.1 christos list->match = match;
2285 1.1 christos list->next = config->reject_list;
2286 1.1 christos config->reject_list = list;
2287 1.1 christos
2288 1.1 christos token = next_token (&val, (unsigned *)0, cfile);
2289 1.1 christos } while (token == COMMA);
2290 1.1 christos
2291 1.1 christos if (token != SEMI) {
2292 1.1 christos parse_warn (cfile, "expecting semicolon.");
2293 1.1 christos skip_to_semi (cfile);
2294 1.1 christos }
2295 1.1 christos }
2296 1.1 christos
2297 1.1 christos /* allow-deny-keyword :== BOOTP
2298 1.1 christos | BOOTING
2299 1.1 christos | DYNAMIC_BOOTP
2300 1.1 christos | UNKNOWN_CLIENTS */
2301 1.1 christos
2302 1.1 christos int parse_allow_deny (oc, cfile, flag)
2303 1.1 christos struct option_cache **oc;
2304 1.1 christos struct parse *cfile;
2305 1.1 christos int flag;
2306 1.1 christos {
2307 1.1 christos parse_warn (cfile, "allow/deny/ignore not permitted here.");
2308 1.1 christos skip_to_semi (cfile);
2309 1.1 christos return 0;
2310 1.1 christos }
2311 1.1 christos
2312 1.1 christos
2313 1.1 christos
2314 1.1 christos /*!
2315 1.1 christos * \brief Parses an lease-id-format statement
2316 1.1 christos *
2317 1.1 christos * A valid statement looks like this:
2318 1.1 christos *
2319 1.1 christos * lease-id-format :==
2320 1.1 christos * LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ;
2321 1.1 christos *
2322 1.1 christos * This function is used to parse the lease-id-format statement. It sets
2323 1.1 christos * top_level_config.lease_id_format.
2324 1.1 christos *
2325 1.1 christos * \param cfile the current parse file
2326 1.1 christos *
2327 1.1 christos */
2328 1.1 christos void parse_lease_id_format (struct parse *cfile)
2329 1.1 christos {
2330 1.1 christos enum dhcp_token token;
2331 1.1 christos const char *val;
2332 1.1 christos
2333 1.1 christos token = next_token(&val, NULL, cfile);
2334 1.1 christos switch(token) {
2335 1.1 christos case TOKEN_OCTAL:
2336 1.1 christos top_level_config.lease_id_format = TOKEN_OCTAL;
2337 1.1 christos break;
2338 1.1 christos case TOKEN_HEX:
2339 1.1 christos top_level_config.lease_id_format = TOKEN_HEX;
2340 1.1 christos break;
2341 1.1 christos default:
2342 1.1 christos parse_warn(cfile, "lease-id-format is invalid: "
2343 1.1 christos " it must be octal or hex.");
2344 1.1 christos skip_to_semi(cfile);
2345 1.1 christos return;
2346 1.1 christos }
2347 1.1 christos
2348 1.1 christos log_debug("lease_id_format is: %s",
2349 1.1 christos (top_level_config.lease_id_format == TOKEN_OCTAL
2350 1.1 christos ? "octal" : "hex"));
2351 1.1 christos
2352 1.1 christos }
2353