Index: stable/11/sbin/dhclient/Makefile =================================================================== --- stable/11/sbin/dhclient/Makefile (revision 332601) +++ stable/11/sbin/dhclient/Makefile (revision 332602) @@ -1,53 +1,54 @@ # $OpenBSD: Makefile,v 1.9 2004/05/04 12:52:05 henning Exp $ # $FreeBSD$ # # Copyright (c) 1996, 1997 The Internet Software Consortium. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of The Internet Software Consortium nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # .include PACKAGE=runtime SRCS= dhclient.c clparse.c alloc.c dispatch.c hash.c bpf.c options.c \ tree.c conflex.c errwarn.c inet.c packet.c convert.c tables.c \ parse.c privsep.c PROG= dhclient SCRIPTS=dhclient-script MAN= dhclient.8 dhclient.conf.5 dhclient.leases.5 dhcp-options.5 \ dhclient-script.8 LIBADD= util -WARNS?= 3 +WARNS?= 4 +NO_WCAST_ALIGN= yes .if ${MK_TESTS} != "no" SUBDIR+= tests .endif .include Index: stable/11/sbin/dhclient/clparse.c =================================================================== --- stable/11/sbin/dhclient/clparse.c (revision 332601) +++ stable/11/sbin/dhclient/clparse.c (revision 332602) @@ -1,957 +1,957 @@ /* $OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $ */ /* Parser for dhclient config and lease files... */ /* * Copyright (c) 1997 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "dhctoken.h" struct client_config top_level_config; struct interface_info *dummy_interfaces; extern struct interface_info *ifi; char client_script_name[] = "/sbin/dhclient-script"; /* * client-conf-file :== client-declarations EOF * client-declarations :== * | client-declaration * | client-declarations client-declaration */ int read_client_conf(void) { FILE *cfile; char *val; int token; struct client_config *config; new_parse(path_dhclient_conf); /* Set up the initial dhcp option universe. */ initialize_universes(); /* 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 = ACCEPT; top_level_config.script_name = client_script_name; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_SUBNET_MASK; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_TIME_OFFSET; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_ROUTERS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME_SERVERS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_HOST_NAME; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_INTERFACE_MTU; if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { do { token = peek_token(&val, cfile); if (token == EOF) break; parse_client_statement(cfile, NULL, &top_level_config); } while (1); token = next_token(&val, cfile); /* Clear the peek buffer */ fclose(cfile); } /* * Set up state and config structures for clients that don't * have per-interface configuration declarations. */ config = NULL; if (!ifi->client) { ifi->client = malloc(sizeof(struct client_state)); if (!ifi->client) error("no memory for client state."); memset(ifi->client, 0, sizeof(*(ifi->client))); } if (!ifi->client->config) { if (!config) { config = malloc(sizeof(struct client_config)); if (!config) error("no memory for client config."); memcpy(config, &top_level_config, sizeof(top_level_config)); } ifi->client->config = config; } return (!warnings_occurred); } /* * lease-file :== client-lease-statements EOF * client-lease-statements :== * | client-lease-statements LEASE client-lease-statement */ void read_client_leases(void) { FILE *cfile; char *val; int token; new_parse(path_dhclient_db); /* Open the lease file. If we can't open it, just return - we can safely trust the server to remember our state. */ if ((cfile = fopen(path_dhclient_db, "r")) == NULL) return; do { token = next_token(&val, cfile); if (token == EOF) break; if (token != LEASE) { warning("Corrupt lease file - possible data loss!"); skip_to_semi(cfile); break; } else parse_client_lease_statement(cfile, 0); } while (1); fclose(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 | * interface-declaration | * LEASE client-lease-statement | * ALIAS client-lease-statement */ void parse_client_statement(FILE *cfile, struct interface_info *ip, struct client_config *config) { int token; char *val; struct option *option; switch (next_token(&val, cfile)) { case SEND: parse_option_decl(cfile, &config->send_options[0]); return; case DEFAULT: option = parse_option_decl(cfile, &config->defaults[0]); if (option) config->default_actions[option->code] = ACTION_DEFAULT; return; case SUPERSEDE: option = parse_option_decl(cfile, &config->defaults[0]); if (option) config->default_actions[option->code] = ACTION_SUPERSEDE; return; case APPEND: option = parse_option_decl(cfile, &config->defaults[0]); if (option) config->default_actions[option->code] = ACTION_APPEND; return; case PREPEND: option = parse_option_decl(cfile, &config->defaults[0]); if (option) config->default_actions[option->code] = ACTION_PREPEND; return; case MEDIA: parse_string_list(cfile, &config->media, 1); return; case HARDWARE: if (ip) parse_hardware_param(cfile, &ip->hw_address); else { parse_warn("hardware address parameter %s", "not allowed here."); skip_to_semi(cfile); } return; case REQUEST: config->requested_option_count = parse_option_list(cfile, config->requested_options); return; case REQUIRE: memset(config->required_options, 0, sizeof(config->required_options)); parse_option_list(cfile, config->required_options); return; case TIMEOUT: parse_lease_time(cfile, &config->timeout); return; case RETRY: parse_lease_time(cfile, &config->retry_interval); return; case SELECT_TIMEOUT: parse_lease_time(cfile, &config->select_interval); return; case REBOOT: parse_lease_time(cfile, &config->reboot_timeout); return; case BACKOFF_CUTOFF: parse_lease_time(cfile, &config->backoff_cutoff); return; case INITIAL_INTERVAL: parse_lease_time(cfile, &config->initial_interval); return; case SCRIPT: config->script_name = parse_string(cfile); return; case INTERFACE: if (ip) parse_warn("nested interface declaration."); parse_interface_declaration(cfile, config); return; case LEASE: parse_client_lease_statement(cfile, 1); return; case ALIAS: parse_client_lease_statement(cfile, 2); return; case REJECT: parse_reject_statement(cfile, config); return; default: parse_warn("expecting a statement."); skip_to_semi(cfile); break; } token = next_token(&val, cfile); if (token != SEMI) { parse_warn("semicolon expected."); skip_to_semi(cfile); } } unsigned parse_X(FILE *cfile, u_int8_t *buf, unsigned max) { int token; char *val; unsigned len; token = peek_token(&val, cfile); if (token == NUMBER_OR_NAME || token == NUMBER) { len = 0; do { token = next_token(&val, cfile); if (token != NUMBER && token != NUMBER_OR_NAME) { parse_warn("expecting hexadecimal constant."); skip_to_semi(cfile); return (0); } convert_num(&buf[len], val, 16, 8); if (len++ > max) { parse_warn("hexadecimal constant too long."); skip_to_semi(cfile); return (0); } token = peek_token(&val, cfile); if (token == COLON) token = next_token(&val, cfile); } while (token == COLON); val = (char *)buf; } else if (token == STRING) { token = next_token(&val, cfile); len = strlen(val); if (len + 1 > max) { parse_warn("string constant too long."); skip_to_semi(cfile); return (0); } memcpy(buf, val, len + 1); } else { parse_warn("expecting string or hexadecimal data"); skip_to_semi(cfile); return (0); } return (len); } /* * option-list :== option_name | * option_list COMMA option_name */ int parse_option_list(FILE *cfile, u_int8_t *list) { int ix, i; int token; char *val; ix = 0; do { token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expected option name."); skip_to_semi(cfile); return (0); } for (i = 0; i < 256; i++) if (!strcasecmp(dhcp_options[i].name, val)) break; if (i == 256) { parse_warn("%s: unexpected option name.", val); skip_to_semi(cfile); return (0); } list[ix++] = i; if (ix == 256) { parse_warn("%s: too many options.", val); skip_to_semi(cfile); return (0); } token = next_token(&val, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn("expecting semicolon."); skip_to_semi(cfile); return (0); } return (ix); } /* * interface-declaration :== * INTERFACE string LBRACE client-declarations RBRACE */ void parse_interface_declaration(FILE *cfile, struct client_config *outer_config) { int token; char *val; struct interface_info *ip; token = next_token(&val, cfile); if (token != STRING) { parse_warn("expecting interface name (in quotes)."); skip_to_semi(cfile); return; } ip = interface_or_dummy(val); if (!ip->client) make_client_state(ip); if (!ip->client->config) make_client_config(ip, outer_config); token = next_token(&val, cfile); if (token != LBRACE) { parse_warn("expecting left brace."); skip_to_semi(cfile); return; } do { token = peek_token(&val, cfile); if (token == EOF) { parse_warn("unterminated interface declaration."); return; } if (token == RBRACE) break; parse_client_statement(cfile, ip, ip->client->config); } while (1); token = next_token(&val, cfile); } struct interface_info * interface_or_dummy(char *name) { struct interface_info *ip; /* Find the interface (if any) that matches the name. */ if (!strcmp(ifi->name, name)) return (ifi); /* If it's not a real interface, see if it's on the dummy list. */ for (ip = dummy_interfaces; ip; ip = ip->next) if (!strcmp(ip->name, name)) return (ip); /* * If we didn't find an interface, make a dummy interface as a * placeholder. */ ip = malloc(sizeof(*ip)); if (!ip) error("Insufficient memory to record interface %s", name); memset(ip, 0, sizeof(*ip)); strlcpy(ip->name, name, IFNAMSIZ); ip->next = dummy_interfaces; dummy_interfaces = ip; return (ip); } void make_client_state(struct interface_info *ip) { ip->client = malloc(sizeof(*(ip->client))); if (!ip->client) error("no memory for state on %s", ip->name); memset(ip->client, 0, sizeof(*(ip->client))); } void make_client_config(struct interface_info *ip, struct client_config *config) { ip->client->config = malloc(sizeof(struct client_config)); if (!ip->client->config) error("no memory for config for %s", ip->name); memset(ip->client->config, 0, sizeof(*(ip->client->config))); memcpy(ip->client->config, config, sizeof(*config)); } /* * client-lease-statement :== * RBRACE client-lease-declarations LBRACE * * client-lease-declarations :== * | * client-lease-declaration | * client-lease-declarations client-lease-declaration */ void parse_client_lease_statement(FILE *cfile, int is_static) { struct client_lease *lease, *lp, *pl; struct interface_info *ip; int token; char *val; token = next_token(&val, cfile); if (token != LBRACE) { parse_warn("expecting left brace."); skip_to_semi(cfile); return; } lease = malloc(sizeof(struct client_lease)); if (!lease) error("no memory for lease."); memset(lease, 0, sizeof(*lease)); lease->is_static = is_static; ip = NULL; do { token = peek_token(&val, cfile); if (token == EOF) { parse_warn("unterminated lease declaration."); free_client_lease(lease); return; } if (token == RBRACE) break; parse_client_lease_declaration(cfile, lease, &ip); } while (1); token = next_token(&val, cfile); /* If the lease declaration didn't include an interface * declaration that we recognized, it's of no use to us. */ if (!ip) { free_client_lease(lease); return; } /* Make sure there's a client state structure... */ if (!ip->client) make_client_state(ip); /* If this is an alias lease, it doesn't need to be sorted in. */ if (is_static == 2) { ip->client->alias = lease; return; } /* * The new lease may supersede a lease that's not the active * lease but is still on the lease list, so scan the lease list * looking for a lease with the same address, and if we find it, * toss it. */ pl = NULL; for (lp = ip->client->leases; lp; lp = lp->next) { if (lp->address.len == lease->address.len && !memcmp(lp->address.iabuf, lease->address.iabuf, lease->address.len)) { if (pl) pl->next = lp->next; else ip->client->leases = lp->next; free_client_lease(lp); break; } } /* * If this is a preloaded lease, just put it on the list of * recorded leases - don't make it the active lease. */ if (is_static) { lease->next = ip->client->leases; ip->client->leases = lease; return; } /* * The last lease in the lease file on a particular interface is * the active lease for that interface. Of course, we don't * know what the last lease in the file is until we've parsed * the whole file, so at this point, we assume that the lease we * just parsed is the active lease for its interface. If * there's already an active lease for the interface, and this * lease is for the same ip address, then we just toss the old * active lease and replace it with this one. If this lease is * for a different address, then if the old active lease has * expired, we dump it; if not, we put it on the list of leases * for this interface which are still valid but no longer * active. */ if (ip->client->active) { if (ip->client->active->expiry < cur_time) free_client_lease(ip->client->active); else if (ip->client->active->address.len == lease->address.len && !memcmp(ip->client->active->address.iabuf, lease->address.iabuf, lease->address.len)) free_client_lease(ip->client->active); else { ip->client->active->next = ip->client->leases; ip->client->leases = ip->client->active; } } ip->client->active = lease; /* Phew. */ } /* * client-lease-declaration :== * BOOTP | * INTERFACE string | * FIXED_ADDR ip_address | * FILENAME string | * SERVER_NAME string | * OPTION option-decl | * RENEW time-decl | * REBIND time-decl | * EXPIRE time-decl */ void parse_client_lease_declaration(FILE *cfile, struct client_lease *lease, struct interface_info **ipp) { int token; char *val; struct interface_info *ip; switch (next_token(&val, cfile)) { case BOOTP: lease->is_bootp = 1; break; case INTERFACE: token = next_token(&val, cfile); if (token != STRING) { parse_warn("expecting interface name (in quotes)."); skip_to_semi(cfile); break; } ip = interface_or_dummy(val); *ipp = ip; break; case FIXED_ADDR: if (!parse_ip_addr(cfile, &lease->address)) return; break; case MEDIUM: parse_string_list(cfile, &lease->medium, 0); return; case FILENAME: lease->filename = parse_string(cfile); return; case NEXT_SERVER: if (!parse_ip_addr(cfile, &lease->nextserver)) return; break; case SERVER_NAME: lease->server_name = parse_string(cfile); return; case RENEW: lease->renewal = parse_date(cfile); return; case REBIND: lease->rebind = parse_date(cfile); return; case EXPIRE: lease->expiry = parse_date(cfile); return; case OPTION: parse_option_decl(cfile, lease->options); return; default: parse_warn("expecting lease declaration."); skip_to_semi(cfile); break; } token = next_token(&val, cfile); if (token != SEMI) { parse_warn("expecting semicolon."); skip_to_semi(cfile); } } struct option * parse_option_decl(FILE *cfile, struct option_data *options) { char *val; int token; u_int8_t buf[4]; u_int8_t hunkbuf[1024]; unsigned hunkix = 0; char *vendor; - char *fmt; + const char *fmt; struct universe *universe; struct option *option; struct iaddr ip_addr; u_int8_t *dp; unsigned len; int nul_term = 0; token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier after option keyword."); if (token != SEMI) skip_to_semi(cfile); return (NULL); } if ((vendor = strdup(val)) == NULL) error("no memory for vendor information."); token = peek_token(&val, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ token = next_token(&val, cfile); /* The next token should be an identifier... */ token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier after '.'"); if (token != SEMI) skip_to_semi(cfile); free(vendor); return (NULL); } /* Look up the option name hash table for the specified vendor. */ universe = ((struct universe *)hash_lookup(&universe_hash, (unsigned char *)vendor, 0)); /* If it's not there, we can't parse the rest of the declaration. */ if (!universe) { parse_warn("no vendor named %s.", vendor); skip_to_semi(cfile); free(vendor); return (NULL); } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ val = vendor; universe = &dhcp_universe; } /* Look up the actual option info... */ option = (struct option *)hash_lookup(universe->hash, (unsigned char *)val, 0); /* If we didn't get an option structure, it's an undefined option. */ if (!option) { if (val == vendor) parse_warn("no option named %s", val); else parse_warn("no option named %s for vendor %s", val, vendor); skip_to_semi(cfile); free(vendor); return (NULL); } /* Free the initial identifier token. */ free(vendor); /* Parse the option data... */ do { for (fmt = option->format; *fmt; fmt++) { if (*fmt == 'A') break; switch (*fmt) { case 'X': len = parse_X(cfile, &hunkbuf[hunkix], sizeof(hunkbuf) - hunkix); hunkix += len; break; case 't': /* Text string... */ token = next_token(&val, cfile); if (token != STRING) { parse_warn("expecting string."); skip_to_semi(cfile); return (NULL); } len = strlen(val); if (hunkix + len + 1 > sizeof(hunkbuf)) { parse_warn("option data buffer %s", "overflow"); skip_to_semi(cfile); return (NULL); } memcpy(&hunkbuf[hunkix], val, len + 1); nul_term = 1; hunkix += len; break; case 'I': /* IP address. */ if (!parse_ip_addr(cfile, &ip_addr)) return (NULL); len = ip_addr.len; dp = ip_addr.iabuf; alloc: if (hunkix + len > sizeof(hunkbuf)) { parse_warn("option data buffer " "overflow"); skip_to_semi(cfile); return (NULL); } memcpy(&hunkbuf[hunkix], dp, len); hunkix += len; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token(&val, cfile); if (token != NUMBER) { need_number: parse_warn("expecting number."); if (token != SEMI) skip_to_semi(cfile); return (NULL); } convert_num(buf, val, 0, 32); len = 4; dp = buf; goto alloc; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token(&val, cfile); if (token != NUMBER) goto need_number; convert_num(buf, val, 0, 16); len = 2; dp = buf; goto alloc; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token(&val, cfile); if (token != NUMBER) goto need_number; convert_num(buf, val, 0, 8); len = 1; dp = buf; goto alloc; case 'f': /* Boolean flag. */ token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier."); bad_flag: if (token != SEMI) skip_to_semi(cfile); return (NULL); } if (!strcasecmp(val, "true") || !strcasecmp(val, "on")) buf[0] = 1; else if (!strcasecmp(val, "false") || !strcasecmp(val, "off")) buf[0] = 0; else { parse_warn("expecting boolean."); goto bad_flag; } len = 1; dp = buf; goto alloc; default: warning("Bad format %c in parse_option_param.", *fmt); skip_to_semi(cfile); return (NULL); } } token = next_token(&val, cfile); } while (*fmt == 'A' && token == COMMA); if (token != SEMI) { parse_warn("semicolon expected."); skip_to_semi(cfile); return (NULL); } options[option->code].data = malloc(hunkix + nul_term); if (!options[option->code].data) error("out of memory allocating option data."); memcpy(options[option->code].data, hunkbuf, hunkix + nul_term); options[option->code].len = hunkix; return (option); } void parse_string_list(FILE *cfile, struct string_list **lp, int multiple) { int token; char *val; size_t valsize; struct string_list *cur, *tmp; /* Find the last medium in the media list. */ if (*lp) for (cur = *lp; cur->next; cur = cur->next) ; /* nothing */ else cur = NULL; do { token = next_token(&val, cfile); if (token != STRING) { parse_warn("Expecting media options."); skip_to_semi(cfile); return; } valsize = strlen(val) + 1; tmp = new_string_list(valsize); if (tmp == NULL) error("no memory for string list entry."); memcpy(tmp->string, val, valsize); tmp->next = NULL; /* Store this medium at the end of the media list. */ if (cur) cur->next = tmp; else *lp = tmp; cur = tmp; token = next_token(&val, cfile); } while (multiple && token == COMMA); if (token != SEMI) { parse_warn("expecting semicolon."); skip_to_semi(cfile); } } void parse_reject_statement(FILE *cfile, struct client_config *config) { int token; char *val; struct iaddr addr; struct iaddrlist *list; do { if (!parse_ip_addr(cfile, &addr)) { parse_warn("expecting IP address."); skip_to_semi(cfile); return; } list = malloc(sizeof(struct iaddrlist)); if (!list) error("no memory for reject list!"); list->addr = addr; list->next = config->reject_list; config->reject_list = list; token = next_token(&val, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn("expecting semicolon."); skip_to_semi(cfile); } } Index: stable/11/sbin/dhclient/conflex.c =================================================================== --- stable/11/sbin/dhclient/conflex.c (revision 332601) +++ stable/11/sbin/dhclient/conflex.c (revision 332602) @@ -1,531 +1,531 @@ /* $OpenBSD: conflex.c,v 1.7 2004/09/15 19:02:38 deraadt Exp $ */ /* Lexical scanner for dhcpd config file... */ /* * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include #include "dhcpd.h" #include "dhctoken.h" int lexline; int lexchar; char *token_line; char *prev_line; char *cur_line; -char *tlname; +const char *tlname; int eol_token; static char line1[81]; static char line2[81]; static unsigned lpos; static unsigned line; static int tlpos; static int tline; static int token; static int ugflag; static char *tval; static char tokbuf[1500]; static int get_char(FILE *); static int get_token(FILE *); static void skip_to_eol(FILE *); static int read_string(FILE *); static int read_number(int, FILE *); static int read_num_or_name(int, FILE *); static int intern(char *, int); void -new_parse(char *name) +new_parse(const char *name) { tlname = name; lpos = line = 1; cur_line = line1; prev_line = line2; token_line = cur_line; cur_line[0] = prev_line[0] = 0; warnings_occurred = 0; } static int get_char(FILE *cfile) { int c = getc(cfile); if (!ugflag) { if (c == '\n') { if (cur_line == line1) { cur_line = line2; prev_line = line1; } else { cur_line = line1; prev_line = line2; } line++; lpos = 1; cur_line[0] = 0; } else if (c != EOF) { if (lpos < sizeof(line1)) { cur_line[lpos - 1] = c; cur_line[lpos] = 0; } lpos++; } } else ugflag = 0; return (c); } static int get_token(FILE *cfile) { int c, ttok; static char tb[2]; int l, p; do { l = line; p = lpos; c = get_char(cfile); if (!(c == '\n' && eol_token) && isascii(c) && isspace(c)) continue; if (c == '#') { skip_to_eol(cfile); continue; } if (c == '"') { lexline = l; lexchar = p; ttok = read_string(cfile); break; } if ((isascii(c) && isdigit(c)) || c == '-') { lexline = l; lexchar = p; ttok = read_number(c, cfile); break; } else if (isascii(c) && isalpha(c)) { lexline = l; lexchar = p; ttok = read_num_or_name(c, cfile); break; } else { lexline = l; lexchar = p; tb[0] = c; tb[1] = 0; tval = tb; ttok = c; break; } } while (1); return (ttok); } int next_token(char **rval, FILE *cfile) { int rv; if (token) { if (lexline != tline) token_line = cur_line; lexchar = tlpos; lexline = tline; rv = token; token = 0; } else { rv = get_token(cfile); token_line = cur_line; } if (rval) *rval = tval; return (rv); } int peek_token(char **rval, FILE *cfile) { int x; if (!token) { tlpos = lexchar; tline = lexline; token = get_token(cfile); if (lexline != tline) token_line = prev_line; x = lexchar; lexchar = tlpos; tlpos = x; x = lexline; lexline = tline; tline = x; } if (rval) *rval = tval; return (token); } static void skip_to_eol(FILE *cfile) { int c; do { c = get_char(cfile); if (c == EOF) return; if (c == '\n') return; } while (1); } static int read_string(FILE *cfile) { int c, bs = 0; unsigned i; for (i = 0; i < sizeof(tokbuf); i++) { c = get_char(cfile); if (c == EOF) { parse_warn("eof in string constant"); break; } if (bs) { bs = 0; i--; tokbuf[i] = c; } else if (c == '\\') bs = 1; else if (c == '"') break; else tokbuf[i] = c; } /* * Normally, I'd feel guilty about this, but we're talking about * strings that'll fit in a DHCP packet here... */ if (i == sizeof(tokbuf)) { parse_warn("string constant larger than internal buffer"); i--; } tokbuf[i] = 0; tval = tokbuf; return (STRING); } static int read_number(int c, FILE *cfile) { - int seenx = 0, token = NUMBER; + int seenx = 0, _token = NUMBER; unsigned i = 0; tokbuf[i++] = c; for (; i < sizeof(tokbuf); i++) { c = get_char(cfile); if (!seenx && c == 'x') seenx = 1; else if (!isascii(c) || !isxdigit(c)) { ungetc(c, cfile); ugflag = 1; break; } tokbuf[i] = c; } if (i == sizeof(tokbuf)) { parse_warn("numeric token larger than internal buffer"); i--; } tokbuf[i] = 0; tval = tokbuf; - return (token); + return (_token); } static int read_num_or_name(int c, FILE *cfile) { unsigned i = 0; int rv = NUMBER_OR_NAME; tokbuf[i++] = c; for (; i < sizeof(tokbuf); i++) { c = get_char(cfile); if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { ungetc(c, cfile); ugflag = 1; break; } if (!isxdigit(c)) rv = NAME; tokbuf[i] = c; } if (i == sizeof(tokbuf)) { parse_warn("token larger than internal buffer"); i--; } tokbuf[i] = 0; tval = tokbuf; return (intern(tval, rv)); } static int intern(char *atom, int dfv) { if (!isascii(atom[0])) return (dfv); switch (tolower(atom[0])) { case 'a': if (!strcasecmp(atom + 1, "lways-reply-rfc1048")) return (ALWAYS_REPLY_RFC1048); if (!strcasecmp(atom + 1, "ppend")) return (APPEND); if (!strcasecmp(atom + 1, "llow")) return (ALLOW); if (!strcasecmp(atom + 1, "lias")) return (ALIAS); if (!strcasecmp(atom + 1, "bandoned")) return (ABANDONED); if (!strcasecmp(atom + 1, "uthoritative")) return (AUTHORITATIVE); break; case 'b': if (!strcasecmp(atom + 1, "ackoff-cutoff")) return (BACKOFF_CUTOFF); if (!strcasecmp(atom + 1, "ootp")) return (BOOTP); if (!strcasecmp(atom + 1, "ooting")) return (BOOTING); if (!strcasecmp(atom + 1, "oot-unknown-clients")) return (BOOT_UNKNOWN_CLIENTS); case 'c': if (!strcasecmp(atom + 1, "lass")) return (CLASS); if (!strcasecmp(atom + 1, "iaddr")) return (CIADDR); if (!strcasecmp(atom + 1, "lient-identifier")) return (CLIENT_IDENTIFIER); if (!strcasecmp(atom + 1, "lient-hostname")) return (CLIENT_HOSTNAME); break; case 'd': if (!strcasecmp(atom + 1, "omain")) return (DOMAIN); if (!strcasecmp(atom + 1, "eny")) return (DENY); if (!strncasecmp(atom + 1, "efault", 6)) { if (!atom[7]) return (DEFAULT); if (!strcasecmp(atom + 7, "-lease-time")) return (DEFAULT_LEASE_TIME); break; } if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { if (!atom[13]) return (DYNAMIC_BOOTP); if (!strcasecmp(atom + 13, "-lease-cutoff")) return (DYNAMIC_BOOTP_LEASE_CUTOFF); if (!strcasecmp(atom + 13, "-lease-length")) return (DYNAMIC_BOOTP_LEASE_LENGTH); break; } break; case 'e': if (!strcasecmp(atom + 1, "thernet")) return (ETHERNET); if (!strcasecmp(atom + 1, "nds")) return (ENDS); if (!strcasecmp(atom + 1, "xpire")) return (EXPIRE); break; case 'f': if (!strcasecmp(atom + 1, "ilename")) return (FILENAME); if (!strcasecmp(atom + 1, "ixed-address")) return (FIXED_ADDR); if (!strcasecmp(atom + 1, "ddi")) return (FDDI); break; case 'g': if (!strcasecmp(atom + 1, "iaddr")) return (GIADDR); if (!strcasecmp(atom + 1, "roup")) return (GROUP); if (!strcasecmp(atom + 1, "et-lease-hostnames")) return (GET_LEASE_HOSTNAMES); break; case 'h': if (!strcasecmp(atom + 1, "ost")) return (HOST); if (!strcasecmp(atom + 1, "ardware")) return (HARDWARE); if (!strcasecmp(atom + 1, "ostname")) return (HOSTNAME); break; case 'i': if (!strcasecmp(atom + 1, "nitial-interval")) return (INITIAL_INTERVAL); if (!strcasecmp(atom + 1, "nterface")) return (INTERFACE); break; case 'l': if (!strcasecmp(atom + 1, "ease")) return (LEASE); break; case 'm': if (!strcasecmp(atom + 1, "ax-lease-time")) return (MAX_LEASE_TIME); if (!strncasecmp(atom + 1, "edi", 3)) { if (!strcasecmp(atom + 4, "a")) return (MEDIA); if (!strcasecmp(atom + 4, "um")) return (MEDIUM); break; } break; case 'n': if (!strcasecmp(atom + 1, "ameserver")) return (NAMESERVER); if (!strcasecmp(atom + 1, "etmask")) return (NETMASK); if (!strcasecmp(atom + 1, "ext-server")) return (NEXT_SERVER); if (!strcasecmp(atom + 1, "ot")) return (TOKEN_NOT); break; case 'o': if (!strcasecmp(atom + 1, "ption")) return (OPTION); if (!strcasecmp(atom + 1, "ne-lease-per-client")) return (ONE_LEASE_PER_CLIENT); break; case 'p': if (!strcasecmp(atom + 1, "repend")) return (PREPEND); if (!strcasecmp(atom + 1, "acket")) return (PACKET); break; case 'r': if (!strcasecmp(atom + 1, "ange")) return (RANGE); if (!strcasecmp(atom + 1, "equest")) return (REQUEST); if (!strcasecmp(atom + 1, "equire")) return (REQUIRE); if (!strcasecmp(atom + 1, "etry")) return (RETRY); if (!strcasecmp(atom + 1, "enew")) return (RENEW); if (!strcasecmp(atom + 1, "ebind")) return (REBIND); if (!strcasecmp(atom + 1, "eboot")) return (REBOOT); if (!strcasecmp(atom + 1, "eject")) return (REJECT); break; case 's': if (!strcasecmp(atom + 1, "earch")) return (SEARCH); if (!strcasecmp(atom + 1, "tarts")) return (STARTS); if (!strcasecmp(atom + 1, "iaddr")) return (SIADDR); if (!strcasecmp(atom + 1, "ubnet")) return (SUBNET); if (!strcasecmp(atom + 1, "hared-network")) return (SHARED_NETWORK); if (!strcasecmp(atom + 1, "erver-name")) return (SERVER_NAME); if (!strcasecmp(atom + 1, "erver-identifier")) return (SERVER_IDENTIFIER); if (!strcasecmp(atom + 1, "elect-timeout")) return (SELECT_TIMEOUT); if (!strcasecmp(atom + 1, "end")) return (SEND); if (!strcasecmp(atom + 1, "cript")) return (SCRIPT); if (!strcasecmp(atom + 1, "upersede")) return (SUPERSEDE); break; case 't': if (!strcasecmp(atom + 1, "imestamp")) return (TIMESTAMP); if (!strcasecmp(atom + 1, "imeout")) return (TIMEOUT); if (!strcasecmp(atom + 1, "oken-ring")) return (TOKEN_RING); break; case 'u': if (!strncasecmp(atom + 1, "se", 2)) { if (!strcasecmp(atom + 3, "r-class")) return (USER_CLASS); if (!strcasecmp(atom + 3, "-host-decl-names")) return (USE_HOST_DECL_NAMES); if (!strcasecmp(atom + 3, "-lease-addr-for-default-route")) return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); break; } if (!strcasecmp(atom + 1, "id")) return (UID); if (!strcasecmp(atom + 1, "nknown-clients")) return (UNKNOWN_CLIENTS); break; case 'v': if (!strcasecmp(atom + 1, "endor-class")) return (VENDOR_CLASS); break; case 'y': if (!strcasecmp(atom + 1, "iaddr")) return (YIADDR); break; } return (dfv); } Index: stable/11/sbin/dhclient/dhclient.c =================================================================== --- stable/11/sbin/dhclient/dhclient.c (revision 332601) +++ stable/11/sbin/dhclient/dhclient.c (revision 332602) @@ -1,2801 +1,2800 @@ /* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */ /* * Copyright 2004 Henning Brauer * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. * * This client was substantially modified and enhanced by Elliot Poger * for use on Linux while he was working on the MosquitoNet project at * Stanford. * * The current version owes much to Elliot's Linux enhancements, but * was substantially reorganized and partially rewritten by Ted Lemon * so as to use the same networking framework that the Internet Software * Consortium DHCP server uses. Much system-specific configuration code * was moved into a shell script so that as support for more operating * systems is added, it will not be necessary to port and maintain * system-specific configuration code to these operating systems - instead, * the shell script can invoke the native tools to accomplish the same * purpose. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "privsep.h" #include #include #include #ifndef _PATH_VAREMPTY #define _PATH_VAREMPTY "/var/empty" #endif #define PERIOD 0x2e #define hyphenchar(c) ((c) == 0x2d) #define bslashchar(c) ((c) == 0x5c) #define periodchar(c) ((c) == PERIOD) #define asterchar(c) ((c) == 0x2a) #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ ((c) >= 0x61 && (c) <= 0x7a)) #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) #define whitechar(c) ((c) == ' ' || (c) == '\t') #define borderchar(c) (alphachar(c) || digitchar(c)) #define middlechar(c) (borderchar(c) || hyphenchar(c)) #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" time_t cur_time; time_t default_lease_time = 43200; /* 12 hours... */ -char *path_dhclient_conf = _PATH_DHCLIENT_CONF; +const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; char *path_dhclient_db = NULL; int log_perror = 1; int privfd; int nullfd = -1; char hostname[_POSIX_HOST_NAME_MAX + 1]; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct in_addr inaddr_any, inaddr_broadcast; char *path_dhclient_pidfile; struct pidfh *pidfile; /* * ASSERT_STATE() does nothing now; it used to be * assert (state_is == state_shouldbe). */ #define ASSERT_STATE(state_is, state_shouldbe) {} /* * We need to check that the expiry, renewal and rebind times are not beyond * the end of time (~2038 when a 32-bit time_t is being used). */ #define TIME_MAX ((((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1) int log_priority; int no_daemon; int unknown_ok = 1; int routefd; struct interface_info *ifi; int findproto(char *, int); struct sockaddr *get_ifa(char *, int); void routehandler(struct protocol *); void usage(void); int check_option(struct client_lease *l, int option); int check_classless_option(unsigned char *data, int len); -int ipv4addrs(char * buf); +int ipv4addrs(const char * buf); int res_hnok(const char *dn); int check_search(const char *srch); -char *option_as_string(unsigned int code, unsigned char *data, int len); +const char *option_as_string(unsigned int code, unsigned char *data, int len); int fork_privchld(int, int); #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) /* Minimum MTU is 68 as per RFC791, p. 24 */ #define MIN_MTU 68 static time_t scripttime; int findproto(char *cp, int n) { struct sockaddr *sa; unsigned i; if (n == 0) return -1; for (i = 1; i; i <<= 1) { if (i & n) { sa = (struct sockaddr *)cp; switch (i) { case RTA_IFA: case RTA_DST: case RTA_GATEWAY: case RTA_NETMASK: if (sa->sa_family == AF_INET) return AF_INET; if (sa->sa_family == AF_INET6) return AF_INET6; break; case RTA_IFP: break; } ADVANCE(cp, sa); } } return (-1); } struct sockaddr * get_ifa(char *cp, int n) { struct sockaddr *sa; unsigned i; if (n == 0) return (NULL); for (i = 1; i; i <<= 1) if (i & n) { sa = (struct sockaddr *)cp; if (i == RTA_IFA) return (sa); ADVANCE(cp, sa); } return (NULL); } struct iaddr defaddr = { .len = 4 }; uint8_t curbssid[6]; static void disassoc(void *arg) { - struct interface_info *ifi = arg; + struct interface_info *_ifi = arg; /* * Clear existing state. */ - if (ifi->client->active != NULL) { + if (_ifi->client->active != NULL) { script_init("EXPIRE", NULL); script_write_params("old_", - ifi->client->active); - if (ifi->client->alias) + _ifi->client->active); + if (_ifi->client->alias) script_write_params("alias_", - ifi->client->alias); + _ifi->client->alias); script_go(); } - ifi->client->state = S_INIT; + _ifi->client->state = S_INIT; } -/* ARGSUSED */ void -routehandler(struct protocol *p) +routehandler(struct protocol *p __unused) { char msg[2048], *addr; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct if_announcemsghdr *ifan; struct ieee80211_join_event *jev; struct client_lease *l; time_t t = time(NULL); - struct sockaddr *sa; + struct sockaddr_in *sa; struct iaddr a; ssize_t n; int linkstat; n = read(routefd, &msg, sizeof(msg)); rtm = (struct rt_msghdr *)msg; if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < (ssize_t)rtm->rtm_msglen || rtm->rtm_version != RTM_VERSION) return; switch (rtm->rtm_type) { case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; if (ifam->ifam_index != ifi->index) break; if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) break; if (scripttime == 0 || t < scripttime + 10) break; - sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs); + sa = (struct sockaddr_in*)get_ifa((char *)(ifam + 1), ifam->ifam_addrs); if (sa == NULL) break; if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) error("king bula sez: len mismatch"); - memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len); + memcpy(a.iabuf, &sa->sin_addr, a.len); if (addr_eq(a, defaddr)) break; for (l = ifi->client->active; l != NULL; l = l->next) if (addr_eq(a, l->address)) break; if (l == NULL) /* added/deleted addr is not the one we set */ break; - addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); + addr = inet_ntoa(sa->sin_addr); if (rtm->rtm_type == RTM_NEWADDR) { /* * XXX: If someone other than us adds our address, * should we assume they are taking over from us, * delete the lease record, and exit without modifying * the interface? */ warning("My address (%s) was re-added", addr); } else { warning("My address (%s) was deleted, dhclient exiting", addr); goto die; } break; case RTM_IFINFO: ifm = (struct if_msghdr *)rtm; if (ifm->ifm_index != ifi->index) break; if ((rtm->rtm_flags & RTF_UP) == 0) { warning("Interface %s is down, dhclient exiting", ifi->name); goto die; } linkstat = interface_link_status(ifi->name); if (linkstat != ifi->linkstat) { debug("%s link state %s -> %s", ifi->name, ifi->linkstat ? "up" : "down", linkstat ? "up" : "down"); ifi->linkstat = linkstat; if (linkstat) state_reboot(ifi); } break; case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *)rtm; if (ifan->ifan_what == IFAN_DEPARTURE && ifan->ifan_index == ifi->index) { warning("Interface %s is gone, dhclient exiting", ifi->name); goto die; } break; case RTM_IEEE80211: ifan = (struct if_announcemsghdr *)rtm; if (ifan->ifan_index != ifi->index) break; switch (ifan->ifan_what) { case RTM_IEEE80211_ASSOC: case RTM_IEEE80211_REASSOC: /* * Use assoc/reassoc event to kick state machine * in case we roam. Otherwise fall back to the * normal state machine just like a wired network. */ jev = (struct ieee80211_join_event *) &ifan[1]; if (memcmp(curbssid, jev->iev_addr, 6)) { disassoc(ifi); state_reboot(ifi); } memcpy(curbssid, jev->iev_addr, 6); break; } break; default: break; } return; die: script_init("FAIL", NULL); if (ifi->client->alias) script_write_params("alias_", ifi->client->alias); script_go(); if (pidfile != NULL) pidfile_remove(pidfile); exit(1); } int main(int argc, char *argv[]) { extern char *__progname; int ch, fd, quiet = 0, i = 0; int pipe_fd[2]; int immediate_daemon = 0; struct passwd *pw; pid_t otherpid; cap_rights_t rights; /* Initially, log errors to stderr as well as to syslogd. */ openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); setlogmask(LOG_UPTO(LOG_DEBUG)); while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1) switch (ch) { case 'b': immediate_daemon = 1; break; case 'c': path_dhclient_conf = optarg; break; case 'd': no_daemon = 1; break; case 'l': path_dhclient_db = optarg; break; case 'p': path_dhclient_pidfile = optarg; break; case 'q': quiet = 1; break; case 'u': unknown_ok = 0; break; default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); if (path_dhclient_pidfile == NULL) { asprintf(&path_dhclient_pidfile, "%sdhclient.%s.pid", _PATH_VARRUN, *argv); if (path_dhclient_pidfile == NULL) error("asprintf"); } pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid); if (pidfile == NULL) { if (errno == EEXIST) error("dhclient already running, pid: %d.", otherpid); if (errno == EAGAIN) error("dhclient already running."); warning("Cannot open or create pidfile: %m"); } if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL) error("calloc"); if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ) error("Interface name too long"); if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s", _PATH_DHCLIENT_DB, ifi->name) == -1) error("asprintf"); if (quiet) log_perror = 0; tzset(); time(&cur_time); inaddr_broadcast.s_addr = INADDR_BROADCAST; inaddr_any.s_addr = INADDR_ANY; read_client_conf(); /* The next bit is potentially very time-consuming, so write out the pidfile right away. We will write it out again with the correct pid after daemonizing. */ if (pidfile != NULL) pidfile_write(pidfile); if (!interface_link_status(ifi->name)) { fprintf(stderr, "%s: no link ...", ifi->name); fflush(stderr); sleep(1); while (!interface_link_status(ifi->name)) { fprintf(stderr, "."); fflush(stderr); if (++i > 10) { fprintf(stderr, " giving up\n"); exit(1); } sleep(1); } fprintf(stderr, " got link\n"); } ifi->linkstat = 1; if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) error("cannot open %s: %m", _PATH_DEVNULL); if ((pw = getpwnam("_dhcp")) == NULL) { warning("no such user: _dhcp, falling back to \"nobody\""); if ((pw = getpwnam("nobody")) == NULL) error("no such user: nobody"); } /* * Obtain hostname before entering capability mode - it won't be * possible then, as reading kern.hostname is not permitted. */ if (gethostname(hostname, sizeof(hostname)) < 0) hostname[0] = '\0'; priv_script_init("PREINIT", NULL); if (ifi->client->alias) priv_script_write_params("alias_", ifi->client->alias); priv_script_go(); /* set up the interface */ discover_interfaces(ifi); if (pipe(pipe_fd) == -1) error("pipe"); fork_privchld(pipe_fd[0], pipe_fd[1]); close(ifi->ufdesc); ifi->ufdesc = -1; close(ifi->wfdesc); ifi->wfdesc = -1; close(pipe_fd[0]); privfd = pipe_fd[1]; cap_rights_init(&rights, CAP_READ, CAP_WRITE); if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS) error("can't limit private descriptor: %m"); if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); read_client_leases(); rewrite_client_leases(); close(fd); if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) add_protocol("AF_ROUTE", routefd, routehandler, ifi); if (shutdown(routefd, SHUT_WR) < 0) error("can't shutdown route socket: %m"); cap_rights_init(&rights, CAP_EVENT, CAP_READ); if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS) error("can't limit route socket: %m"); if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); if (chdir("/") == -1) error("chdir(\"/\")"); if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) error("can't drop privileges: %m"); endpwent(); setproctitle("%s", ifi->name); if (cap_enter() < 0 && errno != ENOSYS) error("can't enter capability mode: %m"); if (immediate_daemon) go_daemon(); ifi->client->state = S_INIT; state_reboot(ifi); bootp_packet_handler = do_packet; dispatch(); /* not reached */ return (0); } void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-bdqu] ", __progname); fprintf(stderr, "[-c conffile] [-l leasefile] interface\n"); exit(1); } /* * Individual States: * * Each routine is called from the dhclient_state_machine() in one of * these conditions: * -> entering INIT state * -> recvpacket_flag == 0: timeout in this state * -> otherwise: received a packet in this state * * Return conditions as handled by dhclient_state_machine(): * Returns 1, sendpacket_flag = 1: send packet, reset timer. * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). * Returns 0: finish the nap which was interrupted for no good reason. * * Several per-interface variables are used to keep track of the process: * active_lease: the lease that is being used on the interface * (null pointer if not configured yet). * offered_leases: leases corresponding to DHCPOFFER messages that have * been sent to us by DHCP servers. * acked_leases: leases corresponding to DHCPACK messages that have been * sent to us by DHCP servers. * sendpacket: DHCP packet we're trying to send. * destination: IP address to send sendpacket to * In addition, there are several relevant per-lease variables. * T1_expiry, T2_expiry, lease_expiry: lease milestones * In the active lease, these control the process of renewing the lease; * In leases on the acked_leases list, this simply determines when we * can no longer legitimately use the lease. */ void state_reboot(void *ipp) { struct interface_info *ip = ipp; /* If we don't remember an active lease, go straight to INIT. */ if (!ip->client->active || ip->client->active->is_bootp) { state_init(ip); return; } /* We are in the rebooting state. */ ip->client->state = S_REBOOTING; /* make_request doesn't initialize xid because it normally comes from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, so pick an xid now. */ ip->client->xid = arc4random(); /* Make a DHCPREQUEST packet, and set appropriate per-interface flags. */ make_request(ip, ip->client->active); ip->client->destination = iaddr_broadcast; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Zap the medium list... */ ip->client->medium = NULL; /* Send out the first DHCPREQUEST packet. */ send_request(ip); } /* * Called when a lease has completely expired and we've * been unable to renew it. */ void state_init(void *ipp) { struct interface_info *ip = ipp; ASSERT_STATE(state, S_INIT); /* Make a DHCPDISCOVER packet, and set appropriate per-interface flags. */ make_discover(ip, ip->client->active); ip->client->xid = ip->client->packet.xid; ip->client->destination = iaddr_broadcast; ip->client->state = S_SELECTING; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Add an immediate timeout to cause the first DHCPDISCOVER packet to go out. */ send_discover(ip); } /* * state_selecting is called when one or more DHCPOFFER packets * have been received and a configurable period of time has passed. */ void state_selecting(void *ipp) { struct interface_info *ip = ipp; struct client_lease *lp, *next, *picked; ASSERT_STATE(state, S_SELECTING); /* Cancel state_selecting and send_discover timeouts, since either one could have got us here. */ cancel_timeout(state_selecting, ip); cancel_timeout(send_discover, ip); /* We have received one or more DHCPOFFER packets. Currently, the only criterion by which we judge leases is whether or not we get a response when we arp for them. */ picked = NULL; for (lp = ip->client->offered_leases; lp; lp = next) { next = lp->next; /* Check to see if we got an ARPREPLY for the address in this particular lease. */ if (!picked) { script_init("ARPCHECK", lp->medium); script_write_params("check_", lp); /* If the ARPCHECK code detects another machine using the offered address, it exits nonzero. We need to send a DHCPDECLINE and toss the lease. */ if (script_go()) { make_decline(ip, lp); send_decline(ip); goto freeit; } picked = lp; picked->next = NULL; } else { freeit: free_client_lease(lp); } } ip->client->offered_leases = NULL; /* If we just tossed all the leases we were offered, go back to square one. */ if (!picked) { ip->client->state = S_INIT; state_init(ip); return; } /* If it was a BOOTREPLY, we can just take the address right now. */ if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { ip->client->new = picked; /* Make up some lease expiry times XXX these should be configurable. */ ip->client->new->expiry = cur_time + 12000; ip->client->new->renewal += cur_time + 8000; ip->client->new->rebind += cur_time + 10000; ip->client->state = S_REQUESTING; /* Bind to the address we received. */ bind_lease(ip); return; } /* Go to the REQUESTING state. */ ip->client->destination = iaddr_broadcast; ip->client->state = S_REQUESTING; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; /* Make a DHCPREQUEST packet from the lease we picked. */ make_request(ip, picked); ip->client->xid = ip->client->packet.xid; /* Toss the lease we picked - we'll get it back in a DHCPACK. */ free_client_lease(picked); /* Add an immediate timeout to send the first DHCPREQUEST packet. */ send_request(ip); } /* state_requesting is called when we receive a DHCPACK message after having sent out one or more DHCPREQUEST packets. */ void dhcpack(struct packet *packet) { struct interface_info *ip = packet->interface; struct client_lease *lease; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; if (ip->client->state != S_REBOOTING && ip->client->state != S_REQUESTING && ip->client->state != S_RENEWING && ip->client->state != S_REBINDING) return; note("DHCPACK from %s", piaddr(packet->client_addr)); lease = packet_to_lease(packet); if (!lease) { note("packet_to_lease failed."); return; } ip->client->new = lease; /* Stop resending DHCPREQUEST. */ cancel_timeout(send_request, ip); /* Figure out the lease time. */ if (ip->client->config->default_actions[DHO_DHCP_LEASE_TIME] == ACTION_SUPERSEDE) ip->client->new->expiry = getULong( ip->client->config->defaults[DHO_DHCP_LEASE_TIME].data); else if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) ip->client->new->expiry = getULong( ip->client->new->options[DHO_DHCP_LEASE_TIME].data); else ip->client->new->expiry = default_lease_time; /* A number that looks negative here is really just very large, because the lease expiry offset is unsigned. Also make sure that the addition of cur_time below does not overflow (a 32 bit) time_t. */ if (ip->client->new->expiry < 0 || ip->client->new->expiry > TIME_MAX - cur_time) ip->client->new->expiry = TIME_MAX - cur_time; /* XXX should be fixed by resetting the client state */ if (ip->client->new->expiry < 60) ip->client->new->expiry = 60; /* Unless overridden in the config, take the server-provided renewal * time if there is one. Otherwise figure it out according to the spec. * Also make sure the renewal time does not exceed the expiry time. */ if (ip->client->config->default_actions[DHO_DHCP_RENEWAL_TIME] == ACTION_SUPERSEDE) ip->client->new->renewal = getULong( ip->client->config->defaults[DHO_DHCP_RENEWAL_TIME].data); else if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) ip->client->new->renewal = getULong( ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); else ip->client->new->renewal = ip->client->new->expiry / 2; if (ip->client->new->renewal < 0 || ip->client->new->renewal > ip->client->new->expiry / 2) ip->client->new->renewal = ip->client->new->expiry / 2; /* Same deal with the rebind time. */ if (ip->client->config->default_actions[DHO_DHCP_REBINDING_TIME] == ACTION_SUPERSEDE) ip->client->new->rebind = getULong( ip->client->config->defaults[DHO_DHCP_REBINDING_TIME].data); else if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) ip->client->new->rebind = getULong( ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); else ip->client->new->rebind = ip->client->new->renewal / 4 * 7; if (ip->client->new->rebind < 0 || ip->client->new->rebind > ip->client->new->renewal / 4 * 7) ip->client->new->rebind = ip->client->new->renewal / 4 * 7; /* Convert the time offsets into seconds-since-the-epoch */ ip->client->new->expiry += cur_time; ip->client->new->renewal += cur_time; ip->client->new->rebind += cur_time; bind_lease(ip); } void bind_lease(struct interface_info *ip) { struct option_data *opt; /* Remember the medium. */ ip->client->new->medium = ip->client->medium; opt = &ip->client->new->options[DHO_INTERFACE_MTU]; if (opt->len == sizeof(u_int16_t)) { u_int16_t mtu = be16dec(opt->data); if (mtu < MIN_MTU) warning("mtu size %u < %d: ignored", (unsigned)mtu, MIN_MTU); else interface_set_mtu_unpriv(privfd, mtu); } /* Write out the new lease. */ write_client_lease(ip, ip->client->new, 0); /* Run the client script with the new parameters. */ script_init((ip->client->state == S_REQUESTING ? "BOUND" : (ip->client->state == S_RENEWING ? "RENEW" : (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), ip->client->new->medium); if (ip->client->active && ip->client->state != S_REBOOTING) script_write_params("old_", ip->client->active); script_write_params("new_", ip->client->new); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); /* Replace the old active lease with the new one. */ if (ip->client->active) free_client_lease(ip->client->active); ip->client->active = ip->client->new; ip->client->new = NULL; /* Set up a timeout to start the renewal process. */ add_timeout(ip->client->active->renewal, state_bound, ip); note("bound to %s -- renewal in %d seconds.", piaddr(ip->client->active->address), (int)(ip->client->active->renewal - cur_time)); ip->client->state = S_BOUND; reinitialize_interfaces(); go_daemon(); } /* * state_bound is called when we've successfully bound to a particular * lease, but the renewal time on that lease has expired. We are * expected to unicast a DHCPREQUEST to the server that gave us our * original lease. */ void state_bound(void *ipp) { struct interface_info *ip = ipp; ASSERT_STATE(state, S_BOUND); /* T1 has expired. */ make_request(ip, ip->client->active); ip->client->xid = ip->client->packet.xid; if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { memcpy(ip->client->destination.iabuf, ip->client->active-> options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); ip->client->destination.len = 4; } else ip->client->destination = iaddr_broadcast; ip->client->first_sending = cur_time; ip->client->interval = ip->client->config->initial_interval; ip->client->state = S_RENEWING; /* Send the first packet immediately. */ send_request(ip); } void bootp(struct packet *packet) { struct iaddrlist *ap; if (packet->raw->op != BOOTREPLY) return; /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet->interface->client->config->reject_list; ap; ap = ap->next) { if (addr_eq(packet->client_addr, ap->addr)) { note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); return; } } dhcpoffer(packet); } void dhcp(struct packet *packet) { struct iaddrlist *ap; void (*handler)(struct packet *); - char *type; + const char *type; switch (packet->packet_type) { case DHCPOFFER: handler = dhcpoffer; type = "DHCPOFFER"; break; case DHCPNAK: handler = dhcpnak; type = "DHCPNACK"; break; case DHCPACK: handler = dhcpack; type = "DHCPACK"; break; default: return; } /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet->interface->client->config->reject_list; ap; ap = ap->next) { if (addr_eq(packet->client_addr, ap->addr)) { note("%s from %s rejected.", type, piaddr(ap->addr)); return; } } (*handler)(packet); } void dhcpoffer(struct packet *packet) { struct interface_info *ip = packet->interface; struct client_lease *lease, *lp; int i; int arp_timeout_needed, stop_selecting; - char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? + const char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" : "BOOTREPLY"; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (ip->client->state != S_SELECTING || packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; note("%s from %s", name, piaddr(packet->client_addr)); /* If this lease doesn't supply the minimum required parameters, blow it off. */ for (i = 0; ip->client->config->required_options[i]; i++) { if (!packet->options[ip->client->config-> required_options[i]].len) { note("%s isn't satisfactory.", name); return; } } /* If we've already seen this lease, don't record it again. */ for (lease = ip->client->offered_leases; lease; lease = lease->next) { if (lease->address.len == sizeof(packet->raw->yiaddr) && !memcmp(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len)) { debug("%s already seen.", name); return; } } lease = packet_to_lease(packet); if (!lease) { note("packet_to_lease failed."); return; } /* If this lease was acquired through a BOOTREPLY, record that fact. */ if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) lease->is_bootp = 1; /* Record the medium under which this lease was offered. */ lease->medium = ip->client->medium; /* Send out an ARP Request for the offered IP address. */ script_init("ARPSEND", lease->medium); script_write_params("check_", lease); /* If the script can't send an ARP request without waiting, we'll be waiting when we do the ARPCHECK, so don't wait now. */ if (script_go()) arp_timeout_needed = 0; else arp_timeout_needed = 2; /* Figure out when we're supposed to stop selecting. */ stop_selecting = ip->client->first_sending + ip->client->config->select_interval; /* If this is the lease we asked for, put it at the head of the list, and don't mess with the arp request timeout. */ if (lease->address.len == ip->client->requested_address.len && !memcmp(lease->address.iabuf, ip->client->requested_address.iabuf, ip->client->requested_address.len)) { lease->next = ip->client->offered_leases; ip->client->offered_leases = lease; } else { /* If we already have an offer, and arping for this offer would take us past the selection timeout, then don't extend the timeout - just hope for the best. */ if (ip->client->offered_leases && (cur_time + arp_timeout_needed) > stop_selecting) arp_timeout_needed = 0; /* Put the lease at the end of the list. */ lease->next = NULL; if (!ip->client->offered_leases) ip->client->offered_leases = lease; else { for (lp = ip->client->offered_leases; lp->next; lp = lp->next) ; /* nothing */ lp->next = lease; } } /* If we're supposed to stop selecting before we've had time to wait for the ARPREPLY, add some delay to wait for the ARPREPLY. */ if (stop_selecting - cur_time < arp_timeout_needed) stop_selecting = cur_time + arp_timeout_needed; /* If the selecting interval has expired, go immediately to state_selecting(). Otherwise, time out into state_selecting at the select interval. */ if (stop_selecting <= 0) state_selecting(ip); else { add_timeout(stop_selecting, state_selecting, ip); cancel_timeout(send_discover, ip); } } /* Allocate a client_lease structure and initialize it from the parameters in the specified packet. */ struct client_lease * packet_to_lease(struct packet *packet) { struct client_lease *lease; int i; lease = malloc(sizeof(struct client_lease)); if (!lease) { warning("dhcpoffer: no memory to record lease."); return (NULL); } memset(lease, 0, sizeof(*lease)); /* Copy the lease options. */ for (i = 0; i < 256; i++) { if (packet->options[i].len) { lease->options[i].data = malloc(packet->options[i].len + 1); if (!lease->options[i].data) { warning("dhcpoffer: no memory for option %d", i); free_client_lease(lease); return (NULL); } else { memcpy(lease->options[i].data, packet->options[i].data, packet->options[i].len); lease->options[i].len = packet->options[i].len; lease->options[i].data[lease->options[i].len] = 0; } if (!check_option(lease,i)) { /* ignore a bogus lease offer */ warning("Invalid lease option - ignoring offer"); free_client_lease(lease); return (NULL); } } } lease->address.len = sizeof(packet->raw->yiaddr); memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); lease->nextserver.len = sizeof(packet->raw->siaddr); memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len); /* If the server name was filled out, copy it. Do not attempt to validate the server name as a host name. RFC 2131 merely states that sname is NUL-terminated (which do do not assume) and that it is the server's host name. Since the ISC client and server allow arbitrary characters, we do as well. */ if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && packet->raw->sname[0]) { lease->server_name = malloc(DHCP_SNAME_LEN + 1); if (!lease->server_name) { warning("dhcpoffer: no memory for server name."); free_client_lease(lease); return (NULL); } memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); lease->server_name[DHCP_SNAME_LEN]='\0'; } /* Ditto for the filename. */ if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && packet->raw->file[0]) { /* Don't count on the NUL terminator. */ lease->filename = malloc(DHCP_FILE_LEN + 1); if (!lease->filename) { warning("dhcpoffer: no memory for filename."); free_client_lease(lease); return (NULL); } memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); lease->filename[DHCP_FILE_LEN]='\0'; } return lease; } void dhcpnak(struct packet *packet) { struct interface_info *ip = packet->interface; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet->interface->client->xid != packet->raw->xid || (packet->interface->hw_address.hlen != packet->raw->hlen) || (memcmp(packet->interface->hw_address.haddr, packet->raw->chaddr, packet->raw->hlen))) return; if (ip->client->state != S_REBOOTING && ip->client->state != S_REQUESTING && ip->client->state != S_RENEWING && ip->client->state != S_REBINDING) return; note("DHCPNAK from %s", piaddr(packet->client_addr)); if (!ip->client->active) { note("DHCPNAK with no active lease.\n"); return; } free_client_lease(ip->client->active); ip->client->active = NULL; /* Stop sending DHCPREQUEST packets... */ cancel_timeout(send_request, ip); ip->client->state = S_INIT; state_init(ip); } /* Send out a DHCPDISCOVER packet, and set a timeout to send out another one after the right interval has expired. If we don't get an offer by the time we reach the panic interval, call the panic function. */ void send_discover(void *ipp) { struct interface_info *ip = ipp; int interval, increase = 1; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip->client->first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ if (interval > ip->client->config->timeout) { state_panic(ip); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ if (!ip->client->offered_leases && ip->client->config->media) { int fail = 0; again: if (ip->client->medium) { ip->client->medium = ip->client->medium->next; increase = 0; } if (!ip->client->medium) { if (fail) error("No valid media types for %s!", ip->name); ip->client->medium = ip->client->config->media; increase = 1; } note("Trying medium \"%s\" %d", ip->client->medium->string, increase); script_init("MEDIUM", ip->client->medium); if (script_go()) goto again; } /* * If we're supposed to increase the interval, do so. If it's * currently zero (i.e., we haven't sent any packets yet), set * it to one; otherwise, add to it a random number between zero * and two times itself. On average, this means that it will * double with every transmission. */ if (increase) { if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; else { ip->client->interval += (arc4random() >> 2) % (2 * ip->client->interval); } /* Don't backoff past cutoff. */ if (ip->client->interval > ip->client->config->backoff_cutoff) ip->client->interval = ((ip->client->config->backoff_cutoff / 2) + ((arc4random() >> 2) % ip->client->config->backoff_cutoff)); } else if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ if (cur_time + ip->client->interval > ip->client->first_sending + ip->client->config->timeout) ip->client->interval = (ip->client->first_sending + ip->client->config->timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) ip->client->packet.secs = htons(interval); else ip->client->packet.secs = htons(65535); ip->client->secs = ip->client->packet.secs; note("DHCPDISCOVER on %s to %s port %d interval %d", ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, (int)ip->client->interval); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } /* * state_panic gets called if we haven't received any offers in a preset * amount of time. When this happens, we try to use existing leases * that haven't yet expired, and failing that, we call the client script * and hope it can do something. */ void state_panic(void *ipp) { struct interface_info *ip = ipp; struct client_lease *loop = ip->client->active; struct client_lease *lp; note("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ if (!ip->client->active && ip->client->leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ while (ip->client->active) { if (ip->client->active->expiry > cur_time) { note("Trying recorded lease %s", piaddr(ip->client->active->address)); /* Run the client script with the existing parameters. */ script_init("TIMEOUT", ip->client->active->medium); script_write_params("new_", ip->client->active); if (ip->client->alias) script_write_params("alias_", ip->client->alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ if (!script_go()) { if (cur_time < ip->client->active->renewal) { ip->client->state = S_BOUND; note("bound: renewal in %d seconds.", (int)(ip->client->active->renewal - cur_time)); add_timeout( ip->client->active->renewal, state_bound, ip); } else { ip->client->state = S_BOUND; note("bound: immediate renewal."); state_bound(ip); } reinitialize_interfaces(); go_daemon(); return; } } /* If there are no other leases, give up. */ if (!ip->client->leases) { ip->client->leases = ip->client->active; ip->client->active = NULL; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ for (lp = ip->client->leases; lp->next; lp = lp->next) ; lp->next = ip->client->active; if (lp->next) lp->next->next = NULL; ip->client->active = ip->client->leases; ip->client->leases = ip->client->leases->next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ if (ip->client->active == loop) break; else if (!loop) loop = ip->client->active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ note("No working leases in persistent database - sleeping.\n"); script_init("FAIL", NULL); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); ip->client->state = S_INIT; add_timeout(cur_time + ip->client->config->retry_interval, state_init, ip); go_daemon(); } void send_request(void *ipp) { struct interface_info *ip = ipp; struct in_addr from, to; int interval; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip->client->first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can DISCOVER an address... */ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it means either that we're on a network with no DHCP server, or that our server is down. In the latter case, assuming that there is a backup DHCP server, DHCPDISCOVER will get us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ if ((ip->client->state == S_REBOOTING || ip->client->state == S_REQUESTING) && interval > ip->client->config->reboot_timeout) { cancel: ip->client->state = S_INIT; cancel_timeout(send_request, ip); state_init(ip); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ if (ip->client->state == S_REBOOTING && !ip->client->medium && ip->client->active->medium ) { script_init("MEDIUM", ip->client->active->medium); /* If the medium we chose won't fly, go to INIT state. */ if (script_go()) goto cancel; /* Record the medium. */ ip->client->medium = ip->client->active->medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ if (ip->client->state != S_REQUESTING && cur_time > ip->client->active->expiry) { /* Run the client script with the new parameters. */ script_init("EXPIRE", NULL); script_write_params("old_", ip->client->active); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); /* Now do a preinit on the interface so that we can discover a new address. */ script_init("PREINIT", NULL); if (ip->client->alias) script_write_params("alias_", ip->client->alias); script_go(); ip->client->state = S_INIT; state_init(ip); return; } /* Do the exponential backoff... */ if (!ip->client->interval) ip->client->interval = ip->client->config->initial_interval; else ip->client->interval += ((arc4random() >> 2) % (2 * ip->client->interval)); /* Don't backoff past cutoff. */ if (ip->client->interval > ip->client->config->backoff_cutoff) ip->client->interval = ((ip->client->config->backoff_cutoff / 2) + ((arc4random() >> 2) % ip->client->interval)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ if (ip->client->state != S_REQUESTING && cur_time + ip->client->interval > ip->client->active->expiry) ip->client->interval = ip->client->active->expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING || cur_time > ip->client->active->rebind) to.s_addr = INADDR_BROADCAST; else memcpy(&to.s_addr, ip->client->destination.iabuf, sizeof(to.s_addr)); if (ip->client->state != S_REQUESTING && ip->client->state != S_REBOOTING) memcpy(&from, ip->client->active->address.iabuf, sizeof(from)); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ if (ip->client->state == S_REQUESTING) ip->client->packet.secs = ip->client->secs; else { if (interval < 65536) ip->client->packet.secs = htons(interval); else ip->client->packet.secs = htons(65535); } note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), REMOTE_PORT); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); } void send_decline(void *ipp) { struct interface_info *ip = ipp; note("DHCPDECLINE on %s to %s port %d", ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ send_packet_unpriv(privfd, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); } void make_discover(struct interface_info *ip, struct client_lease *lease) { unsigned char discover = DHCPDISCOVER; struct tree_cache *options[256]; struct tree_cache option_elements[256]; int i; memset(option_elements, 0, sizeof(option_elements)); memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &option_elements[i]; options[i]->value = &discover; options[i]->len = sizeof(discover); options[i]->buf_size = sizeof(discover); options[i]->timeout = 0xFFFFFFFF; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options[i] = &option_elements[i]; options[i]->value = ip->client->config->requested_options; options[i]->len = ip->client->config->requested_option_count; options[i]->buf_size = ip->client->config->requested_option_count; options[i]->timeout = 0xFFFFFFFF; /* If we had an address, try to get it again. */ if (lease) { ip->client->requested_address = lease->address; i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &option_elements[i]; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; } else ip->client->requested_address.len = 0; /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) if (!options[i] && ip->client->config->send_options[i].data) { options[i] = &option_elements[i]; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* send host name if not set via config file. */ if (!options[DHO_HOST_NAME]) { if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) len = posDot - hostname; else len = strlen(hostname); options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; options[DHO_HOST_NAME]->value = hostname; options[DHO_HOST_NAME]->len = len; options[DHO_HOST_NAME]->buf_size = len; options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; } } /* set unique client identifier */ char client_ident[sizeof(ip->hw_address.haddr) + 1]; if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = arc4random(); ip->client->packet.secs = 0; /* filled in by send_discover. */ ip->client->packet.flags = 0; memset(&(ip->client->packet.ciaddr), 0, sizeof(ip->client->packet.ciaddr)); memset(&(ip->client->packet.yiaddr), 0, sizeof(ip->client->packet.yiaddr)); memset(&(ip->client->packet.siaddr), 0, sizeof(ip->client->packet.siaddr)); memset(&(ip->client->packet.giaddr), 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void make_request(struct interface_info *ip, struct client_lease * lease) { unsigned char request = DHCPREQUEST; struct tree_cache *options[256]; struct tree_cache option_elements[256]; int i; memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &option_elements[i]; options[i]->value = &request; options[i]->len = sizeof(request); options[i]->buf_size = sizeof(request); options[i]->timeout = 0xFFFFFFFF; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options[i] = &option_elements[i]; options[i]->value = ip->client->config->requested_options; options[i]->len = ip->client->config->requested_option_count; options[i]->buf_size = ip->client->config->requested_option_count; options[i]->timeout = 0xFFFFFFFF; /* If we are requesting an address that hasn't yet been assigned to us, use the DHCP Requested Address option. */ if (ip->client->state == S_REQUESTING) { /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options[i] = &option_elements[i]; options[i]->value = lease->options[i].data; options[i]->len = lease->options[i].len; options[i]->buf_size = lease->options[i].len; options[i]->timeout = 0xFFFFFFFF; } if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING) { ip->client->requested_address = lease->address; i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &option_elements[i]; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; } else ip->client->requested_address.len = 0; /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) if (!options[i] && ip->client->config->send_options[i].data) { options[i] = &option_elements[i]; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* send host name if not set via config file. */ if (!options[DHO_HOST_NAME]) { if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) len = posDot - hostname; else len = strlen(hostname); options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; options[DHO_HOST_NAME]->value = hostname; options[DHO_HOST_NAME]->len = len; options[DHO_HOST_NAME]->buf_size = len; options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; } } /* set unique client identifier */ char client_ident[sizeof(struct hardware)]; if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = ip->client->xid; ip->client->packet.secs = 0; /* Filled in by send_request. */ /* If we own the address we're requesting, put it in ciaddr; otherwise set ciaddr to zero. */ if (ip->client->state == S_BOUND || ip->client->state == S_RENEWING || ip->client->state == S_REBINDING) { memcpy(&ip->client->packet.ciaddr, lease->address.iabuf, lease->address.len); ip->client->packet.flags = 0; } else { memset(&ip->client->packet.ciaddr, 0, sizeof(ip->client->packet.ciaddr)); ip->client->packet.flags = 0; } memset(&ip->client->packet.yiaddr, 0, sizeof(ip->client->packet.yiaddr)); memset(&ip->client->packet.siaddr, 0, sizeof(ip->client->packet.siaddr)); memset(&ip->client->packet.giaddr, 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void make_decline(struct interface_info *ip, struct client_lease *lease) { struct tree_cache *options[256], message_type_tree; struct tree_cache requested_address_tree; struct tree_cache server_id_tree, client_id_tree; unsigned char decline = DHCPDECLINE; int i; memset(options, 0, sizeof(options)); memset(&ip->client->packet, 0, sizeof(ip->client->packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ i = DHO_DHCP_MESSAGE_TYPE; options[i] = &message_type_tree; options[i]->value = &decline; options[i]->len = sizeof(decline); options[i]->buf_size = sizeof(decline); options[i]->timeout = 0xFFFFFFFF; /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options[i] = &server_id_tree; options[i]->value = lease->options[i].data; options[i]->len = lease->options[i].len; options[i]->buf_size = lease->options[i].len; options[i]->timeout = 0xFFFFFFFF; /* Send back the address we're declining. */ i = DHO_DHCP_REQUESTED_ADDRESS; options[i] = &requested_address_tree; options[i]->value = lease->address.iabuf; options[i]->len = lease->address.len; options[i]->buf_size = lease->address.len; options[i]->timeout = 0xFFFFFFFF; /* Send the uid if the user supplied one. */ i = DHO_DHCP_CLIENT_IDENTIFIER; if (ip->client->config->send_options[i].len) { options[i] = &client_id_tree; options[i]->value = ip->client->config->send_options[i].data; options[i]->len = ip->client->config->send_options[i].len; options[i]->buf_size = ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } /* Set up the option buffer... */ ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options, 0, 0, 0, NULL, 0); if (ip->client->packet_length < BOOTP_MIN_LEN) ip->client->packet_length = BOOTP_MIN_LEN; ip->client->packet.op = BOOTREQUEST; ip->client->packet.htype = ip->hw_address.htype; ip->client->packet.hlen = ip->hw_address.hlen; ip->client->packet.hops = 0; ip->client->packet.xid = ip->client->xid; ip->client->packet.secs = 0; /* Filled in by send_request. */ ip->client->packet.flags = 0; /* ciaddr must always be zero. */ memset(&ip->client->packet.ciaddr, 0, sizeof(ip->client->packet.ciaddr)); memset(&ip->client->packet.yiaddr, 0, sizeof(ip->client->packet.yiaddr)); memset(&ip->client->packet.siaddr, 0, sizeof(ip->client->packet.siaddr)); memset(&ip->client->packet.giaddr, 0, sizeof(ip->client->packet.giaddr)); memcpy(ip->client->packet.chaddr, ip->hw_address.haddr, ip->hw_address.hlen); } void free_client_lease(struct client_lease *lease) { int i; if (lease->server_name) free(lease->server_name); if (lease->filename) free(lease->filename); for (i = 0; i < 256; i++) { if (lease->options[i].len) free(lease->options[i].data); } free(lease); } FILE *leaseFile; void rewrite_client_leases(void) { struct client_lease *lp; cap_rights_t rights; if (!leaseFile) { leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && errno != ENOSYS) { error("can't limit lease descriptor: %m"); } if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) { error("can't limit lease descriptor fcntls: %m"); } } else { fflush(leaseFile); rewind(leaseFile); } for (lp = ifi->client->leases; lp; lp = lp->next) write_client_lease(ifi, lp, 1); if (ifi->client->active) write_client_lease(ifi, ifi->client->active, 1); fflush(leaseFile); ftruncate(fileno(leaseFile), ftello(leaseFile)); fsync(fileno(leaseFile)); } void write_client_lease(struct interface_info *ip, struct client_lease *lease, int rewrite) { static int leases_written; struct tm *t; int i; if (!rewrite) { if (leases_written++ > 20) { rewrite_client_leases(); leases_written = 0; } } /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease->is_static) return; if (!leaseFile) { /* XXX */ leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); } fprintf(leaseFile, "lease {\n"); if (lease->is_bootp) fprintf(leaseFile, " bootp;\n"); fprintf(leaseFile, " interface \"%s\";\n", ip->name); fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); if (lease->nextserver.len == sizeof(inaddr_any) && 0 != memcmp(lease->nextserver.iabuf, &inaddr_any, sizeof(inaddr_any))) fprintf(leaseFile, " next-server %s;\n", piaddr(lease->nextserver)); if (lease->filename) fprintf(leaseFile, " filename \"%s\";\n", lease->filename); if (lease->server_name) fprintf(leaseFile, " server-name \"%s\";\n", lease->server_name); if (lease->medium) fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); for (i = 0; i < 256; i++) if (lease->options[i].len) fprintf(leaseFile, " option %s %s;\n", dhcp_options[i].name, pretty_print_option(i, lease->options[i].data, lease->options[i].len, 1, 1)); t = gmtime(&lease->renewal); fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); t = gmtime(&lease->rebind); fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); t = gmtime(&lease->expiry); fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); fprintf(leaseFile, "}\n"); fflush(leaseFile); } void -script_init(char *reason, struct string_list *medium) +script_init(const char *reason, struct string_list *medium) { size_t len, mediumlen = 0; struct imsg_hdr hdr; struct buf *buf; int errs; if (medium != NULL && medium->string != NULL) mediumlen = strlen(medium->string); hdr.code = IMSG_SCRIPT_INIT; hdr.len = sizeof(struct imsg_hdr) + sizeof(size_t) + mediumlen + sizeof(size_t) + strlen(reason); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); errs = 0; errs += buf_add(buf, &hdr, sizeof(hdr)); errs += buf_add(buf, &mediumlen, sizeof(mediumlen)); if (mediumlen > 0) errs += buf_add(buf, medium->string, mediumlen); len = strlen(reason); errs += buf_add(buf, &len, sizeof(len)); errs += buf_add(buf, reason, len); if (errs) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); } void -priv_script_init(char *reason, char *medium) +priv_script_init(const char *reason, char *medium) { struct interface_info *ip = ifi; if (ip) { ip->client->scriptEnvsize = 100; if (ip->client->scriptEnv == NULL) ip->client->scriptEnv = malloc(ip->client->scriptEnvsize * sizeof(char *)); if (ip->client->scriptEnv == NULL) error("script_init: no memory for environment"); ip->client->scriptEnv[0] = strdup(CLIENT_PATH); if (ip->client->scriptEnv[0] == NULL) error("script_init: no memory for environment"); ip->client->scriptEnv[1] = NULL; script_set_env(ip->client, "", "interface", ip->name); if (medium) script_set_env(ip->client, "", "medium", medium); script_set_env(ip->client, "", "reason", reason); } } void -priv_script_write_params(char *prefix, struct client_lease *lease) +priv_script_write_params(const char *prefix, struct client_lease *lease) { struct interface_info *ip = ifi; u_int8_t dbuf[1500], *dp = NULL; int i; size_t len; char tbuf[128]; script_set_env(ip->client, prefix, "ip_address", piaddr(lease->address)); if (ip->client->config->default_actions[DHO_SUBNET_MASK] == ACTION_SUPERSEDE) { dp = ip->client->config->defaults[DHO_SUBNET_MASK].data; len = ip->client->config->defaults[DHO_SUBNET_MASK].len; } else { dp = lease->options[DHO_SUBNET_MASK].data; len = lease->options[DHO_SUBNET_MASK].len; } if (len && (len < sizeof(lease->address.iabuf))) { struct iaddr netmask, subnet, broadcast; memcpy(netmask.iabuf, dp, len); netmask.len = len; subnet = subnet_number(lease->address, netmask); if (subnet.len) { script_set_env(ip->client, prefix, "network_number", piaddr(subnet)); if (!lease->options[DHO_BROADCAST_ADDRESS].len) { broadcast = broadcast_addr(subnet, netmask); if (broadcast.len) script_set_env(ip->client, prefix, "broadcast_address", piaddr(broadcast)); } } } if (lease->filename) script_set_env(ip->client, prefix, "filename", lease->filename); if (lease->server_name) script_set_env(ip->client, prefix, "server_name", lease->server_name); for (i = 0; i < 256; i++) { len = 0; if (ip->client->config->defaults[i].len) { if (lease->options[i].len) { switch ( ip->client->config->default_actions[i]) { case ACTION_DEFAULT: dp = lease->options[i].data; len = lease->options[i].len; break; case ACTION_SUPERSEDE: supersede: dp = ip->client-> config->defaults[i].data; len = ip->client-> config->defaults[i].len; break; case ACTION_PREPEND: len = ip->client-> config->defaults[i].len + lease->options[i].len; if (len >= sizeof(dbuf)) { warning("no space to %s %s", "prepend option", dhcp_options[i].name); goto supersede; } dp = dbuf; memcpy(dp, ip->client-> config->defaults[i].data, ip->client-> config->defaults[i].len); memcpy(dp + ip->client-> config->defaults[i].len, lease->options[i].data, lease->options[i].len); dp[len] = '\0'; break; case ACTION_APPEND: /* * When we append, we assume that we're * appending to text. Some MS servers * include a NUL byte at the end of * the search string provided. */ len = ip->client-> config->defaults[i].len + lease->options[i].len; if (len >= sizeof(dbuf)) { warning("no space to %s %s", "append option", dhcp_options[i].name); goto supersede; } memcpy(dbuf, lease->options[i].data, lease->options[i].len); for (dp = dbuf + lease->options[i].len; dp > dbuf; dp--, len--) if (dp[-1] != '\0') break; memcpy(dp, ip->client-> config->defaults[i].data, ip->client-> config->defaults[i].len); dp = dbuf; dp[len] = '\0'; } } else { dp = ip->client-> config->defaults[i].data; len = ip->client-> config->defaults[i].len; } } else if (lease->options[i].len) { len = lease->options[i].len; dp = lease->options[i].data; } else { len = 0; } if (len) { char name[256]; if (dhcp_option_ev_name(name, sizeof(name), &dhcp_options[i])) script_set_env(ip->client, prefix, name, pretty_print_option(i, dp, len, 0, 0)); } } snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); script_set_env(ip->client, prefix, "expiry", tbuf); } void -script_write_params(char *prefix, struct client_lease *lease) +script_write_params(const char *prefix, struct client_lease *lease) { size_t fn_len = 0, sn_len = 0, pr_len = 0; struct imsg_hdr hdr; struct buf *buf; int errs, i; if (lease->filename != NULL) fn_len = strlen(lease->filename); if (lease->server_name != NULL) sn_len = strlen(lease->server_name); if (prefix != NULL) pr_len = strlen(prefix); hdr.code = IMSG_SCRIPT_WRITE_PARAMS; hdr.len = sizeof(hdr) + sizeof(*lease) + sizeof(fn_len) + fn_len + sizeof(sn_len) + sn_len + sizeof(pr_len) + pr_len; for (i = 0; i < 256; i++) { hdr.len += sizeof(lease->options[i].len); hdr.len += lease->options[i].len; } scripttime = time(NULL); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); errs = 0; errs += buf_add(buf, &hdr, sizeof(hdr)); errs += buf_add(buf, lease, sizeof(*lease)); errs += buf_add(buf, &fn_len, sizeof(fn_len)); errs += buf_add(buf, lease->filename, fn_len); errs += buf_add(buf, &sn_len, sizeof(sn_len)); errs += buf_add(buf, lease->server_name, sn_len); errs += buf_add(buf, &pr_len, sizeof(pr_len)); errs += buf_add(buf, prefix, pr_len); for (i = 0; i < 256; i++) { errs += buf_add(buf, &lease->options[i].len, sizeof(lease->options[i].len)); errs += buf_add(buf, lease->options[i].data, lease->options[i].len); } if (errs) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); } int script_go(void) { struct imsg_hdr hdr; struct buf *buf; int ret; hdr.code = IMSG_SCRIPT_GO; hdr.len = sizeof(struct imsg_hdr); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); if (buf_add(buf, &hdr, sizeof(hdr))) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); bzero(&hdr, sizeof(hdr)); buf_read(privfd, &hdr, sizeof(hdr)); if (hdr.code != IMSG_SCRIPT_GO_RET) error("unexpected msg type %u", hdr.code); if (hdr.len != sizeof(hdr) + sizeof(int)) error("received corrupted message"); buf_read(privfd, &ret, sizeof(ret)); scripttime = time(NULL); return (ret); } int priv_script_go(void) { char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI"; static char client_path[] = CLIENT_PATH; struct interface_info *ip = ifi; int pid, wpid, wstatus; scripttime = time(NULL); if (ip) { scriptName = ip->client->config->script_name; envp = ip->client->scriptEnv; } else { scriptName = top_level_config.script_name; epp[0] = reason; epp[1] = client_path; epp[2] = NULL; envp = epp; } argv[0] = scriptName; argv[1] = NULL; pid = fork(); if (pid < 0) { error("fork: %m"); wstatus = 0; } else if (pid) { do { wpid = wait(&wstatus); } while (wpid != pid && wpid > 0); if (wpid < 0) { error("wait: %m"); wstatus = 0; } } else { execve(scriptName, argv, envp); error("execve (%s, ...): %m", scriptName); } if (ip) script_flush_env(ip->client); return (wstatus & 0xff); } void script_set_env(struct client_state *client, const char *prefix, const char *name, const char *value) { int i, namelen; size_t j; /* No `` or $() command substitution allowed in environment values! */ for (j=0; j < strlen(value); j++) switch (value[j]) { case '`': case '$': warning("illegal character (%c) in value '%s'", value[j], value); /* Ignore this option */ return; } namelen = strlen(name); for (i = 0; client->scriptEnv[i]; i++) if (strncmp(client->scriptEnv[i], name, namelen) == 0 && client->scriptEnv[i][namelen] == '=') break; if (client->scriptEnv[i]) /* Reuse the slot. */ free(client->scriptEnv[i]); else { /* New variable. Expand if necessary. */ if (i >= client->scriptEnvsize - 1) { char **newscriptEnv; int newscriptEnvsize = client->scriptEnvsize + 50; newscriptEnv = realloc(client->scriptEnv, newscriptEnvsize); if (newscriptEnv == NULL) { free(client->scriptEnv); client->scriptEnv = NULL; client->scriptEnvsize = 0; error("script_set_env: no memory for variable"); } client->scriptEnv = newscriptEnv; client->scriptEnvsize = newscriptEnvsize; } /* need to set the NULL pointer at end of array beyond the new slot. */ client->scriptEnv[i + 1] = NULL; } /* Allocate space and format the variable in the appropriate slot. */ client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + strlen(value) + 1); if (client->scriptEnv[i] == NULL) error("script_set_env: no memory for variable assignment"); snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); } void script_flush_env(struct client_state *client) { int i; for (i = 0; client->scriptEnv[i]; i++) { free(client->scriptEnv[i]); client->scriptEnv[i] = NULL; } client->scriptEnvsize = 0; } int dhcp_option_ev_name(char *buf, size_t buflen, struct option *option) { size_t i; for (i = 0; option->name[i]; i++) { if (i + 1 == buflen) return 0; if (option->name[i] == '-') buf[i] = '_'; else buf[i] = option->name[i]; } buf[i] = 0; return 1; } void go_daemon(void) { static int state = 0; cap_rights_t rights; if (no_daemon || state) return; state = 1; /* Stop logging to stderr... */ log_perror = 0; if (daemon(1, 0) == -1) error("daemon"); cap_rights_init(&rights); if (pidfile != NULL) { pidfile_write(pidfile); if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 && errno != ENOSYS) { error("can't limit pidfile descriptor: %m"); } } /* we are chrooted, daemon(3) fails to open /dev/null */ if (nullfd != -1) { dup2(nullfd, STDIN_FILENO); dup2(nullfd, STDOUT_FILENO); dup2(nullfd, STDERR_FILENO); close(nullfd); nullfd = -1; } if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdin: %m"); cap_rights_init(&rights, CAP_WRITE); if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stdout: %m"); if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) error("can't limit stderr: %m"); } int check_option(struct client_lease *l, int option) { - char *opbuf; - char *sbuf; + const char *opbuf; + const char *sbuf; /* we use this, since this is what gets passed to dhclient-script */ opbuf = pretty_print_option(option, l->options[option].data, l->options[option].len, 0, 0); sbuf = option_as_string(option, l->options[option].data, l->options[option].len); switch (option) { case DHO_SUBNET_MASK: case DHO_TIME_SERVERS: case DHO_NAME_SERVERS: case DHO_ROUTERS: case DHO_DOMAIN_NAME_SERVERS: case DHO_LOG_SERVERS: case DHO_COOKIE_SERVERS: case DHO_LPR_SERVERS: case DHO_IMPRESS_SERVERS: case DHO_RESOURCE_LOCATION_SERVERS: case DHO_SWAP_SERVER: case DHO_BROADCAST_ADDRESS: case DHO_NIS_SERVERS: case DHO_NTP_SERVERS: case DHO_NETBIOS_NAME_SERVERS: case DHO_NETBIOS_DD_SERVER: case DHO_FONT_SERVERS: case DHO_DHCP_SERVER_IDENTIFIER: case DHO_NISPLUS_SERVERS: case DHO_MOBILE_IP_HOME_AGENT: case DHO_SMTP_SERVER: case DHO_POP_SERVER: case DHO_NNTP_SERVER: case DHO_WWW_SERVER: case DHO_FINGER_SERVER: case DHO_IRC_SERVER: case DHO_STREETTALK_SERVER: case DHO_STREETTALK_DA_SERVER: if (!ipv4addrs(opbuf)) { warning("Invalid IP address in option: %s", opbuf); return (0); } return (1) ; case DHO_HOST_NAME: case DHO_NIS_DOMAIN: case DHO_NISPLUS_DOMAIN: case DHO_TFTP_SERVER_NAME: if (!res_hnok(sbuf)) { warning("Bogus Host Name option %d: %s (%s)", option, sbuf, opbuf); l->options[option].len = 0; free(l->options[option].data); } return (1); case DHO_DOMAIN_NAME: case DHO_DOMAIN_SEARCH: if (!res_hnok(sbuf)) { if (!check_search(sbuf)) { warning("Bogus domain search list %d: %s (%s)", option, sbuf, opbuf); l->options[option].len = 0; free(l->options[option].data); } } return (1); case DHO_PAD: case DHO_TIME_OFFSET: case DHO_BOOT_SIZE: case DHO_MERIT_DUMP: case DHO_ROOT_PATH: case DHO_EXTENSIONS_PATH: case DHO_IP_FORWARDING: case DHO_NON_LOCAL_SOURCE_ROUTING: case DHO_POLICY_FILTER: case DHO_MAX_DGRAM_REASSEMBLY: case DHO_DEFAULT_IP_TTL: case DHO_PATH_MTU_AGING_TIMEOUT: case DHO_PATH_MTU_PLATEAU_TABLE: case DHO_INTERFACE_MTU: case DHO_ALL_SUBNETS_LOCAL: case DHO_PERFORM_MASK_DISCOVERY: case DHO_MASK_SUPPLIER: case DHO_ROUTER_DISCOVERY: case DHO_ROUTER_SOLICITATION_ADDRESS: case DHO_STATIC_ROUTES: case DHO_TRAILER_ENCAPSULATION: case DHO_ARP_CACHE_TIMEOUT: case DHO_IEEE802_3_ENCAPSULATION: case DHO_DEFAULT_TCP_TTL: case DHO_TCP_KEEPALIVE_INTERVAL: case DHO_TCP_KEEPALIVE_GARBAGE: case DHO_VENDOR_ENCAPSULATED_OPTIONS: case DHO_NETBIOS_NODE_TYPE: case DHO_NETBIOS_SCOPE: case DHO_X_DISPLAY_MANAGER: case DHO_DHCP_REQUESTED_ADDRESS: case DHO_DHCP_LEASE_TIME: case DHO_DHCP_OPTION_OVERLOAD: case DHO_DHCP_MESSAGE_TYPE: case DHO_DHCP_PARAMETER_REQUEST_LIST: case DHO_DHCP_MESSAGE: case DHO_DHCP_MAX_MESSAGE_SIZE: case DHO_DHCP_RENEWAL_TIME: case DHO_DHCP_REBINDING_TIME: case DHO_DHCP_CLASS_IDENTIFIER: case DHO_DHCP_CLIENT_IDENTIFIER: case DHO_BOOTFILE_NAME: case DHO_DHCP_USER_CLASS_ID: case DHO_END: return (1); case DHO_CLASSLESS_ROUTES: return (check_classless_option(l->options[option].data, l->options[option].len)); default: warning("unknown dhcp option value 0x%x", option); return (unknown_ok); } } /* RFC 3442 The Classless Static Routes option checks */ int check_classless_option(unsigned char *data, int len) { int i = 0; unsigned char width; in_addr_t addr, mask; if (len < 5) { warning("Too small length: %d", len); return (0); } while(i < len) { width = data[i++]; if (width == 0) { i += 4; continue; } else if (width < 9) { addr = (in_addr_t)(data[i] << 24); i += 1; } else if (width < 17) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16); i += 2; } else if (width < 25) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8); i += 3; } else if (width < 33) { addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8) + data[i + 3]; i += 4; } else { warning("Incorrect subnet width: %d", width); return (0); } mask = (in_addr_t)(~0) << (32 - width); addr = ntohl(addr); mask = ntohl(mask); /* * From RFC 3442: * ... After deriving a subnet number and subnet mask * from each destination descriptor, the DHCP client * MUST zero any bits in the subnet number where the * corresponding bit in the mask is zero... */ if ((addr & mask) != addr) { addr &= mask; data[i - 1] = (unsigned char)( (addr >> (((32 - width)/8)*8)) & 0xFF); } i += 4; } if (i > len) { warning("Incorrect data length: %d (must be %d)", len, i); return (0); } return (1); } int res_hnok(const char *dn) { int pch = PERIOD, ch = *dn++; while (ch != '\0') { int nch = *dn++; if (periodchar(ch)) { ; } else if (periodchar(pch)) { if (!borderchar(ch)) return (0); } else if (periodchar(nch) || nch == '\0') { if (!borderchar(ch)) return (0); } else { if (!middlechar(ch)) return (0); } pch = ch, ch = nch; } return (1); } int check_search(const char *srch) { int pch = PERIOD, ch = *srch++; int domains = 1; /* 256 char limit re resolv.conf(5) */ if (strlen(srch) > 256) return (0); while (whitechar(ch)) ch = *srch++; while (ch != '\0') { int nch = *srch++; if (periodchar(ch) || whitechar(ch)) { ; } else if (periodchar(pch)) { if (!borderchar(ch)) return (0); } else if (periodchar(nch) || nch == '\0') { if (!borderchar(ch)) return (0); } else { if (!middlechar(ch)) return (0); } if (!whitechar(ch)) { pch = ch; } else { while (whitechar(nch)) { nch = *srch++; } if (nch != '\0') domains++; pch = PERIOD; } ch = nch; } /* 6 domain limit re resolv.conf(5) */ if (domains > 6) return (0); return (1); } /* Does buf consist only of dotted decimal ipv4 addrs? * return how many if so, * otherwise, return 0 */ int -ipv4addrs(char * buf) +ipv4addrs(const char * buf) { struct in_addr jnk; int count = 0; while (inet_aton(buf, &jnk) == 1){ count++; while (periodchar(*buf) || digitchar(*buf)) buf++; if (*buf == '\0') return (count); while (*buf == ' ') buf++; } return (0); } -char * +const char * option_as_string(unsigned int code, unsigned char *data, int len) { static char optbuf[32768]; /* XXX */ char *op = optbuf; int opleft = sizeof(optbuf); unsigned char *dp = data; if (code > 255) error("option_as_string: bad code %d", code); for (; dp < data + len; dp++) { if (!isascii(*dp) || !isprint(*dp)) { if (dp + 1 != data + len || *dp != 0) { snprintf(op, opleft, "\\%03o", *dp); op += 4; opleft -= 4; } } else if (*dp == '"' || *dp == '\'' || *dp == '$' || *dp == '`' || *dp == '\\') { *op++ = '\\'; *op++ = *dp; opleft -= 2; } else { *op++ = *dp; opleft--; } } if (opleft < 1) goto toobig; *op = 0; return optbuf; toobig: warning("dhcp option too large"); return ""; } int fork_privchld(int fd, int fd2) { struct pollfd pfd[1]; int nfds; switch (fork()) { case -1: error("cannot fork"); case 0: break; default: return (0); } setproctitle("%s [priv]", ifi->name); setsid(); dup2(nullfd, STDIN_FILENO); dup2(nullfd, STDOUT_FILENO); dup2(nullfd, STDERR_FILENO); close(nullfd); close(fd2); close(ifi->rfdesc); ifi->rfdesc = -1; for (;;) { pfd[0].fd = fd; pfd[0].events = POLLIN; if ((nfds = poll(pfd, 1, INFTIM)) == -1) if (errno != EINTR) error("poll error"); if (nfds == 0 || !(pfd[0].revents & POLLIN)) continue; dispatch_imsg(ifi, fd); } } Index: stable/11/sbin/dhclient/dhcpd.h =================================================================== --- stable/11/sbin/dhclient/dhcpd.h (revision 332601) +++ stable/11/sbin/dhclient/dhcpd.h (revision 332602) @@ -1,442 +1,443 @@ /* $OpenBSD: dhcpd.h,v 1.33 2004/05/06 22:29:15 deraadt Exp $ */ /* * Copyright (c) 2004 Henning Brauer * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dhcp.h" #include "tree.h" #define LOCAL_PORT 68 #define REMOTE_PORT 67 struct option_data { size_t len; u_int8_t *data; }; struct string_list { struct string_list *next; char *string; }; struct iaddr { size_t len; unsigned char iabuf[16]; }; struct iaddrlist { struct iaddrlist *next; struct iaddr addr; }; struct packet { struct dhcp_packet *raw; int packet_length; int packet_type; int options_valid; int client_port; struct iaddr client_addr; struct interface_info *interface; struct hardware *haddr; struct option_data options[256]; }; struct hardware { u_int8_t htype; u_int8_t hlen; u_int8_t haddr[16]; }; struct client_lease { struct client_lease *next; time_t expiry, renewal, rebind; struct iaddr address; struct iaddr nextserver; char *server_name; char *filename; struct string_list *medium; unsigned int is_static : 1; unsigned int is_bootp : 1; struct option_data options[256]; }; /* Possible states in which the client can be. */ enum dhcp_state { S_REBOOTING, S_INIT, S_SELECTING, S_REQUESTING, S_BOUND, S_RENEWING, S_REBINDING }; struct client_config { struct option_data defaults[256]; enum { ACTION_DEFAULT, ACTION_SUPERSEDE, ACTION_PREPEND, ACTION_APPEND } default_actions[256]; struct option_data send_options[256]; u_int8_t required_options[256]; u_int8_t requested_options[256]; int requested_option_count; time_t timeout; time_t initial_interval; time_t retry_interval; time_t select_interval; time_t reboot_timeout; time_t backoff_cutoff; struct string_list *media; char *script_name; enum { IGNORE, ACCEPT, PREFER } bootp_policy; struct string_list *medium; struct iaddrlist *reject_list; }; struct client_state { struct client_lease *active; struct client_lease *new; struct client_lease *offered_leases; struct client_lease *leases; struct client_lease *alias; enum dhcp_state state; struct iaddr destination; u_int32_t xid; u_int16_t secs; time_t first_sending; time_t interval; struct string_list *medium; struct dhcp_packet packet; int packet_length; struct iaddr requested_address; struct client_config *config; char **scriptEnv; int scriptEnvsize; struct string_list *env; int envc; }; struct interface_info { struct interface_info *next; struct hardware hw_address; struct in_addr primary_address; char name[IFNAMSIZ]; int rfdesc; int wfdesc; int ufdesc; unsigned char *rbuf; size_t rbuf_max; size_t rbuf_offset; size_t rbuf_len; struct ifreq *ifp; struct client_state *client; int noifmedia; int errors; int dead; u_int16_t index; int linkstat; }; struct timeout { struct timeout *next; time_t when; void (*func)(void *); void *what; }; struct protocol { struct protocol *next; int fd; void (*handler)(struct protocol *); void *local; }; #define DEFAULT_HASH_SIZE 97 struct hash_bucket { struct hash_bucket *next; - unsigned char *name; + const unsigned char *name; int len; unsigned char *value; }; struct hash_table { int hash_count; struct hash_bucket *buckets[DEFAULT_HASH_SIZE]; }; /* Default path to dhcpd config file. */ #define _PATH_DHCLIENT_CONF "/etc/dhclient.conf" #define _PATH_DHCLIENT_DB "/var/db/dhclient.leases" #define DHCPD_LOG_FACILITY LOG_DAEMON #define MAX_TIME 0x7fffffff #define MIN_TIME 0 /* External definitions... */ /* options.c */ int cons_options(struct packet *, struct dhcp_packet *, int, struct tree_cache **, int, int, int, u_int8_t *, int); -char *pretty_print_option(unsigned int, +const char *pretty_print_option(unsigned int, unsigned char *, int, int, int); void do_packet(struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); /* errwarn.c */ extern int warnings_occurred; -void error(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -int warning(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -int note(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -int debug(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -int parse_warn(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +void error(const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int warning(const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int note(const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int debug(const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +int parse_warn(const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); /* conflex.c */ extern int lexline, lexchar; -extern char *token_line, *tlname; +extern char *token_line; +extern const char *tlname; extern char comments[4096]; extern int comment_index; extern int eol_token; -void new_parse(char *); +void new_parse(const char *); int next_token(char **, FILE *); int peek_token(char **, FILE *); /* parse.c */ void skip_to_semi(FILE *); int parse_semi(FILE *); char *parse_string(FILE *); int parse_ip_addr(FILE *, struct iaddr *); void parse_hardware_param(FILE *, struct hardware *); void parse_lease_time(FILE *, time_t *); unsigned char *parse_numeric_aggregate(FILE *, unsigned char *, size_t *, int, unsigned, int); void convert_num(unsigned char *, char *, unsigned, int); time_t parse_date(FILE *); /* tree.c */ pair cons(caddr_t, pair); /* alloc.c */ struct string_list *new_string_list(size_t size); struct hash_table *new_hash_table(int); struct hash_bucket *new_hash_bucket(void); /* bpf.c */ int if_register_bpf(struct interface_info *, int); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); void send_packet_unpriv(int, struct dhcp_packet *, size_t, struct in_addr, struct in_addr); struct imsg_hdr; void send_packet_priv(struct interface_info *, struct imsg_hdr *, int); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); /* dispatch.c */ extern void (*bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); void discover_interfaces(struct interface_info *); void reinitialize_interfaces(void); void dispatch(void); void got_one(struct protocol *); void add_timeout(time_t, void (*)(void *), void *); void cancel_timeout(void (*)(void *), void *); -void add_protocol(char *, int, void (*)(struct protocol *), void *); +void add_protocol(const char *, int, void (*)(struct protocol *), void *); void remove_protocol(struct protocol *); int interface_link_status(char *); void interface_set_mtu_unpriv(int, u_int16_t); void interface_set_mtu_priv(char *, u_int16_t); /* hash.c */ struct hash_table *new_hash(void); -void add_hash(struct hash_table *, unsigned char *, int, unsigned char *); -unsigned char *hash_lookup(struct hash_table *, unsigned char *, int); +void add_hash(struct hash_table *, const unsigned char *, int, unsigned char *); +void *hash_lookup(struct hash_table *, unsigned char *, int); /* tables.c */ extern struct option dhcp_options[256]; extern unsigned char dhcp_option_default_priority_list[]; extern int sizeof_dhcp_option_default_priority_list; extern struct hash_table universe_hash; extern struct universe dhcp_universe; void initialize_universes(void); /* convert.c */ u_int32_t getULong(unsigned char *); int32_t getLong(unsigned char *); u_int16_t getUShort(unsigned char *); int16_t getShort(unsigned char *); void putULong(unsigned char *, u_int32_t); void putLong(unsigned char *, int32_t); void putUShort(unsigned char *, unsigned int); void putShort(unsigned char *, int); /* inet.c */ struct iaddr subnet_number(struct iaddr, struct iaddr); struct iaddr broadcast_addr(struct iaddr, struct iaddr); int addr_eq(struct iaddr, struct iaddr); char *piaddr(struct iaddr); /* dhclient.c */ -extern char *path_dhclient_conf; +extern const char *path_dhclient_conf; extern char *path_dhclient_db; extern time_t cur_time; extern int log_priority; extern int log_perror; extern struct client_config top_level_config; extern struct pidfh *pidfile; void dhcpoffer(struct packet *); void dhcpack(struct packet *); void dhcpnak(struct packet *); void send_discover(void *); void send_request(void *); void send_decline(void *); void state_reboot(void *); void state_init(void *); void state_selecting(void *); void state_requesting(void *); void state_bound(void *); void state_panic(void *); void bind_lease(struct interface_info *); void make_discover(struct interface_info *, struct client_lease *); void make_request(struct interface_info *, struct client_lease *); void make_decline(struct interface_info *, struct client_lease *); void free_client_lease(struct client_lease *); void rewrite_client_leases(void); void write_client_lease(struct interface_info *, struct client_lease *, int); -void priv_script_init(char *, char *); -void priv_script_write_params(char *, struct client_lease *); +void priv_script_init(const char *, char *); +void priv_script_write_params(const char *, struct client_lease *); int priv_script_go(void); -void script_init(char *, struct string_list *); -void script_write_params(char *, struct client_lease *); +void script_init(const char *, struct string_list *); +void script_write_params(const char *, struct client_lease *); int script_go(void); void client_envadd(struct client_state *, const char *, const char *, const char *, ...); void script_set_env(struct client_state *, const char *, const char *, const char *); void script_flush_env(struct client_state *); int dhcp_option_ev_name(char *, size_t, struct option *); struct client_lease *packet_to_lease(struct packet *); void go_daemon(void); void client_location_changed(void); void bootp(struct packet *); void dhcp(struct packet *); /* packet.c */ void assemble_hw_header(struct interface_info *, unsigned char *, int *); void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, unsigned int, unsigned char *, int); ssize_t decode_hw_header(unsigned char *, int, struct hardware *); ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *, unsigned char *, int); /* clparse.c */ int read_client_conf(void); void read_client_leases(void); void parse_client_statement(FILE *, struct interface_info *, struct client_config *); unsigned parse_X(FILE *, u_int8_t *, unsigned); int parse_option_list(FILE *, u_int8_t *); void parse_interface_declaration(FILE *, struct client_config *); struct interface_info *interface_or_dummy(char *); void make_client_state(struct interface_info *); void make_client_config(struct interface_info *, struct client_config *); void parse_client_lease_statement(FILE *, int); void parse_client_lease_declaration(FILE *, struct client_lease *, struct interface_info **); struct option *parse_option_decl(FILE *, struct option_data *); void parse_string_list(FILE *, struct string_list **, int); void parse_reject_statement(FILE *, struct client_config *); /* privsep.c */ struct buf *buf_open(size_t); -int buf_add(struct buf *, void *, size_t); +int buf_add(struct buf *, const void *, size_t); int buf_close(int, struct buf *); ssize_t buf_read(int, void *, size_t); void dispatch_imsg(struct interface_info *, int); Index: stable/11/sbin/dhclient/dispatch.c =================================================================== --- stable/11/sbin/dhclient/dispatch.c (revision 332601) +++ stable/11/sbin/dhclient/dispatch.c (revision 332602) @@ -1,543 +1,561 @@ /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ /* * Copyright 2004 Henning Brauer * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "privsep.h" #include +#include #include #include #include +/* Assert that pointer p is aligned to at least align bytes */ +#define assert_aligned(p, align) assert((((uintptr_t)p) & ((align) - 1)) == 0) + struct protocol *protocols; struct timeout *timeouts; static struct timeout *free_timeouts; static int interfaces_invalidated; void (*bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); static int interface_status(struct interface_info *ifinfo); /* * Use getifaddrs() to get a list of all the attached interfaces. For * each interface that's of type INET and not the loopback interface, * register that interface with the network I/O software, figure out * what subnet it's on, and add it to the list of interfaces. */ void discover_interfaces(struct interface_info *iface) { struct ifaddrs *ifap, *ifa; - struct sockaddr_in foo; struct ifreq *tif; if (getifaddrs(&ifap) != 0) error("getifaddrs failed"); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT) || (!(ifa->ifa_flags & IFF_UP))) continue; if (strcmp(iface->name, ifa->ifa_name)) continue; /* * If we have the capability, extract link information * and record it in a linked list. */ if (ifa->ifa_addr->sa_family == AF_LINK) { - struct sockaddr_dl *foo = - (struct sockaddr_dl *)ifa->ifa_addr; + struct sockaddr_dl *foo; + /* + * The implementation of getifaddrs should guarantee + * this alignment + */ + assert_aligned(ifa->ifa_addr, + _Alignof(struct sockaddr_dl)); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-align" +#endif + foo = (struct sockaddr_dl *)ifa->ifa_addr; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + iface->index = foo->sdl_index; iface->hw_address.hlen = foo->sdl_alen; iface->hw_address.htype = HTYPE_ETHER; /* XXX */ memcpy(iface->hw_address.haddr, LLADDR(foo), foo->sdl_alen); } else if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in foo; struct iaddr addr; memcpy(&foo, ifa->ifa_addr, sizeof(foo)); if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) continue; if (!iface->ifp) { if ((tif = calloc(1, sizeof(struct ifreq))) == NULL) error("no space to remember ifp"); strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); memcpy(&tif->ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); iface->ifp = tif; iface->primary_address = foo.sin_addr; } addr.len = 4; memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); } } if (!iface->ifp) error("%s: not found", iface->name); /* Register the interface... */ if_register_receive(iface); if_register_send(iface); add_protocol(iface->name, iface->rfdesc, got_one, iface); freeifaddrs(ifap); } void reinitialize_interfaces(void) { interfaces_invalidated = 1; } /* * Wait for packets to come in using poll(). When a packet comes in, * call receive_packet to receive the packet and possibly strip hardware * addressing information from it, and then call through the * bootp_packet_handler hook to try to do something with it. */ void dispatch(void) { int count, live_interfaces, i, to_msec, nfds = 0; struct protocol *l; struct pollfd *fds; time_t howlong; for (l = protocols; l; l = l->next) nfds++; fds = malloc(nfds * sizeof(struct pollfd)); if (fds == NULL) error("Can't allocate poll structures."); do { /* * Call any expired timeouts, and then if there's still * a timeout registered, time out the select call then. */ another: if (timeouts) { struct timeout *t; if (timeouts->when <= cur_time) { t = timeouts; timeouts = timeouts->next; (*(t->func))(t->what); t->next = free_timeouts; free_timeouts = t; goto another; } /* * Figure timeout in milliseconds, and check for * potential overflow, so we can cram into an * int for poll, while not polling with a * negative timeout and blocking indefinitely. */ howlong = timeouts->when - cur_time; if (howlong > INT_MAX / 1000) howlong = INT_MAX / 1000; to_msec = howlong * 1000; } else to_msec = -1; /* Set up the descriptors to be polled. */ live_interfaces = 0; for (i = 0, l = protocols; l; l = l->next) { struct interface_info *ip = l->local; if (ip == NULL || ip->dead) continue; fds[i].fd = l->fd; fds[i].events = POLLIN; fds[i].revents = 0; i++; if (l->handler == got_one) live_interfaces++; } if (live_interfaces == 0) error("No live interfaces to poll on - exiting."); /* Wait for a packet or a timeout... XXX */ count = poll(fds, nfds, to_msec); /* Not likely to be transitory... */ if (count == -1) { if (errno == EAGAIN || errno == EINTR) { time(&cur_time); continue; } else error("poll: %m"); } /* Get the current time... */ time(&cur_time); i = 0; for (l = protocols; l; l = l->next) { struct interface_info *ip; ip = l->local; if ((fds[i].revents & (POLLIN | POLLHUP))) { fds[i].revents = 0; if (ip && (l->handler != got_one || !ip->dead)) (*(l->handler))(l); if (interfaces_invalidated) break; } i++; } interfaces_invalidated = 0; } while (1); } void got_one(struct protocol *l) { struct sockaddr_in from; struct hardware hfrom; struct iaddr ifrom; ssize_t result; union { /* * Packet input buffer. Must be as large as largest * possible MTU. */ unsigned char packbuf[4095]; struct dhcp_packet packet; } u; struct interface_info *ip = l->local; if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, &hfrom)) == -1) { warning("receive_packet failed on %s: %s", ip->name, strerror(errno)); ip->errors++; if ((!interface_status(ip)) || (ip->noifmedia && ip->errors > 20)) { /* our interface has gone away. */ warning("Interface %s no longer appears valid.", ip->name); ip->dead = 1; interfaces_invalidated = 1; close(l->fd); remove_protocol(l); free(ip); } return; } if (result == 0) return; if (bootp_packet_handler) { ifrom.len = 4; memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); (*bootp_packet_handler)(ip, &u.packet, result, from.sin_port, ifrom, &hfrom); } } int interface_status(struct interface_info *ifinfo) { char *ifname = ifinfo->name; int ifsock = ifinfo->rfdesc; struct ifreq ifr; struct ifmediareq ifmr; /* get interface flags */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname); goto inactive; } /* * if one of UP and RUNNING flags is dropped, * the interface is not active. */ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) goto inactive; /* Next, check carrier on the interface, if possible */ if (ifinfo->noifmedia) goto active; memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { if (errno != EINVAL) { syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); ifinfo->noifmedia = 1; goto active; } /* * EINVAL (or ENOTTY) simply means that the interface * does not support the SIOCGIFMEDIA ioctl. We regard it alive. */ ifinfo->noifmedia = 1; goto active; } if (ifmr.ifm_status & IFM_AVALID) { switch (ifmr.ifm_active & IFM_NMASK) { case IFM_ETHER: case IFM_IEEE80211: if (ifmr.ifm_status & IFM_ACTIVE) goto active; else goto inactive; break; default: goto inactive; } } inactive: return (0); active: return (1); } void add_timeout(time_t when, void (*where)(void *), void *what) { struct timeout *t, *q; /* See if this timeout supersedes an existing timeout. */ t = NULL; for (q = timeouts; q; q = q->next) { if (q->func == where && q->what == what) { if (t) t->next = q->next; else timeouts = q->next; break; } t = q; } /* If we didn't supersede a timeout, allocate a timeout structure now. */ if (!q) { if (free_timeouts) { q = free_timeouts; free_timeouts = q->next; q->func = where; q->what = what; } else { q = malloc(sizeof(struct timeout)); if (!q) error("Can't allocate timeout structure!"); q->func = where; q->what = what; } } q->when = when; /* Now sort this timeout into the timeout list. */ /* Beginning of list? */ if (!timeouts || timeouts->when > q->when) { q->next = timeouts; timeouts = q; return; } /* Middle of list? */ for (t = timeouts; t->next; t = t->next) { if (t->next->when > q->when) { q->next = t->next; t->next = q; return; } } /* End of list. */ t->next = q; q->next = NULL; } void cancel_timeout(void (*where)(void *), void *what) { struct timeout *t, *q; /* Look for this timeout on the list, and unlink it if we find it. */ t = NULL; for (q = timeouts; q; q = q->next) { if (q->func == where && q->what == what) { if (t) t->next = q->next; else timeouts = q->next; break; } t = q; } /* If we found the timeout, put it on the free list. */ if (q) { q->next = free_timeouts; free_timeouts = q; } } /* Add a protocol to the list of protocols... */ void -add_protocol(char *name, int fd, void (*handler)(struct protocol *), +add_protocol(const char *name, int fd, void (*handler)(struct protocol *), void *local) { struct protocol *p; p = malloc(sizeof(*p)); if (!p) error("can't allocate protocol struct for %s", name); p->fd = fd; p->handler = handler; p->local = local; p->next = protocols; protocols = p; } void remove_protocol(struct protocol *proto) { struct protocol *p, *next; for (p = protocols; p; p = next) { next = p->next; if (p == proto) { protocols = p->next; free(p); } } } int interface_link_status(char *ifname) { struct ifmediareq ifmr; int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) error("Can't create socket"); memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { /* EINVAL -> link state unknown. treat as active */ if (errno != EINVAL) syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); close(sock); return (1); } close(sock); if (ifmr.ifm_status & IFM_AVALID) { switch (ifmr.ifm_active & IFM_NMASK) { case IFM_ETHER: case IFM_IEEE80211: if (ifmr.ifm_status & IFM_ACTIVE) return (1); else return (0); } } return (1); } void interface_set_mtu_unpriv(int privfd, u_int16_t mtu) { struct imsg_hdr hdr; struct buf *buf; int errs = 0; hdr.code = IMSG_SET_INTERFACE_MTU; hdr.len = sizeof(hdr) + sizeof(u_int16_t); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); errs += buf_add(buf, &hdr, sizeof(hdr)); errs += buf_add(buf, &mtu, sizeof(mtu)); if (errs) error("buf_add: %m"); if (buf_close(privfd, buf) == -1) error("buf_close: %m"); } void interface_set_mtu_priv(char *ifname, u_int16_t mtu) { struct ifreq ifr; int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) error("Can't create socket"); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_mtu = mtu; if (ioctl(sock, SIOCSIFMTU, &ifr) == -1) warning("SIOCSIFMTU failed (%d): %s", mtu, strerror(errno)); close(sock); } Index: stable/11/sbin/dhclient/errwarn.c =================================================================== --- stable/11/sbin/dhclient/errwarn.c (revision 332601) +++ stable/11/sbin/dhclient/errwarn.c (revision 332602) @@ -1,239 +1,239 @@ /* $OpenBSD: errwarn.c,v 1.7 2004/05/04 22:23:01 mickey Exp $ */ /* Errors and warnings... */ /* * Copyright (c) 1996 The Internet Software Consortium. * All Rights Reserved. * Copyright (c) 1995 RadioMail Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of RadioMail Corporation, the Internet Software * Consortium nor the names of its contributors may be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY RADIOMAIL CORPORATION, THE INTERNET * SOFTWARE CONSORTIUM AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL RADIOMAIL CORPORATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * This software was written for RadioMail Corporation by Ted Lemon * under a contract with Vixie Enterprises. Further modifications have * been made for the Internet Software Consortium under a contract * with Vixie Laboratories. */ #include __FBSDID("$FreeBSD$"); #include #include "dhcpd.h" -static void do_percentm(char *obuf, size_t size, char *ibuf); +static void do_percentm(char *obuf, size_t size, const char *ibuf); static char mbuf[1024]; static char fbuf[1024]; int warnings_occurred; /* * Log an error message, then exit. */ void -error(char *fmt, ...) +error(const char *fmt, ...) { va_list list; do_percentm(fbuf, sizeof(fbuf), fmt); va_start(list, fmt); vsnprintf(mbuf, sizeof(mbuf), fbuf, list); va_end(list); #ifndef DEBUG syslog(log_priority | LOG_ERR, "%s", mbuf); #endif /* Also log it to stderr? */ if (log_perror) { write(2, mbuf, strlen(mbuf)); write(2, "\n", 1); } syslog(LOG_CRIT, "exiting."); if (log_perror) { fprintf(stderr, "exiting.\n"); fflush(stderr); } if (pidfile != NULL) pidfile_remove(pidfile); exit(1); } /* * Log a warning message... */ int -warning(char *fmt, ...) +warning(const char *fmt, ...) { va_list list; do_percentm(fbuf, sizeof(fbuf), fmt); va_start(list, fmt); vsnprintf(mbuf, sizeof(mbuf), fbuf, list); va_end(list); #ifndef DEBUG syslog(log_priority | LOG_ERR, "%s", mbuf); #endif if (log_perror) { write(2, mbuf, strlen(mbuf)); write(2, "\n", 1); } return (0); } /* * Log a note... */ int -note(char *fmt, ...) +note(const char *fmt, ...) { va_list list; do_percentm(fbuf, sizeof(fbuf), fmt); va_start(list, fmt); vsnprintf(mbuf, sizeof(mbuf), fbuf, list); va_end(list); #ifndef DEBUG syslog(log_priority | LOG_INFO, "%s", mbuf); #endif if (log_perror) { write(2, mbuf, strlen(mbuf)); write(2, "\n", 1); } return (0); } /* * Log a debug message... */ int -debug(char *fmt, ...) +debug(const char *fmt, ...) { va_list list; do_percentm(fbuf, sizeof(fbuf), fmt); va_start(list, fmt); vsnprintf(mbuf, sizeof(mbuf), fbuf, list); va_end(list); #ifndef DEBUG syslog(log_priority | LOG_DEBUG, "%s", mbuf); #endif if (log_perror) { write(2, mbuf, strlen(mbuf)); write(2, "\n", 1); } return (0); } /* * Find %m in the input string and substitute an error message string. */ static void -do_percentm(char *obuf, size_t size, char *ibuf) +do_percentm(char *obuf, size_t size, const char *ibuf) { char ch; - char *s = ibuf; + const char *s = ibuf; char *t = obuf; size_t prlen; size_t fmt_left; int saved_errno = errno; /* * We wouldn't need this mess if printf handled %m, or if * strerror() had been invented before syslog(). */ for (fmt_left = size; (ch = *s); ++s) { if (ch == '%' && s[1] == 'm') { ++s; prlen = snprintf(t, fmt_left, "%s", strerror(saved_errno)); if (prlen >= fmt_left) prlen = fmt_left - 1; t += prlen; fmt_left -= prlen; } else { if (fmt_left > 1) { *t++ = ch; fmt_left--; } } } *t = '\0'; } int -parse_warn(char *fmt, ...) +parse_warn(const char *fmt, ...) { va_list list; static char spaces[] = " " " "; /* 80 spaces */ do_percentm(mbuf, sizeof(mbuf), fmt); snprintf(fbuf, sizeof(fbuf), "%s line %d: %s", tlname, lexline, mbuf); va_start(list, fmt); vsnprintf(mbuf, sizeof(mbuf), fbuf, list); va_end(list); #ifndef DEBUG syslog(log_priority | LOG_ERR, "%s", mbuf); syslog(log_priority | LOG_ERR, "%s", token_line); if (lexline < 81) syslog(log_priority | LOG_ERR, "%s^", &spaces[sizeof(spaces) - lexchar]); #endif if (log_perror) { write(2, mbuf, strlen(mbuf)); write(2, "\n", 1); write(2, token_line, strlen(token_line)); write(2, "\n", 1); write(2, spaces, lexchar - 1); write(2, "^\n", 2); } warnings_occurred = 1; return (0); } Index: stable/11/sbin/dhclient/hash.c =================================================================== --- stable/11/sbin/dhclient/hash.c (revision 332601) +++ stable/11/sbin/dhclient/hash.c (revision 332602) @@ -1,122 +1,122 @@ /* $OpenBSD: hash.c,v 1.9 2004/05/10 15:30:47 deraadt Exp $ */ /* Routines for manipulating hash tables... */ /* * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" -static int do_hash(unsigned char *, int, int); +static int do_hash(const unsigned char *, int, int); struct hash_table * new_hash(void) { struct hash_table *rv = new_hash_table(DEFAULT_HASH_SIZE); if (!rv) return (rv); memset(&rv->buckets[0], 0, DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *)); return (rv); } static int -do_hash(unsigned char *name, int len, int size) +do_hash(const unsigned char *name, int len, int size) { - unsigned char *s = name; + const unsigned char *s = name; int accum = 0, i = len; while (i--) { /* Add the character in... */ accum += *s++; /* Add carry back in... */ while (accum > 255) accum = (accum & 255) + (accum >> 8); } return (accum % size); } -void add_hash(struct hash_table *table, unsigned char *name, int len, +void add_hash(struct hash_table *table, const unsigned char *name, int len, unsigned char *pointer) { struct hash_bucket *bp; int hashno; if (!table) return; if (!len) - len = strlen((char *)name); + len = strlen((const char *)name); hashno = do_hash(name, len, table->hash_count); bp = new_hash_bucket(); if (!bp) { warning("Can't add %s to hash table.", name); return; } bp->name = name; bp->value = pointer; bp->next = table->buckets[hashno]; bp->len = len; table->buckets[hashno] = bp; } -unsigned char * +void * hash_lookup(struct hash_table *table, unsigned char *name, int len) { struct hash_bucket *bp; int hashno; if (!table) return (NULL); if (!len) len = strlen((char *)name); hashno = do_hash(name, len, table->hash_count); for (bp = table->buckets[hashno]; bp; bp = bp->next) if (len == bp->len && !memcmp(bp->name, name, len)) return (bp->value); return (NULL); } Index: stable/11/sbin/dhclient/options.c =================================================================== --- stable/11/sbin/dhclient/options.c (revision 332601) +++ stable/11/sbin/dhclient/options.c (revision 332602) @@ -1,899 +1,899 @@ /* $OpenBSD: options.c,v 1.15 2004/12/26 03:17:07 deraadt Exp $ */ /* DHCP options parsing and reassembly. */ /* * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include #define DHCP_OPTION_DATA #include "dhcpd.h" int bad_options = 0; int bad_options_max = 5; void parse_options(struct packet *); void parse_option_buffer(struct packet *, unsigned char *, int); unsigned store_options(unsigned char *, int, struct tree_cache **, unsigned char *, int, int, int, int); void expand_domain_search(struct packet *packet); int find_search_domain_name_len(struct option_data *option, size_t *offset); void expand_search_domain_name(struct option_data *option, size_t *offset, unsigned char **domain_search); /* * Parse all available options out of the specified packet. */ void parse_options(struct packet *packet) { /* Initially, zero all option pointers. */ memset(packet->options, 0, sizeof(packet->options)); /* If we don't see the magic cookie, there's nothing to parse. */ if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) { packet->options_valid = 0; return; } /* * Go through the options field, up to the end of the packet or * the End field. */ parse_option_buffer(packet, &packet->raw->options[4], packet->packet_length - DHCP_FIXED_NON_UDP - 4); /* * If we parsed a DHCP Option Overload option, parse more * options out of the buffer(s) containing them. */ if (packet->options_valid && packet->options[DHO_DHCP_OPTION_OVERLOAD].data) { if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) parse_option_buffer(packet, (unsigned char *)packet->raw->file, sizeof(packet->raw->file)); if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) parse_option_buffer(packet, (unsigned char *)packet->raw->sname, sizeof(packet->raw->sname)); } /* Expand DHCP Domain Search option. */ if (packet->options_valid) { expand_domain_search(packet); } } /* * Parse options out of the specified buffer, storing addresses of * option values in packet->options and setting packet->options_valid if * no errors are encountered. */ void parse_option_buffer(struct packet *packet, unsigned char *buffer, int length) { unsigned char *s, *t, *end = buffer + length; int len, code; for (s = buffer; *s != DHO_END && s < end; ) { code = s[0]; /* Pad options don't have a length - just skip them. */ if (code == DHO_PAD) { s++; continue; } if (s + 2 > end) { len = 65536; goto bogus; } /* * All other fields (except end, see above) have a * one-byte length. */ len = s[1]; /* * If the length is outrageous, silently skip the rest, * and mark the packet bad. Unfortunately some crappy * dhcp servers always seem to give us garbage on the * end of a packet. so rather than keep refusing, give * up and try to take one after seeing a few without * anything good. */ if (s + len + 2 > end) { bogus: bad_options++; warning("option %s (%d) %s.", dhcp_options[code].name, len, "larger than buffer"); if (bad_options == bad_options_max) { packet->options_valid = 1; bad_options = 0; warning("Many bogus options seen in offers. " "Taking this offer in spite of bogus " "options - hope for the best!"); } else { warning("rejecting bogus offer."); packet->options_valid = 0; } return; } /* * If we haven't seen this option before, just make * space for it and copy it there. */ if (!packet->options[code].data) { if (!(t = calloc(1, len + 1))) error("Can't allocate storage for option %s.", dhcp_options[code].name); /* * Copy and NUL-terminate the option (in case * it's an ASCII string. */ memcpy(t, &s[2], len); t[len] = 0; packet->options[code].len = len; packet->options[code].data = t; } else { /* * If it's a repeat, concatenate it to whatever * we last saw. This is really only required * for clients, but what the heck... */ t = calloc(1, len + packet->options[code].len + 1); if (!t) error("Can't expand storage for option %s.", dhcp_options[code].name); memcpy(t, packet->options[code].data, packet->options[code].len); memcpy(t + packet->options[code].len, &s[2], len); packet->options[code].len += len; t[packet->options[code].len] = 0; free(packet->options[code].data); packet->options[code].data = t; } s += len + 2; } packet->options_valid = 1; } /* * Expand DHCP Domain Search option. The value of this option is * encoded like DNS' list of labels. See: * RFC 3397 * RFC 1035 */ void expand_domain_search(struct packet *packet) { size_t offset; int expanded_len, next_domain_len; struct option_data *option; unsigned char *domain_search, *cursor; if (packet->options[DHO_DOMAIN_SEARCH].data == NULL) return; option = &packet->options[DHO_DOMAIN_SEARCH]; /* Compute final expanded length. */ expanded_len = 0; offset = 0; while (offset < option->len) { next_domain_len = find_search_domain_name_len(option, &offset); if (next_domain_len < 0) /* The Domain Search option value is invalid. */ return; /* We add 1 for the space between domain names. */ expanded_len += next_domain_len + 1; } if (expanded_len > 0) /* Remove 1 for the superfluous trailing space. */ --expanded_len; domain_search = malloc(expanded_len + 1); if (domain_search == NULL) error("Can't allocate storage for expanded domain-search\n"); offset = 0; cursor = domain_search; while (offset < option->len) { expand_search_domain_name(option, &offset, &cursor); cursor[0] = ' '; cursor++; } domain_search[expanded_len] = '\0'; free(option->data); option->len = expanded_len; option->data = domain_search; } int find_search_domain_name_len(struct option_data *option, size_t *offset) { int domain_name_len, label_len, pointed_len; size_t i, pointer; domain_name_len = 0; i = *offset; while (i < option->len) { label_len = option->data[i]; if (label_len == 0) { /* * A zero-length label marks the end of this * domain name. */ *offset = i + 1; return (domain_name_len); } else if (label_len & 0xC0) { /* This is a pointer to another list of labels. */ if (i + 1 >= option->len) { /* The pointer is truncated. */ warning("Truncated pointer in DHCP Domain " "Search option."); return (-1); } pointer = ((label_len & ~(0xC0)) << 8) + option->data[i + 1]; if (pointer >= *offset) { /* * The pointer must indicate a prior * occurrence. */ warning("Invalid forward pointer in DHCP " "Domain Search option compression."); return (-1); } pointed_len = find_search_domain_name_len(option, &pointer); domain_name_len += pointed_len; *offset = i + 2; return (domain_name_len); } if (i + label_len >= option->len) { warning("Truncated label in DHCP Domain Search " "option."); return (-1); } /* * Update the domain name length with the length of the * current label, plus a trailing dot ('.'). */ domain_name_len += label_len + 1; /* Move cursor. */ i += label_len + 1; } warning("Truncated DHCP Domain Search option."); return (-1); } void expand_search_domain_name(struct option_data *option, size_t *offset, unsigned char **domain_search) { int label_len; size_t i, pointer; unsigned char *cursor; /* * This is the same loop than the function above * (find_search_domain_name_len). Therefore, we remove checks, * they're already done. Here, we just make the copy. */ i = *offset; cursor = *domain_search; while (i < option->len) { label_len = option->data[i]; if (label_len == 0) { /* * A zero-length label marks the end of this * domain name. */ *offset = i + 1; *domain_search = cursor; return; } else if (label_len & 0xC0) { /* This is a pointer to another list of labels. */ pointer = ((label_len & ~(0xC0)) << 8) + option->data[i + 1]; expand_search_domain_name(option, &pointer, &cursor); *offset = i + 2; *domain_search = cursor; return; } /* Copy the label found. */ memcpy(cursor, option->data + i + 1, label_len); cursor[label_len] = '.'; /* Move cursor. */ i += label_len + 1; cursor += label_len + 1; } } /* * cons options into a big buffer, and then split them out into the * three separate buffers if needed. This allows us to cons up a set of * vendor options using the same routine. */ int cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, int mms, struct tree_cache **options, int overload, /* Overload flags that may be set. */ int terminate, int bootpp, u_int8_t *prl, int prl_len) { unsigned char priority_list[300], buffer[4096]; unsigned priority_len; size_t main_buffer_size; unsigned option_size, bufix, mainbufix; int length; /* * If the client has provided a maximum DHCP message size, use * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use * up to the minimum IP MTU size (576 bytes). * * XXX if a BOOTP client specifies a max message size, we will * honor it. */ if (!mms && inpacket && inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data && (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >= sizeof(u_int16_t))) mms = getUShort( inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data); if (mms) main_buffer_size = mms - DHCP_FIXED_LEN; else if (bootpp) main_buffer_size = 64; else main_buffer_size = 576 - DHCP_FIXED_LEN; if (main_buffer_size > sizeof(buffer)) main_buffer_size = sizeof(buffer); /* Preload the option priority list with mandatory options. */ priority_len = 0; priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE; priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; priority_list[priority_len++] = DHO_DHCP_LEASE_TIME; priority_list[priority_len++] = DHO_DHCP_MESSAGE; /* * If the client has provided a list of options that it wishes * returned, use it to prioritize. Otherwise, prioritize based * on the default priority list. */ if (inpacket && inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data) { unsigned prlen = inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len; if (prlen + priority_len > sizeof(priority_list)) prlen = sizeof(priority_list) - priority_len; memcpy(&priority_list[priority_len], inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data, prlen); priority_len += prlen; prl = priority_list; } else if (prl) { if (prl_len + priority_len > sizeof(priority_list)) prl_len = sizeof(priority_list) - priority_len; memcpy(&priority_list[priority_len], prl, prl_len); priority_len += prl_len; prl = priority_list; } else { memcpy(&priority_list[priority_len], dhcp_option_default_priority_list, sizeof_dhcp_option_default_priority_list); priority_len += sizeof_dhcp_option_default_priority_list; } /* Copy the options into the big buffer... */ option_size = store_options( buffer, (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) + ((overload & 2) ? DHCP_SNAME_LEN : 0)), options, priority_list, priority_len, main_buffer_size, (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)), terminate); /* Put the cookie up front... */ memcpy(outpacket->options, DHCP_OPTIONS_COOKIE, 4); mainbufix = 4; /* * If we're going to have to overload, store the overload option * at the beginning. If we can, though, just store the whole * thing in the packet's option buffer and leave it at that. */ if (option_size <= main_buffer_size - mainbufix) { memcpy(&outpacket->options[mainbufix], buffer, option_size); mainbufix += option_size; if (mainbufix < main_buffer_size) outpacket->options[mainbufix++] = DHO_END; length = DHCP_FIXED_NON_UDP + mainbufix; } else { outpacket->options[mainbufix++] = DHO_DHCP_OPTION_OVERLOAD; outpacket->options[mainbufix++] = 1; if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN) outpacket->options[mainbufix++] = 3; else outpacket->options[mainbufix++] = 1; memcpy(&outpacket->options[mainbufix], buffer, main_buffer_size - mainbufix); bufix = main_buffer_size - mainbufix; length = DHCP_FIXED_NON_UDP + mainbufix; if (overload & 1) { if (option_size - bufix <= DHCP_FILE_LEN) { memcpy(outpacket->file, &buffer[bufix], option_size - bufix); mainbufix = option_size - bufix; if (mainbufix < DHCP_FILE_LEN) outpacket->file[mainbufix++] = (char)DHO_END; while (mainbufix < DHCP_FILE_LEN) outpacket->file[mainbufix++] = (char)DHO_PAD; } else { memcpy(outpacket->file, &buffer[bufix], DHCP_FILE_LEN); bufix += DHCP_FILE_LEN; } } if ((overload & 2) && option_size < bufix) { memcpy(outpacket->sname, &buffer[bufix], option_size - bufix); mainbufix = option_size - bufix; if (mainbufix < DHCP_SNAME_LEN) outpacket->file[mainbufix++] = (char)DHO_END; while (mainbufix < DHCP_SNAME_LEN) outpacket->file[mainbufix++] = (char)DHO_PAD; } } return (length); } /* * Store all the requested options into the requested buffer. */ unsigned store_options(unsigned char *buffer, int buflen, struct tree_cache **options, unsigned char *priority_list, int priority_len, int first_cutoff, int second_cutoff, int terminate) { int bufix = 0, option_stored[256], i, ix, tto; /* Zero out the stored-lengths array. */ memset(option_stored, 0, sizeof(option_stored)); /* * Copy out the options in the order that they appear in the * priority list... */ for (i = 0; i < priority_len; i++) { /* Code for next option to try to store. */ int code = priority_list[i]; int optstart; /* * Number of bytes left to store (some may already have * been stored by a previous pass). */ int length; /* If no data is available for this option, skip it. */ if (!options[code]) { continue; } /* * The client could ask for things that are mandatory, * in which case we should avoid storing them twice... */ if (option_stored[code]) continue; option_stored[code] = 1; /* We should now have a constant length for the option. */ length = options[code]->len; /* Do we add a NUL? */ if (terminate && dhcp_options[code].format[0] == 't') { length++; tto = 1; } else tto = 0; /* Try to store the option. */ /* * If the option's length is more than 255, we must * store it in multiple hunks. Store 255-byte hunks * first. However, in any case, if the option data will * cross a buffer boundary, split it across that * boundary. */ ix = 0; optstart = bufix; while (length) { unsigned char incr = length > 255 ? 255 : length; /* * If this hunk of the buffer will cross a * boundary, only go up to the boundary in this * pass. */ if (bufix < first_cutoff && bufix + incr > first_cutoff) incr = first_cutoff - bufix; else if (bufix < second_cutoff && bufix + incr > second_cutoff) incr = second_cutoff - bufix; /* * If this option is going to overflow the * buffer, skip it. */ if (bufix + 2 + incr > buflen) { bufix = optstart; break; } /* Everything looks good - copy it in! */ buffer[bufix] = code; buffer[bufix + 1] = incr; if (tto && incr == length) { memcpy(buffer + bufix + 2, options[code]->value + ix, incr - 1); buffer[bufix + 2 + incr - 1] = 0; } else memcpy(buffer + bufix + 2, options[code]->value + ix, incr); length -= incr; ix += incr; bufix += 2 + incr; } } return (bufix); } /* * Format the specified option so that a human can easily read it. */ -char * +const char * pretty_print_option(unsigned int code, unsigned char *data, int len, int emit_commas, int emit_quotes) { static char optbuf[32768]; /* XXX */ int hunksize = 0, numhunk = -1, numelem = 0; char fmtbuf[32], *op = optbuf; int i, j, k, opleft = sizeof(optbuf); unsigned char *dp = data; struct in_addr foo; char comma; /* Code should be between 0 and 255. */ if (code > 255) error("pretty_print_option: bad code %d", code); if (emit_commas) comma = ','; else comma = ' '; /* Figure out the size of the data. */ for (i = 0; dhcp_options[code].format[i]; i++) { if (!numhunk) { warning("%s: Excess information in format string: %s", dhcp_options[code].name, &(dhcp_options[code].format[i])); break; } numelem++; fmtbuf[i] = dhcp_options[code].format[i]; switch (dhcp_options[code].format[i]) { case 'A': --numelem; fmtbuf[i] = 0; numhunk = 0; break; case 'X': for (k = 0; k < len; k++) if (!isascii(data[k]) || !isprint(data[k])) break; if (k == len) { fmtbuf[i] = 't'; numhunk = -2; } else { fmtbuf[i] = 'x'; hunksize++; comma = ':'; numhunk = 0; } fmtbuf[i + 1] = 0; break; case 't': fmtbuf[i] = 't'; fmtbuf[i + 1] = 0; numhunk = -2; break; case 'I': case 'l': case 'L': hunksize += 4; break; case 's': case 'S': hunksize += 2; break; case 'b': case 'B': case 'f': hunksize++; break; case 'e': break; default: warning("%s: garbage in format string: %s", dhcp_options[code].name, &(dhcp_options[code].format[i])); break; } } /* Check for too few bytes... */ if (hunksize > len) { warning("%s: expecting at least %d bytes; got %d", dhcp_options[code].name, hunksize, len); return (""); } /* Check for too many bytes... */ if (numhunk == -1 && hunksize < len) warning("%s: %d extra bytes", dhcp_options[code].name, len - hunksize); /* If this is an array, compute its size. */ if (!numhunk) numhunk = len / hunksize; /* See if we got an exact number of hunks. */ if (numhunk > 0 && numhunk * hunksize < len) warning("%s: %d extra bytes at end of array", dhcp_options[code].name, len - numhunk * hunksize); /* A one-hunk array prints the same as a single hunk. */ if (numhunk < 0) numhunk = 1; /* Cycle through the array (or hunk) printing the data. */ for (i = 0; i < numhunk; i++) { for (j = 0; j < numelem; j++) { int opcount; switch (fmtbuf[j]) { case 't': if (emit_quotes) { *op++ = '"'; opleft--; } for (; dp < data + len; dp++) { if (!isascii(*dp) || !isprint(*dp)) { if (dp + 1 != data + len || *dp != 0) { snprintf(op, opleft, "\\%03o", *dp); op += 4; opleft -= 4; } } else if (*dp == '"' || *dp == '\'' || *dp == '$' || *dp == '`' || *dp == '\\') { *op++ = '\\'; *op++ = *dp; opleft -= 2; } else { *op++ = *dp; opleft--; } } if (emit_quotes) { *op++ = '"'; opleft--; } *op = 0; break; case 'I': foo.s_addr = htonl(getULong(dp)); opcount = strlcpy(op, inet_ntoa(foo), opleft); if (opcount >= opleft) goto toobig; opleft -= opcount; dp += 4; break; case 'l': opcount = snprintf(op, opleft, "%ld", (long)getLong(dp)); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; dp += 4; break; case 'L': opcount = snprintf(op, opleft, "%lu", (unsigned long)getULong(dp)); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; dp += 4; break; case 's': opcount = snprintf(op, opleft, "%d", getShort(dp)); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; dp += 2; break; case 'S': opcount = snprintf(op, opleft, "%u", getUShort(dp)); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; dp += 2; break; case 'b': opcount = snprintf(op, opleft, "%d", *(char *)dp++); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; break; case 'B': opcount = snprintf(op, opleft, "%d", *dp++); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; break; case 'x': opcount = snprintf(op, opleft, "%x", *dp++); if (opcount >= opleft || opcount == -1) goto toobig; opleft -= opcount; break; case 'f': opcount = strlcpy(op, *dp++ ? "true" : "false", opleft); if (opcount >= opleft) goto toobig; opleft -= opcount; break; default: warning("Unexpected format code %c", fmtbuf[j]); } op += strlen(op); opleft -= strlen(op); if (opleft < 1) goto toobig; if (j + 1 < numelem && comma != ':') { *op++ = ' '; opleft--; } } if (i + 1 < numhunk) { *op++ = comma; opleft--; } if (opleft < 1) goto toobig; } return (optbuf); toobig: warning("dhcp option too large"); return (""); } void do_packet(struct interface_info *interface, struct dhcp_packet *packet, int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom) { struct packet tp; int i; if (packet->hlen > sizeof(packet->chaddr)) { note("Discarding packet with invalid hlen."); return; } memset(&tp, 0, sizeof(tp)); tp.raw = packet; tp.packet_length = len; tp.client_port = from_port; tp.client_addr = from; tp.interface = interface; tp.haddr = hfrom; parse_options(&tp); if (tp.options_valid && tp.options[DHO_DHCP_MESSAGE_TYPE].data) tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0]; if (tp.packet_type) dhcp(&tp); else bootp(&tp); /* Free the data associated with the options. */ for (i = 0; i < 256; i++) if (tp.options[i].len && tp.options[i].data) free(tp.options[i].data); } Index: stable/11/sbin/dhclient/privsep.c =================================================================== --- stable/11/sbin/dhclient/privsep.c (revision 332601) +++ stable/11/sbin/dhclient/privsep.c (revision 332602) @@ -1,250 +1,250 @@ /* $OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */ /* * Copyright (c) 2004 Henning Brauer * * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "privsep.h" struct buf * buf_open(size_t len) { struct buf *buf; if ((buf = calloc(1, sizeof(struct buf))) == NULL) return (NULL); if ((buf->buf = malloc(len)) == NULL) { free(buf); return (NULL); } buf->size = len; return (buf); } int -buf_add(struct buf *buf, void *data, size_t len) +buf_add(struct buf *buf, const void *data, size_t len) { if (buf->wpos + len > buf->size) return (-1); memcpy(buf->buf + buf->wpos, data, len); buf->wpos += len; return (0); } int buf_close(int sock, struct buf *buf) { ssize_t n; do { n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos); if (n != -1) buf->rpos += n; if (n == 0) { /* connection closed */ errno = 0; return (-1); } } while (n == -1 && (errno == EAGAIN || errno == EINTR)); if (buf->rpos < buf->size) error("short write: wanted %lu got %ld bytes", (unsigned long)buf->size, (long)buf->rpos); free(buf->buf); free(buf); return (n); } ssize_t buf_read(int sock, void *buf, size_t nbytes) { ssize_t n; size_t r = 0; char *p = buf; do { n = read(sock, p, nbytes); if (n == 0) error("connection closed"); if (n != -1) { r += (size_t)n; p += n; nbytes -= n; } } while (n == -1 && (errno == EINTR || errno == EAGAIN)); if (n == -1) error("buf_read: %m"); if (r < nbytes) error("short read: wanted %lu got %ld bytes", (unsigned long)nbytes, (long)r); return (r); } void dispatch_imsg(struct interface_info *ifi, int fd) { struct imsg_hdr hdr; char *medium, *reason, *filename, *servername, *prefix; size_t medium_len, reason_len, filename_len, servername_len, optlen, prefix_len, totlen; struct client_lease lease; int ret, i; struct buf *buf; u_int16_t mtu; buf_read(fd, &hdr, sizeof(hdr)); switch (hdr.code) { case IMSG_SCRIPT_INIT: if (hdr.len < sizeof(hdr) + sizeof(size_t)) error("corrupted message received"); buf_read(fd, &medium_len, sizeof(medium_len)); if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr) + sizeof(size_t) || medium_len == SIZE_T_MAX) error("corrupted message received"); if (medium_len > 0) { if ((medium = calloc(1, medium_len + 1)) == NULL) error("%m"); buf_read(fd, medium, medium_len); } else medium = NULL; buf_read(fd, &reason_len, sizeof(reason_len)); if (hdr.len < medium_len + reason_len + sizeof(hdr) || reason_len == SIZE_T_MAX) error("corrupted message received"); if (reason_len > 0) { if ((reason = calloc(1, reason_len + 1)) == NULL) error("%m"); buf_read(fd, reason, reason_len); } else reason = NULL; priv_script_init(reason, medium); free(reason); free(medium); break; case IMSG_SCRIPT_WRITE_PARAMS: bzero(&lease, sizeof lease); totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t); if (hdr.len < totlen) error("corrupted message received"); buf_read(fd, &lease, sizeof(lease)); buf_read(fd, &filename_len, sizeof(filename_len)); totlen += filename_len + sizeof(size_t); if (hdr.len < totlen || filename_len == SIZE_T_MAX) error("corrupted message received"); if (filename_len > 0) { if ((filename = calloc(1, filename_len + 1)) == NULL) error("%m"); buf_read(fd, filename, filename_len); } else filename = NULL; buf_read(fd, &servername_len, sizeof(servername_len)); totlen += servername_len + sizeof(size_t); if (hdr.len < totlen || servername_len == SIZE_T_MAX) error("corrupted message received"); if (servername_len > 0) { if ((servername = calloc(1, servername_len + 1)) == NULL) error("%m"); buf_read(fd, servername, servername_len); } else servername = NULL; buf_read(fd, &prefix_len, sizeof(prefix_len)); totlen += prefix_len; if (hdr.len < totlen || prefix_len == SIZE_T_MAX) error("corrupted message received"); if (prefix_len > 0) { if ((prefix = calloc(1, prefix_len + 1)) == NULL) error("%m"); buf_read(fd, prefix, prefix_len); } else prefix = NULL; for (i = 0; i < 256; i++) { totlen += sizeof(optlen); if (hdr.len < totlen) error("corrupted message received"); buf_read(fd, &optlen, sizeof(optlen)); lease.options[i].data = NULL; lease.options[i].len = optlen; if (optlen > 0) { totlen += optlen; if (hdr.len < totlen || optlen == SIZE_T_MAX) error("corrupted message received"); lease.options[i].data = calloc(1, optlen + 1); if (lease.options[i].data == NULL) error("%m"); buf_read(fd, lease.options[i].data, optlen); } } lease.server_name = servername; lease.filename = filename; priv_script_write_params(prefix, &lease); free(servername); free(filename); free(prefix); for (i = 0; i < 256; i++) if (lease.options[i].len > 0) free(lease.options[i].data); break; case IMSG_SCRIPT_GO: if (hdr.len != sizeof(hdr)) error("corrupted message received"); ret = priv_script_go(); hdr.code = IMSG_SCRIPT_GO_RET; hdr.len = sizeof(struct imsg_hdr) + sizeof(int); if ((buf = buf_open(hdr.len)) == NULL) error("buf_open: %m"); if (buf_add(buf, &hdr, sizeof(hdr))) error("buf_add: %m"); if (buf_add(buf, &ret, sizeof(ret))) error("buf_add: %m"); if (buf_close(fd, buf) == -1) error("buf_close: %m"); break; case IMSG_SEND_PACKET: send_packet_priv(ifi, &hdr, fd); break; case IMSG_SET_INTERFACE_MTU: if (hdr.len < sizeof(hdr) + sizeof(u_int16_t)) error("corrupted message received"); buf_read(fd, &mtu, sizeof(u_int16_t)); interface_set_mtu_priv(ifi->name, mtu); break; default: error("received unknown message, code %d", hdr.code); } } Index: stable/11/sbin/dhclient/privsep.h =================================================================== --- stable/11/sbin/dhclient/privsep.h (revision 332601) +++ stable/11/sbin/dhclient/privsep.h (revision 332602) @@ -1,51 +1,51 @@ /* $OpenBSD: privsep.h,v 1.2 2004/05/04 18:51:18 henning Exp $ */ /* * Copyright (c) 2004 Henning Brauer * * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include #include #include struct buf { u_char *buf; size_t size; size_t wpos; size_t rpos; }; enum imsg_code { IMSG_NONE, IMSG_SCRIPT_INIT, IMSG_SCRIPT_WRITE_PARAMS, IMSG_SCRIPT_GO, IMSG_SCRIPT_GO_RET, IMSG_SEND_PACKET, IMSG_SET_INTERFACE_MTU, }; struct imsg_hdr { enum imsg_code code; size_t len; }; struct buf *buf_open(size_t); -int buf_add(struct buf *, void *, size_t); +int buf_add(struct buf *, const void *, size_t); int buf_close(int, struct buf *); ssize_t buf_read(int sock, void *, size_t); Index: stable/11/sbin/dhclient/tables.c =================================================================== --- stable/11/sbin/dhclient/tables.c (revision 332601) +++ stable/11/sbin/dhclient/tables.c (revision 332602) @@ -1,447 +1,447 @@ /* $OpenBSD: tables.c,v 1.4 2004/05/04 20:28:40 deraadt Exp $ */ /* Tables of information... */ /* * Copyright (c) 1995, 1996 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #include __FBSDID("$FreeBSD$"); #include "dhcpd.h" /* * DHCP Option names, formats and codes, from RFC1533. * * Format codes: * * e - end of data * I - IP address * l - 32-bit signed integer * L - 32-bit unsigned integer * s - 16-bit signed integer * S - 16-bit unsigned integer * b - 8-bit signed integer * B - 8-bit unsigned integer * t - ASCII text * f - flag (true or false) * A - array of whatever precedes (e.g., IA means array of IP addresses) */ struct universe dhcp_universe; struct option dhcp_options[256] = { { "pad", "", &dhcp_universe, 0 }, { "subnet-mask", "I", &dhcp_universe, 1 }, { "time-offset", "l", &dhcp_universe, 2 }, { "routers", "IA", &dhcp_universe, 3 }, { "time-servers", "IA", &dhcp_universe, 4 }, { "ien116-name-servers", "IA", &dhcp_universe, 5 }, { "domain-name-servers", "IA", &dhcp_universe, 6 }, { "log-servers", "IA", &dhcp_universe, 7 }, { "cookie-servers", "IA", &dhcp_universe, 8 }, { "lpr-servers", "IA", &dhcp_universe, 9 }, { "impress-servers", "IA", &dhcp_universe, 10 }, { "resource-location-servers", "IA", &dhcp_universe, 11 }, { "host-name", "t", &dhcp_universe, 12 }, { "boot-size", "S", &dhcp_universe, 13 }, { "merit-dump", "t", &dhcp_universe, 14 }, { "domain-name", "t", &dhcp_universe, 15 }, { "swap-server", "I", &dhcp_universe, 16 }, { "root-path", "t", &dhcp_universe, 17 }, { "extensions-path", "t", &dhcp_universe, 18 }, { "ip-forwarding", "f", &dhcp_universe, 19 }, { "non-local-source-routing", "f", &dhcp_universe, 20 }, { "policy-filter", "IIA", &dhcp_universe, 21 }, { "max-dgram-reassembly", "S", &dhcp_universe, 22 }, { "default-ip-ttl", "B", &dhcp_universe, 23 }, { "path-mtu-aging-timeout", "L", &dhcp_universe, 24 }, { "path-mtu-plateau-table", "SA", &dhcp_universe, 25 }, { "interface-mtu", "S", &dhcp_universe, 26 }, { "all-subnets-local", "f", &dhcp_universe, 27 }, { "broadcast-address", "I", &dhcp_universe, 28 }, { "perform-mask-discovery", "f", &dhcp_universe, 29 }, { "mask-supplier", "f", &dhcp_universe, 30 }, { "router-discovery", "f", &dhcp_universe, 31 }, { "router-solicitation-address", "I", &dhcp_universe, 32 }, { "static-routes", "IIA", &dhcp_universe, 33 }, { "trailer-encapsulation", "f", &dhcp_universe, 34 }, { "arp-cache-timeout", "L", &dhcp_universe, 35 }, { "ieee802-3-encapsulation", "f", &dhcp_universe, 36 }, { "default-tcp-ttl", "B", &dhcp_universe, 37 }, { "tcp-keepalive-interval", "L", &dhcp_universe, 38 }, { "tcp-keepalive-garbage", "f", &dhcp_universe, 39 }, { "nis-domain", "t", &dhcp_universe, 40 }, { "nis-servers", "IA", &dhcp_universe, 41 }, { "ntp-servers", "IA", &dhcp_universe, 42 }, { "vendor-encapsulated-options", "X", &dhcp_universe, 43 }, { "netbios-name-servers", "IA", &dhcp_universe, 44 }, { "netbios-dd-server", "IA", &dhcp_universe, 45 }, { "netbios-node-type", "B", &dhcp_universe, 46 }, { "netbios-scope", "t", &dhcp_universe, 47 }, { "font-servers", "IA", &dhcp_universe, 48 }, { "x-display-manager", "IA", &dhcp_universe, 49 }, { "dhcp-requested-address", "I", &dhcp_universe, 50 }, { "dhcp-lease-time", "L", &dhcp_universe, 51 }, { "dhcp-option-overload", "B", &dhcp_universe, 52 }, { "dhcp-message-type", "B", &dhcp_universe, 53 }, { "dhcp-server-identifier", "I", &dhcp_universe, 54 }, { "dhcp-parameter-request-list", "BA", &dhcp_universe, 55 }, { "dhcp-message", "t", &dhcp_universe, 56 }, { "dhcp-max-message-size", "S", &dhcp_universe, 57 }, { "dhcp-renewal-time", "L", &dhcp_universe, 58 }, { "dhcp-rebinding-time", "L", &dhcp_universe, 59 }, { "dhcp-class-identifier", "t", &dhcp_universe, 60 }, { "dhcp-client-identifier", "X", &dhcp_universe, 61 }, { "option-62", "X", &dhcp_universe, 62 }, { "option-63", "X", &dhcp_universe, 63 }, { "nisplus-domain", "t", &dhcp_universe, 64 }, { "nisplus-servers", "IA", &dhcp_universe, 65 }, { "tftp-server-name", "t", &dhcp_universe, 66 }, { "bootfile-name", "t", &dhcp_universe, 67 }, { "mobile-ip-home-agent", "IA", &dhcp_universe, 68 }, { "smtp-server", "IA", &dhcp_universe, 69 }, { "pop-server", "IA", &dhcp_universe, 70 }, { "nntp-server", "IA", &dhcp_universe, 71 }, { "www-server", "IA", &dhcp_universe, 72 }, { "finger-server", "IA", &dhcp_universe, 73 }, { "irc-server", "IA", &dhcp_universe, 74 }, { "streettalk-server", "IA", &dhcp_universe, 75 }, { "streettalk-directory-assistance-server", "IA", &dhcp_universe, 76 }, { "user-class", "t", &dhcp_universe, 77 }, { "option-78", "X", &dhcp_universe, 78 }, { "option-79", "X", &dhcp_universe, 79 }, { "option-80", "X", &dhcp_universe, 80 }, { "option-81", "X", &dhcp_universe, 81 }, { "option-82", "X", &dhcp_universe, 82 }, { "option-83", "X", &dhcp_universe, 83 }, { "option-84", "X", &dhcp_universe, 84 }, { "nds-servers", "IA", &dhcp_universe, 85 }, { "nds-tree-name", "X", &dhcp_universe, 86 }, { "nds-context", "X", &dhcp_universe, 87 }, { "option-88", "X", &dhcp_universe, 88 }, { "option-89", "X", &dhcp_universe, 89 }, { "option-90", "X", &dhcp_universe, 90 }, { "option-91", "X", &dhcp_universe, 91 }, { "option-92", "X", &dhcp_universe, 92 }, { "option-93", "X", &dhcp_universe, 93 }, { "option-94", "X", &dhcp_universe, 94 }, { "option-95", "X", &dhcp_universe, 95 }, { "option-96", "X", &dhcp_universe, 96 }, { "option-97", "X", &dhcp_universe, 97 }, { "option-98", "X", &dhcp_universe, 98 }, { "option-99", "X", &dhcp_universe, 99 }, { "option-100", "X", &dhcp_universe, 100 }, { "option-101", "X", &dhcp_universe, 101 }, { "option-102", "X", &dhcp_universe, 102 }, { "option-103", "X", &dhcp_universe, 103 }, { "option-104", "X", &dhcp_universe, 104 }, { "option-105", "X", &dhcp_universe, 105 }, { "option-106", "X", &dhcp_universe, 106 }, { "option-107", "X", &dhcp_universe, 107 }, { "option-108", "X", &dhcp_universe, 108 }, { "option-109", "X", &dhcp_universe, 109 }, { "option-110", "X", &dhcp_universe, 110 }, { "option-111", "X", &dhcp_universe, 111 }, { "option-112", "X", &dhcp_universe, 112 }, { "option-113", "X", &dhcp_universe, 113 }, { "option-114", "X", &dhcp_universe, 114 }, { "option-115", "X", &dhcp_universe, 115 }, { "option-116", "X", &dhcp_universe, 116 }, { "option-117", "X", &dhcp_universe, 117 }, { "option-118", "X", &dhcp_universe, 118 }, { "domain-search", "t", &dhcp_universe, 119 }, { "option-120", "X", &dhcp_universe, 120 }, { "classless-routes", "BA", &dhcp_universe, 121 }, { "option-122", "X", &dhcp_universe, 122 }, { "option-123", "X", &dhcp_universe, 123 }, { "option-124", "X", &dhcp_universe, 124 }, { "option-125", "X", &dhcp_universe, 125 }, { "option-126", "X", &dhcp_universe, 126 }, { "option-127", "X", &dhcp_universe, 127 }, { "option-128", "X", &dhcp_universe, 128 }, { "option-129", "X", &dhcp_universe, 129 }, { "option-130", "X", &dhcp_universe, 130 }, { "option-131", "X", &dhcp_universe, 131 }, { "option-132", "X", &dhcp_universe, 132 }, { "option-133", "X", &dhcp_universe, 133 }, { "option-134", "X", &dhcp_universe, 134 }, { "option-135", "X", &dhcp_universe, 135 }, { "option-136", "X", &dhcp_universe, 136 }, { "option-137", "X", &dhcp_universe, 137 }, { "option-138", "X", &dhcp_universe, 138 }, { "option-139", "X", &dhcp_universe, 139 }, { "option-140", "X", &dhcp_universe, 140 }, { "option-141", "X", &dhcp_universe, 141 }, { "option-142", "X", &dhcp_universe, 142 }, { "option-143", "X", &dhcp_universe, 143 }, { "option-144", "X", &dhcp_universe, 144 }, { "option-145", "X", &dhcp_universe, 145 }, { "option-146", "X", &dhcp_universe, 146 }, { "option-147", "X", &dhcp_universe, 147 }, { "option-148", "X", &dhcp_universe, 148 }, { "option-149", "X", &dhcp_universe, 149 }, { "option-150", "X", &dhcp_universe, 150 }, { "option-151", "X", &dhcp_universe, 151 }, { "option-152", "X", &dhcp_universe, 152 }, { "option-153", "X", &dhcp_universe, 153 }, { "option-154", "X", &dhcp_universe, 154 }, { "option-155", "X", &dhcp_universe, 155 }, { "option-156", "X", &dhcp_universe, 156 }, { "option-157", "X", &dhcp_universe, 157 }, { "option-158", "X", &dhcp_universe, 158 }, { "option-159", "X", &dhcp_universe, 159 }, { "option-160", "X", &dhcp_universe, 160 }, { "option-161", "X", &dhcp_universe, 161 }, { "option-162", "X", &dhcp_universe, 162 }, { "option-163", "X", &dhcp_universe, 163 }, { "option-164", "X", &dhcp_universe, 164 }, { "option-165", "X", &dhcp_universe, 165 }, { "option-166", "X", &dhcp_universe, 166 }, { "option-167", "X", &dhcp_universe, 167 }, { "option-168", "X", &dhcp_universe, 168 }, { "option-169", "X", &dhcp_universe, 169 }, { "option-170", "X", &dhcp_universe, 170 }, { "option-171", "X", &dhcp_universe, 171 }, { "option-172", "X", &dhcp_universe, 172 }, { "option-173", "X", &dhcp_universe, 173 }, { "option-174", "X", &dhcp_universe, 174 }, { "option-175", "X", &dhcp_universe, 175 }, { "option-176", "X", &dhcp_universe, 176 }, { "option-177", "X", &dhcp_universe, 177 }, { "option-178", "X", &dhcp_universe, 178 }, { "option-179", "X", &dhcp_universe, 179 }, { "option-180", "X", &dhcp_universe, 180 }, { "option-181", "X", &dhcp_universe, 181 }, { "option-182", "X", &dhcp_universe, 182 }, { "option-183", "X", &dhcp_universe, 183 }, { "option-184", "X", &dhcp_universe, 184 }, { "option-185", "X", &dhcp_universe, 185 }, { "option-186", "X", &dhcp_universe, 186 }, { "option-187", "X", &dhcp_universe, 187 }, { "option-188", "X", &dhcp_universe, 188 }, { "option-189", "X", &dhcp_universe, 189 }, { "option-190", "X", &dhcp_universe, 190 }, { "option-191", "X", &dhcp_universe, 191 }, { "option-192", "X", &dhcp_universe, 192 }, { "option-193", "X", &dhcp_universe, 193 }, { "option-194", "X", &dhcp_universe, 194 }, { "option-195", "X", &dhcp_universe, 195 }, { "option-196", "X", &dhcp_universe, 196 }, { "option-197", "X", &dhcp_universe, 197 }, { "option-198", "X", &dhcp_universe, 198 }, { "option-199", "X", &dhcp_universe, 199 }, { "option-200", "X", &dhcp_universe, 200 }, { "option-201", "X", &dhcp_universe, 201 }, { "option-202", "X", &dhcp_universe, 202 }, { "option-203", "X", &dhcp_universe, 203 }, { "option-204", "X", &dhcp_universe, 204 }, { "option-205", "X", &dhcp_universe, 205 }, { "option-206", "X", &dhcp_universe, 206 }, { "option-207", "X", &dhcp_universe, 207 }, { "option-208", "X", &dhcp_universe, 208 }, { "option-209", "X", &dhcp_universe, 209 }, { "option-210", "X", &dhcp_universe, 210 }, { "option-211", "X", &dhcp_universe, 211 }, { "option-212", "X", &dhcp_universe, 212 }, { "option-213", "X", &dhcp_universe, 213 }, { "option-214", "X", &dhcp_universe, 214 }, { "option-215", "X", &dhcp_universe, 215 }, { "option-216", "X", &dhcp_universe, 216 }, { "option-217", "X", &dhcp_universe, 217 }, { "option-218", "X", &dhcp_universe, 218 }, { "option-219", "X", &dhcp_universe, 219 }, { "option-220", "X", &dhcp_universe, 220 }, { "option-221", "X", &dhcp_universe, 221 }, { "option-222", "X", &dhcp_universe, 222 }, { "option-223", "X", &dhcp_universe, 223 }, { "option-224", "X", &dhcp_universe, 224 }, { "option-225", "X", &dhcp_universe, 225 }, { "option-226", "X", &dhcp_universe, 226 }, { "option-227", "X", &dhcp_universe, 227 }, { "option-228", "X", &dhcp_universe, 228 }, { "option-229", "X", &dhcp_universe, 229 }, { "option-230", "X", &dhcp_universe, 230 }, { "option-231", "X", &dhcp_universe, 231 }, { "option-232", "X", &dhcp_universe, 232 }, { "option-233", "X", &dhcp_universe, 233 }, { "option-234", "X", &dhcp_universe, 234 }, { "option-235", "X", &dhcp_universe, 235 }, { "option-236", "X", &dhcp_universe, 236 }, { "option-237", "X", &dhcp_universe, 237 }, { "option-238", "X", &dhcp_universe, 238 }, { "option-239", "X", &dhcp_universe, 239 }, { "option-240", "X", &dhcp_universe, 240 }, { "option-241", "X", &dhcp_universe, 241 }, { "option-242", "X", &dhcp_universe, 242 }, { "option-243", "X", &dhcp_universe, 243 }, { "option-244", "X", &dhcp_universe, 244 }, { "option-245", "X", &dhcp_universe, 245 }, { "option-246", "X", &dhcp_universe, 246 }, { "option-247", "X", &dhcp_universe, 247 }, { "option-248", "X", &dhcp_universe, 248 }, { "option-249", "X", &dhcp_universe, 249 }, { "option-250", "X", &dhcp_universe, 250 }, { "option-251", "X", &dhcp_universe, 251 }, { "option-252", "X", &dhcp_universe, 252 }, { "option-253", "X", &dhcp_universe, 253 }, { "option-254", "X", &dhcp_universe, 254 }, { "option-end", "e", &dhcp_universe, 255 }, }; /* * Default dhcp option priority list (this is ad hoc and should not be * mistaken for a carefully crafted and optimized list). */ unsigned char dhcp_option_default_priority_list[] = { DHO_DHCP_REQUESTED_ADDRESS, DHO_DHCP_OPTION_OVERLOAD, DHO_DHCP_MAX_MESSAGE_SIZE, DHO_DHCP_RENEWAL_TIME, DHO_DHCP_REBINDING_TIME, DHO_DHCP_CLASS_IDENTIFIER, DHO_DHCP_CLIENT_IDENTIFIER, DHO_SUBNET_MASK, DHO_TIME_OFFSET, DHO_CLASSLESS_ROUTES, DHO_ROUTERS, DHO_TIME_SERVERS, DHO_NAME_SERVERS, DHO_DOMAIN_NAME_SERVERS, DHO_HOST_NAME, DHO_LOG_SERVERS, DHO_COOKIE_SERVERS, DHO_LPR_SERVERS, DHO_IMPRESS_SERVERS, DHO_RESOURCE_LOCATION_SERVERS, DHO_HOST_NAME, DHO_BOOT_SIZE, DHO_MERIT_DUMP, DHO_DOMAIN_NAME, DHO_SWAP_SERVER, DHO_ROOT_PATH, DHO_EXTENSIONS_PATH, DHO_IP_FORWARDING, DHO_NON_LOCAL_SOURCE_ROUTING, DHO_POLICY_FILTER, DHO_MAX_DGRAM_REASSEMBLY, DHO_DEFAULT_IP_TTL, DHO_PATH_MTU_AGING_TIMEOUT, DHO_PATH_MTU_PLATEAU_TABLE, DHO_INTERFACE_MTU, DHO_ALL_SUBNETS_LOCAL, DHO_BROADCAST_ADDRESS, DHO_PERFORM_MASK_DISCOVERY, DHO_MASK_SUPPLIER, DHO_ROUTER_DISCOVERY, DHO_ROUTER_SOLICITATION_ADDRESS, DHO_STATIC_ROUTES, DHO_TRAILER_ENCAPSULATION, DHO_ARP_CACHE_TIMEOUT, DHO_IEEE802_3_ENCAPSULATION, DHO_DEFAULT_TCP_TTL, DHO_TCP_KEEPALIVE_INTERVAL, DHO_TCP_KEEPALIVE_GARBAGE, DHO_NIS_DOMAIN, DHO_NIS_SERVERS, DHO_NTP_SERVERS, DHO_VENDOR_ENCAPSULATED_OPTIONS, DHO_NETBIOS_NAME_SERVERS, DHO_NETBIOS_DD_SERVER, DHO_NETBIOS_NODE_TYPE, DHO_NETBIOS_SCOPE, DHO_FONT_SERVERS, DHO_X_DISPLAY_MANAGER, DHO_DHCP_PARAMETER_REQUEST_LIST, DHO_NISPLUS_DOMAIN, DHO_NISPLUS_SERVERS, DHO_TFTP_SERVER_NAME, DHO_BOOTFILE_NAME, DHO_MOBILE_IP_HOME_AGENT, DHO_SMTP_SERVER, DHO_POP_SERVER, DHO_NNTP_SERVER, DHO_WWW_SERVER, DHO_FINGER_SERVER, DHO_IRC_SERVER, DHO_STREETTALK_SERVER, DHO_STREETTALK_DA_SERVER, DHO_DOMAIN_SEARCH, /* Presently-undefined options... */ 62, 63, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, }; int sizeof_dhcp_option_default_priority_list = sizeof(dhcp_option_default_priority_list); struct hash_table universe_hash; void initialize_universes(void) { int i; dhcp_universe.name = "dhcp"; dhcp_universe.hash = new_hash(); if (!dhcp_universe.hash) error("Can't allocate dhcp option hash table."); for (i = 0; i < 256; i++) { dhcp_universe.options[i] = &dhcp_options[i]; add_hash(dhcp_universe.hash, - (unsigned char *)dhcp_options[i].name, 0, + (const unsigned char *)dhcp_options[i].name, 0, (unsigned char *)&dhcp_options[i]); } universe_hash.hash_count = DEFAULT_HASH_SIZE; add_hash(&universe_hash, - (unsigned char *)dhcp_universe.name, 0, + (const unsigned char *)dhcp_universe.name, 0, (unsigned char *)&dhcp_universe); } Index: stable/11/sbin/dhclient/tests/fake.c =================================================================== --- stable/11/sbin/dhclient/tests/fake.c (revision 332601) +++ stable/11/sbin/dhclient/tests/fake.c (revision 332602) @@ -1,63 +1,63 @@ /* $FreeBSD$ */ #include #include #include #include "dhcpd.h" extern jmp_buf env; void -error(char *fmt, ...) +error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); longjmp(env, 1); } int -warning(char *fmt, ...) +warning(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void)vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); /* * The original warning() would return "ret" here. We do this to * check warnings explicitely. */ longjmp(env, 1); } int -note(char *fmt, ...) +note(const char *fmt, ...) { int ret; va_list ap; va_start(ap, fmt); ret = vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); return ret; } void bootp(struct packet *packet) { } void dhcp(struct packet *packet) { } Index: stable/11/sbin/dhclient/tree.h =================================================================== --- stable/11/sbin/dhclient/tree.h (revision 332601) +++ stable/11/sbin/dhclient/tree.h (revision 332602) @@ -1,70 +1,70 @@ /* $OpenBSD: tree.h,v 1.5 2004/05/06 22:29:15 deraadt Exp $ */ /* Definitions for address trees... */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1995 The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. * * $FreeBSD$ */ /* A pair of pointers, suitable for making a linked list. */ typedef struct _pair { caddr_t car; struct _pair *cdr; } *pair; struct tree_cache { unsigned char *value; int len; int buf_size; time_t timeout; }; struct universe { - char *name; + const char *name; struct hash_table *hash; struct option *options[256]; }; struct option { - char *name; - char *format; + const char *name; + const char *format; struct universe *universe; unsigned char code; }; Index: stable/11 =================================================================== --- stable/11 (revision 332601) +++ stable/11 (revision 332602) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r329754