]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
Merge pull request #1374 from olof/autoconf_gcrypt_dep
[thirdparty/systemd.git] / src / basic / hostname-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/utsname.h>
23 #include <ctype.h>
24
25 #include "util.h"
26 #include "hostname-util.h"
27
28 bool hostname_is_set(void) {
29 struct utsname u;
30
31 assert_se(uname(&u) >= 0);
32
33 if (isempty(u.nodename))
34 return false;
35
36 /* This is the built-in kernel default host name */
37 if (streq(u.nodename, "(none)"))
38 return false;
39
40 return true;
41 }
42
43 char* gethostname_malloc(void) {
44 struct utsname u;
45
46 assert_se(uname(&u) >= 0);
47
48 if (isempty(u.nodename) || streq(u.nodename, "(none)"))
49 return strdup(u.sysname);
50
51 return strdup(u.nodename);
52 }
53
54 static bool hostname_valid_char(char c) {
55 return
56 (c >= 'a' && c <= 'z') ||
57 (c >= 'A' && c <= 'Z') ||
58 (c >= '0' && c <= '9') ||
59 c == '-' ||
60 c == '_' ||
61 c == '.';
62 }
63
64 /**
65 * Check if s looks like a valid host name or FQDN. This does not do
66 * full DNS validation, but only checks if the name is composed of
67 * allowed characters and the length is not above the maximum allowed
68 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
69 * allow_trailing_dot is true and at least two components are present
70 * in the name. Note that due to the restricted charset and length
71 * this call is substantially more conservative than
72 * dns_domain_is_valid().
73 */
74 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
75 unsigned n_dots = 0;
76 const char *p;
77 bool dot;
78
79 if (isempty(s))
80 return false;
81
82 /* Doesn't accept empty hostnames, hostnames with
83 * leading dots, and hostnames with multiple dots in a
84 * sequence. Also ensures that the length stays below
85 * HOST_NAME_MAX. */
86
87 for (p = s, dot = true; *p; p++) {
88 if (*p == '.') {
89 if (dot)
90 return false;
91
92 dot = true;
93 n_dots ++;
94 } else {
95 if (!hostname_valid_char(*p))
96 return false;
97
98 dot = false;
99 }
100 }
101
102 if (dot && (n_dots < 2 || !allow_trailing_dot))
103 return false;
104
105 if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
106 * Linux, but DNS allows domain names
107 * up to 255 characters */
108 return false;
109
110 return true;
111 }
112
113 char* hostname_cleanup(char *s) {
114 char *p, *d;
115 bool dot;
116
117 assert(s);
118
119 for (p = s, d = s, dot = true; *p; p++) {
120 if (*p == '.') {
121 if (dot)
122 continue;
123
124 *(d++) = '.';
125 dot = true;
126 } else if (hostname_valid_char(*p)) {
127 *(d++) = *p;
128 dot = false;
129 }
130
131 }
132
133 if (dot && d > s)
134 d[-1] = 0;
135 else
136 *d = 0;
137
138 strshorten(s, HOST_NAME_MAX);
139
140 return s;
141 }
142
143 bool is_localhost(const char *hostname) {
144 assert(hostname);
145
146 /* This tries to identify local host and domain names
147 * described in RFC6761 plus the redhatism of .localdomain */
148
149 return strcaseeq(hostname, "localhost") ||
150 strcaseeq(hostname, "localhost.") ||
151 strcaseeq(hostname, "localdomain.") ||
152 strcaseeq(hostname, "localdomain") ||
153 endswith_no_case(hostname, ".localhost") ||
154 endswith_no_case(hostname, ".localhost.") ||
155 endswith_no_case(hostname, ".localdomain") ||
156 endswith_no_case(hostname, ".localdomain.");
157 }
158
159 bool is_gateway_hostname(const char *hostname) {
160 assert(hostname);
161
162 /* This tries to identify the valid syntaxes for the our
163 * synthetic "gateway" host. */
164
165 return
166 strcaseeq(hostname, "gateway") ||
167 strcaseeq(hostname, "gateway.");
168 }
169
170 int sethostname_idempotent(const char *s) {
171 char buf[HOST_NAME_MAX + 1] = {};
172
173 assert(s);
174
175 if (gethostname(buf, sizeof(buf)) < 0)
176 return -errno;
177
178 if (streq(buf, s))
179 return 0;
180
181 if (sethostname(s, strlen(s)) < 0)
182 return -errno;
183
184 return 1;
185 }
186
187 int read_hostname_config(const char *path, char **hostname) {
188 _cleanup_fclose_ FILE *f = NULL;
189 char l[LINE_MAX];
190 char *name = NULL;
191
192 assert(path);
193 assert(hostname);
194
195 f = fopen(path, "re");
196 if (!f)
197 return -errno;
198
199 /* may have comments, ignore them */
200 FOREACH_LINE(l, f, return -errno) {
201 truncate_nl(l);
202 if (l[0] != '\0' && l[0] != '#') {
203 /* found line with value */
204 name = hostname_cleanup(l);
205 name = strdup(name);
206 if (!name)
207 return -ENOMEM;
208 break;
209 }
210 }
211
212 if (!name)
213 /* no non-empty line found */
214 return -ENOENT;
215
216 *hostname = name;
217 return 0;
218 }