summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-10-31 22:39:20 +0100
committerThomas Haller <thaller@redhat.com>2016-11-09 12:07:34 +0100
commitc55b7e866efe069e01a4af6953a2fd783caf1c71 (patch)
treefc255c7a857cea6c5886a077bc6295e47318983e
parent7b548fb9a806b0c2baf7f381d82c1c0ec484aee6 (diff)
downloadNetworkManager-c55b7e866efe069e01a4af6953a2fd783caf1c71.tar.gz
ifcfg-rh: support storing newline '\n' and other ANSI control caracters
This is especially important for the team config JSON, which is expected to contain newlines. ANSI C quotation is bash specific, but initscripts already use #!/bin/bash. Unfortunately, g_strescape() doesn't escape '\'' and can thus not be used. Also add a test that svEscape() and svUnescape() do a round-trip. Not only consider \r and \n as candidates for ANSI C quotation, but all ANSI control characters.
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c96
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c15
2 files changed, 101 insertions, 10 deletions
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 5929811a12..886e301659 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -99,15 +99,88 @@ _shell_is_name (const char *key)
/*****************************************************************************/
+/* like g_strescape(), except that it also escapes '\''' *sigh*.
+ *
+ * While at it, add $''. */
+static char *
+_escape_ansic (const char *source)
+{
+ const char *p;
+ gchar *dest;
+ gchar *q;
+
+ nm_assert (source);
+
+ p = (const char *) source;
+ /* Each source byte needs maximally four destination chars (\777) */
+ q = dest = g_malloc (strlen (source) * 4 + 1 + 3);
+
+ *q++ = '$';
+ *q++ = '\'';
+
+ while (*p) {
+ switch (*p) {
+ case '\b':
+ *q++ = '\\';
+ *q++ = 'b';
+ break;
+ case '\f':
+ *q++ = '\\';
+ *q++ = 'f';
+ break;
+ case '\n':
+ *q++ = '\\';
+ *q++ = 'n';
+ break;
+ case '\r':
+ *q++ = '\\';
+ *q++ = 'r';
+ break;
+ case '\t':
+ *q++ = '\\';
+ *q++ = 't';
+ break;
+ case '\v':
+ *q++ = '\\';
+ *q++ = 'v';
+ break;
+ case '\\':
+ case '"':
+ case '\'':
+ *q++ = '\\';
+ *q++ = *p;
+ break;
+ default:
+ if ((*p < ' ') || (*p >= 0177)) {
+ *q++ = '\\';
+ *q++ = '0' + (((*p) >> 6) & 07);
+ *q++ = '0' + (((*p) >> 3) & 07);
+ *q++ = '0' + ((*p) & 07);
+ } else
+ *q++ = *p;
+ break;
+ }
+ p++;
+ }
+ *q++ = '\'';
+ *q++ = '\0';
+
+ nm_assert (q - dest <= strlen (source) * 4 + 1 + 3);
+
+ return dest;
+}
+
+/*****************************************************************************/
+
#define ESC_ESCAPEES "\"'\\$~`" /* must be escaped */
#define ESC_SPACES " \t|&;()<>" /* only require "" */
-#define ESC_NEWLINES "\n\r" /* will be removed */
const char *
svEscape (const char *s, char **to_free)
{
char *new;
- int mangle = 0, space = 0, newline = 0;
+ gsize mangle = 0;
+ gboolean has_space = FALSE;
int newlen;
size_t i, j, slen;
@@ -117,23 +190,26 @@ svEscape (const char *s, char **to_free)
if (strchr (ESC_ESCAPEES, s[i]))
mangle++;
if (strchr (ESC_SPACES, s[i]))
- space++;
- if (strchr (ESC_NEWLINES, s[i]))
- newline++;
+ has_space = TRUE;
+ if (s[i] < ' ') {
+ /* if the string contains newline we can only express it using ANSI C quotation
+ * (as we don't support line continuation).
+ * Additionally, ANSI control characters look odd with regular quotation, so handle
+ * them too. */
+ return (*to_free = _escape_ansic (s));
+ }
}
- if (!mangle && !space && !newline) {
+ if (!mangle && !has_space) {
*to_free = NULL;
return s;
}
- newlen = slen + mangle - newline + 3; /* 3 is extra ""\0 */
+ newlen = slen + mangle + 3; /* 3 is extra ""\0 */
new = g_malloc (newlen);
j = 0;
new[j++] = '"';
for (i = 0; i < slen; i++) {
- if (strchr (ESC_NEWLINES, s[i]))
- continue;
if (strchr (ESC_ESCAPEES, s[i])) {
new[j++] = '\\';
}
@@ -142,7 +218,7 @@ svEscape (const char *s, char **to_free)
new[j++] = '"';
new[j++] = '\0';
- nm_assert (j == slen + mangle - newline + 3);
+ nm_assert (j == slen + mangle + 3);
*to_free = new;
return new;
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 59d20e078e..960f16e304 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -8730,6 +8730,21 @@ do_svUnescape_assert (const char *str, const char *expected)
s = _svUnescape (str, &to_free);
g_assert_cmpstr (s, ==, expected);
+
+ /* check we can make a round-trip */
+ if (expected) {
+ gs_free char *s1_free = NULL;
+ gs_free char *s2_free = NULL;
+ const char *s1, *s2;
+
+ s1 = svEscape (expected, &s1_free);
+ g_assert (s1);
+
+ s2 = _svUnescape (s1, &s2_free);
+ g_assert (s2);
+
+ g_assert_cmpstr (s2, ==, expected);
+ }
}
static void