]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
lib/, src/, tests/: Pass the badname flag as a function parameter
authorAlejandro Colomar <alx@kernel.org>
Sun, 12 Jul 2026 14:22:17 +0000 (16:22 +0200)
committerIker Pedrosa <ikerpedrosam@gmail.com>
Fri, 17 Jul 2026 07:33:21 +0000 (09:33 +0200)
... instead of an extern variable.  This makes it easier to analyze
which programs allow badnames and which don't.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
14 files changed:
lib/chkname.c
lib/chkname.h
src/chfn.c
src/chsh.c
src/groupadd.c
src/groupmod.c
src/grpck.c
src/newgrp.c
src/newusers.c
src/passwd.c
src/pwck.c
src/useradd.c
src/usermod.c
tests/unit/test_chkname.c

index ee8ff9d108eefaf9408fb459291ef650319bb045..2f80740db80fc1cfdb89ac1c24cf2152339cac9a 100644 (file)
@@ -20,8 +20,6 @@
 
 #include "config.h"
 
-#ident "$Id$"
-
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #define LABEL_MAXLEN   63
 
 
-int allow_bad_names = false;
-
-
 static bool
-is_valid_name(const char *name)
+is_valid_name(const char *name, bool badnames)
 {
        if (streq(name, "")
         || streq(name, ".")
@@ -63,9 +58,8 @@ is_valid_name(const char *name)
                return false;
        }
 
-       if (allow_bad_names) {
+       if (badnames)
                return true;
-       }
 
        /*
         * User/group names must match BRE regex:
@@ -105,19 +99,19 @@ is_valid_name(const char *name)
 
 
 bool
-is_valid_user_name(const char *name)
+is_valid_user_name(const char *name, bool badnames)
 {
        if (strlen(name) >= LOGIN_NAME_MAX) {
                errno = EOVERFLOW;
                return false;
        }
 
-       return is_valid_name(name);
+       return is_valid_name(name, badnames);
 }
 
 
 bool
-is_valid_group_name(const char *name)
+is_valid_group_name(const char *name, bool badnames)
 {
        /*
         * Arbitrary limit for group names.
@@ -130,7 +124,7 @@ is_valid_group_name(const char *name)
                return false;
        }
 
-       return is_valid_name (name);
+       return is_valid_name(name, badnames);
 }
 
 
@@ -196,7 +190,7 @@ is_valid_domain_name(const char *domain)
  * in any authentication system.
  */
 bool
-is_valid_upn(const char *upn)
+is_valid_upn(const char *upn, bool badnames)
 {
        char  *u, *d;
 
@@ -212,5 +206,5 @@ is_valid_upn(const char *upn)
                return false;
        }
 
-       return is_valid_user_name(u) && is_valid_domain_name(d);
+       return is_valid_user_name(u, badnames) && is_valid_domain_name(d);
 }
index de93b8251a87c83b368597465824fb2fbdb678de..43766e66ba63ff916af847d01d20a409b668216a 100644 (file)
@@ -26,8 +26,8 @@
 #include <stdbool.h>
 
 
-extern bool is_valid_user_name (const char *name);
-extern bool is_valid_group_name (const char *name);
-extern bool is_valid_upn (const char *name);
+extern bool is_valid_user_name(const char *name, bool badnames);
+extern bool is_valid_group_name(const char *name, bool badnames);
+extern bool is_valid_upn(const char *name, bool badnames);
 
 #endif
index 71875253e9fadd2d0ec08f0c4891bf6cfc28a333..966919bc6992754f849920c85ac7d161961e98a7 100644 (file)
@@ -604,7 +604,7 @@ int main (int argc, char **argv)
         * name, or the name getlogin() returns.
         */
        if (optind < argc) {
-               if (!is_valid_user_name (argv[optind])) {
+               if (!is_valid_user_name(argv[optind], false)) {
                        fprintf (stderr, _("%s: Provided user name is not a valid name\n"), Prog);
                        fail_exit (E_NOPERM, process_selinux);
                }
index fafa9759d655b0fb396ed7320ab14c176f2f50c2..0e3a6923f81300e339cc64e4c3f922bbe0039968 100644 (file)
@@ -493,7 +493,7 @@ int main (int argc, char **argv)
         * name, or the name getlogin() returns.
         */
        if (optind < argc) {
-               if (!is_valid_user_name (argv[optind])) {
+               if (!is_valid_user_name(argv[optind], false)) {
                        fprintf (stderr, _("%s: Provided user name is not a valid name\n"), Prog);
                        fail_exit (1, process_selinux);
                }
index 3c4ac8b13c2dda1fb9540d65fe6e8ad57ca30e38..27537172752f536091b2c1dcd5ddd0f2501f62fb 100644 (file)
@@ -260,7 +260,7 @@ grp_update(void)
 static void
 check_new_name(void)
 {
-       if (!is_valid_group_name(group_name)) {
+       if (!is_valid_group_name(group_name, false)) {
                fprintf(stderr, _("%s: '%s' is not a valid group name\n"),
                        Prog, group_name);
 
index 0ad7a30730c586481403830c149f503ccf211f68..5056faffe76e97df415527d52d7fa509784038fa 100644 (file)
@@ -382,7 +382,7 @@ check_new_name(void)
                return;
        }
 
-       if (!is_valid_group_name(group_newname)) {
+       if (!is_valid_group_name(group_newname, false)) {
                fprintf(stderr,
                        _("%s: invalid group name '%s'\n"),
                        Prog, group_newname);
index 385c105e87ae6dbf311db67a27a19886f2e9db87..76c191dd75c5671e4f60af6ea899ac52ced12222 100644 (file)
@@ -580,7 +580,7 @@ static void check_grp_file(bool *errors, bool *changed, const struct option_flag
                /*
                 * Check for invalid group names.  --marekm
                 */
-               if (!is_valid_group_name (grp->gr_name)) {
+               if (!is_valid_group_name(grp->gr_name, false)) {
                        *errors = true;
                        printf (_("invalid group name '%s'\n"), grp->gr_name);
                }
index afe4d851857f5f70913e3049f9ea377a8d0039f1..f7671ae4fef490e029a933160bf24d9509699130 100644 (file)
@@ -480,7 +480,7 @@ int main (int argc, char **argv)
                 * not "newgrp".
                 */
                if ((argc > 0) && (argv[0][0] != '-')) {
-                       if (!is_valid_group_name (argv[0])) {
+                       if (!is_valid_group_name(argv[0], false)) {
                                fprintf (
                                        stderr, _("%s: provided group is not a valid group name\n"),
                                        Prog);
@@ -516,7 +516,7 @@ int main (int argc, char **argv)
                        usage ();
                        goto failure;
                } else if (argv[0] != NULL) {
-                       if (!is_valid_group_name (argv[0])) {
+                       if (!is_valid_group_name(argv[0], false)) {
                                fprintf (
                                        stderr, _("%s: provided group is not a valid group name\n"),
                                        Prog);
index b316d8b5caae28e4ec90b1e7e23983b5203c12ae..c66f7ee4dc1afb3ea5beff361e408eb9ecc692fb 100644 (file)
@@ -70,6 +70,7 @@ struct option_flags {
  */
 static const char Prog[] = "newusers";
 
+static bool bflg = false;
 static bool rflg = false;      /* create a system account */
 #ifndef USE_PAM
 static /*@null@*//*@observer@*/char *crypt_method = NULL;
@@ -114,7 +115,6 @@ static void check_flags (void);
 static void open_files (bool process_selinux);
 static void close_files(const struct option_flags *flags);
 
-extern int allow_bad_names;
 
 /*
  * usage - display usage message and exit
@@ -288,7 +288,7 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid)
        }
 
        /* Check if this is a valid group name */
-       if (!is_valid_group_name (grent.gr_name)) {
+       if (!is_valid_group_name(grent.gr_name, bflg)) {
                fprintf (stderr,
                         _("%s: invalid group name '%s'\n"),
                         Prog, grent.gr_name);
@@ -385,7 +385,7 @@ static int add_user (const char *name, uid_t uid, gid_t gid)
        struct passwd pwent;
 
        /* Check if this is a valid user name */
-       if (!is_valid_user_name(name)) {
+       if (!is_valid_user_name(name, bflg)) {
                if (errno == EILSEQ) {
                        fprintf(stderr,
                                _("%s: invalid user name '%s': use --badname to ignore\n"),
@@ -643,7 +643,7 @@ static void process_flags (int argc, char **argv, struct option_flags *flags)
                                 long_options, NULL)) != -1) {
                switch (c) {
                case 'b':
-                       allow_bad_names = true;
+                       bflg = true;
                        break;
 #ifndef USE_PAM
                case 'c':
index 1873bf89fcee8a936967c43c62cd093afe22ff4b..83b45f63c4aa6f2a6a77eba5b40f377882fadf68 100644 (file)
@@ -946,7 +946,7 @@ main(int argc, char **argv)
        }
        myname = xstrdup (pw->pw_name);
        if (optind < argc) {
-               if (!is_valid_user_name (argv[optind]) && !is_valid_upn (argv[optind])) {
+               if (!is_valid_user_name(argv[optind], false) && !is_valid_upn(argv[optind], false)) {
                        fprintf (stderr, _("%s: Provided user name is not a valid name\n"), Prog);
                        fail_exit (E_NOPERM, process_selinux);
                }
index 0413f3f8eb017f502725cfd408003a0972630dfe..954cf3a8ade916dbb08b74c8e4dda1ccbdad9a83 100644 (file)
@@ -68,6 +68,7 @@ static bool pw_locked  = false;
 static bool spw_locked = false;
 
 /* Options */
+static bool bflg = false;
 static bool read_only = false;
 static bool sort_mode = false;
 static bool quiet = false;             /* don't report warnings, only errors */
@@ -82,7 +83,6 @@ static void check_pw_file (bool *errors, bool *changed,
                            const struct option_flags *flags);
 static void check_spw_file (bool *errors, bool *changed);
 
-extern int allow_bad_names;
 
 /*
  * fail_exit - do some cleanup and exit with the given error code
@@ -178,7 +178,7 @@ static void process_flags (int argc, char **argv, struct option_flags *flags)
                                 long_options, NULL)) != -1) {
                switch (c) {
                case 'b':
-                       allow_bad_names = true;
+                       bflg = true;
                        break;
                case 'h':
                        usage (E_SUCCESS);
@@ -486,7 +486,7 @@ static void check_pw_file(bool *errors, bool *changed, const struct option_flags
                 * Check for invalid usernames.  --marekm
                 */
 
-               if (!is_valid_user_name(pwd->pw_name)) {
+               if (!is_valid_user_name(pwd->pw_name, bflg)) {
                        if (errno == EILSEQ) {
                                printf(_("invalid user name '%s': use --badname to ignore\n"),
                                       pwd->pw_name);
index 81798b6af5bb6694263edb363aa225c73cc7189d..9b52c8fc8bdafdf2fc5c292109a1b0d99537bddf 100644 (file)
@@ -160,9 +160,8 @@ static char **user_groups;  /* NULL-terminated list */
 static size_t sys_ngroups;
 static bool do_grp_update = false;     /* group files need to be updated */
 
-extern int allow_bad_names;
-
 static bool
+    badnameflg = false,
     bflg = false,              /* new default root of home directory */
     cflg = false,              /* comment (GECOS) field for new account */
     dflg = false,              /* home directory for new account */
@@ -1215,7 +1214,7 @@ static void process_flags (int argc, char **argv, struct option_flags *flags)
                                subvolflg = true;
                                break;
                        case 201:
-                               allow_bad_names = true;
+                               badnameflg = true;
                                break;
                        case 'c':
                                if (!VALID (optarg)) {
@@ -1516,7 +1515,7 @@ static void process_flags (int argc, char **argv, struct option_flags *flags)
                }
 
                user_name = argv[optind];
-               if (!is_valid_user_name(user_name)) {
+               if (!is_valid_user_name(user_name, badnameflg)) {
                        if (errno == EILSEQ) {
                                fprintf(stderr,
                                        _("%s: invalid user name '%s': use --badname to ignore\n"),
index 5a222263871e7e392191fccd98b4535a25d3affe..31addeb34e612fb3b5b97335474b5c187321670d 100644 (file)
@@ -147,6 +147,7 @@ static char* prefix_user_newhome = NULL;
 
 static bool
     aflg = false,              /* append to existing secondary group set */
+    bflg = false,
     cflg = false,              /* new comment (GECOS) field */
     dflg = false,              /* new home directory */
     eflg = false,              /* days since 1970-01-01 when account becomes expired */
@@ -225,7 +226,6 @@ static void update_faillog (void);
 static void move_mailbox (void);
 #endif
 
-extern int allow_bad_names;
 
 /*
  * get_groups - convert a list of group names to an array of group IDs
@@ -1084,7 +1084,7 @@ process_flags(int argc, char **argv, struct option_flags *flags)
                                aflg = true;
                                break;
                        case 'b':
-                               allow_bad_names = true;
+                               bflg = true;
                                break;
                        case 'c':
                                if (!VALID (optarg)) {
@@ -1159,7 +1159,7 @@ process_flags(int argc, char **argv, struct option_flags *flags)
                                usage (E_SUCCESS);
                                /*@notreached@*/break;
                        case 'l':
-                               if (!is_valid_user_name(optarg)) {
+                               if (!is_valid_user_name(optarg, bflg)) {
                                        if (errno == EILSEQ) {
                                                fprintf(stderr,
                                                        _("%s: invalid user name '%s': use --badname to ignore\n"),
index a211b9f5931dbd930e18cf5166b4c5b6b318d71c..56af7afa1e8905b842eafbf088aaaefaa8bc26e8 100644 (file)
@@ -66,15 +66,15 @@ main(void)
 static void
 test_is_valid_user_name_ok(MAYBE_UNUSED void ** _1)
 {
-       assert_true(is_valid_user_name("alx"));
-       assert_true(is_valid_user_name("u-ser"));
-       assert_true(is_valid_user_name("u"));
-       assert_true(is_valid_user_name("I"));
-       assert_true(is_valid_user_name("_"));
-       assert_true(is_valid_user_name("_.-"));
-       assert_true(is_valid_user_name(".007"));
-       assert_true(is_valid_user_name("0_0"));
-       assert_true(is_valid_user_name("some_longish_user_name_sHould_also_be_valid.wHY_not"));
+       assert_true(is_valid_user_name("alx", false));
+       assert_true(is_valid_user_name("u-ser", false));
+       assert_true(is_valid_user_name("u", false));
+       assert_true(is_valid_user_name("I", false));
+       assert_true(is_valid_user_name("_", false));
+       assert_true(is_valid_user_name("_.-", false));
+       assert_true(is_valid_user_name(".007", false));
+       assert_true(is_valid_user_name("0_0", false));
+       assert_true(is_valid_user_name("some_longish_user_name_sHould_also_be_valid.wHY_not", false));
 }
 
 
@@ -82,61 +82,61 @@ static void
 test_is_valid_user_name_ok_dollar(MAYBE_UNUSED void ** _1)
 {
        // Non-POSIX extension for Samba 3.x "add machine script".
-       assert_true(is_valid_user_name("dollar$"));
-       assert_true(is_valid_user_name("SSS$"));
+       assert_true(is_valid_user_name("dollar$", false));
+       assert_true(is_valid_user_name("SSS$", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_dash(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name("-"));
-       assert_true(false == is_valid_user_name("-not-valid"));
-       assert_true(false == is_valid_user_name("--C"));
+       assert_true(false == is_valid_user_name("-", false));
+       assert_true(false == is_valid_user_name("-not-valid", false));
+       assert_true(false == is_valid_user_name("--C", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_dir(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name("."));
-       assert_true(false == is_valid_user_name(".."));
+       assert_true(false == is_valid_user_name(".", false));
+       assert_true(false == is_valid_user_name("..", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_dollar(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name("$"));
-       assert_true(false == is_valid_user_name("$dollar"));
-       assert_true(false == is_valid_user_name("mo$ney"));
-       assert_true(false == is_valid_user_name("do$$ar"));
-       assert_true(false == is_valid_user_name("foo$bar$"));
+       assert_true(false == is_valid_user_name("$", false));
+       assert_true(false == is_valid_user_name("$dollar", false));
+       assert_true(false == is_valid_user_name("mo$ney", false));
+       assert_true(false == is_valid_user_name("do$$ar", false));
+       assert_true(false == is_valid_user_name("foo$bar$", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_empty(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name(""));
+       assert_true(false == is_valid_user_name("", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_numeric(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name("6"));
-       assert_true(false == is_valid_user_name("42"));
+       assert_true(false == is_valid_user_name("6", false));
+       assert_true(false == is_valid_user_name("42", false));
 }
 
 
 static void
 test_is_valid_user_name_nok_otherchars(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_user_name("no spaces"));
-       assert_true(false == is_valid_user_name("no,"));
-       assert_true(false == is_valid_user_name("no;"));
-       assert_true(false == is_valid_user_name("no:"));
+       assert_true(false == is_valid_user_name("no spaces", false));
+       assert_true(false == is_valid_user_name("no,", false));
+       assert_true(false == is_valid_user_name("no;", false));
+       assert_true(false == is_valid_user_name("no:", false));
 }
 
 
@@ -151,10 +151,10 @@ test_is_valid_user_name_long(MAYBE_UNUSED void ** _1)
        memset(name, '_', LOGIN_NAME_MAX);
 
        stpcpy(&name[LOGIN_NAME_MAX], "");
-       assert_true(false == is_valid_user_name(name));
+       assert_true(false == is_valid_user_name(name, false));
 
        stpcpy(&name[LOGIN_NAME_MAX - 1], "");
-       assert_true(is_valid_user_name(name));
+       assert_true(is_valid_user_name(name, false));
 
        free(name);
 }
@@ -163,27 +163,27 @@ test_is_valid_user_name_long(MAYBE_UNUSED void ** _1)
 static void
 test_is_valid_upn_ok(MAYBE_UNUSED void ** _1)
 {
-       assert_true(is_valid_upn("user@example.com"));
-       assert_true(is_valid_upn("john.doe@corp.example.org"));
-       assert_true(is_valid_upn("test@sub.domain.net"));
-       assert_true(is_valid_upn("a@b.c"));
-       assert_true(is_valid_upn("user123@test123.example"));
-       assert_true(is_valid_upn("user_name@example-domain.com"));
-       assert_true(is_valid_upn("test.user@example.domain.org"));
-       assert_true(is_valid_upn("user@domain"));
-       assert_true(is_valid_upn("user@domain.com."));
-       assert_true(is_valid_upn("user@sub."));
+       assert_true(is_valid_upn("user@example.com", false));
+       assert_true(is_valid_upn("john.doe@corp.example.org", false));
+       assert_true(is_valid_upn("test@sub.domain.net", false));
+       assert_true(is_valid_upn("a@b.c", false));
+       assert_true(is_valid_upn("user123@test123.example", false));
+       assert_true(is_valid_upn("user_name@example-domain.com", false));
+       assert_true(is_valid_upn("test.user@example.domain.org", false));
+       assert_true(is_valid_upn("user@domain", false));
+       assert_true(is_valid_upn("user@domain.com.", false));
+       assert_true(is_valid_upn("user@sub.", false));
 }
 
 
 static void
 test_is_valid_upn_nok_not_upn(MAYBE_UNUSED void ** _1)
 {
-       assert_true(false == is_valid_upn("regularuser"));
-       assert_true(false == is_valid_upn("user.name"));
-       assert_true(false == is_valid_upn("user_name"));
-       assert_true(false == is_valid_upn("123user"));
-       assert_true(false == is_valid_upn("USER"));
+       assert_true(false == is_valid_upn("regularuser", false));
+       assert_true(false == is_valid_upn("user.name", false));
+       assert_true(false == is_valid_upn("user_name", false));
+       assert_true(false == is_valid_upn("123user", false));
+       assert_true(false == is_valid_upn("USER", false));
 }
 
 
@@ -191,22 +191,22 @@ static void
 test_is_valid_upn_nok_structure(MAYBE_UNUSED void ** _1)
 {
        // Empty parts
-       assert_true(false == is_valid_upn("@domain.com"));
-       assert_true(false == is_valid_upn("user@"));
-       assert_true(false == is_valid_upn("@"));
+       assert_true(false == is_valid_upn("@domain.com", false));
+       assert_true(false == is_valid_upn("user@", false));
+       assert_true(false == is_valid_upn("@", false));
 
        // Multiple @ symbols
-       assert_true(false == is_valid_upn("user@domain@com"));
-       assert_true(false == is_valid_upn("@@domain.com"));
-       assert_true(false == is_valid_upn("user@@domain.com"));
+       assert_true(false == is_valid_upn("user@domain@com", false));
+       assert_true(false == is_valid_upn("@@domain.com", false));
+       assert_true(false == is_valid_upn("user@@domain.com", false));
 
        // Empty string
-       assert_true(false == is_valid_upn(""));
+       assert_true(false == is_valid_upn("", false));
 
        // Invalid prefix
-       assert_true(false == is_valid_upn("-user@domain.com"));
-       assert_true(false == is_valid_upn("123@domain.com"));
-       assert_true(false == is_valid_upn("user space@domain.com"));
+       assert_true(false == is_valid_upn("-user@domain.com", false));
+       assert_true(false == is_valid_upn("123@domain.com", false));
+       assert_true(false == is_valid_upn("user space@domain.com", false));
 }
 
 
@@ -214,12 +214,12 @@ static void
 test_is_valid_upn_nok_domain(MAYBE_UNUSED void ** _1)
 {
        // Invalid domain formats
-       assert_true(false == is_valid_upn("user@.domain.com"));
-       assert_true(false == is_valid_upn("user@domain..com"));
+       assert_true(false == is_valid_upn("user@.domain.com", false));
+       assert_true(false == is_valid_upn("user@domain..com", false));
 
        // Invalid domain characters
-       assert_true(false == is_valid_upn("user@domain_name.com"));
-       assert_true(false == is_valid_upn("user@domain name.com"));
+       assert_true(false == is_valid_upn("user@domain_name.com", false));
+       assert_true(false == is_valid_upn("user@domain name.com", false));
 }
 
 
@@ -244,7 +244,7 @@ test_is_valid_upn_ok_limits(MAYBE_UNUSED void ** _1)
        assert_true(upn != NULL);
        strcpy(upn, "user@");
        strcat(upn, domain);
-       assert_true(is_valid_upn(upn));
+       assert_true(is_valid_upn(upn, false));
 
        free(upn);
        free(domain);
@@ -267,7 +267,7 @@ test_is_valid_upn_nok_limits(MAYBE_UNUSED void ** _1)
        assert_true(upn != NULL);
        strcpy(upn, "user@");
        strcat(upn, domain);
-       assert_true(false == is_valid_upn(upn));
+       assert_true(false == is_valid_upn(upn, false));
 
        free(upn);
        free(domain);
@@ -275,5 +275,5 @@ test_is_valid_upn_nok_limits(MAYBE_UNUSED void ** _1)
        // Domain label too long (>63 chars)
        assert_true(false == is_valid_upn("user@"
                "verylongdomainlabelthatexceedssixtythreecharacterslimitsetbyRFC1035"
-               ".com"));
+               ".com", false));
 }