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 enum nss_status
_nss_mymachines_gethostbyname4_r(
68 struct gaih_addrtuple
**pat
,
69 char *buffer
, size_t buflen
,
70 int *errnop
, int *h_errnop
,
73 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
74 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
75 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
76 _cleanup_free_
int *ifindices
= NULL
;
77 _cleanup_free_
char *class = NULL
;
79 unsigned i
= 0, c
= 0;
83 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
91 r
= sd_machine_get_class(name
, &class);
94 if (!streq(class, "container")) {
99 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
100 if (n_ifindices
< 0) {
105 r
= sd_bus_open_system(&bus
);
109 r
= sd_bus_call_method(bus
,
110 "org.freedesktop.machine1",
111 "/org/freedesktop/machine1",
112 "org.freedesktop.machine1.Manager",
113 "GetMachineAddresses",
120 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
124 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
130 *h_errnop
= HOST_NOT_FOUND
;
131 return NSS_STATUS_NOTFOUND
;
135 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
138 *h_errnop
= NETDB_INTERNAL
;
139 return NSS_STATUS_TRYAGAIN
;
142 /* First, append name */
144 memcpy(r_name
, name
, l
+1);
147 /* Second, append addresses */
148 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
149 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
154 r
= sd_bus_message_read(reply
, "i", &family
);
158 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
162 r
= sd_bus_message_exit_container(reply
);
166 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
171 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
176 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
177 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
178 r_tuple
->name
= r_name
;
179 r_tuple
->family
= family
;
180 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
181 memcpy(r_tuple
->addr
, a
, sz
);
183 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
189 r
= sd_bus_message_exit_container(reply
);
196 **pat
= *r_tuple_first
;
198 *pat
= r_tuple_first
;
203 /* Explicitly reset all error variables */
205 *h_errnop
= NETDB_SUCCESS
;
208 return NSS_STATUS_SUCCESS
;
213 return NSS_STATUS_UNAVAIL
;
216 enum nss_status
_nss_mymachines_gethostbyname3_r(
219 struct hostent
*result
,
220 char *buffer
, size_t buflen
,
221 int *errnop
, int *h_errnop
,
225 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
226 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
227 _cleanup_free_
char *class = NULL
;
228 unsigned c
= 0, i
= 0;
229 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
230 size_t l
, idx
, ms
, alen
;
233 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
244 if (af
!= AF_INET
&& af
!= AF_INET6
) {
249 r
= sd_machine_get_class(name
, &class);
252 if (!streq(class, "container")) {
257 r
= sd_bus_open_system(&bus
);
261 r
= sd_bus_call_method(bus
,
262 "org.freedesktop.machine1",
263 "/org/freedesktop/machine1",
264 "org.freedesktop.machine1.Manager",
265 "GetMachineAddresses",
272 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
276 r
= count_addresses(reply
, af
, &c
);
282 *h_errnop
= HOST_NOT_FOUND
;
283 return NSS_STATUS_NOTFOUND
;
286 alen
= FAMILY_ADDRESS_SIZE(af
);
289 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
293 *h_errnop
= NETDB_INTERNAL
;
294 return NSS_STATUS_TRYAGAIN
;
297 /* First, append name */
299 memcpy(r_name
, name
, l
+1);
302 /* Second, create aliases array */
303 r_aliases
= buffer
+ idx
;
304 ((char**) r_aliases
)[0] = NULL
;
305 idx
+= sizeof(char*);
307 /* Third, append addresses */
308 r_addr
= buffer
+ idx
;
309 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
314 r
= sd_bus_message_read(reply
, "i", &family
);
318 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
322 r
= sd_bus_message_exit_container(reply
);
334 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
339 idx
+= c
* ALIGN(alen
);
341 r
= sd_bus_message_exit_container(reply
);
345 /* Third, append address pointer array */
346 r_addr_list
= buffer
+ idx
;
347 for (i
= 0; i
< c
; i
++)
348 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
350 ((char**) r_addr_list
)[i
] = NULL
;
351 idx
+= (c
+1) * sizeof(char*);
355 result
->h_name
= r_name
;
356 result
->h_aliases
= (char**) r_aliases
;
357 result
->h_addrtype
= af
;
358 result
->h_length
= alen
;
359 result
->h_addr_list
= (char**) r_addr_list
;
367 /* Explicitly reset all error variables */
369 *h_errnop
= NETDB_SUCCESS
;
372 return NSS_STATUS_SUCCESS
;
377 return NSS_STATUS_UNAVAIL
;
380 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
382 enum nss_status
_nss_mymachines_getpwnam_r(
385 char *buffer
, size_t buflen
,
388 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
389 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
390 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
391 const char *p
, *e
, *machine
;
397 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
402 p
= startswith(name
, "vu-");
410 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
413 r
= parse_uid(e
+ 1, &uid
);
417 machine
= strndupa(p
, e
- p
);
418 if (!machine_name_is_valid(machine
))
421 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
422 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
423 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
424 * running on the host. */
427 r
= sd_bus_open_system(&bus
);
431 r
= sd_bus_call_method(bus
,
432 "org.freedesktop.machine1",
433 "/org/freedesktop/machine1",
434 "org.freedesktop.machine1.Manager",
435 "MapFromMachineUser",
439 machine
, (uint32_t) uid
);
441 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
447 r
= sd_bus_message_read(reply
, "u", &mapped
);
451 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
452 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
458 return NSS_STATUS_TRYAGAIN
;
461 memcpy(buffer
, name
, l
+1);
463 pwd
->pw_name
= buffer
;
464 pwd
->pw_uid
= mapped
;
465 pwd
->pw_gid
= GID_NOBODY
;
466 pwd
->pw_gecos
= buffer
;
467 pwd
->pw_passwd
= (char*) "*"; /* locked */
468 pwd
->pw_dir
= (char*) "/";
469 pwd
->pw_shell
= (char*) "/sbin/nologin";
472 return NSS_STATUS_SUCCESS
;
476 return NSS_STATUS_NOTFOUND
;
480 return NSS_STATUS_UNAVAIL
;
483 enum nss_status
_nss_mymachines_getpwuid_r(
486 char *buffer
, size_t buflen
,
489 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
490 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
491 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
496 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
498 if (!uid_is_valid(uid
))
501 /* We consider all uids < 65536 host uids */
502 if (uid
< HOST_UID_LIMIT
)
505 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
508 r
= sd_bus_open_system(&bus
);
512 r
= sd_bus_call_method(bus
,
513 "org.freedesktop.machine1",
514 "/org/freedesktop/machine1",
515 "org.freedesktop.machine1.Manager",
522 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
528 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
535 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
537 return NSS_STATUS_TRYAGAIN
;
540 pwd
->pw_name
= buffer
;
542 pwd
->pw_gid
= GID_NOBODY
;
543 pwd
->pw_gecos
= buffer
;
544 pwd
->pw_passwd
= (char*) "*"; /* locked */
545 pwd
->pw_dir
= (char*) "/";
546 pwd
->pw_shell
= (char*) "/sbin/nologin";
549 return NSS_STATUS_SUCCESS
;
553 return NSS_STATUS_NOTFOUND
;
557 return NSS_STATUS_UNAVAIL
;
560 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
562 enum nss_status
_nss_mymachines_getgrnam_r(
565 char *buffer
, size_t buflen
,
568 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
569 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
570 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
571 const char *p
, *e
, *machine
;
577 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
582 p
= startswith(name
, "vg-");
590 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
593 r
= parse_gid(e
+ 1, &gid
);
597 machine
= strndupa(p
, e
- p
);
598 if (!machine_name_is_valid(machine
))
601 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
604 r
= sd_bus_open_system(&bus
);
608 r
= sd_bus_call_method(bus
,
609 "org.freedesktop.machine1",
610 "/org/freedesktop/machine1",
611 "org.freedesktop.machine1.Manager",
612 "MapFromMachineGroup",
616 machine
, (uint32_t) gid
);
618 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
624 r
= sd_bus_message_read(reply
, "u", &mapped
);
628 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
631 l
= sizeof(char*) + strlen(name
) + 1;
634 return NSS_STATUS_TRYAGAIN
;
637 memzero(buffer
, sizeof(char*));
638 strcpy(buffer
+ sizeof(char*), name
);
640 gr
->gr_name
= buffer
+ sizeof(char*);
642 gr
->gr_passwd
= (char*) "*"; /* locked */
643 gr
->gr_mem
= (char**) buffer
;
646 return NSS_STATUS_SUCCESS
;
650 return NSS_STATUS_NOTFOUND
;
654 return NSS_STATUS_UNAVAIL
;
657 enum nss_status
_nss_mymachines_getgrgid_r(
660 char *buffer
, size_t buflen
,
663 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
664 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
665 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
670 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
672 if (!gid_is_valid(gid
))
675 /* We consider all gids < 65536 host gids */
676 if (gid
< HOST_GID_LIMIT
)
679 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
682 r
= sd_bus_open_system(&bus
);
686 r
= sd_bus_call_method(bus
,
687 "org.freedesktop.machine1",
688 "/org/freedesktop/machine1",
689 "org.freedesktop.machine1.Manager",
696 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
702 r
= sd_bus_message_read(reply
, "sou", &machine
, NULL
, &mapped
);
709 if (buflen
< sizeof(char*) + 1) {
711 return NSS_STATUS_TRYAGAIN
;
714 memzero(buffer
, sizeof(char*));
715 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
717 return NSS_STATUS_TRYAGAIN
;
720 gr
->gr_name
= buffer
+ sizeof(char*);
722 gr
->gr_passwd
= (char*) "*"; /* locked */
723 gr
->gr_mem
= (char**) buffer
;
726 return NSS_STATUS_SUCCESS
;
730 return NSS_STATUS_NOTFOUND
;
734 return NSS_STATUS_UNAVAIL
;