1
0
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:
Lennart Poettering 2015-07-09 14:46:20 -03:00
parent 43694a8cc7
commit c01ff965b4
8 changed files with 635 additions and 19 deletions

View File

@ -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>

View 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) \

View 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"

View File

@ -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

View File

@ -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"/>

View File

@ -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;
}

View 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: *;
};

View 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_