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).
This commit is contained in:
Lennart Poettering
2017-11-20 16:43:15 +01:00
parent 9990ea0e59
commit f35cb39ed6
5 changed files with 58 additions and 35 deletions
+46 -24
View 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);
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;
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;
*ret = copy;
return 0;
}
}
}
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;
/* 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)
return -ENOMEM;
break;
}
}
return read_etc_hostname_stream(f, ret);
if (!name)
/* no non-empty line found */
return -ENOENT;
*hostname = name;
return 0;
}
+2 -1
View 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);