#include <string.h>
#include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "format-util.h"
#include "macro.h"
+#include "path-util.h"
#include "sort-util.h"
+#include "stat-util.h"
#include "uid-range.h"
#include "user-util.h"
return false;
}
+
+int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ /* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
+ * the specified file (which can be either uid_map or gid_map, in case caller needs to deal with GID
+ * maps).
+ *
+ * To simplify things this will modify the passed array in case of later failure. */
+
+ if (!path)
+ path = "/proc/self/uid_map";
+
+ f = fopen(path, "re");
+ if (!f) {
+ r = -errno;
+
+ if (r == -ENOENT && path_startswith(path, "/proc/") && proc_mounted() > 0)
+ return -EOPNOTSUPP;
+
+ return r;
+ }
+
+ for (;;) {
+ uid_t uid_base, uid_shift, uid_range;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
+ if (k == EOF) {
+ if (ferror(f))
+ return errno_or_else(EIO);
+
+ return 0;
+ }
+ if (k != 3)
+ return -EBADMSG;
+
+ r = uid_range_add(p, n, uid_base, uid_range);
+ if (r < 0)
+ return r;
+ }
+}
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
bool uid_range_contains(const UidRange *p, size_t n, uid_t uid);
+
+int uid_range_load_userns(UidRange **p, size_t *n, const char *path);
#include <stddef.h>
#include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "tests.h"
+#include "tmpfile-util.h"
#include "uid-range.h"
#include "user-util.h"
#include "util.h"
+#include "virt.h"
TEST(uid_range) {
_cleanup_free_ UidRange *p = NULL;
assert_se(p[0].nr == 1983);
}
+TEST(load_userns) {
+ _cleanup_(unlink_and_freep) char *fn = NULL;
+ _cleanup_free_ UidRange *p = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ size_t n = 0;
+ int r;
+
+ r = uid_range_load_userns(&p, &n, NULL);
+ if (ERRNO_IS_NOT_SUPPORTED(r))
+ return;
+
+ assert_se(r >= 0);
+ assert_se(uid_range_contains(p, n, getuid()));
+
+ r = running_in_userns();
+ if (r == 0) {
+ assert_se(n == 1);
+ assert_se(p[0].start == 0);
+ assert_se(p[0].nr == UINT32_MAX);
+ }
+
+ assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
+ fputs("0 0 20\n"
+ "100 0 20\n", f);
+ assert_se(fflush_and_check(f) >= 0);
+
+ p = mfree(p);
+ n = 0;
+
+ assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
+
+ assert_se(uid_range_contains(p, n, 0));
+ assert_se(uid_range_contains(p, n, 19));
+ assert_se(!uid_range_contains(p, n, 20));
+
+ assert_se(!uid_range_contains(p, n, 99));
+ assert_se(uid_range_contains(p, n, 100));
+ assert_se(uid_range_contains(p, n, 119));
+ assert_se(!uid_range_contains(p, n, 120));
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);