diff options
author | Lennart Poettering <lennart@poettering.net> | 2017-11-14 19:51:06 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2017-11-20 16:43:15 +0100 |
commit | f35cb39ed6fa8ad48bd3125c30bca7f310ef5788 (patch) | |
tree | fd507f1e37bc864b7b7e338cf139b1dacb1e5eb8 | |
parent | 9990ea0e59373c02b6bd64a5a4c860d2579f77db (diff) | |
download | systemd-f35cb39ed6fa8ad48bd3125c30bca7f310ef5788.tar.gz systemd-f35cb39ed6fa8ad48bd3125c30bca7f310ef5788.tar.bz2 systemd-f35cb39ed6fa8ad48bd3125c30bca7f310ef5788.zip |
hostname-util: rework read_hostname_config() a bit
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).
-rw-r--r-- | src/basic/hostname-util.c | 68 | ||||
-rw-r--r-- | src/basic/hostname-util.h | 3 | ||||
-rw-r--r-- | src/core/hostname-setup.c | 2 | ||||
-rw-r--r-- | src/hostname/hostnamed.c | 2 | ||||
-rw-r--r-- | src/test/test-hostname-util.c | 16 |
5 files changed, 57 insertions, 34 deletions
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 78f18e26bf..12a579b38a 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -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; } diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index a7d09c910b..52fd6b0899 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -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); diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index f905f52991..19299918cc 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -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; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a9d5d49bdd..5feaa60c99 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -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; diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index d5a986b1cb..b73468ddbc 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -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; } |