]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
Remove/add (un)needed includes
[thirdparty/systemd.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 <errno.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/utsname.h>
25 #include <unistd.h>
26
27 #include "fd-util.h"
28 #include "fileio.h"
29 #include "hostname-util.h"
30 #include "macro.h"
31 #include "string-util.h"
32
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
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_name_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 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
148 bool is_localhost(const char *hostname) {
149 assert(hostname);
150
151 /* This tries to identify local host and domain names
152 * described in RFC6761 plus the redhatism of .localdomain */
153
154 return strcaseeq(hostname, "localhost") ||
155 strcaseeq(hostname, "localhost.") ||
156 strcaseeq(hostname, "localdomain.") ||
157 strcaseeq(hostname, "localdomain") ||
158 endswith_no_case(hostname, ".localhost") ||
159 endswith_no_case(hostname, ".localhost.") ||
160 endswith_no_case(hostname, ".localdomain") ||
161 endswith_no_case(hostname, ".localdomain.");
162 }
163
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 }