]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nss-mymachines: map userns users of containers to real user names
authorLennart Poettering <lennart@poettering.net>
Thu, 9 Jul 2015 17:46:20 +0000 (14:46 -0300)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Jul 2015 17:46:20 +0000 (14:46 -0300)
Given a container "foo", that maps user id $UID to container user, using
user namespaces, this NSS module extenstion will now map the $UID to a
name "vu-foo-$TUID" for the translated UID $UID.

Similar, userns groups are mapped to "vg-foo-$TGID" for translated GIDs
of $GID.

This simple change should make userns users more discoverable. Also,
given that many tools like "adduser" check NSS before allocating a UID,
should lower the chance of UID range conflicts between tools.

man/nss-mymachines.xml
src/basic/macro.h
src/libsystemd/sd-bus/bus-common-errors.h
src/machine/machined-dbus.c
src/machine/org.freedesktop.machine1.conf
src/nss-mymachines/nss-mymachines.c
src/nss-mymachines/nss-mymachines.sym
src/shared/nss-util.h

index eb1ed2592b835f3b80df8e537f7bcb8c0cc93c94..41ec458e4b87835ac7b1b273f6c11e761f864d68 100644 (file)
     <para><command>nss-mymachines</command> is a plugin for the GNU
     Name Service Switch (NSS) functionality of the GNU C Library
     (<command>glibc</command>) providing hostname resolution for
-    containers running locally, that are registered with
+    container names of containers running locally, that are registered
+    with
     <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-    The container names are resolved to IP addresses of the specific
-    container, ordered by their scope.</para>
+    The container names are resolved to the IP addresses of the
+    specific container, ordered by their scope.</para>
+
+    <para>The module also resolves user IDs used by containers to user
+    names indicating the container name, and back.</para>
 
     <para>To activate the NSS modules, <literal>mymachines</literal>
-    has to be added to the line starting with
-    <literal>hosts:</literal> in
+    has to be added to the lines starting with
+    <literal>hosts:</literal>, <literal>passwd:</literal> and
+    <literal>group:</literal> in
     <filename>/etc/nsswitch.conf</filename>.</para>
 
     <para>It is recommended to place <literal>mymachines</literal>
-    near the end of the <filename>nsswitch.conf</filename> line to
-    make sure that this mapping is only used as fallback, and any DNS
-    or <filename>/etc/hosts</filename> based mapping takes
-    precedence.</para>
+    near the end of the <filename>nsswitch.conf</filename> lines to
+    make sure that its mappings are only used as fallback, and any
+    other mappings, such as DNS or <filename>/etc/hosts</filename>
+    based mappings take precedence.</para>
   </refsect1>
 
   <refsect1>
     <para>Here's an example <filename>/etc/nsswitch.conf</filename>
     file, that enables <command>mymachines</command> correctly:</para>
 
-<programlisting>passwd:   compat
-group:    compat
-shadow:   compat
+    <programlisting>passwd:         compat <command>mymachines</command>
+group:          compat <command>mymachines</command>
+shadow:         compat
 
-hosts:    files dns <command>mymachines</command> myhostname
+hosts:          files dns <command>mymachines</command> myhostname
 networks:       files
 
 protocols:      db files
 services:       db files
-ethers:   db files
-rpc:      db files
+ethers:         db files
+rpc:            db files
 
 netgroup:       nis</programlisting>
 
index 5fa17ed2085cdc2fe3a7b992468f5917d6cd96b0..58530a398089a1ff16b199111bde046659a3bf40 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <inttypes.h>
+#include <stdbool.h>
 
 #define _printf_(a,b) __attribute__ ((format (printf, a, b)))
 #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -461,6 +462,18 @@ do {                                                                    \
 #define GID_INVALID ((gid_t) -1)
 #define MODE_INVALID ((mode_t) -1)
 
+static inline bool UID_IS_INVALID(uid_t uid) {
+        /* We consider both the old 16bit -1 user and the newer 32bit
+         * -1 user invalid, since they are or used to be incompatible
+         * with syscalls such as setresuid() or chown(). */
+
+        return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
+}
+
+static inline bool GID_IS_INVALID(gid_t gid) {
+        return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
+}
+
 #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)                 \
         static inline void func##p(type *p) {                   \
                 if (*p)                                         \
