1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Lennart Poettering
12 #include "alloc-util.h"
13 #include "bus-common-errors.h"
15 #include "hostname-util.h"
16 #include "in-addr-util.h"
19 #include "signal-util.h"
20 #include "string-util.h"
21 #include "user-util.h"
24 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
25 NSS_GETPW_PROTOTYPES(mymachines
);
26 NSS_GETGR_PROTOTYPES(mymachines
);
28 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
29 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
31 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
38 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
41 r
= sd_bus_message_read(m
, "i", &family
);
45 r
= sd_bus_message_skip(m
, "ay");
49 r
= sd_bus_message_exit_container(m
);
53 if (af
!= AF_UNSPEC
&& family
!= af
)
61 r
= sd_bus_message_rewind(m
, false);
69 enum nss_status
_nss_mymachines_gethostbyname4_r(
71 struct gaih_addrtuple
**pat
,
72 char *buffer
, size_t buflen
,
73 int *errnop
, int *h_errnop
,
76 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
77 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
78 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
79 _cleanup_free_
int *ifindices
= NULL
;
80 _cleanup_free_
char *class = NULL
;
82 unsigned i
= 0, c
= 0;
86 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
94 r
= sd_machine_get_class(name
, &class);
97 if (!streq(class, "container")) {
102 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
103 if (n_ifindices
< 0) {
108 r
= sd_bus_open_system(&bus
);
112 r
= sd_bus_call_method(bus
,
113 "org.freedesktop.machine1",
114 "/org/freedesktop/machine1",
115 "org.freedesktop.machine1.Manager",
116 "GetMachineAddresses",
123 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
127 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
133 *h_errnop
= HOST_NOT_FOUND
;
134 return NSS_STATUS_NOTFOUND
;
138 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
141 *h_errnop
= NETDB_INTERNAL
;
142 return NSS_STATUS_TRYAGAIN
;
145 /* First, append name */
147 memcpy(r_name
, name
, l
+1);
150 /* Second, append addresses */
151 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
152 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
157 r
= sd_bus_message_read(reply
, "i", &family
);
161 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
165 r
= sd_bus_message_exit_container(reply
);
169 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
174 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
179 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
180 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
181 r_tuple
->name
= r_name
;
182 r_tuple
->family
= family
;
183 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
184 memcpy(r_tuple
->addr
, a
, sz
);
186 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
192 r
= sd_bus_message_exit_container(reply
);
199 **pat
= *r_tuple_first
;
201 *pat
= r_tuple_first
;
206 /* Explicitly reset all error variables */
208 *h_errnop
= NETDB_SUCCESS
;
211 return NSS_STATUS_SUCCESS
;
216 return NSS_STATUS_UNAVAIL
;
219 enum nss_status
_nss_mymachines_gethostbyname3_r(
222 struct hostent
*result
,
223 char *buffer
, size_t buflen
,
224 int *errnop
, int *h_errnop
,
228 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
229 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
230 _cleanup_free_
char *class = NULL
;
231 unsigned c
= 0, i
= 0;
232 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
233 size_t l
, idx
, ms
, alen
;
236 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
247 if (af
!= AF_INET
&& af
!= AF_INET6
) {
252 r
= sd_machine_get_class(name
, &class);
255 if (!streq(class, "container")) {
260 r
= sd_bus_open_system(&bus
);
264 r
= sd_bus_call_method(bus
,
265 "org.freedesktop.machine1",
266 "/org/freedesktop/machine1",
267 "org.freedesktop.machine1.Manager",
268 "GetMachineAddresses",
275 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
279 r
= count_addresses(reply
, af
, &c
);
285 *h_errnop
= HOST_NOT_FOUND
;
286 return NSS_STATUS_NOTFOUND
;
289 alen
= FAMILY_ADDRESS_SIZE(af
);
292 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
296 *h_errnop
= NETDB_INTERNAL
;
297 return NSS_STATUS_TRYAGAIN
;
300 /* First, append name */
302 memcpy(r_name
, name
, l
+1);
305 /* Second, create aliases array */
306 r_aliases
= buffer
+ idx
;
307 ((char**) r_aliases
)[0] = NULL
;
308 idx
+= sizeof(char*);
310 /* Third, append addresses */
311 r_addr
= buffer
+ idx
;
312 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
317 r
= sd_bus_message_read(reply
, "i", &family
);
321 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
325 r
= sd_bus_message_exit_container(reply
);
337 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
342 idx
+= c
* ALIGN(alen
);
344 r
= sd_bus_message_exit_container(reply
);
348 /* Third, append address pointer array */
349 r_addr_list
= buffer
+ idx
;
350 for (i
= 0; i
< c
; i
++)
351 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
353 ((char**) r_addr_list
)[i
] = NULL
;
354 idx
+= (c
+1) * sizeof(char*);
358 result
->h_name
= r_name
;
359 result
->h_aliases
= (char**) r_aliases
;
360 result
->h_addrtype
= af
;
361 result
->h_length
= alen
;
362 result
->h_addr_list
= (char**) r_addr_list
;
370 /* Explicitly reset all error variables */
372 *h_errnop
= NETDB_SUCCESS
;
375 return NSS_STATUS_SUCCESS
;
380 return NSS_STATUS_UNAVAIL
;
383 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
385 enum nss_status
_nss_mymachines_getpwnam_r(
388 char *buffer
, size_t buflen
,
391 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
392 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
393 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
394 const char *p
, *e
, *machine
;
400 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
405 p
= startswith(name
, "vu-");
413 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
416 r
= parse_uid(e
+ 1, &uid
);
420 machine
= strndupa(p
, e
- p
);
421 if (!machine_name_is_valid(machine
))
424 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
425 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
426 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
427 * running on the host. */
430 r
= sd_bus_open_system(&bus
);
434 r
= sd_bus_call_method(bus
,
435 "org.freedesktop.machine1",
436 "/org/freedesktop/machine1",
437 "org.freedesktop.machine1.Manager",
438 "MapFromMachineUser",
442 machine
, (uint32_t) uid
);
444 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
450 r
= sd_bus_message_read(reply
, "u", &mapped
);
454 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
455 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
461 return NSS_STATUS_TRYAGAIN
;
464 memcpy(buffer
, name
, l
+1);
466 pwd
->pw_name
= buffer
;
467 pwd
->pw_uid
= mapped
;
468 pwd
->pw_gid
= GID_NOBODY
;
469 pwd
->pw_gecos
= buffer
;
470 pwd
->pw_passwd
= (char*) "*"; /* locked */
471 pwd
->pw_dir
= (char*) "/";
472 pwd
->pw_shell
= (char*) "/sbin/nologin";
475 return NSS_STATUS_SUCCESS
;
479 return NSS_STATUS_NOTFOUND
;
483 return NSS_STATUS_UNAVAIL
;
486 enum nss_status
_nss_mymachines_getpwuid_r(
489 char *buffer
, size_t buflen
,
492 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
493 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
494 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
495 const char *machine
, *object
;
499 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
501 if (!uid_is_valid(uid
))
504 /* We consider all uids < 65536 host uids */
505 if (uid
< HOST_UID_LIMIT
)
508 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
511 r
= sd_bus_open_system(&bus
);
515 r
= sd_bus_call_method(bus
,
516 "org.freedesktop.machine1",
517 "/org/freedesktop/machine1",
518 "org.freedesktop.machine1.Manager",
525 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
531 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
538 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
540 return NSS_STATUS_TRYAGAIN
;
543 pwd
->pw_name
= buffer
;
545 pwd
->pw_gid
= GID_NOBODY
;
546 pwd
->pw_gecos
= buffer
;
547 pwd
->pw_passwd
= (char*) "*"; /* locked */
548 pwd
->pw_dir
= (char*) "/";
549 pwd
->pw_shell
= (char*) "/sbin/nologin";
552 return NSS_STATUS_SUCCESS
;
556 return NSS_STATUS_NOTFOUND
;
560 return NSS_STATUS_UNAVAIL
;
563 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
565 enum nss_status
_nss_mymachines_getgrnam_r(
568 char *buffer
, size_t buflen
,
571 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
572 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
573 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
574 const char *p
, *e
, *machine
;
580 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
585 p
= startswith(name
, "vg-");
593 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
596 r
= parse_gid(e
+ 1, &gid
);
600 machine
= strndupa(p
, e
- p
);
601 if (!machine_name_is_valid(machine
))
604 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
607 r
= sd_bus_open_system(&bus
);
611 r
= sd_bus_call_method(bus
,
612 "org.freedesktop.machine1",
613 "/org/freedesktop/machine1",
614 "org.freedesktop.machine1.Manager",
615 "MapFromMachineGroup",
619 machine
, (uint32_t) gid
);
621 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
627 r
= sd_bus_message_read(reply
, "u", &mapped
);
631 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
634 l
= sizeof(char*) + strlen(name
) + 1;
637 return NSS_STATUS_TRYAGAIN
;
640 memzero(buffer
, sizeof(char*));
641 strcpy(buffer
+ sizeof(char*), name
);
643 gr
->gr_name
= buffer
+ sizeof(char*);
645 gr
->gr_passwd
= (char*) "*"; /* locked */
646 gr
->gr_mem
= (char**) buffer
;
649 return NSS_STATUS_SUCCESS
;
653 return NSS_STATUS_NOTFOUND
;
657 return NSS_STATUS_UNAVAIL
;
660 enum nss_status
_nss_mymachines_getgrgid_r(
663 char *buffer
, size_t buflen
,
666 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
667 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
668 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
669 const char *machine
, *object
;
673 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
675 if (!gid_is_valid(gid
))
678 /* We consider all gids < 65536 host gids */
679 if (gid
< HOST_GID_LIMIT
)
682 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
685 r
= sd_bus_open_system(&bus
);
689 r
= sd_bus_call_method(bus
,
690 "org.freedesktop.machine1",
691 "/org/freedesktop/machine1",
692 "org.freedesktop.machine1.Manager",
699 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
705 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
712 if (buflen
< sizeof(char*) + 1) {
714 return NSS_STATUS_TRYAGAIN
;
717 memzero(buffer
, sizeof(char*));
718 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
720 return NSS_STATUS_TRYAGAIN
;
723 gr
->gr_name
= buffer
+ sizeof(char*);
725 gr
->gr_passwd
= (char*) "*"; /* locked */
726 gr
->gr_mem
= (char**) buffer
;
729 return NSS_STATUS_SUCCESS
;
733 return NSS_STATUS_NOTFOUND
;
737 return NSS_STATUS_UNAVAIL
;