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"
28 #include "hostname-util.h"
29 #include "in-addr-util.h"
32 #include "signal-util.h"
33 #include "string-util.h"
34 #include "user-util.h"
37 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines
);
38 NSS_GETPW_PROTOTYPES(mymachines
);
39 NSS_GETGR_PROTOTYPES(mymachines
);
41 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
48 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
51 r
= sd_bus_message_read(m
, "i", &family
);
55 r
= sd_bus_message_skip(m
, "ay");
59 r
= sd_bus_message_exit_container(m
);
63 if (af
!= AF_UNSPEC
&& family
!= af
)
71 r
= sd_bus_message_rewind(m
, false);
79 enum nss_status
_nss_mymachines_gethostbyname4_r(
81 struct gaih_addrtuple
**pat
,
82 char *buffer
, size_t buflen
,
83 int *errnop
, int *h_errnop
,
86 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
87 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
88 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
89 _cleanup_free_
int *ifindices
= NULL
;
90 _cleanup_free_
char *class = NULL
;
92 unsigned i
= 0, c
= 0;
96 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
104 r
= sd_machine_get_class(name
, &class);
107 if (!streq(class, "container")) {
112 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
113 if (n_ifindices
< 0) {
118 r
= sd_bus_open_system(&bus
);
122 r
= sd_bus_call_method(bus
,
123 "org.freedesktop.machine1",
124 "/org/freedesktop/machine1",
125 "org.freedesktop.machine1.Manager",
126 "GetMachineAddresses",
133 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
137 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
143 *h_errnop
= HOST_NOT_FOUND
;
144 return NSS_STATUS_NOTFOUND
;
148 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
151 *h_errnop
= TRY_AGAIN
;
152 return NSS_STATUS_TRYAGAIN
;
155 /* First, append name */
157 memcpy(r_name
, name
, l
+1);
160 /* Second, append addresses */
161 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
162 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
167 r
= sd_bus_message_read(reply
, "i", &family
);
171 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
175 r
= sd_bus_message_exit_container(reply
);
179 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
184 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
189 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
190 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
191 r_tuple
->name
= r_name
;
192 r_tuple
->family
= family
;
193 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
194 memcpy(r_tuple
->addr
, a
, sz
);
196 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
202 r
= sd_bus_message_exit_container(reply
);
209 **pat
= *r_tuple_first
;
211 *pat
= r_tuple_first
;
216 /* Explicitly reset all error variables */
218 *h_errnop
= NETDB_SUCCESS
;
221 return NSS_STATUS_SUCCESS
;
226 return NSS_STATUS_UNAVAIL
;
229 enum nss_status
_nss_mymachines_gethostbyname3_r(
232 struct hostent
*result
,
233 char *buffer
, size_t buflen
,
234 int *errnop
, int *h_errnop
,
238 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
239 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
240 _cleanup_free_
char *class = NULL
;
241 unsigned c
= 0, i
= 0;
242 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
243 size_t l
, idx
, ms
, alen
;
246 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
257 if (af
!= AF_INET
&& af
!= AF_INET6
) {
262 r
= sd_machine_get_class(name
, &class);
265 if (!streq(class, "container")) {
270 r
= sd_bus_open_system(&bus
);
274 r
= sd_bus_call_method(bus
,
275 "org.freedesktop.machine1",
276 "/org/freedesktop/machine1",
277 "org.freedesktop.machine1.Manager",
278 "GetMachineAddresses",
285 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
289 r
= count_addresses(reply
, af
, &c
);
295 *h_errnop
= HOST_NOT_FOUND
;
296 return NSS_STATUS_NOTFOUND
;
299 alen
= FAMILY_ADDRESS_SIZE(af
);
302 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
306 *h_errnop
= NO_RECOVERY
;
307 return NSS_STATUS_TRYAGAIN
;
310 /* First, append name */
312 memcpy(r_name
, name
, l
+1);
315 /* Second, create aliases array */
316 r_aliases
= buffer
+ idx
;
317 ((char**) r_aliases
)[0] = NULL
;
318 idx
+= sizeof(char*);
320 /* Third, append addresses */
321 r_addr
= buffer
+ idx
;
322 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
327 r
= sd_bus_message_read(reply
, "i", &family
);
331 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
335 r
= sd_bus_message_exit_container(reply
);
347 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
352 idx
+= c
* ALIGN(alen
);
354 r
= sd_bus_message_exit_container(reply
);
358 /* Third, append address pointer array */
359 r_addr_list
= buffer
+ idx
;
360 for (i
= 0; i
< c
; i
++)
361 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
363 ((char**) r_addr_list
)[i
] = NULL
;
364 idx
+= (c
+1) * sizeof(char*);
368 result
->h_name
= r_name
;
369 result
->h_aliases
= (char**) r_aliases
;
370 result
->h_addrtype
= af
;
371 result
->h_length
= alen
;
372 result
->h_addr_list
= (char**) r_addr_list
;
380 /* Explicitly reset all error variables */
382 *h_errnop
= NETDB_SUCCESS
;
385 return NSS_STATUS_SUCCESS
;
390 return NSS_STATUS_UNAVAIL
;
393 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
395 enum nss_status
_nss_mymachines_getpwnam_r(
398 char *buffer
, size_t buflen
,
401 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
402 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
403 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
404 const char *p
, *e
, *machine
;
410 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
415 p
= startswith(name
, "vu-");
423 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
426 r
= parse_uid(e
+ 1, &uid
);
430 machine
= strndupa(p
, e
- p
);
431 if (!machine_name_is_valid(machine
))
434 r
= sd_bus_open_system(&bus
);
438 r
= sd_bus_call_method(bus
,
439 "org.freedesktop.machine1",
440 "/org/freedesktop/machine1",
441 "org.freedesktop.machine1.Manager",
442 "MapFromMachineUser",
446 machine
, (uint32_t) uid
);
448 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
454 r
= sd_bus_message_read(reply
, "u", &mapped
);
461 return NSS_STATUS_TRYAGAIN
;
464 memcpy(buffer
, name
, l
+1);
466 pwd
->pw_name
= buffer
;
467 pwd
->pw_uid
= mapped
;
468 pwd
->pw_gid
= 65534; /* nobody */
469 pwd
->pw_gecos
= buffer
;
470 pwd
->pw_passwd
= (char*) "*"; /* locked */
471 pwd
->pw_dir
= (char*) "/";
472 pwd
->pw_shell
= (char*) "/sbin/nologin";
475 return NSS_STATUS_SUCCESS
;
479 return NSS_STATUS_NOTFOUND
;
483 return NSS_STATUS_UNAVAIL
;
486 enum nss_status
_nss_mymachines_getpwuid_r(
489 char *buffer
, size_t buflen
,
492 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
493 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
494 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
495 const char *machine
, *object
;
499 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
501 if (!uid_is_valid(uid
)) {
506 /* We consider all uids < 65536 host uids */
510 r
= sd_bus_open_system(&bus
);
514 r
= sd_bus_call_method(bus
,
515 "org.freedesktop.machine1",
516 "/org/freedesktop/machine1",
517 "org.freedesktop.machine1.Manager",
524 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
530 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
534 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
536 return NSS_STATUS_TRYAGAIN
;
539 pwd
->pw_name
= buffer
;
541 pwd
->pw_gid
= 65534; /* nobody */
542 pwd
->pw_gecos
= buffer
;
543 pwd
->pw_passwd
= (char*) "*"; /* locked */
544 pwd
->pw_dir
= (char*) "/";
545 pwd
->pw_shell
= (char*) "/sbin/nologin";
548 return NSS_STATUS_SUCCESS
;
552 return NSS_STATUS_NOTFOUND
;
556 return NSS_STATUS_UNAVAIL
;
559 enum nss_status
_nss_mymachines_getgrnam_r(
562 char *buffer
, size_t buflen
,
565 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
566 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
567 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
568 const char *p
, *e
, *machine
;
574 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
579 p
= startswith(name
, "vg-");
587 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
590 r
= parse_gid(e
+ 1, &gid
);
594 machine
= strndupa(p
, e
- p
);
595 if (!machine_name_is_valid(machine
))
598 r
= sd_bus_open_system(&bus
);
602 r
= sd_bus_call_method(bus
,
603 "org.freedesktop.machine1",
604 "/org/freedesktop/machine1",
605 "org.freedesktop.machine1.Manager",
606 "MapFromMachineGroup",
610 machine
, (uint32_t) gid
);
612 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
618 r
= sd_bus_message_read(reply
, "u", &mapped
);
622 l
= sizeof(char*) + strlen(name
) + 1;
625 return NSS_STATUS_TRYAGAIN
;
628 memzero(buffer
, sizeof(char*));
629 strcpy(buffer
+ sizeof(char*), name
);
631 gr
->gr_name
= buffer
+ sizeof(char*);
633 gr
->gr_passwd
= (char*) "*"; /* locked */
634 gr
->gr_mem
= (char**) buffer
;
637 return NSS_STATUS_SUCCESS
;
641 return NSS_STATUS_NOTFOUND
;
645 return NSS_STATUS_UNAVAIL
;
648 enum nss_status
_nss_mymachines_getgrgid_r(
651 char *buffer
, size_t buflen
,
654 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
655 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
656 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
657 const char *machine
, *object
;
661 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
663 if (!gid_is_valid(gid
)) {
668 /* We consider all gids < 65536 host gids */
672 r
= sd_bus_open_system(&bus
);
676 r
= sd_bus_call_method(bus
,
677 "org.freedesktop.machine1",
678 "/org/freedesktop/machine1",
679 "org.freedesktop.machine1.Manager",
686 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
692 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
696 if (buflen
< sizeof(char*) + 1) {
698 return NSS_STATUS_TRYAGAIN
;
701 memzero(buffer
, sizeof(char*));
702 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
704 return NSS_STATUS_TRYAGAIN
;
707 gr
->gr_name
= buffer
+ sizeof(char*);
709 gr
->gr_passwd
= (char*) "*"; /* locked */
710 gr
->gr_mem
= (char**) buffer
;
713 return NSS_STATUS_SUCCESS
;
717 return NSS_STATUS_NOTFOUND
;
721 return NSS_STATUS_UNAVAIL
;