From 1c5acb5f1f70c67ad24f549f5b01329a98a80170 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Mon, 23 Dec 2024 11:06:33 +0100 Subject: [PATCH] lib/chkname.c, src/: Strictly disallow really bad names Some names are bad, and some names are really bad. '--badname' should only allow the mildly bad ones, which we can handle. Some names are too bad, and it's not possible to deal with them. Reject them unconditionally. Cc: Chris Hofstaedtler Cc: Marc 'Zugschlus' Haber Cc: Iker Pedrosa Cc: Serge Hallyn Signed-off-by: Alejandro Colomar --- lib/chkname.c | 36 ++++++++++++++++++------------------ src/newusers.c | 2 +- src/pwck.c | 2 +- src/useradd.c | 2 +- src/usermod.c | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/chkname.c b/lib/chkname.c index c2b46d2a2..43a650bd3 100644 --- a/lib/chkname.c +++ b/lib/chkname.c @@ -13,7 +13,8 @@ * true - OK * false - bad name * errors: - * EINVAL Invalid name characters or sequences + * EINVAL Invalid name + * EILSEQ Invalid name character sequence (acceptable with --badname) * EOVERFLOW Name longer than maximum size */ @@ -33,6 +34,8 @@ #include "defines.h" #include "chkname.h" +#include "string/ctype/strchrisascii/strchriscntrl.h" +#include "string/ctype/strisascii/strisdigit.h" #include "string/strcmp/streq.h" @@ -56,6 +59,17 @@ login_name_max_size(void) static bool is_valid_name(const char *name) { + if (streq(name, "") + || streq(name, ".") + || streq(name, "..") + || strpbrk(name, ",:") + || strchriscntrl(name) + || strisdigit(name)) + { + errno = EINVAL; + return false; + } + if (allow_bad_names) { return true; } @@ -66,26 +80,18 @@ is_valid_name(const char *name) * * as a non-POSIX, extension, allow "$" as the last char for * sake of Samba 3.x "add machine script" - * - * Also do not allow fully numeric names or just "." or "..". */ - int numeric; - if (streq(name, "") || - streq(name, ".") || - streq(name, "..") || - !((*name >= 'a' && *name <= 'z') || + if (!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z') || (*name >= '0' && *name <= '9') || *name == '_' || *name == '.')) { - errno = EINVAL; + errno = EILSEQ; return false; } - numeric = isdigit(*name); - while (!streq(++name, "")) { if (!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z') || @@ -96,15 +102,9 @@ is_valid_name(const char *name) streq(name, "$") )) { - errno = EINVAL; + errno = EILSEQ; return false; } - numeric &= isdigit(*name); - } - - if (numeric) { - errno = EINVAL; - return false; } return true; diff --git a/src/newusers.c b/src/newusers.c index 5e78dd976..18748268e 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -388,7 +388,7 @@ static int add_user (const char *name, uid_t uid, gid_t gid) /* Check if this is a valid user name */ if (!is_valid_user_name(name)) { - if (errno == EINVAL) { + if (errno == EILSEQ) { fprintf(stderr, _("%s: invalid user name '%s': use --badname to ignore\n"), Prog, name); diff --git a/src/pwck.c b/src/pwck.c index ae7ddaddf..8594e2e59 100644 --- a/src/pwck.c +++ b/src/pwck.c @@ -475,7 +475,7 @@ static void check_pw_file (int *errors, bool *changed) */ if (!is_valid_user_name(pwd->pw_name)) { - if (errno == EINVAL) { + if (errno == EILSEQ) { printf(_("invalid user name '%s': use --badname to ignore\n"), pwd->pw_name); } else { diff --git a/src/useradd.c b/src/useradd.c index 4275794a7..67b2f3e18 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -1534,7 +1534,7 @@ static void process_flags (int argc, char **argv) user_name = argv[optind]; if (!is_valid_user_name(user_name)) { - if (errno == EINVAL) { + if (errno == EILSEQ) { fprintf(stderr, _("%s: invalid user name '%s': use --badname to ignore\n"), Prog, user_name); diff --git a/src/usermod.c b/src/usermod.c index 24c5a4d23..ca4860f93 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -1118,7 +1118,7 @@ process_flags(int argc, char **argv) /*@notreached@*/break; case 'l': if (!is_valid_user_name(optarg)) { - if (errno == EINVAL) { + if (errno == EILSEQ) { fprintf(stderr, _("%s: invalid user name '%s': use --badname to ignore\n"), Prog, optarg);