summaryrefslogtreecommitdiff
path: root/src/userdb
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-03-31 15:22:33 +0200
committerLennart Poettering <lennart@poettering.net>2022-04-01 11:21:44 +0200
commit9cce7fb193e5b12dee091ff7023669ef9034c1c0 (patch)
tree67bf963e73944e5c3ead62ed48424ad9b80ca5c5 /src/userdb
parent49888d31b6ccb3c16e9564049290f1d21df15abf (diff)
downloadsystemd-9cce7fb193e5b12dee091ff7023669ef9034c1c0.tar.gz
userdbctl: also show available UID range in current userns
Containers generally have a smaller UID range assigned than host systems. Let's visualize this in the user/group tables. We insert markers for unavailable regions. This way display is identical to status quo ante on host systems, but in containers unavailable ranges will be shown as that. And while we are at it, also hide well-known UID ranges when they are outside of userns uid_map range. This is mostly about the "container" range. It's pointless showing the cotnainer range (i.e. a range UID > 65535) if that range isn#t available in the container anyway.
Diffstat (limited to 'src/userdb')
-rw-r--r--src/userdb/userdbctl.c220
1 files changed, 206 insertions, 14 deletions
diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c
index c3d61f0059..b299bb8e11 100644
--- a/src/userdb/userdbctl.c
+++ b/src/userdb/userdbctl.c
@@ -17,6 +17,7 @@
#include "socket-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "uid-range.h"
#include "user-record-show.h"
#include "user-util.h"
#include "userdb.h"
@@ -167,14 +168,22 @@ static const struct {
},
};
-static int table_add_uid_boundaries(Table *table) {
+static int table_add_uid_boundaries(
+ Table *table,
+ const UidRange *p,
+ size_t n) {
int r;
assert(table);
+ assert(p || n == 0);
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
_cleanup_free_ char *name = NULL, *comment = NULL;
+ if (n > 0 &&
+ !uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
+ continue;
+
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", uid_range_table[i].name, " users ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@@ -199,7 +208,7 @@ static int table_add_uid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_EMPTY,
- TABLE_INT, -1); /* sort before an other entry with the same UID */
+ TABLE_INT, -1); /* sort before any other entry with the same UID */
if (r < 0)
return table_log_add_error(r);
@@ -229,7 +238,7 @@ static int table_add_uid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_EMPTY,
- TABLE_INT, 1); /* sort after an other entry with the same UID */
+ TABLE_INT, 1); /* sort after any other entry with the same UID */
if (r < 0)
return table_log_add_error(r);
}
@@ -237,6 +246,104 @@ static int table_add_uid_boundaries(Table *table) {
return ELEMENTSOF(uid_range_table) * 2;
}
+static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
+ _cleanup_free_ char *name = NULL;
+ int r;
+
+ assert(table);
+ assert(start <= end);
+
+ name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
+ " begin unavailable users ",
+ special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
+ if (!name)
+ return log_oom();
+
+ r = table_add_many(
+ table,
+ TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP),
+ TABLE_STRING, name,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_UID, start,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_STRING, "First unavailable user",
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_EMPTY,
+ TABLE_INT, -1); /* sort before an other entry with the same UID */
+ if (r < 0)
+ return table_log_add_error(r);
+
+ free(name);
+ name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
+ " end unavailable users ",
+ special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
+ if (!name)
+ return log_oom();
+
+ r = table_add_many(
+ table,
+ TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
+ TABLE_STRING, name,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_UID, end,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_STRING, "Last unavailable user",
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_EMPTY,
+ TABLE_INT, 1); /* sort after any other entry with the same UID */
+ if (r < 0)
+ return table_log_add_error(r);
+
+ return 2;
+}
+
+static int table_add_uid_map(
+ Table *table,
+ const UidRange *p,
+ size_t n,
+ int (*add_unavailable)(Table *t, uid_t start, uid_t end)) {
+
+ uid_t focus = 0;
+ int n_added = 0, r;
+
+ assert(table);
+ assert(p || n == 0);
+ assert(add_unavailable);
+
+ for (size_t i = 0; i < n; i++) {
+ if (focus < p[i].start) {
+ r = add_unavailable(table, focus, p[i].start-1);
+ if (r < 0)
+ return r;
+
+ n_added += r;
+ }
+
+ if (p[i].start > UINT32_MAX - p[i].nr) { /* overflow check */
+ focus = UINT32_MAX;
+ break;
+ }
+
+ focus = p[i].start + p[i].nr;
+ }
+
+ if (focus < UINT32_MAX-1) {
+ r = add_unavailable(table, focus, UINT32_MAX-1);
+ if (r < 0)
+ return r;
+
+ n_added += r;
+ }
+
+ return n_added;
+}
+
static int display_user(int argc, char *argv[], void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL;
bool draw_separator = false;
@@ -322,12 +429,22 @@ static int display_user(int argc, char *argv[], void *userdata) {
}
if (table) {
- int boundary_lines;
+ _cleanup_free_ UidRange *uid_range = NULL;
+ int boundary_lines, uid_map_lines;
+ size_t n_uid_range;
+
+ r = uid_range_load_userns(&uid_range, &n_uid_range, "/proc/self/uid_map");
+ if (r < 0)
+ log_debug_errno(r, "Failed to load /proc/self/uid_map, ignoring: %m");
- boundary_lines = table_add_uid_boundaries(table);
+ boundary_lines = table_add_uid_boundaries(table, uid_range, n_uid_range);
if (boundary_lines < 0)
return boundary_lines;
+ uid_map_lines = table_add_uid_map(table, uid_range, n_uid_range, add_unavailable_uid);
+ if (uid_map_lines < 0)
+ return uid_map_lines;
+
if (table_get_rows(table) > 1) {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
@@ -335,8 +452,11 @@ static int display_user(int argc, char *argv[], void *userdata) {
}
if (arg_legend) {
- if (table_get_rows(table) > 1)
- printf("\n%zu users listed.\n", table_get_rows(table) - 1 - boundary_lines);
+ size_t k;
+
+ k = table_get_rows(table) - 1 - boundary_lines - uid_map_lines;
+ if (k > 0)
+ printf("\n%zu users listed.\n", k);
else
printf("No users.\n");
}
@@ -411,14 +531,22 @@ static int show_group(GroupRecord *gr, Table *table) {
return 0;
}
-static int table_add_gid_boundaries(Table *table) {
+static int table_add_gid_boundaries(
+ Table *table,
+ const UidRange *p,
+ size_t n) {
int r;
assert(table);
+ assert(p || n == 0);
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
_cleanup_free_ char *name = NULL, *comment = NULL;
+ if (n > 0 &&
+ !uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last))
+ continue;
+
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", uid_range_table[i].name, " groups ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@@ -440,7 +568,7 @@ static int table_add_gid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, comment,
TABLE_SET_COLOR, ansi_grey(),
- TABLE_INT, -1); /* sort before an other entry with the same GID */
+ TABLE_INT, -1); /* sort before any other entry with the same GID */
if (r < 0)
return table_log_add_error(r);
@@ -467,7 +595,7 @@ static int table_add_gid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, comment,
TABLE_SET_COLOR, ansi_grey(),
- TABLE_INT, 1); /* sort after an other entry with the same GID */
+ TABLE_INT, 1); /* sort after any other entry with the same GID */
if (r < 0)
return table_log_add_error(r);
}
@@ -475,6 +603,57 @@ static int table_add_gid_boundaries(Table *table) {
return ELEMENTSOF(uid_range_table) * 2;
}
+static int add_unavailable_gid(Table *table, uid_t start, uid_t end) {
+ _cleanup_free_ char *name = NULL;
+ int r;
+
+ assert(table);
+ assert(start <= end);
+
+ name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
+ " begin unavailable groups ",
+ special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
+ if (!name)
+ return log_oom();
+
+ r = table_add_many(
+ table,
+ TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP),
+ TABLE_STRING, name,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_GID, start,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_STRING, "First unavailable group",
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_INT, -1); /* sort before any other entry with the same GID */
+ if (r < 0)
+ return table_log_add_error(r);
+
+ free(name);
+ name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
+ " end unavailable groups ",
+ special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
+ if (!name)
+ return log_oom();
+
+ r = table_add_many(
+ table,
+ TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
+ TABLE_STRING, name,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_EMPTY,
+ TABLE_GID, end,
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_STRING, "Last unavailable group",
+ TABLE_SET_COLOR, ansi_grey(),
+ TABLE_INT, 1); /* sort after any other entry with the same GID */
+ if (r < 0)
+ return table_log_add_error(r);
+
+ return 2;
+}
+
static int display_group(int argc, char *argv[], void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL;
bool draw_separator = false;
@@ -559,12 +738,22 @@ static int display_group(int argc, char *argv[], void *userdata) {
}
if (table) {
- int boundary_lines;
+ _cleanup_free_ UidRange *gid_range = NULL;
+ int boundary_lines, gid_map_lines;
+ size_t n_gid_range;
+
+ r = uid_range_load_userns(&gid_range, &n_gid_range, "/proc/self/gid_map");
+ if (r < 0)
+ log_debug_errno(r, "Failed to load /proc/self/gid_map, ignoring: %m");
- boundary_lines = table_add_gid_boundaries(table);
+ boundary_lines = table_add_gid_boundaries(table, gid_range, n_gid_range);
if (boundary_lines < 0)
return boundary_lines;
+ gid_map_lines = table_add_uid_map(table, gid_range, n_gid_range, add_unavailable_gid);
+ if (gid_map_lines < 0)
+ return gid_map_lines;
+
if (table_get_rows(table) > 1) {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
@@ -572,8 +761,11 @@ static int display_group(int argc, char *argv[], void *userdata) {
}
if (arg_legend) {
- if (table_get_rows(table) > 1)
- printf("\n%zu groups listed.\n", table_get_rows(table) - 1 - boundary_lines);
+ size_t k;
+
+ k = table_get_rows(table) - 1 - boundary_lines - gid_map_lines;
+ if (k > 0)
+ printf("\n%zu groups listed.\n", k);
else
printf("No groups.\n");
}