1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "bus-common-errors.h"
13 #include "errno-util.h"
14 #include "format-util.h"
15 #include "hostname-util.h"
16 #include "in-addr-util.h"
18 #include "memory-util.h"
20 #include "signal-util.h"
21 #include "string-util.h"
22 #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 static bool avoid_deadlock(void) {
71 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
72 * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to
73 * systemd-machined if we are required to finish before it can be started. This of course won't detect all
74 * possible dead locks of this kind, but it should work for the most obvious cases. */
76 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
79 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") &&
80 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
83 enum nss_status
_nss_mymachines_gethostbyname4_r(
85 struct gaih_addrtuple
**pat
,
86 char *buffer
, size_t buflen
,
87 int *errnop
, int *h_errnop
,
90 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
91 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
92 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
93 _cleanup_free_
int *ifindices
= NULL
;
94 _cleanup_free_
char *class = NULL
;
96 unsigned i
= 0, c
= 0;
101 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
109 r
= sd_machine_get_class(name
, &class);
112 if (!streq(class, "container")) {
117 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
118 if (n_ifindices
< 0) {
123 if (avoid_deadlock()) {
128 r
= sd_bus_open_system(&bus
);
132 r
= bus_call_method(bus
, bus_machine_mgr
, "GetMachineAddresses", NULL
, &reply
, "s", name
);
136 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
140 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
145 *h_errnop
= HOST_NOT_FOUND
;
146 return NSS_STATUS_NOTFOUND
;
150 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
154 *h_errnop
= NETDB_INTERNAL
;
155 return NSS_STATUS_TRYAGAIN
;
158 /* First, append name */
160 memcpy(r_name
, name
, l
+1);
163 /* Second, append addresses */
164 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
165 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
170 r
= sd_bus_message_read(reply
, "i", &family
);
174 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
178 r
= sd_bus_message_exit_container(reply
);
182 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
187 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
192 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
193 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
194 r_tuple
->name
= r_name
;
195 r_tuple
->family
= family
;
196 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
197 memcpy(r_tuple
->addr
, a
, sz
);
199 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
205 r
= sd_bus_message_exit_container(reply
);
212 **pat
= *r_tuple_first
;
214 *pat
= r_tuple_first
;
219 /* Explicitly reset both *h_errnop and h_errno to work around
220 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
221 *h_errnop
= NETDB_SUCCESS
;
224 return NSS_STATUS_SUCCESS
;
229 *h_errnop
= NO_RECOVERY
;
230 return NSS_STATUS_UNAVAIL
;
233 enum nss_status
_nss_mymachines_gethostbyname3_r(
236 struct hostent
*result
,
237 char *buffer
, size_t buflen
,
238 int *errnop
, int *h_errnop
,
242 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
243 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
244 _cleanup_free_
char *class = NULL
;
245 unsigned c
= 0, i
= 0;
246 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
247 size_t l
, idx
, ms
, alen
;
251 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
262 if (af
!= AF_INET
&& af
!= AF_INET6
) {
267 r
= sd_machine_get_class(name
, &class);
270 if (!streq(class, "container")) {
275 if (avoid_deadlock()) {
280 r
= sd_bus_open_system(&bus
);
284 r
= bus_call_method(bus
, bus_machine_mgr
, "GetMachineAddresses", NULL
, &reply
, "s", name
);
288 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
292 r
= count_addresses(reply
, af
, &c
);
297 *h_errnop
= HOST_NOT_FOUND
;
298 return NSS_STATUS_NOTFOUND
;
301 alen
= FAMILY_ADDRESS_SIZE(af
);
304 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
309 *h_errnop
= NETDB_INTERNAL
;
310 return NSS_STATUS_TRYAGAIN
;
313 /* First, append name */
315 memcpy(r_name
, name
, l
+1);
318 /* Second, create aliases array */
319 r_aliases
= buffer
+ idx
;
320 ((char**) r_aliases
)[0] = NULL
;
321 idx
+= sizeof(char*);
323 /* Third, append addresses */
324 r_addr
= buffer
+ idx
;
325 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
330 r
= sd_bus_message_read(reply
, "i", &family
);
334 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
338 r
= sd_bus_message_exit_container(reply
);
350 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
355 idx
+= c
* ALIGN(alen
);
357 r
= sd_bus_message_exit_container(reply
);
361 /* Third, append address pointer array */
362 r_addr_list
= buffer
+ idx
;
363 for (i
= 0; i
< c
; i
++)
364 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
366 ((char**) r_addr_list
)[i
] = NULL
;
367 idx
+= (c
+1) * sizeof(char*);
371 result
->h_name
= r_name
;
372 result
->h_aliases
= (char**) r_aliases
;
373 result
->h_addrtype
= af
;
374 result
->h_length
= alen
;
375 result
->h_addr_list
= (char**) r_addr_list
;
383 /* Explicitly reset both *h_errnop and h_errno to work around
384 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
385 *h_errnop
= NETDB_SUCCESS
;
388 return NSS_STATUS_SUCCESS
;
393 *h_errnop
= NO_RECOVERY
;
394 return NSS_STATUS_UNAVAIL
;
397 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
399 enum nss_status
_nss_mymachines_getpwnam_r(
402 char *buffer
, size_t buflen
,
405 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
406 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
407 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
408 const char *p
, *e
, *machine
;
415 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
420 p
= startswith(name
, "vu-");
422 return NSS_STATUS_NOTFOUND
;
426 return NSS_STATUS_NOTFOUND
;
428 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
429 return NSS_STATUS_NOTFOUND
;
431 r
= parse_uid(e
+ 1, &uid
);
433 return NSS_STATUS_NOTFOUND
;
435 machine
= strndupa(p
, e
- p
);
436 if (!machine_name_is_valid(machine
))
437 return NSS_STATUS_NOTFOUND
;
439 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
440 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
441 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
442 * running on the host. */
443 return NSS_STATUS_NOTFOUND
;
445 if (avoid_deadlock()) {
450 r
= sd_bus_open_system(&bus
);
454 r
= bus_call_method(bus
, bus_machine_mgr
, "MapFromMachineUser", &error
, &reply
, "su", machine
, (uint32_t) uid
);
456 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
457 return NSS_STATUS_NOTFOUND
;
462 r
= sd_bus_message_read(reply
, "u", &mapped
);
466 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
467 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
468 return NSS_STATUS_NOTFOUND
;
474 return NSS_STATUS_TRYAGAIN
;
477 memcpy(buffer
, name
, l
+1);
479 pwd
->pw_name
= buffer
;
480 pwd
->pw_uid
= mapped
;
481 pwd
->pw_gid
= GID_NOBODY
;
482 pwd
->pw_gecos
= buffer
;
483 pwd
->pw_passwd
= (char*) "*"; /* locked */
484 pwd
->pw_dir
= (char*) "/";
485 pwd
->pw_shell
= (char*) NOLOGIN
;
487 return NSS_STATUS_SUCCESS
;
492 return NSS_STATUS_UNAVAIL
;
495 enum nss_status
_nss_mymachines_getpwuid_r(
498 char *buffer
, size_t buflen
,
501 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
502 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
503 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
509 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
511 if (!uid_is_valid(uid
))
512 return NSS_STATUS_NOTFOUND
;
514 /* We consider all uids < 65536 host uids */
515 if (uid
< HOST_UID_LIMIT
)
516 return NSS_STATUS_NOTFOUND
;
518 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
519 return NSS_STATUS_NOTFOUND
;
521 if (avoid_deadlock()) {
526 r
= sd_bus_open_system(&bus
);
530 r
= bus_call_method(bus
, bus_machine_mgr
, "MapToMachineUser", &error
, &reply
, "u", (uint32_t) uid
);
532 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
533 return NSS_STATUS_NOTFOUND
;
538 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
543 return NSS_STATUS_NOTFOUND
;
545 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
548 return NSS_STATUS_TRYAGAIN
;
551 pwd
->pw_name
= buffer
;
553 pwd
->pw_gid
= GID_NOBODY
;
554 pwd
->pw_gecos
= buffer
;
555 pwd
->pw_passwd
= (char*) "*"; /* locked */
556 pwd
->pw_dir
= (char*) "/";
557 pwd
->pw_shell
= (char*) NOLOGIN
;
559 return NSS_STATUS_SUCCESS
;
564 return NSS_STATUS_UNAVAIL
;
567 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
569 enum nss_status
_nss_mymachines_getgrnam_r(
572 char *buffer
, size_t buflen
,
575 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
576 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
577 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
578 const char *p
, *e
, *machine
;
585 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
590 p
= startswith(name
, "vg-");
592 return NSS_STATUS_NOTFOUND
;
596 return NSS_STATUS_NOTFOUND
;
598 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
599 return NSS_STATUS_NOTFOUND
;
601 r
= parse_gid(e
+ 1, &gid
);
603 return NSS_STATUS_NOTFOUND
;
605 machine
= strndupa(p
, e
- p
);
606 if (!machine_name_is_valid(machine
))
607 return NSS_STATUS_NOTFOUND
;
609 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
610 return NSS_STATUS_NOTFOUND
;
612 if (avoid_deadlock()) {
617 r
= sd_bus_open_system(&bus
);
621 r
= bus_call_method(bus
, bus_machine_mgr
, "MapFromMachineGroup", &error
, &reply
, "su", machine
, (uint32_t) gid
);
623 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
624 return NSS_STATUS_NOTFOUND
;
629 r
= sd_bus_message_read(reply
, "u", &mapped
);
633 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
634 return NSS_STATUS_NOTFOUND
;
636 l
= sizeof(char*) + strlen(name
) + 1;
640 return NSS_STATUS_TRYAGAIN
;
643 memzero(buffer
, sizeof(char*));
644 strcpy(buffer
+ sizeof(char*), name
);
646 gr
->gr_name
= buffer
+ sizeof(char*);
648 gr
->gr_passwd
= (char*) "*"; /* locked */
649 gr
->gr_mem
= (char**) buffer
;
651 return NSS_STATUS_SUCCESS
;
656 return NSS_STATUS_UNAVAIL
;
659 enum nss_status
_nss_mymachines_getgrgid_r(
662 char *buffer
, size_t buflen
,
665 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
666 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
667 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
673 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
675 if (!gid_is_valid(gid
))
676 return NSS_STATUS_NOTFOUND
;
678 /* We consider all gids < 65536 host gids */
679 if (gid
< HOST_GID_LIMIT
)
680 return NSS_STATUS_NOTFOUND
;
682 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
683 return NSS_STATUS_NOTFOUND
;
685 if (avoid_deadlock()) {
690 r
= sd_bus_open_system(&bus
);
694 r
= bus_call_method(bus
, bus_machine_mgr
, "MapToMachineGroup", &error
, &reply
, "u", (uint32_t) gid
);
696 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
697 return NSS_STATUS_NOTFOUND
;
702 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
707 return NSS_STATUS_NOTFOUND
;
709 if (buflen
< sizeof(char*) + 1) {
712 return NSS_STATUS_TRYAGAIN
;
715 memzero(buffer
, sizeof(char*));
716 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
719 return NSS_STATUS_TRYAGAIN
;
722 gr
->gr_name
= buffer
+ sizeof(char*);
724 gr
->gr_passwd
= (char*) "*"; /* locked */
725 gr
->gr_mem
= (char**) buffer
;
727 return NSS_STATUS_SUCCESS
;
732 return NSS_STATUS_UNAVAIL
;