]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hostname-util: rework read_hostname_config() a bit
authorLennart Poettering <lennart@poettering.net>
Tue, 14 Nov 2017 18:51:06 +0000 (19:51 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 20 Nov 2017 15:43:15 +0000 (16:43 +0100)
First of all, let's rename it to read_etc_hostname(), to make clearer
what kind of configuration it actually reads: the file format defined in
/etc/hostname and nothing else.

Secondly: let's port this to use read_line(), i.e. the new way to read
lines from a file in a safe, bounded way.

Thirdly: let's strip leading/trailing whitespace from what we are
reading. Given that we are already pretty lenient what we read (comments
and empty lines), let's be permissive regarding whitespace too.

Fourthly: let's actually validate the hostname when reading it. So far
we tried to make it valid, but that's not always possible (for example,
we can't make an empty hostname valid, ever).

src/basic/hostname-util.c
src/basic/hostname-util.h
src/core/hostname-setup.c
src/hostname/hostnamed.c
src/test/test-hostname-util.c

index 78f18e26bf7e9ee955f2886d618f312300ed5db7..12a579b38ac0432785d1148448c84e3978dd066c 100644 (file)
@@ -25,6 +25,8 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
@@ -219,35 +221,55 @@ int sethostname_idempotent(const char *s) {
         return 1;
 }
 
-int read_hostname_config(const char *path, char **hostname) {
-        _cleanup_fclose_ FILE *f = NULL;
-        char l[LINE_MAX];
-        char *name = NULL;
+int read_etc_hostname_stream(FILE *f, char **ret) {
+        int r;
 
-        assert(path);
-        assert(hostname);
+        assert(f);
+        assert(ret);
 
-        f = fopen(path, "re");
-        if (!f)
-                return -errno;
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                char *p;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
+                        return -ENOENT;
 
-        /* may have comments, ignore them */
-        FOREACH_LINE(l, f, return -errno) {
-                truncate_nl(l);
-                if (!IN_SET(l[0], '\0', '#')) {
-                        /* found line with value */
-                        name = hostname_cleanup(l);
-                        name = strdup(name);
-                        if (!name)
+                p = strstrip(line);
+
+                /* File may have empty lines or comments, ignore them */
+                if (!IN_SET(*p, '\0', '#')) {
+                        char *copy;
+
+                        hostname_cleanup(p); /* normalize the hostname */
+
+                        if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
+                                return -EBADMSG;
+
+                        copy = strdup(p);
+                        if (!copy)
                                 return -ENOMEM;
-                        break;
+
+                        *ret = copy;
+                        return 0;
                 }
         }
+}
 
-        if (!name)
-                /* no non-empty line found */
-                return -ENOENT;
+int read_etc_hostname(const char *path, char **ret) {
+        _cleanup_fclose_ FILE *f = NULL;
+
+        assert(ret);
+
+        if (!path)
+                path = "/etc/hostname";
+
+        f = fopen(path, "re");
+        if (!f)
+                return -errno;
+
+        return read_etc_hostname_stream(f, ret);
 
-        *hostname = name;
-        return 0;
 }
index a7d09c910b5d02ed3a80bb2d9e0d3546b439ba39..52fd6b0899b5f5581b8c9aa135c0d9f7296c63e0 100644 (file)
@@ -39,4 +39,5 @@ bool is_gateway_hostname(const char *hostname);
 
 int sethostname_idempotent(const char *s);
 
-int read_hostname_config(const char *path, char **hostname);
+int read_etc_hostname_stream(FILE *f, char **ret);
+int read_etc_hostname(const char *path, char **ret);
index f905f5299151a56f6667b6e06fa4e36476b2d92b..19299918cc1f1d9f947fab02540985b4aa0037f0 100644 (file)
@@ -37,7 +37,7 @@ int hostname_setup(void) {
         const char *hn;
         int r;
 
-        r = read_hostname_config("/etc/hostname", &b);
+        r = read_etc_hostname(NULL, &b);
         if (r < 0) {
                 if (r == -ENOENT)
                         enoent = true;
index a9d5d49bddd4f28365186713a150a88fccfc517d..5feaa60c99fe3719a79bc5101a1874a38e9e363c 100644 (file)
@@ -96,7 +96,7 @@ static int context_read_data(Context *c) {
         if (!c->data[PROP_HOSTNAME])
                 return -ENOMEM;
 
-        r = read_hostname_config("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
+        r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
         if (r < 0 && r != -ENOENT)
                 return r;
 
index d5a986b1cb8eb928b9def62b5b9e4c0a10f060c8..b73468ddbcf257848995e3e53b62630d80399e03 100644 (file)
@@ -100,7 +100,7 @@ static void test_hostname_cleanup(void) {
         assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
 }
 
-static void test_read_hostname_config(void) {
+static void test_read_etc_hostname(void) {
         char path[] = "/tmp/hostname.XXXXXX";
         char *hostname;
         int fd;
@@ -111,27 +111,27 @@ static void test_read_hostname_config(void) {
 
         /* simple hostname */
         write_string_file(path, "foo", WRITE_STRING_FILE_CREATE);
-        assert_se(read_hostname_config(path, &hostname) == 0);
+        assert_se(read_etc_hostname(path, &hostname) == 0);
         assert_se(streq(hostname, "foo"));
         hostname = mfree(hostname);
 
         /* with comment */
         write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE);
-        assert_se(read_hostname_config(path, &hostname) == 0);
+        assert_se(read_etc_hostname(path, &hostname) == 0);
         assert_se(hostname);
         assert_se(streq(hostname, "foo"));
         hostname = mfree(hostname);
 
         /* with comment and extra whitespace */
         write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE);
-        assert_se(read_hostname_config(path, &hostname) == 0);
+        assert_se(read_etc_hostname(path, &hostname) == 0);
         assert_se(hostname);
         assert_se(streq(hostname, "foo"));
         hostname = mfree(hostname);
 
         /* cleans up name */
         write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE);
-        assert_se(read_hostname_config(path, &hostname) == 0);
+        assert_se(read_etc_hostname(path, &hostname) == 0);
         assert_se(hostname);
         assert_se(streq(hostname, "foobar.com"));
         hostname = mfree(hostname);
@@ -139,11 +139,11 @@ static void test_read_hostname_config(void) {
         /* no value set */
         hostname = (char*) 0x1234;
         write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE);
-        assert_se(read_hostname_config(path, &hostname) == -ENOENT);
+        assert_se(read_etc_hostname(path, &hostname) == -ENOENT);
         assert_se(hostname == (char*) 0x1234);  /* does not touch argument on error */
 
         /* nonexisting file */
-        assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT);
+        assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT);
         assert_se(hostname == (char*) 0x1234);  /* does not touch argument on error */
 
         unlink(path);
@@ -155,7 +155,7 @@ int main(int argc, char *argv[]) {
 
         test_hostname_is_valid();
         test_hostname_cleanup();
-        test_read_hostname_config();
+        test_read_etc_hostname();
 
         return 0;
 }