mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-28 12:57:42 +00:00
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.
This commit is contained in:
parent
9f9265b63f
commit
35de6c8c24
11
RELNOTES
11
RELNOTES
@ -57,6 +57,17 @@ work on other platforms. Please report any problems and suggested fixes to
|
|||||||
for reporting this issue.
|
for reporting this issue.
|
||||||
[ISC-Bugs #29062]
|
[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.2.3
|
Changes since 4.2.3
|
||||||
|
|
||||||
! Add a check for a null pointer before calling the regexec function.
|
! Add a check for a null pointer before calling the regexec function.
|
||||||
|
@ -2742,10 +2742,21 @@ void write_lease_option (struct option_cache *oc,
|
|||||||
}
|
}
|
||||||
if (evaluate_option_cache (&ds, packet, lease, client_state,
|
if (evaluate_option_cache (&ds, packet, lease, client_state,
|
||||||
in_options, cfg_options, scope, oc, MDL)) {
|
in_options, cfg_options, scope, oc, MDL)) {
|
||||||
fprintf(leaseFile, "%soption %s%s%s %s;\n", preamble,
|
/* The option name */
|
||||||
name, dot, oc->option->name,
|
fprintf(leaseFile, "%soption %s%s%s", preamble,
|
||||||
pretty_print_option(oc->option, ds.data, ds.len,
|
name, dot, oc->option->name);
|
||||||
1, 1));
|
|
||||||
|
/* 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);
|
data_string_forget (&ds, MDL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1683,6 +1683,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
|
|||||||
const unsigned char *dp = data;
|
const unsigned char *dp = data;
|
||||||
char comma;
|
char comma;
|
||||||
unsigned long tval;
|
unsigned long tval;
|
||||||
|
isc_boolean_t a_array = ISC_FALSE;
|
||||||
|
int len_used;
|
||||||
|
|
||||||
if (emit_commas)
|
if (emit_commas)
|
||||||
comma = ',';
|
comma = ',';
|
||||||
@ -1707,6 +1709,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
|
|||||||
fmtbuf [l] = option -> format [i];
|
fmtbuf [l] = option -> format [i];
|
||||||
switch (option -> format [i]) {
|
switch (option -> format [i]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
|
a_array = ISC_TRUE;
|
||||||
|
/* Fall through */
|
||||||
case 'A':
|
case 'A':
|
||||||
--numelem;
|
--numelem;
|
||||||
fmtbuf [l] = 0;
|
fmtbuf [l] = 0;
|
||||||
@ -1735,6 +1739,8 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
|
|||||||
hunksize++;
|
hunksize++;
|
||||||
comma = ':';
|
comma = ':';
|
||||||
numhunk = 0;
|
numhunk = 0;
|
||||||
|
a_array = ISC_TRUE;
|
||||||
|
hunkinc = 1;
|
||||||
}
|
}
|
||||||
fmtbuf [l + 1] = 0;
|
fmtbuf [l + 1] = 0;
|
||||||
break;
|
break;
|
||||||
@ -1828,13 +1834,34 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
|
|||||||
len - hunksize);
|
len - hunksize);
|
||||||
|
|
||||||
/* If this is an array, compute its size. */
|
/* If this is an array, compute its size. */
|
||||||
if (!numhunk)
|
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;
|
numhunk = len / hunksize;
|
||||||
|
len_used = numhunk * hunksize;
|
||||||
|
}
|
||||||
|
|
||||||
/* See if we got an exact number of hunks. */
|
/* See if we got an exact number of hunks. */
|
||||||
if (numhunk > 0 && numhunk * hunksize < len)
|
if (len_used < len) {
|
||||||
log_error ("%s: %d extra bytes at end of array\n",
|
log_error ("%s: %d extra bytes at end of array\n",
|
||||||
option -> name,
|
option -> name,
|
||||||
len - numhunk * hunksize);
|
len - len_used);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* A one-hunk array prints the same as a single hunk. */
|
/* A one-hunk array prints the same as a single hunk. */
|
||||||
if (numhunk < 0)
|
if (numhunk < 0)
|
||||||
@ -1842,7 +1869,24 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
|
|||||||
|
|
||||||
/* Cycle through the array (or hunk) printing the data. */
|
/* Cycle through the array (or hunk) printing the data. */
|
||||||
for (i = 0; i < numhunk; i++) {
|
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]) {
|
switch (fmtbuf [j]) {
|
||||||
case 't':
|
case 't':
|
||||||
/* endbuf-1 leaves room for NULL. */
|
/* endbuf-1 leaves room for NULL. */
|
||||||
|
@ -5518,11 +5518,26 @@ int parse_option_decl (oc, cfile)
|
|||||||
if (status != ISC_R_SUCCESS || option == NULL)
|
if (status != ISC_R_SUCCESS || option == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fmt = option->format;
|
||||||
|
|
||||||
/* Parse the option data... */
|
/* Parse the option data... */
|
||||||
do {
|
do {
|
||||||
for (fmt = option -> format; *fmt; fmt++) {
|
for (; *fmt; fmt++) {
|
||||||
if (*fmt == 'A')
|
if (*fmt == 'A') {
|
||||||
|
/* 'A' is an array of records, start at
|
||||||
|
* the beginning
|
||||||
|
*/
|
||||||
|
fmt = option->format;
|
||||||
break;
|
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)
|
if (*fmt == 'o' && fmt != option -> format)
|
||||||
continue;
|
continue;
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
@ -5718,7 +5733,7 @@ int parse_option_decl (oc, cfile)
|
|||||||
goto alloc;
|
goto alloc;
|
||||||
|
|
||||||
case 'Z': /* Zero-length option */
|
case 'Z': /* Zero-length option */
|
||||||
token = next_token(&val, (unsigned *)0, cfile);
|
token = peek_token(&val, (unsigned *)0, cfile);
|
||||||
if (token != SEMI) {
|
if (token != SEMI) {
|
||||||
parse_warn(cfile,
|
parse_warn(cfile,
|
||||||
"semicolon expected.");
|
"semicolon expected.");
|
||||||
@ -5735,7 +5750,7 @@ int parse_option_decl (oc, cfile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
token = next_token (&val, (unsigned *)0, cfile);
|
token = next_token (&val, (unsigned *)0, cfile);
|
||||||
} while (*fmt == 'A' && token == COMMA);
|
} while (*fmt && token == COMMA);
|
||||||
|
|
||||||
if (token != SEMI) {
|
if (token != SEMI) {
|
||||||
parse_warn (cfile, "semicolon expected.");
|
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
|
some event. The special all-ones value means 'infinite'. May either
|
||||||
be printed as a decimal, eg, "3600", or as this name, eg, "infinite".
|
be printed as a decimal, eg, "3600", or as this name, eg, "infinite".
|
||||||
f - flag (true or false)
|
f - flag (true or false)
|
||||||
A - array of whatever precedes (e.g., IA means array of IP addresses)
|
A - array of all that precedes (e.g., fIA means array of records of
|
||||||
a - array of the preceding character (e.g., IIa means two or more IP
|
a flag and an IP address)
|
||||||
addresses)
|
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)
|
U - name of an option space (universe)
|
||||||
F - implicit flag - the presence of the option indicates that the
|
F - implicit flag - the presence of the option indicates that the
|
||||||
flag is true.
|
flag is true.
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Routines for manipulating parse trees... */
|
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) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
* Copyright (c) 1995-2003 by Internet Software Consortium
|
* Copyright (c) 1995-2003 by Internet Software Consortium
|
||||||
*
|
*
|
||||||
@ -2409,6 +2409,7 @@ int evaluate_numeric_expression (result, packet, lease, client_state,
|
|||||||
struct binding *binding;
|
struct binding *binding;
|
||||||
struct binding_value *bv;
|
struct binding_value *bv;
|
||||||
unsigned long ileft, iright;
|
unsigned long ileft, iright;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
switch (expr -> op) {
|
switch (expr -> op) {
|
||||||
case expr_check:
|
case expr_check:
|
||||||
@ -2477,32 +2478,42 @@ int evaluate_numeric_expression (result, packet, lease, client_state,
|
|||||||
status = (evaluate_data_expression
|
status = (evaluate_data_expression
|
||||||
(&data, packet, lease, client_state, in_options,
|
(&data, packet, lease, client_state, in_options,
|
||||||
cfg_options, scope, expr -> data.extract_int, MDL));
|
cfg_options, scope, expr -> data.extract_int, MDL));
|
||||||
if (status && data.len >= 2)
|
if (status && data.len >= 2) {
|
||||||
*result = getUShort (data.data);
|
*result = getUShort (data.data);
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
|
if (rc == 1) {
|
||||||
log_debug ("num: extract_int16 (%s) = %ld",
|
log_debug ("num: extract_int16 (%s) = %ld",
|
||||||
((status && data.len >= 2) ?
|
print_hex_1(data.len, data.data, 60)
|
||||||
print_hex_1 (data.len, data.data, 60) : "NULL"),
|
|
||||||
*result);
|
*result);
|
||||||
|
} else {
|
||||||
|
log_debug ("num: extract_int16 (NULL) = NULL");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (status) data_string_forget (&data, MDL);
|
if (status) data_string_forget (&data, MDL);
|
||||||
return (status && data.len >= 2);
|
return (rc);
|
||||||
|
|
||||||
case expr_extract_int32:
|
case expr_extract_int32:
|
||||||
memset (&data, 0, sizeof data);
|
memset (&data, 0, sizeof data);
|
||||||
status = (evaluate_data_expression
|
status = (evaluate_data_expression
|
||||||
(&data, packet, lease, client_state, in_options,
|
(&data, packet, lease, client_state, in_options,
|
||||||
cfg_options, scope, expr -> data.extract_int, MDL));
|
cfg_options, scope, expr -> data.extract_int, MDL));
|
||||||
if (status && data.len >= 4)
|
if (status && data.len >= 4) {
|
||||||
*result = getULong (data.data);
|
*result = getULong (data.data);
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
|
if (rc == 1) {
|
||||||
log_debug ("num: extract_int32 (%s) = %ld",
|
log_debug ("num: extract_int32 (%s) = %ld",
|
||||||
((status && data.len >= 4) ?
|
print_hex_1 (data.len, data.data, 60),
|
||||||
print_hex_1 (data.len, data.data, 60) : "NULL"),
|
|
||||||
*result);
|
*result);
|
||||||
|
} else {
|
||||||
|
log_debug ("num: extract_int32 (NULL) = NULL");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (status) data_string_forget (&data, MDL);
|
if (status) data_string_forget (&data, MDL);
|
||||||
return (status && data.len >= 4);
|
return (rc);
|
||||||
|
|
||||||
case expr_const_int:
|
case expr_const_int:
|
||||||
*result = expr -> data.const_int;
|
*result = expr -> data.const_int;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user