index 0dbfbddcf6b419bdf8241585d846c5ba9883623d..f2092795f410b40c3142338bbc8d2495980040b2 100644 (file)
@@ -46,6 +46,8 @@
 #define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
 #define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"
 #define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking"
+#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping"
+#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping"
 
 #define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession"
 #define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID"
index 0e971a6789ad1d8ef9bcecf065af98c7a5e0a563..3637815fc9b15e79b35cbc4d209facd48edffe0f 100644 (file)
 #include "bus-common-errors.h"
 #include "cgroup-util.h"
 #include "btrfs-util.h"
+#include "formats-util.h"
+#include "process-util.h"
 #include "machine-image.h"
 #include "machine-pool.h"
 #include "image-dbus.h"
 #include "machined.h"
 #include "machine-dbus.h"
-#include "formats-util.h"
 
 static int property_get_pool_path(
                 sd_bus *bus,
@@ -840,6 +841,230 @@ static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bu
         return bus_image_method_set_limit(message, i, error);
 }
 
+static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Manager *m = userdata;
+        const char *name, *p;
+        Machine *machine;
+        uint32_t uid;
+        int r;
+
+        r = sd_bus_message_read(message, "su", &name, &uid);
+        if (r < 0)
+                return r;
+
+        if (UID_IS_INVALID(uid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        p = procfs_file_alloca(machine->leader, "uid_map");
+        f = fopen(p, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                uid_t uid_base, uid_shift, uid_range, converted;
+                int k;
+
+                errno = 0;
+                k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+                if (k < 0 && feof(f))
+                        break;
+                if (k != 3) {
+                        if (ferror(f) && errno != 0)
+                                return -errno;
+
+                        return -EIO;
+                }
+
+                if (uid < uid_base || uid >= uid_base + uid_range)
+                        continue;
+
+                converted = uid - uid_base + uid_shift;
+                if (UID_IS_INVALID(converted))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+                return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
+}
+
+static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        uid_t uid;
+        Iterator i;
+        int r;
+
+        r = sd_bus_message_read(message, "u", &uid);
+        if (r < 0)
+                return r;
+        if (UID_IS_INVALID(uid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+        if (uid < 0x10000)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
+
+        HASHMAP_FOREACH(machine, m->machines, i) {
+                _cleanup_fclose_ FILE *f = NULL;
+                char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+                xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
+                f = fopen(p, "re");
+                if (!f) {
+                        log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+                        continue;
+                }
+
+                for (;;) {
+                        _cleanup_free_ char *o = NULL;
+                        uid_t uid_base, uid_shift, uid_range, converted;
+                        int k;
+
+                        errno = 0;
+                        k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+                        if (k < 0 && feof(f))
+                                break;
+                        if (k != 3) {
+                                if (ferror(f) && errno != 0)
+                                        return -errno;
+
+                                return -EIO;
+                        }
+
+                        if (uid < uid_shift || uid >= uid_shift + uid_range)
+                                continue;
+
+                        converted = (uid - uid_shift + uid_base);
+                        if (UID_IS_INVALID(converted))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+                        o = machine_bus_path(machine);
+                        if (!o)
+                                return -ENOMEM;
+
+                        return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+                }
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
+}
+
+static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Manager *m = groupdata;
+        const char *name, *p;
+        Machine *machine;
+        uint32_t gid;
+        int r;
+
+        r = sd_bus_message_read(message, "su", &name, &gid);
+        if (r < 0)
+                return r;
+
+        if (GID_IS_INVALID(gid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        p = procfs_file_alloca(machine->leader, "gid_map");
+        f = fopen(p, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                gid_t gid_base, gid_shift, gid_range, converted;
+                int k;
+
+                errno = 0;
+                k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+                if (k < 0 && feof(f))
+                        break;
+                if (k != 3) {
+                        if (ferror(f) && errno != 0)
+                                return -errno;
+
+                        return -EIO;
+                }
+
+                if (gid < gid_base || gid >= gid_base + gid_range)
+                        continue;
+
+                converted = gid - gid_base + gid_shift;
+                if (GID_IS_INVALID(converted))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+                return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
+}
+
+static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+        Manager *m = groupdata;
+        Machine *machine;
+        gid_t gid;
+        Iterator i;
+        int r;
+
+        r = sd_bus_message_read(message, "u", &gid);
+        if (r < 0)
+                return r;
+        if (GID_IS_INVALID(gid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+        if (gid < 0x10000)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
+
+        HASHMAP_FOREACH(machine, m->machines, i) {
+                _cleanup_fclose_ FILE *f = NULL;
+                char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+                xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
+                f = fopen(p, "re");
+                if (!f) {
+                        log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+                        continue;
+                }
+
+                for (;;) {
+                        _cleanup_free_ char *o = NULL;
+                        gid_t gid_base, gid_shift, gid_range, converted;
+                        int k;
+
+                        errno = 0;
+                        k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+                        if (k < 0 && feof(f))
+                                break;
+                        if (k != 3) {
+                                if (ferror(f) && errno != 0)
+                                        return -errno;
+
+                                return -EIO;
+                        }
+
+                        if (gid < gid_shift || gid >= gid_shift + gid_range)
+                                continue;
+
+                        converted = (gid - gid_shift + gid_base);
+                        if (GID_IS_INVALID(converted))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+                        o = machine_bus_path(machine);
+                        if (!o)
+                                return -ENOMEM;
+
+                        return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+                }
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
+}
+
 const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
@@ -869,6 +1094,10 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_SIGNAL("MachineNew", "so", 0),
         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
         SD_BUS_VTABLE_END
index 93aaf6a377e97dd29aa45e21f3531fc46e1eb52f..d58f01507b2e525e4f7c442aa6b6031b63e468c1 100644 (file)
                        send_interface="org.freedesktop.machine1.Manager"
                        send_member="SetImageLimit"/>
 
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="MapFromMachineUser"/>
+
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="MapToMachineUser"/>
+
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="MapFromMachineGroup"/>
+
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="MapToMachineGroup"/>
+
                 <allow send_destination="org.freedesktop.machine1"
                        send_interface="org.freedesktop.machine1.Machine"
                        send_member="GetAddresses"/>
index f712033e6c8fec5b632416820449fec78279d8eb..cdec83d074064c82c7117250c25d0f744e78582f 100644 (file)
 #include "util.h"
 #include "nss-util.h"
 #include "bus-util.h"
+#include "bus-common-errors.h"
 #include "in-addr-util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
+NSS_GETPW_PROTOTYPES(mymachines);
+NSS_GETGR_PROTOTYPES(mymachines);
 
 static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
         unsigned c = 0;
@@ -380,4 +383,319 @@ fail:
         return NSS_STATUS_UNAVAIL;
 }
 
-NSS_GETHOSTBYNAME_FALLBACKS(mymachines)
+NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
+
+enum nss_status _nss_mymachines_getpwnam_r(
+                const char *name,
+                struct passwd *pwd,
+                char *buffer, size_t buflen,
+                int *errnop) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        const char *p, *e, *machine;
+        uint32_t mapped;
+        uid_t uid;
+        size_t l;
+        int r;
+
+        assert(name);
+        assert(pwd);
+
+        p = startswith(name, "vu-");
+        if (!p)
+                goto not_found;
+
+        e = strrchr(p, '-');
+        if (!e || e == p)
+                goto not_found;
+
+        r = parse_uid(e + 1, &uid);
+        if (r < 0)
+                goto not_found;
+
+        machine = strndupa(p, e - p);
+        if (!machine_name_is_valid(machine))
+                goto not_found;
+
+        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",
+                               "MapFromMachineUser",
+                               &error,
+                               &reply,
+                               "su",
+                               machine, (uint32_t) uid);
+        if (r < 0) {
+                if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+                        goto not_found;
+
+                goto fail;
+        }
+
+        r = sd_bus_message_read(reply, "u", &mapped);
+        if (r < 0)
+                goto fail;
+
+        l = strlen(name);
+        if (buflen < l+1) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_TRYAGAIN;
+        }
+
+        memcpy(buffer, name, l+1);
+
+        pwd->pw_name = buffer;
+        pwd->pw_uid = mapped;
+        pwd->pw_gid = 65534; /* nobody */
+        pwd->pw_gecos = buffer;
+        pwd->pw_passwd = (char*) "*"; /* locked */
+        pwd->pw_dir = (char*) "/";
+        pwd->pw_shell = (char*) "/sbin/nologin";
+
+        *errnop = 0;
+        return NSS_STATUS_SUCCESS;
+
+not_found:
+        *errnop = 0;
+        return NSS_STATUS_NOTFOUND;
+
+fail:
+        *errnop = -r;
+        return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getpwuid_r(
+                uid_t uid,
+                struct passwd *pwd,
+                char *buffer, size_t buflen,
+                int *errnop) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        const char *machine, *object;
+        uint32_t mapped;
+        int r;
+
+        if (UID_IS_INVALID(uid)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        /* We consider all uids < 65536 host uids */
+        if (uid < 0x10000)
+                goto not_found;
+
+        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",
+                               "MapToMachineUser",
+                               &error,
+                               &reply,
+                               "u",
+                               (uint32_t) uid);
+        if (r < 0) {
+                if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+                        goto not_found;
+
+                goto fail;
+        }
+
+        r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+        if (r < 0)
+                goto fail;
+
+        if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_TRYAGAIN;
+        }
+
+        pwd->pw_name = buffer;
+        pwd->pw_uid = uid;
+        pwd->pw_gid = 65534; /* nobody */
+        pwd->pw_gecos = buffer;
+        pwd->pw_passwd = (char*) "*"; /* locked */
+        pwd->pw_dir = (char*) "/";
+        pwd->pw_shell = (char*) "/sbin/nologin";
+
+        *errnop = 0;
+        return NSS_STATUS_SUCCESS;
+
+not_found:
+        *errnop = 0;
+        return NSS_STATUS_NOTFOUND;
+
+fail:
+        *errnop = -r;
+        return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getgrnam_r(
+                const char *name,
+                struct group *gr,
+                char *buffer, size_t buflen,
+                int *errnop) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        const char *p, *e, *machine;
+        uint32_t mapped;
+        uid_t gid;
+        size_t l;
+        int r;
+
+        assert(name);
+        assert(gr);
+
+        p = startswith(name, "vg-");
+        if (!p)
+                goto not_found;
+
+        e = strrchr(p, '-');
+        if (!e || e == p)
+                goto not_found;
+
+        r = parse_gid(e + 1, &gid);
+        if (r < 0)
+                goto not_found;
+
+        machine = strndupa(p, e - p);
+        if (!machine_name_is_valid(machine))
+                goto not_found;
+
+        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",
+                               "MapFromMachineGroup",
+                               &error,
+                               &reply,
+                               "su",
+                               machine, (uint32_t) gid);
+        if (r < 0) {
+                if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+                        goto not_found;
+
+                goto fail;
+        }
+
+        r = sd_bus_message_read(reply, "u", &mapped);
+        if (r < 0)
+                goto fail;
+
+        l = sizeof(char*) + strlen(name) + 1;
+        if (buflen < l) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_TRYAGAIN;
+        }
+
+        memzero(buffer, sizeof(char*));
+        strcpy(buffer + sizeof(char*), name);
+
+        gr->gr_name = buffer + sizeof(char*);
+        gr->gr_gid = gid;
+        gr->gr_passwd = (char*) "*"; /* locked */
+        gr->gr_mem = (char**) buffer;
+
+        *errnop = 0;
+        return NSS_STATUS_SUCCESS;
+
+not_found:
+        *errnop = 0;
+        return NSS_STATUS_NOTFOUND;
+
+fail:
+        *errnop = -r;
+        return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getgrgid_r(
+                gid_t gid,
+                struct group *gr,
+                char *buffer, size_t buflen,
+                int *errnop) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        const char *machine, *object;
+        uint32_t mapped;
+        int r;
+
+        if (GID_IS_INVALID(gid)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        /* We consider all gids < 65536 host gids */
+        if (gid < 0x10000)
+                goto not_found;
+
+        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",
+                               "MapToMachineGroup",
+                               &error,
+                               &reply,
+                               "u",
+                               (uint32_t) gid);
+        if (r < 0) {
+                if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+                        goto not_found;
+
+                goto fail;
+        }
+
+        r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+        if (r < 0)
+                goto fail;
+
+        if (buflen < sizeof(char*) + 1) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_TRYAGAIN;
+        }
+
+        memzero(buffer, sizeof(char*));
+        if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_TRYAGAIN;
+        }
+
+        gr->gr_name = buffer + sizeof(char*);
+        gr->gr_gid = gid;
+        gr->gr_passwd = (char*) "*"; /* locked */
+        gr->gr_mem = (char**) buffer;
+
+        *errnop = 0;
+        return NSS_STATUS_SUCCESS;
+
+not_found:
+        *errnop = 0;
+        return NSS_STATUS_NOTFOUND;
+
+fail:
+        *errnop = -r;
+        return NSS_STATUS_UNAVAIL;
+}
index f80b51c1aaa0b5f0dcfa7cc0b10979041c84cde0..0728ac3ba73483357c98f5a877685858b246797b 100644 (file)
@@ -13,5 +13,9 @@ global:
         _nss_mymachines_gethostbyname2_r;
         _nss_mymachines_gethostbyname3_r;
         _nss_mymachines_gethostbyname4_r;
