📄 clparse.c
字号:
/* clparse.c Parser for dhclient config and lease files... *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * <info@isc.org> * http://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#ifndef lintstatic char copyright[] ="$Id: clparse.c,v 1.62.2.6 2004/06/10 17:59:11 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"static TIME parsed_time;struct client_config top_level_config;u_int32_t default_requested_options [] = { DHO_SUBNET_MASK, DHO_BROADCAST_ADDRESS, DHO_TIME_OFFSET, DHO_ROUTERS, DHO_DOMAIN_NAME, DHO_DOMAIN_NAME_SERVERS, DHO_HOST_NAME, 0};/* client-conf-file :== client-declarations END_OF_FILE client-declarations :== <nil> | client-declaration | client-declarations client-declaration */isc_result_t read_client_conf (){ struct client_config *config; struct client_state *state; struct interface_info *ip; isc_result_t status; /* Set up the initial dhcp option universe. */ initialize_common_option_spaces (); /* Initialize the top level client configuration. */ memset (&top_level_config, 0, sizeof top_level_config); /* Set some defaults... */ top_level_config.timeout = 60; top_level_config.select_interval = 0; top_level_config.reboot_timeout = 10; top_level_config.retry_interval = 300; top_level_config.backoff_cutoff = 15; top_level_config.initial_interval = 3; top_level_config.bootp_policy = P_ACCEPT; top_level_config.script_name = path_dhclient_script; top_level_config.requested_options = default_requested_options; top_level_config.omapi_port = -1; top_level_config.do_forward_update = 1; group_allocate (&top_level_config.on_receipt, MDL); if (!top_level_config.on_receipt) log_fatal ("no memory for top-level on_receipt group"); group_allocate (&top_level_config.on_transmission, MDL); if (!top_level_config.on_transmission) log_fatal ("no memory for top-level on_transmission group"); status = read_client_conf_file (path_dhclient_conf, (struct interface_info *)0, &top_level_config); if (status != ISC_R_SUCCESS) { ;#ifdef LATER /* Set up the standard name service updater routine. */ parse = (struct parse *)0; status = new_parse (&parse, -1, default_client_config, (sizeof default_client_config) - 1, "default client configuration", 0); if (status != ISC_R_SUCCESS) log_fatal ("can't begin default client config!"); do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; parse_client_statement (cfile, (struct interface_info *)0, &top_level_config); } while (1); end_parse (&parse);#endif } /* Set up state and config structures for clients that don't have per-interface configuration statements. */ config = (struct client_config *)0; for (ip = interfaces; ip; ip = ip -> next) { if (!ip -> client) { ip -> client = (struct client_state *) dmalloc (sizeof (struct client_state), MDL); if (!ip -> client) log_fatal ("no memory for client state."); memset (ip -> client, 0, sizeof *(ip -> client)); ip -> client -> interface = ip; } if (!ip -> client -> config) { if (!config) { config = (struct client_config *) dmalloc (sizeof (struct client_config), MDL); if (!config) log_fatal ("no memory for client config."); memcpy (config, &top_level_config, sizeof top_level_config); } ip -> client -> config = config; } } return status;}int read_client_conf_file (const char *name, struct interface_info *ip, struct client_config *client){ int file; struct parse *cfile; const char *val; int token; isc_result_t status; if ((file = open (name, O_RDONLY)) < 0) return uerr2isc (errno); cfile = (struct parse *)0; new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0); do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; parse_client_statement (cfile, ip, client); } while (1); token = next_token (&val, (unsigned *)0, cfile); status = (cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS); close (file); end_parse (&cfile); return status;}/* lease-file :== client-lease-statements END_OF_FILE client-lease-statements :== <nil> | client-lease-statements LEASE client-lease-statement */void read_client_leases (){ int file; struct parse *cfile; const char *val; int token; /* Open the lease file. If we can't open it, just return - we can safely trust the server to remember our state. */ if ((file = open (path_dhclient_db, O_RDONLY)) < 0) return; cfile = (struct parse *)0; new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0); do { token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; if (token != LEASE) { log_error ("Corrupt lease file - possible data loss!"); skip_to_semi (cfile); break; } else parse_client_lease_statement (cfile, 0); } while (1); close (file); end_parse (&cfile);}/* client-declaration :== SEND option-decl | DEFAULT option-decl | SUPERSEDE option-decl | PREPEND option-decl | APPEND option-decl | hardware-declaration | REQUEST option-list | REQUIRE option-list | TIMEOUT number | RETRY number | REBOOT number | SELECT_TIMEOUT number | SCRIPT string | VENDOR_SPACE string | interface-declaration | LEASE client-lease-statement | ALIAS client-lease-statement | KEY key-definition */void parse_client_statement (cfile, ip, config) struct parse *cfile; struct interface_info *ip; struct client_config *config;{ int token; const char *val; struct option *option; struct executable_statement *stmt, **p; enum statement_op op; int lose; char *name; struct data_string key_id; enum policy policy; int known; int tmp, i; isc_result_t status; switch (peek_token (&val, (unsigned *)0, cfile)) { case INCLUDE: next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "filename string expected."); skip_to_semi (cfile); } else { status = read_client_conf_file (val, ip, config); if (status != ISC_R_SUCCESS) parse_warn (cfile, "%s: bad parse.", val); parse_semi (cfile); } return; case KEY: next_token (&val, (unsigned *)0, cfile); if (ip) { /* This may seem arbitrary, but there's a reason for doing it: the authentication key database is not scoped. If we allow the user to declare a key other than in the outer scope, the user is very likely to believe that the key will only be used in that scope. If the user only wants the key to be used on one interface, because it's known that the other interface may be connected to an insecure net and the secret key is considered sensitive, we don't want to lull them into believing they've gotten their way. This is a bit contrived, but people tend not to be entirely rational about security. */ parse_warn (cfile, "key definition not allowed here."); skip_to_semi (cfile); break; } parse_key (cfile); return; /* REQUIRE can either start a policy statement or a comma-seperated list of names of required options. */ case REQUIRE: next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == AUTHENTICATION) { policy = P_REQUIRE; goto do_policy; } parse_option_list (cfile, &config -> required_options); return; case IGNORE: next_token (&val, (unsigned *)0, cfile); policy = P_IGNORE; goto do_policy; case ACCEPT: next_token (&val, (unsigned *)0, cfile); policy = P_ACCEPT; goto do_policy; case PREFER: next_token (&val, (unsigned *)0, cfile); policy = P_PREFER; goto do_policy; case DONT: next_token (&val, (unsigned *)0, cfile); policy = P_DONT; goto do_policy; do_policy: token = next_token (&val, (unsigned *)0, cfile); if (token == AUTHENTICATION) { if (policy != P_PREFER && policy != P_REQUIRE && policy != P_DONT) { parse_warn (cfile, "invalid authentication policy."); skip_to_semi (cfile); return; } config -> auth_policy = policy; } else if (token != TOKEN_BOOTP) { if (policy != P_PREFER && policy != P_IGNORE && policy != P_ACCEPT) { parse_warn (cfile, "invalid bootp policy."); skip_to_semi (cfile); return; } config -> bootp_policy = policy; } else { parse_warn (cfile, "expecting a policy type."); skip_to_semi (cfile); return; } break; case OPTION: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == SPACE) { if (ip) { parse_warn (cfile, "option space definitions %s", " may not be scoped."); skip_to_semi (cfile); break; } parse_option_space_decl (cfile); return; } option = parse_option_name (cfile, 1, &known); if (!option) return; token = next_token (&val, (unsigned *)0, cfile); if (token != CODE) { parse_warn (cfile, "expecting \"code\" keyword."); skip_to_semi (cfile); free_option (option, MDL); return; } if (ip) { parse_warn (cfile, "option definitions may only appear in %s", "the outermost scope."); skip_to_semi (cfile); free_option (option, MDL); return; } if (!parse_option_code_definition (cfile, option)) free_option (option, MDL); return; case MEDIA:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -