Skip to content

Commit

Permalink
Create a new libsubid
Browse files Browse the repository at this point in the history
Closes #154

Currently this has three functions: one which returns the
list of subuid ranges for a user, one returning the subgids,
and one which frees the ranges lists.

I might be mistaken about what -disable-man means;  some of
the code suggests it means just don't re-generate them, but
not totally ignore them.  But that doesn't seem to really work,
so let's just ignore man/ when -disable-man.

Remove --disable-shared.  I'm not sure why it was there, but it stems
from long, long ago, and I suspect it comes from some ancient
toolchain bug.

Create a tests/run_some, a shorter version of run_all.  I'll
slowly add tests to this as I verify they work, then I can
work on fixing the once which don't.

Also, don't touch man/ if not -enable-man.

Changelog:
	Apr 22: change the subid list api as recomended by Dan Walsh.
	Apr 23: implement get_subid_owner
	Apr 24: implement range add/release
	Apr 25: finish tests and rebase
	May 10: make @owner const

Signed-off-by: Serge Hallyn <serge@hallyn.com>
  • Loading branch information
hallyn committed Jun 7, 2020
1 parent 43a917c commit 0a7888b
Show file tree
Hide file tree
Showing 31 changed files with 1,105 additions and 17 deletions.
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ arch:

before_install:
- sudo apt-get update -qq
- sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext
- sudo apt-get -y install -qq automake autopoint xsltproc libselinux1-dev gettext expect
script:
- ./autogen.sh --without-selinux --disable-man
- grep ENABLE_ config.status
Expand All @@ -38,4 +38,14 @@ addons:
build_command: "make -j4"
branch_pattern: master

script:
- cat /proc/self/uid_map
- cat /proc/self/status
- systemd-detect-virt
- ./autogen.sh --without-selinux --disable-man
- grep ENABLE_ config.status
- make
- sudo make install
- (cd tests; sudo ./run_some; cat testsuite.log)

# vim:et:ts=2:sw=2
13 changes: 11 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@

EXTRA_DIST = NEWS README TODO shadow.spec.in

SUBDIRS = po man libmisc lib src \
contrib doc etc
SUBDIRS = libmisc lib

if ENABLE_SUBIDS
SUBDIRS += libsubid
endif

SUBDIRS += src po contrib doc etc

if ENABLE_REGENERATE_MAN
SUBDIRS += man
endif
2 changes: 1 addition & 1 deletion autogen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ autoreconf -v -f --install || exit 1
CFLAGS="-O2 -Wall" \
--enable-man \
--enable-maintainer-mode \
--disable-shared \
--enable-shared \
--without-libpam \
--with-selinux \
"$@"
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ test "$prefix" = "/usr" && exec_prefix=""

AC_GNU_SOURCE

AM_DISABLE_SHARED
AM_ENABLE_STATIC
AM_ENABLE_SHARED

AM_MAINTAINER_MODE

