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