+        _nss_mymachines_getpwnam_r;
+        _nss_mymachines_getpwuid_r;
+        _nss_mymachines_getgrnam_r;
+        _nss_mymachines_getgrgid_r;
 local: *;
 };
index 230a98604013caefb6151fd42ce97c6df9cc5887..3657aa5d9c5693d5747236fddabdafba6f6fd259 100644 (file)
@@ -24,6 +24,9 @@
 #include <nss.h>
 #include <netdb.h>
 #include <resolv.h>
+#include <pwd.h>
+#include <grp.h>
+
 
 #define NSS_GETHOSTBYNAME_PROTOTYPES(module)            \
 enum nss_status _nss_##module##_gethostbyname4_r(       \
@@ -109,7 +112,8 @@ enum nss_status _nss_##module##_gethostbyname_r(        \
                         NULL,                           \
                         NULL);                          \
        return ret;                                      \
-}
+}                                                       \
+struct __useless_struct_to_allow_trailing_semicolon__
 
 #define NSS_GETHOSTBYADDR_FALLBACKS(module)             \
 enum nss_status _nss_##module##_gethostbyaddr_r(        \
@@ -125,4 +129,29 @@ enum nss_status _nss_##module##_gethostbyaddr_r(        \
                         buffer, buflen,                 \
                         errnop, h_errnop,               \
                         NULL);                          \
-}
+}                                                       \
+struct __useless_struct_to_allow_trailing_semicolon__
+
+#define NSS_GETPW_PROTOTYPES(module)                    \
+enum nss_status _nss_##module##_getpwnam_r(             \
+                const char *name,                       \
+                struct passwd *pwd,                     \
+                char *buffer, size_t buflen,            \
+                int *errnop) _public_;                  \
+enum nss_status _nss_mymachines_getpwuid_r(             \
+                uid_t uid,                              \
+                struct passwd *pwd,                     \
+                char *buffer, size_t buflen,            \
+                int *errnop) _public_
+
+#define NSS_GETGR_PROTOTYPES(module)                    \
+enum nss_status _nss_##module##_getgrnam_r(             \
+                const char *name,                       \
+                struct group *gr,                       \
+                char *buffer, size_t buflen,            \
+                int *errnop) _public_;                  \
+enum nss_status _nss_##module##_getgrgid_r(             \
+                gid_t gid,                              \
+                struct group *gr,                       \
+                char *buffer, size_t buflen,            \
+                int *errnop) _public_