Expand Down Expand Up @@ -725,6 +725,7 @@ AC_CONFIG_FILES([
man/zh_TW/Makefile
libmisc/Makefile
lib/Makefile
libsubid/Makefile
src/Makefile
contrib/Makefile
etc/Makefile
Expand Down
204 changes: 192 additions & 12 deletions lib/subordinateio.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@
#include "subordinateio.h"
#include <sys/types.h>
#include <pwd.h>

struct subordinate_range {
const char *owner;
unsigned long start;
unsigned long count;
};

#define NFIELDS 3
#include <ctype.h>

/*
* subordinate_dup: create a duplicate range
Expand Down Expand Up @@ -78,7 +71,7 @@ static void *subordinate_parse (const char *line)
static char rangebuf[1024];
int i;
char *cp;
char *fields[NFIELDS];
char *fields[SUBID_NFIELDS];

/*
* Copy the string to a temporary buffer so the substrings can
Expand All @@ -93,7 +86,7 @@ static void *subordinate_parse (const char *line)
* field. The fields are converted into NUL terminated strings.
*/

for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
for (cp = rangebuf, i = 0; (i < SUBID_NFIELDS) && (NULL != cp); i++) {
fields[i] = cp;
while (('\0' != *cp) && (':' != *cp)) {
cp++;
Expand All @@ -108,10 +101,10 @@ static void *subordinate_parse (const char *line)
}

/*
* There must be exactly NFIELDS colon separated fields or
* There must be exactly SUBID_NFIELDS colon separated fields or
* the entry is invalid. Also, fields must be non-blank.
*/
if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
if (i != SUBID_NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
return NULL;
range.owner = fields[0];
if (getulong (fields[1], &range.start) == 0)
Expand Down Expand Up @@ -314,6 +307,39 @@ static bool have_range(struct commonio_db *db,
return false;
}

static bool append_range(struct subordinate_range ***ranges, const struct subordinate_range *new, int n)
{
struct subordinate_range *tmp;
if (!*ranges) {
*ranges = malloc(2 * sizeof(struct subordinate_range **));
if (!*ranges)
return false;
} else {
struct subordinate_range **new;
new = realloc(*ranges, (n + 2) * (sizeof(struct subordinate_range **)));
if (!new)
return false;
*ranges = new;
}
(*ranges)[n] = (*ranges)[n+1] = NULL;
tmp = subordinate_dup(new);
if (!tmp)
return false;
(*ranges)[n] = tmp;
return true;
}

void free_subordinate_ranges(struct subordinate_range **ranges)
{
int i;

if (!ranges)
return;
for (i = 0; ranges[i]; i++)
subordinate_free(ranges[i]);
free(ranges);
}

/*
* subordinate_range_cmp: compare uid ranges
*
Expand Down Expand Up @@ -692,6 +718,160 @@ gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count)
start = find_free_range (&subordinate_gid_db, min, max, count);
return start == ULONG_MAX ? (gid_t) -1 : start;
}

/*
struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type)
*
* @owner: username
* @id_type: UID or GUID
*
* Returns the subuid or subgid ranges which are owned by the specified
* user. Username may be a username or a string representation of a
* UID number. If id_type is UID, then subuids are returned, else
* subgids are returned. If there is an error, < 0 is returned.
*
* The caller must free the subordinate range list.
*/
struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type)
{
// TODO - need to handle owner being either uid or username
const struct subordinate_range *range;
struct subordinate_range **ranges = NULL;
struct commonio_db *db;
int size = 0;

if (id_type == ID_TYPE_UID)
db = &subordinate_uid_db;
else
db = &subordinate_gid_db;

commonio_rewind(db);
while ((range = commonio_next(db)) != NULL) {
if (0 == strcmp(range->owner, owner)) {
if (!append_range(&ranges, range, size++)) {
free_subordinate_ranges(ranges);
return NULL;
}
}
}

return ranges;
}

static bool all_digits(const char *str)
{
int i;

for (i = 0; str[i] != '\0'; i++)
if (!isdigit(str[i]))
return false;
return true;
}

static int append_uids(uid_t **uids, const char *owner, int n)
{
uid_t owner_uid;
uid_t *ret;
int i;

if (all_digits(owner)) {
i = sscanf(owner, "%d", &owner_uid);
if (i != 1) {
// should not happen
free(*uids);
*uids = NULL;
return -1;
}
} else {
struct passwd *pwd = getpwnam(owner);
if (NULL == pwd) {
/* Username not defined in /etc/passwd, or error occured during lookup */
free(*uids);
*uids = NULL;
return -1;
}
owner_uid = pwd->pw_uid;
}

for (i = 0; i < n; i++) {
if (owner_uid == (*uids)[i])
return n;
}

ret = realloc(*uids, (n + 1) * sizeof(uid_t));
if (!ret) {
free(*uids);
return -1;
}
ret[n] = owner_uid;
*uids = ret;
return n+1;
}

int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type)
{
const struct subordinate_range *range;
struct commonio_db *db;
int n = 0;

*uids = NULL;
if (id_type == ID_TYPE_UID)
db = &subordinate_uid_db;
else
db = &subordinate_gid_db;

commonio_rewind(db);
while ((range = commonio_next(db)) != NULL) {
if (id >= range->start && id < range->start + range-> count) {
n = append_uids(uids, range->owner, n);
if (n < 0)
break;
}
}

return n;
}

bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse)
{
struct commonio_db *db;
const struct subordinate_range *r;

if (id_type == ID_TYPE_UID)
db = &subordinate_uid_db;
else
db = &subordinate_gid_db;
commonio_rewind(db);
if (reuse) {
while ((r = commonio_next(db)) != NULL) {
// TODO account for username vs uid_t
if (0 != strcmp(r->owner, range->owner))
continue;
if (r->count >= range->count) {
range->count = r->count;
range->start = r->start;
return true;
}
}
}

range->start = find_free_range(db, range->start, ULONG_MAX, range->count);
if (range->start == ULONG_MAX)
return false;

return add_range(db, range->owner, range->start, range->count) == 1;
}

bool release_subid_range(struct subordinate_range *range, enum subid_type id_type)
{
struct commonio_db *db;
if (id_type == ID_TYPE_UID)
db = &subordinate_uid_db;
else
db = &subordinate_gid_db;
return remove_range(db, range->owner, range->start, range->count) == 1;
}

#else /* !ENABLE_SUBIDS */
extern int errno; /* warning: ANSI C forbids an empty source file */
#endif /* !ENABLE_SUBIDS */
Expand Down
7 changes: 7 additions & 0 deletions lib/subordinateio.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <sys/types.h>

#include "../libsubid/subid.h"

extern int sub_uid_close(void);
extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
extern bool sub_uid_file_present (void);
Expand All @@ -23,6 +25,11 @@ extern int sub_uid_unlock (void);
extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
extern struct subordinate_range **list_owner_ranges(const char *owner, enum subid_type id_type);
extern bool new_subid_range(struct subordinate_range *range, enum subid_type id_type, bool reuse);
extern bool release_subid_range(struct subordinate_range *range, enum subid_type id_type);
extern int find_subid_owners(unsigned long id, uid_t **uids, enum subid_type id_type);
extern void free_subordinate_ranges(struct subordinate_range **ranges);

extern int sub_gid_close(void);
extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
Expand Down
25 changes: 25 additions & 0 deletions libsubid/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
lib_LTLIBRARIES = libsubid.la
libsubid_la_LDFLAGS = -Wl,-soname,libsubid.so.@LIBSUBID_ABI@ \
-shared -version-info @LIBSUBID_ABI_MAJOR@
libsubid_la_SOURCES = api.c

MISCLIBS = \
$(LIBAUDIT) \
$(LIBSELINUX) \
$(LIBSEMANAGE) \
$(LIBCRYPT_NOPAM) \
$(LIBSKEY) \
$(LIBMD) \
$(LIBECONF) \
$(LIBCRYPT) \
$(LIBTCB)

libsubid_la_LIBADD = \
$(top_srcdir)/lib/libshadow.la \
$(top_srcdir)/libmisc/libmisc.a \
$(MISCLIBS)

AM_CPPFLAGS = \
-I${top_srcdir}/lib \
-I${top_srcdir}/libmisc \
-DLOCALEDIR=\"$(datadir)/locale\"
Loading

0 comments on commit 0a7888b

Please sign in to comment.