summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2017-11-14 19:51:06 +0100
committerLennart Poettering <lennart@poettering.net>2017-11-20 16:43:15 +0100
commitf35cb39ed6fa8ad48bd3125c30bca7f310ef5788 (patch)
treefd507f1e37bc864b7b7e338cf139b1dacb1e5eb8
parent9990ea0e59373c02b6bd64a5a4c860d2579f77db (diff)
downloadsystemd-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.c68
-rw-r--r--src/basic/hostname-util.h3
-rw-r--r--src/core/hostname-setup.c2
-rw-r--r--src/hostname/hostnamed.c2
-rw-r--r--src/test/test-hostname-util.c16
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;
}