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