1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "bus-common-errors.h"
12 #include "errno-util.h"
13 #include "format-util.h"
14 #include "hostname-util.h"
15 #include "in-addr-util.h"
17 #include "memory-util.h"
19 #include "signal-util.h"
20 #include "string-util.h"
21 #include "user-util.h"
23 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
24 NSS_GETPW_PROTOTYPES(mymachines
);
25 NSS_GETGR_PROTOTYPES(mymachines
);
27 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
28 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
30 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
37 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
40 r
= sd_bus_message_read(m
, "i", &family
);
44 r
= sd_bus_message_skip(m
, "ay");
48 r
= sd_bus_message_exit_container(m
);
52 if (af
!= AF_UNSPEC
&& family
!= af
)
60 r
= sd_bus_message_rewind(m
, false);
68 static bool avoid_deadlock(void) {
70 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
71 * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to
72 * systemd-machined if we are required to finish before it can be started. This of course won't detect all
73 * possible dead locks of this kind, but it should work for the most obvious cases. */
75 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
78 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") &&
79 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
82 enum nss_status
_nss_mymachines_gethostbyname4_r(
84 struct gaih_addrtuple
**pat
,
85 char *buffer
, size_t buflen
,
86 int *errnop
, int *h_errnop
,
89 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
90 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
91 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
92 _cleanup_free_
int *ifindices
= NULL
;
93 _cleanup_free_
char *class = NULL
;
95 unsigned i
= 0, c
= 0;
100 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
108 r
= sd_machine_get_class(name
, &class);
111 if (!streq(class, "container")) {
116 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
117 if (n_ifindices
< 0) {
122 if (avoid_deadlock()) {
127 r
= sd_bus_open_system(&bus
);
131 r
= sd_bus_call_method(bus
,
132 "org.freedesktop.machine1",
133 "/org/freedesktop/machine1",
134 "org.freedesktop.machine1.Manager",
135 "GetMachineAddresses",
142 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
146 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
151 *h_errnop
= HOST_NOT_FOUND
;
152 return NSS_STATUS_NOTFOUND
;
156 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
160 *h_errnop
= NETDB_INTERNAL
;
161 return NSS_STATUS_TRYAGAIN
;
164 /* First, append name */
166 memcpy(r_name
, name
, l
+1);
169 /* Second, append addresses */
170 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
171 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
176 r
= sd_bus_message_read(reply
, "i", &family
);
180 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
184 r
= sd_bus_message_exit_container(reply
);
188 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
193 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
198 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
199 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
200 r_tuple
->name
= r_name
;
201 r_tuple
->family
= family
;
202 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
203 memcpy(r_tuple
->addr
, a
, sz
);
205 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
211 r
= sd_bus_message_exit_container(reply
);
218 **pat
= *r_tuple_first
;
220 *pat
= r_tuple_first
;
225 /* Explicitly reset both *h_errnop and h_errno to work around
226 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
227 *h_errnop
= NETDB_SUCCESS
;
230 return NSS_STATUS_SUCCESS
;
236 return NSS_STATUS_UNAVAIL
;
239 enum nss_status
_nss_mymachines_gethostbyname3_r(
242 struct hostent
*result
,
243 char *buffer
, size_t buflen
,
244 int *errnop
, int *h_errnop
,
248 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
249 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
250 _cleanup_free_
char *class = NULL
;
251 unsigned c
= 0, i
= 0;
252 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
253 size_t l
, idx
, ms
, alen
;
257 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
268 if (af
!= AF_INET
&& af
!= AF_INET6
) {
273 r
= sd_machine_get_class(name
, &class);
276 if (!streq(class, "container")) {
281 if (avoid_deadlock()) {
286 r
= sd_bus_open_system(&bus
);
290 r
= sd_bus_call_method(bus
,
291 "org.freedesktop.machine1",
292 "/org/freedesktop/machine1",
293 "org.freedesktop.machine1.Manager",
294 "GetMachineAddresses",
301 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
305 r
= count_addresses(reply
, af
, &c
);
310 *h_errnop
= HOST_NOT_FOUND
;
311 return NSS_STATUS_NOTFOUND
;
314 alen
= FAMILY_ADDRESS_SIZE(af
);
317 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
322 *h_errnop
= NETDB_INTERNAL
;
323 return NSS_STATUS_TRYAGAIN
;
326 /* First, append name */
328 memcpy(r_name
, name
, l
+1);
331 /* Second, create aliases array */
332 r_aliases
= buffer
+ idx
;
333 ((char**) r_aliases
)[0] = NULL
;
334 idx
+= sizeof(char*);
336 /* Third, append addresses */
337 r_addr
= buffer
+ idx
;
338 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
343 r
= sd_bus_message_read(reply
, "i", &family
);
347 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
351 r
= sd_bus_message_exit_container(reply
);
363 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
368 idx
+= c
* ALIGN(alen
);
370 r
= sd_bus_message_exit_container(reply
);
374 /* Third, append address pointer array */
375 r_addr_list
= buffer
+ idx
;
376 for (i
= 0; i
< c
; i
++)
377 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
379 ((char**) r_addr_list
)[i
] = NULL
;
380 idx
+= (c
+1) * sizeof(char*);
384 result
->h_name
= r_name
;
385 result
->h_aliases
= (char**) r_aliases
;
386 result
->h_addrtype
= af
;
387 result
->h_length
= alen
;
388 result
->h_addr_list
= (char**) r_addr_list
;
396 /* Explicitly reset both *h_errnop and h_errno to work around
397 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
398 *h_errnop
= NETDB_SUCCESS
;
401 return NSS_STATUS_SUCCESS
;
407 return NSS_STATUS_UNAVAIL
;
410 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
412 enum nss_status
_nss_mymachines_getpwnam_r(
415 char *buffer
, size_t buflen
,
418 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
419 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
420 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
421 const char *p
, *e
, *machine
;
428 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
433 p
= startswith(name
, "vu-");
435 return NSS_STATUS_NOTFOUND
;
439 return NSS_STATUS_NOTFOUND
;
441 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
442 return NSS_STATUS_NOTFOUND
;
444 r
= parse_uid(e
+ 1, &uid
);
446 return NSS_STATUS_NOTFOUND
;
448 machine
= strndupa(p
, e
- p
);
449 if (!machine_name_is_valid(machine
))
450 return NSS_STATUS_NOTFOUND
;
452 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
453 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
454 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
455 * running on the host. */
456 return NSS_STATUS_NOTFOUND
;
458 if (avoid_deadlock()) {
463 r
= sd_bus_open_system(&bus
);
467 r
= sd_bus_call_method(bus
,
468 "org.freedesktop.machine1",
469 "/org/freedesktop/machine1",
470 "org.freedesktop.machine1.Manager",
471 "MapFromMachineUser",
475 machine
, (uint32_t) uid
);
477 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
478 return NSS_STATUS_NOTFOUND
;
483 r
= sd_bus_message_read(reply
, "u", &mapped
);
487 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
488 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
489 return NSS_STATUS_NOTFOUND
;
495 return NSS_STATUS_TRYAGAIN
;
498 memcpy(buffer
, name
, l
+1);
500 pwd
->pw_name
= buffer
;
501 pwd
->pw_uid
= mapped
;
502 pwd
->pw_gid
= GID_NOBODY
;
503 pwd
->pw_gecos
= buffer
;
504 pwd
->pw_passwd
= (char*) "*"; /* locked */
505 pwd
->pw_dir
= (char*) "/";
506 pwd
->pw_shell
= (char*) "/sbin/nologin";
508 return NSS_STATUS_SUCCESS
;
513 return NSS_STATUS_UNAVAIL
;
516 enum nss_status
_nss_mymachines_getpwuid_r(
519 char *buffer
, size_t buflen
,
522 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
523 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
524 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
530 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
532 if (!uid_is_valid(uid
))
533 return NSS_STATUS_NOTFOUND
;
535 /* We consider all uids < 65536 host uids */
536 if (uid
< HOST_UID_LIMIT
)
537 return NSS_STATUS_NOTFOUND
;
539 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
540 return NSS_STATUS_NOTFOUND
;
542 if (avoid_deadlock()) {
547 r
= sd_bus_open_system(&bus
);
551 r
= sd_bus_call_method(bus
,
552 "org.freedesktop.machine1",
553 "/org/freedesktop/machine1",
554 "org.freedesktop.machine1.Manager",
561 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
562 return NSS_STATUS_NOTFOUND
;
567 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
572 return NSS_STATUS_NOTFOUND
;
574 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
577 return NSS_STATUS_TRYAGAIN
;
580 pwd
->pw_name
= buffer
;
582 pwd
->pw_gid
= GID_NOBODY
;
583 pwd
->pw_gecos
= buffer
;
584 pwd
->pw_passwd
= (char*) "*"; /* locked */
585 pwd
->pw_dir
= (char*) "/";
586 pwd
->pw_shell
= (char*) "/sbin/nologin";
588 return NSS_STATUS_SUCCESS
;
593 return NSS_STATUS_UNAVAIL
;
596 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
598 enum nss_status
_nss_mymachines_getgrnam_r(
601 char *buffer
, size_t buflen
,
604 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
605 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
606 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
607 const char *p
, *e
, *machine
;
614 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
619 p
= startswith(name
, "vg-");
621 return NSS_STATUS_NOTFOUND
;
625 return NSS_STATUS_NOTFOUND
;
627 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
628 return NSS_STATUS_NOTFOUND
;
630 r
= parse_gid(e
+ 1, &gid
);
632 return NSS_STATUS_NOTFOUND
;
634 machine
= strndupa(p
, e
- p
);
635 if (!machine_name_is_valid(machine
))
636 return NSS_STATUS_NOTFOUND
;
638 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
639 return NSS_STATUS_NOTFOUND
;
641 if (avoid_deadlock()) {
646 r
= sd_bus_open_system(&bus
);
650 r
= sd_bus_call_method(bus
,
651 "org.freedesktop.machine1",
652 "/org/freedesktop/machine1",
653 "org.freedesktop.machine1.Manager",
654 "MapFromMachineGroup",
658 machine
, (uint32_t) gid
);
660 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
661 return NSS_STATUS_NOTFOUND
;
666 r
= sd_bus_message_read(reply
, "u", &mapped
);
670 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
671 return NSS_STATUS_NOTFOUND
;
673 l
= sizeof(char*) + strlen(name
) + 1;
677 return NSS_STATUS_TRYAGAIN
;
680 memzero(buffer
, sizeof(char*));
681 strcpy(buffer
+ sizeof(char*), name
);
683 gr
->gr_name
= buffer
+ sizeof(char*);
685 gr
->gr_passwd
= (char*) "*"; /* locked */
686 gr
->gr_mem
= (char**) buffer
;
688 return NSS_STATUS_SUCCESS
;
693 return NSS_STATUS_UNAVAIL
;
696 enum nss_status
_nss_mymachines_getgrgid_r(
699 char *buffer
, size_t buflen
,
702 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
703 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
704 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
710 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
712 if (!gid_is_valid(gid
))
713 return NSS_STATUS_NOTFOUND
;
715 /* We consider all gids < 65536 host gids */
716 if (gid
< HOST_GID_LIMIT
)
717 return NSS_STATUS_NOTFOUND
;
719 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
720 return NSS_STATUS_NOTFOUND
;
722 if (avoid_deadlock()) {
727 r
= sd_bus_open_system(&bus
);
731 r
= sd_bus_call_method(bus
,
732 "org.freedesktop.machine1",
733 "/org/freedesktop/machine1",
734 "org.freedesktop.machine1.Manager",
741 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
742 return NSS_STATUS_NOTFOUND
;
747 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
752 return NSS_STATUS_NOTFOUND
;
754 if (buflen
< sizeof(char*) + 1) {
757 return NSS_STATUS_TRYAGAIN
;
760 memzero(buffer
, sizeof(char*));
761 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
764 return NSS_STATUS_TRYAGAIN
;
767 gr
->gr_name
= buffer
+ sizeof(char*);
769 gr
->gr_passwd
= (char*) "*"; /* locked */
770 gr
->gr_mem
= (char**) buffer
;
772 return NSS_STATUS_SUCCESS
;
777 return NSS_STATUS_UNAVAIL
;