1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "alloc-util.h"
29 #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 static int count_addresses(sd_bus_message
*m
, int af
, unsigned *ret
) {
50 while ((r
= sd_bus_message_enter_container(m
, 'r', "iay")) > 0) {
53 r
= sd_bus_message_read(m
, "i", &family
);
57 r
= sd_bus_message_skip(m
, "ay");
61 r
= sd_bus_message_exit_container(m
);
65 if (af
!= AF_UNSPEC
&& family
!= af
)
73 r
= sd_bus_message_rewind(m
, false);
81 enum nss_status
_nss_mymachines_gethostbyname4_r(
83 struct gaih_addrtuple
**pat
,
84 char *buffer
, size_t buflen
,
85 int *errnop
, int *h_errnop
,
88 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
89 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
90 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
91 _cleanup_free_
int *ifindices
= NULL
;
92 _cleanup_free_
char *class = NULL
;
94 unsigned i
= 0, c
= 0;
98 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
106 r
= sd_machine_get_class(name
, &class);
109 if (!streq(class, "container")) {
114 n_ifindices
= sd_machine_get_ifindices(name
, &ifindices
);
115 if (n_ifindices
< 0) {
120 r
= sd_bus_open_system(&bus
);
124 r
= sd_bus_call_method(bus
,
125 "org.freedesktop.machine1",
126 "/org/freedesktop/machine1",
127 "org.freedesktop.machine1.Manager",
128 "GetMachineAddresses",
135 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
139 r
= count_addresses(reply
, AF_UNSPEC
, &c
);
145 *h_errnop
= HOST_NOT_FOUND
;
146 return NSS_STATUS_NOTFOUND
;
150 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
153 *h_errnop
= TRY_AGAIN
;
154 return NSS_STATUS_TRYAGAIN
;
157 /* First, append name */
159 memcpy(r_name
, name
, l
+1);
162 /* Second, append addresses */
163 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
164 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
169 r
= sd_bus_message_read(reply
, "i", &family
);
173 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
177 r
= sd_bus_message_exit_container(reply
);
181 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
186 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
191 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
192 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
193 r_tuple
->name
= r_name
;
194 r_tuple
->family
= family
;
195 r_tuple
->scopeid
= n_ifindices
== 1 ? ifindices
[0] : 0;
196 memcpy(r_tuple
->addr
, a
, sz
);
198 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
204 r
= sd_bus_message_exit_container(reply
);
211 **pat
= *r_tuple_first
;
213 *pat
= r_tuple_first
;
218 /* Explicitly reset all error variables */
220 *h_errnop
= NETDB_SUCCESS
;
223 return NSS_STATUS_SUCCESS
;
228 return NSS_STATUS_UNAVAIL
;
231 enum nss_status
_nss_mymachines_gethostbyname3_r(
234 struct hostent
*result
,
235 char *buffer
, size_t buflen
,
236 int *errnop
, int *h_errnop
,
240 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
241 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
242 _cleanup_free_
char *class = NULL
;
243 unsigned c
= 0, i
= 0;
244 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
245 size_t l
, idx
, ms
, alen
;
248 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
259 if (af
!= AF_INET
&& af
!= AF_INET6
) {
264 r
= sd_machine_get_class(name
, &class);
267 if (!streq(class, "container")) {
272 r
= sd_bus_open_system(&bus
);
276 r
= sd_bus_call_method(bus
,
277 "org.freedesktop.machine1",
278 "/org/freedesktop/machine1",
279 "org.freedesktop.machine1.Manager",
280 "GetMachineAddresses",
287 r
= sd_bus_message_enter_container(reply
, 'a', "(iay)");
291 r
= count_addresses(reply
, af
, &c
);
297 *h_errnop
= HOST_NOT_FOUND
;
298 return NSS_STATUS_NOTFOUND
;
301 alen
= FAMILY_ADDRESS_SIZE(af
);
304 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
308 *h_errnop
= NO_RECOVERY
;
309 return NSS_STATUS_TRYAGAIN
;
312 /* First, append name */
314 memcpy(r_name
, name
, l
+1);
317 /* Second, create aliases array */
318 r_aliases
= buffer
+ idx
;
319 ((char**) r_aliases
)[0] = NULL
;
320 idx
+= sizeof(char*);
322 /* Third, append addresses */
323 r_addr
= buffer
+ idx
;
324 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iay")) > 0) {
329 r
= sd_bus_message_read(reply
, "i", &family
);
333 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
337 r
= sd_bus_message_exit_container(reply
);
349 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
354 idx
+= c
* ALIGN(alen
);
356 r
= sd_bus_message_exit_container(reply
);
360 /* Third, append address pointer array */
361 r_addr_list
= buffer
+ idx
;
362 for (i
= 0; i
< c
; i
++)
363 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
365 ((char**) r_addr_list
)[i
] = NULL
;
366 idx
+= (c
+1) * sizeof(char*);
370 result
->h_name
= r_name
;
371 result
->h_aliases
= (char**) r_aliases
;
372 result
->h_addrtype
= af
;
373 result
->h_length
= alen
;
374 result
->h_addr_list
= (char**) r_addr_list
;
382 /* Explicitly reset all error variables */
384 *h_errnop
= NETDB_SUCCESS
;
387 return NSS_STATUS_SUCCESS
;
392 return NSS_STATUS_UNAVAIL
;
395 NSS_GETHOSTBYNAME_FALLBACKS(mymachines
);
397 enum nss_status
_nss_mymachines_getpwnam_r(
400 char *buffer
, size_t buflen
,
403 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
404 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
405 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
406 const char *p
, *e
, *machine
;
412 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
417 p
= startswith(name
, "vu-");
425 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
428 r
= parse_uid(e
+ 1, &uid
);
432 machine
= strndupa(p
, e
- p
);
433 if (!machine_name_is_valid(machine
))
436 r
= sd_bus_open_system(&bus
);
440 r
= sd_bus_call_method(bus
,
441 "org.freedesktop.machine1",
442 "/org/freedesktop/machine1",
443 "org.freedesktop.machine1.Manager",
444 "MapFromMachineUser",
448 machine
, (uint32_t) uid
);
450 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
456 r
= sd_bus_message_read(reply
, "u", &mapped
);
463 return NSS_STATUS_TRYAGAIN
;
466 memcpy(buffer
, name
, l
+1);
468 pwd
->pw_name
= buffer
;
469 pwd
->pw_uid
= mapped
;
470 pwd
->pw_gid
= 65534; /* nobody */
471 pwd
->pw_gecos
= buffer
;
472 pwd
->pw_passwd
= (char*) "*"; /* locked */
473 pwd
->pw_dir
= (char*) "/";
474 pwd
->pw_shell
= (char*) "/sbin/nologin";
477 return NSS_STATUS_SUCCESS
;
481 return NSS_STATUS_NOTFOUND
;
485 return NSS_STATUS_UNAVAIL
;
488 enum nss_status
_nss_mymachines_getpwuid_r(
491 char *buffer
, size_t buflen
,
494 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
495 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
496 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
497 const char *machine
, *object
;
501 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
503 if (!uid_is_valid(uid
)) {
508 /* We consider all uids < 65536 host uids */
512 r
= sd_bus_open_system(&bus
);
516 r
= sd_bus_call_method(bus
,
517 "org.freedesktop.machine1",
518 "/org/freedesktop/machine1",
519 "org.freedesktop.machine1.Manager",
526 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_USER_MAPPING
))
532 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
536 if (snprintf(buffer
, buflen
, "vu-%s-" UID_FMT
, machine
, (uid_t
) mapped
) >= (int) buflen
) {
538 return NSS_STATUS_TRYAGAIN
;
541 pwd
->pw_name
= buffer
;
543 pwd
->pw_gid
= 65534; /* nobody */
544 pwd
->pw_gecos
= buffer
;
545 pwd
->pw_passwd
= (char*) "*"; /* locked */
546 pwd
->pw_dir
= (char*) "/";
547 pwd
->pw_shell
= (char*) "/sbin/nologin";
550 return NSS_STATUS_SUCCESS
;
554 return NSS_STATUS_NOTFOUND
;
558 return NSS_STATUS_UNAVAIL
;
561 enum nss_status
_nss_mymachines_getgrnam_r(
564 char *buffer
, size_t buflen
,
567 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
568 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
569 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
570 const char *p
, *e
, *machine
;
576 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
581 p
= startswith(name
, "vg-");
589 if (e
- p
> HOST_NAME_MAX
- 1) /* -1 for the last dash */
592 r
= parse_gid(e
+ 1, &gid
);
596 machine
= strndupa(p
, e
- p
);
597 if (!machine_name_is_valid(machine
))
600 r
= sd_bus_open_system(&bus
);
604 r
= sd_bus_call_method(bus
,
605 "org.freedesktop.machine1",
606 "/org/freedesktop/machine1",
607 "org.freedesktop.machine1.Manager",
608 "MapFromMachineGroup",
612 machine
, (uint32_t) gid
);
614 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
620 r
= sd_bus_message_read(reply
, "u", &mapped
);
624 l
= sizeof(char*) + strlen(name
) + 1;
627 return NSS_STATUS_TRYAGAIN
;
630 memzero(buffer
, sizeof(char*));
631 strcpy(buffer
+ sizeof(char*), name
);
633 gr
->gr_name
= buffer
+ sizeof(char*);
635 gr
->gr_passwd
= (char*) "*"; /* locked */
636 gr
->gr_mem
= (char**) buffer
;
639 return NSS_STATUS_SUCCESS
;
643 return NSS_STATUS_NOTFOUND
;
647 return NSS_STATUS_UNAVAIL
;
650 enum nss_status
_nss_mymachines_getgrgid_r(
653 char *buffer
, size_t buflen
,
656 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
657 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
658 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
659 const char *machine
, *object
;
663 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
665 if (!gid_is_valid(gid
)) {
670 /* We consider all gids < 65536 host gids */
674 r
= sd_bus_open_system(&bus
);
678 r
= sd_bus_call_method(bus
,
679 "org.freedesktop.machine1",
680 "/org/freedesktop/machine1",
681 "org.freedesktop.machine1.Manager",
688 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
))
694 r
= sd_bus_message_read(reply
, "sou", &machine
, &object
, &mapped
);
698 if (buflen
< sizeof(char*) + 1) {
700 return NSS_STATUS_TRYAGAIN
;
703 memzero(buffer
, sizeof(char*));
704 if (snprintf(buffer
+ sizeof(char*), buflen
- sizeof(char*), "vg-%s-" GID_FMT
, machine
, (gid_t
) mapped
) >= (int) buflen
) {
706 return NSS_STATUS_TRYAGAIN
;
709 gr
->gr_name
= buffer
+ sizeof(char*);
711 gr
->gr_passwd
= (char*) "*"; /* locked */
712 gr
->gr_mem
= (char**) buffer
;
715 return NSS_STATUS_SUCCESS
;
719 return NSS_STATUS_NOTFOUND
;
723 return NSS_STATUS_UNAVAIL
;