]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-myhostname/nss-myhostname.c
fileio: unify how we chop off whitespace from key and value in parse_env_file_internal()
[thirdparty/systemd.git] / src / nss-myhostname / nss-myhostname.c
CommitLineData
8041b5ba 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4e8c8252 2
4e8c8252 3/***
cbc06dcd 4 This file is part of systemd.
4e8c8252 5
8041b5ba 6 Copyright 2008-2011 Lennart Poettering
4e8c8252 7
cbc06dcd
TG
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.
4e8c8252 12
cbc06dcd
TG
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
4e8c8252 17
cbc06dcd
TG
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/>.
4e8c8252 20***/
6b21f0cf
LP
21
22#include <limits.h>
23#include <nss.h>
24#include <sys/types.h>
25#include <netdb.h>
26#include <errno.h>
27#include <string.h>
6b21f0cf 28#include <unistd.h>
4e8c8252 29#include <net/if.h>
8041b5ba
LP
30#include <stdlib.h>
31#include <arpa/inet.h>
32
1df2a0fc 33#include "ifconf.h"
1c633045
ZJS
34#include "macro.h"
35#include "util.h"
4e8c8252 36
1e335af7
DR
37/* Ensure that glibc's assert is used. We cannot use assert from macro.h, as
38 * libnss_myhostname will be linked into arbitrary programs which will, in turn
39 * attempt to write to the journal via log_dispatch() */
40#include <assert.h>
41
4e8c8252
LP
42/* We use 127.0.0.2 as IPv4 address. This has the advantage over
43 * 127.0.0.1 that it can be translated back to the local hostname. For
44 * IPv6 we use ::1 which unfortunately will not translate back to the
45 * hostname but instead something like "localhost6" or so. */
46
47#define LOCALADDRESS_IPV4 (htonl(0x7F000002))
48#define LOCALADDRESS_IPV6 &in6addr_loopback
49#define LOOPBACK_INTERFACE "lo"
50
8041b5ba
LP
51enum nss_status _nss_myhostname_gethostbyname4_r(
52 const char *name,
53 struct gaih_addrtuple **pat,
54 char *buffer, size_t buflen,
55 int *errnop, int *h_errnop,
fe0fc11b 56 int32_t *ttlp) _public_;
8041b5ba
LP
57
58enum nss_status _nss_myhostname_gethostbyname3_r(
59 const char *name,
60 int af,
61 struct hostent *host,
62 char *buffer, size_t buflen,
63 int *errnop, int *h_errnop,
64 int32_t *ttlp,
fe0fc11b 65 char **canonp) _public_;
8041b5ba
LP
66
67enum nss_status _nss_myhostname_gethostbyname2_r(
68 const char *name,
69 int af,
70 struct hostent *host,
71 char *buffer, size_t buflen,
fe0fc11b 72 int *errnop, int *h_errnop) _public_;
8041b5ba
LP
73
74enum nss_status _nss_myhostname_gethostbyname_r(
75 const char *name,
76 struct hostent *host,
77 char *buffer, size_t buflen,
fe0fc11b 78 int *errnop, int *h_errnop) _public_;
8041b5ba
LP
79
80enum nss_status _nss_myhostname_gethostbyaddr2_r(
81 const void* addr, socklen_t len,
82 int af,
83 struct hostent *host,
84 char *buffer, size_t buflen,
85 int *errnop, int *h_errnop,
fe0fc11b 86 int32_t *ttlp) _public_;
8041b5ba
LP
87
88enum nss_status _nss_myhostname_gethostbyaddr_r(
89 const void* addr, socklen_t len,
90 int af,
91 struct hostent *host,
92 char *buffer, size_t buflen,
fe0fc11b 93 int *errnop, int *h_errnop) _public_;
8041b5ba 94
4e8c8252
LP
95enum nss_status _nss_myhostname_gethostbyname4_r(
96 const char *name,
97 struct gaih_addrtuple **pat,
98 char *buffer, size_t buflen,
99 int *errnop, int *h_errnop,
100 int32_t *ttlp) {
101
8041b5ba 102 unsigned lo_ifi;
1c633045 103 char hn[HOST_NAME_MAX+1] = {};
4e8c8252
LP
104 size_t l, idx, ms;
105 char *r_name;
8041b5ba
LP
106 struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
107 struct address *addresses = NULL, *a;
108 unsigned n_addresses = 0, n;
4e8c8252 109
4e8c8252
LP
110 if (gethostname(hn, sizeof(hn)-1) < 0) {
111 *errnop = errno;
112 *h_errnop = NO_RECOVERY;
113 return NSS_STATUS_UNAVAIL;
114 }
115
116 if (strcasecmp(name, hn) != 0) {
117 *errnop = ENOENT;
118 *h_errnop = HOST_NOT_FOUND;
119 return NSS_STATUS_NOTFOUND;
120 }
6b21f0cf 121
8041b5ba 122 /* If this fails, n_addresses is 0. Which is fine */
1df2a0fc 123 ifconf_acquire_addresses(&addresses, &n_addresses);
8041b5ba 124
4e8c8252 125 /* If this call fails we fill in 0 as scope. Which is fine */
8041b5ba 126 lo_ifi = if_nametoindex(LOOPBACK_INTERFACE);
4e8c8252
LP
127
128 l = strlen(hn);
8041b5ba 129 ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*(n_addresses > 0 ? n_addresses : 2);
4e8c8252
LP
130 if (buflen < ms) {
131 *errnop = ENOMEM;
132 *h_errnop = NO_RECOVERY;
8041b5ba 133 free(addresses);
4e8c8252
LP
134 return NSS_STATUS_TRYAGAIN;
135 }
136
137 /* First, fill in hostname */
138 r_name = buffer;
139 memcpy(r_name, hn, l+1);
140 idx = ALIGN(l+1);
141
8041b5ba
LP
142 if (n_addresses <= 0) {
143 /* Second, fill in IPv6 tuple */
144 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
145 r_tuple->next = r_tuple_prev;
146 r_tuple->name = r_name;
147 r_tuple->family = AF_INET6;
148 memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
149 r_tuple->scopeid = (uint32_t) lo_ifi;
150
151 idx += ALIGN(sizeof(struct gaih_addrtuple));
152 r_tuple_prev = r_tuple;
153
154 /* Third, fill in IPv4 tuple */
155 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
156 r_tuple->next = r_tuple_prev;
157 r_tuple->name = r_name;
158 r_tuple->family = AF_INET;
159 *(uint32_t*) r_tuple->addr = LOCALADDRESS_IPV4;
160 r_tuple->scopeid = (uint32_t) lo_ifi;
161
162 idx += ALIGN(sizeof(struct gaih_addrtuple));
163 r_tuple_prev = r_tuple;
164 }
165
166 /* Fourth, fill actual addresses in, but in backwards order */
167 for (a = addresses + n_addresses - 1, n = 0; n < n_addresses; n++, a--) {
168 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
169 r_tuple->next = r_tuple_prev;
170 r_tuple->name = r_name;
171 r_tuple->family = a->family;
172 r_tuple->scopeid = a->ifindex;
173 memcpy(r_tuple->addr, a->address, 16);
174
175 idx += ALIGN(sizeof(struct gaih_addrtuple));
176 r_tuple_prev = r_tuple;
177 }
4e8c8252
LP
178
179 /* Verify the size matches */
180 assert(idx == ms);
181
d2f1f23a
ED
182 /* Nscd expects us to store the first record in **pat. */
183 if (*pat)
184 **pat = *r_tuple_prev;
185 else
186 *pat = r_tuple_prev;
4e8c8252
LP
187
188 if (ttlp)
189 *ttlp = 0;
190
8041b5ba
LP
191 free(addresses);
192
4e8c8252
LP
193 return NSS_STATUS_SUCCESS;
194}
6b21f0cf
LP
195
196static enum nss_status fill_in_hostent(
4e8c8252
LP
197 const char *hn,
198 int af,
199 struct hostent *result,
200 char *buffer, size_t buflen,
201 int *errnop, int *h_errnop,
202 int32_t *ttlp,
203 char **canonp) {
204
205 size_t l, idx, ms;
206 char *r_addr, *r_name, *r_aliases, *r_addr_list;
207 size_t alen;
8041b5ba
LP
208 struct address *addresses = NULL, *a;
209 unsigned n_addresses = 0, n, c;
210
211 alen = PROTO_ADDRESS_SIZE(af);
212
1df2a0fc 213 ifconf_acquire_addresses(&addresses, &n_addresses);
4e8c8252 214
8041b5ba
LP
215 for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
216 if (af == a->family)
217 c++;
4e8c8252
LP
218
219 l = strlen(hn);
8041b5ba
LP
220 ms = ALIGN(l+1)+
221 sizeof(char*)+
222 (c > 0 ? c : 1)*ALIGN(alen)+
223 (c > 0 ? c+1 : 2)*sizeof(char*);
224
4e8c8252
LP
225 if (buflen < ms) {
226 *errnop = ENOMEM;
227 *h_errnop = NO_RECOVERY;
8041b5ba 228 free(addresses);
4e8c8252
LP
229 return NSS_STATUS_TRYAGAIN;
230 }
231
232 /* First, fill in hostname */
233 r_name = buffer;
234 memcpy(r_name, hn, l+1);
235 idx = ALIGN(l+1);
236
8041b5ba 237 /* Second, create (empty) aliases array */
4e8c8252
LP
238 r_aliases = buffer + idx;
239 *(char**) r_aliases = NULL;
240 idx += sizeof(char*);
241
8041b5ba 242 /* Third, add addresses */
4e8c8252 243 r_addr = buffer + idx;
8041b5ba
LP
244 if (c > 0) {
245 unsigned i = 0;
246
247 for (a = addresses, n = 0; n < n_addresses; a++, n++) {
248 if (af != a->family)
249 continue;
250
251 memcpy(r_addr + i*ALIGN(alen), a->address, alen);
252 i++;
253 }
254
255 assert(i == c);
256 idx += c*ALIGN(alen);
257 } else {
258 if (af == AF_INET)
259 *(uint32_t*) r_addr = LOCALADDRESS_IPV4;
260 else
261 memcpy(r_addr, LOCALADDRESS_IPV6, 16);
262
263 idx += ALIGN(alen);
264 }
4e8c8252
LP
265
266 /* Fourth, add address pointer array */
267 r_addr_list = buffer + idx;
8041b5ba
LP
268 if (c > 0) {
269 unsigned i = 0;
270
271 for (a = addresses, n = 0; n < n_addresses; a++, n++) {
272 if (af != a->family)
273 continue;
274
275 ((char**) r_addr_list)[i] = (r_addr + i*ALIGN(alen));
276 i++;
277 }
278
279 assert(i == c);
280 ((char**) r_addr_list)[c] = NULL;
281 idx += (c+1)*sizeof(char*);
282
283 } else {
284 ((char**) r_addr_list)[0] = r_addr;
285 ((char**) r_addr_list)[1] = NULL;
286 idx += 2*sizeof(char*);
287 }
4e8c8252
LP
288
289 /* Verify the size matches */
290 assert(idx == ms);
291
292 result->h_name = r_name;
293 result->h_aliases = (char**) r_aliases;
294 result->h_addrtype = af;
295 result->h_length = alen;
296 result->h_addr_list = (char**) r_addr_list;
297
298 if (ttlp)
299 *ttlp = 0;
300
301 if (canonp)
302 *canonp = r_name;
303
8041b5ba
LP
304 free(addresses);
305
4e8c8252 306 return NSS_STATUS_SUCCESS;
6b21f0cf
LP
307}
308
4e8c8252
LP
309enum nss_status _nss_myhostname_gethostbyname3_r(
310 const char *name,
311 int af,
312 struct hostent *host,
313 char *buffer, size_t buflen,
314 int *errnop, int *h_errnop,
315 int32_t *ttlp,
316 char **canonp) {
6b21f0cf 317
1c633045 318 char hn[HOST_NAME_MAX+1] = {};
6b21f0cf 319
4e8c8252
LP
320 if (af == AF_UNSPEC)
321 af = AF_INET;
6b21f0cf 322
4e8c8252
LP
323 if (af != AF_INET && af != AF_INET6) {
324 *errnop = EAFNOSUPPORT;
325 *h_errnop = NO_DATA;
326 return NSS_STATUS_UNAVAIL;
327 }
6b21f0cf 328
4e8c8252
LP
329 if (gethostname(hn, sizeof(hn)-1) < 0) {
330 *errnop = errno;
331 *h_errnop = NO_RECOVERY;
332 return NSS_STATUS_UNAVAIL;
333 }
6b21f0cf 334
4e8c8252
LP
335 if (strcasecmp(name, hn) != 0) {
336 *errnop = ENOENT;
337 *h_errnop = HOST_NOT_FOUND;
338 return NSS_STATUS_NOTFOUND;
339 }
6b21f0cf 340
4e8c8252
LP
341 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, canonp);
342}
6b21f0cf 343
4e8c8252
LP
344enum nss_status _nss_myhostname_gethostbyname2_r(
345 const char *name,
346 int af,
347 struct hostent *host,
348 char *buffer, size_t buflen,
349 int *errnop, int *h_errnop) {
6b21f0cf 350
4e8c8252
LP
351 return _nss_myhostname_gethostbyname3_r(
352 name,
353 af,
354 host,
355 buffer, buflen,
356 errnop, h_errnop,
357 NULL,
358 NULL);
6b21f0cf
LP
359}
360
8041b5ba 361enum nss_status _nss_myhostname_gethostbyname_r(
4e8c8252
LP
362 const char *name,
363 struct hostent *host,
364 char *buffer, size_t buflen,
365 int *errnop, int *h_errnop) {
366
367 return _nss_myhostname_gethostbyname3_r(
368 name,
369 AF_UNSPEC,
370 host,
371 buffer, buflen,
372 errnop, h_errnop,
373 NULL,
374 NULL);
6b21f0cf
LP
375}
376
4e8c8252
LP
377enum nss_status _nss_myhostname_gethostbyaddr2_r(
378 const void* addr, socklen_t len,
379 int af,
380 struct hostent *host,
381 char *buffer, size_t buflen,
382 int *errnop, int *h_errnop,
383 int32_t *ttlp) {
6b21f0cf 384
1c633045 385 char hn[HOST_NAME_MAX+1] = {};
7fd1b19b 386 _cleanup_free_ struct address *addresses = NULL;
1c633045 387 struct address *a;
8041b5ba
LP
388 unsigned n_addresses = 0, n;
389
390 if (len != PROTO_ADDRESS_SIZE(af)) {
391 *errnop = EINVAL;
392 *h_errnop = NO_RECOVERY;
393 return NSS_STATUS_UNAVAIL;
394 }
6b21f0cf 395
4e8c8252 396 if (af == AF_INET) {
8041b5ba
LP
397
398 if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
399 goto found;
6b21f0cf 400
4e8c8252 401 } else if (af == AF_INET6) {
8041b5ba
LP
402
403 if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0)
404 goto found;
405
4e8c8252
LP
406 } else {
407 *errnop = EAFNOSUPPORT;
408 *h_errnop = NO_DATA;
409 return NSS_STATUS_UNAVAIL;
410 }
411
1df2a0fc 412 ifconf_acquire_addresses(&addresses, &n_addresses);
8041b5ba
LP
413
414 for (a = addresses, n = 0; n < n_addresses; n++, a++) {
415 if (af != a->family)
416 continue;
417
418 if (memcmp(addr, a->address, PROTO_ADDRESS_SIZE(af)) == 0)
419 goto found;
420 }
421
422 *errnop = ENOENT;
423 *h_errnop = HOST_NOT_FOUND;
424
8041b5ba
LP
425 return NSS_STATUS_NOTFOUND;
426
427found:
4e8c8252
LP
428 if (gethostname(hn, sizeof(hn)-1) < 0) {
429 *errnop = errno;
430 *h_errnop = NO_RECOVERY;
8041b5ba 431
4e8c8252
LP
432 return NSS_STATUS_UNAVAIL;
433 }
434
435 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
436
4e8c8252 437}
6b21f0cf 438
4e8c8252
LP
439enum nss_status _nss_myhostname_gethostbyaddr_r(
440 const void* addr, socklen_t len,
441 int af,
442 struct hostent *host,
443 char *buffer, size_t buflen,
444 int *errnop, int *h_errnop) {
6b21f0cf 445
4e8c8252
LP
446 return _nss_myhostname_gethostbyaddr2_r(
447 addr, len,
448 af,
449 host,
450 buffer, buflen,
451 errnop, h_errnop,
452 NULL);
6b21f0cf 453}