Commit 4c659fb2 authored by Shawn Routhier's avatar Shawn Routhier
Browse files

Fix some issues in the code for parsing and printing options.

[ISC-Bugs #22625] - properly print options that have several fields
followed by an array of something for example "fIa"
[ISC-Bugs #27289] - properly parse options in declarations that have
several fields followed by an array of something for example "fIa"
[ISC-Bugs #27296] - properly determine if we parsed a 16 or 32 bit
value in evaluate_numeric_expression (extract-int).
[ISC-Bugs #27314] - properly parse a zero length option from
a lease file.  Thanks to Marius Tomaschewski from SUSE for the report
and prototype patch for this ticket as well as ticket 27289.
parent 777df876
......@@ -60,6 +60,17 @@ work on other platforms. Please report any problems and suggested fixes to
for reporting this issue.
[ISC-Bugs #29062]
- Fix some issues in the code for parsing and printing options.
[ISC-Bugs #22625] - properly print options that have several fields
followed by an array of something for example "fIa"
[ISC-Bugs #27289] - properly parse options in declarations that have
several fields followed by an array of something for example "fIa"
[ISC-Bugs #27296] - properly determine if we parsed a 16 or 32 bit
value in evaluate_numeric_expression (extract-int).
[ISC-Bugs #27314] - properly parse a zero length option from
a lease file. Thanks to Marius Tomaschewski from SUSE for the report
and prototype patch for this ticket as well as ticket 27289.
Changes since 4.1-ESV-R5rc2
- None
......
......@@ -2728,10 +2728,21 @@ void write_lease_option (struct option_cache *oc,
}
if (evaluate_option_cache (&ds, packet, lease, client_state,
in_options, cfg_options, scope, oc, MDL)) {
fprintf(leaseFile, "%soption %s%s%s %s;\n", preamble,
name, dot, oc->option->name,
pretty_print_option(oc->option, ds.data, ds.len,
1, 1));
/* The option name */
fprintf(leaseFile, "%soption %s%s%s", preamble,
name, dot, oc->option->name);
/* The option value if there is one */
if ((oc->option->format == NULL) ||
(oc->option->format[0] != 'Z')) {
fprintf(leaseFile, " %s",
pretty_print_option(oc->option, ds.data,
ds.len, 1, 1));
}
/* The closing semi-colon and newline */
fprintf(leaseFile, ";\n");
data_string_forget (&ds, MDL);
}
}
......
......@@ -1677,6 +1677,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
const unsigned char *dp = data;
char comma;
unsigned long tval;
isc_boolean_t a_array = ISC_FALSE;
int len_used;
if (emit_commas)
comma = ',';
......@@ -1701,6 +1703,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
fmtbuf [l] = option -> format [i];
switch (option -> format [i]) {
case 'a':
a_array = ISC_TRUE;
/* Fall through */
case 'A':
--numelem;
fmtbuf [l] = 0;
......@@ -1729,6 +1733,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
hunksize++;
comma = ':';
numhunk = 0;
a_array = ISC_TRUE;
hunkinc = 1;
}
fmtbuf [l + 1] = 0;
break;
......@@ -1822,13 +1828,34 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
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)
log_error ("%s: %d extra bytes at end of array\n",
option -> name,
len - numhunk * hunksize);
if (numhunk == 0) {
if (a_array == ISC_TRUE) {
/*
* It is an 'a' type array - we repeat the
* last format type. A binary string for 'X'
* is also like this. hunkinc is the size
* of the last format type and we add 1 to
* cover the entire first record.
*/
numhunk = ((len - hunksize) / hunkinc) + 1;
len_used = hunksize + ((numhunk - 1) * hunkinc);
} else {
/*
* It is an 'A' type array - we repeat the
* entire record
*/
numhunk = len / hunksize;
len_used = numhunk * hunksize;
}
/* See if we got an exact number of hunks. */
if (len_used < len) {
log_error ("%s: %d extra bytes at end of array\n",
option -> name,
len - len_used);
}
}
/* A one-hunk array prints the same as a single hunk. */
if (numhunk < 0)
......@@ -1836,7 +1863,24 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
/* Cycle through the array (or hunk) printing the data. */
for (i = 0; i < numhunk; i++) {
for (j = 0; j < numelem; j++) {
if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
/*
* For 'a' type of arrays we repeat
* only the last format character
* We should never hit the case of numelem == 0
* but let's include the check to be safe.
*/
j = numelem - 1;
} else {
/*
* for other types of arrays or the first
* time through for 'a' types, we go through
* the entire set of format characters.
*/
j = 0;
}
for (; j < numelem; j++) {
switch (fmtbuf [j]) {
case 't':
/* endbuf-1 leaves room for NULL. */
......
......@@ -5437,11 +5437,26 @@ int parse_option_decl (oc, cfile)
if (status != ISC_R_SUCCESS || option == NULL)
return 0;
fmt = option->format;
/* Parse the option data... */
do {
for (fmt = option -> format; *fmt; fmt++) {
if (*fmt == 'A')
for (; *fmt; fmt++) {
if (*fmt == 'A') {
/* 'A' is an array of records, start at
* the beginning
*/
fmt = option->format;
break;
}
if (*fmt == 'a') {
/* 'a' is an array of the last field,
* back up one format character
*/
fmt--;
break;
}
if (*fmt == 'o' && fmt != option -> format)
continue;
switch (*fmt) {
......@@ -5637,7 +5652,7 @@ int parse_option_decl (oc, cfile)
goto alloc;
case 'Z': /* Zero-length option */
token = next_token(&val, (unsigned *)0, cfile);
token = peek_token(&val, (unsigned *)0, cfile);
if (token != SEMI) {
parse_warn(cfile,
"semicolon expected.");
......@@ -5654,7 +5669,7 @@ int parse_option_decl (oc, cfile)
}
}
token = next_token (&val, (unsigned *)0, cfile);
} while (*fmt == 'A' && token == COMMA);
} while (*fmt && token == COMMA);
if (token != SEMI) {
parse_warn (cfile, "semicolon expected.");
......
......@@ -64,9 +64,10 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option,
some event. The special all-ones value means 'infinite'. May either
be printed as a decimal, eg, "3600", or as this name, eg, "infinite".
f - flag (true or false)
A - array of whatever precedes (e.g., IA means array of IP addresses)
a - array of the preceding character (e.g., IIa means two or more IP
addresses)
A - array of all that precedes (e.g., fIA means array of records of
a flag and an IP address)
a - array of the preceding character (e.g., fIa means a single flag
followed by an array of IP addresses)
U - name of an option space (universe)
F - implicit flag - the presence of the option indicates that the
flag is true.
......
......@@ -3,7 +3,7 @@
Routines for manipulating parse trees... */
/*
* Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
......@@ -2379,6 +2379,7 @@ int evaluate_numeric_expression (result, packet, lease, client_state,
struct binding *binding;
struct binding_value *bv;
unsigned long ileft, iright;
int rc = 0;
switch (expr -> op) {
case expr_check:
......@@ -2446,32 +2447,42 @@ int evaluate_numeric_expression (result, packet, lease, client_state,
status = (evaluate_data_expression
(&data, packet, lease, client_state, in_options,
cfg_options, scope, expr -> data.extract_int, MDL));
if (status && data.len >= 2)
if (status && data.len >= 2) {
*result = getUShort (data.data);
rc = 1;
}
#if defined (DEBUG_EXPRESSIONS)
log_debug ("num: extract_int16 (%s) = %ld",
((status && data.len >= 2) ?
print_hex_1 (data.len, data.data, 60) : "NULL"),
*result);
if (rc == 1) {
log_debug ("num: extract_int16 (%s) = %ld",
print_hex_1(data.len, data.data, 60)
*result);
} else {
log_debug ("num: extract_int16 (NULL) = NULL");
}
#endif
if (status) data_string_forget (&data, MDL);
return (status && data.len >= 2);
return (rc);
case expr_extract_int32:
memset (&data, 0, sizeof data);
status = (evaluate_data_expression
(&data, packet, lease, client_state, in_options,
cfg_options, scope, expr -> data.extract_int, MDL));
if (status && data.len >= 4)
if (status && data.len >= 4) {
*result = getULong (data.data);
rc = 1;
}
#if defined (DEBUG_EXPRESSIONS)
log_debug ("num: extract_int32 (%s) = %ld",
((status && data.len >= 4) ?
print_hex_1 (data.len, data.data, 60) : "NULL"),
*result);
if (rc == 1) {
log_debug ("num: extract_int32 (%s) = %ld",
print_hex_1 (data.len, data.data, 60),
*result);
} else {
log_debug ("num: extract_int32 (NULL) = NULL");
}
#endif
if (status) data_string_forget (&data, MDL);
return (status && data.len >= 4);
return (rc);
case expr_const_int:
*result = expr -> data.const_int;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment