chiark / gitweb /
Remove utmp stuff that has found it's way back in.
[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 char* hostname_cleanup(char *s) {
117         char *p, *d;
118         bool dot;
119
120         assert(s);
121
122         for (p = s, d = s, dot = true; *p; p++) {
123                 if (*p == '.') {
124                         if (dot)
125                                 continue;
126
127                         *(d++) = '.';
128                         dot = true;
129                 } else if (hostname_valid_char(*p)) {
130                         *(d++) = *p;
131                         dot = false;
132                 }
133
134         }
135
136         if (dot && d > s)
137                 d[-1] = 0;
138         else
139                 *d = 0;
140
141         strshorten(s, HOST_NAME_MAX);
142
143         return s;
144 }
145
146 bool is_localhost(const char *hostname) {
147         assert(hostname);
148
149         /* This tries to identify local host and domain names
150          * described in RFC6761 plus the redhatism of .localdomain */
151
152         return strcaseeq(hostname, "localhost") ||
153                strcaseeq(hostname, "localhost.") ||
154                strcaseeq(hostname, "localdomain.") ||
155                strcaseeq(hostname, "localdomain") ||
156                endswith_no_case(hostname, ".localhost") ||
157                endswith_no_case(hostname, ".localhost.") ||
158                endswith_no_case(hostname, ".localdomain") ||
159                endswith_no_case(hostname, ".localdomain.");
160 }
161
162 /// UNNEEDED by elogind
163 #if 0
164 bool is_gateway_hostname(const char *hostname) {
165         assert(hostname);
166
167         /* This tries to identify the valid syntaxes for the our
168          * synthetic "gateway" host. */
169
170         return
171                 strcaseeq(hostname, "gateway") ||
172                 strcaseeq(hostname, "gateway.");
173 }
174
175 int sethostname_idempotent(const char *s) {
176         char buf[HOST_NAME_MAX + 1] = {};
177
178         assert(s);
179
180         if (gethostname(buf, sizeof(buf)) < 0)
181                 return -errno;
182
183         if (streq(buf, s))
184                 return 0;
185
186         if (sethostname(s, strlen(s)) < 0)
187                 return -errno;
188
189         return 1;
190 }
191
192 int read_hostname_config(const char *path, char **hostname) {
193         _cleanup_fclose_ FILE *f = NULL;
194         char l[LINE_MAX];
195         char *name = NULL;
196
197         assert(path);
198         assert(hostname);
199
200         f = fopen(path, "re");
201         if (!f)
202                 return -errno;
203
204         /* may have comments, ignore them */
205         FOREACH_LINE(l, f, return -errno) {
206                 truncate_nl(l);
207                 if (l[0] != '\0' && l[0] != '#') {
208                         /* found line with value */
209                         name = hostname_cleanup(l);
210                         name = strdup(name);
211                         if (!name)
212                                 return -ENOMEM;
213                         break;
214                 }
215         }
216
217         if (!name)
218                 /* no non-empty line found */
219                 return -ENOENT;
220
221         *hostname = name;
222         return 0;
223 }
224 #endif // 0