subids: support nsswitch

Closes #154

When starting any operation to do with subuid delegation, check
nsswitch for a module to use.  If none is specified, then use
the traditional /etc/subuid and /etc/subgid files.

Currently only one module is supported, and there is no fallback
to the files on errors.  Several possibilities could be considered:

1. in case of connection error, fall back to files
2. in case of unknown user, also fall back to files

etc...

When non-files nss module is used, functions to edit the range
are not supported.  It may make sense to support it, but it also
may make sense to require another tool to be used.

libsubordinateio also uses the nss_ helpers.  This is how for instance
lxc could easily be converted to supporting nsswitch.

Add a set of test cases, including a dummy libsubid_zzz module.  This
hardcodes values such that:

'ubuntu' gets 200000 - 300000
'user1' gets 100000 - 165536
'error' emulates an nss module error
'unknown' emulates a user unknown to the nss module
'conn' emulates a connection error ot the nss module

Changes to libsubid:

Change the list_owner_ranges api: return a count instead of making the array
null terminated.

This is a breaking change, so bump the libsubid abi major number.

Rename free_subuid_range and free_subgid_range to ungrant_subuid_range,
because otherwise it's confusing with free_subid_ranges which frees
    memory.

Run libsubid tests in jenkins

Switch argument order in find_subid_owners

Move the db locking into subordinateio.c

Signed-off-by: Serge Hallyn <serge@hallyn.com>
This commit is contained in:
Serge Hallyn
2021-01-31 17:38:20 -06:00
parent 514c1328b6
commit 8492dee663
26 changed files with 935 additions and 205 deletions

View File

@ -38,132 +38,48 @@
#include "idmapping.h"
#include "api.h"
static struct subordinate_range **get_subid_ranges(const char *owner, enum subid_type id_type)
static
int get_subid_ranges(const char *owner, enum subid_type id_type, struct subordinate_range ***ranges)
{
struct subordinate_range **ranges = NULL;
switch (id_type) {
case ID_TYPE_UID:
if (!sub_uid_open(O_RDONLY)) {
return NULL;
}
break;
case ID_TYPE_GID:
if (!sub_gid_open(O_RDONLY)) {
return NULL;
}
break;
default:
return NULL;
}
ranges = list_owner_ranges(owner, id_type);
if (id_type == ID_TYPE_UID)
sub_uid_close();
else
sub_gid_close();
return ranges;
return list_owner_ranges(owner, id_type, ranges);
}
struct subordinate_range **get_subuid_ranges(const char *owner)
int get_subuid_ranges(const char *owner, struct subordinate_range ***ranges)
{
return get_subid_ranges(owner, ID_TYPE_UID);
return get_subid_ranges(owner, ID_TYPE_UID, ranges);
}
struct subordinate_range **get_subgid_ranges(const char *owner)
int get_subgid_ranges(const char *owner, struct subordinate_range ***ranges)
{
return get_subid_ranges(owner, ID_TYPE_GID);
return get_subid_ranges(owner, ID_TYPE_GID, ranges);
}
void subid_free_ranges(struct subordinate_range **ranges)
void subid_free_ranges(struct subordinate_range **ranges, int count)
{
return free_subordinate_ranges(ranges);
return free_subordinate_ranges(ranges, count);
}
int get_subid_owner(unsigned long id, uid_t **owner, enum subid_type id_type)
static
int get_subid_owner(unsigned long id, enum subid_type id_type, uid_t **owner)
{
int ret = -1;
switch (id_type) {
case ID_TYPE_UID:
if (!sub_uid_open(O_RDONLY)) {
return -1;
}
break;
case ID_TYPE_GID:
if (!sub_gid_open(O_RDONLY)) {
return -1;
}
break;
default:
return -1;
}
ret = find_subid_owners(id, owner, id_type);
if (id_type == ID_TYPE_UID)
sub_uid_close();
else
sub_gid_close();
return ret;
return find_subid_owners(id, id_type, owner);
}
int get_subuid_owners(uid_t uid, uid_t **owner)
{
return get_subid_owner((unsigned long)uid, owner, ID_TYPE_UID);
return get_subid_owner((unsigned long)uid, ID_TYPE_UID, owner);
}
int get_subgid_owners(gid_t gid, uid_t **owner)
{
return get_subid_owner((unsigned long)gid, owner, ID_TYPE_GID);
return get_subid_owner((unsigned long)gid, ID_TYPE_GID, owner);
}
static
bool grant_subid_range(struct subordinate_range *range, bool reuse,
enum subid_type id_type)
{
bool ret;
switch (id_type) {
case ID_TYPE_UID:
if (!sub_uid_lock()) {
printf("Failed loging subuids (errno %d)\n", errno);
return false;
}
if (!sub_uid_open(O_CREAT | O_RDWR)) {
printf("Failed opening subuids (errno %d)\n", errno);
sub_uid_unlock();
return false;
}
break;
case ID_TYPE_GID:
if (!sub_gid_lock()) {
printf("Failed loging subgids (errno %d)\n", errno);
return false;
}
if (!sub_gid_open(O_CREAT | O_RDWR)) {
printf("Failed opening subgids (errno %d)\n", errno);
sub_gid_unlock();
return false;
}
break;
default:
return false;
}
ret = new_subid_range(range, id_type, reuse);
if (id_type == ID_TYPE_UID) {
sub_uid_close();
sub_uid_unlock();
} else {
sub_gid_close();
sub_gid_unlock();
}
return ret;
return new_subid_range(range, id_type, reuse);
}
bool grant_subuid_range(struct subordinate_range *range, bool reuse)
@ -176,56 +92,18 @@ bool grant_subgid_range(struct subordinate_range *range, bool reuse)
return grant_subid_range(range, reuse, ID_TYPE_GID);
}
bool free_subid_range(struct subordinate_range *range, enum subid_type id_type)
static
bool ungrant_subid_range(struct subordinate_range *range, enum subid_type id_type)
{
bool ret;
switch (id_type) {
case ID_TYPE_UID:
if (!sub_uid_lock()) {
printf("Failed loging subuids (errno %d)\n", errno);
return false;
}
if (!sub_uid_open(O_CREAT | O_RDWR)) {
printf("Failed opening subuids (errno %d)\n", errno);
sub_uid_unlock();
return false;
}
break;
case ID_TYPE_GID:
if (!sub_gid_lock()) {
printf("Failed loging subgids (errno %d)\n", errno);
return false;
}
if (!sub_gid_open(O_CREAT | O_RDWR)) {
printf("Failed opening subgids (errno %d)\n", errno);
sub_gid_unlock();
return false;
}
break;
default:
return false;
}
ret = release_subid_range(range, id_type);
if (id_type == ID_TYPE_UID) {
sub_uid_close();
sub_uid_unlock();
} else {
sub_gid_close();
sub_gid_unlock();
}
return ret;
return release_subid_range(range, id_type);
}
bool free_subuid_range(struct subordinate_range *range)
bool ungrant_subuid_range(struct subordinate_range *range)
{
return free_subid_range(range, ID_TYPE_UID);
return ungrant_subid_range(range, ID_TYPE_UID);
}
bool free_subgid_range(struct subordinate_range *range)
bool ungrant_subgid_range(struct subordinate_range *range)
{
return free_subid_range(range, ID_TYPE_GID);
return ungrant_subid_range(range, ID_TYPE_GID);
}