be52b9f
From c884f73cb754db77632a84830e5a058827d732e5 Mon Sep 17 00:00:00 2001
be52b9f
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
be52b9f
Date: Wed, 11 Sep 2013 21:50:16 -0400
51b11df
Subject: [PATCH] Allow tabs in environment files
be52b9f
be52b9f
bash allows them, and so should we.
be52b9f
be52b9f
string_has_cc is changed to allow tabs, and if they are not wanted,
be52b9f
they must be now checked for explicitly. There are two other callers,
be52b9f
apart from the env file loaders, and one already checked anyway, and
be52b9f
the other is changed to check.
be52b9f
be52b9f
https://bugs.freedesktop.org/show_bug.cgi?id=68592
be52b9f
https://bugs.gentoo.org/show_bug.cgi?id=481554
be52b9f
---
be52b9f
 src/hostname/hostnamed.c |  3 ++-
be52b9f
 src/shared/util.c        |  4 ++++
be52b9f
 src/test/test-fileio.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
be52b9f
 3 files changed, 60 insertions(+), 1 deletion(-)
be52b9f
be52b9f
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
674ca7d
index 0437e33a66..6a43aeb840 100644
be52b9f
--- a/src/hostname/hostnamed.c
be52b9f
+++ b/src/hostname/hostnamed.c
be52b9f
@@ -553,7 +553,8 @@ static DBusHandlerResult hostname_message_handler(
be52b9f
                                  * safe than sorry */
be52b9f
                                 if (k == PROP_ICON_NAME && !filename_is_safe(name))
be52b9f
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
be52b9f
-                                if (k == PROP_PRETTY_HOSTNAME && string_has_cc(name))
be52b9f
+                                if (k == PROP_PRETTY_HOSTNAME &&
be52b9f
+                                    (string_has_cc(name) || chars_intersect(name, "\t")))
be52b9f
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
be52b9f
                                 if (k == PROP_CHASSIS && !valid_chassis(name))
be52b9f
                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
be52b9f
diff --git a/src/shared/util.c b/src/shared/util.c
674ca7d
index 673e0da6b6..113133f22a 100644
be52b9f
--- a/src/shared/util.c
be52b9f
+++ b/src/shared/util.c
be52b9f
@@ -5264,6 +5264,10 @@ bool string_is_safe(const char *p) {
be52b9f
         return true;
be52b9f
 }
be52b9f
 
be52b9f
+/**
be52b9f
+ * Check if a string contains control characters.
be52b9f
+ * Spaces and tabs are not considered control characters.
be52b9f
+ */
be52b9f
 bool string_has_cc(const char *p) {
be52b9f
         const char *t;
be52b9f
 
be52b9f
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
674ca7d
index b08e796b7d..ce77304108 100644
be52b9f
--- a/src/test/test-fileio.c
be52b9f
+++ b/src/test/test-fileio.c
be52b9f
@@ -139,6 +139,59 @@ static void test_parse_env_file(void) {
be52b9f
         unlink("/tmp/test-fileio");
be52b9f
 }
be52b9f
 
be52b9f
+static void test_parse_multiline_env_file(void) {
be52b9f
+        char    t[] = "/tmp/test-fileio-in-XXXXXX",
be52b9f
+                p[] = "/tmp/test-fileio-out-XXXXXX";
be52b9f
+        int fd, r;
be52b9f
+        FILE *f;
be52b9f
+        _cleanup_strv_free_ char **a = NULL, **b = NULL;
be52b9f
+        char **i;
be52b9f
+
be52b9f
+        assert_se(mktemp(p));
be52b9f
+
be52b9f
+        fd = mkostemp(t, O_CLOEXEC);
be52b9f
+        assert_se(fd >= 0);
be52b9f
+
be52b9f
+        f = fdopen(fd, "w");
be52b9f
+        assert_se(f);
be52b9f
+
be52b9f
+        fputs("one=BAR\\\n"
be52b9f
+              "    VAR\\\n"
be52b9f
+              "\tGAR\n"
be52b9f
+              "#comment\n"
be52b9f
+              "two=\"bar\\\n"
be52b9f
+              "    var\\\n"
be52b9f
+              "\tgar\"\n"
be52b9f
+              "#comment\n"
be52b9f
+              "tri=\"bar \\\n"
be52b9f
+              "    var \\\n"
be52b9f
+              "\tgar \"\n", f);
be52b9f
+
be52b9f
+        fflush(f);
be52b9f
+        fclose(f);
be52b9f
+
be52b9f
+        r = load_env_file(t, NULL, &a);
be52b9f
+        assert_se(r >= 0);
be52b9f
+
be52b9f
+        STRV_FOREACH(i, a)
be52b9f
+                log_info("Got: <%s>", *i);
be52b9f
+
be52b9f
+        assert_se(streq(a[0], "one=BAR    VAR\tGAR"));
be52b9f
+        assert_se(streq(a[1], "two=bar    var\tgar"));
be52b9f
+        assert_se(streq(a[2], "tri=bar     var \tgar "));
be52b9f
+        assert_se(a[3] == NULL);
be52b9f
+
be52b9f
+        r = write_env_file(p, a);
be52b9f
+        assert_se(r >= 0);
be52b9f
+
be52b9f
+        r = load_env_file(p, NULL, &b);
be52b9f
+        assert_se(r >= 0);
be52b9f
+
be52b9f
+        unlink(t);
be52b9f
+        unlink(p);
be52b9f
+}
be52b9f
+
be52b9f
+
be52b9f
 static void test_executable_is_script(void) {
be52b9f
         char t[] = "/tmp/test-executable-XXXXXX";
be52b9f
         int fd, r;
be52b9f
@@ -175,6 +228,7 @@ static void test_executable_is_script(void) {
be52b9f
 
be52b9f
 int main(int argc, char *argv[]) {
be52b9f
         test_parse_env_file();
be52b9f
+        test_parse_multiline_env_file();
be52b9f
         test_executable_is_script();
be52b9f
         return 0;
be52b9f
 }