1*8952c965Shenning /* $OpenBSD: confpars.c,v 1.9 2004/05/08 06:11:53 henning Exp $ */ 2e853bc5dShenning 3e853bc5dShenning /* 4e853bc5dShenning * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. 5e853bc5dShenning * All rights reserved. 6e853bc5dShenning * 7e853bc5dShenning * Redistribution and use in source and binary forms, with or without 8e853bc5dShenning * modification, are permitted provided that the following conditions 9e853bc5dShenning * are met: 10e853bc5dShenning * 11e853bc5dShenning * 1. Redistributions of source code must retain the above copyright 12e853bc5dShenning * notice, this list of conditions and the following disclaimer. 13e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright 14e853bc5dShenning * notice, this list of conditions and the following disclaimer in the 15e853bc5dShenning * documentation and/or other materials provided with the distribution. 16e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names 17e853bc5dShenning * of its contributors may be used to endorse or promote products derived 18e853bc5dShenning * from this software without specific prior written permission. 19e853bc5dShenning * 20e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 21e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 25e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32e853bc5dShenning * SUCH DAMAGE. 33e853bc5dShenning * 34e853bc5dShenning * This software has been written for the Internet Software Consortium 35e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 36e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium, 37e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie 38e853bc5dShenning * Enterprises, see ``http://www.vix.com''. 39e853bc5dShenning */ 40e853bc5dShenning 41e853bc5dShenning #include "dhcpd.h" 42e853bc5dShenning #include "dhctoken.h" 43e853bc5dShenning 44fbc5e94dShenning static time_t parsed_time; 45e853bc5dShenning 46e853bc5dShenning /* conf-file :== parameters declarations EOF 47e853bc5dShenning parameters :== <nil> | parameter | parameters parameter 48e853bc5dShenning declarations :== <nil> | declaration | declarations declaration */ 49e853bc5dShenning 506a467ce1Sderaadt int 516a467ce1Sderaadt readconf(void) 52e853bc5dShenning { 53e853bc5dShenning FILE *cfile; 54e853bc5dShenning char *val; 55e853bc5dShenning int token; 56e853bc5dShenning int declaration = 0; 57e853bc5dShenning 58e853bc5dShenning new_parse(path_dhcpd_conf); 59e853bc5dShenning 60e853bc5dShenning /* Set up the initial dhcp option universe. */ 61e853bc5dShenning initialize_universes(); 62e853bc5dShenning 63e853bc5dShenning /* Set up the global defaults... */ 64e853bc5dShenning root_group.default_lease_time = 43200; /* 12 hours. */ 65e853bc5dShenning root_group.max_lease_time = 86400; /* 24 hours. */ 66e853bc5dShenning root_group.bootp_lease_cutoff = MAX_TIME; 67e853bc5dShenning root_group.boot_unknown_clients = 1; 68e853bc5dShenning root_group.allow_bootp = 1; 69e853bc5dShenning root_group.allow_booting = 1; 70e853bc5dShenning root_group.authoritative = 1; 71e853bc5dShenning 726a467ce1Sderaadt if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL) 73e853bc5dShenning error("Can't open %s: %m", path_dhcpd_conf); 74e853bc5dShenning 75e853bc5dShenning do { 76e853bc5dShenning token = peek_token(&val, cfile); 77e853bc5dShenning if (token == EOF) 78e853bc5dShenning break; 79e853bc5dShenning declaration = parse_statement(cfile, &root_group, 80e853bc5dShenning ROOT_GROUP, 816a467ce1Sderaadt NULL, 82e853bc5dShenning declaration); 83e853bc5dShenning } while (1); 84e853bc5dShenning token = next_token(&val, cfile); /* Clear the peek buffer */ 85e853bc5dShenning fclose(cfile); 86e853bc5dShenning 87e853bc5dShenning return !warnings_occurred; 88e853bc5dShenning } 89e853bc5dShenning 90e853bc5dShenning /* lease-file :== lease-declarations EOF 91e853bc5dShenning lease-statments :== <nil> 92e853bc5dShenning | lease-declaration 936a467ce1Sderaadt | lease-declarations lease-declaration 946a467ce1Sderaadt */ 956a467ce1Sderaadt void 966a467ce1Sderaadt read_leases(void) 97e853bc5dShenning { 98e853bc5dShenning FILE *cfile; 99e853bc5dShenning char *val; 100e853bc5dShenning int token; 101e853bc5dShenning 102e853bc5dShenning new_parse(path_dhcpd_db); 103e853bc5dShenning 104e853bc5dShenning /* Open the lease file. If we can't open it, fail. The reason 105e853bc5dShenning for this is that although on initial startup, the absence of 106e853bc5dShenning a lease file is perfectly benign, if dhcpd has been running 107e853bc5dShenning and this file is absent, it means that dhcpd tried and failed 108e853bc5dShenning to rewrite the lease database. If we proceed and the 109e853bc5dShenning problem which caused the rewrite to fail has been fixed, but no 110e853bc5dShenning human has corrected the database problem, then we are left 111e853bc5dShenning thinking that no leases have been assigned to anybody, which 112e853bc5dShenning could create severe network chaos. */ 113e853bc5dShenning if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) { 114e853bc5dShenning warn("Can't open lease database %s: %m -- %s", 115e853bc5dShenning path_dhcpd_db, 116e853bc5dShenning "check for failed database rewrite attempt!"); 117e853bc5dShenning warn("Please read the dhcpd.leases manual page if you."); 118e853bc5dShenning error("don't know what to do about this."); } 119e853bc5dShenning 120e853bc5dShenning do { 121e853bc5dShenning token = next_token(&val, cfile); 122e853bc5dShenning if (token == EOF) 123e853bc5dShenning break; 124e853bc5dShenning if (token != LEASE) { 125e853bc5dShenning warn("Corrupt lease file - possible data loss!"); 126e853bc5dShenning skip_to_semi(cfile); 127e853bc5dShenning } else { 128e853bc5dShenning struct lease *lease; 129e853bc5dShenning lease = parse_lease_declaration(cfile); 130e853bc5dShenning if (lease) 131e853bc5dShenning enter_lease(lease); 132e853bc5dShenning else 133e853bc5dShenning parse_warn("possibly corrupt lease file"); 134e853bc5dShenning } 135e853bc5dShenning 136e853bc5dShenning } while (1); 137e853bc5dShenning fclose(cfile); 138e853bc5dShenning } 139e853bc5dShenning 140e853bc5dShenning /* statement :== parameter | declaration 141e853bc5dShenning 142e853bc5dShenning parameter :== timestamp 143e853bc5dShenning | DEFAULT_LEASE_TIME lease_time 144e853bc5dShenning | MAX_LEASE_TIME lease_time 145e853bc5dShenning | DYNAMIC_BOOTP_LEASE_CUTOFF date 146e853bc5dShenning | DYNAMIC_BOOTP_LEASE_LENGTH lease_time 147e853bc5dShenning | BOOT_UNKNOWN_CLIENTS boolean 148e853bc5dShenning | ONE_LEASE_PER_CLIENT boolean 149e853bc5dShenning | GET_LEASE_HOSTNAMES boolean 150e853bc5dShenning | USE_HOST_DECL_NAME boolean 151e853bc5dShenning | NEXT_SERVER ip-addr-or-hostname SEMI 152e853bc5dShenning | option_parameter 153e853bc5dShenning | SERVER-IDENTIFIER ip-addr-or-hostname SEMI 154e853bc5dShenning | FILENAME string-parameter 155e853bc5dShenning | SERVER_NAME string-parameter 156e853bc5dShenning | hardware-parameter 157e853bc5dShenning | fixed-address-parameter 158e853bc5dShenning | ALLOW allow-deny-keyword 159e853bc5dShenning | DENY allow-deny-keyword 160e853bc5dShenning | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean 161e853bc5dShenning 162e853bc5dShenning declaration :== host-declaration 163e853bc5dShenning | group-declaration 164e853bc5dShenning | shared-network-declaration 165e853bc5dShenning | subnet-declaration 166e853bc5dShenning | VENDOR_CLASS class-declaration 167e853bc5dShenning | USER_CLASS class-declaration 168e853bc5dShenning | RANGE address-range-declaration */ 169e853bc5dShenning 170e853bc5dShenning int parse_statement(cfile, group, type, host_decl, declaration) 171e853bc5dShenning FILE *cfile; 172e853bc5dShenning struct group *group; 173e853bc5dShenning int type; 174e853bc5dShenning struct host_decl *host_decl; 175e853bc5dShenning int declaration; 176e853bc5dShenning { 177e853bc5dShenning int token; 178e853bc5dShenning char *val; 179e853bc5dShenning struct shared_network *share; 180e853bc5dShenning char *t, *n; 181e853bc5dShenning struct tree *tree; 182e853bc5dShenning struct tree_cache *cache; 183e853bc5dShenning struct hardware hardware; 184e853bc5dShenning 185e853bc5dShenning switch (next_token(&val, cfile)) { 186e853bc5dShenning case HOST: 187e853bc5dShenning if (type != HOST_DECL) 188e853bc5dShenning parse_host_declaration(cfile, group); 189e853bc5dShenning else { 190e853bc5dShenning parse_warn("host declarations not allowed here."); 191e853bc5dShenning skip_to_semi(cfile); 192e853bc5dShenning } 193e853bc5dShenning return 1; 194e853bc5dShenning 195e853bc5dShenning case GROUP: 196e853bc5dShenning if (type != HOST_DECL) 197e853bc5dShenning parse_group_declaration(cfile, group); 198e853bc5dShenning else { 199e853bc5dShenning parse_warn("host declarations not allowed here."); 200e853bc5dShenning skip_to_semi(cfile); 201e853bc5dShenning } 202e853bc5dShenning return 1; 203e853bc5dShenning 204e853bc5dShenning case TIMESTAMP: 205e853bc5dShenning parsed_time = parse_timestamp(cfile); 206e853bc5dShenning break; 207e853bc5dShenning 208e853bc5dShenning case SHARED_NETWORK: 209e853bc5dShenning if (type == SHARED_NET_DECL || 210e853bc5dShenning type == HOST_DECL || 211e853bc5dShenning type == SUBNET_DECL) { 212e853bc5dShenning parse_warn("shared-network parameters not %s.", 213e853bc5dShenning "allowed here"); 214e853bc5dShenning skip_to_semi(cfile); 215e853bc5dShenning break; 216e853bc5dShenning } 217e853bc5dShenning 218e853bc5dShenning parse_shared_net_declaration(cfile, group); 219e853bc5dShenning return 1; 220e853bc5dShenning 221e853bc5dShenning case SUBNET: 222e853bc5dShenning if (type == HOST_DECL || type == SUBNET_DECL) { 223e853bc5dShenning parse_warn("subnet declarations not allowed here."); 224e853bc5dShenning skip_to_semi(cfile); 225e853bc5dShenning return 1; 226e853bc5dShenning } 227e853bc5dShenning 228e853bc5dShenning /* If we're in a subnet declaration, just do the parse. */ 229e853bc5dShenning if (group->shared_network) { 230e853bc5dShenning parse_subnet_declaration(cfile, 231e853bc5dShenning group->shared_network); 232e853bc5dShenning break; 233e853bc5dShenning } 234e853bc5dShenning 235e853bc5dShenning /* Otherwise, cons up a fake shared network structure 236e853bc5dShenning and populate it with the lone subnet... */ 237e853bc5dShenning 238e853bc5dShenning share = new_shared_network("parse_statement"); 239e853bc5dShenning if (!share) 240e853bc5dShenning error("No memory for shared subnet"); 241e853bc5dShenning share->group = clone_group(group, "parse_statement:subnet"); 242e853bc5dShenning share->group->shared_network = share; 243e853bc5dShenning 244e853bc5dShenning parse_subnet_declaration(cfile, share); 245e853bc5dShenning 246e853bc5dShenning /* share->subnets is the subnet we just parsed. */ 247e853bc5dShenning if (share->subnets) { 248e853bc5dShenning share->interface = 249e853bc5dShenning share->subnets->interface; 250e853bc5dShenning 251e853bc5dShenning /* Make the shared network name from network number. */ 252e853bc5dShenning n = piaddr(share->subnets->net); 253e853bc5dShenning t = malloc(strlen(n) + 1); 254e853bc5dShenning if (!t) 255e853bc5dShenning error("no memory for subnet name"); 256e853bc5dShenning strlcpy(t, n, (strlen(n) + 1)); 257e853bc5dShenning share->name = t; 258e853bc5dShenning 259e853bc5dShenning /* Copy the authoritative parameter from the subnet, 260e853bc5dShenning since there is no opportunity to declare it here. */ 261e853bc5dShenning share->group->authoritative = 262e853bc5dShenning share->subnets->group->authoritative; 263e853bc5dShenning enter_shared_network(share); 264e853bc5dShenning } 265e853bc5dShenning return 1; 266e853bc5dShenning 267e853bc5dShenning case VENDOR_CLASS: 268e853bc5dShenning parse_class_declaration(cfile, group, 0); 269e853bc5dShenning return 1; 270e853bc5dShenning 271e853bc5dShenning case USER_CLASS: 272e853bc5dShenning parse_class_declaration(cfile, group, 1); 273e853bc5dShenning return 1; 274e853bc5dShenning 275e853bc5dShenning case DEFAULT_LEASE_TIME: 276e853bc5dShenning parse_lease_time(cfile, &group->default_lease_time); 277e853bc5dShenning break; 278e853bc5dShenning 279e853bc5dShenning case MAX_LEASE_TIME: 280e853bc5dShenning parse_lease_time(cfile, &group->max_lease_time); 281e853bc5dShenning break; 282e853bc5dShenning 283e853bc5dShenning case DYNAMIC_BOOTP_LEASE_CUTOFF: 284e853bc5dShenning group->bootp_lease_cutoff = parse_date(cfile); 285e853bc5dShenning break; 286e853bc5dShenning 287e853bc5dShenning case DYNAMIC_BOOTP_LEASE_LENGTH: 288e853bc5dShenning parse_lease_time(cfile, &group->bootp_lease_length); 289e853bc5dShenning break; 290e853bc5dShenning 291e853bc5dShenning case BOOT_UNKNOWN_CLIENTS: 292e853bc5dShenning if (type == HOST_DECL) 293e853bc5dShenning parse_warn("boot-unknown-clients not allowed here."); 294e853bc5dShenning group->boot_unknown_clients = parse_boolean(cfile); 295e853bc5dShenning break; 296e853bc5dShenning 297e853bc5dShenning case ONE_LEASE_PER_CLIENT: 298e853bc5dShenning if (type == HOST_DECL) 299e853bc5dShenning parse_warn("one-lease-per-client not allowed here."); 300e853bc5dShenning group->one_lease_per_client = parse_boolean(cfile); 301e853bc5dShenning break; 302e853bc5dShenning 303e853bc5dShenning case GET_LEASE_HOSTNAMES: 304e853bc5dShenning if (type == HOST_DECL) 305e853bc5dShenning parse_warn("get-lease-hostnames not allowed here."); 306e853bc5dShenning group->get_lease_hostnames = parse_boolean(cfile); 307e853bc5dShenning break; 308e853bc5dShenning 309e853bc5dShenning case ALWAYS_REPLY_RFC1048: 310e853bc5dShenning group->always_reply_rfc1048 = parse_boolean(cfile); 311e853bc5dShenning break; 312e853bc5dShenning 313e853bc5dShenning case USE_HOST_DECL_NAMES: 314e853bc5dShenning if (type == HOST_DECL) 315e853bc5dShenning parse_warn("use-host-decl-names not allowed here."); 316e853bc5dShenning group->use_host_decl_names = parse_boolean(cfile); 317e853bc5dShenning break; 318e853bc5dShenning 319e853bc5dShenning case USE_LEASE_ADDR_FOR_DEFAULT_ROUTE: 320e853bc5dShenning group->use_lease_addr_for_default_route = 321e853bc5dShenning parse_boolean(cfile); 322e853bc5dShenning break; 323e853bc5dShenning 324e853bc5dShenning case TOKEN_NOT: 325e853bc5dShenning token = next_token(&val, cfile); 326e853bc5dShenning switch (token) { 327e853bc5dShenning case AUTHORITATIVE: 328e853bc5dShenning if (type == HOST_DECL) 329e853bc5dShenning parse_warn("authority makes no sense here."); 330e853bc5dShenning group->authoritative = 0; 331e853bc5dShenning parse_semi(cfile); 332e853bc5dShenning break; 333e853bc5dShenning default: 334e853bc5dShenning parse_warn("expecting assertion"); 335e853bc5dShenning skip_to_semi(cfile); 336e853bc5dShenning break; 337e853bc5dShenning } 338e853bc5dShenning break; 339e853bc5dShenning 340e853bc5dShenning case AUTHORITATIVE: 341e853bc5dShenning if (type == HOST_DECL) 342e853bc5dShenning parse_warn("authority makes no sense here."); 343e853bc5dShenning group->authoritative = 1; 344e853bc5dShenning parse_semi(cfile); 345e853bc5dShenning break; 346e853bc5dShenning 347e853bc5dShenning case NEXT_SERVER: 348e853bc5dShenning tree = parse_ip_addr_or_hostname(cfile, 0); 349e853bc5dShenning if (!tree) 350e853bc5dShenning break; 351e853bc5dShenning cache = tree_cache(tree); 352e853bc5dShenning if (!tree_evaluate (cache)) 353e853bc5dShenning error("next-server is not known"); 354e853bc5dShenning group->next_server.len = 4; 355e853bc5dShenning memcpy(group->next_server.iabuf, 356e853bc5dShenning cache->value, group->next_server.len); 357e853bc5dShenning parse_semi(cfile); 358e853bc5dShenning break; 359e853bc5dShenning 360e853bc5dShenning case OPTION: 361e853bc5dShenning parse_option_param(cfile, group); 362e853bc5dShenning break; 363e853bc5dShenning 364e853bc5dShenning case SERVER_IDENTIFIER: 365e853bc5dShenning tree = parse_ip_addr_or_hostname(cfile, 0); 366e853bc5dShenning if (!tree) 367e853bc5dShenning return declaration; 368cca1f910Shenning group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree); 369e853bc5dShenning token = next_token(&val, cfile); 370e853bc5dShenning break; 371e853bc5dShenning 372e853bc5dShenning case FILENAME: 373e853bc5dShenning group->filename = parse_string(cfile); 374e853bc5dShenning break; 375e853bc5dShenning 376e853bc5dShenning case SERVER_NAME: 377e853bc5dShenning group->server_name = parse_string(cfile); 378e853bc5dShenning break; 379e853bc5dShenning 380e853bc5dShenning case HARDWARE: 381e853bc5dShenning parse_hardware_param(cfile, &hardware); 382e853bc5dShenning if (host_decl) 383e853bc5dShenning host_decl->interface = hardware; 384e853bc5dShenning else 385e853bc5dShenning parse_warn("hardware address parameter %s", 386e853bc5dShenning "not allowed here."); 387e853bc5dShenning break; 388e853bc5dShenning 389e853bc5dShenning case FIXED_ADDR: 390e853bc5dShenning cache = parse_fixed_addr_param(cfile); 391e853bc5dShenning if (host_decl) 392e853bc5dShenning host_decl->fixed_addr = cache; 393e853bc5dShenning else 394e853bc5dShenning parse_warn("fixed-address parameter not %s", 395e853bc5dShenning "allowed here."); 396e853bc5dShenning break; 397e853bc5dShenning 398e853bc5dShenning case RANGE: 399e853bc5dShenning if (type != SUBNET_DECL || !group->subnet) { 400e853bc5dShenning parse_warn("range declaration not allowed here."); 401e853bc5dShenning skip_to_semi(cfile); 402e853bc5dShenning return declaration; 403e853bc5dShenning } 404e853bc5dShenning parse_address_range(cfile, group->subnet); 405e853bc5dShenning return declaration; 406e853bc5dShenning 407e853bc5dShenning case ALLOW: 408e853bc5dShenning parse_allow_deny(cfile, group, 1); 409e853bc5dShenning break; 410e853bc5dShenning 411e853bc5dShenning case DENY: 412e853bc5dShenning parse_allow_deny(cfile, group, 0); 413e853bc5dShenning break; 414e853bc5dShenning 415e853bc5dShenning default: 416e853bc5dShenning if (declaration) 417e853bc5dShenning parse_warn("expecting a declaration."); 418e853bc5dShenning else 419e853bc5dShenning parse_warn("expecting a parameter or declaration."); 420e853bc5dShenning skip_to_semi(cfile); 421e853bc5dShenning return declaration; 422e853bc5dShenning } 423e853bc5dShenning 424e853bc5dShenning if (declaration) { 425e853bc5dShenning parse_warn("parameters not allowed after first declaration."); 426e853bc5dShenning return 1; 427e853bc5dShenning } 428e853bc5dShenning 429e853bc5dShenning return 0; 430e853bc5dShenning } 431e853bc5dShenning 432e853bc5dShenning /* allow-deny-keyword :== BOOTP 433e853bc5dShenning | BOOTING 434e853bc5dShenning | DYNAMIC_BOOTP 435e853bc5dShenning | UNKNOWN_CLIENTS */ 436e853bc5dShenning 437e853bc5dShenning void parse_allow_deny(cfile, group, flag) 438e853bc5dShenning FILE *cfile; 439e853bc5dShenning struct group *group; 440e853bc5dShenning int flag; 441e853bc5dShenning { 442e853bc5dShenning int token; 443e853bc5dShenning char *val; 444e853bc5dShenning 445e853bc5dShenning token = next_token(&val, cfile); 446e853bc5dShenning switch (token) { 447e853bc5dShenning case BOOTP: 448e853bc5dShenning group->allow_bootp = flag; 449e853bc5dShenning break; 450e853bc5dShenning 451e853bc5dShenning case BOOTING: 452e853bc5dShenning group->allow_booting = flag; 453e853bc5dShenning break; 454e853bc5dShenning 455e853bc5dShenning case DYNAMIC_BOOTP: 456e853bc5dShenning group->dynamic_bootp = flag; 457e853bc5dShenning break; 458e853bc5dShenning 459e853bc5dShenning case UNKNOWN_CLIENTS: 460e853bc5dShenning group->boot_unknown_clients = flag; 461e853bc5dShenning break; 462e853bc5dShenning 463e853bc5dShenning default: 464e853bc5dShenning parse_warn("expecting allow/deny key"); 465e853bc5dShenning skip_to_semi(cfile); 466e853bc5dShenning return; 467e853bc5dShenning } 468e853bc5dShenning parse_semi(cfile); 469e853bc5dShenning } 470e853bc5dShenning 471e853bc5dShenning /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ 472e853bc5dShenning 473e853bc5dShenning int parse_boolean(cfile) 474e853bc5dShenning FILE *cfile; 475e853bc5dShenning { 476e853bc5dShenning int token; 477e853bc5dShenning char *val; 478e853bc5dShenning int rv; 479e853bc5dShenning 480e853bc5dShenning token = next_token(&val, cfile); 481e853bc5dShenning if (!strcasecmp (val, "true") 482e853bc5dShenning || !strcasecmp (val, "on")) 483e853bc5dShenning rv = 1; 484e853bc5dShenning else if (!strcasecmp (val, "false") 485e853bc5dShenning || !strcasecmp (val, "off")) 486e853bc5dShenning rv = 0; 487e853bc5dShenning else { 488e853bc5dShenning parse_warn("boolean value (true/false/on/off) expected"); 489e853bc5dShenning skip_to_semi(cfile); 490e853bc5dShenning return 0; 491e853bc5dShenning } 492e853bc5dShenning parse_semi(cfile); 493e853bc5dShenning return rv; 494e853bc5dShenning } 495e853bc5dShenning 496e853bc5dShenning /* Expect a left brace; if there isn't one, skip over the rest of the 497e853bc5dShenning statement and return zero; otherwise, return 1. */ 498e853bc5dShenning 4996a467ce1Sderaadt int 5006a467ce1Sderaadt parse_lbrace(FILE *cfile) 501e853bc5dShenning { 502e853bc5dShenning int token; 503e853bc5dShenning char *val; 504e853bc5dShenning 505e853bc5dShenning token = next_token(&val, cfile); 506e853bc5dShenning if (token != LBRACE) { 507e853bc5dShenning parse_warn("expecting left brace."); 508e853bc5dShenning skip_to_semi(cfile); 509e853bc5dShenning return 0; 510e853bc5dShenning } 511e853bc5dShenning return 1; 512e853bc5dShenning } 513e853bc5dShenning 514e853bc5dShenning 515e853bc5dShenning /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ 516e853bc5dShenning 517e853bc5dShenning void parse_host_declaration(cfile, group) 518e853bc5dShenning FILE *cfile; 519e853bc5dShenning struct group *group; 520e853bc5dShenning { 521e853bc5dShenning char *val; 522e853bc5dShenning int token; 523e853bc5dShenning struct host_decl *host; 524e853bc5dShenning char *name = parse_host_name(cfile); 525e853bc5dShenning int declaration = 0; 526e853bc5dShenning 527e853bc5dShenning if (!name) 528e853bc5dShenning return; 529e853bc5dShenning 530e853bc5dShenning host = (struct host_decl *)dmalloc(sizeof (struct host_decl), 531e853bc5dShenning "parse_host_declaration"); 532e853bc5dShenning if (!host) 533e853bc5dShenning error("can't allocate host decl struct %s.", name); 534e853bc5dShenning 535e853bc5dShenning host->name = name; 536e853bc5dShenning host->group = clone_group(group, "parse_host_declaration"); 537e853bc5dShenning 538e853bc5dShenning if (!parse_lbrace(cfile)) 539e853bc5dShenning return; 540e853bc5dShenning 541e853bc5dShenning do { 542e853bc5dShenning token = peek_token(&val, cfile); 543e853bc5dShenning if (token == RBRACE) { 544e853bc5dShenning token = next_token(&val, cfile); 545e853bc5dShenning break; 546e853bc5dShenning } 547e853bc5dShenning if (token == EOF) { 548e853bc5dShenning token = next_token(&val, cfile); 549e853bc5dShenning parse_warn("unexpected end of file"); 550e853bc5dShenning break; 551e853bc5dShenning } 552e853bc5dShenning declaration = parse_statement(cfile, host->group, 5536a467ce1Sderaadt HOST_DECL, host, declaration); 554e853bc5dShenning } while (1); 555e853bc5dShenning 556e853bc5dShenning if (!host->group->options[DHO_HOST_NAME] && 557e853bc5dShenning host->group->use_host_decl_names) { 558e853bc5dShenning host->group->options[DHO_HOST_NAME] = 559e853bc5dShenning new_tree_cache("parse_host_declaration"); 560e853bc5dShenning if (!host->group->options[DHO_HOST_NAME]) 561e853bc5dShenning error("can't allocate a tree cache for hostname."); 562e853bc5dShenning host->group->options[DHO_HOST_NAME]->len = 563e853bc5dShenning strlen(name); 564e853bc5dShenning host->group->options[DHO_HOST_NAME]->value = 565e853bc5dShenning (unsigned char *)name; 566e853bc5dShenning host->group->options[DHO_HOST_NAME]->buf_size = 567e853bc5dShenning host->group->options[DHO_HOST_NAME]->len; 568e853bc5dShenning host->group->options[DHO_HOST_NAME]->timeout = 569e853bc5dShenning 0xFFFFFFFF; 570e853bc5dShenning host->group->options[DHO_HOST_NAME]->tree = 5716a467ce1Sderaadt NULL; 572e853bc5dShenning } 573e853bc5dShenning 574e853bc5dShenning enter_host(host); 575e853bc5dShenning } 576e853bc5dShenning 577e853bc5dShenning /* class-declaration :== STRING LBRACE parameters declarations RBRACE 578e853bc5dShenning */ 579e853bc5dShenning 580e853bc5dShenning void parse_class_declaration(cfile, group, type) 581e853bc5dShenning FILE *cfile; 582e853bc5dShenning struct group *group; 583e853bc5dShenning int type; 584e853bc5dShenning { 585e853bc5dShenning char *val; 586e853bc5dShenning int token; 587e853bc5dShenning struct class *class; 588e853bc5dShenning int declaration = 0; 589e853bc5dShenning 590e853bc5dShenning token = next_token(&val, cfile); 591e853bc5dShenning if (token != STRING) { 592e853bc5dShenning parse_warn("Expecting class name"); 593e853bc5dShenning skip_to_semi(cfile); 594e853bc5dShenning return; 595e853bc5dShenning } 596e853bc5dShenning 597e853bc5dShenning class = add_class (type, val); 598e853bc5dShenning if (!class) 599e853bc5dShenning error("No memory for class %s.", val); 600e853bc5dShenning class->group = clone_group(group, "parse_class_declaration"); 601e853bc5dShenning 602e853bc5dShenning if (!parse_lbrace(cfile)) 603e853bc5dShenning return; 604e853bc5dShenning 605e853bc5dShenning do { 606e853bc5dShenning token = peek_token(&val, cfile); 607e853bc5dShenning if (token == RBRACE) { 608e853bc5dShenning token = next_token(&val, cfile); 609e853bc5dShenning break; 610e853bc5dShenning } else if (token == EOF) { 611e853bc5dShenning token = next_token(&val, cfile); 612e853bc5dShenning parse_warn("unexpected end of file"); 613e853bc5dShenning break; 614e853bc5dShenning } else { 615e853bc5dShenning declaration = parse_statement(cfile, class->group, 6166a467ce1Sderaadt CLASS_DECL, NULL, declaration); 617e853bc5dShenning } 618e853bc5dShenning } while (1); 619e853bc5dShenning } 620e853bc5dShenning 621e853bc5dShenning /* shared-network-declaration :== 622e853bc5dShenning hostname LBRACE declarations parameters RBRACE */ 623e853bc5dShenning 624e853bc5dShenning void parse_shared_net_declaration(cfile, group) 625e853bc5dShenning FILE *cfile; 626e853bc5dShenning struct group *group; 627e853bc5dShenning { 628e853bc5dShenning char *val; 629e853bc5dShenning int token; 630e853bc5dShenning struct shared_network *share; 631e853bc5dShenning char *name; 632e853bc5dShenning int declaration = 0; 633e853bc5dShenning 634e853bc5dShenning share = new_shared_network("parse_shared_net_declaration"); 635e853bc5dShenning if (!share) 636e853bc5dShenning error("No memory for shared subnet"); 6376a467ce1Sderaadt share->leases = NULL; 6386a467ce1Sderaadt share->last_lease = NULL; 6396a467ce1Sderaadt share->insertion_point = NULL; 6406a467ce1Sderaadt share->next = NULL; 6416a467ce1Sderaadt share->interface = NULL; 642e853bc5dShenning share->group = clone_group(group, "parse_shared_net_declaration"); 643e853bc5dShenning share->group->shared_network = share; 644e853bc5dShenning 645e853bc5dShenning /* Get the name of the shared network... */ 646e853bc5dShenning token = peek_token(&val, cfile); 647e853bc5dShenning if (token == STRING) { 648e853bc5dShenning token = next_token(&val, cfile); 649e853bc5dShenning 650e853bc5dShenning if (val[0] == 0) { 651e853bc5dShenning parse_warn("zero-length shared network name"); 652e853bc5dShenning val = "<no-name-given>"; 653e853bc5dShenning } 654e853bc5dShenning name = malloc(strlen(val) + 1); 655e853bc5dShenning if (!name) 656e853bc5dShenning error("no memory for shared network name"); 657e853bc5dShenning strlcpy(name, val, strlen(val) + 1); 658e853bc5dShenning } else { 659e853bc5dShenning name = parse_host_name(cfile); 660e853bc5dShenning if (!name) 661e853bc5dShenning return; 662e853bc5dShenning } 663e853bc5dShenning share->name = name; 664e853bc5dShenning 665e853bc5dShenning if (!parse_lbrace(cfile)) 666e853bc5dShenning return; 667e853bc5dShenning 668e853bc5dShenning do { 669e853bc5dShenning token = peek_token(&val, cfile); 670e853bc5dShenning if (token == RBRACE) { 671e853bc5dShenning token = next_token(&val, cfile); 672e853bc5dShenning if (!share->subnets) { 673e853bc5dShenning parse_warn("empty shared-network decl"); 674e853bc5dShenning return; 675e853bc5dShenning } 676e853bc5dShenning enter_shared_network(share); 677e853bc5dShenning return; 678e853bc5dShenning } else if (token == EOF) { 679e853bc5dShenning token = next_token(&val, cfile); 680e853bc5dShenning parse_warn("unexpected end of file"); 681e853bc5dShenning break; 682e853bc5dShenning } 683e853bc5dShenning 684e853bc5dShenning declaration = parse_statement(cfile, share->group, 6856a467ce1Sderaadt SHARED_NET_DECL, NULL, declaration); 686e853bc5dShenning } while (1); 687e853bc5dShenning } 688e853bc5dShenning 689e853bc5dShenning /* subnet-declaration :== 690e853bc5dShenning net NETMASK netmask RBRACE parameters declarations LBRACE */ 691e853bc5dShenning 692e853bc5dShenning void parse_subnet_declaration(cfile, share) 693e853bc5dShenning FILE *cfile; 694e853bc5dShenning struct shared_network *share; 695e853bc5dShenning { 696e853bc5dShenning char *val; 697e853bc5dShenning int token; 698e853bc5dShenning struct subnet *subnet, *t, *u; 699e853bc5dShenning struct iaddr iaddr; 700e853bc5dShenning unsigned char addr[4]; 701e853bc5dShenning int len = sizeof addr; 702e853bc5dShenning int declaration = 0; 703e853bc5dShenning 704e853bc5dShenning subnet = new_subnet("parse_subnet_declaration"); 705e853bc5dShenning if (!subnet) 706e853bc5dShenning error("No memory for new subnet"); 707e853bc5dShenning subnet->shared_network = share; 7086a467ce1Sderaadt subnet->group = clone_group(share->group, "parse_subnet_declaration"); 709e853bc5dShenning subnet->group->subnet = subnet; 710e853bc5dShenning 711e853bc5dShenning /* Get the network number... */ 712e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 713e853bc5dShenning return; 714e853bc5dShenning memcpy(iaddr.iabuf, addr, len); 715e853bc5dShenning iaddr.len = len; 716e853bc5dShenning subnet->net = iaddr; 717e853bc5dShenning 718e853bc5dShenning token = next_token(&val, cfile); 719e853bc5dShenning if (token != NETMASK) { 720e853bc5dShenning parse_warn("Expecting netmask"); 721e853bc5dShenning skip_to_semi(cfile); 722e853bc5dShenning return; 723e853bc5dShenning } 724e853bc5dShenning 725e853bc5dShenning /* Get the netmask... */ 726e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 727e853bc5dShenning return; 728e853bc5dShenning memcpy(iaddr.iabuf, addr, len); 729e853bc5dShenning iaddr.len = len; 730e853bc5dShenning subnet->netmask = iaddr; 731e853bc5dShenning 732e853bc5dShenning enter_subnet(subnet); 733e853bc5dShenning 734e853bc5dShenning if (!parse_lbrace(cfile)) 735e853bc5dShenning return; 736e853bc5dShenning 737e853bc5dShenning do { 738e853bc5dShenning token = peek_token(&val, cfile); 739e853bc5dShenning if (token == RBRACE) { 740e853bc5dShenning token = next_token(&val, cfile); 741e853bc5dShenning break; 742e853bc5dShenning } else if (token == EOF) { 743e853bc5dShenning token = next_token(&val, cfile); 744e853bc5dShenning parse_warn("unexpected end of file"); 745e853bc5dShenning break; 746e853bc5dShenning } 747e853bc5dShenning declaration = parse_statement(cfile, subnet->group, 7486a467ce1Sderaadt SUBNET_DECL, NULL, declaration); 749e853bc5dShenning } while (1); 750e853bc5dShenning 751e853bc5dShenning /* If this subnet supports dynamic bootp, flag it so in the 752e853bc5dShenning shared_network containing it. */ 753e853bc5dShenning if (subnet->group->dynamic_bootp) 754e853bc5dShenning share->group->dynamic_bootp = 1; 755e853bc5dShenning if (subnet->group->one_lease_per_client) 756e853bc5dShenning share->group->one_lease_per_client = 1; 757e853bc5dShenning 758e853bc5dShenning /* Add the subnet to the list of subnets in this shared net. */ 759e853bc5dShenning if (!share->subnets) 760e853bc5dShenning share->subnets = subnet; 761e853bc5dShenning else { 7626a467ce1Sderaadt u = NULL; 763e853bc5dShenning for (t = share->subnets; t; t = t->next_sibling) { 764e853bc5dShenning if (subnet_inner_than(subnet, t, 0)) { 765e853bc5dShenning if (u) 766e853bc5dShenning u->next_sibling = subnet; 767e853bc5dShenning else 768e853bc5dShenning share->subnets = subnet; 769e853bc5dShenning subnet->next_sibling = t; 770e853bc5dShenning return; 771e853bc5dShenning } 772e853bc5dShenning u = t; 773e853bc5dShenning } 774e853bc5dShenning u->next_sibling = subnet; 775e853bc5dShenning } 776e853bc5dShenning } 777e853bc5dShenning 778e853bc5dShenning /* group-declaration :== RBRACE parameters declarations LBRACE */ 779e853bc5dShenning 780e853bc5dShenning void parse_group_declaration(cfile, group) 781e853bc5dShenning FILE *cfile; 782e853bc5dShenning struct group *group; 783e853bc5dShenning { 784e853bc5dShenning char *val; 785e853bc5dShenning int token; 786e853bc5dShenning struct group *g; 787e853bc5dShenning int declaration = 0; 788e853bc5dShenning 789e853bc5dShenning g = clone_group(group, "parse_group_declaration"); 790e853bc5dShenning 791e853bc5dShenning if (!parse_lbrace(cfile)) 792e853bc5dShenning return; 793e853bc5dShenning 794e853bc5dShenning do { 795e853bc5dShenning token = peek_token(&val, cfile); 796e853bc5dShenning if (token == RBRACE) { 797e853bc5dShenning token = next_token(&val, cfile); 798e853bc5dShenning break; 799e853bc5dShenning } else if (token == EOF) { 800e853bc5dShenning token = next_token(&val, cfile); 801e853bc5dShenning parse_warn("unexpected end of file"); 802e853bc5dShenning break; 803e853bc5dShenning } 8046a467ce1Sderaadt declaration = parse_statement(cfile, g, GROUP_DECL, NULL, 805e853bc5dShenning declaration); 806e853bc5dShenning } while (1); 807e853bc5dShenning } 808e853bc5dShenning 809e853bc5dShenning /* ip-addr-or-hostname :== ip-address | hostname 810e853bc5dShenning ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 811e853bc5dShenning 812e853bc5dShenning Parse an ip address or a hostname. If uniform is zero, put in 813e853bc5dShenning a TREE_LIMIT node to catch hostnames that evaluate to more than 814e853bc5dShenning one IP address. */ 815e853bc5dShenning 816e853bc5dShenning struct tree *parse_ip_addr_or_hostname(cfile, uniform) 817e853bc5dShenning FILE *cfile; 818e853bc5dShenning int uniform; 819e853bc5dShenning { 820e853bc5dShenning char *val; 821e853bc5dShenning int token; 822e853bc5dShenning unsigned char addr[4]; 823e853bc5dShenning int len = sizeof addr; 824e853bc5dShenning char *name; 825e853bc5dShenning struct tree *rv; 826*8952c965Shenning struct hostent *h; 827e853bc5dShenning 828e853bc5dShenning token = peek_token(&val, cfile); 829e853bc5dShenning if (is_identifier(token)) { 830e853bc5dShenning name = parse_host_name(cfile); 831e853bc5dShenning if (!name) 8326a467ce1Sderaadt return NULL; 833*8952c965Shenning h = gethostbyname(name); 834*8952c965Shenning if (h == NULL) 835*8952c965Shenning parse_warn("%s (%d): could not resolve hostname", 836*8952c965Shenning val, token); 837*8952c965Shenning rv = tree_const(h->h_addr_list[0], h->h_length); 838e853bc5dShenning if (!uniform) 839e853bc5dShenning rv = tree_limit(rv, 4); 840e853bc5dShenning } else if (token == NUMBER) { 841e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 8426a467ce1Sderaadt return NULL; 843e853bc5dShenning rv = tree_const(addr, len); 844e853bc5dShenning } else { 845e853bc5dShenning if (token != RBRACE && token != LBRACE) 846e853bc5dShenning token = next_token(&val, cfile); 847e853bc5dShenning parse_warn("%s (%d): expecting IP address or hostname", 848e853bc5dShenning val, token); 849e853bc5dShenning if (token != SEMI) 850e853bc5dShenning skip_to_semi(cfile); 8516a467ce1Sderaadt return NULL; 852e853bc5dShenning } 853e853bc5dShenning 854e853bc5dShenning return rv; 855e853bc5dShenning } 856e853bc5dShenning 857e853bc5dShenning 858e853bc5dShenning /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI 859e853bc5dShenning ip-addrs-or-hostnames :== ip-addr-or-hostname 860e853bc5dShenning | ip-addrs-or-hostnames ip-addr-or-hostname */ 861e853bc5dShenning 862e853bc5dShenning struct tree_cache *parse_fixed_addr_param(cfile) 863e853bc5dShenning FILE *cfile; 864e853bc5dShenning { 865e853bc5dShenning char *val; 866e853bc5dShenning int token; 8676a467ce1Sderaadt struct tree *tree = NULL; 868e853bc5dShenning struct tree *tmp; 869e853bc5dShenning 870e853bc5dShenning do { 871e853bc5dShenning tmp = parse_ip_addr_or_hostname(cfile, 0); 872e853bc5dShenning if (tree) 873e853bc5dShenning tree = tree_concat(tree, tmp); 874e853bc5dShenning else 875e853bc5dShenning tree = tmp; 876e853bc5dShenning token = peek_token(&val, cfile); 877e853bc5dShenning if (token == COMMA) 878e853bc5dShenning token = next_token(&val, cfile); 879e853bc5dShenning } while (token == COMMA); 880e853bc5dShenning 881e853bc5dShenning if (!parse_semi(cfile)) 8826a467ce1Sderaadt return NULL; 883e853bc5dShenning return tree_cache(tree); 884e853bc5dShenning } 885e853bc5dShenning 886e853bc5dShenning /* option_parameter :== identifier DOT identifier <syntax> SEMI 887e853bc5dShenning | identifier <syntax> SEMI 888e853bc5dShenning 889e853bc5dShenning Option syntax is handled specially through format strings, so it 890e853bc5dShenning would be painful to come up with BNF for it. However, it always 891e853bc5dShenning starts as above and ends in a SEMI. */ 892e853bc5dShenning 893e853bc5dShenning void parse_option_param(cfile, group) 894e853bc5dShenning FILE *cfile; 895e853bc5dShenning struct group *group; 896e853bc5dShenning { 897e853bc5dShenning char *val; 898e853bc5dShenning int token; 899e853bc5dShenning unsigned char buf[4]; 900e853bc5dShenning char *vendor; 901e853bc5dShenning char *fmt; 902e853bc5dShenning struct universe *universe; 903e853bc5dShenning struct option *option; 9046a467ce1Sderaadt struct tree *tree = NULL; 905e853bc5dShenning struct tree *t; 906e853bc5dShenning 907e853bc5dShenning token = next_token(&val, cfile); 908e853bc5dShenning if (!is_identifier(token)) { 909e853bc5dShenning parse_warn("expecting identifier after option keyword."); 910e853bc5dShenning if (token != SEMI) 911e853bc5dShenning skip_to_semi(cfile); 912e853bc5dShenning return; 913e853bc5dShenning } 914e853bc5dShenning vendor = malloc(strlen(val) + 1); 915e853bc5dShenning if (!vendor) 916e853bc5dShenning error("no memory for vendor token."); 917e853bc5dShenning strlcpy(vendor, val, strlen(val) + 1); 918e853bc5dShenning token = peek_token(&val, cfile); 919e853bc5dShenning if (token == DOT) { 920e853bc5dShenning /* Go ahead and take the DOT token... */ 921e853bc5dShenning token = next_token(&val, cfile); 922e853bc5dShenning 923e853bc5dShenning /* The next token should be an identifier... */ 924e853bc5dShenning token = next_token(&val, cfile); 925e853bc5dShenning if (!is_identifier(token)) { 926e853bc5dShenning parse_warn("expecting identifier after '.'"); 927e853bc5dShenning if (token != SEMI) 928e853bc5dShenning skip_to_semi(cfile); 929e853bc5dShenning return; 930e853bc5dShenning } 931e853bc5dShenning 932e853bc5dShenning /* Look up the option name hash table for the specified 933e853bc5dShenning vendor. */ 934cca1f910Shenning universe = ((struct universe *)hash_lookup(&universe_hash, 935e853bc5dShenning (unsigned char *)vendor, 0)); 936e853bc5dShenning /* If it's not there, we can't parse the rest of the 937e853bc5dShenning declaration. */ 938e853bc5dShenning if (!universe) { 939e853bc5dShenning parse_warn("no vendor named %s.", vendor); 940e853bc5dShenning skip_to_semi(cfile); 941e853bc5dShenning return; 942e853bc5dShenning } 943e853bc5dShenning } else { 944e853bc5dShenning /* Use the default hash table, which contains all the 945e853bc5dShenning standard dhcp option names. */ 946e853bc5dShenning val = vendor; 947e853bc5dShenning universe = &dhcp_universe; 948e853bc5dShenning } 949e853bc5dShenning 950e853bc5dShenning /* Look up the actual option info... */ 951e853bc5dShenning option = (struct option *)hash_lookup(universe->hash, 952e853bc5dShenning (unsigned char *)val, 0); 953e853bc5dShenning 954e853bc5dShenning /* If we didn't get an option structure, it's an undefined option. */ 955e853bc5dShenning if (!option) { 956e853bc5dShenning if (val == vendor) 957e853bc5dShenning parse_warn("no option named %s", val); 958e853bc5dShenning else 959e853bc5dShenning parse_warn("no option named %s for vendor %s", 960e853bc5dShenning val, vendor); 961e853bc5dShenning skip_to_semi(cfile); 962e853bc5dShenning return; 963e853bc5dShenning } 964e853bc5dShenning 965e853bc5dShenning /* Free the initial identifier token. */ 966e853bc5dShenning free(vendor); 967e853bc5dShenning 968e853bc5dShenning /* Parse the option data... */ 969e853bc5dShenning do { 970e853bc5dShenning /* Set a flag if this is an array of a simple type (i.e., 971e853bc5dShenning not an array of pairs of IP addresses, or something 972e853bc5dShenning like that. */ 973e853bc5dShenning int uniform = option->format[1] == 'A'; 974e853bc5dShenning 975e853bc5dShenning for (fmt = option->format; *fmt; fmt++) { 976e853bc5dShenning if (*fmt == 'A') 977e853bc5dShenning break; 978e853bc5dShenning switch (*fmt) { 979e853bc5dShenning case 'X': 980e853bc5dShenning token = peek_token(&val, cfile); 981e853bc5dShenning if (token == NUMBER_OR_NAME || 982e853bc5dShenning token == NUMBER) { 983e853bc5dShenning do { 984e853bc5dShenning token = next_token 985e853bc5dShenning (&val, cfile); 986cca1f910Shenning if (token != NUMBER && 987cca1f910Shenning token != NUMBER_OR_NAME) { 988cca1f910Shenning parse_warn("expecting " 989cca1f910Shenning "number."); 990cca1f910Shenning if (token != SEMI) 991cca1f910Shenning skip_to_semi( 992cca1f910Shenning cfile); 993cca1f910Shenning return; 994cca1f910Shenning } 995e853bc5dShenning convert_num(buf, val, 16, 8); 996cca1f910Shenning tree = tree_concat(tree, 997e853bc5dShenning tree_const(buf, 1)); 998cca1f910Shenning token = peek_token(&val, cfile); 999e853bc5dShenning if (token == COLON) 1000cca1f910Shenning token = next_token(&val, 1001cca1f910Shenning cfile); 1002e853bc5dShenning } while (token == COLON); 1003e853bc5dShenning } else if (token == STRING) { 1004e853bc5dShenning token = next_token(&val, cfile); 1005cca1f910Shenning tree = tree_concat(tree, 1006cca1f910Shenning tree_const((unsigned char *)val, 1007e853bc5dShenning strlen(val))); 1008e853bc5dShenning } else { 1009e853bc5dShenning parse_warn("expecting string %s.", 1010e853bc5dShenning "or hexadecimal data"); 1011e853bc5dShenning skip_to_semi(cfile); 1012e853bc5dShenning return; 1013e853bc5dShenning } 1014e853bc5dShenning break; 1015e853bc5dShenning 1016e853bc5dShenning case 't': /* Text string... */ 1017e853bc5dShenning token = next_token(&val, cfile); 1018e853bc5dShenning if (token != STRING 1019e853bc5dShenning && !is_identifier(token)) { 1020e853bc5dShenning parse_warn("expecting string."); 1021e853bc5dShenning if (token != SEMI) 1022e853bc5dShenning skip_to_semi(cfile); 1023e853bc5dShenning return; 1024e853bc5dShenning } 1025cca1f910Shenning tree = tree_concat(tree, 1026e853bc5dShenning tree_const((unsigned char *)val, 1027e853bc5dShenning strlen(val))); 1028e853bc5dShenning break; 1029e853bc5dShenning 1030e853bc5dShenning case 'I': /* IP address or hostname. */ 1031e853bc5dShenning t = parse_ip_addr_or_hostname(cfile, uniform); 1032e853bc5dShenning if (!t) 1033e853bc5dShenning return; 1034e853bc5dShenning tree = tree_concat(tree, t); 1035e853bc5dShenning break; 1036e853bc5dShenning 1037e853bc5dShenning case 'L': /* Unsigned 32-bit integer... */ 1038e853bc5dShenning case 'l': /* Signed 32-bit integer... */ 1039e853bc5dShenning token = next_token(&val, cfile); 1040e853bc5dShenning if (token != NUMBER) { 1041e853bc5dShenning parse_warn("expecting number."); 1042e853bc5dShenning if (token != SEMI) 1043e853bc5dShenning skip_to_semi(cfile); 1044e853bc5dShenning return; 1045e853bc5dShenning } 1046e853bc5dShenning convert_num(buf, val, 0, 32); 1047e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 4)); 1048e853bc5dShenning break; 1049e853bc5dShenning case 's': /* Signed 16-bit integer. */ 1050e853bc5dShenning case 'S': /* Unsigned 16-bit integer. */ 1051e853bc5dShenning token = next_token(&val, cfile); 1052cca1f910Shenning if (token != NUMBER) { 1053cca1f910Shenning parse_warn("expecting number."); 1054cca1f910Shenning if (token != SEMI) 1055cca1f910Shenning skip_to_semi(cfile); 1056cca1f910Shenning return; 1057cca1f910Shenning } 1058e853bc5dShenning convert_num(buf, val, 0, 16); 1059e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 2)); 1060e853bc5dShenning break; 1061e853bc5dShenning case 'b': /* Signed 8-bit integer. */ 1062e853bc5dShenning case 'B': /* Unsigned 8-bit integer. */ 1063e853bc5dShenning token = next_token(&val, cfile); 1064cca1f910Shenning if (token != NUMBER) { 1065cca1f910Shenning parse_warn("expecting number."); 1066cca1f910Shenning if (token != SEMI) 1067cca1f910Shenning skip_to_semi(cfile); 1068cca1f910Shenning return; 1069cca1f910Shenning } 1070e853bc5dShenning convert_num(buf, val, 0, 8); 1071e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 1)); 1072e853bc5dShenning break; 1073e853bc5dShenning case 'f': /* Boolean flag. */ 1074e853bc5dShenning token = next_token(&val, cfile); 1075e853bc5dShenning if (!is_identifier(token)) { 1076e853bc5dShenning parse_warn("expecting identifier."); 1077e853bc5dShenning if (token != SEMI) 1078e853bc5dShenning skip_to_semi(cfile); 1079e853bc5dShenning return; 1080e853bc5dShenning } 1081e853bc5dShenning if (!strcasecmp(val, "true") 1082e853bc5dShenning || !strcasecmp(val, "on")) 1083e853bc5dShenning buf[0] = 1; 1084e853bc5dShenning else if (!strcasecmp(val, "false") 1085e853bc5dShenning || !strcasecmp(val, "off")) 1086e853bc5dShenning buf[0] = 0; 1087e853bc5dShenning else { 1088e853bc5dShenning parse_warn("expecting boolean."); 1089cca1f910Shenning if (token != SEMI) 1090cca1f910Shenning skip_to_semi(cfile); 1091cca1f910Shenning return; 1092e853bc5dShenning } 1093e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 1)); 1094e853bc5dShenning break; 1095e853bc5dShenning default: 1096e853bc5dShenning warn("Bad format %c in parse_option_param.", 1097e853bc5dShenning *fmt); 1098e853bc5dShenning skip_to_semi(cfile); 1099e853bc5dShenning return; 1100e853bc5dShenning } 1101e853bc5dShenning } 1102e853bc5dShenning if (*fmt == 'A') { 1103e853bc5dShenning token = peek_token(&val, cfile); 1104e853bc5dShenning if (token == COMMA) { 1105e853bc5dShenning token = next_token(&val, cfile); 1106e853bc5dShenning continue; 1107e853bc5dShenning } 1108e853bc5dShenning break; 1109e853bc5dShenning } 1110e853bc5dShenning } while (*fmt == 'A'); 1111e853bc5dShenning 1112e853bc5dShenning token = next_token(&val, cfile); 1113e853bc5dShenning if (token != SEMI) { 1114e853bc5dShenning parse_warn("semicolon expected."); 1115e853bc5dShenning skip_to_semi(cfile); 1116e853bc5dShenning return; 1117e853bc5dShenning } 1118e853bc5dShenning group->options[option->code] = tree_cache(tree); 1119e853bc5dShenning } 1120e853bc5dShenning 1121e853bc5dShenning /* timestamp :== date 1122e853bc5dShenning 1123e853bc5dShenning Timestamps are actually not used in dhcpd.conf, which is a static file, 1124e853bc5dShenning but rather in the database file and the journal file. (Okay, actually 1125e853bc5dShenning they're not even used there yet). */ 1126e853bc5dShenning 1127fbc5e94dShenning time_t parse_timestamp(cfile) 1128e853bc5dShenning FILE *cfile; 1129e853bc5dShenning { 1130fbc5e94dShenning time_t rv; 1131e853bc5dShenning 1132e853bc5dShenning rv = parse_date(cfile); 1133e853bc5dShenning return rv; 1134e853bc5dShenning } 1135e853bc5dShenning 1136e853bc5dShenning /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE 1137e853bc5dShenning 1138e853bc5dShenning lease_parameters :== <nil> 1139e853bc5dShenning | lease_parameter 1140e853bc5dShenning | lease_parameters lease_parameter 1141e853bc5dShenning 1142e853bc5dShenning lease_parameter :== STARTS date 1143e853bc5dShenning | ENDS date 1144e853bc5dShenning | TIMESTAMP date 1145e853bc5dShenning | HARDWARE hardware-parameter 1146e853bc5dShenning | UID hex_numbers SEMI 1147e853bc5dShenning | HOSTNAME hostname SEMI 1148e853bc5dShenning | CLIENT_HOSTNAME hostname SEMI 1149e853bc5dShenning | CLASS identifier SEMI 1150e853bc5dShenning | DYNAMIC_BOOTP SEMI */ 1151e853bc5dShenning 1152e853bc5dShenning struct lease *parse_lease_declaration(cfile) 1153e853bc5dShenning FILE *cfile; 1154e853bc5dShenning { 1155e853bc5dShenning char *val; 1156e853bc5dShenning int token; 1157e853bc5dShenning unsigned char addr[4]; 1158e853bc5dShenning int len = sizeof addr; 1159e853bc5dShenning int seenmask = 0; 1160e853bc5dShenning int seenbit; 1161e853bc5dShenning char tbuf[32]; 1162e853bc5dShenning static struct lease lease; 1163e853bc5dShenning 1164e853bc5dShenning /* Zap the lease structure... */ 1165e853bc5dShenning memset(&lease, 0, sizeof lease); 1166e853bc5dShenning 1167e853bc5dShenning /* Get the address for which the lease has been issued. */ 1168e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 11696a467ce1Sderaadt return NULL; 1170e853bc5dShenning memcpy(lease.ip_addr.iabuf, addr, len); 1171e853bc5dShenning lease.ip_addr.len = len; 1172e853bc5dShenning 1173e853bc5dShenning if (!parse_lbrace(cfile)) 11746a467ce1Sderaadt return NULL; 1175e853bc5dShenning 1176e853bc5dShenning do { 1177e853bc5dShenning token = next_token(&val, cfile); 1178e853bc5dShenning if (token == RBRACE) 1179e853bc5dShenning break; 1180e853bc5dShenning else if (token == EOF) { 1181e853bc5dShenning parse_warn("unexpected end of file"); 1182e853bc5dShenning break; 1183e853bc5dShenning } 1184e853bc5dShenning strlcpy(tbuf, val, sizeof tbuf); 1185e853bc5dShenning 1186e853bc5dShenning /* Parse any of the times associated with the lease. */ 1187e853bc5dShenning if (token == STARTS || token == ENDS || token == TIMESTAMP) { 1188fbc5e94dShenning time_t t; 1189e853bc5dShenning t = parse_date(cfile); 1190e853bc5dShenning switch (token) { 1191e853bc5dShenning case STARTS: 1192e853bc5dShenning seenbit = 1; 1193e853bc5dShenning lease.starts = t; 1194e853bc5dShenning break; 1195e853bc5dShenning 1196e853bc5dShenning case ENDS: 1197e853bc5dShenning seenbit = 2; 1198e853bc5dShenning lease.ends = t; 1199e853bc5dShenning break; 1200e853bc5dShenning 1201e853bc5dShenning case TIMESTAMP: 1202e853bc5dShenning seenbit = 4; 1203e853bc5dShenning lease.timestamp = t; 1204e853bc5dShenning break; 1205e853bc5dShenning 1206e853bc5dShenning default: 1207e853bc5dShenning /*NOTREACHED*/ 1208e853bc5dShenning seenbit = 0; 1209e853bc5dShenning break; 1210e853bc5dShenning } 1211e853bc5dShenning } else { 1212e853bc5dShenning switch (token) { 1213e853bc5dShenning /* Colon-separated hexadecimal octets... */ 1214e853bc5dShenning case UID: 1215e853bc5dShenning seenbit = 8; 1216e853bc5dShenning token = peek_token(&val, cfile); 1217e853bc5dShenning if (token == STRING) { 1218e853bc5dShenning token = next_token(&val, cfile); 1219e853bc5dShenning lease.uid_len = strlen(val); 1220e853bc5dShenning lease.uid = (unsigned char *) 1221e853bc5dShenning malloc(lease.uid_len); 1222e853bc5dShenning if (!lease.uid) { 1223e853bc5dShenning warn("no space for uid"); 12246a467ce1Sderaadt return NULL; 1225e853bc5dShenning } 1226e853bc5dShenning memcpy(lease.uid, val, lease.uid_len); 1227e853bc5dShenning parse_semi(cfile); 1228e853bc5dShenning } else { 1229e853bc5dShenning lease.uid_len = 0; 1230cca1f910Shenning lease.uid = 1231cca1f910Shenning parse_numeric_aggregate(cfile, 12326a467ce1Sderaadt NULL, &lease.uid_len, ':', 16, 8); 1233e853bc5dShenning if (!lease.uid) { 1234e853bc5dShenning warn("no space for uid"); 12356a467ce1Sderaadt return NULL; 1236e853bc5dShenning } 1237e853bc5dShenning if (lease.uid_len == 0) { 12386a467ce1Sderaadt lease.uid = NULL; 1239e853bc5dShenning parse_warn("zero-length uid"); 1240e853bc5dShenning seenbit = 0; 1241e853bc5dShenning break; 1242e853bc5dShenning } 1243e853bc5dShenning } 12446a467ce1Sderaadt if (!lease.uid) 1245e853bc5dShenning error("No memory for lease uid"); 1246e853bc5dShenning break; 1247e853bc5dShenning 1248e853bc5dShenning case CLASS: 1249e853bc5dShenning seenbit = 32; 1250e853bc5dShenning token = next_token(&val, cfile); 1251e853bc5dShenning if (!is_identifier(token)) { 1252e853bc5dShenning if (token != SEMI) 1253e853bc5dShenning skip_to_semi(cfile); 12546a467ce1Sderaadt return NULL; 1255e853bc5dShenning } 1256e853bc5dShenning /* for now, we aren't using this. */ 1257e853bc5dShenning break; 1258e853bc5dShenning 1259e853bc5dShenning case HARDWARE: 1260e853bc5dShenning seenbit = 64; 1261e853bc5dShenning parse_hardware_param(cfile, 1262e853bc5dShenning &lease.hardware_addr); 1263e853bc5dShenning break; 1264e853bc5dShenning 1265e853bc5dShenning case DYNAMIC_BOOTP: 1266e853bc5dShenning seenbit = 128; 1267e853bc5dShenning lease.flags |= BOOTP_LEASE; 1268e853bc5dShenning break; 1269e853bc5dShenning 1270e853bc5dShenning case ABANDONED: 1271e853bc5dShenning seenbit = 256; 1272e853bc5dShenning lease.flags |= ABANDONED_LEASE; 1273e853bc5dShenning break; 1274e853bc5dShenning 1275e853bc5dShenning case HOSTNAME: 1276e853bc5dShenning seenbit = 512; 1277e853bc5dShenning token = peek_token(&val, cfile); 1278e853bc5dShenning if (token == STRING) 1279e853bc5dShenning lease.hostname = parse_string(cfile); 1280e853bc5dShenning else 1281e853bc5dShenning lease.hostname = 1282e853bc5dShenning parse_host_name(cfile); 1283e853bc5dShenning if (!lease.hostname) { 1284e853bc5dShenning seenbit = 0; 12856a467ce1Sderaadt return NULL; 1286e853bc5dShenning } 1287e853bc5dShenning break; 1288e853bc5dShenning 1289e853bc5dShenning case CLIENT_HOSTNAME: 1290e853bc5dShenning seenbit = 1024; 1291e853bc5dShenning token = peek_token(&val, cfile); 1292e853bc5dShenning if (token == STRING) 1293e853bc5dShenning lease.client_hostname = 1294e853bc5dShenning parse_string(cfile); 1295e853bc5dShenning else 1296e853bc5dShenning lease.client_hostname = 1297e853bc5dShenning parse_host_name(cfile); 1298e853bc5dShenning break; 1299e853bc5dShenning 1300e853bc5dShenning default: 1301e853bc5dShenning skip_to_semi(cfile); 1302e853bc5dShenning seenbit = 0; 13036a467ce1Sderaadt return NULL; 1304e853bc5dShenning } 1305e853bc5dShenning 1306e853bc5dShenning if (token != HARDWARE && token != STRING) { 1307e853bc5dShenning token = next_token(&val, cfile); 1308e853bc5dShenning if (token != SEMI) { 1309e853bc5dShenning parse_warn("semicolon expected."); 1310e853bc5dShenning skip_to_semi(cfile); 13116a467ce1Sderaadt return NULL; 1312e853bc5dShenning } 1313e853bc5dShenning } 1314e853bc5dShenning } 1315e853bc5dShenning if (seenmask & seenbit) { 1316e853bc5dShenning parse_warn("Too many %s parameters in lease %s\n", 1317e853bc5dShenning tbuf, piaddr(lease.ip_addr)); 1318e853bc5dShenning } else 1319e853bc5dShenning seenmask |= seenbit; 1320e853bc5dShenning 1321e853bc5dShenning } while (1); 1322e853bc5dShenning return &lease; 1323e853bc5dShenning } 1324e853bc5dShenning 13256a467ce1Sderaadt /* 13266a467ce1Sderaadt * address-range-declaration :== ip-address ip-address SEMI 13276a467ce1Sderaadt * | DYNAMIC_BOOTP ip-address ip-address SEMI 13286a467ce1Sderaadt */ 13296a467ce1Sderaadt void 13306a467ce1Sderaadt parse_address_range(FILE *cfile, struct subnet *subnet) 1331e853bc5dShenning { 1332e853bc5dShenning struct iaddr low, high; 1333e853bc5dShenning unsigned char addr[4]; 13346a467ce1Sderaadt int len = sizeof addr, token, dynamic = 0; 1335e853bc5dShenning char *val; 1336e853bc5dShenning 1337e853bc5dShenning if ((token = peek_token(&val, cfile)) == DYNAMIC_BOOTP) { 1338e853bc5dShenning token = next_token(&val, cfile); 1339e853bc5dShenning subnet->group->dynamic_bootp = dynamic = 1; 1340e853bc5dShenning } 1341e853bc5dShenning 1342e853bc5dShenning /* Get the bottom address in the range... */ 1343e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 1344e853bc5dShenning return; 1345e853bc5dShenning memcpy(low.iabuf, addr, len); 1346e853bc5dShenning low.len = len; 1347e853bc5dShenning 1348e853bc5dShenning /* Only one address? */ 1349e853bc5dShenning token = peek_token(&val, cfile); 1350e853bc5dShenning if (token == SEMI) 1351e853bc5dShenning high = low; 1352e853bc5dShenning else { 1353e853bc5dShenning /* Get the top address in the range... */ 1354e853bc5dShenning if (!parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8)) 1355e853bc5dShenning return; 1356e853bc5dShenning memcpy(high.iabuf, addr, len); 1357e853bc5dShenning high.len = len; 1358e853bc5dShenning } 1359e853bc5dShenning 1360e853bc5dShenning token = next_token(&val, cfile); 1361e853bc5dShenning if (token != SEMI) { 1362e853bc5dShenning parse_warn("semicolon expected."); 1363e853bc5dShenning skip_to_semi(cfile); 1364e853bc5dShenning return; 1365e853bc5dShenning } 1366e853bc5dShenning 1367e853bc5dShenning /* Create the new address range... */ 1368e853bc5dShenning new_address_range(low, high, subnet, dynamic); 1369e853bc5dShenning } 1370e853bc5dShenning 1371e853bc5dShenning 1372