2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "bus-common-errors.h"
29 #include "hostname-util.h"
30 #include "in-addr-util.h"
33 #include "signal-util.h"
34 #include "string-util.h"
35 #include "user-util.h"
38 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
39 NSS_GETPW_PROTOTYPES(mymachines
);
40 NSS_GETGR_PROTOTYPES(mymachines
);
42 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
43 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
45 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
52 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
55 r
= sd_bus_message_read(m
, "i", &family
);
59 r
= sd_bus_message_skip(m
, "ay");
63 r
= sd_bus_message_exit_container(m
);
67 if (af
!= AF_UNSPEC
&& family
!= af
)
75 r
= sd_bus_message_rewind(m
, false);
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;
100 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
108 r
= sd_machine_get_class(name
, &class);
111 if (!streq(class, "container")) {
116 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
117 if (n_ifindices
< 0) {
122 r
= sd_bus_open_system(&bus
);
126 r
= sd_bus_call_method(bus
,
127 "org.freedesktop.machine1",
128 "/org/freedesktop/machine1",
129 "org.freedesktop.machine1.Manager",
130 "GetMachineAddresses",
137 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
141 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
147 *h_errnop
= HOST_NOT_FOUND
;
148 return NSS_STATUS_NOTFOUND
;
152 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
155 *h_errnop
= NETDB_INTERNAL
;
156 return NSS_STATUS_TRYAGAIN
;
159 /* First, append name */
161 memcpy(r_name
, name
, l
+1);
164 /* Second, append addresses */
165 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
166 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
171 r
= sd_bus_message_read(reply
, "i", &family
);
175 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
179 r
= sd_bus_message_exit_container(reply
);
183 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
188 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
193 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
194 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
195 r_tuple
->name
= r_name
;
196 r_tuple
->family
= family
;
197 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
198 memcpy(r_tuple
->addr
, a
, sz
);
200 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
206 r
= sd_bus_message_exit_container(reply
);
213 **pat
= *r_tuple_first
;
215 *pat
= r_tuple_first
;
220 /* Explicitly reset all error variables */
222 *h_errnop
= NETDB_SUCCESS
;
225 return NSS_STATUS_SUCCESS
;
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
;
250 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
261 if (af
!= AF_INET
&& af
!= AF_INET6
) {
266 r
= sd_machine_get_class(name
, &class);
269 if (!streq(class, "container")) {
274 r
= sd_bus_open_system(&bus
);
278 r
= sd_bus_call_method(bus
,
279 "org.freedesktop.machine1",
280 "/org/freedesktop/machine1",
281 "org.freedesktop.machine1.Manager",
282 "GetMachineAddresses",
289 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
293 r
= count_addresses(reply
, af
, &c
);
299 *h_errnop
= HOST_NOT_FOUND
;
300 return NSS_STATUS_NOTFOUND
;
303 alen
= FAMILY_ADDRESS_SIZE(af
);
306 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
310 *h_errnop
= NETDB_INTERNAL
;
311 return NSS_STATUS_TRYAGAIN
;
314 /* First, append name */
316 memcpy(r_name
, name
, l
+1);
319 /* Second, create aliases array */
320 r_aliases
= buffer
+ idx
;
321 ((char**) r_aliases
)[0] = NULL
;
322 idx
+= sizeof(char*);
324 /* Third, append addresses */
325 r_addr
= buffer
+ idx
;
326 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
331 r
= sd_bus_message_read(reply
, "i", &family
);
335 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
339 r
= sd_bus_message_exit_container(reply
);
351 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
356 idx
+= c
* ALIGN(alen
);
358 r
= sd_bus_message_exit_container(reply
);
362 /* Third, append address pointer array */
363 r_addr_list
= buffer
+ idx
;
364 for (i
= 0; i
< c
; i
++)
365 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
367 ((char**) r_addr_list
)[i
] = NULL
;
368 idx
+= (c
+1) * sizeof(char*);
372 result
->h_name
= r_name
;
373 result
->h_aliases
= (char**) r_aliases
;
374 result
->h_addrtype
= af
;
375 result
->h_length
= alen
;
376 result
->h_addr_list
= (char**) r_addr_list
;
384 /* Explicitly reset all error variables */
386 *h_errnop
= NETDB_SUCCESS
;
389 return NSS_STATUS_SUCCESS
;
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
;
414 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
419 p
= startswith(name
, "vu-");
427 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
430 r
= parse_uid(e
+ 1, &uid
);
434 machine
= strndupa(p
, e
- p
);
435 if (!machine_name_is_valid(machine
))
438 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
439 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
440 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
441 * running on the host. */
444 r
= sd_bus_open_system(&bus
);
448 r
= sd_bus_call_method(bus
,
449 "org.freedesktop.machine1",
450 "/org/freedesktop/machine1",
451 "org.freedesktop.machine1.Manager",
452 "MapFromMachineUser",
456 machine
, (uint32_t) uid
);
458 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
464 r
= sd_bus_message_read(reply
, "u", &mapped
);
468 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
469 if (mapped
< HOST_UID_LIMIT
|| mapped
== uid
)
475 return NSS_STATUS_TRYAGAIN
;
478 memcpy(buffer
, name
, l
+1);
480 pwd
->pw_name
= buffer
;
481 pwd
->pw_uid
= mapped
;
482 pwd
->pw_gid
= 65534; /* nobody */
483 pwd
->pw_gecos
= buffer
;
484 pwd
->pw_passwd
= (char*) "*"; /* locked */
485 pwd
->pw_dir
= (char*) "/";
486 pwd
->pw_shell
= (char*) "/sbin/nologin";
489 return NSS_STATUS_SUCCESS
;
493 return NSS_STATUS_NOTFOUND
;
497 return NSS_STATUS_UNAVAIL
;
500 enum nss_status
_nss_mymachines_getpwuid_r(
503 char *buffer
, size_t buflen
,
506 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
507 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
508 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
509 const char *machine
, *object
;
513 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
515 if (!uid_is_valid(uid
))
518 /* We consider all uids < 65536 host uids */
519 if (uid
< HOST_UID_LIMIT
)
522 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
525 r
= sd_bus_open_system(&bus
);
529 r
= sd_bus_call_method(bus
,
530 "org.freedesktop.machine1",
531 "/org/freedesktop/machine1",
532 "org.freedesktop.machine1.Manager",
539 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
545 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
552 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
554 return NSS_STATUS_TRYAGAIN
;
557 pwd
->pw_name
= buffer
;
559 pwd
->pw_gid
= 65534; /* nobody */
560 pwd
->pw_gecos
= buffer
;
561 pwd
->pw_passwd
= (char*) "*"; /* locked */
562 pwd
->pw_dir
= (char*) "/";
563 pwd
->pw_shell
= (char*) "/sbin/nologin";
566 return NSS_STATUS_SUCCESS
;
570 return NSS_STATUS_NOTFOUND
;
574 return NSS_STATUS_UNAVAIL
;
577 enum nss_status
_nss_mymachines_getgrnam_r(
580 char *buffer
, size_t buflen
,
583 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
584 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
585 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
586 const char *p
, *e
, *machine
;
592 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
597 p
= startswith(name
, "vg-");
605 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
608 r
= parse_gid(e
+ 1, &gid
);
612 machine
= strndupa(p
, e
- p
);
613 if (!machine_name_is_valid(machine
))
616 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
619 r
= sd_bus_open_system(&bus
);
623 r
= sd_bus_call_method(bus
,
624 "org.freedesktop.machine1",
625 "/org/freedesktop/machine1",
626 "org.freedesktop.machine1.Manager",
627 "MapFromMachineGroup",
631 machine
, (uint32_t) gid
);
633 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
639 r
= sd_bus_message_read(reply
, "u", &mapped
);
643 if (mapped
< HOST_GID_LIMIT
|| mapped
== gid
)
646 l
= sizeof(char*) + strlen(name
) + 1;
649 return NSS_STATUS_TRYAGAIN
;
652 memzero(buffer
, sizeof(char*));
653 strcpy(buffer
+ sizeof(char*), name
);
655 gr
->gr_name
= buffer
+ sizeof(char*);
657 gr
->gr_passwd
= (char*) "*"; /* locked */
658 gr
->gr_mem
= (char**) buffer
;
661 return NSS_STATUS_SUCCESS
;
665 return NSS_STATUS_NOTFOUND
;
669 return NSS_STATUS_UNAVAIL
;
672 enum nss_status
_nss_mymachines_getgrgid_r(
675 char *buffer
, size_t buflen
,
678 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
679 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
680 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
681 const char *machine
, *object
;
685 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
687 if (!gid_is_valid(gid
))
690 /* We consider all gids < 65536 host gids */
691 if (gid
< HOST_GID_LIMIT
)
694 if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
697 r
= sd_bus_open_system(&bus
);
701 r
= sd_bus_call_method(bus
,
702 "org.freedesktop.machine1",
703 "/org/freedesktop/machine1",
704 "org.freedesktop.machine1.Manager",
711 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
717 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
724 if (buflen
< sizeof(char*) + 1) {
726 return NSS_STATUS_TRYAGAIN
;
729 memzero(buffer
, sizeof(char*));
730 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
732 return NSS_STATUS_TRYAGAIN
;
735 gr
->gr_name
= buffer
+ sizeof(char*);
737 gr
->gr_passwd
= (char*) "*"; /* locked */
738 gr
->gr_mem
= (char**) buffer
;
741 return NSS_STATUS_SUCCESS
;
745 return NSS_STATUS_NOTFOUND
;
749 return NSS_STATUS_UNAVAIL
;