From cabb0bc6b1a4ec57e108dc99364687d7c4f9670f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Jul 2014 03:15:21 +0200 Subject: [PATCH] nss-mymachines: add new NSS module for automatically resolving addresses of all local containers --- Makefile.am | 19 ++ src/libsystemd/libsystemd.sym.m4 | 7 +- src/libsystemd/sd-login/sd-login.c | 43 +++ src/nss-mymachines/Makefile | 1 + src/nss-mymachines/nss-mymachines.c | 371 ++++++++++++++++++++++++++ src/nss-mymachines/nss-mymachines.sym | 17 ++ src/systemd/sd-login.h | 3 + 7 files changed, 460 insertions(+), 1 deletion(-) create mode 120000 src/nss-mymachines/Makefile create mode 100644 src/nss-mymachines/nss-mymachines.c create mode 100644 src/nss-mymachines/nss-mymachines.sym diff --git a/Makefile.am b/Makefile.am index 734e5c148..f934bb147 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4497,6 +4497,25 @@ BUSNAMES_TARGET_WANTS += \ EXTRA_DIST += \ units/systemd-machined.service.in +libnss_mymachines_la_SOURCES = \ + src/nss-mymachines/nss-mymachines.sym \ + src/nss-mymachines/nss-mymachines.c + +libnss_mymachines_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -module \ + -export-dynamic \ + -avoid-version \ + -shared \ + -shrext .so.2 \ + -Wl,--version-script=$(top_srcdir)/src/nss-mymachines/nss-mymachines.sym + +libnss_mymachines_la_LIBADD = \ + libsystemd-shared.la \ + libsystemd-internal.la + +lib_LTLIBRARIES += \ + libnss_mymachines.la endif # ------------------------------------------------------------------------------ diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 index 39e1f51f7..48572cc0b 100644 --- a/src/libsystemd/libsystemd.sym.m4 +++ b/src/libsystemd/libsystemd.sym.m4 @@ -148,6 +148,11 @@ global: sd_pid_notifyf; } LIBSYSTEMD_213; +LIBSYSTEMD_216 { +global: + sd_machine_get_ifindexes; +} LIBSYSTEMD_214; + m4_ifdef(`ENABLE_KDBUS', LIBSYSTEMD_FUTURE { global: @@ -444,5 +449,5 @@ global: /* sd-path */ sd_path_home; sd_path_search; -} LIBSYSTEMD_214; +} LIBSYSTEMD_216; ) diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index d1478ddb7..83d644924 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -786,6 +786,49 @@ _public_ int sd_machine_get_class(const char *machine, char **class) { return 0; } +_public_ int sd_machine_get_ifindexes(const char *machine, int **ifindexes) { + _cleanup_free_ char *netif = NULL; + size_t l, allocated = 0, nr = 0; + char *w, *state; + int *ni = NULL; + const char *p; + int r; + + assert_return(machine_name_is_valid(machine), -EINVAL); + assert_return(ifindexes, -EINVAL); + + p = strappenda("/run/systemd/machines/", machine); + r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL); + if (r < 0) + return r; + if (!netif) { + *ifindexes = NULL; + return 0; + } + + FOREACH_WORD(w, l, netif, state) { + char buf[l+1]; + int ifi; + + *(char*) (mempcpy(buf, w, l)) = 0; + + if (safe_atoi(buf, &ifi) < 0) + continue; + if (ifi <= 0) + continue; + + if (!GREEDY_REALLOC(ni, allocated, nr+1)) { + free(ni); + return -ENOMEM; + } + + ni[nr++] = ifi; + } + + *ifindexes = ni; + return nr; +} + static inline int MONITOR_TO_FD(sd_login_monitor *m) { return (int) (unsigned long) m - 1; } diff --git a/src/nss-mymachines/Makefile b/src/nss-mymachines/Makefile new file mode 120000 index 000000000..d0b0e8e00 --- /dev/null +++ b/src/nss-mymachines/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c new file mode 100644 index 000000000..2d3e54210 --- /dev/null +++ b/src/nss-mymachines/nss-mymachines.c @@ -0,0 +1,371 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-bus.h" +#include "sd-login.h" +#include "macro.h" +#include "util.h" +#include "nss-util.h" +#include "bus-util.h" +#include "in-addr-util.h" + +NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); + +static int count_addresses(sd_bus_message *m, unsigned af, unsigned *ret) { + unsigned c = 0; + int r; + + assert(m); + assert(ret); + + while ((r = sd_bus_message_enter_container(m, 'r', "yay")) > 0) { + unsigned char family; + + r = sd_bus_message_read(m, "y", &family); + if (r < 0) + return r; + + r = sd_bus_message_skip(m, "ay"); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (af != AF_UNSPEC && family != af) + continue; + + c ++; + } + if (r < 0) + return r; + + r = sd_bus_message_rewind(m, false); + if (r < 0) + return r; + + *ret = c; + return 0; +} + +enum nss_status _nss_mymachines_gethostbyname4_r( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp) { + + struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_free_ int *ifindexes = NULL; + _cleanup_free_ char *class = NULL; + size_t l, ms, idx; + unsigned i = 0, c = 0; + char *r_name; + int n_ifindexes, r; + + assert(name); + assert(pat); + assert(buffer); + assert(errnop); + assert(h_errnop); + + r = sd_machine_get_class(name, &class); + if (r < 0) + goto fail; + if (!streq(class, "container")) { + r = -ENOTTY; + goto fail; + } + + n_ifindexes = sd_machine_get_ifindexes(name, &ifindexes); + if (n_ifindexes < 0) { + r = n_ifindexes; + goto fail; + } + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachineAddresses", + NULL, + &reply, + "s", name); + if (r < 0) + goto fail; + + r = sd_bus_message_enter_container(reply, 'a', "(yay)"); + if (r < 0) + goto fail; + + r = count_addresses(reply, AF_UNSPEC, &c); + if (r < 0) + goto fail; + + if (c <= 0) { + *errnop = ENOENT; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + l = strlen(name); + ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; + if (buflen < ms) { + *errnop = ENOMEM; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_TRYAGAIN; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, l+1); + idx = ALIGN(l+1); + + /* Second, append addresses */ + r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); + while ((r = sd_bus_message_enter_container(reply, 'r', "yay")) > 0) { + unsigned char family; + const void *a; + size_t sz; + + r = sd_bus_message_read(reply, "y", &family); + if (r < 0) + goto fail; + + r = sd_bus_message_read_array(reply, 'y', &a, &sz); + if (r < 0) + goto fail; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto fail; + + if (sz != PROTO_ADDRESS_SIZE(family)) { + r = -EINVAL; + goto fail; + } + + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); + r_tuple->name = r_name; + r_tuple->family = family; + r_tuple->scopeid = n_ifindexes == 1 ? ifindexes[0] : 0; + memcpy(r_tuple->addr, a, sz); + + idx += ALIGN(sizeof(struct gaih_addrtuple)); + i++; + } + + assert(i == c); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto fail; + + assert(idx == ms); + + if (*pat) + **pat = *r_tuple_first; + else + *pat = r_tuple_first; + + if (ttlp) + *ttlp = 0; + + return NSS_STATUS_SUCCESS; + +fail: + *errnop = -r; + *h_errnop = NO_DATA; + return NSS_STATUS_UNAVAIL; +} + +enum nss_status _nss_mymachines_gethostbyname3_r( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp) { + + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_free_ char *class = NULL; + unsigned c = 0, i = 0; + char *r_name, *r_aliases, *r_addr, *r_addr_list; + size_t l, idx, ms, alen; + int r; + + assert(name); + assert(result); + assert(buffer); + assert(errnop); + assert(h_errnop); + + if (af == AF_UNSPEC) + af = AF_INET; + + if (af != AF_INET && af != AF_INET6) { + r = -EAFNOSUPPORT; + goto fail; + } + + r = sd_machine_get_class(name, &class); + if (r < 0) + goto fail; + if (!streq(class, "container")) { + r = -ENOTTY; + goto fail; + } + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachineAddresses", + NULL, + &reply, + "s", name); + if (r < 0) + goto fail; + + r = sd_bus_message_enter_container(reply, 'a', "(yay)"); + if (r < 0) + goto fail; + + r = count_addresses(reply, af, &c); + if (r < 0) + goto fail; + + if (c <= 0) { + *errnop = ENOENT; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + alen = PROTO_ADDRESS_SIZE(af); + l = strlen(name); + + ms = ALIGN(l+1) + + sizeof(char*) + + (c > 0 ? c : 1) * ALIGN(alen) + + (c > 0 ? c+1 : 2) * sizeof(char*); + + if (buflen < ms) { + *errnop = ENOMEM; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_TRYAGAIN; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, l+1); + idx = ALIGN(l+1); + + /* Second, create aliases array */ + r_aliases = buffer + idx; + ((char**) r_aliases)[0] = NULL; + idx += sizeof(char*); + + /* Third, append addresses */ + r_addr = buffer + idx; + while ((r = sd_bus_message_enter_container(reply, 'r', "yay")) > 0) { + unsigned char family; + const void *a; + size_t sz; + + r = sd_bus_message_read(reply, "y", &family); + if (r < 0) + goto fail; + + r = sd_bus_message_read_array(reply, 'y', &a, &sz); + if (r < 0) + goto fail; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto fail; + + if (family != af) + continue; + + if (sz != alen) { + r = -EINVAL; + goto fail; + } + + memcpy(r_addr + i*ALIGN(alen), a, alen); + i++; + } + + assert(i == c); + idx += c * ALIGN(alen); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto fail; + + /* Third, append address pointer array */ + r_addr_list = buffer + idx; + for (i = 0; i < c; i++) + ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen); + + ((char**) r_addr_list)[i] = NULL; + idx += (c+1) * sizeof(char*); + + assert(idx == ms); + + result->h_name = r_name; + result->h_aliases = (char**) r_aliases; + result->h_addrtype = af; + result->h_length = alen; + result->h_addr_list = (char**) r_addr_list; + + if (ttlp) + *ttlp = 0; + + if (canonp) + *canonp = r_name; + + return NSS_STATUS_SUCCESS; + +fail: + *errnop = -r; + *h_errnop = NO_DATA; + return NSS_STATUS_UNAVAIL; +} + +NSS_GETHOSTBYNAME_FALLBACKS(mymachines) diff --git a/src/nss-mymachines/nss-mymachines.sym b/src/nss-mymachines/nss-mymachines.sym new file mode 100644 index 000000000..f80b51c1a --- /dev/null +++ b/src/nss-mymachines/nss-mymachines.sym @@ -0,0 +1,17 @@ +/*** + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +***/ + +{ +global: + _nss_mymachines_gethostbyname_r; + _nss_mymachines_gethostbyname2_r; + _nss_mymachines_gethostbyname3_r; + _nss_mymachines_gethostbyname4_r; +local: *; +}; diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index dad459a7e..b289ad2a5 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -181,6 +181,9 @@ int sd_seat_can_graphical(const char *seat); /* Return the class of machine */ int sd_machine_get_class(const char *machine, char **clazz); +/* Return the list if host-side network interface indexes of a machine */ +int sd_machine_get_ifindexes(const char *machine, int **ifindexes); + /* Get all seats, store in *seats. Returns the number of seats. If * seats is NULL, this only returns the number of seats. */ int sd_get_seats(char ***seats); -- 2.30.2