chiark / gitweb /
Prep v228: Add remaining updates from upstream (2/3)
[elogind.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 <ctype.h>
23 #include <sys/utsname.h>
24
25 //#include "fd-util.h"
26 #include "fileio.h"
27 #include "hostname-util.h"
28 #include "string-util.h"
29 #include "util.h"
30
31 /// UNNEEDED by elogind
32 #if 0
33 bool hostname_is_set(void) {
34         struct utsname u;
35
36         assert_se(uname(&u) >= 0);
37
38         if (isempty(u.nodename))
39                 return false;
40
41         /* This is the built-in kernel default host name */
42         if (streq(u.nodename, "(none)"))
43                 return false;
44
45         return true;
46 }
47
48 char* gethostname_malloc(void) {
49         struct utsname u;
50
51         assert_se(uname(&u) >= 0);
52
53         if (isempty(u.nodename) || streq(u.nodename, "(none)"))
54                 return strdup(u.sysname);
55
56         return strdup(u.nodename);
57 }
58 #endif // 0
59
60 static bool hostname_valid_char(char c) {
61         return
62                 (c >= 'a' && c <= 'z') ||
63                 (c >= 'A' && c <= 'Z') ||
64                 (c >= '0' && c <= '9') ||
65                 c == '-' ||
66                 c == '_' ||
67                 c == '.';
68 }
69
70 /**
71  * Check if s looks like a valid host name or FQDN. This does not do
72  * full DNS validation, but only checks if the name is composed of
73  * allowed characters and the length is not above the maximum allowed
74  * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
75  * allow_trailing_dot is true and at least two components are present
76  * in the name. Note that due to the restricted charset and length
77  * this call is substantially more conservative than
78  * dns_domain_is_valid().
79  */
80 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
81         unsigned n_dots = 0;
82         const char *p;
83         bool dot;
84
85         if (isempty(s))
86                 return false;
87
88         /* Doesn't accept empty hostnames, hostnames with
89          * leading dots, and hostnames with multiple dots in a
90          * sequence. Also ensures that the length stays below
91          * HOST_NAME_MAX. */
92
93         for (p = s, dot = true; *p; p++) {
94                 if (*p == '.') {
95                         if (dot)
96                                 return false;
97
98                         dot = true;
99                         n_dots ++;
100                 } else {
101                         if (!hostname_valid_char(*p))
102                                 return false;
103
104                         dot = false;
105                 }
106         }
107
108         if (dot && (n_dots < 2 || !allow_trailing_dot))
109                 return false;
110
111         if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
112                                   * Linux, but DNS allows domain names
113                                   * up to 255 characters */
114                 return false;
115
116         return true;
117 }
118
119 /// UNNEEDED by elogind
120 #if 0
121 char* hostname_cleanup(char *s) {
122         char *p, *d;
123         bool dot;
124
125         assert(s);
126
127         for (p = s, d = s, dot = true; *p; p++) {
128                 if (*p == '.') {
129                         if (dot)
130                                 continue;
131
132                         *(d++) = '.';
133                         dot = true;
134                 } else if (hostname_valid_char(*p)) {
135                         *(d++) = *p;
136                         dot = false;
137                 }
138
139         }
140
141         if (dot && d > s)
142                 d[-1] = 0;
143         else
144                 *d = 0;
145
146         strshorten(s, HOST_NAME_MAX);
147
148         return s;
149 }
150 #endif // 0
151
152 bool is_localhost(const char *hostname) {
153         assert(hostname);
154
155         /* This tries to identify local host and domain names
156          * described in RFC6761 plus the redhatism of .localdomain */
157
158         return strcaseeq(hostname, "localhost") ||
159                strcaseeq(hostname, "localhost.") ||
160                strcaseeq(hostname, "localdomain.") ||
161                strcaseeq(hostname, "localdomain") ||
162                endswith_no_case(hostname, ".localhost") ||
163                endswith_no_case(hostname, ".localhost.") ||
164                endswith_no_case(hostname, ".localdomain") ||
165                endswith_no_case(hostname, ".localdomain.");
166 }
167
168 /// UNNEEDED by elogind
169 #if 0
170 bool is_gateway_hostname(const char *hostname) {
171         assert(hostname);
172
173         /* This tries to identify the valid syntaxes for the our
174          * synthetic "gateway" host. */
175
176         return
177                 strcaseeq(hostname, "gateway") ||
178                 strcaseeq(hostname, "gateway.");
179 }
180
181 int sethostname_idempotent(const char *s) {
182         char buf[HOST_NAME_MAX + 1] = {};
183
184         assert(s);
185
186         if (gethostname(buf, sizeof(buf)) < 0)
187                 return -errno;
188
189         if (streq(buf, s))
190                 return 0;
191
192         if (sethostname(s, strlen(s)) < 0)
193                 return -errno;
194
195         return 1;
196 }
197
198 int read_hostname_config(const char *path, char **hostname) {
199         _cleanup_fclose_ FILE *f = NULL;
200         char l[LINE_MAX];
201         char *name = NULL;
202
203         assert(path);
204         assert(hostname);
205
206         f = fopen(path, "re");
207         if (!f)
208                 return -errno;
209
210         /* may have comments, ignore them */
211         FOREACH_LINE(l, f, return -errno) {
212                 truncate_nl(l);
213                 if (l[0] != '\0' && l[0] != '#') {
214                         /* found line with value */
215                         name = hostname_cleanup(l);
216                         name = strdup(name);
217                         if (!name)
218                                 return -ENOMEM;
219                         break;
220                 }
221         }
222
223         if (!name)
224                 /* no non-empty line found */
225                 return -ENOENT;
226
227         *hostname = name;
228         return 0;
229 }
230 #endif // 0