diff options
author | Ted Lemon <source@isc.org> | 1998-06-25 03:02:50 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1998-06-25 03:02:50 +0000 |
commit | b480793829ea3443252e92726cc8f3d81d611bb2 (patch) | |
tree | 7ed8ab06e5d51244c9e744bc9238e6acf97291cb | |
parent | 6aba7542e35f91c6dc15d86f91e089ec679b084d (diff) | |
download | isc-dhcp-b480793829ea3443252e92726cc8f3d81d611bb2.tar.gz |
cons_options now takes option_state struct instead of options and agent_options args. Fix bufgfer overflow attack in parameter request list. Change over to expression evaluation code instead of ds tree evaluation code. do_packet now takes a pointer to a dhcp packet instead of a pointer to a character buffer. This fixess another possible overflow. Add per-option-universe lookup and set functions.
-rw-r--r-- | common/options.c | 155 |
1 files changed, 127 insertions, 28 deletions
diff --git a/common/options.c b/common/options.c index 96db7020..89257b6e 100644 --- a/common/options.c +++ b/common/options.c @@ -42,12 +42,16 @@ #ifndef lint static char copyright[] = -"$Id: options.c,v 1.31 1998/04/19 23:19:14 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: options.c,v 1.32 1998/06/25 03:02:50 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #define DHCP_OPTION_DATA #include "dhcpd.h" +static void do_option_set PROTO ((struct option_cache **, + struct option_cache *, + enum statement_op)); + /* Parse all available options out of the specified packet. */ void parse_options (packet) @@ -214,13 +218,12 @@ int parse_agent_information_option (packet, len, data) three seperate buffers if needed. This allows us to cons up a set of vendor options using the same routine. */ -int cons_options (inpacket, outpacket, mms, options, agent_options, +int cons_options (inpacket, outpacket, mms, options, overload, terminate, bootpp) struct packet *inpacket; struct dhcp_packet *outpacket; int mms; - struct tree_cache **options; - struct agent_options *agent_options; + struct option_state *options; int overload; /* Overload flags that may be set. */ int terminate; int bootpp; @@ -283,14 +286,15 @@ int cons_options (inpacket, outpacket, mms, options, agent_options, if (inpacket && inpacket -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data) { + int 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, - inpacket -> options - [DHO_DHCP_PARAMETER_REQUEST_LIST].len); - priority_len += - inpacket -> options - [DHO_DHCP_PARAMETER_REQUEST_LIST].len; + [DHO_DHCP_PARAMETER_REQUEST_LIST].data, prlen); + priority_len += prlen; } else { memcpy (&priority_list [priority_len], dhcp_option_default_priority_list, @@ -303,7 +307,8 @@ int cons_options (inpacket, outpacket, mms, options, agent_options, (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) + ((overload & 2) ? DHCP_SNAME_LEN : 0)), - options, priority_list, priority_len, + options -> dhcp_options, + priority_list, priority_len, main_buffer_size, (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)), @@ -383,7 +388,7 @@ int cons_options (inpacket, outpacket, mms, options, agent_options, /* Cycle through the options, appending them to the buffer. */ - for (a = agent_options; a; a = a -> next) { + for (a = options -> agent_options; a; a = a -> next) { if (agentix + a -> length + 3 + DHCP_FIXED_LEN <= dhcp_max_agent_option_packet_length) { outpacket -> @@ -414,7 +419,7 @@ int store_options (buffer, buflen, options, priority_list, priority_len, first_cutoff, second_cutoff, terminate) unsigned char *buffer; int buflen; - struct tree_cache **options; + struct option_cache **options; unsigned char *priority_list; int priority_len; int first_cutoff, second_cutoff; @@ -425,6 +430,7 @@ int store_options (buffer, buflen, options, priority_list, priority_len, int i; int ix; int tto; + struct data_string od; /* Zero out the stored-lengths array. */ memset (option_stored, 0, sizeof option_stored); @@ -452,16 +458,13 @@ int store_options (buffer, buflen, options, priority_list, priority_len, option_stored [code] = 1; /* Find the value of the option... */ - if (!tree_evaluate (options [code])) { - continue; - } - - /* If it evaluated to nothing, don't send the option. */ - if (!options [code] -> len) + od = evaluate_data_expression ((struct packet *)0, + options [code] -> expression); + if (!od.len) continue; /* We should now have a constant length for the option. */ - length = options [code] -> len; + length = od.len; /* Do we add a NUL? */ if (terminate && dhcp_options [code].format [0] == 't') { @@ -506,17 +509,18 @@ int store_options (buffer, buflen, options, priority_list, priority_len, buffer [bufix + 1] = incr; if (tto && incr == length) { memcpy (buffer + bufix + 2, - options [code] -> value + ix, - incr - 1); + od.data + ix, incr - 1); buffer [bufix + 2 + incr - 1] = 0; } else { memcpy (buffer + bufix + 2, - options [code] -> value + ix, incr); + od.data + ix, incr); } length -= incr; ix += incr; bufix += 2 + incr; } + if (od.buffer) + dfree (od.buffer, "store_options"); } return bufix; } @@ -690,26 +694,28 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes) return optbuf; } -void do_packet (interface, packbuf, len, from_port, from, hfrom) +void do_packet (interface, packet, len, from_port, from, hfrom) struct interface_info *interface; - unsigned char *packbuf; + struct dhcp_packet *packet; int len; unsigned int from_port; struct iaddr from; struct hardware *hfrom; { struct packet tp; - struct dhcp_packet tdp; /* XXX This < 1500 bytes! */ - memcpy (&tdp, packbuf, len); memset (&tp, 0, sizeof tp); - tp.raw = &tdp; + tp.raw = packet; tp.packet_length = len; tp.client_port = from_port; tp.client_addr = from; tp.interface = interface; tp.haddr = hfrom; + if (packet -> hlen > sizeof packet -> chaddr) { + note ("Discarding packet with bogus hardware address length."); + return; + } parse_options (&tp); if (tp.options_valid && tp.options [DHO_DHCP_MESSAGE_TYPE].data) @@ -760,3 +766,96 @@ struct data_string agent_suboption_lookup (packet, code) return result; } +struct data_string server_option_lookup (packet, code) + struct packet *packet; + int code; +{ + struct data_string result; + + result.len = 0; + result.data = (unsigned char *)0; + result.terminated = 0; + result.buffer = (unsigned char *)0; + return result; +} + +void dhcp_option_set (options, option, op) + struct option_state *options; + struct option_cache *option; + enum statement_op op; +{ + struct option_cache *thecache; + + do_option_set (&options -> server_options + [option -> option -> code], option, op); +} + +void server_option_set (options, option, op) + struct option_state *options; + struct option_cache *option; + enum statement_op op; +{ + do_option_set (&options -> server_options + [option -> option -> code], option, op); +} + +static void do_option_set (thecache, option, op) + struct option_cache **thecache; + struct option_cache *option; + enum statement_op op; +{ + struct option_cache *oc; + + switch (op) { + case if_statement: + case add_statement: + case eval_statement: + case break_statement: + default: + warn ("bogus statement type in do_option_set."); + break; + + case default_option_statement: + if (*thecache) + break; + *thecache = option; + break; + + case supersede_option_statement: + /* Free any ephemeral state associated with the + current value. */ + if (*thecache) + free_oc_ephemeral_state (*thecache); + *thecache = option; + break; + + case append_option_statement: + case prepend_option_statement: + if (!*thecache) { + *thecache = option; + break; + } + if (((*thecache) -> expression -> flags) & EXPR_EPHEMERAL) + oc = *thecache; + else { + oc = new_option_cache ("do_option_set"); + if (!oc) { + warn ("can't allocate option cache!"); + break; + } + *oc = **thecache; + } + if (op == append_option_statement) + oc -> expression = + make_concat ((*thecache) -> expression, + option -> expression); + else + oc -> expression = + make_concat (option -> expression, + (*thecache) -> expression); + + oc -> expression -> flags |= EXPR_EPHEMERAL; + *thecache = oc; + break; + } +} |