00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00031 #include "dhcpd.h"
00032
00033 static unsigned char global_host_once = 1;
00034
00035 static int parse_binding_value(struct parse *cfile,
00036 struct binding_value *value);
00037
00038 #if defined (TRACING)
00039 trace_type_t *trace_readconf_type;
00040 trace_type_t *trace_readleases_type;
00041
00042 void parse_trace_setup ()
00043 {
00044 trace_readconf_type = trace_type_register ("readconf", (void *)0,
00045 trace_conf_input,
00046 trace_conf_stop, MDL);
00047 trace_readleases_type = trace_type_register ("readleases", (void *)0,
00048 trace_conf_input,
00049 trace_conf_stop, MDL);
00050 }
00051 #endif
00052
00053
00054
00055
00056
00057 isc_result_t readconf ()
00058 {
00059 isc_result_t res;
00060
00061 res = read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
00062 #if defined(LDAP_CONFIGURATION)
00063 if (res != ISC_R_SUCCESS)
00064 return (res);
00065
00066 return ldap_read_config ();
00067 #else
00068 return (res);
00069 #endif
00070 }
00071
00072 isc_result_t read_conf_file (const char *filename, struct group *group,
00073 int group_type, int leasep)
00074 {
00075 int file;
00076 struct parse *cfile;
00077 isc_result_t status;
00078 #if defined (TRACING)
00079 char *fbuf, *dbuf;
00080 off_t flen;
00081 int result;
00082 unsigned tflen, ulen;
00083 trace_type_t *ttype;
00084
00085 if (leasep)
00086 ttype = trace_readleases_type;
00087 else
00088 ttype = trace_readconf_type;
00089
00090
00091
00092
00093 if (trace_playback ()) {
00094 dbuf = (char *)0;
00095 tflen = 0;
00096 status = trace_get_file (ttype, filename, &tflen, &dbuf);
00097 if (status != ISC_R_SUCCESS)
00098 return status;
00099 ulen = tflen;
00100
00101
00102
00103
00104
00105
00106
00107 tflen = strlen (dbuf);
00108 ulen = ulen - tflen - 1;
00109 fbuf = dbuf + tflen + 1;
00110 goto memfile;
00111 }
00112 #endif
00113
00114 if ((file = open (filename, O_RDONLY | O_CLOEXEC)) < 0) {
00115 if (leasep) {
00116 log_error ("Can't open lease database %s: %m --",
00117 path_dhcpd_db);
00118 log_error (" check for failed database %s!",
00119 "rewrite attempt");
00120 log_error ("Please read the dhcpd.leases manual%s",
00121 " page if you");
00122 log_fatal ("don't know what to do about this.");
00123 } else {
00124 log_fatal ("Can't open %s: %m", filename);
00125 }
00126 }
00127
00128 cfile = (struct parse *)0;
00129 #if defined (TRACING)
00130 flen = lseek (file, (off_t)0, SEEK_END);
00131 if (flen < 0) {
00132 boom:
00133 log_fatal ("Can't lseek on %s: %m", filename);
00134 }
00135 if (lseek (file, (off_t)0, SEEK_SET) < 0)
00136 goto boom;
00137
00138 if (flen > 0x7FFFFFFFUL)
00139 log_fatal ("%s: file is too long to buffer.", filename);
00140 ulen = flen;
00141
00142
00143
00144 tflen = strlen (filename);
00145 dbuf = dmalloc (ulen + tflen + 1, MDL);
00146 if (!dbuf)
00147 log_fatal ("No memory for %s (%d bytes)",
00148 filename, ulen);
00149
00150
00151 strcpy (dbuf, filename);
00152
00153
00154 fbuf = dbuf + tflen + 1;
00155 result = read (file, fbuf, ulen);
00156 if (result < 0)
00157 log_fatal ("Can't read in %s: %m", filename);
00158 if (result != ulen)
00159 log_fatal ("%s: short read of %d bytes instead of %d.",
00160 filename, ulen, result);
00161 close (file);
00162 memfile:
00163
00164 if (trace_record ())
00165 trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
00166 status = new_parse(&cfile, -1, fbuf, ulen, filename, 0);
00167 #else
00168 status = new_parse(&cfile, file, NULL, 0, filename, 0);
00169 #endif
00170 if (status != ISC_R_SUCCESS || cfile == NULL)
00171 return status;
00172
00173 if (leasep)
00174 status = lease_file_subparse (cfile);
00175 else
00176 status = conf_file_subparse (cfile, group, group_type);
00177 end_parse (&cfile);
00178 #if defined (TRACING)
00179 dfree (dbuf, MDL);
00180 #endif
00181 return status;
00182 }
00183
00184 #if defined (TRACING)
00185 void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
00186 {
00187 char *fbuf;
00188 unsigned flen;
00189 unsigned tflen;
00190 struct parse *cfile = (struct parse *)0;
00191 static int postconf_initialized;
00192 static int leaseconf_initialized;
00193 isc_result_t status;
00194
00195
00196
00197 tflen = strlen (data);
00198 flen = len - tflen - 1;
00199 fbuf = data + tflen + 1;
00200
00201
00202 if (trace_record ())
00203 trace_write_packet (ttype, len, data, MDL);
00204
00205 status = new_parse(&cfile, -1, fbuf, flen, data, 0);
00206 if (status == ISC_R_SUCCESS || cfile != NULL) {
00207 if (ttype == trace_readleases_type)
00208 lease_file_subparse (cfile);
00209 else
00210 conf_file_subparse (cfile, root_group, ROOT_GROUP);
00211 end_parse (&cfile);
00212 }
00213
00214
00215
00216 if (!postconf_initialized && ttype == trace_readconf_type) {
00217 postconf_initialization (0);
00218 postconf_initialized = 1;
00219 }
00220
00221 if (!leaseconf_initialized && ttype == trace_readleases_type) {
00222 #if defined (PARANOIA)
00223 db_startup (0, 0, 0);
00224 #else
00225 db_startup (0);
00226 #endif
00227 leaseconf_initialized = 1;
00228 postdb_startup ();
00229 }
00230 }
00231
00232 void trace_conf_stop (trace_type_t *ttype) { }
00233 #endif
00234
00235
00236
00237
00238
00239 isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
00240 int group_type)
00241 {
00242 const char *val;
00243 enum dhcp_token token;
00244 int declaration = 0;
00245 int status;
00246
00247 do {
00248 token = peek_token (&val, (unsigned *)0, cfile);
00249 if (token == END_OF_FILE)
00250 break;
00251 declaration = parse_statement (cfile, group, group_type,
00252 (struct host_decl *)0,
00253 declaration);
00254 } while (1);
00255 skip_token(&val, (unsigned *)0, cfile);
00256
00257 status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
00258 return status;
00259 }
00260
00261
00262
00263
00264
00265
00266 isc_result_t lease_file_subparse (struct parse *cfile)
00267 {
00268 const char *val;
00269 enum dhcp_token token;
00270 isc_result_t status;
00271
00272 do {
00273 token = next_token (&val, (unsigned *)0, cfile);
00274 if (token == END_OF_FILE)
00275 break;
00276 if (token == LEASE) {
00277 struct lease *lease = (struct lease *)0;
00278 if (parse_lease_declaration (&lease, cfile)) {
00279 enter_lease (lease);
00280 lease_dereference (&lease, MDL);
00281 } else
00282 parse_warn (cfile,
00283 "possibly corrupt lease file");
00284 } else if (token == IA_NA) {
00285 parse_ia_na_declaration(cfile);
00286 } else if (token == IA_TA) {
00287 parse_ia_ta_declaration(cfile);
00288 } else if (token == IA_PD) {
00289 parse_ia_pd_declaration(cfile);
00290 } else if (token == CLASS) {
00291 parse_class_declaration(0, cfile, root_group,
00292 CLASS_TYPE_CLASS);
00293 } else if (token == SUBCLASS) {
00294 parse_class_declaration(0, cfile, root_group,
00295 CLASS_TYPE_SUBCLASS);
00296 } else if (token == HOST) {
00297 parse_host_declaration (cfile, root_group);
00298 } else if (token == GROUP) {
00299 parse_group_declaration (cfile, root_group);
00300 #if defined (FAILOVER_PROTOCOL)
00301 } else if (token == FAILOVER) {
00302 parse_failover_state_declaration
00303 (cfile, (dhcp_failover_state_t *)0);
00304 #endif
00305 #ifdef DHCPv6
00306 } else if (token == SERVER_DUID) {
00307 parse_server_duid(cfile);
00308 #endif
00309 } else {
00310 log_error ("Corrupt lease file - possible data loss!");
00311 skip_to_semi (cfile);
00312 }
00313
00314 } while (1);
00315
00316 status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
00317 return status;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 int parse_statement (cfile, group, type, host_decl, declaration)
00352 struct parse *cfile;
00353 struct group *group;
00354 int type;
00355 struct host_decl *host_decl;
00356 int declaration;
00357 {
00358 enum dhcp_token token;
00359 const char *val;
00360 struct shared_network *share;
00361 char *n;
00362 struct hardware hardware;
00363 struct executable_statement *et, *ep;
00364 struct option *option = NULL;
00365 struct option_cache *cache;
00366 int lose;
00367 int known;
00368 isc_result_t status;
00369 unsigned code;
00370
00371 token = peek_token (&val, (unsigned *)0, cfile);
00372
00373 switch (token) {
00374 case INCLUDE:
00375 skip_token(&val, (unsigned *)0, cfile);
00376 token = next_token (&val, (unsigned *)0, cfile);
00377 if (token != STRING) {
00378 parse_warn (cfile, "filename string expected.");
00379 skip_to_semi (cfile);
00380 } else {
00381 status = read_conf_file (val, group, type, 0);
00382 if (status != ISC_R_SUCCESS)
00383 parse_warn (cfile, "%s: bad parse.", val);
00384 parse_semi (cfile);
00385 }
00386 return 1;
00387
00388 case HOST:
00389 skip_token(&val, (unsigned *)0, cfile);
00390 if (type != HOST_DECL && type != CLASS_DECL) {
00391 if (global_host_once &&
00392 (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
00393 global_host_once = 0;
00394 log_error("WARNING: Host declarations are "
00395 "global. They are not limited to "
00396 "the scope you declared them in.");
00397 }
00398
00399 parse_host_declaration (cfile, group);
00400 } else {
00401 parse_warn (cfile,
00402 "host declarations not allowed here.");
00403 skip_to_semi (cfile);
00404 }
00405 return 1;
00406
00407 case GROUP:
00408 skip_token(&val, (unsigned *)0, cfile);
00409 if (type != HOST_DECL && type != CLASS_DECL)
00410 parse_group_declaration (cfile, group);
00411 else {
00412 parse_warn (cfile,
00413 "group declarations not allowed here.");
00414 skip_to_semi (cfile);
00415 }
00416 return 1;
00417
00418 case SHARED_NETWORK:
00419 skip_token(&val, (unsigned *)0, cfile);
00420 if (type == SHARED_NET_DECL ||
00421 type == HOST_DECL ||
00422 type == SUBNET_DECL ||
00423 type == CLASS_DECL) {
00424 parse_warn (cfile, "shared-network parameters not %s.",
00425 "allowed here");
00426 skip_to_semi (cfile);
00427 break;
00428 }
00429
00430 parse_shared_net_declaration (cfile, group);
00431 return 1;
00432
00433 case SUBNET:
00434 case SUBNET6:
00435 skip_token(&val, (unsigned *)0, cfile);
00436 if (type == HOST_DECL || type == SUBNET_DECL ||
00437 type == CLASS_DECL) {
00438 parse_warn (cfile,
00439 "subnet declarations not allowed here.");
00440 skip_to_semi (cfile);
00441 return 1;
00442 }
00443
00444
00445 if (group->shared_network != NULL) {
00446 if (token == SUBNET) {
00447 parse_subnet_declaration(cfile,
00448 group->shared_network);
00449 } else {
00450 parse_subnet6_declaration(cfile,
00451 group->shared_network);
00452 }
00453 break;
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 share = NULL;
00465 status = shared_network_allocate (&share, MDL);
00466 if (status != ISC_R_SUCCESS)
00467 log_fatal ("Can't allocate shared subnet: %s",
00468 isc_result_totext (status));
00469 if (!clone_group (&share -> group, group, MDL))
00470 log_fatal ("Can't allocate group for shared net");
00471 shared_network_reference (&share -> group -> shared_network,
00472 share, MDL);
00473
00474
00475
00476
00477
00478 share->flags |= SHARED_IMPLICIT;
00479
00480 if (token == SUBNET) {
00481 parse_subnet_declaration(cfile, share);
00482 } else {
00483 parse_subnet6_declaration(cfile, share);
00484 }
00485
00486
00487 if (share->subnets) {
00488 interface_reference(&share->interface,
00489 share->subnets->interface,
00490 MDL);
00491
00492
00493 if (token == SUBNET) {
00494 n = piaddrmask(&share->subnets->net,
00495 &share->subnets->netmask);
00496 } else {
00497 n = piaddrcidr(&share->subnets->net,
00498 share->subnets->prefix_len);
00499 }
00500
00501 share->name = strdup(n);
00502
00503 if (share->name == NULL)
00504 log_fatal("Out of memory allocating default "
00505 "shared network name (\"%s\").", n);
00506
00507
00508
00509 share->group->authoritative =
00510 share->subnets->group->authoritative;
00511 enter_shared_network(share);
00512 }
00513 shared_network_dereference(&share, MDL);
00514 return 1;
00515
00516 case VENDOR_CLASS:
00517 skip_token(&val, (unsigned *)0, cfile);
00518 if (type == CLASS_DECL) {
00519 parse_warn (cfile,
00520 "class declarations not allowed here.");
00521 skip_to_semi (cfile);
00522 break;
00523 }
00524 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
00525 return 1;
00526
00527 case USER_CLASS:
00528 skip_token(&val, (unsigned *)0, cfile);
00529 if (type == CLASS_DECL) {
00530 parse_warn (cfile,
00531 "class declarations not allowed here.");
00532 skip_to_semi (cfile);
00533 break;
00534 }
00535 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
00536 return 1;
00537
00538 case CLASS:
00539 skip_token(&val, (unsigned *)0, cfile);
00540 if (type == CLASS_DECL) {
00541 parse_warn (cfile,
00542 "class declarations not allowed here.");
00543 skip_to_semi (cfile);
00544 break;
00545 }
00546 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
00547 return 1;
00548
00549 case SUBCLASS:
00550 skip_token(&val, (unsigned *)0, cfile);
00551 if (type == CLASS_DECL) {
00552 parse_warn (cfile,
00553 "class declarations not allowed here.");
00554 skip_to_semi (cfile);
00555 break;
00556 }
00557 parse_class_declaration(NULL, cfile, group,
00558 CLASS_TYPE_SUBCLASS);
00559 return 1;
00560
00561 case HARDWARE:
00562 skip_token(&val, (unsigned *)0, cfile);
00563 memset (&hardware, 0, sizeof hardware);
00564 if (host_decl && memcmp(&hardware, &(host_decl->interface),
00565 sizeof(hardware)) != 0) {
00566 parse_warn(cfile, "Host %s hardware address already "
00567 "configured.", host_decl->name);
00568 break;
00569 }
00570
00571 parse_hardware_param (cfile, &hardware);
00572 if (host_decl)
00573 host_decl -> interface = hardware;
00574 else
00575 parse_warn (cfile, "hardware address parameter %s",
00576 "not allowed here.");
00577 break;
00578
00579 case FIXED_ADDR:
00580 case FIXED_ADDR6:
00581 skip_token(&val, NULL, cfile);
00582 cache = NULL;
00583 if (parse_fixed_addr_param(&cache, cfile, token)) {
00584 if (host_decl) {
00585 if (host_decl->fixed_addr) {
00586 option_cache_dereference(&cache, MDL);
00587 parse_warn(cfile,
00588 "Only one fixed address "
00589 "declaration per host.");
00590 } else {
00591 host_decl->fixed_addr = cache;
00592 }
00593 } else {
00594 parse_warn(cfile,
00595 "fixed-address parameter not "
00596 "allowed here.");
00597 option_cache_dereference(&cache, MDL);
00598 }
00599 }
00600 break;
00601
00602 case POOL:
00603 skip_token(&val, (unsigned *)0, cfile);
00604 if (type == POOL_DECL) {
00605 parse_warn (cfile, "pool declared within pool.");
00606 skip_to_semi(cfile);
00607 } else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
00608 parse_warn (cfile, "pool declared outside of network");
00609 skip_to_semi(cfile);
00610 } else
00611 parse_pool_statement (cfile, group, type);
00612
00613 return declaration;
00614
00615 case RANGE:
00616 skip_token(&val, (unsigned *)0, cfile);
00617 if (type != SUBNET_DECL || !group -> subnet) {
00618 parse_warn (cfile,
00619 "range declaration not allowed here.");
00620 skip_to_semi (cfile);
00621 return declaration;
00622 }
00623 parse_address_range (cfile, group, type, (struct pool *)0,
00624 (struct lease **)0);
00625 return declaration;
00626
00627 #ifdef DHCPv6
00628 case RANGE6:
00629 skip_token(NULL, NULL, cfile);
00630 if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
00631 parse_warn (cfile,
00632 "range6 declaration not allowed here.");
00633 skip_to_semi(cfile);
00634 return declaration;
00635 }
00636 parse_address_range6(cfile, group, NULL);
00637 return declaration;
00638
00639 case PREFIX6:
00640 skip_token(NULL, NULL, cfile);
00641 if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
00642 parse_warn (cfile,
00643 "prefix6 declaration not allowed here.");
00644 skip_to_semi(cfile);
00645 return declaration;
00646 }
00647 parse_prefix6(cfile, group, NULL);
00648 return declaration;
00649
00650 case FIXED_PREFIX6:
00651 skip_token(&val, NULL, cfile);
00652 if (!host_decl) {
00653 parse_warn (cfile,
00654 "fixed-prefix6 declaration not "
00655 "allowed here.");
00656 skip_to_semi(cfile);
00657 break;
00658 }
00659 parse_fixed_prefix6(cfile, host_decl);
00660 break;
00661
00662 case POOL6:
00663 skip_token(&val, NULL, cfile);
00664 if (type == POOL_DECL) {
00665 parse_warn (cfile, "pool declared within pool.");
00666 skip_to_semi(cfile);
00667 } else if (type != SUBNET_DECL) {
00668 parse_warn (cfile, "pool declared outside of network");
00669 skip_to_semi(cfile);
00670 } else
00671 parse_pool6_statement (cfile, group, type);
00672
00673 return declaration;
00674
00675 #endif
00676
00677 case TOKEN_NOT:
00678 skip_token(&val, (unsigned *)0, cfile);
00679 token = next_token (&val, (unsigned *)0, cfile);
00680 switch (token) {
00681 case AUTHORITATIVE:
00682 group -> authoritative = 0;
00683 goto authoritative;
00684 default:
00685 parse_warn (cfile, "expecting assertion");
00686 skip_to_semi (cfile);
00687 break;
00688 }
00689 break;
00690 case AUTHORITATIVE:
00691 skip_token(&val, (unsigned *)0, cfile);
00692 group -> authoritative = 1;
00693 authoritative:
00694 if (type == HOST_DECL)
00695 parse_warn (cfile, "authority makes no sense here.");
00696 parse_semi (cfile);
00697 break;
00698
00699
00700
00701 case SERVER_IDENTIFIER:
00702 code = DHO_DHCP_SERVER_IDENTIFIER;
00703 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
00704 &code, 0, MDL))
00705 log_fatal("Server identifier not in hash (%s:%d).",
00706 MDL);
00707 skip_token(&val, (unsigned *)0, cfile);
00708 goto finish_option;
00709
00710 case OPTION:
00711 skip_token(&val, (unsigned *)0, cfile);
00712 token = peek_token (&val, (unsigned *)0, cfile);
00713 if (token == SPACE) {
00714 if (type != ROOT_GROUP) {
00715 parse_warn (cfile,
00716 "option space definitions %s",
00717 "may not be scoped.");
00718 skip_to_semi (cfile);
00719 break;
00720 }
00721 parse_option_space_decl (cfile);
00722 return declaration;
00723 }
00724
00725 known = 0;
00726 status = parse_option_name(cfile, 1, &known, &option);
00727 if (status == ISC_R_SUCCESS) {
00728 token = peek_token (&val, (unsigned *)0, cfile);
00729 if (token == CODE) {
00730 if (type != ROOT_GROUP) {
00731 parse_warn (cfile,
00732 "option definitions%s",
00733 " may not be scoped.");
00734 skip_to_semi (cfile);
00735 option_dereference(&option, MDL);
00736 break;
00737 }
00738 skip_token(&val, (unsigned *)0, cfile);
00739
00740
00741
00742
00743
00744 if (known) {
00745 option_name_hash_delete(
00746 option->universe->name_hash,
00747 option->name, 0, MDL);
00748 option_code_hash_delete(
00749 option->universe->code_hash,
00750 &option->code, 0, MDL);
00751 }
00752
00753 parse_option_code_definition(cfile, option);
00754 option_dereference(&option, MDL);
00755 return declaration;
00756 }
00757
00758
00759
00760 if (!known) {
00761 parse_warn (cfile, "unknown option %s.%s",
00762 option -> universe -> name,
00763 option -> name);
00764 skip_to_semi (cfile);
00765 option_dereference(&option, MDL);
00766 return declaration;
00767 }
00768
00769 finish_option:
00770 et = (struct executable_statement *)0;
00771 if (!parse_option_statement
00772 (&et, cfile, 1, option,
00773 supersede_option_statement))
00774 return declaration;
00775 option_dereference(&option, MDL);
00776 goto insert_statement;
00777 } else
00778 return declaration;
00779
00780 break;
00781
00782 case FAILOVER:
00783 if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
00784 parse_warn (cfile, "failover peers may only be %s",
00785 "defined in shared-network");
00786 log_error ("declarations and the outer scope.");
00787 skip_to_semi (cfile);
00788 break;
00789 }
00790 token = next_token (&val, (unsigned *)0, cfile);
00791 #if defined (FAILOVER_PROTOCOL)
00792 parse_failover_peer (cfile, group, type);
00793 #else
00794 parse_warn (cfile, "No failover support.");
00795 skip_to_semi (cfile);
00796 #endif
00797 break;
00798
00799 #ifdef DHCPv6
00800 case SERVER_DUID:
00801 parse_server_duid_conf(cfile);
00802 break;
00803 #endif
00804
00805 default:
00806 et = (struct executable_statement *)0;
00807 lose = 0;
00808 if (!parse_executable_statement (&et, cfile, &lose,
00809 context_any)) {
00810 if (!lose) {
00811 if (declaration)
00812 parse_warn (cfile,
00813 "expecting a declaration");
00814 else
00815 parse_warn (cfile,
00816 "expecting a parameter %s",
00817 "or declaration");
00818 skip_to_semi (cfile);
00819 }
00820 return declaration;
00821 }
00822 if (!et)
00823 return declaration;
00824 insert_statement:
00825 if (group -> statements) {
00826 int multi = 0;
00827
00828
00829
00830
00831 for (ep = group -> statements; ep -> next;
00832 ep = ep -> next)
00833 if (ep -> refcnt > 1)
00834 multi = 1;
00835 if (!multi) {
00836 executable_statement_reference (&ep -> next,
00837 et, MDL);
00838 executable_statement_dereference (&et, MDL);
00839 return declaration;
00840 }
00841
00842
00843
00844
00845 ep = (struct executable_statement *)0;
00846 if (!executable_statement_allocate (&ep, MDL))
00847 log_fatal ("No memory for statements.");
00848 ep -> op = statements_statement;
00849 executable_statement_reference (&ep -> data.statements,
00850 group -> statements,
00851 MDL);
00852 executable_statement_reference (&ep -> next, et, MDL);
00853 executable_statement_dereference (&group -> statements,
00854 MDL);
00855 executable_statement_reference (&group -> statements,
00856 ep, MDL);
00857 executable_statement_dereference (&ep, MDL);
00858 } else {
00859 executable_statement_reference (&group -> statements,
00860 et, MDL);
00861 }
00862 executable_statement_dereference (&et, MDL);
00863 return declaration;
00864 }
00865
00866 return 0;
00867 }
00868
00869 #if defined (FAILOVER_PROTOCOL)
00870 void parse_failover_peer (cfile, group, type)
00871 struct parse *cfile;
00872 struct group *group;
00873 int type;
00874 {
00875 enum dhcp_token token;
00876 const char *val;
00877 dhcp_failover_state_t *peer;
00878 u_int32_t *tp;
00879 char *name;
00880 u_int32_t split;
00881 u_int8_t hba [32];
00882 unsigned hba_len = sizeof hba;
00883 int i;
00884 struct expression *expr;
00885 isc_result_t status;
00886 dhcp_failover_config_t *cp;
00887
00888 token = next_token (&val, (unsigned *)0, cfile);
00889 if (token != PEER) {
00890 parse_warn (cfile, "expecting \"peer\"");
00891 skip_to_semi (cfile);
00892 return;
00893 }
00894
00895 token = next_token (&val, (unsigned *)0, cfile);
00896 if (is_identifier (token) || token == STRING) {
00897 name = dmalloc (strlen (val) + 1, MDL);
00898 if (!name)
00899 log_fatal ("no memory for peer name %s", name);
00900 strcpy (name, val);
00901 } else {
00902 parse_warn (cfile, "expecting failover peer name.");
00903 skip_to_semi (cfile);
00904 return;
00905 }
00906
00907
00908 peer = (dhcp_failover_state_t *)0;
00909 find_failover_peer (&peer, name, MDL);
00910
00911 token = next_token (&val, (unsigned *)0, cfile);
00912 if (token == SEMI) {
00913 dfree (name, MDL);
00914 if (type != SHARED_NET_DECL)
00915 parse_warn (cfile, "failover peer reference not %s",
00916 "in shared-network declaration");
00917 else {
00918 if (!peer) {
00919 parse_warn (cfile, "reference to unknown%s%s",
00920 " failover peer ", name);
00921 return;
00922 }
00923 dhcp_failover_state_reference
00924 (&group -> shared_network -> failover_peer,
00925 peer, MDL);
00926 }
00927 dhcp_failover_state_dereference (&peer, MDL);
00928 return;
00929 } else if (token == STATE) {
00930 if (!peer) {
00931 parse_warn (cfile, "state declaration for unknown%s%s",
00932 " failover peer ", name);
00933 return;
00934 }
00935 parse_failover_state_declaration (cfile, peer);
00936 dhcp_failover_state_dereference (&peer, MDL);
00937 return;
00938 } else if (token != LBRACE) {
00939 parse_warn (cfile, "expecting left brace");
00940 skip_to_semi (cfile);
00941 }
00942
00943
00944 if (peer) {
00945 parse_warn (cfile, "redeclaration of failover peer %s", name);
00946 skip_to_rbrace (cfile, 1);
00947 dhcp_failover_state_dereference (&peer, MDL);
00948 return;
00949 }
00950
00951 status = dhcp_failover_state_allocate (&peer, MDL);
00952 if (status != ISC_R_SUCCESS)
00953 log_fatal ("Can't allocate failover peer %s: %s",
00954 name, isc_result_totext (status));
00955
00956
00957 peer -> name = name;
00958
00959 do {
00960 cp = &peer -> me;
00961 peer:
00962 token = next_token (&val, (unsigned *)0, cfile);
00963 switch (token) {
00964 case RBRACE:
00965 break;
00966
00967 case PRIMARY:
00968 peer -> i_am = primary;
00969 break;
00970
00971 case SECONDARY:
00972 peer -> i_am = secondary;
00973 if (peer -> hba)
00974 parse_warn (cfile,
00975 "secondary may not define %s",
00976 "load balance settings.");
00977 break;
00978
00979 case PEER:
00980 cp = &peer -> partner;
00981 goto peer;
00982
00983 case ADDRESS:
00984 expr = (struct expression *)0;
00985 if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
00986 skip_to_rbrace (cfile, 1);
00987 dhcp_failover_state_dereference (&peer, MDL);
00988 return;
00989 }
00990 option_cache (&cp -> address,
00991 (struct data_string *)0, expr,
00992 (struct option *)0, MDL);
00993 expression_dereference (&expr, MDL);
00994 break;
00995
00996 case PORT:
00997 token = next_token (&val, (unsigned *)0, cfile);
00998 if (token != NUMBER) {
00999 parse_warn (cfile, "expecting number");
01000 skip_to_rbrace (cfile, 1);
01001 }
01002 cp -> port = atoi (val);
01003 break;
01004
01005 case MAX_LEASE_MISBALANCE:
01006 tp = &peer->max_lease_misbalance;
01007 goto parse_idle;
01008
01009 case MAX_LEASE_OWNERSHIP:
01010 tp = &peer->max_lease_ownership;
01011 goto parse_idle;
01012
01013 case MAX_BALANCE:
01014 tp = &peer->max_balance;
01015 goto parse_idle;
01016
01017 case MIN_BALANCE:
01018 tp = &peer->min_balance;
01019 goto parse_idle;
01020
01021 case AUTO_PARTNER_DOWN:
01022 tp = &peer->auto_partner_down;
01023 goto parse_idle;
01024
01025 case MAX_RESPONSE_DELAY:
01026 tp = &cp -> max_response_delay;
01027 parse_idle:
01028 token = next_token (&val, (unsigned *)0, cfile);
01029 if (token != NUMBER) {
01030 parse_warn (cfile, "expecting number.");
01031 skip_to_rbrace (cfile, 1);
01032 dhcp_failover_state_dereference (&peer, MDL);
01033 return;
01034 }
01035 *tp = atoi (val);
01036 break;
01037
01038 case MAX_UNACKED_UPDATES:
01039 tp = &cp -> max_flying_updates;
01040 goto parse_idle;
01041
01042 case MCLT:
01043 tp = &peer -> mclt;
01044 goto parse_idle;
01045
01046 case HBA:
01047 hba_len = 32;
01048 if (peer -> i_am == secondary)
01049 parse_warn (cfile,
01050 "secondary may not define %s",
01051 "load balance settings.");
01052 if (!parse_numeric_aggregate (cfile, hba, &hba_len,
01053 COLON, 16, 8)) {
01054 skip_to_rbrace (cfile, 1);
01055 dhcp_failover_state_dereference (&peer, MDL);
01056 return;
01057 }
01058 if (hba_len != 32) {
01059 parse_warn (cfile,
01060 "HBA must be exactly 32 bytes.");
01061 break;
01062 }
01063 make_hba:
01064 peer -> hba = dmalloc (32, MDL);
01065 if (!peer -> hba) {
01066 dfree (peer -> name, MDL);
01067 dfree (peer, MDL);
01068 }
01069 memcpy (peer -> hba, hba, 32);
01070 break;
01071
01072 case SPLIT:
01073 token = next_token (&val, (unsigned *)0, cfile);
01074 if (peer -> i_am == secondary)
01075 parse_warn (cfile,
01076 "secondary may not define %s",
01077 "load balance settings.");
01078 if (token != NUMBER) {
01079 parse_warn (cfile, "expecting number");
01080 skip_to_rbrace (cfile, 1);
01081 dhcp_failover_state_dereference (&peer, MDL);
01082 return;
01083 }
01084 split = atoi (val);
01085 if (split > 255) {
01086 parse_warn (cfile, "split must be < 256");
01087 } else {
01088 memset (hba, 0, sizeof hba);
01089 for (i = 0; i < split; i++) {
01090 if (i < split)
01091 hba [i / 8] |= (1 << (i & 7));
01092 }
01093 goto make_hba;
01094 }
01095 break;
01096
01097 case LOAD:
01098 token = next_token (&val, (unsigned *)0, cfile);
01099 if (token != BALANCE) {
01100 parse_warn (cfile, "expecting 'balance'");
01101 badload:
01102 skip_to_rbrace (cfile, 1);
01103 break;
01104 }
01105 token = next_token (&val, (unsigned *)0, cfile);
01106 if (token != TOKEN_MAX) {
01107 parse_warn (cfile, "expecting 'max'");
01108 goto badload;
01109 }
01110 token = next_token (&val, (unsigned *)0, cfile);
01111 if (token != SECONDS) {
01112 parse_warn (cfile, "expecting 'secs'");
01113 goto badload;
01114 }
01115 token = next_token (&val, (unsigned *)0, cfile);
01116 if (token != NUMBER) {
01117 parse_warn (cfile, "expecting number");
01118 goto badload;
01119 }
01120 peer -> load_balance_max_secs = atoi (val);
01121 break;
01122
01123 default:
01124 parse_warn (cfile,
01125 "invalid statement in peer declaration");
01126 skip_to_rbrace (cfile, 1);
01127 dhcp_failover_state_dereference (&peer, MDL);
01128 return;
01129 }
01130 if (token != RBRACE && !parse_semi (cfile)) {
01131 skip_to_rbrace (cfile, 1);
01132 dhcp_failover_state_dereference (&peer, MDL);
01133 return;
01134 }
01135 } while (token != RBRACE);
01136
01137
01138
01139
01140 if (!peer -> partner.address)
01141 parse_warn (cfile, "peer address may not be omitted");
01142
01143 if (!peer->me.port)
01144 peer->me.port = DEFAULT_FAILOVER_PORT;
01145 if (!peer->partner.port)
01146 peer->partner.port = DEFAULT_FAILOVER_PORT;
01147
01148 if (peer -> i_am == primary) {
01149 if (!peer -> hba) {
01150 parse_warn (cfile,
01151 "primary failover server must have hba or split.");
01152 } else if (!peer -> mclt) {
01153 parse_warn (cfile,
01154 "primary failover server must have mclt.");
01155 }
01156 }
01157
01158 if (!peer->max_lease_misbalance)
01159 peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
01160 if (!peer->max_lease_ownership)
01161 peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
01162 if (!peer->max_balance)
01163 peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
01164 if (!peer->min_balance)
01165 peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
01166 if (!peer->me.max_flying_updates)
01167 peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
01168 if (!peer->me.max_response_delay)
01169 peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
01170
01171 if (type == SHARED_NET_DECL)
01172 group->shared_network->failover_peer = peer;
01173
01174
01175 if (peer -> i_am == primary) {
01176 peer -> me.state = recover;
01177 peer -> me.stos = cur_time;
01178 peer -> partner.state = unknown_state;
01179 peer -> partner.stos = cur_time;
01180 } else {
01181 peer -> me.state = recover;
01182 peer -> me.stos = cur_time;
01183 peer -> partner.state = unknown_state;
01184 peer -> partner.stos = cur_time;
01185 }
01186
01187 status = enter_failover_peer (peer);
01188 if (status != ISC_R_SUCCESS)
01189 parse_warn (cfile, "failover peer %s: %s",
01190 peer -> name, isc_result_totext (status));
01191 dhcp_failover_state_dereference (&peer, MDL);
01192 }
01193
01194 void parse_failover_state_declaration (struct parse *cfile,
01195 dhcp_failover_state_t *peer)
01196 {
01197 enum dhcp_token token;
01198 const char *val;
01199 char *name;
01200 dhcp_failover_state_t *state;
01201 dhcp_failover_config_t *cp;
01202
01203 if (!peer) {
01204 token = next_token (&val, (unsigned *)0, cfile);
01205 if (token != PEER) {
01206 parse_warn (cfile, "expecting \"peer\"");
01207 skip_to_semi (cfile);
01208 return;
01209 }
01210
01211 token = next_token (&val, (unsigned *)0, cfile);
01212 if (is_identifier (token) || token == STRING) {
01213 name = dmalloc (strlen (val) + 1, MDL);
01214 if (!name)
01215 log_fatal ("failover peer name %s: no memory",
01216 name);
01217 strcpy (name, val);
01218 } else {
01219 parse_warn (cfile, "expecting failover peer name.");
01220 skip_to_semi (cfile);
01221 return;
01222 }
01223
01224
01225 state = (dhcp_failover_state_t *)0;
01226 find_failover_peer (&state, name, MDL);
01227 if (!state) {
01228 parse_warn (cfile, "unknown failover peer: %s", name);
01229 skip_to_semi (cfile);
01230 return;
01231 }
01232
01233 token = next_token (&val, (unsigned *)0, cfile);
01234 if (token != STATE) {
01235 parse_warn (cfile, "expecting 'state'");
01236 if (token != SEMI)
01237 skip_to_semi (cfile);
01238 return;
01239 }
01240 } else {
01241 state = (dhcp_failover_state_t *)0;
01242 dhcp_failover_state_reference (&state, peer, MDL);
01243 }
01244 token = next_token (&val, (unsigned *)0, cfile);
01245 if (token != LBRACE) {
01246 parse_warn (cfile, "expecting left brace");
01247 if (token != SEMI)
01248 skip_to_semi (cfile);
01249 dhcp_failover_state_dereference (&state, MDL);
01250 return;
01251 }
01252 do {
01253 token = next_token (&val, (unsigned *)0, cfile);
01254 switch (token) {
01255 case RBRACE:
01256 break;
01257 case MY:
01258 cp = &state -> me;
01259 do_state:
01260 token = next_token (&val, (unsigned *)0, cfile);
01261 if (token != STATE) {
01262 parse_warn (cfile, "expecting 'state'");
01263 goto bogus;
01264 }
01265 parse_failover_state (cfile,
01266 &cp -> state, &cp -> stos);
01267 break;
01268
01269 case PARTNER:
01270 cp = &state -> partner;
01271 goto do_state;
01272
01273 case MCLT:
01274 if (state -> i_am == primary) {
01275 parse_warn (cfile,
01276 "mclt not valid for primary");
01277 goto bogus;
01278 }
01279 token = next_token (&val, (unsigned *)0, cfile);
01280 if (token != NUMBER) {
01281 parse_warn (cfile, "expecting a number.");
01282 goto bogus;
01283 }
01284 state -> mclt = atoi (val);
01285 parse_semi (cfile);
01286 break;
01287
01288 default:
01289 parse_warn (cfile, "expecting state setting.");
01290 bogus:
01291 skip_to_rbrace (cfile, 1);
01292 dhcp_failover_state_dereference (&state, MDL);
01293 return;
01294 }
01295 } while (token != RBRACE);
01296 dhcp_failover_state_dereference (&state, MDL);
01297 }
01298
01299 void parse_failover_state (cfile, state, stos)
01300 struct parse *cfile;
01301 enum failover_state *state;
01302 TIME *stos;
01303 {
01304 enum dhcp_token token;
01305 const char *val;
01306 enum failover_state state_in;
01307 TIME stos_in;
01308
01309 token = next_token (&val, (unsigned *)0, cfile);
01310 switch (token) {
01311 case UNKNOWN_STATE:
01312 state_in = unknown_state;
01313 break;
01314
01315 case PARTNER_DOWN:
01316 state_in = partner_down;
01317 break;
01318
01319 case NORMAL:
01320 state_in = normal;
01321 break;
01322
01323 case COMMUNICATIONS_INTERRUPTED:
01324 state_in = communications_interrupted;
01325 break;
01326
01327 case CONFLICT_DONE:
01328 state_in = conflict_done;
01329 break;
01330
01331 case RESOLUTION_INTERRUPTED:
01332 state_in = resolution_interrupted;
01333 break;
01334
01335 case POTENTIAL_CONFLICT:
01336 state_in = potential_conflict;
01337 break;
01338
01339 case RECOVER:
01340 state_in = recover;
01341 break;
01342
01343 case RECOVER_WAIT:
01344 state_in = recover_wait;
01345 break;
01346
01347 case RECOVER_DONE:
01348 state_in = recover_done;
01349 break;
01350
01351 case SHUTDOWN:
01352 state_in = shut_down;
01353 break;
01354
01355 case PAUSED:
01356 state_in = paused;
01357 break;
01358
01359 case STARTUP:
01360 state_in = startup;
01361 break;
01362
01363 default:
01364 parse_warn (cfile, "unknown failover state");
01365 skip_to_semi (cfile);
01366 return;
01367 }
01368
01369 token = next_token (&val, (unsigned *)0, cfile);
01370 if (token == SEMI) {
01371 stos_in = cur_time;
01372 } else {
01373 if (token != AT) {
01374 parse_warn (cfile, "expecting \"at\"");
01375 skip_to_semi (cfile);
01376 return;
01377 }
01378
01379 stos_in = parse_date (cfile);
01380 if (!stos_in)
01381 return;
01382 }
01383
01384
01385
01386
01387 *stos = stos_in;
01388 *state = state_in;
01389 }
01390 #endif
01391
01424 void get_permit(cfile, permit_head, is_allow, valid_from, valid_until)
01425 struct parse *cfile;
01426 struct permit **permit_head;
01427 int is_allow;
01428 TIME *valid_from, *valid_until;
01429 {
01430 enum dhcp_token token;
01431 struct permit *permit;
01432 const char *val;
01433 int need_clients = 1;
01434 TIME t;
01435
01436
01437 permit = new_permit(MDL);
01438 if (!permit)
01439 log_fatal ("no memory for permit");
01440
01441 token = next_token(&val, NULL, cfile);
01442 switch (token) {
01443 case UNKNOWN:
01444 permit->type = permit_unknown_clients;
01445 break;
01446
01447 case KNOWN_CLIENTS:
01448 need_clients = 0;
01449 permit->type = permit_known_clients;
01450 break;
01451
01452 case UNKNOWN_CLIENTS:
01453 need_clients = 0;
01454 permit->type = permit_unknown_clients;
01455 break;
01456
01457 case KNOWN:
01458 permit->type = permit_known_clients;
01459 break;
01460
01461 case AUTHENTICATED:
01462 permit->type = permit_authenticated_clients;
01463 break;
01464
01465 case UNAUTHENTICATED:
01466 permit->type = permit_unauthenticated_clients;
01467 break;
01468
01469 case ALL:
01470 permit->type = permit_all_clients;
01471 break;
01472
01473 case DYNAMIC:
01474 permit->type = permit_dynamic_bootp_clients;
01475 if (next_token (&val, NULL, cfile) != TOKEN_BOOTP) {
01476 parse_warn (cfile, "expecting \"bootp\"");
01477 skip_to_semi (cfile);
01478 free_permit (permit, MDL);
01479 return;
01480 }
01481 break;
01482
01483 case MEMBERS:
01484 need_clients = 0;
01485 if (next_token (&val, NULL, cfile) != OF) {
01486 parse_warn (cfile, "expecting \"of\"");
01487 skip_to_semi (cfile);
01488 free_permit (permit, MDL);
01489 return;
01490 }
01491 if (next_token (&val, NULL, cfile) != STRING) {
01492 parse_warn (cfile, "expecting class name.");
01493 skip_to_semi (cfile);
01494 free_permit (permit, MDL);
01495 return;
01496 }
01497 permit->type = permit_class;
01498 permit->class = NULL;
01499 find_class(&permit->class, val, MDL);
01500 if (!permit->class)
01501 parse_warn(cfile, "no such class: %s", val);
01502 break;
01503
01504 case AFTER:
01505 need_clients = 0;
01506 if (*valid_from || *valid_until) {
01507 parse_warn(cfile, "duplicate \"after\" clause.");
01508 skip_to_semi(cfile);
01509 free_permit(permit, MDL);
01510 return;
01511 }
01512 t = parse_date_core(cfile);
01513 permit->type = permit_after;
01514 permit->after = t;
01515 if (is_allow) {
01516 *valid_from = t;
01517 } else {
01518 *valid_until = t;
01519 }
01520 break;
01521
01522 default:
01523 parse_warn (cfile, "expecting permit type.");
01524 skip_to_semi (cfile);
01525 free_permit (permit, MDL);
01526 return;
01527 }
01528
01529
01530
01531
01532
01533 if ((need_clients != 0) &&
01534 (next_token (&val, NULL, cfile) != CLIENTS)) {
01535 parse_warn (cfile, "expecting \"clients\"");
01536 skip_to_semi (cfile);
01537 free_permit (permit, MDL);
01538 return;
01539 }
01540
01541 while (*permit_head)
01542 permit_head = &((*permit_head)->next);
01543 *permit_head = permit;
01544 parse_semi (cfile);
01545
01546 return;
01547 }
01548
01549
01550
01551
01552
01553
01554 int permit_list_match (struct permit *lhs, struct permit *rhs)
01555 {
01556 struct permit *plp, *prp;
01557 int matched;
01558
01559 if (!lhs)
01560 return 1;
01561 if (!rhs)
01562 return 0;
01563 for (plp = lhs; plp; plp = plp -> next) {
01564 matched = 0;
01565 for (prp = rhs; prp; prp = prp -> next) {
01566 if (prp -> type == plp -> type &&
01567 (prp -> type != permit_class ||
01568 prp -> class == plp -> class)) {
01569 matched = 1;
01570 break;
01571 }
01572 }
01573 if (!matched)
01574 return 0;
01575 }
01576 return 1;
01577 }
01578
01598 void parse_pool_statement (cfile, group, type)
01599 struct parse *cfile;
01600 struct group *group;
01601 int type;
01602 {
01603 enum dhcp_token token;
01604 const char *val;
01605 int done = 0;
01606 struct pool *pool, **p, *pp;
01607 int declaration = 0;
01608 isc_result_t status;
01609 struct lease *lpchain = NULL, *lp;
01610
01611 pool = NULL;
01612 status = pool_allocate(&pool, MDL);
01613 if (status != ISC_R_SUCCESS)
01614 log_fatal ("no memory for pool: %s",
01615 isc_result_totext (status));
01616
01617 if (type == SUBNET_DECL)
01618 shared_network_reference(&pool->shared_network,
01619 group->subnet->shared_network,
01620 MDL);
01621 else if (type == SHARED_NET_DECL)
01622 shared_network_reference(&pool->shared_network,
01623 group->shared_network, MDL);
01624 else {
01625 parse_warn(cfile, "Dynamic pools are only valid inside "
01626 "subnet or shared-network statements.");
01627 skip_to_semi(cfile);
01628 return;
01629 }
01630
01631 if (pool->shared_network == NULL ||
01632 !clone_group(&pool->group, pool->shared_network->group, MDL))
01633 log_fatal("can't clone pool group.");
01634
01635 #if defined (FAILOVER_PROTOCOL)
01636
01637 if (pool->shared_network->failover_peer)
01638 dhcp_failover_state_reference
01639 (&pool->failover_peer,
01640 pool->shared_network->failover_peer, MDL);
01641 #endif
01642
01643 if (!parse_lbrace(cfile)) {
01644 pool_dereference(&pool, MDL);
01645 return;
01646 }
01647
01648 do {
01649 token = peek_token(&val, NULL, cfile);
01650 switch (token) {
01651 case TOKEN_NO:
01652 skip_token(&val, NULL, cfile);
01653 token = next_token(&val, NULL, cfile);
01654 if (token != FAILOVER ||
01655 (token = next_token(&val, NULL, cfile)) != PEER) {
01656 parse_warn(cfile,
01657 "expecting \"failover peer\".");
01658 skip_to_semi(cfile);
01659 continue;
01660 }
01661 #if defined (FAILOVER_PROTOCOL)
01662 if (pool->failover_peer)
01663 dhcp_failover_state_dereference
01664 (&pool->failover_peer, MDL);
01665 #endif
01666 break;
01667
01668 #if defined (FAILOVER_PROTOCOL)
01669 case FAILOVER:
01670 skip_token(&val, NULL, cfile);
01671 token = next_token (&val, NULL, cfile);
01672 if (token != PEER) {
01673 parse_warn(cfile, "expecting 'peer'.");
01674 skip_to_semi(cfile);
01675 break;
01676 }
01677 token = next_token(&val, NULL, cfile);
01678 if (token != STRING) {
01679 parse_warn(cfile, "expecting string.");
01680 skip_to_semi(cfile);
01681 break;
01682 }
01683 if (pool->failover_peer)
01684 dhcp_failover_state_dereference
01685 (&pool->failover_peer, MDL);
01686 status = find_failover_peer(&pool->failover_peer,
01687 val, MDL);
01688 if (status != ISC_R_SUCCESS)
01689 parse_warn(cfile,
01690 "failover peer %s: %s", val,
01691 isc_result_totext (status));
01692 else
01693 pool->failover_peer->pool_count++;
01694 parse_semi(cfile);
01695 break;
01696 #endif
01697
01698 case RANGE:
01699 skip_token(&val, NULL, cfile);
01700 parse_address_range (cfile, group, type,
01701 pool, &lpchain);
01702 break;
01703 case ALLOW:
01704 skip_token(&val, NULL, cfile);
01705 get_permit(cfile, &pool->permit_list, 1,
01706 &pool->valid_from, &pool->valid_until);
01707 break;
01708
01709 case DENY:
01710 skip_token(&val, NULL, cfile);
01711 get_permit(cfile, &pool->prohibit_list, 0,
01712 &pool->valid_from, &pool->valid_until);
01713 break;
01714
01715 case RBRACE:
01716 skip_token(&val, NULL, cfile);
01717 done = 1;
01718 break;
01719
01720 case END_OF_FILE:
01721
01722
01723
01724
01725
01726 parse_warn(cfile, "unexpected end of file");
01727 goto cleanup;
01728
01729 default:
01730 declaration = parse_statement(cfile, pool->group,
01731 POOL_DECL, NULL,
01732 declaration);
01733 break;
01734 }
01735 } while (!done);
01736
01737
01738 for (pp = pool->shared_network->pools; pp; pp = pp->next) {
01739 if (pp->group->statements != pool->group->statements)
01740 continue;
01741 #if defined (FAILOVER_PROTOCOL)
01742 if (pool->failover_peer != pp->failover_peer)
01743 continue;
01744 #endif
01745 if (!permit_list_match(pp->permit_list,
01746 pool->permit_list) ||
01747 !permit_list_match(pool->permit_list,
01748 pp->permit_list) ||
01749 !permit_list_match(pp->prohibit_list,
01750 pool->prohibit_list) ||
01751 !permit_list_match(pool->prohibit_list,
01752 pp->prohibit_list))
01753 continue;
01754
01755
01756
01757 for (lp = lpchain; lp; lp = lp->next) {
01758 pool_dereference(&lp->pool, MDL);
01759 pool_reference(&lp->pool, pp, MDL);
01760 }
01761 break;
01762 }
01763
01764
01765
01766 if (!pp) {
01767 p = &pool->shared_network->pools;
01768 for (; *p; p = &((*p)->next))
01769 ;
01770 pool_reference(p, pool, MDL);
01771 }
01772
01773
01774
01775 if (!lpchain) {
01776 parse_warn(cfile, "Pool declaration with no address range.");
01777 log_error("Pool declarations must always contain at least");
01778 log_error("one range statement.");
01779 }
01780
01781 cleanup:
01782
01783 lp = NULL;
01784 while (lpchain) {
01785 lease_reference(&lp, lpchain, MDL);
01786 lease_dereference(&lpchain, MDL);
01787 if (lp->next) {
01788 lease_reference(&lpchain, lp->next, MDL);
01789 lease_dereference(&lp->next, MDL);
01790 lease_dereference(&lp, MDL);
01791 }
01792 }
01793 pool_dereference(&pool, MDL);
01794 }
01795
01796
01797
01798
01799 int parse_lbrace (cfile)
01800 struct parse *cfile;
01801 {
01802 enum dhcp_token token;
01803 const char *val;
01804
01805 token = next_token (&val, (unsigned *)0, cfile);
01806 if (token != LBRACE) {
01807 parse_warn (cfile, "expecting left brace.");
01808 skip_to_semi (cfile);
01809 return 0;
01810 }
01811 return 1;
01812 }
01813
01814
01815
01816
01817 void parse_host_declaration (cfile, group)
01818 struct parse *cfile;
01819 struct group *group;
01820 {
01821 const char *val;
01822 enum dhcp_token token;
01823 struct host_decl *host;
01824 char *name;
01825 int declaration = 0;
01826 int dynamicp = 0;
01827 int deleted = 0;
01828 isc_result_t status;
01829 int known;
01830 struct option *option;
01831 struct expression *expr = NULL;
01832
01833 name = parse_host_name (cfile);
01834 if (!name) {
01835 parse_warn (cfile, "expecting a name for host declaration.");
01836 skip_to_semi (cfile);
01837 return;
01838 }
01839
01840 host = (struct host_decl *)0;
01841 status = host_allocate (&host, MDL);
01842 if (status != ISC_R_SUCCESS)
01843 log_fatal ("can't allocate host decl struct %s: %s",
01844 name, isc_result_totext (status));
01845 host -> name = name;
01846 if (!clone_group (&host -> group, group, MDL)) {
01847 log_fatal ("can't clone group for host %s", name);
01848 boom:
01849 host_dereference (&host, MDL);
01850 return;
01851 }
01852
01853 if (!parse_lbrace (cfile))
01854 goto boom;
01855
01856 do {
01857 token = peek_token (&val, (unsigned *)0, cfile);
01858 if (token == RBRACE) {
01859 skip_token(&val, (unsigned *)0, cfile);
01860 break;
01861 }
01862 if (token == END_OF_FILE) {
01863 skip_token(&val, (unsigned *)0, cfile);
01864 parse_warn (cfile, "unexpected end of file");
01865 break;
01866 }
01867
01868
01869 if (token == DYNAMIC) {
01870 dynamicp = 1;
01871 skip_token(&val, (unsigned *)0, cfile);
01872 if (!parse_semi (cfile))
01873 break;
01874 continue;
01875 }
01876
01877
01878 if (token == TOKEN_DELETED) {
01879 deleted = 1;
01880 skip_token(&val, (unsigned *)0, cfile);
01881 if (!parse_semi (cfile))
01882 break;
01883 continue;
01884 }
01885
01886 if (token == GROUP) {
01887 struct group_object *go;
01888 skip_token(&val, (unsigned *)0, cfile);
01889 token = next_token (&val, (unsigned *)0, cfile);
01890 if (token != STRING && !is_identifier (token)) {
01891 parse_warn (cfile,
01892 "expecting string or identifier.");
01893 skip_to_rbrace (cfile, 1);
01894 break;
01895 }
01896 go = (struct group_object *)0;
01897 if (!group_hash_lookup (&go, group_name_hash,
01898 val, strlen (val), MDL)) {
01899 parse_warn (cfile, "unknown group %s in host %s",
01900 val, host -> name);
01901 } else {
01902 if (host -> named_group)
01903 group_object_dereference
01904 (&host -> named_group, MDL);
01905 group_object_reference (&host -> named_group,
01906 go, MDL);
01907 group_object_dereference (&go, MDL);
01908 }
01909 if (!parse_semi (cfile))
01910 break;
01911 continue;
01912 }
01913
01914 if (token == UID) {
01915 const char *s;
01916 unsigned char *t = 0;
01917 unsigned len;
01918
01919 skip_token(&val, (unsigned *)0, cfile);
01920 data_string_forget (&host -> client_identifier, MDL);
01921
01922 if (host->client_identifier.len != 0) {
01923 parse_warn(cfile, "Host %s already has a "
01924 "client identifier.",
01925 host->name);
01926 break;
01927 }
01928
01929
01930 token = peek_token (&val, (unsigned *)0, cfile);
01931 if (token == STRING) {
01932 skip_token(&val, &len, cfile);
01933 s = val;
01934 host -> client_identifier.terminated = 1;
01935 } else {
01936 len = 0;
01937 t = parse_numeric_aggregate
01938 (cfile,
01939 (unsigned char *)0, &len, ':', 16, 8);
01940 if (!t) {
01941 parse_warn (cfile,
01942 "expecting hex list.");
01943 skip_to_semi (cfile);
01944 }
01945 s = (const char *)t;
01946 }
01947 if (!buffer_allocate
01948 (&host -> client_identifier.buffer,
01949 len + host -> client_identifier.terminated, MDL))
01950 log_fatal ("no memory for uid for host %s.",
01951 host -> name);
01952 host -> client_identifier.data =
01953 host -> client_identifier.buffer -> data;
01954 host -> client_identifier.len = len;
01955 memcpy (host -> client_identifier.buffer -> data, s,
01956 len + host -> client_identifier.terminated);
01957 if (t)
01958 dfree (t, MDL);
01959
01960 if (!parse_semi (cfile))
01961 break;
01962 continue;
01963 }
01964
01965 if (token == HOST_IDENTIFIER) {
01966 if (host->host_id_option != NULL) {
01967 parse_warn(cfile,
01968 "only one host-identifier allowed "
01969 "per host");
01970 skip_to_rbrace(cfile, 1);
01971 break;
01972 }
01973 skip_token(&val, NULL, cfile);
01974 token = next_token(&val, NULL, cfile);
01975 if (token == V6RELOPT) {
01976 token = next_token(&val, NULL, cfile);
01977 if (token != NUMBER) {
01978 parse_warn(cfile,
01979 "host-identifier v6relopt "
01980 "must have a number");
01981 skip_to_rbrace(cfile, 1);
01982 break;
01983 }
01984 host->relays = atoi(val);
01985 if (host->relays < 0) {
01986 parse_warn(cfile,
01987 "host-identifier v6relopt "
01988 "must have a number >= 0");
01989 skip_to_rbrace(cfile, 1);
01990 break;
01991 }
01992 } else if (token != OPTION) {
01993 parse_warn(cfile,
01994 "host-identifier must be an option"
01995 " or v6relopt");
01996 skip_to_rbrace(cfile, 1);
01997 break;
01998 }
01999 known = 0;
02000 option = NULL;
02001 status = parse_option_name(cfile, 1, &known, &option);
02002 if ((status != ISC_R_SUCCESS) || (option == NULL)) {
02003 break;
02004 }
02005 if (!known) {
02006 parse_warn(cfile, "unknown option %s.%s",
02007 option->universe->name,
02008 option->name);
02009 skip_to_rbrace(cfile, 1);
02010 break;
02011 }
02012
02013 if (! parse_option_data(&expr, cfile, 1, option)) {
02014 skip_to_rbrace(cfile, 1);
02015 option_dereference(&option, MDL);
02016 break;
02017 }
02018
02019 if (!parse_semi(cfile)) {
02020 skip_to_rbrace(cfile, 1);
02021 expression_dereference(&expr, MDL);
02022 option_dereference(&option, MDL);
02023 break;
02024 }
02025
02026 option_reference(&host->host_id_option, option, MDL);
02027 option_dereference(&option, MDL);
02028 data_string_copy(&host->host_id,
02029 &expr->data.const_data, MDL);
02030 expression_dereference(&expr, MDL);
02031 continue;
02032 }
02033
02034 declaration = parse_statement(cfile, host->group, HOST_DECL,
02035 host, declaration);
02036 } while (1);
02037
02038 if (deleted) {
02039 struct host_decl *hp = (struct host_decl *)0;
02040 if (host_hash_lookup (&hp, host_name_hash,
02041 (unsigned char *)host -> name,
02042 strlen (host -> name), MDL)) {
02043 delete_host (hp, 0);
02044 host_dereference (&hp, MDL);
02045 }
02046 } else {
02047 if (host -> named_group && host -> named_group -> group) {
02048 if (host -> group -> statements ||
02049 (host -> group -> authoritative !=
02050 host -> named_group -> group -> authoritative)) {
02051 if (host -> group -> next)
02052 group_dereference (&host -> group -> next,
02053 MDL);
02054 group_reference (&host -> group -> next,
02055 host -> named_group -> group,
02056 MDL);
02057 } else {
02058 group_dereference (&host -> group, MDL);
02059 group_reference (&host -> group,
02060 host -> named_group -> group,
02061 MDL);
02062 }
02063 }
02064
02065 if (dynamicp)
02066 host -> flags |= HOST_DECL_DYNAMIC;
02067 else
02068 host -> flags |= HOST_DECL_STATIC;
02069
02070 status = enter_host (host, dynamicp, 0);
02071 if (status != ISC_R_SUCCESS)
02072 parse_warn (cfile, "host %s: %s", host -> name,
02073 isc_result_totext (status));
02074 }
02075 host_dereference (&host, MDL);
02076 }
02077
02078
02079
02080
02081 int parse_class_declaration (cp, cfile, group, type)
02082 struct class **cp;
02083 struct parse *cfile;
02084 struct group *group;
02085 int type;
02086 {
02087 const char *val;
02088 enum dhcp_token token;
02089 struct class *class = NULL, *pc = NULL;
02090 int declaration = 0;
02091 int lose = 0;
02092 struct data_string data;
02093 char *name;
02094 const char *tname;
02095 struct executable_statement *stmt = NULL;
02096 int new = 1;
02097 isc_result_t status = ISC_R_FAILURE;
02098 int matchedonce = 0;
02099 int submatchedonce = 0;
02100 unsigned code;
02101
02102 token = next_token (&val, NULL, cfile);
02103 if (token != STRING) {
02104 parse_warn (cfile, "Expecting class name");
02105 skip_to_semi (cfile);
02106 return 0;
02107 }
02108
02109
02110 find_class (&pc, val, MDL);
02111
02112
02113
02114
02115
02116 if (pc && (type == CLASS_TYPE_CLASS)) {
02117 class_reference(&class, pc, MDL);
02118 new = 0;
02119 class_dereference(&pc, MDL);
02120 } else if (!pc && (type != CLASS_TYPE_CLASS)) {
02121 parse_warn(cfile, "no class named %s", val);
02122 skip_to_semi(cfile);
02123 return 0;
02124 }
02125
02126
02127
02128
02129
02130
02131
02132
02133 if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
02134 data.len = strlen (val);
02135 data.buffer = NULL;
02136 if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
02137 log_fatal ("no memory for class name.");
02138 data.data = &data.buffer -> data [0];
02139 data.terminated = 1;
02140
02141 tname = type ? "implicit-vendor-class" : "implicit-user-class";
02142 } else if (type == CLASS_TYPE_CLASS) {
02143 tname = val;
02144 } else {
02145 tname = NULL;
02146 }
02147
02148 if (tname) {
02149 name = dmalloc (strlen (tname) + 1, MDL);
02150 if (!name)
02151 log_fatal ("No memory for class name %s.", tname);
02152 strcpy (name, val);
02153 } else
02154 name = NULL;
02155
02156
02157 if (type == CLASS_TYPE_SUBCLASS) {
02158 token = peek_token (&val, NULL, cfile);
02159 if (token == STRING) {
02160 skip_token(&val, &data.len, cfile);
02161 data.buffer = NULL;
02162
02163 if (!buffer_allocate (&data.buffer,
02164 data.len + 1, MDL)) {
02165 if (pc)
02166 class_dereference (&pc, MDL);
02167
02168 return 0;
02169 }
02170 data.terminated = 1;
02171 data.data = &data.buffer -> data [0];
02172 memcpy ((char *)data.buffer -> data, val,
02173 data.len + 1);
02174 } else if (token == NUMBER_OR_NAME || token == NUMBER) {
02175 memset (&data, 0, sizeof data);
02176 if (!parse_cshl (&data, cfile)) {
02177 if (pc)
02178 class_dereference (&pc, MDL);
02179 return 0;
02180 }
02181 } else {
02182 parse_warn (cfile, "Expecting string or hex list.");
02183 if (pc)
02184 class_dereference (&pc, MDL);
02185 return 0;
02186 }
02187 }
02188
02189
02190
02191 if (type != CLASS_TYPE_CLASS)
02192 class_hash_lookup (&class, pc -> hash,
02193 (const char *)data.data, data.len, MDL);
02194
02195
02196 if (!class) {
02197
02198 if (type == CLASS_TYPE_SUBCLASS) {
02199 status = subclass_allocate (&class, MDL);
02200 } else {
02201 status = class_allocate (&class, MDL);
02202 }
02203 if (pc) {
02204 group_reference (&class -> group, pc -> group, MDL);
02205 class_reference (&class -> superclass, pc, MDL);
02206 class -> lease_limit = pc -> lease_limit;
02207 if (class -> lease_limit) {
02208 class -> billed_leases =
02209 dmalloc (class -> lease_limit *
02210 sizeof (struct lease *), MDL);
02211 if (!class -> billed_leases)
02212 log_fatal ("no memory for billing");
02213 memset (class -> billed_leases, 0,
02214 (class -> lease_limit *
02215 sizeof (struct lease *)));
02216 }
02217 data_string_copy (&class -> hash_string, &data, MDL);
02218 if (!pc -> hash &&
02219 !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
02220 log_fatal ("No memory for subclass hash.");
02221 class_hash_add (pc -> hash,
02222 (const char *)class -> hash_string.data,
02223 class -> hash_string.len,
02224 (void *)class, MDL);
02225 } else {
02226 if (class->group)
02227 group_dereference(&class->group, MDL);
02228 if (!clone_group (&class -> group, group, MDL))
02229 log_fatal ("no memory to clone class group.");
02230 }
02231
02232
02233
02234
02235 if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
02236 stmt = NULL;
02237 if (!executable_statement_allocate (&stmt, MDL))
02238 log_fatal ("no memory for class statement.");
02239 stmt -> op = supersede_option_statement;
02240 if (option_cache_allocate (&stmt -> data.option,
02241 MDL)) {
02242 stmt -> data.option -> data = data;
02243 code = (type == CLASS_TYPE_VENDOR)
02244 ? DHO_VENDOR_CLASS_IDENTIFIER
02245 : DHO_USER_CLASS;
02246 option_code_hash_lookup(
02247 &stmt->data.option->option,
02248 dhcp_universe.code_hash,
02249 &code, 0, MDL);
02250 }
02251 class -> statements = stmt;
02252 }
02253
02254
02255 if (class->name != NULL)
02256 dfree(class->name, MDL);
02257 class->name = name;
02258 }
02259
02260 if (type != CLASS_TYPE_CLASS)
02261 data_string_forget(&data, MDL);
02262
02263
02264 if (class -> superclass) {
02265 token = peek_token (&val, NULL, cfile);
02266 if (token == SEMI) {
02267 skip_token(&val, NULL, cfile);
02268
02269 if (cp)
02270 status = class_reference (cp, class, MDL);
02271 class_dereference (&class, MDL);
02272 if (pc)
02273 class_dereference (&pc, MDL);
02274 return cp ? (status == ISC_R_SUCCESS) : 1;
02275 }
02276
02277 if (!clone_group (&class -> group, class -> group, MDL))
02278 log_fatal ("can't clone class group.");
02279
02280 }
02281
02282 if (!parse_lbrace (cfile)) {
02283 class_dereference (&class, MDL);
02284 if (pc)
02285 class_dereference (&pc, MDL);
02286 return 0;
02287 }
02288
02289 do {
02290 token = peek_token (&val, NULL, cfile);
02291 if (token == RBRACE) {
02292 skip_token(&val, NULL, cfile);
02293 break;
02294 } else if (token == END_OF_FILE) {
02295 skip_token(&val, NULL, cfile);
02296 parse_warn (cfile, "unexpected end of file");
02297 break;
02298 } else if (token == DYNAMIC) {
02299 class->flags |= CLASS_DECL_DYNAMIC;
02300 skip_token(&val, NULL, cfile);
02301 if (!parse_semi (cfile))
02302 break;
02303 continue;
02304 } else if (token == TOKEN_DELETED) {
02305 class->flags |= CLASS_DECL_DELETED;
02306 skip_token(&val, NULL, cfile);
02307 if (!parse_semi (cfile))
02308 break;
02309 continue;
02310 } else if (token == MATCH) {
02311 if (pc) {
02312 parse_warn (cfile,
02313 "invalid match in subclass.");
02314 skip_to_semi (cfile);
02315 break;
02316 }
02317 skip_token(&val, NULL, cfile);
02318 token = peek_token (&val, NULL, cfile);
02319 if (token != IF)
02320 goto submatch;
02321 skip_token(&val, NULL, cfile);
02322 if (matchedonce) {
02323 parse_warn(cfile, "A class may only have "
02324 "one 'match if' clause.");
02325 skip_to_semi(cfile);
02326 break;
02327 }
02328 matchedonce = 1;
02329 if (class->expr)
02330 expression_dereference(&class->expr, MDL);
02331 if (!parse_boolean_expression (&class->expr, cfile,
02332 &lose)) {
02333 if (!lose) {
02334 parse_warn (cfile,
02335 "expecting boolean expr.");
02336 skip_to_semi (cfile);
02337 }
02338 } else {
02339 #if defined (DEBUG_EXPRESSION_PARSE)
02340 print_expression ("class match",
02341 class -> expr);
02342 #endif
02343 parse_semi (cfile);
02344 }
02345 } else if (token == SPAWN) {
02346 skip_token(&val, NULL, cfile);
02347 if (pc) {
02348 parse_warn (cfile,
02349 "invalid spawn in subclass.");
02350 skip_to_semi (cfile);
02351 break;
02352 }
02353 class -> spawning = 1;
02354 token = next_token (&val, NULL, cfile);
02355 if (token != WITH) {
02356 parse_warn (cfile,
02357 "expecting with after spawn");
02358 skip_to_semi (cfile);
02359 break;
02360 }
02361 submatch:
02362 if (submatchedonce) {
02363 parse_warn (cfile,
02364 "can't override existing %s.",
02365 "submatch/spawn");
02366 skip_to_semi (cfile);
02367 break;
02368 }
02369 submatchedonce = 1;
02370 if (class->submatch)
02371 expression_dereference(&class->submatch, MDL);
02372 if (!parse_data_expression (&class -> submatch,
02373 cfile, &lose)) {
02374 if (!lose) {
02375 parse_warn (cfile,
02376 "expecting data expr.");
02377 skip_to_semi (cfile);
02378 }
02379 } else {
02380 #if defined (DEBUG_EXPRESSION_PARSE)
02381 print_expression ("class submatch",
02382 class -> submatch);
02383 #endif
02384 parse_semi (cfile);
02385 }
02386 } else if (token == LEASE) {
02387 skip_token(&val, NULL, cfile);
02388 token = next_token (&val, NULL, cfile);
02389 if (token != LIMIT) {
02390 parse_warn (cfile, "expecting \"limit\"");
02391 if (token != SEMI)
02392 skip_to_semi (cfile);
02393 break;
02394 }
02395 token = next_token (&val, NULL, cfile);
02396 if (token != NUMBER) {
02397 parse_warn (cfile, "expecting a number");
02398 if (token != SEMI)
02399 skip_to_semi (cfile);
02400 break;
02401 }
02402 class -> lease_limit = atoi (val);
02403 if (class->billed_leases)
02404 dfree(class->billed_leases, MDL);
02405 class -> billed_leases =
02406 dmalloc (class -> lease_limit *
02407 sizeof (struct lease *), MDL);
02408 if (!class -> billed_leases)
02409 log_fatal ("no memory for billed leases.");
02410 memset (class -> billed_leases, 0,
02411 (class -> lease_limit *
02412 sizeof (struct lease *)));
02413 have_billing_classes = 1;
02414 parse_semi (cfile);
02415 } else {
02416 declaration = parse_statement (cfile, class -> group,
02417 CLASS_DECL, NULL,
02418 declaration);
02419 }
02420 } while (1);
02421
02422 if (class->flags & CLASS_DECL_DELETED) {
02423 if (type == CLASS_TYPE_CLASS) {
02424 struct class *theclass = NULL;
02425
02426 status = find_class(&theclass, class->name, MDL);
02427 if (status == ISC_R_SUCCESS) {
02428 delete_class(theclass, 0);
02429 class_dereference(&theclass, MDL);
02430 }
02431 } else {
02432 class_hash_delete(pc->hash,
02433 (char *)class->hash_string.data,
02434 class->hash_string.len, MDL);
02435 }
02436 } else if (type == CLASS_TYPE_CLASS && new) {
02437 if (!collections -> classes)
02438 class_reference (&collections -> classes, class, MDL);
02439 else {
02440 struct class *c;
02441 for (c = collections -> classes;
02442 c -> nic; c = c -> nic)
02443 ;
02444 class_reference (&c -> nic, class, MDL);
02445 }
02446 }
02447
02448 if (cp)
02449 status = class_reference (cp, class, MDL);
02450 class_dereference (&class, MDL);
02451 if (pc)
02452 class_dereference (&pc, MDL);
02453 return cp ? (status == ISC_R_SUCCESS) : 1;
02454 }
02455
02456
02457
02458
02459 void parse_shared_net_declaration (cfile, group)
02460 struct parse *cfile;
02461 struct group *group;
02462 {
02463 const char *val;
02464 enum dhcp_token token;
02465 struct shared_network *share;
02466 char *name;
02467 int declaration = 0;
02468 isc_result_t status;
02469
02470 share = (struct shared_network *)0;
02471 status = shared_network_allocate (&share, MDL);
02472 if (status != ISC_R_SUCCESS)
02473 log_fatal ("Can't allocate shared subnet: %s",
02474 isc_result_totext (status));
02475 if (clone_group (&share -> group, group, MDL) == 0) {
02476 log_fatal ("Can't clone group for shared net");
02477 }
02478 shared_network_reference (&share -> group -> shared_network,
02479 share, MDL);
02480
02481
02482 token = peek_token (&val, (unsigned *)0, cfile);
02483 if (token == STRING) {
02484 skip_token(&val, (unsigned *)0, cfile);
02485
02486 if (val [0] == 0) {
02487 parse_warn (cfile, "zero-length shared network name");
02488 val = "<no-name-given>";
02489 }
02490 name = dmalloc (strlen (val) + 1, MDL);
02491 if (!name)
02492 log_fatal ("no memory for shared network name");
02493 strcpy (name, val);
02494 } else {
02495 name = parse_host_name (cfile);
02496 if (!name) {
02497 parse_warn (cfile,
02498 "expecting a name for shared-network");
02499 skip_to_semi (cfile);
02500 shared_network_dereference (&share, MDL);
02501 return;
02502 }
02503 }
02504 share -> name = name;
02505
02506 if (!parse_lbrace (cfile)) {
02507 shared_network_dereference (&share, MDL);
02508 return;
02509 }
02510
02511 do {
02512 token = peek_token (&val, (unsigned *)0, cfile);
02513 if (token == RBRACE) {
02514 skip_token(&val, (unsigned *)0, cfile);
02515 if (!share -> subnets)
02516 parse_warn (cfile,
02517 "empty shared-network decl");
02518 else
02519 enter_shared_network (share);
02520 shared_network_dereference (&share, MDL);
02521 return;
02522 } else if (token == END_OF_FILE) {
02523 skip_token(&val, (unsigned *)0, cfile);
02524 parse_warn (cfile, "unexpected end of file");
02525 break;
02526 } else if (token == INTERFACE) {
02527 skip_token(&val, (unsigned *)0, cfile);
02528 token = next_token (&val, (unsigned *)0, cfile);
02529 new_shared_network_interface (cfile, share, val);
02530 if (!parse_semi (cfile))
02531 break;
02532 continue;
02533 }
02534
02535 declaration = parse_statement (cfile, share -> group,
02536 SHARED_NET_DECL,
02537 (struct host_decl *)0,
02538 declaration);
02539 } while (1);
02540 shared_network_dereference (&share, MDL);
02541 }
02542
02543
02544 static int
02545 common_subnet_parsing(struct parse *cfile,
02546 struct shared_network *share,
02547 struct subnet *subnet) {
02548 enum dhcp_token token;
02549 struct subnet *t, *u;
02550 const char *val;
02551 int declaration = 0;
02552
02553 enter_subnet(subnet);
02554
02555 if (!parse_lbrace(cfile)) {
02556 subnet_dereference(&subnet, MDL);
02557 return 0;
02558 }
02559
02560 do {
02561 token = peek_token(&val, NULL, cfile);
02562 if (token == RBRACE) {
02563 skip_token(&val, NULL, cfile);
02564 break;
02565 } else if (token == END_OF_FILE) {
02566 skip_token(&val, NULL, cfile);
02567 parse_warn (cfile, "unexpected end of file");
02568 break;
02569 } else if (token == INTERFACE) {
02570 skip_token(&val, NULL, cfile);
02571 token = next_token(&val, NULL, cfile);
02572 new_shared_network_interface(cfile, share, val);
02573 if (!parse_semi(cfile))
02574 break;
02575 continue;
02576 }
02577 declaration = parse_statement(cfile, subnet->group,
02578 SUBNET_DECL,
02579 NULL,
02580 declaration);
02581 } while (1);
02582
02583
02584 if (share->subnets == NULL) {
02585 subnet_reference(&share->subnets, subnet, MDL);
02586 } else {
02587 u = NULL;
02588 for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
02589 if (subnet_inner_than(subnet, t, 0)) {
02590 subnet_reference(&subnet->next_sibling, t, MDL);
02591 if (u) {
02592 subnet_dereference(&u->next_sibling,
02593 MDL);
02594 subnet_reference(&u->next_sibling,
02595 subnet, MDL);
02596 } else {
02597 subnet_dereference(&share->subnets,
02598 MDL);
02599 subnet_reference(&share->subnets,
02600 subnet, MDL);
02601 }
02602 subnet_dereference(&subnet, MDL);
02603 return 1;
02604 }
02605 u = t;
02606 }
02607 subnet_reference(&t->next_sibling, subnet, MDL);
02608 }
02609 subnet_dereference(&subnet, MDL);
02610 return 1;
02611 }
02612
02613
02614
02615
02616 void parse_subnet_declaration (cfile, share)
02617 struct parse *cfile;
02618 struct shared_network *share;
02619 {
02620 const char *val;
02621 enum dhcp_token token;
02622 struct subnet *subnet;
02623 struct iaddr iaddr;
02624 unsigned char addr [4];
02625 unsigned len = sizeof addr;
02626 isc_result_t status;
02627
02628 subnet = (struct subnet *)0;
02629 status = subnet_allocate (&subnet, MDL);
02630 if (status != ISC_R_SUCCESS)
02631 log_fatal ("Allocation of new subnet failed: %s",
02632 isc_result_totext (status));
02633 shared_network_reference (&subnet -> shared_network, share, MDL);
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643 if (share->flags & SHARED_IMPLICIT) {
02644 group_reference(&subnet->group, share->group, MDL);
02645 } else {
02646 if (!clone_group(&subnet->group, share->group, MDL)) {
02647 log_fatal("Allocation of group for new subnet failed.");
02648 }
02649 }
02650 subnet_reference (&subnet -> group -> subnet, subnet, MDL);
02651
02652
02653 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
02654 subnet_dereference (&subnet, MDL);
02655 return;
02656 }
02657 memcpy (iaddr.iabuf, addr, len);
02658 iaddr.len = len;
02659 subnet -> net = iaddr;
02660
02661 token = next_token (&val, (unsigned *)0, cfile);
02662 if (token != NETMASK) {
02663 parse_warn (cfile, "Expecting netmask");
02664 skip_to_semi (cfile);
02665 return;
02666 }
02667
02668
02669 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
02670 subnet_dereference (&subnet, MDL);
02671 return;
02672 }
02673 memcpy (iaddr.iabuf, addr, len);
02674 iaddr.len = len;
02675 subnet -> netmask = iaddr;
02676
02677
02678 if (host_addr (subnet -> net, subnet -> netmask)) {
02679 char *maskstr;
02680
02681 maskstr = strdup (piaddr (subnet -> netmask));
02682 parse_warn (cfile,
02683 "subnet %s netmask %s: bad subnet number/mask combination.",
02684 piaddr (subnet -> net), maskstr);
02685 free(maskstr);
02686 subnet_dereference (&subnet, MDL);
02687 skip_to_semi (cfile);
02688 return;
02689 }
02690
02691 common_subnet_parsing(cfile, share, subnet);
02692 }
02693
02694
02695
02696
02697 void
02698 parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
02699 #if !defined(DHCPv6)
02700 parse_warn(cfile, "No DHCPv6 support.");
02701 skip_to_semi(cfile);
02702 #else
02703 struct subnet *subnet;
02704 isc_result_t status;
02705 enum dhcp_token token;
02706 const char *val;
02707 char *endp;
02708 int ofs;
02709 const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0,
02710 0xF0, 0xF8, 0xFC, 0xFE };
02711 struct iaddr iaddr;
02712
02713 if (local_family != AF_INET6) {
02714 parse_warn(cfile, "subnet6 statement is only supported "
02715 "in DHCPv6 mode.");
02716 skip_to_semi(cfile);
02717 return;
02718 }
02719
02720 subnet = NULL;
02721 status = subnet_allocate(&subnet, MDL);
02722 if (status != ISC_R_SUCCESS) {
02723 log_fatal("Allocation of new subnet failed: %s",
02724 isc_result_totext(status));
02725 }
02726 shared_network_reference(&subnet->shared_network, share, MDL);
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736 if (share->flags & SHARED_IMPLICIT) {
02737 group_reference(&subnet->group, share->group, MDL);
02738 } else {
02739 if (!clone_group(&subnet->group, share->group, MDL)) {
02740 log_fatal("Allocation of group for new subnet failed.");
02741 }
02742 }
02743 subnet_reference(&subnet->group->subnet, subnet, MDL);
02744
02745 if (!parse_ip6_addr(cfile, &subnet->net)) {
02746 subnet_dereference(&subnet, MDL);
02747 return;
02748 }
02749
02750 token = next_token(&val, NULL, cfile);
02751 if (token != SLASH) {
02752 parse_warn(cfile, "Expecting a '/'.");
02753 skip_to_semi(cfile);
02754 return;
02755 }
02756
02757 token = next_token(&val, NULL, cfile);
02758 if (token != NUMBER) {
02759 parse_warn(cfile, "Expecting a number.");
02760 skip_to_semi(cfile);
02761 return;
02762 }
02763
02764 subnet->prefix_len = strtol(val, &endp, 10);
02765 if ((subnet->prefix_len < 0) ||
02766 (subnet->prefix_len > 128) ||
02767 (*endp != '\0')) {
02768 parse_warn(cfile, "Expecting a number between 0 and 128.");
02769 skip_to_semi(cfile);
02770 return;
02771 }
02772
02773 if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
02774 parse_warn(cfile, "New subnet mask too short.");
02775 skip_to_semi(cfile);
02776 return;
02777 }
02778
02779
02780
02781
02782 subnet->netmask.len = 16;
02783 ofs = subnet->prefix_len / 8;
02784 if (ofs < subnet->netmask.len) {
02785 subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
02786 }
02787 while (--ofs >= 0) {
02788 subnet->netmask.iabuf[ofs] = 0xFF;
02789 }
02790
02791
02792 iaddr = subnet_number(subnet->net, subnet->netmask);
02793 if (memcmp(&iaddr, &subnet->net, 16) != 0) {
02794 parse_warn(cfile,
02795 "subnet %s/%d: prefix not long enough for address.",
02796 piaddr(subnet->net), subnet->prefix_len);
02797 subnet_dereference(&subnet, MDL);
02798 skip_to_semi(cfile);
02799 return;
02800 }
02801
02802 if (!common_subnet_parsing(cfile, share, subnet)) {
02803 return;
02804 }
02805 #endif
02806 }
02807
02808
02809
02810 void parse_group_declaration (cfile, group)
02811 struct parse *cfile;
02812 struct group *group;
02813 {
02814 const char *val;
02815 enum dhcp_token token;
02816 struct group *g;
02817 int declaration = 0;
02818 struct group_object *t = NULL;
02819 isc_result_t status;
02820 char *name = NULL;
02821 int deletedp = 0;
02822 int dynamicp = 0;
02823 int staticp = 0;
02824
02825 g = NULL;
02826 if (!clone_group(&g, group, MDL))
02827 log_fatal("no memory for explicit group.");
02828
02829 token = peek_token(&val, NULL, cfile);
02830 if (is_identifier (token) || token == STRING) {
02831 skip_token(&val, NULL, cfile);
02832
02833 name = dmalloc(strlen(val) + 1, MDL);
02834 if (!name)
02835 log_fatal("no memory for group decl name %s", val);
02836 strcpy(name, val);
02837 }
02838
02839 if (!parse_lbrace(cfile)) {
02840 group_dereference(&g, MDL);
02841 return;
02842 }
02843
02844 do {
02845 token = peek_token(&val, NULL, cfile);
02846 if (token == RBRACE) {
02847 skip_token(&val, NULL, cfile);
02848 break;
02849 } else if (token == END_OF_FILE) {
02850 skip_token(&val, NULL, cfile);
02851 parse_warn(cfile, "unexpected end of file");
02852 break;
02853 } else if (token == TOKEN_DELETED) {
02854 skip_token(&val, NULL, cfile);
02855 parse_semi(cfile);
02856 deletedp = 1;
02857 } else if (token == DYNAMIC) {
02858 skip_token(&val, NULL, cfile);
02859 parse_semi(cfile);
02860 dynamicp = 1;
02861 } else if (token == STATIC) {
02862 skip_token(&val, NULL, cfile);
02863 parse_semi(cfile);
02864 staticp = 1;
02865 }
02866 declaration = parse_statement(cfile, g, GROUP_DECL,
02867 NULL, declaration);
02868 } while (1);
02869
02870 if (name) {
02871 if (deletedp) {
02872 if (group_name_hash) {
02873 t = NULL;
02874 if (group_hash_lookup(&t, group_name_hash,
02875 name,
02876 strlen(name), MDL)) {
02877 delete_group(t, 0);
02878 }
02879 }
02880 } else {
02881 t = NULL;
02882 status = group_object_allocate(&t, MDL);
02883 if (status != ISC_R_SUCCESS)
02884 log_fatal("no memory for group decl %s: %s",
02885 val, isc_result_totext(status));
02886 group_reference(&t->group, g, MDL);
02887 t->name = name;
02888
02889 t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
02890 (dynamicp ? GROUP_OBJECT_DYNAMIC : 0));
02891 supersede_group(t, 0);
02892 }
02893 if (t != NULL)
02894 group_object_dereference(&t, MDL);
02895 }
02896 }
02897
02898
02899
02900
02901
02902 int
02903 parse_fixed_addr_param(struct option_cache **oc,
02904 struct parse *cfile,
02905 enum dhcp_token type) {
02906 int parse_ok;
02907 const char *val;
02908 enum dhcp_token token;
02909 struct expression *expr = NULL;
02910 struct expression *tmp, *new;
02911 int status;
02912
02913 do {
02914 tmp = NULL;
02915 if (type == FIXED_ADDR) {
02916 parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
02917 } else {
02918
02919 parse_ok = parse_ip6_addr_expr(&tmp, cfile);
02920 }
02921 if (parse_ok) {
02922 if (expr != NULL) {
02923 new = NULL;
02924 status = make_concat(&new, expr, tmp);
02925 expression_dereference(&expr, MDL);
02926 expression_dereference(&tmp, MDL);
02927 if (!status) {
02928 return 0;
02929 }
02930 expr = new;
02931 } else {
02932 expr = tmp;
02933 }
02934 } else {
02935 if (expr != NULL) {
02936 expression_dereference (&expr, MDL);
02937 }
02938 return 0;
02939 }
02940 token = peek_token(&val, NULL, cfile);
02941 if (token == COMMA) {
02942 token = next_token(&val, NULL, cfile);
02943 }
02944 } while (token == COMMA);
02945
02946 if (!parse_semi(cfile)) {
02947 if (expr) {
02948 expression_dereference (&expr, MDL);
02949 }
02950 return 0;
02951 }
02952
02953 status = option_cache(oc, NULL, expr, NULL, MDL);
02954 expression_dereference(&expr, MDL);
02955 return status;
02956 }
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974 int parse_lease_declaration (struct lease **lp, struct parse *cfile)
02975 {
02976 const char *val;
02977 enum dhcp_token token;
02978 unsigned char addr [4];
02979 unsigned len = sizeof addr;
02980 int seenmask = 0;
02981 int seenbit;
02982 char tbuf [32];
02983 struct lease *lease;
02984 struct executable_statement *on;
02985 int lose;
02986 TIME t;
02987 int noequal, newbinding;
02988 struct binding *binding;
02989 struct binding_value *nv;
02990 isc_result_t status;
02991 struct option_cache *oc;
02992 pair *p;
02993 binding_state_t new_state;
02994 unsigned buflen = 0;
02995 struct class *class;
02996
02997 lease = (struct lease *)0;
02998 status = lease_allocate (&lease, MDL);
02999 if (status != ISC_R_SUCCESS)
03000 return 0;
03001
03002
03003 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
03004 lease_dereference (&lease, MDL);
03005 return 0;
03006 }
03007 memcpy (lease -> ip_addr.iabuf, addr, len);
03008 lease -> ip_addr.len = len;
03009
03010 if (!parse_lbrace (cfile)) {
03011 lease_dereference (&lease, MDL);
03012 return 0;
03013 }
03014
03015 do {
03016 token = next_token (&val, (unsigned *)0, cfile);
03017 if (token == RBRACE)
03018 break;
03019 else if (token == END_OF_FILE) {
03020 parse_warn (cfile, "unexpected end of file");
03021 break;
03022 }
03023 strncpy (tbuf, val, sizeof tbuf);
03024 tbuf [(sizeof tbuf) - 1] = 0;
03025
03026
03027 switch (token) {
03028 case STARTS:
03029 case ENDS:
03030 case TIMESTAMP:
03031 case TSTP:
03032 case TSFP:
03033 case ATSFP:
03034 case CLTT:
03035 t = parse_date (cfile);
03036 switch (token) {
03037 case STARTS:
03038 seenbit = 1;
03039 lease -> starts = t;
03040 break;
03041
03042 case ENDS:
03043 seenbit = 2;
03044 lease -> ends = t;
03045 break;
03046
03047 case TSTP:
03048 seenbit = 65536;
03049 lease -> tstp = t;
03050 break;
03051
03052 case TSFP:
03053 seenbit = 131072;
03054 lease -> tsfp = t;
03055 break;
03056
03057 case ATSFP:
03058 seenbit = 262144;
03059 lease->atsfp = t;
03060 break;
03061
03062 case CLTT:
03063 seenbit = 524288;
03064 lease -> cltt = t;
03065 break;
03066
03067 default:
03068 log_fatal ("Impossible error at %s:%d.", MDL);
03069 return 0;
03070 }
03071 break;
03072
03073
03074 case UID:
03075 seenbit = 8;
03076 token = peek_token (&val, (unsigned *)0, cfile);
03077 if (token == STRING) {
03078 unsigned char *tuid;
03079 skip_token(&val, &buflen, cfile);
03080 if (buflen < sizeof lease -> uid_buf) {
03081 tuid = lease -> uid_buf;
03082 lease -> uid_max =
03083 sizeof lease -> uid_buf;
03084 } else {
03085 tuid = ((unsigned char *)
03086 dmalloc (buflen, MDL));
03087 if (!tuid) {
03088 log_error ("no space for uid");
03089 lease_dereference (&lease,
03090 MDL);
03091 return 0;
03092 }
03093 lease -> uid_max = buflen;
03094 }
03095 lease -> uid_len = buflen;
03096 memcpy (tuid, val, lease -> uid_len);
03097 lease -> uid = tuid;
03098 } else {
03099 buflen = 0;
03100 lease -> uid = (parse_numeric_aggregate
03101 (cfile, (unsigned char *)0,
03102 &buflen, ':', 16, 8));
03103 if (!lease -> uid) {
03104 lease_dereference (&lease, MDL);
03105 return 0;
03106 }
03107 lease -> uid_len = buflen;
03108 lease -> uid_max = buflen;
03109 if (lease -> uid_len == 0) {
03110 lease -> uid = (unsigned char *)0;
03111 parse_warn (cfile, "zero-length uid");
03112 seenbit = 0;
03113 parse_semi (cfile);
03114 break;
03115 }
03116 }
03117 parse_semi (cfile);
03118 if (!lease -> uid) {
03119 log_fatal ("No memory for lease uid");
03120 }
03121 break;
03122
03123 case CLASS:
03124 seenbit = 32;
03125 token = next_token (&val, (unsigned *)0, cfile);
03126 if (!is_identifier (token)) {
03127 if (token != SEMI)
03128 skip_to_rbrace (cfile, 1);
03129 lease_dereference (&lease, MDL);
03130 return 0;
03131 }
03132 parse_semi (cfile);
03133
03134 break;
03135
03136 case HARDWARE:
03137 seenbit = 64;
03138 parse_hardware_param (cfile,
03139 &lease -> hardware_addr);
03140 break;
03141
03142 case TOKEN_RESERVED:
03143 seenbit = 0;
03144 lease->flags |= RESERVED_LEASE;
03145 parse_semi(cfile);
03146 break;
03147
03148 case DYNAMIC_BOOTP:
03149 seenbit = 0;
03150 lease -> flags |= BOOTP_LEASE;
03151 parse_semi (cfile);
03152 break;
03153
03154
03155 case TOKEN_ABANDONED:
03156 seenbit = 256;
03157 lease -> binding_state = FTS_ABANDONED;
03158 lease -> next_binding_state = FTS_ABANDONED;
03159 parse_semi (cfile);
03160 break;
03161
03162 case TOKEN_NEXT:
03163 seenbit = 128;
03164 token = next_token (&val, (unsigned *)0, cfile);
03165 if (token != BINDING) {
03166 parse_warn (cfile, "expecting 'binding'");
03167 skip_to_semi (cfile);
03168 break;
03169 }
03170 goto do_binding_state;
03171
03172 case REWIND:
03173 seenbit = 512;
03174 token = next_token(&val, NULL, cfile);
03175 if (token != BINDING) {
03176 parse_warn(cfile, "expecting 'binding'");
03177 skip_to_semi(cfile);
03178 break;
03179 }
03180 goto do_binding_state;
03181
03182 case BINDING:
03183 seenbit = 256;
03184
03185 do_binding_state:
03186 token = next_token (&val, (unsigned *)0, cfile);
03187 if (token != STATE) {
03188 parse_warn (cfile, "expecting 'state'");
03189 skip_to_semi (cfile);
03190 break;
03191 }
03192 token = next_token (&val, (unsigned *)0, cfile);
03193 switch (token) {
03194 case TOKEN_ABANDONED:
03195 new_state = FTS_ABANDONED;
03196 break;
03197 case TOKEN_FREE:
03198 new_state = FTS_FREE;
03199 break;
03200 case TOKEN_ACTIVE:
03201 new_state = FTS_ACTIVE;
03202 break;
03203 case TOKEN_EXPIRED:
03204 new_state = FTS_EXPIRED;
03205 break;
03206 case TOKEN_RELEASED:
03207 new_state = FTS_RELEASED;
03208 break;
03209 case TOKEN_RESET:
03210 new_state = FTS_RESET;
03211 break;
03212 case TOKEN_BACKUP:
03213 new_state = FTS_BACKUP;
03214 break;
03215
03216
03217
03218
03219 case TOKEN_RESERVED:
03220 new_state = FTS_ACTIVE;
03221 lease->flags |= RESERVED_LEASE;
03222 break;
03223 case TOKEN_BOOTP:
03224 new_state = FTS_ACTIVE;
03225 lease->flags |= BOOTP_LEASE;
03226 break;
03227
03228 default:
03229 parse_warn (cfile,
03230 "%s: expecting a binding state.",
03231 val);
03232 skip_to_semi (cfile);
03233 return 0;
03234 }
03235
03236 if (seenbit == 256) {
03237 lease -> binding_state = new_state;
03238
03239
03240
03241
03242
03243
03244
03245 if (!(seenmask & 128))
03246 lease->next_binding_state = new_state;
03247
03248
03249 if (!(seenmask & 512))
03250 lease->rewind_binding_state = new_state;
03251 } else if (seenbit == 128)
03252 lease -> next_binding_state = new_state;
03253 else if (seenbit == 512)
03254 lease->rewind_binding_state = new_state;
03255 else
03256 log_fatal("Impossible condition at %s:%d.",
03257 MDL);
03258
03259 parse_semi (cfile);
03260 break;
03261
03262 case CLIENT_HOSTNAME:
03263 seenbit = 1024;
03264 token = peek_token (&val, (unsigned *)0, cfile);
03265 if (token == STRING) {
03266 if (!parse_string (cfile,
03267 &lease -> client_hostname,
03268 (unsigned *)0)) {
03269 lease_dereference (&lease, MDL);
03270 return 0;
03271 }
03272 } else {
03273 lease -> client_hostname =
03274 parse_host_name (cfile);
03275 if (lease -> client_hostname)
03276 parse_semi (cfile);
03277 else {
03278 parse_warn (cfile,
03279 "expecting a hostname.");
03280 skip_to_semi (cfile);
03281 lease_dereference (&lease, MDL);
03282 return 0;
03283 }
03284 }
03285 break;
03286
03287 case BILLING:
03288 seenbit = 2048;
03289 class = (struct class *)0;
03290 token = next_token (&val, (unsigned *)0, cfile);
03291 if (token == CLASS) {
03292 token = next_token (&val,
03293 (unsigned *)0, cfile);
03294 if (token != STRING) {
03295 parse_warn (cfile, "expecting string");
03296 if (token != SEMI)
03297 skip_to_semi (cfile);
03298 token = BILLING;
03299 break;
03300 }
03301 if (lease -> billing_class)
03302 class_dereference (&lease -> billing_class,
03303 MDL);
03304 find_class (&class, val, MDL);
03305 if (!class)
03306 parse_warn (cfile,
03307 "unknown class %s", val);
03308 parse_semi (cfile);
03309 } else if (token == SUBCLASS) {
03310 if (lease -> billing_class)
03311 class_dereference (&lease -> billing_class,
03312 MDL);
03313 parse_class_declaration(&class, cfile, NULL,
03314 CLASS_TYPE_SUBCLASS);
03315 } else {
03316 parse_warn (cfile, "expecting \"class\"");
03317 if (token != SEMI)
03318 skip_to_semi (cfile);
03319 }
03320 if (class) {
03321 class_reference (&lease -> billing_class,
03322 class, MDL);
03323 class_dereference (&class, MDL);
03324 }
03325 break;
03326
03327 case ON:
03328 on = (struct executable_statement *)0;
03329 lose = 0;
03330 if (!parse_on_statement (&on, cfile, &lose)) {
03331 skip_to_rbrace (cfile, 1);
03332 lease_dereference (&lease, MDL);
03333 return 0;
03334 }
03335 seenbit = 0;
03336 if ((on->data.on.evtypes & ON_EXPIRY) &&
03337 on->data.on.statements) {
03338 seenbit |= 16384;
03339 executable_statement_reference
03340 (&lease->on_star.on_expiry,
03341 on->data.on.statements, MDL);
03342 }
03343 if ((on->data.on.evtypes & ON_RELEASE) &&
03344 on->data.on.statements) {
03345 seenbit |= 32768;
03346 executable_statement_reference
03347 (&lease->on_star.on_release,
03348 on->data.on.statements, MDL);
03349 }
03350 executable_statement_dereference (&on, MDL);
03351 break;
03352
03353 case OPTION:
03354 case SUPERSEDE:
03355 noequal = 0;
03356 seenbit = 0;
03357 oc = (struct option_cache *)0;
03358 if (parse_option_decl (&oc, cfile)) {
03359 if (oc -> option -> universe !=
03360 &agent_universe) {
03361 parse_warn (cfile,
03362 "agent option expected.");
03363 option_cache_dereference (&oc, MDL);
03364 break;
03365 }
03366 if (!lease -> agent_options &&
03367 !(option_chain_head_allocate
03368 (&lease -> agent_options, MDL))) {
03369 log_error ("no memory to stash agent option");
03370 break;
03371 }
03372 for (p = &lease -> agent_options -> first;
03373 *p; p = &((*p) -> cdr))
03374 ;
03375 *p = cons (0, 0);
03376 option_cache_reference (((struct option_cache **)
03377 &((*p) -> car)), oc, MDL);
03378 option_cache_dereference (&oc, MDL);
03379 }
03380 break;
03381
03382 case TOKEN_SET:
03383 noequal = 0;
03384
03385 token = next_token (&val, (unsigned *)0, cfile);
03386 if (token != NAME && token != NUMBER_OR_NAME) {
03387 parse_warn (cfile,
03388 "%s can't be a variable name",
03389 val);
03390 badset:
03391 skip_to_semi (cfile);
03392 lease_dereference (&lease, MDL);
03393 return 0;
03394 }
03395
03396 seenbit = 0;
03397 special_set:
03398 if (lease -> scope)
03399 binding = find_binding (lease -> scope, val);
03400 else
03401 binding = (struct binding *)0;
03402
03403 if (!binding) {
03404 if (!lease -> scope)
03405 if (!(binding_scope_allocate
03406 (&lease -> scope, MDL)))
03407 log_fatal ("no memory for scope");
03408 binding = dmalloc (sizeof *binding, MDL);
03409 if (!binding)
03410 log_fatal ("No memory for lease %s.",
03411 "binding");
03412 memset (binding, 0, sizeof *binding);
03413 binding -> name =
03414 dmalloc (strlen (val) + 1, MDL);
03415 if (!binding -> name)
03416 log_fatal ("No memory for binding %s.",
03417 "name");
03418 strcpy (binding -> name, val);
03419 newbinding = 1;
03420 } else {
03421 newbinding = 0;
03422 }
03423
03424 nv = NULL;
03425 if (!binding_value_allocate(&nv, MDL))
03426 log_fatal("no memory for binding value.");
03427
03428 if (!noequal) {
03429 token = next_token (&val, (unsigned *)0, cfile);
03430 if (token != EQUAL) {
03431 parse_warn (cfile,
03432 "expecting '=' in set statement.");
03433 goto badset;
03434 }
03435 }
03436
03437 if (!parse_binding_value(cfile, nv)) {
03438 binding_value_dereference(&nv, MDL);
03439 lease_dereference(&lease, MDL);
03440 return 0;
03441 }
03442
03443 if (newbinding) {
03444 binding_value_reference(&binding->value,
03445 nv, MDL);
03446 binding->next = lease->scope->bindings;
03447 lease->scope->bindings = binding;
03448 } else {
03449 binding_value_dereference(&binding->value, MDL);
03450 binding_value_reference(&binding->value,
03451 nv, MDL);
03452 }
03453
03454 binding_value_dereference(&nv, MDL);
03455 parse_semi(cfile);
03456 break;
03457
03458
03459 default:
03460 if (!strcasecmp (val, "ddns-fwd-name")) {
03461 seenbit = 4096;
03462 noequal = 1;
03463 goto special_set;
03464 } else if (!strcasecmp (val, "ddns-rev-name")) {
03465 seenbit = 8192;
03466 noequal = 1;
03467 goto special_set;
03468 } else
03469 parse_warn(cfile, "Unexpected configuration "
03470 "directive.");
03471 skip_to_semi (cfile);
03472 seenbit = 0;
03473 lease_dereference (&lease, MDL);
03474 return 0;
03475 }
03476
03477 if (seenmask & seenbit) {
03478 parse_warn (cfile,
03479 "Too many %s parameters in lease %s\n",
03480 tbuf, piaddr (lease -> ip_addr));
03481 } else
03482 seenmask |= seenbit;
03483
03484 } while (1);
03485
03486
03487 if (!(seenmask & 256)) {
03488 if (lease->ends > cur_time ||
03489 lease->on_star.on_expiry || lease->on_star.on_release)
03490 lease->binding_state = FTS_ACTIVE;
03491 #if defined (FAILOVER_PROTOCOL)
03492 else if (lease->pool && lease->pool->failover_peer)
03493 lease->binding_state = FTS_EXPIRED;
03494 #endif
03495 else
03496 lease->binding_state = FTS_FREE;
03497 if (lease->binding_state == FTS_ACTIVE) {
03498 #if defined (FAILOVER_PROTOCOL)
03499 if (lease->pool && lease->pool->failover_peer)
03500 lease->next_binding_state = FTS_EXPIRED;
03501 else
03502 #endif
03503 lease->next_binding_state = FTS_FREE;
03504 } else
03505 lease->next_binding_state = lease->binding_state;
03506
03507
03508 lease->rewind_binding_state = lease->binding_state;
03509 }
03510
03511 if (!(seenmask & 65536))
03512 lease->tstp = lease->ends;
03513
03514 lease_reference (lp, lease, MDL);
03515 lease_dereference (&lease, MDL);
03516 return 1;
03517 }
03518
03519
03520
03521
03522
03523
03524
03525 static int
03526 parse_binding_value(struct parse *cfile, struct binding_value *value)
03527 {
03528 struct data_string *data;
03529 unsigned char *s;
03530 const char *val;
03531 unsigned buflen;
03532 int token;
03533
03534 if ((cfile == NULL) || (value == NULL))
03535 log_fatal("Invalid arguments at %s:%d.", MDL);
03536
03537 token = peek_token(&val, NULL, cfile);
03538 if (token == STRING) {
03539 skip_token(&val, &buflen, cfile);
03540
03541 value->type = binding_data;
03542 value->value.data.len = buflen;
03543
03544 data = &value->value.data;
03545
03546 if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
03547 log_fatal ("No memory for binding.");
03548
03549 memcpy(data->buffer->data, val, buflen + 1);
03550
03551 data->data = data->buffer->data;
03552 data->terminated = 1;
03553 } else if (token == NUMBER_OR_NAME) {
03554 value->type = binding_data;
03555
03556 data = &value->value.data;
03557 s = parse_numeric_aggregate(cfile, NULL, &data->len,
03558 ':', 16, 8);
03559 if (s == NULL) {
03560 skip_to_semi(cfile);
03561 return 0;
03562 }
03563
03564 if (data->len) {
03565 if (!buffer_allocate(&data->buffer, data->len + 1,
03566 MDL))
03567 log_fatal("No memory for binding.");
03568
03569 memcpy(data->buffer->data, s, data->len);
03570 data->data = data->buffer->data;
03571
03572 dfree (s, MDL);
03573 }
03574 } else if (token == PERCENT) {
03575 skip_token(&val, NULL, cfile);
03576 token = next_token(&val, NULL, cfile);
03577 if (token != NUMBER) {
03578 parse_warn(cfile, "expecting decimal number.");
03579 if (token != SEMI)
03580 skip_to_semi(cfile);
03581 return 0;
03582 }
03583 value->type = binding_numeric;
03584 value->value.intval = atol(val);
03585 } else if (token == NAME) {
03586 token = next_token(&val, NULL, cfile);
03587 value->type = binding_boolean;
03588 if (!strcasecmp(val, "true"))
03589 value->value.boolean = 1;
03590 else if (!strcasecmp(val, "false"))
03591 value->value.boolean = 0;
03592 else {
03593 parse_warn(cfile, "expecting true or false");
03594 if (token != SEMI)
03595 skip_to_semi(cfile);
03596 return 0;
03597 }
03598 } else {
03599 parse_warn (cfile, "expecting a constant value.");
03600 if (token != SEMI)
03601 skip_to_semi (cfile);
03602 return 0;
03603 }
03604
03605 return 1;
03606 }
03607
03608
03609
03610
03611 void parse_address_range (cfile, group, type, inpool, lpchain)
03612 struct parse *cfile;
03613 struct group *group;
03614 int type;
03615 struct pool *inpool;
03616 struct lease **lpchain;
03617 {
03618 struct iaddr low, high, net;
03619 unsigned char addr [4];
03620 unsigned len = sizeof addr;
03621 enum dhcp_token token;
03622 const char *val;
03623 int dynamic = 0;
03624 struct subnet *subnet;
03625 struct shared_network *share;
03626 struct pool *pool;
03627 isc_result_t status;
03628
03629 if ((token = peek_token (&val,
03630 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
03631 skip_token(&val, (unsigned *)0, cfile);
03632 dynamic = 1;
03633 }
03634
03635
03636 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
03637 return;
03638 memcpy (low.iabuf, addr, len);
03639 low.len = len;
03640
03641
03642 token = peek_token (&val, (unsigned *)0, cfile);
03643 if (token == SEMI)
03644 high = low;
03645 else {
03646
03647 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
03648 return;
03649 memcpy (high.iabuf, addr, len);
03650 high.len = len;
03651 }
03652
03653 token = next_token (&val, (unsigned *)0, cfile);
03654 if (token != SEMI) {
03655 parse_warn (cfile, "semicolon expected.");
03656 skip_to_semi (cfile);
03657 return;
03658 }
03659
03660 if (type == SUBNET_DECL) {
03661 subnet = group -> subnet;
03662 share = subnet -> shared_network;
03663 } else {
03664 share = group -> shared_network;
03665 for (subnet = share -> subnets;
03666 subnet; subnet = subnet -> next_sibling) {
03667 net = subnet_number (low, subnet -> netmask);
03668 if (addr_eq (net, subnet -> net))
03669 break;
03670 }
03671 if (!subnet) {
03672 parse_warn (cfile, "address range not on network %s",
03673 group -> shared_network -> name);
03674 log_error ("Be sure to place pool statement after %s",
03675 "related subnet declarations.");
03676 return;
03677 }
03678 }
03679
03680 if (!inpool) {
03681 struct pool *last = (struct pool *)0;
03682
03683
03684
03685
03686 for (pool = share -> pools; pool; pool = pool -> next) {
03687 if ((!dynamic && !pool -> permit_list &&
03688 pool -> prohibit_list &&
03689 !pool -> prohibit_list -> next &&
03690 (pool -> prohibit_list -> type ==
03691 permit_dynamic_bootp_clients)) ||
03692 (dynamic && !pool -> prohibit_list &&
03693 pool -> permit_list &&
03694 !pool -> permit_list -> next &&
03695 (pool -> permit_list -> type ==
03696 permit_all_clients))) {
03697 break;
03698 }
03699 last = pool;
03700 }
03701
03702
03703 if (!pool) {
03704 struct permit *p;
03705 status = pool_allocate (&pool, MDL);
03706 if (status != ISC_R_SUCCESS)
03707 log_fatal ("no memory for ad-hoc pool: %s",
03708 isc_result_totext (status));
03709 p = new_permit (MDL);
03710 if (!p)
03711 log_fatal ("no memory for ad-hoc permit.");
03712
03713
03714
03715 if (dynamic) {
03716 p -> type = permit_all_clients;
03717 pool -> permit_list = p;
03718 } else {
03719 p -> type = permit_dynamic_bootp_clients;
03720 pool -> prohibit_list = p;
03721 }
03722
03723 if (share -> pools)
03724 pool_reference (&last -> next, pool, MDL);
03725 else
03726 pool_reference (&share -> pools, pool, MDL);
03727 shared_network_reference (&pool -> shared_network,
03728 share, MDL);
03729 if (!clone_group (&pool -> group, share -> group, MDL))
03730 log_fatal ("no memory for anon pool group.");
03731 } else {
03732 pool = (struct pool *)0;
03733 if (last)
03734 pool_reference (&pool, last, MDL);
03735 else
03736 pool_reference (&pool, share -> pools, MDL);
03737 }
03738 } else {
03739 pool = (struct pool *)0;
03740 pool_reference (&pool, inpool, MDL);
03741 }
03742
03743 #if defined (FAILOVER_PROTOCOL)
03744 if (pool -> failover_peer && dynamic) {
03745
03746
03747 parse_warn (cfile, "dynamic-bootp flag is %s",
03748 "not permitted for address");
03749 log_error ("range declarations where there is a failover");
03750 log_error ("peer in scope. If you wish to declare an");
03751 log_error ("address range from which dynamic bootp leases");
03752 log_error ("can be allocated, please declare it within a");
03753 log_error ("pool declaration that also contains the \"no");
03754 log_error ("failover\" statement. The failover protocol");
03755 log_error ("itself does not permit dynamic bootp - this");
03756 log_error ("is not a limitation specific to the ISC DHCP");
03757 log_error ("server. Please don't ask me to defend this");
03758 log_error ("until you have read and really tried %s",
03759 "to understand");
03760 log_error ("the failover protocol specification.");
03761
03762
03763
03764
03765 }
03766 #endif
03767
03768
03769 new_address_range (cfile, low, high, subnet, pool, lpchain);
03770 pool_dereference (&pool, MDL);
03771 }
03772
03773 #ifdef DHCPv6
03774 static void
03775 add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
03776 struct iaddr *lo_addr, int bits, int units,
03777 struct ipv6_pond *pond) {
03778 struct ipv6_pool *pool;
03779 struct in6_addr tmp_in6_addr;
03780 int num_pools;
03781 struct ipv6_pool **tmp;
03782
03783
03784
03785
03786 if (lo_addr->len != sizeof(tmp_in6_addr)) {
03787 log_fatal("Internal error: Attempt to add non-IPv6 address "
03788 "to IPv6 shared network.");
03789 }
03790 memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
03791 pool = NULL;
03792 if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
03793 bits, units, MDL) != ISC_R_SUCCESS) {
03794 log_fatal("Out of memory");
03795 }
03796
03797
03798
03799
03800 if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
03801 log_fatal ("Out of memory");
03802 }
03803
03804
03805
03806
03807 pool->subnet = NULL;
03808 subnet_reference(&pool->subnet, subnet, MDL);
03809 pool->shared_network = NULL;
03810 shared_network_reference(&pool->shared_network,
03811 subnet->shared_network, MDL);
03812 pool->ipv6_pond = NULL;
03813 ipv6_pond_reference(&pool->ipv6_pond, pond, MDL);
03814
03815
03816
03817
03818 if (pond->ipv6_pools == NULL) {
03819 num_pools = 0;
03820 } else {
03821 num_pools = 0;
03822 while (pond->ipv6_pools[num_pools] != NULL) {
03823 num_pools++;
03824 }
03825 }
03826 tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
03827 if (tmp == NULL) {
03828 log_fatal("Out of memory");
03829 }
03830 if (num_pools > 0) {
03831 memcpy(tmp, pond->ipv6_pools,
03832 sizeof(struct ipv6_pool *) * num_pools);
03833 }
03834 if (pond->ipv6_pools != NULL) {
03835 dfree(pond->ipv6_pools, MDL);
03836 }
03837 pond->ipv6_pools = tmp;
03838
03839
03840
03841
03842 ipv6_pool_reference(&pond->ipv6_pools[num_pools], pool, MDL);
03843 pond->ipv6_pools[num_pools+1] = NULL;
03844 }
03845
03872 static void
03873 add_ipv6_pond_to_network(struct group *group,
03874 struct ipv6_pond **ret_pond) {
03875
03876 struct ipv6_pond *pond = NULL, *last = NULL;
03877 struct permit *p;
03878 isc_result_t status;
03879 struct shared_network *shared = group->subnet->shared_network;
03880
03881 for (pond = shared->ipv6_pond; pond; pond = pond->next) {
03882 if ((pond->group->statements == group->statements) &&
03883 (pond->prohibit_list == NULL) &&
03884 (pond->permit_list != NULL) &&
03885 (pond->permit_list->next == NULL) &&
03886 (pond->permit_list->type == permit_all_clients)) {
03887 ipv6_pond_reference(ret_pond, pond, MDL);
03888 return;
03889 }
03890 last = pond;
03891 }
03892
03893
03894 status = ipv6_pond_allocate(&pond, MDL);
03895 if (status != ISC_R_SUCCESS)
03896 log_fatal ("no memory for ad-hoc ipv6 pond: %s",
03897 isc_result_totext (status));
03898 p = new_permit (MDL);
03899 if (p == NULL)
03900 log_fatal ("no memory for ad-hoc ipv6 permit.");
03901
03902
03903 p->type = permit_all_clients;
03904 pond->permit_list = p;
03905
03906
03907 ipv6_pond_reference(ret_pond, pond, MDL);
03908
03909 if (shared->ipv6_pond)
03910 ipv6_pond_reference(&last->next, pond, MDL);
03911 else
03912 ipv6_pond_reference(&shared->ipv6_pond, pond, MDL);
03913
03914 shared_network_reference(&pond->shared_network, shared, MDL);
03915 if (!clone_group (&pond->group, group, MDL))
03916 log_fatal ("no memory for anon pool group.");
03917
03918 ipv6_pond_dereference(&pond, MDL);
03919 return;
03920 }
03921
03922 static void
03923 check_addr_in_subnet(struct subnet *subnet, struct iaddr *addr) {
03924 char lowbuf [INET6_ADDRSTRLEN], netbuf [INET6_ADDRSTRLEN];
03925
03926 if (!addr_eq(subnet->net, subnet_number(*addr, subnet->netmask))) {
03927 strncpy(lowbuf, piaddr(*addr), INET6_ADDRSTRLEN);
03928 strncpy(netbuf, piaddr(subnet->net), INET6_ADDRSTRLEN);
03929 log_fatal("bad range6, address %s not in subnet6 %s/%d",
03930 lowbuf, netbuf, subnet->prefix_len);
03931 }
03932
03933 }
03934
03935
03936
03937
03938
03939 void
03940 parse_address_range6(struct parse *cfile,
03941 struct group *group,
03942 struct ipv6_pond *inpond) {
03943 struct iaddr lo, hi;
03944 int bits;
03945 enum dhcp_token token;
03946 const char *val;
03947 struct iaddrcidrnetlist *nets, net;
03948 struct iaddrcidrnetlist *p;
03949 u_int16_t type = D6O_IA_NA;
03950 struct ipv6_pond *pond = NULL;
03951
03952 if (local_family != AF_INET6) {
03953 parse_warn(cfile, "range6 statement is only supported "
03954 "in DHCPv6 mode.");
03955 skip_to_semi(cfile);
03956 return;
03957 }
03958
03959
03960 if (group->subnet == NULL)
03961 log_fatal("Impossible condition at %s:%d.", MDL);
03962
03963
03964
03965
03966 if (!parse_ip6_addr(cfile, &lo)) {
03967 return;
03968 }
03969
03970
03971
03972
03973 memset(&net, 0, sizeof(net));
03974 net.cidrnet.lo_addr = lo;
03975
03976 check_addr_in_subnet(group->subnet, &lo);
03977
03978
03979
03980
03981 token = peek_token(&val, NULL, cfile);
03982 if (token == SLASH) {
03983
03984
03985
03986 skip_token(NULL, NULL, cfile);
03987 token = next_token(&val, NULL, cfile);
03988 if (token != NUMBER) {
03989 parse_warn(cfile, "expecting number");
03990 skip_to_semi(cfile);
03991 return;
03992 }
03993 net.cidrnet.bits = atoi(val);
03994 bits = net.cidrnet.bits;
03995 if ((bits < 0) || (bits > 128)) {
03996 parse_warn(cfile, "networks have 0 to 128 bits");
03997 skip_to_semi(cfile);
03998 return;
03999 }
04000
04001 if (!is_cidr_mask_valid(&net.cidrnet.lo_addr, bits)) {
04002 parse_warn(cfile, "network mask too short");
04003 skip_to_semi(cfile);
04004 return;
04005 }
04006
04007
04008
04009
04010 token = peek_token(&val, NULL, cfile);
04011 if (token == TEMPORARY) {
04012 if (bits < 64)
04013 parse_warn(cfile, "temporary mask too short");
04014 if (bits == 128)
04015 parse_warn(cfile, "temporary singleton?");
04016 skip_token(NULL, NULL, cfile);
04017 type = D6O_IA_TA;
04018 }
04019
04020 nets = &net;
04021
04022 } else if (token == TEMPORARY) {
04023
04024
04025
04026 type = D6O_IA_TA;
04027 skip_token(NULL, NULL, cfile);
04028 net.cidrnet.bits = 64;
04029 if (!is_cidr_mask_valid(&net.cidrnet.lo_addr,
04030 net.cidrnet.bits)) {
04031 parse_warn(cfile, "network mask too short");
04032 skip_to_semi(cfile);
04033 return;
04034 }
04035
04036 nets = &net;
04037
04038 } else {
04039
04040
04041
04042
04043 if (!parse_ip6_addr(cfile, &hi)) {
04044 return;
04045 }
04046
04047 check_addr_in_subnet(group->subnet, &hi);
04048
04049
04050
04051
04052 nets = NULL;
04053 if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
04054 log_fatal("Error converting range to CIDR networks");
04055 }
04056
04057 }
04058
04059
04060
04061
04062
04063
04064
04065 if (inpond != NULL) {
04066 ipv6_pond_reference(&pond, inpond, MDL);
04067 } else {
04068 add_ipv6_pond_to_network(group, &pond);
04069 }
04070
04071
04072 for (p=nets; p != NULL; p=p->next) {
04073 add_ipv6_pool_to_subnet(group->subnet, type,
04074 &p->cidrnet.lo_addr,
04075 p->cidrnet.bits, 128, pond);
04076 }
04077
04078
04079 if (nets != &net)
04080 free_iaddrcidrnetlist(&nets);
04081
04082 ipv6_pond_dereference(&pond, MDL);
04083
04084 token = next_token(NULL, NULL, cfile);
04085 if (token != SEMI) {
04086 parse_warn(cfile, "semicolon expected.");
04087 skip_to_semi(cfile);
04088 return;
04089 }
04090 }
04091
04092
04093
04094 void
04095 parse_prefix6(struct parse *cfile,
04096 struct group *group,
04097 struct ipv6_pond *inpond) {
04098 struct iaddr lo, hi;
04099 int bits;
04100 enum dhcp_token token;
04101 const char *val;
04102 struct iaddrcidrnetlist *nets;
04103 struct iaddrcidrnetlist *p;
04104 struct ipv6_pond *pond = NULL;
04105
04106 if (local_family != AF_INET6) {
04107 parse_warn(cfile, "prefix6 statement is only supported "
04108 "in DHCPv6 mode.");
04109 skip_to_semi(cfile);
04110 return;
04111 }
04112
04113
04114 if (group->subnet == NULL)
04115 log_fatal("Impossible condition at %s:%d.", MDL);
04116
04117
04118
04119
04120 if (!parse_ip6_addr(cfile, &lo)) {
04121 return;
04122 }
04123 if (!parse_ip6_addr(cfile, &hi)) {
04124 return;
04125 }
04126
04127
04128
04129
04130 token = next_token(NULL, NULL, cfile);
04131 if (token != SLASH) {
04132 parse_warn(cfile, "expecting '/'");
04133 if (token != SEMI)
04134 skip_to_semi(cfile);
04135 return;
04136 }
04137 token = next_token(&val, NULL, cfile);
04138 if (token != NUMBER) {
04139 parse_warn(cfile, "expecting number");
04140 if (token != SEMI)
04141 skip_to_semi(cfile);
04142 return;
04143 }
04144 bits = atoi(val);
04145 if ((bits <= 0) || (bits >= 128)) {
04146 parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
04147 return;
04148 }
04149 if (!is_cidr_mask_valid(&lo, bits) ||
04150 !is_cidr_mask_valid(&hi, bits)) {
04151 parse_warn(cfile, "network mask too short");
04152 return;
04153 }
04154 token = next_token(NULL, NULL, cfile);
04155 if (token != SEMI) {
04156 parse_warn(cfile, "semicolon expected.");
04157 skip_to_semi(cfile);
04158 return;
04159 }
04160
04161
04162
04163
04164 nets = NULL;
04165 if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
04166 log_fatal("Error converting prefix to CIDR");
04167 }
04168
04169
04170
04171
04172
04173
04174
04175 if (inpond != NULL) {
04176 ipv6_pond_reference(&pond, inpond, MDL);
04177 } else {
04178 add_ipv6_pond_to_network(group, &pond);
04179 }
04180
04181 for (p = nets; p != NULL; p = p->next) {
04182
04183 if (p->cidrnet.bits == 128) {
04184 p->cidrnet.bits = bits;
04185 }
04186 if (p->cidrnet.bits > bits) {
04187 parse_warn(cfile, "impossible mask length");
04188 continue;
04189 }
04190 add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
04191 &p->cidrnet.lo_addr,
04192 p->cidrnet.bits, bits, pond);
04193 }
04194
04195 free_iaddrcidrnetlist(&nets);
04196 }
04197
04198
04199
04200 void
04201 parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
04202 struct iaddrcidrnetlist *ia, **h;
04203 enum dhcp_token token;
04204 const char *val;
04205
04206
04207
04208
04209 h = &host_decl->fixed_prefix;
04210
04211
04212
04213
04214 while (*h != NULL) {
04215 h = &((*h)->next);
04216 }
04217
04218
04219
04220
04221 ia = dmalloc(sizeof(*ia), MDL);
04222 if (!ia) {
04223 log_fatal("Out of memory");
04224 }
04225
04226
04227
04228
04229 if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
04230 dfree(ia, MDL);
04231 return;
04232 }
04233 token = next_token(NULL, NULL, cfile);
04234 if (token != SLASH) {
04235 dfree(ia, MDL);
04236 parse_warn(cfile, "expecting '/'");
04237 if (token != SEMI)
04238 skip_to_semi(cfile);
04239 return;
04240 }
04241 token = next_token(&val, NULL, cfile);
04242 if (token != NUMBER) {
04243 dfree(ia, MDL);
04244 parse_warn(cfile, "expecting number");
04245 if (token != SEMI)
04246 skip_to_semi(cfile);
04247 return;
04248 }
04249 token = next_token(NULL, NULL, cfile);
04250 if (token != SEMI) {
04251 dfree(ia, MDL);
04252 parse_warn(cfile, "semicolon expected.");
04253 skip_to_semi(cfile);
04254 return;
04255 }
04256
04257
04258
04259
04260 ia->cidrnet.bits = atoi(val);
04261 if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
04262 dfree(ia, MDL);
04263 parse_warn(cfile, "networks have 0 to 128 bits");
04264 return;
04265 }
04266 if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
04267 dfree(ia, MDL);
04268 parse_warn(cfile, "network mask too short");
04269 return;
04270 }
04271
04272
04273
04274
04275 *h = ia;
04276 return;
04277 }
04278
04298 void parse_pool6_statement (cfile, group, type)
04299 struct parse *cfile;
04300 struct group *group;
04301 int type;
04302 {
04303 enum dhcp_token token;
04304 const char *val;
04305 int done = 0;
04306 struct ipv6_pond *pond, **p;
04307 int declaration = 0;
04308 isc_result_t status;
04309
04310 pond = NULL;
04311 status = ipv6_pond_allocate(&pond, MDL);
04312 if (status != ISC_R_SUCCESS)
04313 log_fatal("no memory for pool6: %s",
04314 isc_result_totext (status));
04315
04316 if (type == SUBNET_DECL)
04317 shared_network_reference(&pond->shared_network,
04318 group->subnet->shared_network,
04319 MDL);
04320 else {
04321 parse_warn(cfile, "Dynamic pool6s are only valid inside "
04322 "subnet statements.");
04323 skip_to_semi(cfile);
04324 return;
04325 }
04326
04327 if (clone_group(&pond->group, group, MDL) == 0)
04328 log_fatal("can't clone pool6 group.");
04329
04330 if (parse_lbrace(cfile) == 0) {
04331 ipv6_pond_dereference(&pond, MDL);
04332 return;
04333 }
04334
04335 do {
04336 token = peek_token(&val, NULL, cfile);
04337 switch (token) {
04338 case RANGE6:
04339 skip_token(NULL, NULL, cfile);
04340 parse_address_range6(cfile, group, pond);
04341 break;
04342
04343 case PREFIX6:
04344 skip_token(NULL, NULL, cfile);
04345 parse_prefix6(cfile, group, pond);
04346 break;
04347
04348 case ALLOW:
04349 skip_token(NULL, NULL, cfile);
04350 get_permit(cfile, &pond->permit_list, 1,
04351 &pond->valid_from, &pond->valid_until);
04352 break;
04353
04354 case DENY:
04355 skip_token(NULL, NULL, cfile);
04356 get_permit(cfile, &pond->prohibit_list, 0,
04357 &pond->valid_from, &pond->valid_until);
04358 break;
04359
04360 case RBRACE:
04361 skip_token(&val, NULL, cfile);
04362 done = 1;
04363 break;
04364
04365 case END_OF_FILE:
04366
04367
04368
04369
04370
04371 parse_warn(cfile, "unexpected end of file");
04372 goto cleanup;
04373
04374 default:
04375 declaration = parse_statement(cfile, pond->group,
04376 POOL_DECL, NULL,
04377 declaration);
04378 break;
04379 }
04380 } while (!done);
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393 p = &pond->shared_network->ipv6_pond;
04394 for (; *p; p = &((*p)->next))
04395 ;
04396 ipv6_pond_reference(p, pond, MDL);
04397
04398
04399
04400 if (pond->ipv6_pools == NULL) {
04401 parse_warn (cfile, "Pool6 declaration with no %s.",
04402 "address range6 or prefix6");
04403 log_error ("Pool6 declarations must always contain at least");
04404 log_error ("one range6 or prefix6 statement.");
04405 }
04406
04407 cleanup:
04408 ipv6_pond_dereference(&pond, MDL);
04409 }
04410
04411
04412
04413 #endif
04414
04415
04416
04417
04418
04419
04420 int parse_allow_deny (oc, cfile, flag)
04421 struct option_cache **oc;
04422 struct parse *cfile;
04423 int flag;
04424 {
04425 enum dhcp_token token;
04426 const char *val;
04427 unsigned char rf = flag;
04428 unsigned code;
04429 struct option *option = NULL;
04430 struct expression *data = (struct expression *)0;
04431 int status;
04432
04433 if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
04434 return 0;
04435
04436 token = next_token (&val, (unsigned *)0, cfile);
04437 switch (token) {
04438 case TOKEN_BOOTP:
04439 code = SV_ALLOW_BOOTP;
04440 break;
04441
04442 case BOOTING:
04443 code = SV_ALLOW_BOOTING;
04444 break;
04445
04446 case DYNAMIC_BOOTP:
04447 code = SV_DYNAMIC_BOOTP;
04448 break;
04449
04450 case UNKNOWN_CLIENTS:
04451 code = SV_BOOT_UNKNOWN_CLIENTS;
04452 break;
04453
04454 case DUPLICATES:
04455 code = SV_DUPLICATES;
04456 break;
04457
04458 case DECLINES:
04459 code= SV_DECLINES;
04460 break;
04461
04462 case CLIENT_UPDATES:
04463 code = SV_CLIENT_UPDATES;
04464 break;
04465
04466 case LEASEQUERY:
04467 code = SV_LEASEQUERY;
04468 break;
04469
04470 default:
04471 parse_warn (cfile, "expecting allow/deny key");
04472 skip_to_semi (cfile);
04473 return 0;
04474 }
04475
04476 if (!option_code_hash_lookup(&option, server_universe.code_hash,
04477 &code, 0, MDL))
04478 log_fatal("Unable to find server option %u (%s:%d).",
04479 code, MDL);
04480 status = option_cache(oc, NULL, data, option, MDL);
04481 expression_dereference (&data, MDL);
04482 parse_semi (cfile);
04483 return status;
04484 }
04485
04486 void
04487 parse_ia_na_declaration(struct parse *cfile) {
04488 #if !defined(DHCPv6)
04489 parse_warn(cfile, "No DHCPv6 support.");
04490 skip_to_semi(cfile);
04491 #else
04492 enum dhcp_token token;
04493 struct ia_xx *ia;
04494 const char *val;
04495 struct ia_xx *old_ia;
04496 unsigned int len;
04497 u_int32_t iaid;
04498 struct iaddr iaddr;
04499 binding_state_t state;
04500 u_int32_t prefer;
04501 u_int32_t valid;
04502 TIME end_time;
04503 struct iasubopt *iaaddr;
04504 struct ipv6_pool *pool;
04505 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
04506 isc_boolean_t newbinding;
04507 struct binding_scope *scope = NULL;
04508 struct binding *bnd;
04509 struct binding_value *nv = NULL;
04510 struct executable_statement *on_star[2] = {NULL, NULL};
04511 int lose, i;
04512
04513 if (local_family != AF_INET6) {
04514 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
04515 skip_to_semi(cfile);
04516 return;
04517 }
04518
04519 token = next_token(&val, &len, cfile);
04520 if (token != STRING) {
04521 parse_warn(cfile, "corrupt lease file; "
04522 "expecting an iaid+ia_na string");
04523 skip_to_semi(cfile);
04524 return;
04525 }
04526 if (len < 5) {
04527 parse_warn(cfile, "corrupt lease file; "
04528 "iaid+ia_na string too short");
04529 skip_to_semi(cfile);
04530 return;
04531 }
04532
04533 memcpy(&iaid, val, 4);
04534 ia = NULL;
04535 if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
04536 log_fatal("Out of memory.");
04537 }
04538 ia->ia_type = D6O_IA_NA;
04539
04540 token = next_token(&val, NULL, cfile);
04541 if (token != LBRACE) {
04542 parse_warn(cfile, "corrupt lease file; expecting left brace");
04543 skip_to_semi(cfile);
04544 return;
04545 }
04546
04547 for (;;) {
04548 token = next_token(&val, NULL, cfile);
04549 if (token == RBRACE) break;
04550
04551 if (token == CLTT) {
04552 ia->cltt = parse_date (cfile);
04553 continue;
04554 }
04555
04556 if (token != IAADDR) {
04557 parse_warn(cfile, "corrupt lease file; "
04558 "expecting IAADDR or right brace");
04559 skip_to_semi(cfile);
04560 return;
04561 }
04562
04563 if (!parse_ip6_addr(cfile, &iaddr)) {
04564 parse_warn(cfile, "corrupt lease file; "
04565 "expecting IPv6 address");
04566 skip_to_semi(cfile);
04567 return;
04568 }
04569
04570 token = next_token(&val, NULL, cfile);
04571 if (token != LBRACE) {
04572 parse_warn(cfile, "corrupt lease file; "
04573 "expecting left brace");
04574 skip_to_semi(cfile);
04575 return;
04576 }
04577
04578 state = FTS_LAST+1;
04579 prefer = valid = 0;
04580 end_time = -1;
04581 for (;;) {
04582 token = next_token(&val, NULL, cfile);
04583 if (token == RBRACE) break;
04584
04585 switch(token) {
04586
04587 case BINDING:
04588 token = next_token(&val, NULL, cfile);
04589 if (token != STATE) {
04590 parse_warn(cfile, "corrupt lease file; "
04591 "expecting state");
04592 skip_to_semi(cfile);
04593 return;
04594 }
04595 token = next_token(&val, NULL, cfile);
04596 switch (token) {
04597 case TOKEN_ABANDONED:
04598 state = FTS_ABANDONED;
04599 break;
04600 case TOKEN_FREE:
04601 state = FTS_FREE;
04602 break;
04603 case TOKEN_ACTIVE:
04604 state = FTS_ACTIVE;
04605 break;
04606 case TOKEN_EXPIRED:
04607 state = FTS_EXPIRED;
04608 break;
04609 case TOKEN_RELEASED:
04610 state = FTS_RELEASED;
04611 break;
04612 default:
04613 parse_warn(cfile,
04614 "corrupt lease "
04615 "file; "
04616 "expecting a "
04617 "binding state.");
04618 skip_to_semi(cfile);
04619 return;
04620 }
04621
04622 token = next_token(&val, NULL, cfile);
04623 if (token != SEMI) {
04624 parse_warn(cfile, "corrupt lease file; "
04625 "expecting "
04626 "semicolon.");
04627 }
04628 break;
04629
04630
04631 case PREFERRED_LIFE:
04632 token = next_token(&val, NULL, cfile);
04633 if (token != NUMBER) {
04634 parse_warn(cfile, "%s is not a valid "
04635 "preferred time",
04636 val);
04637 skip_to_semi(cfile);
04638 continue;
04639 }
04640 prefer = atoi (val);
04641
04642
04643
04644
04645
04646
04647
04648 token = peek_token(&val, NULL, cfile);
04649 if (token == SEMI) {
04650 skip_token(&val, NULL, cfile);
04651 } else {
04652 parse_warn(cfile,
04653 "corrupt lease file; "
04654 "expecting semicolon.");
04655 }
04656 break;
04657
04658
04659 case MAX_LIFE:
04660 token = next_token(&val, NULL, cfile);
04661 if (token != NUMBER) {
04662 parse_warn(cfile, "%s is not a valid "
04663 "max time",
04664 val);
04665 skip_to_semi(cfile);
04666 continue;
04667 }
04668 valid = atoi (val);
04669
04670
04671
04672
04673
04674
04675
04676 token = peek_token(&val, NULL, cfile);
04677 if (token == SEMI) {
04678 skip_token(&val, NULL, cfile);
04679 } else {
04680 parse_warn(cfile,
04681 "corrupt lease file; "
04682 "expecting semicolon.");
04683 }
04684 break;
04685
04686
04687 case ENDS:
04688 end_time = parse_date(cfile);
04689 break;
04690
04691
04692 case TOKEN_SET:
04693 token = next_token(&val, NULL, cfile);
04694 if ((token != NAME) &&
04695 (token != NUMBER_OR_NAME)) {
04696 parse_warn(cfile, "%s is not a valid "
04697 "variable name",
04698 val);
04699 skip_to_semi(cfile);
04700 continue;
04701 }
04702
04703 if (scope != NULL)
04704 bnd = find_binding(scope, val);
04705 else {
04706 if (!binding_scope_allocate(&scope,
04707 MDL)) {
04708 log_fatal("Out of memory for "
04709 "lease binding "
04710 "scope.");
04711 }
04712
04713 bnd = NULL;
04714 }
04715
04716 if (bnd == NULL) {
04717 bnd = dmalloc(sizeof(*bnd),
04718 MDL);
04719 if (bnd == NULL) {
04720 log_fatal("No memory for "
04721 "lease binding.");
04722 }
04723
04724 bnd->name = dmalloc(strlen(val) + 1,
04725 MDL);
04726 if (bnd->name == NULL) {
04727 log_fatal("No memory for "
04728 "binding name.");
04729 }
04730 strcpy(bnd->name, val);
04731
04732 newbinding = ISC_TRUE;
04733 } else {
04734 newbinding = ISC_FALSE;
04735 }
04736
04737 if (!binding_value_allocate(&nv, MDL)) {
04738 log_fatal("no memory for binding "
04739 "value.");
04740 }
04741
04742 token = next_token(NULL, NULL, cfile);
04743 if (token != EQUAL) {
04744 parse_warn(cfile, "expecting '=' in "
04745 "set statement.");
04746 goto binding_err;
04747 }
04748
04749 if (!parse_binding_value(cfile, nv)) {
04750 binding_err:
04751 binding_value_dereference(&nv, MDL);
04752 binding_scope_dereference(&scope, MDL);
04753 return;
04754 }
04755
04756 if (newbinding) {
04757 binding_value_reference(&bnd->value,
04758 nv, MDL);
04759 bnd->next = scope->bindings;
04760 scope->bindings = bnd;
04761 } else {
04762 binding_value_dereference(&bnd->value,
04763 MDL);
04764 binding_value_reference(&bnd->value,
04765 nv, MDL);
04766 }
04767
04768 binding_value_dereference(&nv, MDL);
04769 parse_semi(cfile);
04770 break;
04771
04772 case ON:
04773 lose = 0;
04774
04775
04776
04777
04778
04779
04780
04781 if (on_star[0] == NULL) {
04782 if (!parse_on_statement (&on_star[0],
04783 cfile,
04784 &lose)) {
04785 parse_warn(cfile,
04786 "corrupt lease "
04787 "file; bad ON "
04788 "statement");
04789 skip_to_rbrace (cfile, 1);
04790 return;
04791 }
04792 } else {
04793 if (!parse_on_statement (&on_star[1],
04794 cfile,
04795 &lose)) {
04796 parse_warn(cfile,
04797 "corrupt lease "
04798 "file; bad ON "
04799 "statement");
04800 skip_to_rbrace (cfile, 1);
04801 return;
04802 }
04803 }
04804
04805 break;
04806
04807 default:
04808 parse_warn(cfile, "corrupt lease file; "
04809 "expecting ia_na contents, "
04810 "got '%s'", val);
04811 skip_to_semi(cfile);
04812 continue;
04813 }
04814 }
04815
04816 if (state == FTS_LAST+1) {
04817 parse_warn(cfile, "corrupt lease file; "
04818 "missing state in iaaddr");
04819 return;
04820 }
04821 if (end_time == -1) {
04822 parse_warn(cfile, "corrupt lease file; "
04823 "missing end time in iaaddr");
04824 return;
04825 }
04826
04827 iaaddr = NULL;
04828 if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
04829 log_fatal("Out of memory.");
04830 }
04831 memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
04832 iaaddr->plen = 0;
04833 iaaddr->state = state;
04834 iaaddr->prefer = prefer;
04835 iaaddr->valid = valid;
04836 if (iaaddr->state == FTS_RELEASED)
04837 iaaddr->hard_lifetime_end_time = end_time;
04838
04839 if (scope != NULL) {
04840 binding_scope_reference(&iaaddr->scope, scope, MDL);
04841 binding_scope_dereference(&scope, MDL);
04842 }
04843
04844
04845
04846
04847
04848
04849
04850 for (i = 0;
04851 (i < 2) && on_star[i] != NULL ;
04852 i++) {
04853 if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
04854 on_star[i]->data.on.statements) {
04855 executable_statement_reference
04856 (&iaaddr->on_star.on_expiry,
04857 on_star[i]->data.on.statements, MDL);
04858 }
04859 if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
04860 on_star[i]->data.on.statements) {
04861 executable_statement_reference
04862 (&iaaddr->on_star.on_release,
04863 on_star[i]->data.on.statements, MDL);
04864 }
04865 executable_statement_dereference (&on_star[i], MDL);
04866 }
04867
04868
04869 pool = NULL;
04870 if (find_ipv6_pool(&pool, D6O_IA_NA,
04871 &iaaddr->addr) != ISC_R_SUCCESS) {
04872 inet_ntop(AF_INET6, &iaaddr->addr,
04873 addr_buf, sizeof(addr_buf));
04874 parse_warn(cfile, "no pool found for address %s",
04875 addr_buf);
04876 return;
04877 }
04878
04879
04880 if (cleanup_lease6(ia_na_active, pool,
04881 iaaddr, ia) != ISC_R_SUCCESS) {
04882 inet_ntop(AF_INET6, &iaaddr->addr,
04883 addr_buf, sizeof(addr_buf));
04884 parse_warn(cfile, "duplicate na lease for address %s",
04885 addr_buf);
04886 }
04887
04888
04889
04890
04891
04892
04893 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
04894 ia_add_iasubopt(ia, iaaddr, MDL);
04895 ia_reference(&iaaddr->ia, ia, MDL);
04896 add_lease6(pool, iaaddr, end_time);
04897 }
04898
04899 iasubopt_dereference(&iaaddr, MDL);
04900 ipv6_pool_dereference(&pool, MDL);
04901 }
04902
04903
04904
04905
04906 old_ia = NULL;
04907 if (ia_hash_lookup(&old_ia, ia_na_active,
04908 (unsigned char *)ia->iaid_duid.data,
04909 ia->iaid_duid.len, MDL)) {
04910 ia_hash_delete(ia_na_active,
04911 (unsigned char *)ia->iaid_duid.data,
04912 ia->iaid_duid.len, MDL);
04913 ia_dereference(&old_ia, MDL);
04914 }
04915
04916
04917
04918
04919 if (ia->num_iasubopt > 0) {
04920 ia_hash_add(ia_na_active,
04921 (unsigned char *)ia->iaid_duid.data,
04922 ia->iaid_duid.len, ia, MDL);
04923 }
04924 ia_dereference(&ia, MDL);
04925 #endif
04926 }
04927
04928 void
04929 parse_ia_ta_declaration(struct parse *cfile) {
04930 #if !defined(DHCPv6)
04931 parse_warn(cfile, "No DHCPv6 support.");
04932 skip_to_semi(cfile);
04933 #else
04934 enum dhcp_token token;
04935 struct ia_xx *ia;
04936 const char *val;
04937 struct ia_xx *old_ia;
04938 unsigned int len;
04939 u_int32_t iaid;
04940 struct iaddr iaddr;
04941 binding_state_t state;
04942 u_int32_t prefer;
04943 u_int32_t valid;
04944 TIME end_time;
04945 struct iasubopt *iaaddr;
04946 struct ipv6_pool *pool;
04947 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
04948 isc_boolean_t newbinding;
04949 struct binding_scope *scope = NULL;
04950 struct binding *bnd;
04951 struct binding_value *nv = NULL;
04952 struct executable_statement *on_star[2] = {NULL, NULL};
04953 int lose, i;
04954
04955 if (local_family != AF_INET6) {
04956 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
04957 skip_to_semi(cfile);
04958 return;
04959 }
04960
04961 token = next_token(&val, &len, cfile);
04962 if (token != STRING) {
04963 parse_warn(cfile, "corrupt lease file; "
04964 "expecting an iaid+ia_ta string");
04965 skip_to_semi(cfile);
04966 return;
04967 }
04968 if (len < 5) {
04969 parse_warn(cfile, "corrupt lease file; "
04970 "iaid+ia_ta string too short");
04971 skip_to_semi(cfile);
04972 return;
04973 }
04974
04975 memcpy(&iaid, val, 4);
04976 ia = NULL;
04977 if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
04978 log_fatal("Out of memory.");
04979 }
04980 ia->ia_type = D6O_IA_TA;
04981
04982 token = next_token(&val, NULL, cfile);
04983 if (token != LBRACE) {
04984 parse_warn(cfile, "corrupt lease file; expecting left brace");
04985 skip_to_semi(cfile);
04986 return;
04987 }
04988
04989 for (;;) {
04990 token = next_token(&val, NULL, cfile);
04991 if (token == RBRACE) break;
04992
04993 if (token == CLTT) {
04994 ia->cltt = parse_date (cfile);
04995 continue;
04996 }
04997
04998 if (token != IAADDR) {
04999 parse_warn(cfile, "corrupt lease file; "
05000 "expecting IAADDR or right brace");
05001 skip_to_semi(cfile);
05002 return;
05003 }
05004
05005 if (!parse_ip6_addr(cfile, &iaddr)) {
05006 parse_warn(cfile, "corrupt lease file; "
05007 "expecting IPv6 address");
05008 skip_to_semi(cfile);
05009 return;
05010 }
05011
05012 token = next_token(&val, NULL, cfile);
05013 if (token != LBRACE) {
05014 parse_warn(cfile, "corrupt lease file; "
05015 "expecting left brace");
05016 skip_to_semi(cfile);
05017 return;
05018 }
05019
05020 state = FTS_LAST+1;
05021 prefer = valid = 0;
05022 end_time = -1;
05023 for (;;) {
05024 token = next_token(&val, NULL, cfile);
05025 if (token == RBRACE) break;
05026
05027 switch(token) {
05028
05029 case BINDING:
05030 token = next_token(&val, NULL, cfile);
05031 if (token != STATE) {
05032 parse_warn(cfile, "corrupt lease file; "
05033 "expecting state");
05034 skip_to_semi(cfile);
05035 return;
05036 }
05037 token = next_token(&val, NULL, cfile);
05038 switch (token) {
05039 case TOKEN_ABANDONED:
05040 state = FTS_ABANDONED;
05041 break;
05042 case TOKEN_FREE:
05043 state = FTS_FREE;
05044 break;
05045 case TOKEN_ACTIVE:
05046 state = FTS_ACTIVE;
05047 break;
05048 case TOKEN_EXPIRED:
05049 state = FTS_EXPIRED;
05050 break;
05051 case TOKEN_RELEASED:
05052 state = FTS_RELEASED;
05053 break;
05054 default:
05055 parse_warn(cfile,
05056 "corrupt lease "
05057 "file; "
05058 "expecting a "
05059 "binding state.");
05060 skip_to_semi(cfile);
05061 return;
05062 }
05063
05064 token = next_token(&val, NULL, cfile);
05065 if (token != SEMI) {
05066 parse_warn(cfile, "corrupt lease file; "
05067 "expecting "
05068 "semicolon.");
05069 }
05070 break;
05071
05072
05073 case PREFERRED_LIFE:
05074 token = next_token(&val, NULL, cfile);
05075 if (token != NUMBER) {
05076 parse_warn(cfile, "%s is not a valid "
05077 "preferred time",
05078 val);
05079 skip_to_semi(cfile);
05080 continue;
05081 }
05082 prefer = atoi (val);
05083
05084
05085
05086
05087
05088
05089
05090 token = peek_token(&val, NULL, cfile);
05091 if (token == SEMI) {
05092 skip_token(&val, NULL, cfile);
05093 } else {
05094 parse_warn(cfile,
05095 "corrupt lease file; "
05096 "expecting semicolon.");
05097 }
05098 break;
05099
05100
05101 case MAX_LIFE:
05102 token = next_token(&val, NULL, cfile);
05103 if (token != NUMBER) {
05104 parse_warn(cfile, "%s is not a valid "
05105 "max time",
05106 val);
05107 skip_to_semi(cfile);
05108 continue;
05109 }
05110 valid = atoi (val);
05111
05112
05113
05114
05115
05116
05117
05118 token = peek_token(&val, NULL, cfile);
05119 if (token == SEMI) {
05120 skip_token(&val, NULL, cfile);
05121 } else {
05122 parse_warn(cfile,
05123 "corrupt lease file; "
05124 "expecting semicolon.");
05125 }
05126 break;
05127
05128
05129 case ENDS:
05130 end_time = parse_date(cfile);
05131 break;
05132
05133
05134 case TOKEN_SET:
05135 token = next_token(&val, NULL, cfile);
05136 if ((token != NAME) &&
05137 (token != NUMBER_OR_NAME)) {
05138 parse_warn(cfile, "%s is not a valid "
05139 "variable name",
05140 val);
05141 skip_to_semi(cfile);
05142 continue;
05143 }
05144
05145 if (scope != NULL)
05146 bnd = find_binding(scope, val);
05147 else {
05148 if (!binding_scope_allocate(&scope,
05149 MDL)) {
05150 log_fatal("Out of memory for "
05151 "lease binding "
05152 "scope.");
05153 }
05154
05155 bnd = NULL;
05156 }
05157
05158 if (bnd == NULL) {
05159 bnd = dmalloc(sizeof(*bnd),
05160 MDL);
05161 if (bnd == NULL) {
05162 log_fatal("No memory for "
05163 "lease binding.");
05164 }
05165
05166 bnd->name = dmalloc(strlen(val) + 1,
05167 MDL);
05168 if (bnd->name == NULL) {
05169 log_fatal("No memory for "
05170 "binding name.");
05171 }
05172 strcpy(bnd->name, val);
05173
05174 newbinding = ISC_TRUE;
05175 } else {
05176 newbinding = ISC_FALSE;
05177 }
05178
05179 if (!binding_value_allocate(&nv, MDL)) {
05180 log_fatal("no memory for binding "
05181 "value.");
05182 }
05183
05184 token = next_token(NULL, NULL, cfile);
05185 if (token != EQUAL) {
05186 parse_warn(cfile, "expecting '=' in "
05187 "set statement.");
05188 goto binding_err;
05189 }
05190
05191 if (!parse_binding_value(cfile, nv)) {
05192 binding_err:
05193 binding_value_dereference(&nv, MDL);
05194 binding_scope_dereference(&scope, MDL);
05195 return;
05196 }
05197
05198 if (newbinding) {
05199 binding_value_reference(&bnd->value,
05200 nv, MDL);
05201 bnd->next = scope->bindings;
05202 scope->bindings = bnd;
05203 } else {
05204 binding_value_dereference(&bnd->value,
05205 MDL);
05206 binding_value_reference(&bnd->value,
05207 nv, MDL);
05208 }
05209
05210 binding_value_dereference(&nv, MDL);
05211 parse_semi(cfile);
05212 break;
05213
05214 case ON:
05215 lose = 0;
05216
05217
05218
05219
05220
05221
05222
05223 if (on_star[0] == NULL) {
05224 if (!parse_on_statement (&on_star[0],
05225 cfile,
05226 &lose)) {
05227 parse_warn(cfile,
05228 "corrupt lease "
05229 "file; bad ON "
05230 "statement");
05231 skip_to_rbrace (cfile, 1);
05232 return;
05233 }
05234 } else {
05235 if (!parse_on_statement (&on_star[1],
05236 cfile,
05237 &lose)) {
05238 parse_warn(cfile,
05239 "corrupt lease "
05240 "file; bad ON "
05241 "statement");
05242 skip_to_rbrace (cfile, 1);
05243 return;
05244 }
05245 }
05246
05247 break;
05248
05249 default:
05250 parse_warn(cfile, "corrupt lease file; "
05251 "expecting ia_ta contents, "
05252 "got '%s'", val);
05253 skip_to_semi(cfile);
05254 continue;
05255 }
05256 }
05257
05258 if (state == FTS_LAST+1) {
05259 parse_warn(cfile, "corrupt lease file; "
05260 "missing state in iaaddr");
05261 return;
05262 }
05263 if (end_time == -1) {
05264 parse_warn(cfile, "corrupt lease file; "
05265 "missing end time in iaaddr");
05266 return;
05267 }
05268
05269 iaaddr = NULL;
05270 if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
05271 log_fatal("Out of memory.");
05272 }
05273 memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
05274 iaaddr->plen = 0;
05275 iaaddr->state = state;
05276 iaaddr->prefer = prefer;
05277 iaaddr->valid = valid;
05278 if (iaaddr->state == FTS_RELEASED)
05279 iaaddr->hard_lifetime_end_time = end_time;
05280
05281 if (scope != NULL) {
05282 binding_scope_reference(&iaaddr->scope, scope, MDL);
05283 binding_scope_dereference(&scope, MDL);
05284 }
05285
05286
05287
05288
05289
05290
05291
05292 for (i = 0;
05293 (i < 2) && on_star[i] != NULL ;
05294 i++) {
05295 if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
05296 on_star[i]->data.on.statements) {
05297 executable_statement_reference
05298 (&iaaddr->on_star.on_expiry,
05299 on_star[i]->data.on.statements, MDL);
05300 }
05301 if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
05302 on_star[i]->data.on.statements) {
05303 executable_statement_reference
05304 (&iaaddr->on_star.on_release,
05305 on_star[i]->data.on.statements, MDL);
05306 }
05307 executable_statement_dereference (&on_star[i], MDL);
05308 }
05309
05310
05311 pool = NULL;
05312 if (find_ipv6_pool(&pool, D6O_IA_TA,
05313 &iaaddr->addr) != ISC_R_SUCCESS) {
05314 inet_ntop(AF_INET6, &iaaddr->addr,
05315 addr_buf, sizeof(addr_buf));
05316 parse_warn(cfile, "no pool found for address %s",
05317 addr_buf);
05318 return;
05319 }
05320
05321
05322 if (cleanup_lease6(ia_ta_active, pool,
05323 iaaddr, ia) != ISC_R_SUCCESS) {
05324 inet_ntop(AF_INET6, &iaaddr->addr,
05325 addr_buf, sizeof(addr_buf));
05326 parse_warn(cfile, "duplicate ta lease for address %s",
05327 addr_buf);
05328 }
05329
05330
05331
05332
05333
05334
05335 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
05336 ia_add_iasubopt(ia, iaaddr, MDL);
05337 ia_reference(&iaaddr->ia, ia, MDL);
05338 add_lease6(pool, iaaddr, end_time);
05339 }
05340
05341 ipv6_pool_dereference(&pool, MDL);
05342 iasubopt_dereference(&iaaddr, MDL);
05343 }
05344
05345
05346
05347
05348 old_ia = NULL;
05349 if (ia_hash_lookup(&old_ia, ia_ta_active,
05350 (unsigned char *)ia->iaid_duid.data,
05351 ia->iaid_duid.len, MDL)) {
05352 ia_hash_delete(ia_ta_active,
05353 (unsigned char *)ia->iaid_duid.data,
05354 ia->iaid_duid.len, MDL);
05355 ia_dereference(&old_ia, MDL);
05356 }
05357
05358
05359
05360
05361 if (ia->num_iasubopt > 0) {
05362 ia_hash_add(ia_ta_active,
05363 (unsigned char *)ia->iaid_duid.data,
05364 ia->iaid_duid.len, ia, MDL);
05365 }
05366 ia_dereference(&ia, MDL);
05367 #endif
05368 }
05369
05370 void
05371 parse_ia_pd_declaration(struct parse *cfile) {
05372 #if !defined(DHCPv6)
05373 parse_warn(cfile, "No DHCPv6 support.");
05374 skip_to_semi(cfile);
05375 #else
05376 enum dhcp_token token;
05377 struct ia_xx *ia;
05378 const char *val;
05379 struct ia_xx *old_ia;
05380 unsigned int len;
05381 u_int32_t iaid;
05382 struct iaddr iaddr;
05383 u_int8_t plen;
05384 binding_state_t state;
05385 u_int32_t prefer;
05386 u_int32_t valid;
05387 TIME end_time;
05388 struct iasubopt *iapref;
05389 struct ipv6_pool *pool;
05390 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
05391 isc_boolean_t newbinding;
05392 struct binding_scope *scope = NULL;
05393 struct binding *bnd;
05394 struct binding_value *nv = NULL;
05395 struct executable_statement *on_star[2] = {NULL, NULL};
05396 int lose, i;
05397
05398 if (local_family != AF_INET6) {
05399 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
05400 skip_to_semi(cfile);
05401 return;
05402 }
05403
05404 token = next_token(&val, &len, cfile);
05405 if (token != STRING) {
05406 parse_warn(cfile, "corrupt lease file; "
05407 "expecting an iaid+ia_pd string");
05408 skip_to_semi(cfile);
05409 return;
05410 }
05411 if (len < 5) {
05412 parse_warn(cfile, "corrupt lease file; "
05413 "iaid+ia_pd string too short");
05414 skip_to_semi(cfile);
05415 return;
05416 }
05417
05418 memcpy(&iaid, val, 4);
05419 ia = NULL;
05420 if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
05421 log_fatal("Out of memory.");
05422 }
05423 ia->ia_type = D6O_IA_PD;
05424
05425 token = next_token(&val, NULL, cfile);
05426 if (token != LBRACE) {
05427 parse_warn(cfile, "corrupt lease file; expecting left brace");
05428 skip_to_semi(cfile);
05429 return;
05430 }
05431
05432 for (;;) {
05433 token = next_token(&val, NULL, cfile);
05434 if (token == RBRACE) break;
05435
05436 if (token == CLTT) {
05437 ia->cltt = parse_date (cfile);
05438 continue;
05439 }
05440
05441 if (token != IAPREFIX) {
05442 parse_warn(cfile, "corrupt lease file; expecting "
05443 "IAPREFIX or right brace");
05444 skip_to_semi(cfile);
05445 return;
05446 }
05447
05448 if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
05449 parse_warn(cfile, "corrupt lease file; "
05450 "expecting IPv6 prefix");
05451 skip_to_semi(cfile);
05452 return;
05453 }
05454
05455 token = next_token(&val, NULL, cfile);
05456 if (token != LBRACE) {
05457 parse_warn(cfile, "corrupt lease file; "
05458 "expecting left brace");
05459 skip_to_semi(cfile);
05460 return;
05461 }
05462
05463 state = FTS_LAST+1;
05464 prefer = valid = 0;
05465 end_time = -1;
05466 for (;;) {
05467 token = next_token(&val, NULL, cfile);
05468 if (token == RBRACE) break;
05469
05470 switch(token) {
05471
05472 case BINDING:
05473 token = next_token(&val, NULL, cfile);
05474 if (token != STATE) {
05475 parse_warn(cfile, "corrupt lease file; "
05476 "expecting state");
05477 skip_to_semi(cfile);
05478 return;
05479 }
05480 token = next_token(&val, NULL, cfile);
05481 switch (token) {
05482 case TOKEN_ABANDONED:
05483 state = FTS_ABANDONED;
05484 break;
05485 case TOKEN_FREE:
05486 state = FTS_FREE;
05487 break;
05488 case TOKEN_ACTIVE:
05489 state = FTS_ACTIVE;
05490 break;
05491 case TOKEN_EXPIRED:
05492 state = FTS_EXPIRED;
05493 break;
05494 case TOKEN_RELEASED:
05495 state = FTS_RELEASED;
05496 break;
05497 default:
05498 parse_warn(cfile,
05499 "corrupt lease "
05500 "file; "
05501 "expecting a "
05502 "binding state.");
05503 skip_to_semi(cfile);
05504 return;
05505 }
05506
05507 token = next_token(&val, NULL, cfile);
05508 if (token != SEMI) {
05509 parse_warn(cfile, "corrupt lease file; "
05510 "expecting "
05511 "semicolon.");
05512 }
05513 break;
05514
05515
05516 case PREFERRED_LIFE:
05517 token = next_token(&val, NULL, cfile);
05518 if (token != NUMBER) {
05519 parse_warn(cfile, "%s is not a valid "
05520 "preferred time",
05521 val);
05522 skip_to_semi(cfile);
05523 continue;
05524 }
05525 prefer = atoi (val);
05526
05527
05528
05529
05530
05531
05532
05533 token = peek_token(&val, NULL, cfile);
05534 if (token == SEMI) {
05535 skip_token(&val, NULL, cfile);
05536 } else {
05537 parse_warn(cfile,
05538 "corrupt lease file; "
05539 "expecting semicolon.");
05540 }
05541 break;
05542
05543
05544 case MAX_LIFE:
05545 token = next_token(&val, NULL, cfile);
05546 if (token != NUMBER) {
05547 parse_warn(cfile, "%s is not a valid "
05548 "max time",
05549 val);
05550 skip_to_semi(cfile);
05551 continue;
05552 }
05553 valid = atoi (val);
05554
05555
05556
05557
05558
05559
05560
05561 token = peek_token(&val, NULL, cfile);
05562 if (token == SEMI) {
05563 skip_token(&val, NULL, cfile);
05564 } else {
05565 parse_warn(cfile,
05566 "corrupt lease file; "
05567 "expecting semicolon.");
05568 }
05569 break;
05570
05571
05572 case ENDS:
05573 end_time = parse_date(cfile);
05574 break;
05575
05576
05577 case TOKEN_SET:
05578 token = next_token(&val, NULL, cfile);
05579 if ((token != NAME) &&
05580 (token != NUMBER_OR_NAME)) {
05581 parse_warn(cfile, "%s is not a valid "
05582 "variable name",
05583 val);
05584 skip_to_semi(cfile);
05585 continue;
05586 }
05587
05588 if (scope != NULL)
05589 bnd = find_binding(scope, val);
05590 else {
05591 if (!binding_scope_allocate(&scope,
05592 MDL)) {
05593 log_fatal("Out of memory for "
05594 "lease binding "
05595 "scope.");
05596 }
05597
05598 bnd = NULL;
05599 }
05600
05601 if (bnd == NULL) {
05602 bnd = dmalloc(sizeof(*bnd),
05603 MDL);
05604 if (bnd == NULL) {
05605 log_fatal("No memory for "
05606 "prefix binding.");
05607 }
05608
05609 bnd->name = dmalloc(strlen(val) + 1,
05610 MDL);
05611 if (bnd->name == NULL) {
05612 log_fatal("No memory for "
05613 "binding name.");
05614 }
05615 strcpy(bnd->name, val);
05616
05617 newbinding = ISC_TRUE;
05618 } else {
05619 newbinding = ISC_FALSE;
05620 }
05621
05622 if (!binding_value_allocate(&nv, MDL)) {
05623 log_fatal("no memory for binding "
05624 "value.");
05625 }
05626
05627 token = next_token(NULL, NULL, cfile);
05628 if (token != EQUAL) {
05629 parse_warn(cfile, "expecting '=' in "
05630 "set statement.");
05631 goto binding_err;
05632 }
05633
05634 if (!parse_binding_value(cfile, nv)) {
05635 binding_err:
05636 binding_value_dereference(&nv, MDL);
05637 binding_scope_dereference(&scope, MDL);
05638 return;
05639 }
05640
05641 if (newbinding) {
05642 binding_value_reference(&bnd->value,
05643 nv, MDL);
05644 bnd->next = scope->bindings;
05645 scope->bindings = bnd;
05646 } else {
05647 binding_value_dereference(&bnd->value,
05648 MDL);
05649 binding_value_reference(&bnd->value,
05650 nv, MDL);
05651 }
05652
05653 binding_value_dereference(&nv, MDL);
05654 parse_semi(cfile);
05655 break;
05656
05657 case ON:
05658 lose = 0;
05659
05660
05661
05662
05663
05664
05665
05666 if (on_star[0] == NULL) {
05667 if (!parse_on_statement (&on_star[0],
05668 cfile,
05669 &lose)) {
05670 parse_warn(cfile,
05671 "corrupt lease "
05672 "file; bad ON "
05673 "statement");
05674 skip_to_rbrace (cfile, 1);
05675 return;
05676 }
05677 } else {
05678 if (!parse_on_statement (&on_star[1],
05679 cfile,
05680 &lose)) {
05681 parse_warn(cfile,
05682 "corrupt lease "
05683 "file; bad ON "
05684 "statement");
05685 skip_to_rbrace (cfile, 1);
05686 return;
05687 }
05688 }
05689
05690 break;
05691
05692 default:
05693 parse_warn(cfile, "corrupt lease file; "
05694 "expecting ia_pd contents, "
05695 "got '%s'", val);
05696 skip_to_semi(cfile);
05697 continue;
05698 }
05699 }
05700
05701 if (state == FTS_LAST+1) {
05702 parse_warn(cfile, "corrupt lease file; "
05703 "missing state in iaprefix");
05704 return;
05705 }
05706 if (end_time == -1) {
05707 parse_warn(cfile, "corrupt lease file; "
05708 "missing end time in iaprefix");
05709 return;
05710 }
05711
05712 iapref = NULL;
05713 if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
05714 log_fatal("Out of memory.");
05715 }
05716 memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
05717 iapref->plen = plen;
05718 iapref->state = state;
05719 iapref->prefer = prefer;
05720 iapref->valid = valid;
05721 if (iapref->state == FTS_RELEASED)
05722 iapref->hard_lifetime_end_time = end_time;
05723
05724 if (scope != NULL) {
05725 binding_scope_reference(&iapref->scope, scope, MDL);
05726 binding_scope_dereference(&scope, MDL);
05727 }
05728
05729
05730
05731
05732
05733
05734
05735 for (i = 0;
05736 (i < 2) && on_star[i] != NULL ;
05737 i++) {
05738 if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
05739 on_star[i]->data.on.statements) {
05740 executable_statement_reference
05741 (&iapref->on_star.on_expiry,
05742 on_star[i]->data.on.statements, MDL);
05743 }
05744 if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
05745 on_star[i]->data.on.statements) {
05746 executable_statement_reference
05747 (&iapref->on_star.on_release,
05748 on_star[i]->data.on.statements, MDL);
05749 }
05750 executable_statement_dereference (&on_star[i], MDL);
05751 }
05752
05753
05754 pool = NULL;
05755 if (find_ipv6_pool(&pool, D6O_IA_PD,
05756 &iapref->addr) != ISC_R_SUCCESS) {
05757 inet_ntop(AF_INET6, &iapref->addr,
05758 addr_buf, sizeof(addr_buf));
05759 parse_warn(cfile, "no pool found for address %s",
05760 addr_buf);
05761 return;
05762 }
05763
05764
05765 if (cleanup_lease6(ia_pd_active, pool,
05766 iapref, ia) != ISC_R_SUCCESS) {
05767 inet_ntop(AF_INET6, &iapref->addr,
05768 addr_buf, sizeof(addr_buf));
05769 parse_warn(cfile, "duplicate pd lease for address %s",
05770 addr_buf);
05771 }
05772
05773
05774
05775
05776
05777
05778 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
05779 ia_add_iasubopt(ia, iapref, MDL);
05780 ia_reference(&iapref->ia, ia, MDL);
05781 add_lease6(pool, iapref, end_time);
05782 }
05783
05784 ipv6_pool_dereference(&pool, MDL);
05785 iasubopt_dereference(&iapref, MDL);
05786 }
05787
05788
05789
05790
05791 old_ia = NULL;
05792 if (ia_hash_lookup(&old_ia, ia_pd_active,
05793 (unsigned char *)ia->iaid_duid.data,
05794 ia->iaid_duid.len, MDL)) {
05795 ia_hash_delete(ia_pd_active,
05796 (unsigned char *)ia->iaid_duid.data,
05797 ia->iaid_duid.len, MDL);
05798 ia_dereference(&old_ia, MDL);
05799 }
05800
05801
05802
05803
05804 if (ia->num_iasubopt > 0) {
05805 ia_hash_add(ia_pd_active,
05806 (unsigned char *)ia->iaid_duid.data,
05807 ia->iaid_duid.len, ia, MDL);
05808 }
05809 ia_dereference(&ia, MDL);
05810 #endif
05811 }
05812
05813 #ifdef DHCPv6
05814
05815
05816
05817
05818
05819
05820
05821
05822 void
05823 parse_server_duid(struct parse *cfile) {
05824 enum dhcp_token token;
05825 const char *val;
05826 unsigned int len;
05827 struct data_string duid;
05828
05829 token = next_token(&val, &len, cfile);
05830 if (token != STRING) {
05831 parse_warn(cfile, "corrupt lease file; expecting a DUID");
05832 skip_to_semi(cfile);
05833 return;
05834 }
05835
05836 memset(&duid, 0, sizeof(duid));
05837 duid.len = len;
05838 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05839 log_fatal("Out of memory storing DUID");
05840 }
05841 duid.data = (unsigned char *)duid.buffer->data;
05842 memcpy(duid.buffer->data, val, len);
05843
05844 set_server_duid(&duid);
05845
05846 data_string_forget(&duid, MDL);
05847
05848 token = next_token(&val, &len, cfile);
05849 if (token != SEMI) {
05850 parse_warn(cfile, "corrupt lease file; expecting a semicolon");
05851 skip_to_semi(cfile);
05852 return;
05853 }
05854 }
05855
05856
05857
05858
05859
05860
05861
05862
05863
05864
05865
05866
05867 void
05868 parse_server_duid_conf(struct parse *cfile) {
05869 enum dhcp_token token;
05870 const char *val;
05871 unsigned int len;
05872 u_int32_t enterprise_number;
05873 int ll_type;
05874 struct data_string ll_addr;
05875 u_int32_t llt_time;
05876 struct data_string duid;
05877 int duid_type_num;
05878
05879
05880
05881
05882 skip_token(NULL, NULL, cfile);
05883
05884
05885
05886
05887 token = next_token(&val, NULL, cfile);
05888
05889
05890
05891
05892
05893 if (token == EN) {
05894
05895
05896
05897 token = next_token(&val, NULL, cfile);
05898 if (token != NUMBER) {
05899 parse_warn(cfile, "enterprise number expected");
05900 skip_to_semi(cfile);
05901 return;
05902 }
05903 enterprise_number = atoi(val);
05904
05905 token = next_token(&val, &len, cfile);
05906 if (token != STRING) {
05907 parse_warn(cfile, "identifier expected");
05908 skip_to_semi(cfile);
05909 return;
05910 }
05911
05912
05913
05914
05915 memset(&duid, 0, sizeof(duid));
05916 duid.len = 2 + 4 + len;
05917 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05918 log_fatal("Out of memory storing DUID");
05919 }
05920 duid.data = (unsigned char *)duid.buffer->data;
05921 putUShort(duid.buffer->data, DUID_EN);
05922 putULong(duid.buffer->data + 2, enterprise_number);
05923 memcpy(duid.buffer->data + 6, val, len);
05924
05925 set_server_duid(&duid);
05926 data_string_forget(&duid, MDL);
05927 }
05928
05929
05930
05931
05932
05933
05934
05935
05936 else if (token == LL) {
05937 if (peek_token(NULL, NULL, cfile) == SEMI) {
05938 set_server_duid_type(DUID_LL);
05939 } else {
05940
05941
05942
05943 token = next_token(NULL, NULL, cfile);
05944 switch (token) {
05945 case ETHERNET:
05946 ll_type = HTYPE_ETHER;
05947 break;
05948 case TOKEN_RING:
05949 ll_type = HTYPE_IEEE802;
05950 break;
05951 case TOKEN_FDDI:
05952 ll_type = HTYPE_FDDI;
05953 break;
05954 default:
05955 parse_warn(cfile, "hardware type expected");
05956 skip_to_semi(cfile);
05957 return;
05958 }
05959 memset(&ll_addr, 0, sizeof(ll_addr));
05960 if (!parse_cshl(&ll_addr, cfile)) {
05961 return;
05962 }
05963
05964
05965
05966
05967 memset(&duid, 0, sizeof(duid));
05968 duid.len = 2 + 2 + ll_addr.len;
05969 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05970 log_fatal("Out of memory storing DUID");
05971 }
05972 duid.data = (unsigned char *)duid.buffer->data;
05973 putUShort(duid.buffer->data, DUID_LL);
05974 putULong(duid.buffer->data + 2, ll_type);
05975 memcpy(duid.buffer->data + 4,
05976 ll_addr.data, ll_addr.len);
05977
05978 set_server_duid(&duid);
05979 data_string_forget(&duid, MDL);
05980 data_string_forget(&ll_addr, MDL);
05981 }
05982 }
05983
05984
05985
05986
05987
05988
05989
05990
05991 else if (token == LLT) {
05992 if (peek_token(NULL, NULL, cfile) == SEMI) {
05993 set_server_duid_type(DUID_LLT);
05994 } else {
05995
05996
05997
05998 token = next_token(NULL, NULL, cfile);
05999 switch (token) {
06000 case ETHERNET:
06001 ll_type = HTYPE_ETHER;
06002 break;
06003 case TOKEN_RING:
06004 ll_type = HTYPE_IEEE802;
06005 break;
06006 case TOKEN_FDDI:
06007 ll_type = HTYPE_FDDI;
06008 break;
06009 default:
06010 parse_warn(cfile, "hardware type expected");
06011 skip_to_semi(cfile);
06012 return;
06013 }
06014
06015 token = next_token(&val, NULL, cfile);
06016 if (token != NUMBER) {
06017 parse_warn(cfile, "timestamp expected");
06018 skip_to_semi(cfile);
06019 return;
06020 }
06021 llt_time = atoi(val);
06022
06023 memset(&ll_addr, 0, sizeof(ll_addr));
06024 if (!parse_cshl(&ll_addr, cfile)) {
06025 return;
06026 }
06027
06028
06029
06030
06031 memset(&duid, 0, sizeof(duid));
06032 duid.len = 2 + 2 + 4 + ll_addr.len;
06033 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
06034 log_fatal("Out of memory storing DUID");
06035 }
06036 duid.data = (unsigned char *)duid.buffer->data;
06037 putUShort(duid.buffer->data, DUID_LLT);
06038 putULong(duid.buffer->data + 2, ll_type);
06039 putULong(duid.buffer->data + 4, llt_time);
06040 memcpy(duid.buffer->data + 8,
06041 ll_addr.data, ll_addr.len);
06042
06043 set_server_duid(&duid);
06044 data_string_forget(&duid, MDL);
06045 data_string_forget(&ll_addr, MDL);
06046 }
06047 }
06048
06049
06050
06051
06052
06053
06054
06055
06056
06057
06058 else if (token == NUMBER) {
06059 duid_type_num = atoi(val);
06060
06061 token = next_token(&val, &len, cfile);
06062 if (token != STRING) {
06063 parse_warn(cfile, "identifier expected");
06064 skip_to_semi(cfile);
06065 return;
06066 }
06067
06068
06069
06070
06071 memset(&duid, 0, sizeof(duid));
06072 duid.len = 2 + len;
06073 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
06074 log_fatal("Out of memory storing DUID");
06075 }
06076 duid.data = (unsigned char *)duid.buffer->data;
06077 putUShort(duid.buffer->data, duid_type_num);
06078 memcpy(duid.buffer->data + 2, val, len);
06079
06080 set_server_duid(&duid);
06081 data_string_forget(&duid, MDL);
06082 }
06083
06084
06085
06086
06087 else {
06088 parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
06089 skip_to_semi(cfile);
06090 return;
06091 }
06092
06093
06094
06095
06096 token = next_token(NULL, NULL, cfile);
06097 if (token != SEMI) {
06098 parse_warn(cfile, "semicolon expected");
06099 skip_to_semi(cfile);
06100 }
06101 }
06102
06103 #endif
06104