- Moved lease file check to a separate action so it is not used in restart -- it can fail when the daemon rewrites the lease causing a restart failure then (bnc#762108 regression). - Request dhcp6.sntp-servers in /etc/dhclient6.conf and forward to netconfig for processing (bnc#770236). - Removed RFC 4833 TZ options from client requests [unused]. - Update to ISC dhcp-4.2.4 release, fixing a dhcpv6 server assert crash while accessing lease on heap (bnc#767661) and providing... OBS-URL: https://build.opensuse.org/package/show/network:dhcp/dhcp?expand=0&rev=92
299 lines
9.5 KiB
Diff
299 lines
9.5 KiB
Diff
From 29c3de8d0973c66c9c8261c0f3d0deeccfd29994 Mon Sep 17 00:00:00 2001
|
|
From: Marius Tomaschewski <mt@suse.de>
|
|
Date: Tue, 12 Jun 2012 10:01:10 +0200
|
|
Subject: [PATCH] dhcp-4.2.4-parsing-and-printing-options
|
|
|
|
- Fix some issues in the code for parsing and printing options.
|
|
[ISC-Bugs #27314] - properly parse a zero length option from
|
|
a lease file.
|
|
[ISC-Bugs #22796] - properly determine if we parsed a 16 or 32 bit
|
|
value in evaluate_numeric_expression (extract-int).
|
|
[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"
|
|
|
|
This patch obsoletes the following (bnc#739696) patches:
|
|
- dhclient: parse_option_param: Bad format a
|
|
[complete, upstream corrected version]
|
|
- zero-length option lease parse error in dhclient6
|
|
[upstream accepted variant]
|
|
- properly determine if we parsed a 16 or 32 bit value
|
|
[additional upstream patch]
|
|
---
|
|
client/dhclient.c | 19 +++++++++++++---
|
|
common/options.c | 60 +++++++++++++++++++++++++++++++++++++++++++++-------
|
|
common/parse.c | 23 ++++++++++++++++---
|
|
common/tables.c | 7 +++--
|
|
common/tree.c | 35 ++++++++++++++++++++----------
|
|
5 files changed, 113 insertions(+), 31 deletions(-)
|
|
|
|
diff --git a/client/dhclient.c b/client/dhclient.c
|
|
index f920c64..025337a 100644
|
|
--- a/client/dhclient.c
|
|
+++ b/client/dhclient.c
|
|
@@ -2793,10 +2793,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);
|
|
}
|
|
}
|
|
diff --git a/common/options.c b/common/options.c
|
|
index bc9bb97..fa27688 100644
|
|
--- a/common/options.c
|
|
+++ b/common/options.c
|
|
@@ -1683,6 +1683,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 = ',';
|
|
@@ -1707,6 +1709,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;
|
|
@@ -1735,6 +1739,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;
|
|
@@ -1828,13 +1834,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)
|
|
@@ -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. */
|
|
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. */
|
|
diff --git a/common/parse.c b/common/parse.c
|
|
index 434085a..f72c0d6 100644
|
|
--- a/common/parse.c
|
|
+++ b/common/parse.c
|
|
@@ -5518,11 +5518,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) {
|
|
@@ -5718,7 +5733,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.");
|
|
@@ -5735,7 +5750,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.");
|
|
diff --git a/common/tables.c b/common/tables.c
|
|
index c820d83..d224dc1 100644
|
|
--- a/common/tables.c
|
|
+++ b/common/tables.c
|
|
@@ -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.
|
|
diff --git a/common/tree.c b/common/tree.c
|
|
index 3c978b0..7754398 100644
|
|
--- a/common/tree.c
|
|
+++ b/common/tree.c
|
|
@@ -2409,6 +2409,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:
|
|
@@ -2477,32 +2478,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;
|
|
--
|
|
1.7.7
|
|
|