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