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