From c5ac66d392e7543c1fef77cd76c8ba4dbaeaf790 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 7 Nov 2016 17:53:22 +0100 Subject: [PATCH] ifcfg-rh: restore previous behavior for svUnescape() stripping backslash from double-quoting Now we could parse simple shell variable assignment properly, but old versions of svEscape() wrote invalid double-quoted strings. Add a hack to restore the broken behavior for that case only. --- src/settings/plugins/ifcfg-rh/shvar.c | 44 ++++++++++++++++++- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 19 +++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index ff294c7f41..b8dcfb718b 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -245,6 +245,28 @@ svEscape (const char *s, char **to_free) return new; } +static gboolean +_looks_like_old_svescaped (const char *value) +{ + gsize k; + + if (value[0] != '"') + return FALSE; + + for (k = 1; ; k++) { + if (value[k] == '\0') + return FALSE; + if (value[k] == '"') + return (value[k + 1] == '\0'); + if (value[k] == '\\') { + k++; + if (!_char_in_strset (value[k], "\"'\\$~`")) + return FALSE; + } else if (_char_in_strset (value[k], "'\\$~`")) + return FALSE; + } +} + static gboolean _ch_octal_is (char ch) { @@ -302,6 +324,7 @@ svUnescape (const char *value, char **to_free) { gsize i, j; nm_auto_free_gstring GString *str = NULL; + int looks_like_old_svescaped = -1; /* we handle bash syntax here (note that ifup has #!/bin/bash. * Thus, see https://www.gnu.org/software/bash/manual/html_node/Quoting.html#Quoting */ @@ -404,7 +427,26 @@ svUnescape (const char *value, char **to_free) /* we don't support line continuation */ goto out_error; } - if (!NM_IN_SET (value[i], '$', '`', '"', '\\')) + if (NM_IN_SET (value[i], '$', '`', '"', '\\')) { + /* Drop the backslash. */ + } else if (NM_IN_SET (value[i], '\'', '~')) { + /* '\'' and '~' in double qoutes are not handled special by shell. + * However, old versions of svEscape() would wrongly use double-quoting + * with backslash escaping for these characters (expecting svUnescape() + * to remove the backslash). + * + * In order to preserve previous behavior, we continue to read such + * strings different then shell does. */ + + /* Actually, we can relax this. Old svEscape() escaped the entire value + * in a particular way with double quotes. + * If the value doesn't exactly look like something as created by svEscape(), + * don't do the compat hack and preserve the backslash. */ + if (looks_like_old_svescaped < 0) + looks_like_old_svescaped = _looks_like_old_svescaped (value); + if (!looks_like_old_svescaped) + g_string_append_c (str, '\\'); + } else g_string_append_c (str, '\\'); } g_string_append_c (str, value[i]); diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index c5e5456af2..3ee8589c17 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -8233,8 +8233,6 @@ test_svUnescape (void) V1 ("\"\\\\\"", "\\"), V1 ("\"\\a\"", "\\a"), V1 ("\"\\b\"", "\\b"), - V1 ("\"\\'\"", "\\'"), - V1 ("\"\\~\"", "\\~"), V1 ("\"\\\t\"", "\\\t"), V0 ("ab\r", "ab"), V0 ("a'b'\r ", "ab"), @@ -8262,6 +8260,23 @@ test_svUnescape (void) V1 ("\"aa\\\"\"", "aa\""), V1 ("\"aa\\\"b\"c", "aa\"bc"), V1 ("\"aa\\\"\"b", "aa\"b"), + + /* the following is not shell behavior, but kept for backward compatibility + * with old svEscape(). */ + V0 ("\"\\'\"", "'"), + V0 ("\"\\~\"", "~"), + V0 ("\"b\\~b\"", "b~b"), + V0 ("\"\\~\\~\"", "~~"), + V0 ("\"\\~\\'\"", "~'"), + + /* the following is shell-behavior, because it doesn't look like written + * by old svEscape(). */ + V1 ("\"\\~~\"", "\\~~"), + V1 ("\"\\a\\'\"", "\\a\\'"), + V1 ("x\"\\~\"", "x\\~"), + V1 ("\"\\'\"''", "\\'"), + V0 ("\"b\\~b\" ", "b\\~b"), + V1 ("\"b\\~b\"x", "b\\~bx"), }; const UnescapeTestData data_ansi[] = { /* strings inside $''. They cannot be compared directly, but must