From: Lennart Poettering Date: Thu, 6 Aug 2020 14:46:18 +0000 (+0200) Subject: user-util: add mangle_gecos() call for turning strings into fields suitable as GECOS... X-Git-Tag: v247-rc1~439^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b10fd796f56e4f16f7430cd22f59f544766d3bef;p=thirdparty%2Fsystemd.git user-util: add mangle_gecos() call for turning strings into fields suitable as GECOS fields --- diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 8115065b5ec..0e96a75797a 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -863,6 +863,37 @@ bool valid_gecos(const char *d) { return true; } +char *mangle_gecos(const char *d) { + char *mangled; + + /* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's + * putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid + * UTF-8 */ + + mangled = strdup(d); + if (!mangled) + return NULL; + + for (char *i = mangled; *i; i++) { + int len; + + if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') { + *i = ' '; + continue; + } + + len = utf8_encoded_valid_unichar(i, (size_t) -1); + if (len < 0) { + *i = ' '; + continue; + } + + i += len - 1; + } + + return mangled; +} + bool valid_home(const char *p) { /* Note that this function is also called by valid_shell(), any * changes must account for that. */ diff --git a/src/basic/user-util.h b/src/basic/user-util.h index 1f267d21a3f..7c142dd1e66 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -105,6 +105,7 @@ typedef enum ValidUserFlags { bool valid_user_group_name(const char *u, ValidUserFlags flags); bool valid_gecos(const char *d); +char *mangle_gecos(const char *d); bool valid_home(const char *p); static inline bool valid_shell(const char *p) { diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index c9bff941be1..306d08a2824 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -452,6 +452,25 @@ static void test_parse_uid_range(void) { assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5); } +static void test_mangle_gecos_one(const char *input, const char *expected) { + _cleanup_free_ char *p = NULL; + + assert_se(p = mangle_gecos(input)); + assert_se(streq(p, expected)); + assert_se(valid_gecos(p)); +} + +static void test_mangle_gecos(void) { + test_mangle_gecos_one("", ""); + test_mangle_gecos_one("root", "root"); + test_mangle_gecos_one("wuff\nwuff", "wuff wuff"); + test_mangle_gecos_one("wuff:wuff", "wuff wuff"); + test_mangle_gecos_one("wuff\r\n:wuff", "wuff wuff"); + test_mangle_gecos_one("\n--wüff-wäff-wöff::", " --wüff-wäff-wöff "); + test_mangle_gecos_one("\xc3\x28", " ("); + test_mangle_gecos_one("\xe2\x28\xa1", " ( "); +} + int main(int argc, char *argv[]) { test_uid_to_name_one(0, "root"); test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME); @@ -482,6 +501,7 @@ int main(int argc, char *argv[]) { test_valid_user_group_name_or_numeric_relaxed(); test_valid_user_group_name_or_numeric(); test_valid_gecos(); + test_mangle_gecos(); test_valid_home(); test_make_salt();