]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-myhostname/nss-myhostname.c
util-lib: rework get_process_cmdline() (#3529)
[thirdparty/systemd.git] / src / nss-myhostname / nss-myhostname.c
CommitLineData
4e8c8252 1/***
cbc06dcd 2 This file is part of systemd.
4e8c8252 3
8041b5ba 4 Copyright 2008-2011 Lennart Poettering
4e8c8252 5
cbc06dcd
TG
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.
4e8c8252 10
cbc06dcd
TG
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
4e8c8252 15
cbc06dcd
TG
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/>.
4e8c8252 18***/
6b21f0cf 19
6b21f0cf 20#include <errno.h>
4e8c8252 21#include <net/if.h>
07630cea
LP
22#include <netdb.h>
23#include <nss.h>
8041b5ba 24#include <stdlib.h>
07630cea 25#include <string.h>
8041b5ba 26
b5efdb8a 27#include "alloc-util.h"
07630cea 28#include "hostname-util.h"
e80af1bd 29#include "local-addresses.h"
1c633045 30#include "macro.h"
c9fdc26e 31#include "nss-util.h"
0c5eb056 32#include "signal-util.h"
07630cea 33#include "string-util.h"
c9fdc26e 34#include "util.h"
4e8c8252
LP
35
36/* We use 127.0.0.2 as IPv4 address. This has the advantage over
37 * 127.0.0.1 that it can be translated back to the local hostname. For
38 * IPv6 we use ::1 which unfortunately will not translate back to the
3fdcecc8 39 * hostname but instead something like "localhost" or so. */
4e8c8252
LP
40
41#define LOCALADDRESS_IPV4 (htonl(0x7F000002))
42#define LOCALADDRESS_IPV6 &in6addr_loopback
4e8c8252 43
c9fdc26e
LP
44NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
45NSS_GETHOSTBYADDR_PROTOTYPES(myhostname);
8041b5ba 46
4e8c8252
LP
47enum nss_status _nss_myhostname_gethostbyname4_r(
48 const char *name,
49 struct gaih_addrtuple **pat,
50 char *buffer, size_t buflen,
51 int *errnop, int *h_errnop,
52 int32_t *ttlp) {
53
8041b5ba 54 struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
e80af1bd 55 _cleanup_free_ struct local_address *addresses = NULL;
5502f0d9
LP
56 _cleanup_free_ char *hn = NULL;
57 const char *canonical = NULL;
e80af1bd 58 int n_addresses = 0, lo_ifi;
e8a7a315 59 uint32_t local_address_ipv4;
e80af1bd 60 struct local_address *a;
5502f0d9
LP
61 size_t l, idx, ms;
62 char *r_name;
e80af1bd 63 unsigned n;
4e8c8252 64
0c5eb056
LP
65 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
66
5502f0d9
LP
67 assert(name);
68 assert(pat);
69 assert(buffer);
70 assert(errnop);
71 assert(h_errnop);
72
73 if (is_localhost(name)) {
e8a7a315
LP
74 /* We respond to 'localhost', so that /etc/hosts
75 * is optional */
4e8c8252 76
e8a7a315
LP
77 canonical = "localhost";
78 local_address_ipv4 = htonl(INADDR_LOOPBACK);
e9140aff 79
46a5e0e7 80 } else if (is_gateway_hostname(name)) {
e9140aff 81
1d050e1e 82 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
e9140aff
LP
83 if (n_addresses <= 0) {
84 *errnop = ENOENT;
85 *h_errnop = HOST_NOT_FOUND;
86 return NSS_STATUS_NOTFOUND;
87 }
88
89 canonical = "gateway";
90
e8a7a315 91 } else {
5502f0d9
LP
92 hn = gethostname_malloc();
93 if (!hn) {
94 *errnop = ENOMEM;
e8a7a315 95 *h_errnop = NO_RECOVERY;
5502f0d9 96 return NSS_STATUS_TRYAGAIN;
e8a7a315
LP
97 }
98
5502f0d9
LP
99 /* We respond to our local host name, our our hostname suffixed with a single dot. */
100 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
e8a7a315
LP
101 *errnop = ENOENT;
102 *h_errnop = HOST_NOT_FOUND;
103 return NSS_STATUS_NOTFOUND;
104 }
105
1d050e1e 106 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
e80af1bd
LP
107 if (n_addresses < 0)
108 n_addresses = 0;
e8a7a315
LP
109
110 canonical = hn;
111 local_address_ipv4 = LOCALADDRESS_IPV4;
112 }
8041b5ba 113
4e8c8252 114 /* If this call fails we fill in 0 as scope. Which is fine */
f4324288 115 lo_ifi = n_addresses <= 0 ? LOOPBACK_IFINDEX : 0;
4e8c8252 116
e8a7a315 117 l = strlen(canonical);
5502f0d9 118 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
4e8c8252
LP
119 if (buflen < ms) {
120 *errnop = ENOMEM;
121 *h_errnop = NO_RECOVERY;
122 return NSS_STATUS_TRYAGAIN;
123 }
124
125 /* First, fill in hostname */
126 r_name = buffer;
e8a7a315 127 memcpy(r_name, canonical, l+1);
4e8c8252
LP
128 idx = ALIGN(l+1);
129
68a9c7c4
ZJS
130 assert(n_addresses >= 0);
131 if (n_addresses == 0) {
8041b5ba
LP
132 /* Second, fill in IPv6 tuple */
133 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
134 r_tuple->next = r_tuple_prev;
135 r_tuple->name = r_name;
136 r_tuple->family = AF_INET6;
137 memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
138 r_tuple->scopeid = (uint32_t) lo_ifi;
139
140 idx += ALIGN(sizeof(struct gaih_addrtuple));
141 r_tuple_prev = r_tuple;
142
143 /* Third, fill in IPv4 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_INET;
e8a7a315 148 *(uint32_t*) r_tuple->addr = local_address_ipv4;
8041b5ba
LP
149 r_tuple->scopeid = (uint32_t) lo_ifi;
150
151 idx += ALIGN(sizeof(struct gaih_addrtuple));
152 r_tuple_prev = r_tuple;
153 }
154
155 /* Fourth, fill actual addresses in, but in backwards order */
e80af1bd 156 for (a = addresses + n_addresses - 1, n = 0; (int) n < n_addresses; n++, a--) {
8041b5ba
LP
157 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
158 r_tuple->next = r_tuple_prev;
159 r_tuple->name = r_name;
160 r_tuple->family = a->family;
161 r_tuple->scopeid = a->ifindex;
5502f0d9 162 memcpy(r_tuple->addr, &a->address, 16);
8041b5ba
LP
163
164 idx += ALIGN(sizeof(struct gaih_addrtuple));
165 r_tuple_prev = r_tuple;
166 }
4e8c8252
LP
167
168 /* Verify the size matches */
169 assert(idx == ms);
170
d2f1f23a
ED
171 /* Nscd expects us to store the first record in **pat. */
172 if (*pat)
173 **pat = *r_tuple_prev;
174 else
175 *pat = r_tuple_prev;
4e8c8252
LP
176
177 if (ttlp)
178 *ttlp = 0;
179
e70df46b
LP
180 /* Explicitly reset all error variables */
181 *errnop = 0;
182 *h_errnop = NETDB_SUCCESS;
183 h_errno = 0;
184
4e8c8252
LP
185 return NSS_STATUS_SUCCESS;
186}
6b21f0cf
LP
187
188static enum nss_status fill_in_hostent(
e8a7a315 189 const char *canonical, const char *additional,
4e8c8252 190 int af,
e80af1bd 191 struct local_address *addresses, unsigned n_addresses,
e8a7a315 192 uint32_t local_address_ipv4,
4e8c8252
LP
193 struct hostent *result,
194 char *buffer, size_t buflen,
195 int *errnop, int *h_errnop,
196 int32_t *ttlp,
197 char **canonp) {
198
d4c9895d 199 size_t l_canonical, l_additional, idx, ms, alen;
e8a7a315 200 char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list;
e80af1bd 201 struct local_address *a;
e8a7a315 202 unsigned n, c;
8041b5ba 203
5502f0d9
LP
204 assert(canonical);
205 assert(result);
206 assert(buffer);
207 assert(errnop);
208 assert(h_errnop);
209
9d485985 210 alen = FAMILY_ADDRESS_SIZE(af);
8041b5ba 211
8041b5ba
LP
212 for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
213 if (af == a->family)
214 c++;
4e8c8252 215
e8a7a315
LP
216 l_canonical = strlen(canonical);
217 l_additional = additional ? strlen(additional) : 0;
218 ms = ALIGN(l_canonical+1)+
219 (additional ? ALIGN(l_additional+1) : 0) +
5502f0d9 220 sizeof(char*) +
e8a7a315 221 (additional ? sizeof(char*) : 0) +
d4c9895d 222 (c > 0 ? c : 1) * ALIGN(alen) +
5502f0d9 223 (c > 0 ? c+1 : 2) * sizeof(char*);
8041b5ba 224
4e8c8252
LP
225 if (buflen < ms) {
226 *errnop = ENOMEM;
227 *h_errnop = NO_RECOVERY;
228 return NSS_STATUS_TRYAGAIN;
229 }
230
e8a7a315 231 /* First, fill in hostnames */
4e8c8252 232 r_name = buffer;
e8a7a315
LP
233 memcpy(r_name, canonical, l_canonical+1);
234 idx = ALIGN(l_canonical+1);
4e8c8252 235
e8a7a315
LP
236 if (additional) {
237 r_alias = buffer + idx;
238 memcpy(r_alias, additional, l_additional+1);
239 idx += ALIGN(l_additional+1);
240 }
241
242 /* Second, create aliases array */
4e8c8252 243 r_aliases = buffer + idx;
e8a7a315
LP
244 if (additional) {
245 ((char**) r_aliases)[0] = r_alias;
246 ((char**) r_aliases)[1] = NULL;
247 idx += 2*sizeof(char*);
248 } else {
249 ((char**) r_aliases)[0] = NULL;
250 idx += sizeof(char*);
251 }
4e8c8252 252
8041b5ba 253 /* Third, add addresses */
4e8c8252 254 r_addr = buffer + idx;
8041b5ba
LP
255 if (c > 0) {
256 unsigned i = 0;
257
258 for (a = addresses, n = 0; n < n_addresses; a++, n++) {
259 if (af != a->family)
260 continue;
261
5502f0d9 262 memcpy(r_addr + i*ALIGN(alen), &a->address, alen);
8041b5ba
LP
263 i++;
264 }
265
266 assert(i == c);
267 idx += c*ALIGN(alen);
268 } else {
269 if (af == AF_INET)
e8a7a315 270 *(uint32_t*) r_addr = local_address_ipv4;
8041b5ba
LP
271 else
272 memcpy(r_addr, LOCALADDRESS_IPV6, 16);
273
274 idx += ALIGN(alen);
275 }
4e8c8252
LP
276
277 /* Fourth, add address pointer array */
278 r_addr_list = buffer + idx;
8041b5ba 279 if (c > 0) {
d4c9895d 280 unsigned i;
8041b5ba 281
d4c9895d
LP
282 for (i = 0; i < c; i++)
283 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
8041b5ba 284
d4c9895d
LP
285 ((char**) r_addr_list)[i] = NULL;
286 idx += (c+1) * sizeof(char*);
8041b5ba
LP
287
288 } else {
289 ((char**) r_addr_list)[0] = r_addr;
290 ((char**) r_addr_list)[1] = NULL;
d4c9895d 291 idx += 2 * sizeof(char*);
8041b5ba 292 }
4e8c8252
LP
293
294 /* Verify the size matches */
295 assert(idx == ms);
296
297 result->h_name = r_name;
298 result->h_aliases = (char**) r_aliases;
299 result->h_addrtype = af;
300 result->h_length = alen;
301 result->h_addr_list = (char**) r_addr_list;
302
303 if (ttlp)
304 *ttlp = 0;
305
306 if (canonp)
307 *canonp = r_name;
308
e70df46b
LP
309 /* Explicitly reset all error variables */
310 *errnop = 0;
311 *h_errnop = NETDB_SUCCESS;
312 h_errno = 0;
313
4e8c8252 314 return NSS_STATUS_SUCCESS;
6b21f0cf
LP
315}
316
4e8c8252
LP
317enum nss_status _nss_myhostname_gethostbyname3_r(
318 const char *name,
319 int af,
320 struct hostent *host,
321 char *buffer, size_t buflen,
322 int *errnop, int *h_errnop,
323 int32_t *ttlp,
324 char **canonp) {
6b21f0cf 325
e80af1bd 326 _cleanup_free_ struct local_address *addresses = NULL;
e8a7a315 327 const char *canonical, *additional = NULL;
5502f0d9 328 _cleanup_free_ char *hn = NULL;
e9140aff 329 uint32_t local_address_ipv4 = 0;
e80af1bd 330 int n_addresses = 0;
5502f0d9 331
0c5eb056
LP
332 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
333
5502f0d9
LP
334 assert(name);
335 assert(host);
336 assert(buffer);
337 assert(errnop);
338 assert(h_errnop);
6b21f0cf 339
4e8c8252
LP
340 if (af == AF_UNSPEC)
341 af = AF_INET;
6b21f0cf 342
4e8c8252
LP
343 if (af != AF_INET && af != AF_INET6) {
344 *errnop = EAFNOSUPPORT;
345 *h_errnop = NO_DATA;
346 return NSS_STATUS_UNAVAIL;
347 }
6b21f0cf 348
5502f0d9 349 if (is_localhost(name)) {
e8a7a315
LP
350 canonical = "localhost";
351 local_address_ipv4 = htonl(INADDR_LOOPBACK);
e9140aff 352
46a5e0e7 353 } else if (is_gateway_hostname(name)) {
e9140aff 354
1d050e1e 355 n_addresses = local_gateways(NULL, 0, af, &addresses);
e9140aff
LP
356 if (n_addresses <= 0) {
357 *errnop = ENOENT;
358 *h_errnop = HOST_NOT_FOUND;
359 return NSS_STATUS_NOTFOUND;
360 }
361
362 canonical = "gateway";
363
e8a7a315 364 } else {
5502f0d9
LP
365 hn = gethostname_malloc();
366 if (!hn) {
367 *errnop = ENOMEM;
e8a7a315 368 *h_errnop = NO_RECOVERY;
5502f0d9 369 return NSS_STATUS_TRYAGAIN;
e8a7a315 370 }
6b21f0cf 371
5502f0d9 372 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
e8a7a315
LP
373 *errnop = ENOENT;
374 *h_errnop = HOST_NOT_FOUND;
375 return NSS_STATUS_NOTFOUND;
376 }
377
1d050e1e 378 n_addresses = local_addresses(NULL, 0, af, &addresses);
e80af1bd
LP
379 if (n_addresses < 0)
380 n_addresses = 0;
e8a7a315
LP
381
382 canonical = hn;
383 additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL;
384 local_address_ipv4 = LOCALADDRESS_IPV4;
4e8c8252 385 }
6b21f0cf 386
e8a7a315
LP
387 return fill_in_hostent(
388 canonical, additional,
389 af,
390 addresses, n_addresses,
391 local_address_ipv4,
392 host,
393 buffer, buflen,
394 errnop, h_errnop,
395 ttlp,
396 canonp);
4e8c8252 397}
6b21f0cf 398
4e8c8252
LP
399enum nss_status _nss_myhostname_gethostbyaddr2_r(
400 const void* addr, socklen_t len,
401 int af,
402 struct hostent *host,
403 char *buffer, size_t buflen,
404 int *errnop, int *h_errnop,
405 int32_t *ttlp) {
6b21f0cf 406
e8a7a315 407 const char *canonical = NULL, *additional = NULL;
5502f0d9 408 uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
e80af1bd 409 _cleanup_free_ struct local_address *addresses = NULL;
5502f0d9 410 _cleanup_free_ char *hn = NULL;
e80af1bd
LP
411 int n_addresses = 0;
412 struct local_address *a;
3fdcecc8 413 bool additional_from_hostname = false;
e80af1bd 414 unsigned n;
5502f0d9 415
0c5eb056
LP
416 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
417
5502f0d9
LP
418 assert(addr);
419 assert(host);
420 assert(buffer);
421 assert(errnop);
422 assert(h_errnop);
8041b5ba 423
555bd6e9
LP
424 if (!IN_SET(af, AF_INET, AF_INET6)) {
425 *errnop = EAFNOSUPPORT;
426 *h_errnop = NO_DATA;
427 return NSS_STATUS_UNAVAIL;
428 }
429
9d485985 430 if (len != FAMILY_ADDRESS_SIZE(af)) {
8041b5ba
LP
431 *errnop = EINVAL;
432 *h_errnop = NO_RECOVERY;
433 return NSS_STATUS_UNAVAIL;
434 }
6b21f0cf 435
4e8c8252 436 if (af == AF_INET) {
8041b5ba
LP
437 if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
438 goto found;
6b21f0cf 439
e8a7a315
LP
440 if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) {
441 canonical = "localhost";
442 local_address_ipv4 = htonl(INADDR_LOOPBACK);
443 goto found;
444 }
445
555bd6e9
LP
446 } else {
447 assert(af == AF_INET6);
8041b5ba 448
e8a7a315 449 if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) {
3fdcecc8
LP
450 canonical = "localhost";
451 additional_from_hostname = true;
8041b5ba 452 goto found;
e8a7a315 453 }
4e8c8252
LP
454 }
455
1d050e1e 456 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
68a9c7c4
ZJS
457 for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
458 if (af != a->family)
459 continue;
8041b5ba 460
68a9c7c4
ZJS
461 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
462 goto found;
e9140aff
LP
463 }
464
97b11eed 465 addresses = mfree(addresses);
e9140aff 466
1d050e1e 467 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
68a9c7c4
ZJS
468 for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
469 if (af != a->family)
470 continue;
e9140aff 471
68a9c7c4
ZJS
472 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
473 canonical = "gateway";
474 goto found;
e9140aff 475 }
8041b5ba
LP
476 }
477
478 *errnop = ENOENT;
479 *h_errnop = HOST_NOT_FOUND;
8041b5ba
LP
480 return NSS_STATUS_NOTFOUND;
481
482found:
82e4c2d6 483 if (!canonical || additional_from_hostname) {
3fdcecc8
LP
484 hn = gethostname_malloc();
485 if (!hn) {
486 *errnop = ENOMEM;
487 *h_errnop = NO_RECOVERY;
488 return NSS_STATUS_TRYAGAIN;
489 }
490
491 if (!canonical)
492 canonical = hn;
82e4c2d6 493 else
3fdcecc8
LP
494 additional = hn;
495 }
4e8c8252 496
e8a7a315
LP
497 return fill_in_hostent(
498 canonical, additional,
499 af,
500 addresses, n_addresses,
501 local_address_ipv4,
502 host,
503 buffer, buflen,
504 errnop, h_errnop,
505 ttlp,
506 NULL);
4e8c8252 507}
6b21f0cf 508
c9fdc26e
LP
509NSS_GETHOSTBYNAME_FALLBACKS(myhostname);
510NSS_GETHOSTBYADDR_FALLBACKS(myhostname);