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