chiark / gitweb /
b3d79c5a83f1aac516fa6e3daabd03be10b8d071
[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 <bits/local_lim.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/utsname.h>
26 #include <unistd.h>
27
28 //#include "fd-util.h"
29 #include "fileio.h"
30 #include "hostname-util.h"
31 //#include "macro.h"
32 #include "string-util.h"
33
34 #if 0 /// UNNEEDED by elogind
35 bool hostname_is_set(void) {
36         struct utsname u;
37
38         assert_se(uname(&u) >= 0);
39
40         if (isempty(u.nodename))
41                 return false;
42
43         /* This is the built-in kernel default host name */
44         if (streq(u.nodename, "(none)"))
45                 return false;
46
47         return true;
48 }
49
50 char* gethostname_malloc(void) {
51         struct utsname u;
52
53         assert_se(uname(&u) >= 0);
54
55         if (isempty(u.nodename) || streq(u.nodename, "(none)"))
56                 return strdup(u.sysname);
57
58         return strdup(u.nodename);
59 }
60 #endif // 0
61
62 static bool hostname_valid_char(char c) {
63         return
64                 (c >= 'a' && c <= 'z') ||
65                 (c >= 'A' && c <= 'Z') ||
66                 (c >= '0' && c <= '9') ||
67                 c == '-' ||
68                 c == '_' ||
69                 c == '.';
70 }
71
72 /**
73  * Check if s looks like a valid host name or FQDN. This does not do
74  * full DNS validation, but only checks if the name is composed of
75  * allowed characters and the length is not above the maximum allowed
76  * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
77  * allow_trailing_dot is true and at least two components are present
78  * in the name. Note that due to the restricted charset and length
79  * this call is substantially more conservative than
80  * dns_name_is_valid().
81  */
82 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
83         unsigned n_dots = 0;
84         const char *p;
85         bool dot;
86
87         if (isempty(s))
88                 return false;
89
90         /* Doesn't accept empty hostnames, hostnames with
91          * leading dots, and hostnames with multiple dots in a
92          * sequence. Also ensures that the length stays below
93          * HOST_NAME_MAX. */
94
95         for (p = s, dot = true; *p; p++) {
96                 if (*p == '.') {
97                         if (dot)
98                                 return false;
99
100                         dot = true;
101                         n_dots ++;
102                 } else {
103                         if (!hostname_valid_char(*p))
104                                 return false;
105
106                         dot = false;
107                 }
108         }
109
110         if (dot && (n_dots < 2 || !allow_trailing_dot))
111                 return false;
112
113         if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
114                                   * Linux, but DNS allows domain names
115                                   * up to 255 characters */
116                 return false;
117
118         return true;
119 }
120
121 #if 0 /// UNNEEDED by elogind
122 char* hostname_cleanup(char *s) {
123         char *p, *d;
124         bool dot;
125
126         assert(s);
127
128         for (p = s, d = s, dot = true; *p; p++) {
129                 if (*p == '.') {
130                         if (dot)
131                                 continue;
132
133                         *(d++) = '.';
134                         dot = true;
135                 } else if (hostname_valid_char(*p)) {
136                         *(d++) = *p;
137                         dot = false;
138                 }
139
140         }
141
142         if (dot && d > s)
143                 d[-1] = 0;
144         else
145                 *d = 0;
146
147         strshorten(s, HOST_NAME_MAX);
148
149         return s;
150 }
151 #endif // 0
152
153 bool is_localhost(const char *hostname) {
154         assert(hostname);
155
156         /* This tries to identify local host and domain names
157          * described in RFC6761 plus the redhatism of .localdomain */
158
159         return strcaseeq(hostname, "localhost") ||
160                strcaseeq(hostname, "localhost.") ||
161                strcaseeq(hostname, "localdomain.") ||
162                strcaseeq(hostname, "localdomain") ||
163                endswith_no_case(hostname, ".localhost") ||
164                endswith_no_case(hostname, ".localhost.") ||
165                endswith_no_case(hostname, ".localdomain") ||
166                endswith_no_case(hostname, ".localdomain.");
167 }
168
169 #if 0 /// UNNEEDED by elogind
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