1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "bus-common-errors.h"
12 #include "hostname-util.h"
13 #include "in-addr-util.h"
16 #include "signal-util.h"
17 #include "string-util.h"
18 #include "user-util.h"
21 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
22 NSS_GETPW_PROTOTYPES(mymachines
);
23 NSS_GETGR_PROTOTYPES(mymachines
);
25 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
26 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
28 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
35 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
38 r
= sd_bus_message_read(m
, "i", &family
);
42 r
= sd_bus_message_skip(m
, "ay");
46 r
= sd_bus_message_exit_container(m
);
50 if (af
!= AF_UNSPEC
&& family
!= af
)
58 r
= sd_bus_message_rewind(m
, false);
66 static bool avoid_deadlock(void) {
68 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
69 * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to
70 * systemd-machined if we are required to finish before it can be started. This of course won't detect all
71 * possible dead locks of this kind, but it should work for the most obvious cases. */
73 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
76 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") &&
77 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
80 enum nss_status
_nss_mymachines_gethostbyname4_r(
82 struct gaih_addrtuple
**pat
,
83 char *buffer
, size_t buflen
,
84 int *errnop
, int *h_errnop
,
87 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
88 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
89 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
90 _cleanup_free_
int *ifindices
= NULL
;
91 _cleanup_free_
char *class = NULL
;
93 unsigned i
= 0, c
= 0;
98 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
106 r
= sd_machine_get_class(name
, &class);
109 if (!streq(class, "container")) {
114 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
115 if (n_ifindices
< 0) {
120 if (avoid_deadlock()) {
125 r
= sd_bus_open_system(&bus
);
129 r
= sd_bus_call_method(bus
,
130 "org.freedesktop.machine1",
131 "/org/freedesktop/machine1",
132 "org.freedesktop.machine1.Manager",
133 "GetMachineAddresses",
140 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
144 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
149 *h_errnop
= HOST_NOT_FOUND
;
150 return NSS_STATUS_NOTFOUND
;
154 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
157 *h_errnop
= NETDB_INTERNAL
;
158 return NSS_STATUS_TRYAGAIN
;
161 /* First, append name */
163 memcpy(r_name
, name
, l
+1);
166 /* Second, append addresses */
167 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
168 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
173 r
= sd_bus_message_read(reply
, "i", &family
);
177 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
181 r
= sd_bus_message_exit_container(reply
);
185 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
190 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
195 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
196 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
197 r_tuple
->name
= r_name
;
198 r_tuple
->family
= family
;
199 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
200 memcpy(r_tuple
->addr
, a
, sz
);
202 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
208 r
= sd_bus_message_exit_container(reply
);
215 **pat
= *r_tuple_first
;
217 *pat
= r_tuple_first
;
222 /* Explicitly reset both *h_errnop and h_errno to work around
223 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
224 *h_errnop
= NETDB_SUCCESS
;
227 return NSS_STATUS_SUCCESS
;
232 return NSS_STATUS_UNAVAIL
;
235 enum nss_status
_nss_mymachines_gethostbyname3_r(
238 struct hostent
*result
,
239 char *buffer
, size_t buflen
,
240 int *errnop
, int *h_errnop
,
244 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
245 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
246 _cleanup_free_
char *class = NULL
;
247 unsigned c
= 0, i
= 0;
248 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
249 size_t l
, idx
, ms
, alen
;
253 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
264 if (af
!= AF_INET
&& af
!= AF_INET6
) {
269 r
= sd_machine_get_class(name
, &class);
272 if (!streq(class, "container")) {
277 if (avoid_deadlock()) {
282 r
= sd_bus_open_system(&bus
);
286 r
= sd_bus_call_method(bus
,
287 "org.freedesktop.machine1",
288 "/org/freedesktop/machine1",
289 "org.freedesktop.machine1.Manager",
290 "GetMachineAddresses",
297 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
301 r
= count_addresses(reply
, af
, &c
);
306 *h_errnop
= HOST_NOT_FOUND
;
307 return NSS_STATUS_NOTFOUND
;
310 alen
= FAMILY_ADDRESS_SIZE(af
);
313 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
317 *h_errnop
= NETDB_INTERNAL
;
318 return NSS_STATUS_TRYAGAIN
;
321 /* First, append name */
323 memcpy(r_name
, name
, l
+1);
326 /* Second, create aliases array */
327 r_aliases
= buffer
+ idx
;
328 ((char**) r_aliases
)[0] = NULL
;
329 idx
+= sizeof(char*);
331 /* Third, append addresses */
332 r_addr
= buffer
+ idx
;
333 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
338 r
= sd_bus_message_read(reply
, "i", &family
);
342 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
346 r
= sd_bus_message_exit_container(reply
);
358 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
363 idx
+= c
* ALIGN(alen
);
365 r
= sd_bus_message_exit_container(reply
);
369 /* Third, append address pointer array */
370 r_addr_list
= buffer
+ idx
;
371 for (i
= 0; i
< c
; i
++)
372 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
374 ((char**) r_addr_list
)[i
] = NULL
;
375 idx
+= (c
+1) * sizeof(char*);
379 result
->h_name
= r_name
;
380 result
->h_aliases
= (char**) r_aliases
;
381 result
->h_addrtype
= af
;
382 result
->h_length
= alen
;
383 result
->h_addr_list
= (char**) r_addr_list
;
391 /* Explicitly reset both *h_errnop and h_errno to work around
392 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
393 *h_errnop
= NETDB_SUCCESS
;
396 return NSS_STATUS_SUCCESS
;
401 return NSS_STATUS_UNAVAIL
;
404 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
406 enum nss_status
_nss_mymachines_getpwnam_r(
409 char *buffer
, size_t buflen
,
412 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
413 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
414 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
415 const char *p
, *e
, *machine
;
422 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
427 p
= startswith(name
, "vu-");
429 return NSS_STATUS_NOTFOUND
;
433 return NSS_STATUS_NOTFOUND
;
435 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
436 return NSS_STATUS_NOTFOUND
;
438 r
= parse_uid(e
+ 1, &uid
);
440 return NSS_STATUS_NOTFOUND
;
442 machine
= strndupa(p
, e
- p
);
443 if (!machine_name_is_valid(machine
))
444 return NSS_STATUS_NOTFOUND
;
446 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
447 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
448 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
449 * running on the host. */
450 return NSS_STATUS_NOTFOUND
;
452 if (avoid_deadlock()) {
457 r
= sd_bus_open_system(&bus
);
461 r
= sd_bus_call_method(bus
,
462 "org.freedesktop.machine1",
463 "/org/freedesktop/machine1",
464 "org.freedesktop.machine1.Manager",
465 "MapFromMachineUser",
469 machine
, (uint32_t) uid
);
471 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
472 return NSS_STATUS_NOTFOUND
;
477 r
= sd_bus_message_read(reply
, "u", &mapped
);
481 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
482 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
483 return NSS_STATUS_NOTFOUND
;
488 return NSS_STATUS_TRYAGAIN
;
491 memcpy(buffer
, name
, l
+1);
493 pwd
->pw_name
= buffer
;
494 pwd
->pw_uid
= mapped
;
495 pwd
->pw_gid
= GID_NOBODY
;
496 pwd
->pw_gecos
= buffer
;
497 pwd
->pw_passwd
= (char*) "*"; /* locked */
498 pwd
->pw_dir
= (char*) "/";
499 pwd
->pw_shell
= (char*) "/sbin/nologin";
501 return NSS_STATUS_SUCCESS
;
505 return NSS_STATUS_UNAVAIL
;
508 enum nss_status
_nss_mymachines_getpwuid_r(
511 char *buffer
, size_t buflen
,
514 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
515 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
516 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
522 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
524 if (!uid_is_valid(uid
))
525 return NSS_STATUS_NOTFOUND
;
527 /* We consider all uids < 65536 host uids */
528 if (uid
< HOST_UID_LIMIT
)
529 return NSS_STATUS_NOTFOUND
;
531 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
532 return NSS_STATUS_NOTFOUND
;
534 if (avoid_deadlock()) {
539 r
= sd_bus_open_system(&bus
);
543 r
= sd_bus_call_method(bus
,
544 "org.freedesktop.machine1",
545 "/org/freedesktop/machine1",
546 "org.freedesktop.machine1.Manager",
553 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
554 return NSS_STATUS_NOTFOUND
;
559 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
564 return NSS_STATUS_NOTFOUND
;
566 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
568 return NSS_STATUS_TRYAGAIN
;
571 pwd
->pw_name
= buffer
;
573 pwd
->pw_gid
= GID_NOBODY
;
574 pwd
->pw_gecos
= buffer
;
575 pwd
->pw_passwd
= (char*) "*"; /* locked */
576 pwd
->pw_dir
= (char*) "/";
577 pwd
->pw_shell
= (char*) "/sbin/nologin";
579 return NSS_STATUS_SUCCESS
;
583 return NSS_STATUS_UNAVAIL
;
586 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
588 enum nss_status
_nss_mymachines_getgrnam_r(
591 char *buffer
, size_t buflen
,
594 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
595 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
596 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
597 const char *p
, *e
, *machine
;
604 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
609 p
= startswith(name
, "vg-");
611 return NSS_STATUS_NOTFOUND
;
615 return NSS_STATUS_NOTFOUND
;
617 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
618 return NSS_STATUS_NOTFOUND
;
620 r
= parse_gid(e
+ 1, &gid
);
622 return NSS_STATUS_NOTFOUND
;
624 machine
= strndupa(p
, e
- p
);
625 if (!machine_name_is_valid(machine
))
626 return NSS_STATUS_NOTFOUND
;
628 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
629 return NSS_STATUS_NOTFOUND
;
631 if (avoid_deadlock()) {
636 r
= sd_bus_open_system(&bus
);
640 r
= sd_bus_call_method(bus
,
641 "org.freedesktop.machine1",
642 "/org/freedesktop/machine1",
643 "org.freedesktop.machine1.Manager",
644 "MapFromMachineGroup",
648 machine
, (uint32_t) gid
);
650 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
651 return NSS_STATUS_NOTFOUND
;
656 r
= sd_bus_message_read(reply
, "u", &mapped
);
660 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
661 return NSS_STATUS_NOTFOUND
;
663 l
= sizeof(char*) + strlen(name
) + 1;
666 return NSS_STATUS_TRYAGAIN
;
669 memzero(buffer
, sizeof(char*));
670 strcpy(buffer
+ sizeof(char*), name
);
672 gr
->gr_name
= buffer
+ sizeof(char*);
674 gr
->gr_passwd
= (char*) "*"; /* locked */
675 gr
->gr_mem
= (char**) buffer
;
677 return NSS_STATUS_SUCCESS
;
681 return NSS_STATUS_UNAVAIL
;
684 enum nss_status
_nss_mymachines_getgrgid_r(
687 char *buffer
, size_t buflen
,
690 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
691 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
692 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
698 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
700 if (!gid_is_valid(gid
))
701 return NSS_STATUS_NOTFOUND
;
703 /* We consider all gids < 65536 host gids */
704 if (gid
< HOST_GID_LIMIT
)
705 return NSS_STATUS_NOTFOUND
;
707 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
708 return NSS_STATUS_NOTFOUND
;
710 if (avoid_deadlock()) {
715 r
= sd_bus_open_system(&bus
);
719 r
= sd_bus_call_method(bus
,
720 "org.freedesktop.machine1",
721 "/org/freedesktop/machine1",
722 "org.freedesktop.machine1.Manager",
729 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
730 return NSS_STATUS_NOTFOUND
;
735 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
740 return NSS_STATUS_NOTFOUND
;
742 if (buflen
< sizeof(char*) + 1) {
744 return NSS_STATUS_TRYAGAIN
;
747 memzero(buffer
, sizeof(char*));
748 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
750 return NSS_STATUS_TRYAGAIN
;
753 gr
->gr_name
= buffer
+ sizeof(char*);
755 gr
->gr_passwd
= (char*) "*"; /* locked */
756 gr
->gr_mem
= (char**) buffer
;
758 return NSS_STATUS_SUCCESS
;
762 return NSS_STATUS_UNAVAIL
;