21255d
From 57d2e6e64ba490054f8de1a2aad4ffae7778eddc Mon Sep 17 00:00:00 2001
21255d
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
21255d
Date: Sun, 31 May 2020 18:21:09 +0200
21255d
Subject: [PATCH] basic/user-util: always use base 10 for user/group numbers
21255d
21255d
We would parse numbers with base prefixes as user identifiers. For example,
21255d
"0x2b3bfa0" would be interpreted as UID==45334432 and "01750" would be
21255d
interpreted as UID==1000. This parsing was used also in cases where either a
21255d
user/group name or number may be specified. This means that names like
21255d
0x2b3bfa0 would be ambiguous: they are a valid user name according to our
21255d
documented relaxed rules, but they would also be parsed as numeric uids.
21255d
21255d
This behaviour is definitely not expected by users, since tools generally only
21255d
accept decimal numbers (e.g. id, getent passwd), while other tools only accept
21255d
user names and thus will interpret such strings as user names without even
21255d
attempting to convert them to numbers (su, ssh). So let's follow suit and only
21255d
accept numbers in decimal notation. Effectively this means that we will reject
21255d
such strings as a username/uid/groupname/gid where strict mode is used, and try
21255d
to look up a user/group with such a name in relaxed mode.
21255d
21255d
Since the function changed is fairly low-level and fairly widely used, this
21255d
affects multiple tools: loginctl show-user/enable-linger/disable-linger foo',
21255d
the third argument in sysusers.d, fourth and fifth arguments in tmpfiles.d,
21255d
etc.
21255d
21255d
Fixes #15985.
21255d
21255d
(cherry picked from commit 156a5fd297b61bce31630d7a52c15614bf784843)
21255d
21255d
Resolves: #1848373
21255d
---
21255d
 src/basic/parse-util.h    |  8 ++++++--
21255d
 src/basic/user-util.c     |  2 +-
21255d
 src/test/test-user-util.c | 10 ++++++++++
21255d
 3 files changed, 17 insertions(+), 3 deletions(-)
21255d
21255d
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
21255d
index f3267f4cfe..1fc1af7615 100644
21255d
--- a/src/basic/parse-util.h
21255d
+++ b/src/basic/parse-util.h
21255d
@@ -50,9 +50,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
21255d
 
21255d
 int safe_atoi16(const char *s, int16_t *ret);
21255d
 
21255d
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
21255d
+static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
21255d
         assert_cc(sizeof(uint32_t) == sizeof(unsigned));
21255d
-        return safe_atou(s, (unsigned*) ret_u);
21255d
+        return safe_atou_full(s, base, (unsigned*) ret_u);
21255d
+}
21255d
+
21255d
+static inline int safe_atou32(const char *s, uint32_t *ret_u) {
21255d
+        return safe_atou32_full(s, 0, (unsigned*) ret_u);
21255d
 }
21255d
 
21255d
 static inline int safe_atoi32(const char *s, int32_t *ret_i) {
21255d
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
21255d
index d92969c966..10eeb256cd 100644
21255d
--- a/src/basic/user-util.c
21255d
+++ b/src/basic/user-util.c
21255d
@@ -49,7 +49,7 @@ int parse_uid(const char *s, uid_t *ret) {
21255d
         assert(s);
21255d
 
21255d
         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
21255d
-        r = safe_atou32(s, &uid);
21255d
+        r = safe_atou32_full(s, 10, &uid);
21255d
         if (r < 0)
21255d
                 return r;
21255d
 
21255d
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
21255d
index 9114d30b8c..8bf3dcd567 100644
21255d
--- a/src/test/test-user-util.c
21255d
+++ b/src/test/test-user-util.c
21255d
@@ -46,9 +46,19 @@ static void test_parse_uid(void) {
21255d
 
21255d
         r = parse_uid("65535", &uid);
21255d
         assert_se(r == -ENXIO);
21255d
+        assert_se(uid == 100);
21255d
+
21255d
+        r = parse_uid("0x1234", &uid);
21255d
+        assert_se(r == -EINVAL);
21255d
+        assert_se(uid == 100);
21255d
+
21255d
+        r = parse_uid("01234", &uid);
21255d
+        assert_se(r == 0);
21255d
+        assert_se(uid == 1234);
21255d
 
21255d
         r = parse_uid("asdsdas", &uid);
21255d
         assert_se(r == -EINVAL);
21255d
+        assert_se(uid == 1234);
21255d
 }
21255d
 
21255d
 static void test_uid_ptr(void) {