Iker Pedrosa [Tue, 2 Jun 2026 13:18:31 +0000 (15:18 +0200)]
passwd: add UPN validation support
Add User Principal Name (UPN) validation to allow passwd command to
accept usernames in user@domain.com format. Currently, passwd will
accept both traditional usernames and UPN format.
Iker Pedrosa [Tue, 2 Jun 2026 11:15:42 +0000 (13:15 +0200)]
lib/chkname.*: Add UPN validation support
Add is_valid_upn() function to validate User Principal Name format. UPN
validation splits on @ and validates the prefix using existing username
rules and suffix part using RFC 1035/1123 compliant domain name
validation.
doc/contributions/: Add guidelines severely restricting use of AI for contributing
This policy has been derived from Gentoo. I added a requirement that
use of AI is disclosed. And changes resulting from said use should be
disclosed in detail. Also, I left a note saying we'll reject
non-negligible use of AI, which is a bit of an escape allowing us to
just say "too much".
lib/string/strspn/: strr[c]spn(): Return the length counting from the end
Instead of returning the offset from the start of the string, return the
length of the span counting from the end.
This makes the name of the function more representative of its behavior,
and also makes the functions more useful: one can use them as booleans
to determine whether a string ends in a set of characters or not.
if (strrspn(s, "xyz")) // Does 's' end in any chars of "xyz"?
Currently, the only uses of strr[c]spn() are for implementing
stpr[c]spn(), so we had to update those too.
Serge Hallyn [Wed, 17 Jun 2026 18:55:07 +0000 (13:55 -0500)]
man/po: keep tmpdir out of po files
When we pass every filename to the itstool call as $tmpdir/$base.out,
the file:line listed in the .po includes the $tmpdir. That means
every update-po changes every .po.
Serge Hallyn [Tue, 16 Jun 2026 17:35:03 +0000 (12:35 -0500)]
Make man/po update-po more robust
There were some inconsistencies in how remove-potcdate was named.
It exists as po/remove-potcdate.sin. The man/po tried to copy that
in, but it referred to it as remove-potcdate.sed.
Just copy it in as remove-potcdate.sed. I think we can do better
than this, but for now this should make update-po more robust.
This error message didn't make much sense. After inspecting the commit
in which it was introduced, it seems the intention was to diagnose if
the line was empty after ignoring white space. It was incorrectly
written then, so fix it now.
Rewrite it in the following way:
- If there's not a '\n', the entire line is bogus. Fail, and report an
appropriate diagnostic.
- Then, break the string at the first white space, as we were doing
before. No error handling is appropriate here.
- Then, diagnose if the remaining string is empty.
Having trailing white space in a line doesn't remove the need for
a trailing '\n'. Let's fail if a line doesn't have it, regardless of
how much trailing white space there is.
It is not intuitive or clear what the right behavior should be for an
empty string. If we define these APIs as "return true if all characters
in the string belong to the specified character set", then an empty
string should return true. On the other hand, if you ask me if an empty
string is a numeric string, I might naively say no.
It is irrelevant whether we return true or false for an empty string.
All of the callers already handle correctly the case of an empty string.
This makes the implementation simpler, using the argument only once.
This allows implementing these as macros.
lib/: Merge directories "lib/string/ctype/*" into unified files
The APIs defined under each of those subdirs are too similar and related
that it makes more sense to define them in the same files. (BTW, we
only had one API per subdir, except in one subdir that had two APIs, so
in the end, we have almost the same separation.)
Artem Semenov [Mon, 1 Jun 2026 12:57:04 +0000 (15:57 +0300)]
fix: memory leak: free path/rel in shadowtcb_remove()
In function shadowtcb_remove() (lib/tcbfuncs.c), memory allocated
for 'path' and 'rel' pointers was not released, causing a memory leak.
Added explicit free(path) and free(rel) calls before returning.
aborah-sudo [Wed, 3 Jun 2026 05:39:03 +0000 (11:09 +0530)]
Tests: Add two users with same UID using -o flag
This is the transformation to Python of the test located in
`tests/usertools/01/04_useradd_add_user_with_existing_UID_with_-o.test`
which checks that `useradd` add two users with same UID using -o flag
On Linux, userdel/usermod check all /proc/<pid> status files to ensure a
to-be-modified user has no more running tasks, or abort modification
otherwise.
However, the check failed to detect threads running as the user if the
corresponding main thread ran as a different user. The user is deleted
despite still being busy. This is due to passing a wrong value to
check_status. The caller passed "<pid>/task", rather than
"<pid>/task/<tid>". In consequence check_status tried to open
"/proc/<pid>/task/status" - a wrong path that never exists - open fails,
and check_status always returns 0. The correct status file name would
have been "/proc/<pid>/task/<tid>/status" instead.
The bug can only be reproduced by rather exotic code using raw syscalls.
POSIX does not allow threads to have different UIDs.
To fix it, construct the correct path to the tid status file in the
caller, before passing it to check_status.
The old name was too complex, and is inconsistent with all other
sprintf(3)-based APIs having just one letter for differentiation.
This allows breaking less lines.
The original name was chosen for differentiation with the buggy Plan9
API seprint(2). However, 9front (the current fork where Plan9 is mainly
developed) has acknowledged the bug. There's still no decision on
fixing the bug or not, due to the age of their code base, and the
projects depending on their library. It is under consideration
inventing something like a seprint2(2) in 9front for replacement of
seprint(2), but there's no decision yet either.
Considering that 9front acknowledges their bug, and that they *may*
release a fixed API with a similar name, we may as well claim that our
seprintf() is also a fixed version of Plan9's seprint(2). It has a
different name, after all (we terminate in 'f').
This commit was partially scripted with
$ find * -type f \
| xargs grep -l stpeprintf \
| xargs sed -i 's/stpeprintf/seprintf/g';
Instead of having three possible returns (a pointer to the NUL byte, the
end of the array, or NULL), reduce it to two possible ones: one for
success, and one for error.
Use errno, which is a common way to signal the specific error, and thus
treat truncation as any other error. This simplifies error handling
after these calls. Also, if one misuses a pointer after truncation, the
results are better if the pointer is NULL: the program will easily
abort. If we returned 'end', the program could more easily produce a
buffer overrun.
Suggested-by: Douglas McIlroy <douglas.mcilroy@dartmouth.edu> Signed-off-by: Alejandro Colomar <alx@kernel.org>
Iker Pedrosa [Tue, 12 May 2026 12:24:35 +0000 (14:24 +0200)]
man/login.defs.5.xml: clarify documentation for multi-component usage
The login.defs configuration file is used by multiple system components
(shadow-utils, PAM, util-linux), but the documentation was unclear about
this reality. This led to confusion about which parameters are relevant
on different system configurations.
Add explanatory paragraph clarifying that login.defs parameters may be
used by shadow-utils, PAM, and other system components, with behaviour
depending on system configuration and enabled authentication mechanisms.
aborah-sudo [Tue, 12 May 2026 02:05:26 +0000 (07:35 +0530)]
Tests: Unlock user password
This is the transformation to Python of the test located in
`tests/usertools/01/11_usermod_lock_password.test`
which checks that `usermod` can lock user password
aborah-sudo [Fri, 8 May 2026 08:31:53 +0000 (14:01 +0530)]
Tests: Change user password
This is the transformation to Python of the test located in
`tests/usertools/01/11_usermod_change_password.test`
which checks that `usermod` can change user password
aborah-sudo [Fri, 8 May 2026 08:27:59 +0000 (13:57 +0530)]
Tests: Rename user who is member of a group
This is the transformation to Python of the test located in
`tests/usertools/01/10_usermod_rename_user_in_group.test`
which checks that `usermod` can rename user who is member of a group
Tests: Add a new user with home directory creation
This is the transformation to Python of the test located in
`tests/usertools/01/17_useradd_create_homedir.test`
which checks that `useradd` can add a new user with --create-home
Introduce LoginDefsConfig class for /etc/login.defs manipulation.
It supports getting, setting, and removing configuration options
with automatic backup and restoration.
Hadi Chokr [Tue, 28 Apr 2026 10:18:43 +0000 (12:18 +0200)]
useradd: fix btrfs subvolume creation for single-component basedir
dirname() replaces broken stpcpy index arithmetic that produced an
empty string for single-component paths (e.g. /koolhome), causing
statfs to fail and fall back to a regular directory. Use path in
the error message since dirname() modifies btrfs_check in-place,
making it unusable for logging after the call.
Fixes: c1d36a8acb1d (2019-05-04; "Add support for btrfs subvolumes for user homes") Signed-off-by: Hadi Chokr <hadichokr@icloud.com> Reviewed-by: Alejandro Colomar <alx@kernel.org>
tests: add CI user creation to simulate cloud VM environments
Create a 'ci' user in all distribution-specific ansible roles to
simulate cloud VM environments where ID 1000 is already taken. This
ensures that test users start the ID assignment at 1001, making
container tests consistent with cloud CI environments.
tests/system/framework/hosts/shadow.py: fix restore when /home is a mount point
Handle cases where /home is mounted separately by using selective
cleanup instead of attempting to remove the mount point, which causes
"Device or resource busy" errors in cloud environments.
Hadi Chokr [Tue, 21 Apr 2026 07:18:19 +0000 (09:18 +0200)]
useradd(8): fallback to regular dir for BTRFS home on non-BTRFS parent
When the --btrfs-subvolume-home option is used but the parent directory
is not on a BTRFS filesystem, useradd previously failed with an error.
This is too strict; instead, fall back to creating a regular directory
and issue a warning. The subvolume creation is attempted only when the
parent is BTRFS. Otherwise, a regular directory is created and a
syslog(3) warning is logged.
Fixes: 3e8c105 (2026-01-02; "src/useradd: Support config for creating home dirs as Btrfs subvolumes") Co-authored-by: Hadi Chokr <hadichokr@icloud.com> Co-authored-by: Alejandro Colomar <alx@kernel.org> Signed-off-by: Alejandro Colomar <alx@kernel.org>
Tests: Add a new user with supplementary groups using default primary group
This is the transformation to Python of the test located in
`tests/usertools/01/16_useradd_add_user_to_one_group.test` which checks that
`useradd` can add a new user with specific group
Tests: Verify user creation fails when UID exceeds maximum allowed value (2^32 - 1)
This is the transformation to Python of the test located in
`tests/usertools/01/26_useradd_UID_-1.test`
which checks that `useradd` can not add a new user with specific uid
Tests: Add a new user with custom primary group and supplementary groups
This is the transformation to Python of the test located in
`tests/usertools/01/16_useradd_add_user_to_multiple_groups.test`
which checks that `useradd` can add a new user with specific group
Tests: Verify user creation succeeds with large valid UIDs
This is the transformation to Python of the test located in
`tests/usertools/01/25_useradd_specified_large_UID2.test`,
which checks that `useradd` can add a new user with large UID
Pat Riehecky [Fri, 13 Mar 2026 14:25:41 +0000 (09:25 -0500)]
subid: setup deterministic_wrap mode
This adds two new options to /etc/login.defs:
* UNSAFE_SUB_UID_DETERMINISTIC_WRAP
* UNSAFE_SUB_GID_DETERMINISTIC_WRAP
Deterministic subordinate ID allocation ties each user's subid range
directly to their UID, giving consistent, reproducible ranges across all
hosts without a shared database. This property breaks down when the
subordinate ID space is exhausted.
With a UID space that on Linux extends to 2^32-1 and the traditional
per-user subid allocation of 2^16 ranges, a site with a large UID
population could exhaust the subordinate ID space before all user UIDs
are allocated.
UNSAFE_SUB_UID_DETERMINISTIC_WRAP and UNSAFE_SUB_GID_DETERMINISTIC_WRAP
provide an explicit opt-in to modulo (ring-buffer) wrapping as a
predictable last resort. This preserves the deterministic allocation
at the risk of subid overlap.
The UNSAFE_ prefix and the required explicit opt-in are intentional.
Overlapping ranges break namespace isolation and can allow container
escapes and privilege escalation between users whose ranges collide.
These options are appropriate only when all of the following hold:
- Strict subid determinism is require
- The active UID population on the host is small and well-known
- The administrator regularly audits the UID distribution and confirms
no two active users produce overlapping computed ranges
Do not enable these options on hosts with an uncontrolled user population.
Pat Riehecky [Mon, 16 Mar 2026 13:21:30 +0000 (08:21 -0500)]
subid: Add deterministic subid ranges
This adds two new options to /etc/login.defs:
* SUB_UID_DETERMINISTIC
* SUB_GID_DETERMINISTIC
In a lab where users are created ad hoc subids might drift
from one host to the other. If there is a shared home area,
this drift can create some frustration.
Creating subids deterministically provides one type of solution
to this problem. Use of nonconsecutive UIDs will result in blocks
of unused subids.
The manpages provide documentation on how these can be used.
lib/subordinateio.c: find_free_range(): Use id_t instead of u_long
It's the natural type for this API, and it's also more
consistent with its wrappers.
Let's also use literal -1 for the error code, which is safer than
unsigned constants, as -1 is sign-extended to fit whatever unsigned type
we're using.
Revert "strchriscntrl: reject C1 control bytes (0x80-0x9F)"
C1 control bytes are more complicated than that. They're represented as
two bytes in UTF-8.
Commit 19d725da, has issues, rejecting otherwise valid UTF-8 multi-byte
characters.
We could in theory do correct parsing of UTF, possibly parsing the
multi-byte sequences, or translating to wchar_t. However, that would
complicate the source code well beyond what I'd be comfortable with.
Instead, let's revert this, and claim no intention to support UTF-8.
If an admin uses a UTF-8 locale while reading /etc/passwd, that's their
own fault.
aborah-sudo [Tue, 31 Mar 2026 04:23:42 +0000 (09:53 +0530)]
Tests: Add a new user with a specified large UID
This is the transformation to Python of the test located in
`tests/usertools/01/15_useradd_specified_large_UID.test` which
checks that `useradd` can add a new user with large UID
aborah-sudo [Tue, 31 Mar 2026 04:16:02 +0000 (09:46 +0530)]
Tests: Add a new user with an invalid UID
This is the transformation to Python of the test located in
`tests/usertools/01/13_useradd_negative_UID.test`,
`tests/usertools/01/14_useradd_out_of_range_UID.test`
which checks that `useradd` can not add a new user with invalid UID
Iker Pedrosa [Wed, 25 Mar 2026 13:37:01 +0000 (14:37 +0100)]
*/: groupmems(8): Remove program
The utility is redundant for root and effectively broken for regular
users across major distributions, its continued maintenance adds
complexity for little to no benefit.