/oss · 13 merged

uutils/shadow

A rewrite of the Linux user account tools (useradd, usermod, passwd and others) in Rust, aiming to work the same as GNU shadow.

the project on GitHub (opens in a new tab)
  1. 30 Oct 2026

    Group and user IDs can no longer be set to a reserved value

    What was broken
    groupadd and usermod accepted 4294967295 as an ID, a value the system treats as meaning no change.
    What I changed
    Both now refuse it, as the other commands and the original tools already do.
    Why it matters
    Accounts can't end up with an ID that file permissions quietly ignore.

    see the code, #372 (opens in a new tab)

  2. 30 Oct 2026

    usermod can take a user out of some groups

    What was broken
    usermod had no -r option, so removing a user from a few groups meant listing every group they should stay in.
    What I changed
    usermod -r -G now removes the user from just the groups named and keeps the rest.
    Why it matters
    Admins can drop a group membership without touching the others.

    see the code, #370 (opens in a new tab)

  3. 30 Oct 2026

    Changing group members updates both group files

    What was broken
    groupmod -U changed the members in one group file but not in the shadow group file, so the two disagreed.
    What I changed
    The same member change now goes to both files.
    Why it matters
    Group membership stays consistent everywhere the system looks for it.

    see the code, #369 (opens in a new tab)

  4. 30 Oct 2026

    pwck stays quiet when the files are fine

    What was broken
    pwck warned about the normal nobody account on every Debian or Ubuntu system, and said no changes even when nothing was wrong.
    What I changed
    The false warning is gone, and no changes now appears only after real problems, as in the original.
    Why it matters
    A clean system gives a clean check.

    see the code, #366 (opens in a new tab)

  5. 30 Oct 2026

    usermod can move a home folder

    What was broken
    The Rust usermod had no -m option, so changing a user's home path left their files behind.
    What I changed
    usermod -m now moves the old home to the new path, copying across disks with owners, modes and times kept.
    Why it matters
    Admins can rename or relocate a user's home in one step, as with the original tool.

    see the code, #350 (opens in a new tab)

  6. 26 Oct 2026

    chfn and chsh stay quiet after a successful change

    What was broken
    chfn and chsh printed a line on the error stream after every successful change. GNU chfn and chsh print nothing.
    What I changed
    The extra line is gone. Errors and the interactive prompts work as before.
    Why it matters
    Scripts that treat any error output as a failure no longer flag a change that worked.

    see the code, #357 (opens in a new tab)

  7. 26 Oct 2026

    passwd now says "password changed." like GNU passwd

    What was broken
    After locking, unlocking or changing the aging of an account, passwd printed its own message on the error stream, unlike GNU passwd.
    What I changed
    It now prints "passwd: password changed." on normal output, the same line GNU passwd prints. With -q it stays silent.
    Why it matters
    Scripts and logs that expect GNU's message see it, and a success no longer looks like an error.

    see the code, #356 (opens in a new tab)

  8. 26 Oct 2026

    chage can now print dates as YYYY-MM-DD

    What was broken
    chage did not accept -i or --iso8601, so there was no way to get the password aging dates in a fixed year-month-day form.
    What I changed
    chage -l -i now prints every aging date as YYYY-MM-DD, matching GNU chage. Without -i the output stays the same.
    Why it matters
    Scripts can read password expiry dates without parsing month names.

    see the code, #355 (opens in a new tab)

  9. 26 Oct 2026

    System accounts now get IDs from the top of the range

    What was broken
    useradd -r and groupadd -r gave a new system account the lowest free ID, for example 101. GNU shadow starts at the top of the range and counts down.
    What I changed
    System users and groups now get the highest free system ID, 999 on a fresh system, then 998, the same as GNU.
    Why it matters
    Machines set up with these tools hand out the same system IDs as other Linux systems.

    see the code, #344 (opens in a new tab)

  10. 25 Oct 2026

    Changing a user's group also updates their home files

    What was broken
    Changing a user's primary group left the files in their home directory in the old group, unlike GNU usermod.
    What I changed
    The home directory walk now moves files from the old group to the new one, changes links rather than their targets, and skips homes the user does not own.
    Why it matters
    After a group change, the user's files belong to their new group, as admins expect.

    see the code, #349 (opens in a new tab)

  11. 25 Oct 2026

    useradd -U always creates the user's group

    What was broken
    When the system setting for user groups was off, useradd -U quietly skipped creating the user's own group. It also accepted -U together with -g.
    What I changed
    -U now always creates the group, and -U with -g is rejected, as in GNU shadow.
    Why it matters
    Scripts that ask for a user group get one, whatever the system default is.

    see the code, #345 (opens in a new tab)

  12. 22 Oct 2026

    useradd now gives the right exit code for a bad user name

    What was broken
    useradd exited with code 3 when a user name was not allowed. The manual says it should exit with 19, and GNU useradd does.
    What I changed
    A rejected user name now exits with 19, and other errors keep their codes.
    Why it matters
    Scripts that check why useradd failed get the answer the manual promises.

    see the code, #341 (opens in a new tab)

  13. 22 Oct 2026

    useradd and usermod now accept -1 to clear expiry settings

    What was broken
    The manuals say -1 clears the account expiry date and the inactive days, but both tools rejected -1 as an unknown option.
    What I changed
    The expiry and inactive options now take -1 and clear the field, as in GNU shadow.
    Why it matters
    Commands and scripts written for GNU shadow work here unchanged.

    see the code, #339 (opens in a new tab)

← every project