]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
tty-ask-password: Split out password sending
[thirdparty/systemd.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 <bits/local_lim.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/utsname.h>
28 #include <unistd.h>
29
30 #include "fd-util.h"
31 #include "fileio.h"
32 #include "hostname-util.h"
33 #include "macro.h"
34 #include "string-util.h"
35
36 bool hostname_is_set(void) {
37 struct utsname u;
38
39 assert_se(uname(&u) >= 0);
40
41 if (isempty(u.nodename))
42 return false;
43
44 /* This is the built-in kernel default host name */
45 if (streq(u.nodename, "(none)"))
46 return false;
47
48 return true;
49 }
50
51 char* gethostname_malloc(void) {
52 struct utsname u;
53
54 assert_se(uname(&u) >= 0);
55
56 if (isempty(u.nodename) || streq(u.nodename, "(none)"))
57 return strdup(u.sysname);
58
59 return strdup(u.nodename);
60 }
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 char* hostname_cleanup(char *s) {
122 char *p, *d;
123 bool dot;
124
125 assert(s);
126
127 for (p = s, d = s, dot = true; *p; p++) {
128 if (*p == '.') {
129 if (dot)
130 continue;
131
132 *(d++) = '.';
133 dot = true;
134 } else if (hostname_valid_char(*p)) {
135 *(d++) = *p;
136 dot = false;
137 }
138
139 }
140
141 if (dot && d > s)
142 d[-1] = 0;
143 else
144 *d = 0;
145
146 strshorten(s, HOST_NAME_MAX);
147
148 return s;
149 }
150
151 bool is_localhost(const char *hostname) {
152 assert(hostname);
153
154 /* This tries to identify local host and domain names
155 * described in RFC6761 plus the redhatism of .localdomain */
156
157 return strcaseeq(hostname, "localhost") ||
158 strcaseeq(hostname, "localhost.") ||
159 strcaseeq(hostname, "localdomain.") ||
160 strcaseeq(hostname, "localdomain") ||
161 endswith_no_case(hostname, ".localhost") ||
162 endswith_no_case(hostname, ".localhost.") ||
163 endswith_no_case(hostname, ".localdomain") ||
164 endswith_no_case(hostname, ".localdomain.");
165 }
166
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 }