Numeric usernames in Red Hat Enterprise Linux

Solution Verified - Updated -

Environment

  • Red Hat Enterprise Linux 7

Issue

A bug report against systemd-232 discovered that usernames beginning with a number (such as "0day" or "3dogs") are not handled correctly in systemd unit files. Services assigned to such users will instead be started as root.

This does not occur on systemd-219 as shipped in Red Hat Enterprise Linux 7. As the following test demonstrates, such usernames will be handled safely whether the corresponding user exists or not:

# cd /etc/systemd/system
# cat test.service
[Service]
ExecStart=/usr/bin/id
User=0day
# grep 0day /etc/passwd
# systemctl start test.service
...
... Failed at step USER spawning /bin/id: No such process
...

# adduser 0day
...
... new user: name=0day, UID=1003, GID=1003, home=/home/0day, shell=/bin/bash
...
# systemctl start test.service
...
... id[11245]: uid=1003(0day) gid=1003(0day) groups=1003(0day) context=system_u:system_r:unconfined_service_t:s0
...

Comments in the bug report did identify that while many distributions deny usernames beginning with numbers, Red Hat Enterprise Linux has a special patch in shadow-utils that permits such usernames. This article examines the background and implications of that patch.

Resolution

User and group names that consist only of digits, while permitted by shadow-utils, are best avoided or treated with caution. Some tools (eg setfacl, getent) will be unable to recognise them at all, while others will need to be used carefully (eg chown).

Please note, shadow-utils-4.1.5.1-25 (shipped with Red Hat Enterprise Linux 7.6) does not allow to create all-numeric usernames. shadow-utils-4.1.5.1-25.el7_6.1 and later (shipped with Red Hat Enterprise Linux 7.6 batch update 3) requires the environment variable SHADOW_ALLOW_ALL_NUMERIC_USER to be set to any value to allow the useradd command to create all-numeric usernames.

Names that begin with a digit but also contain letters are not known to be a problem on Red Hat Enterprise Linux, though as the systemd issue highlights, it is important to test such cases where variation across distributions and across history means tools can make varying assumptions.

Root Cause

Over a decade ago, a patch was introduced to shadow-utils in Fedora to better support Samba 3.x machine usernames that end with '$'. At the same time, names were allowed to begin with a digit - including purely numeric usernames. This patch was picked up in Red Hat Enterprise Linux.

In 2014, Fedora added a restriction to coreutils to forbid pure numeric usernames. This change was evaluated for Enterprise Linux, but deemed too invasive to release to customers who may have come to rely on numeric usernames. Some customers facing problems using such usernames were advised to avoid them, but we could not simply release an update that could break people's systems.

POSIX

While all-numeric usernames are not forbidden by POSIX, they can introduce ambiguity. Many programs will not care - they're either manipulating a string or an integer, and will do the right thing in each case. But CLI tools receive all their inputs as strings, so they have to make assumptions about whether "1001" should be treated as an integer UID or as a string username.

chown in coreutils is one such example: it will first try to interpret a user string as a name (using getpwnam(3)) and then if that fails, try to parse it as a (decimal) number. Thus, scripts that do chown 0 filename to ensure a file is owned by root can be subverted if a user called 0 is later added to the system. To disambiguate these cases, coreutils supports prefixing user/group identifiers with + to ensure they are interpreted numerically [4]. Other tools that have trouble with numeric user names include Access Control Lists (acl(5)) and getent(1).

The problem is potentially also present for usernames that begin with digits, when interpreted by programs that are not very careful with library calls. atoi("3dogs") will return 3 with no warning. strtoul(3) is safer, but only if the endptr argument is checked after the call to ensure the whole input was consumed.

Systemd

systemd's behaviour here is a little eccentric, and has changed rapidly in recent years. As Lennart Poettering explains towards the end of the bug report, systemd "generally follow(s) the rule that when we encounter a unit setting that does not validate syntax-wise we'll log about it and ignore it, for compat reasons". This seems a reasonable choice for "pid 1", but the behaviour was surprising to the user who expected User=0day to be valid.

Note that the first conclusion reached in the bug report is incorrect: uid 0 is chosen for any syntactically invalid User= line - it would be the same for a user called 7day or 1000day.

The responsible function is valid_user_group_name, which you can see references POSIX. This is a little disingenuous, since POSIX places no restriction on usernames beginning with a digit.

This function also exists in systemd-219 used in Red Hat Enterprise Linux 7, but it is not applied to usernames in unit files.

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.