21

When adding a new user, how is the string validated?

I suppose there is a regular expression. What is that regular expression?

12

The general rule for username is its length must less than 32 characters. It depend on your distribution to make what is valid username.

In Debian, shadow-utils 4.1, there is a is_valid_name function in chkname.c:

static bool is_valid_name (const char *name)
{
    /*
     * User/group names must match [a-z_][a-z0-9_-]*[$]
     */
    if (('\0' == *name) ||
        !((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
        return false;
    }

    while ('\0' != *++name) {
        if (!(( ('a' <= *name) && ('z' >= *name) ) ||
              ( ('0' <= *name) && ('9' >= *name) ) ||
              ('_' == *name) ||
              ('-' == *name) ||
              ( ('$' == *name) && ('\0' == *(name + 1)) )
             )) {
            return false;
        }
    }

    return true;
}

And the length of username was checked before:

bool is_valid_user_name (const char *name)
{
    /*
     * User names are limited by whatever utmp can
     * handle.
     */
    if (strlen (name) > USER_NAME_MAX_LENGTH) {
        return false;
    }

    return is_valid_name (name);
}
15

From the man page of useradd (8):

It is usually recommended to only use usernames that begin with a lower case letter or an underscore, followed by lower case letters, digits, underscores, or dashes. They can end with a dollar sign. In regular expression terms: [a-z_][a-z0-9_-]*[$]?

On Debian, the only constraints are that usernames must neither start with a dash ('-') nor contain a colon (':') or a whitespace (space: ' ', end of line: '\n', tabulation: '\t', etc.). Note that using a slash ('/') may break the default algorithm for the definition of the user's home directory.

Usernames may only be up to 32 characters long.

So, there's a general recommendation. The actual constraints depend on the specifics of your implementation / distribution. On Debian-based systems, apparently there are no very hard constraints. In fact, I just tried useradd '€' on my Ubuntu box, and it worked. Of course, this may break some applications that do not expect such unusual usernames. To avoid such problems, it is best to follow the general recommendation.

12

Sorry for necrobumping this almost 4-year-old question, but it comes up pretty high on Internet search results and it warrants a little more attention.

A more accurate regex is (yes, I know, despite the man page):

^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$

Hopefully that helps some of those searching.

To break it down:

  1. It should start (^) with only lowercase letters or an underscore ([a-z_]). This occupies exactly 1 character.
  2. Then it should be one of either (( ... )):
    1. From 0 to 31 characters ({0,31}) of letters, numbers, underscores, and/or hyphens ([a-z0-9_-]), OR (|)
    2. From 0 to 30 characters of the above plus a USD symbol (\$) at the end, and then
  3. No more characters past this pattern ($).

For those unfamiliar with regex patterns, you may ask why the dollar sign had a backslash in 2.2. but did not in 3. This is because in most (all?) regex variants, the dollar sign indicates the end of a string (or line, etc.). Depending on the engine being used, it will need to be escaped if it's part of the actual string (I can't think off the top of my head of a regex engine that doesn't use backslash as an escape for a pure expression).

Note that Debian and Ubuntu remove some restrictions for a fully POSIX/shadow upstream compliant username (for instance, and I don't know if this has been fixed, but they allow the username to start with a number - which actually is what caused this bug). If you want to guarantee cross-platform, I'd recommend the above regex pattern rather than what passes/fails the check in Debian, Ubuntu, and others.

  • Great answer. Can easily be applied also in Java using java.util.regex.Pattern.matches("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$", user); – dokaspar May 25 '18 at 6:31
  • It should be [abcdefghijklmnopqrstuvwxyz] instead of [a-z]. [a-z] in many regexp engines also matches things like é, œ or even sometimes multi-character collating elements like dsz in Hungarian locales. – Stéphane Chazelas Jul 23 '18 at 6:54
  • Linux usernames do not accept Unicode (unless they are explicitly configured to break POSIX compliance - 1 2). This check should be done outside of the regex, as it's an input/environment/localization validation, not a string validation. Further, I'd love to hear an example of a regex engine that does this. All ones I know of match on ASCII and one has to explicitly enable Unicode, if it's even supported. – brent saner Jul 24 '18 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.