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
= 65534; /* 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
= 65534; /* 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 enum nss_status
_nss_mymachines_getgrnam_r(
581 char *buffer
, size_t buflen
,
584 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
585 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
586 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
587 const char *p
, *e
, *machine
;
593 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
598 p
= startswith(name
, "vg-");
606 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
609 r
= parse_gid(e
+ 1, &gid
);
613 machine
= strndupa(p
, e
- p
);
614 if (!machine_name_is_valid(machine
))
617 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
620 r
= sd_bus_open_system(&bus
);
624 r
= sd_bus_call_method(bus
,
625 "org.freedesktop.machine1",
626 "/org/freedesktop/machine1",
627 "org.freedesktop.machine1.Manager",
628 "MapFromMachineGroup",
632 machine
, (uint32_t) gid
);
634 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
640 r
= sd_bus_message_read(reply
, "u", &mapped
);
644 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
647 l
= sizeof(char*) + strlen(name
) + 1;
650 return NSS_STATUS_TRYAGAIN
;
653 memzero(buffer
, sizeof(char*));
654 strcpy(buffer
+ sizeof(char*), name
);
656 gr
->gr_name
= buffer
+ sizeof(char*);
658 gr
->gr_passwd
= (char*) "*"; /* locked */
659 gr
->gr_mem
= (char**) buffer
;
662 return NSS_STATUS_SUCCESS
;
666 return NSS_STATUS_NOTFOUND
;
670 return NSS_STATUS_UNAVAIL
;
673 enum nss_status
_nss_mymachines_getgrgid_r(
676 char *buffer
, size_t buflen
,
679 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
680 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
681 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
682 const char *machine
, *object
;
686 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
688 if (!gid_is_valid(gid
))
691 /* We consider all gids < 65536 host gids */
692 if (gid
< HOST_GID_LIMIT
)
695 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
698 r
= sd_bus_open_system(&bus
);
702 r
= sd_bus_call_method(bus
,
703 "org.freedesktop.machine1",
704 "/org/freedesktop/machine1",
705 "org.freedesktop.machine1.Manager",
712 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
718 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
725 if (buflen
< sizeof(char*) + 1) {
727 return NSS_STATUS_TRYAGAIN
;
730 memzero(buffer
, sizeof(char*));
731 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
733 return NSS_STATUS_TRYAGAIN
;
736 gr
->gr_name
= buffer
+ sizeof(char*);
738 gr
->gr_passwd
= (char*) "*"; /* locked */
739 gr
->gr_mem
= (char**) buffer
;
742 return NSS_STATUS_SUCCESS
;
746 return NSS_STATUS_NOTFOUND
;
750 return NSS_STATUS_UNAVAIL
;