Blob Blame Raw
From c884f73cb754db77632a84830e5a058827d732e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 11 Sep 2013 21:50:16 -0400
Subject: [PATCH] Allow tabs in environment files

bash allows them, and so should we.

string_has_cc is changed to allow tabs, and if they are not wanted,
they must be now checked for explicitly. There are two other callers,
apart from the env file loaders, and one already checked anyway, and
the other is changed to check.

https://bugs.freedesktop.org/show_bug.cgi?id=68592
https://bugs.gentoo.org/show_bug.cgi?id=481554
---
 src/hostname/hostnamed.c |  3 ++-
 src/shared/util.c        |  4 ++++
 src/test/test-fileio.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 0437e33a66..6a43aeb840 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -553,7 +553,8 @@ static DBusHandlerResult hostname_message_handler(
                                  * safe than sorry */
                                 if (k == PROP_ICON_NAME && !filename_is_safe(name))
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
-                                if (k == PROP_PRETTY_HOSTNAME && string_has_cc(name))
+                                if (k == PROP_PRETTY_HOSTNAME &&
+                                    (string_has_cc(name) || chars_intersect(name, "\t")))
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
                                 if (k == PROP_CHASSIS && !valid_chassis(name))
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
diff --git a/src/shared/util.c b/src/shared/util.c
index 673e0da6b6..113133f22a 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -5264,6 +5264,10 @@ bool string_is_safe(const char *p) {
         return true;
 }
 
+/**
+ * Check if a string contains control characters.
+ * Spaces and tabs are not considered control characters.
+ */
 bool string_has_cc(const char *p) {
         const char *t;
 
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index b08e796b7d..ce77304108 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -139,6 +139,59 @@ static void test_parse_env_file(void) {
         unlink("/tmp/test-fileio");
 }
 
+static void test_parse_multiline_env_file(void) {
+        char    t[] = "/tmp/test-fileio-in-XXXXXX",
+                p[] = "/tmp/test-fileio-out-XXXXXX";
+        int fd, r;
+        FILE *f;
+        _cleanup_strv_free_ char **a = NULL, **b = NULL;
+        char **i;
+
+        assert_se(mktemp(p));
+
+        fd = mkostemp(t, O_CLOEXEC);
+        assert_se(fd >= 0);
+
+        f = fdopen(fd, "w");
+        assert_se(f);
+
+        fputs("one=BAR\\\n"
+              "    VAR\\\n"
+              "\tGAR\n"
+              "#comment\n"
+              "two=\"bar\\\n"
+              "    var\\\n"
+              "\tgar\"\n"
+              "#comment\n"
+              "tri=\"bar \\\n"
+              "    var \\\n"
+              "\tgar \"\n", f);
+
+        fflush(f);
+        fclose(f);
+
+        r = load_env_file(t, NULL, &a);
+        assert_se(r >= 0);
+
+        STRV_FOREACH(i, a)
+                log_info("Got: <%s>", *i);
+
+        assert_se(streq(a[0], "one=BAR    VAR\tGAR"));
+        assert_se(streq(a[1], "two=bar    var\tgar"));
+        assert_se(streq(a[2], "tri=bar     var \tgar "));
+        assert_se(a[3] == NULL);
+
+        r = write_env_file(p, a);
+        assert_se(r >= 0);
+
+        r = load_env_file(p, NULL, &b);
+        assert_se(r >= 0);
+
+        unlink(t);
+        unlink(p);
+}
+
+
 static void test_executable_is_script(void) {
         char t[] = "/tmp/test-executable-XXXXXX";
         int fd, r;
@@ -175,6 +228,7 @@ static void test_executable_is_script(void) {
 
 int main(int argc, char *argv[]) {
         test_parse_env_file();
+        test_parse_multiline_env_file();
         test_executable_is_script();
         return 0;
 }