mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
nss-mymachines: map userns users of containers to real user names
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.
This commit is contained in:
parent
43694a8cc7
commit
c01ff965b4
@ -59,21 +59,26 @@
|
||||
<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>
|
||||
@ -82,17 +87,17 @@
|
||||
<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>
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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"
|
||||
|
@ -31,12 +31,13 @@
|
||||
#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
|
||||
|
@ -112,6 +112,22 @@
|
||||
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"/>
|
||||
|
@ -28,9 +28,12 @@
|
||||
#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;
|
||||
}
|
||||
|
@ -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: *;
|
||||
};
|
||||
|
@ -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_
|
||||
|
Loading…
Reference in New Issue
Block a user