1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
28 #include "bus-common-errors.h"
30 #include "hostname-util.h"
31 #include "in-addr-util.h"
34 #include "signal-util.h"
35 #include "string-util.h"
36 #include "user-util.h"
39 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
40 NSS_GETPW_PROTOTYPES(mymachines
);
41 NSS_GETGR_PROTOTYPES(mymachines
);
43 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
44 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
46 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
53 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
56 r
= sd_bus_message_read(m
, "i", &family
);
60 r
= sd_bus_message_skip(m
, "ay");
64 r
= sd_bus_message_exit_container(m
);
68 if (af
!= AF_UNSPEC
&& family
!= af
)
76 r
= sd_bus_message_rewind(m
, false);
84 enum nss_status
_nss_mymachines_gethostbyname4_r(
86 struct gaih_addrtuple
**pat
,
87 char *buffer
, size_t buflen
,
88 int *errnop
, int *h_errnop
,
91 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
92 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
93 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
94 _cleanup_free_
int *ifindices
= NULL
;
95 _cleanup_free_
char *class = NULL
;
97 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 r
= sd_bus_open_system(&bus
);
127 r
= sd_bus_call_method(bus
,
128 "org.freedesktop.machine1",
129 "/org/freedesktop/machine1",
130 "org.freedesktop.machine1.Manager",
131 "GetMachineAddresses",
138 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
142 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
148 *h_errnop
= HOST_NOT_FOUND
;
149 return NSS_STATUS_NOTFOUND
;
153 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
156 *h_errnop
= NETDB_INTERNAL
;
157 return NSS_STATUS_TRYAGAIN
;
160 /* First, append name */
162 memcpy(r_name
, name
, l
+1);
165 /* Second, append addresses */
166 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
167 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
172 r
= sd_bus_message_read(reply
, "i", &family
);
176 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
180 r
= sd_bus_message_exit_container(reply
);
184 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
189 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
194 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
195 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
196 r_tuple
->name
= r_name
;
197 r_tuple
->family
= family
;
198 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
199 memcpy(r_tuple
->addr
, a
, sz
);
201 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
207 r
= sd_bus_message_exit_container(reply
);
214 **pat
= *r_tuple_first
;
216 *pat
= r_tuple_first
;
221 /* Explicitly reset all error variables */
223 *h_errnop
= NETDB_SUCCESS
;
226 return NSS_STATUS_SUCCESS
;
231 return NSS_STATUS_UNAVAIL
;
234 enum nss_status
_nss_mymachines_gethostbyname3_r(
237 struct hostent
*result
,
238 char *buffer
, size_t buflen
,
239 int *errnop
, int *h_errnop
,
243 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
244 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
245 _cleanup_free_
char *class = NULL
;
246 unsigned c
= 0, i
= 0;
247 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
248 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 r
= sd_bus_open_system(&bus
);
279 r
= sd_bus_call_method(bus
,
280 "org.freedesktop.machine1",
281 "/org/freedesktop/machine1",
282 "org.freedesktop.machine1.Manager",
283 "GetMachineAddresses",
290 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
294 r
= count_addresses(reply
, af
, &c
);
300 *h_errnop
= HOST_NOT_FOUND
;
301 return NSS_STATUS_NOTFOUND
;
304 alen
= FAMILY_ADDRESS_SIZE(af
);
307 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
311 *h_errnop
= NETDB_INTERNAL
;
312 return NSS_STATUS_TRYAGAIN
;
315 /* First, append name */
317 memcpy(r_name
, name
, l
+1);
320 /* Second, create aliases array */
321 r_aliases
= buffer
+ idx
;
322 ((char**) r_aliases
)[0] = NULL
;
323 idx
+= sizeof(char*);
325 /* Third, append addresses */
326 r_addr
= buffer
+ idx
;
327 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
332 r
= sd_bus_message_read(reply
, "i", &family
);
336 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
340 r
= sd_bus_message_exit_container(reply
);
352 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
357 idx
+= c
* ALIGN(alen
);
359 r
= sd_bus_message_exit_container(reply
);
363 /* Third, append address pointer array */
364 r_addr_list
= buffer
+ idx
;
365 for (i
= 0; i
< c
; i
++)
366 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
368 ((char**) r_addr_list
)[i
] = NULL
;
369 idx
+= (c
+1) * sizeof(char*);
373 result
->h_name
= r_name
;
374 result
->h_aliases
= (char**) r_aliases
;
375 result
->h_addrtype
= af
;
376 result
->h_length
= alen
;
377 result
->h_addr_list
= (char**) r_addr_list
;
385 /* Explicitly reset all error variables */
387 *h_errnop
= NETDB_SUCCESS
;
390 return NSS_STATUS_SUCCESS
;
395 return NSS_STATUS_UNAVAIL
;
398 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
400 enum nss_status
_nss_mymachines_getpwnam_r(
403 char *buffer
, size_t buflen
,
406 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
407 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
408 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
409 const char *p
, *e
, *machine
;
415 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
420 p
= startswith(name
, "vu-");
428 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
431 r
= parse_uid(e
+ 1, &uid
);
435 machine
= strndupa(p
, e
- p
);
436 if (!machine_name_is_valid(machine
))
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. */
445 r
= sd_bus_open_system(&bus
);
449 r
= sd_bus_call_method(bus
,
450 "org.freedesktop.machine1",
451 "/org/freedesktop/machine1",
452 "org.freedesktop.machine1.Manager",
453 "MapFromMachineUser",
457 machine
, (uint32_t) uid
);
459 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
465 r
= sd_bus_message_read(reply
, "u", &mapped
);
469 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
470 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
476 return NSS_STATUS_TRYAGAIN
;
479 memcpy(buffer
, name
, l
+1);
481 pwd
->pw_name
= buffer
;
482 pwd
->pw_uid
= mapped
;
483 pwd
->pw_gid
= GID_NOBODY
;
484 pwd
->pw_gecos
= buffer
;
485 pwd
->pw_passwd
= (char*) "*"; /* locked */
486 pwd
->pw_dir
= (char*) "/";
487 pwd
->pw_shell
= (char*) "/sbin/nologin";
490 return NSS_STATUS_SUCCESS
;
494 return NSS_STATUS_NOTFOUND
;
498 return NSS_STATUS_UNAVAIL
;
501 enum nss_status
_nss_mymachines_getpwuid_r(
504 char *buffer
, size_t buflen
,
507 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
508 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
509 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
510 const char *machine
, *object
;
514 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
516 if (!uid_is_valid(uid
))
519 /* We consider all uids < 65536 host uids */
520 if (uid
< HOST_UID_LIMIT
)
523 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
526 r
= sd_bus_open_system(&bus
);
530 r
= sd_bus_call_method(bus
,
531 "org.freedesktop.machine1",
532 "/org/freedesktop/machine1",
533 "org.freedesktop.machine1.Manager",
540 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
546 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
553 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
555 return NSS_STATUS_TRYAGAIN
;
558 pwd
->pw_name
= buffer
;
560 pwd
->pw_gid
= GID_NOBODY
;
561 pwd
->pw_gecos
= buffer
;
562 pwd
->pw_passwd
= (char*) "*"; /* locked */
563 pwd
->pw_dir
= (char*) "/";
564 pwd
->pw_shell
= (char*) "/sbin/nologin";
567 return NSS_STATUS_SUCCESS
;
571 return NSS_STATUS_NOTFOUND
;
575 return NSS_STATUS_UNAVAIL
;
578 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
580 enum nss_status
_nss_mymachines_getgrnam_r(
583 char *buffer
, size_t buflen
,
586 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
587 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
588 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
589 const char *p
, *e
, *machine
;
595 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
600 p
= startswith(name
, "vg-");
608 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
611 r
= parse_gid(e
+ 1, &gid
);
615 machine
= strndupa(p
, e
- p
);
616 if (!machine_name_is_valid(machine
))
619 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
622 r
= sd_bus_open_system(&bus
);
626 r
= sd_bus_call_method(bus
,
627 "org.freedesktop.machine1",
628 "/org/freedesktop/machine1",
629 "org.freedesktop.machine1.Manager",
630 "MapFromMachineGroup",
634 machine
, (uint32_t) gid
);
636 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
642 r
= sd_bus_message_read(reply
, "u", &mapped
);
646 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
649 l
= sizeof(char*) + strlen(name
) + 1;
652 return NSS_STATUS_TRYAGAIN
;
655 memzero(buffer
, sizeof(char*));
656 strcpy(buffer
+ sizeof(char*), name
);
658 gr
->gr_name
= buffer
+ sizeof(char*);
660 gr
->gr_passwd
= (char*) "*"; /* locked */
661 gr
->gr_mem
= (char**) buffer
;
664 return NSS_STATUS_SUCCESS
;
668 return NSS_STATUS_NOTFOUND
;
672 return NSS_STATUS_UNAVAIL
;
675 enum nss_status
_nss_mymachines_getgrgid_r(
678 char *buffer
, size_t buflen
,
681 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
682 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
683 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
684 const char *machine
, *object
;
688 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
690 if (!gid_is_valid(gid
))
693 /* We consider all gids < 65536 host gids */
694 if (gid
< HOST_GID_LIMIT
)
697 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
700 r
= sd_bus_open_system(&bus
);
704 r
= sd_bus_call_method(bus
,
705 "org.freedesktop.machine1",
706 "/org/freedesktop/machine1",
707 "org.freedesktop.machine1.Manager",
714 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
720 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
727 if (buflen
< sizeof(char*) + 1) {
729 return NSS_STATUS_TRYAGAIN
;
732 memzero(buffer
, sizeof(char*));
733 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
735 return NSS_STATUS_TRYAGAIN
;
738 gr
->gr_name
= buffer
+ sizeof(char*);
740 gr
->gr_passwd
= (char*) "*"; /* locked */
741 gr
->gr_mem
= (char**) buffer
;
744 return NSS_STATUS_SUCCESS
;
748 return NSS_STATUS_NOTFOUND
;
752 return NSS_STATUS_UNAVAIL
;