Skip to content

usermod: move home directory files to the new primary group with -g - #349

Open
jayhemnani9910 wants to merge 2 commits into
uutils:mainfrom
jayhemnani9910:fix/347-usermod-g-home-group
Open

jayhemnani9910 wants to merge 2 commits into
uutils:mainfrom
jayhemnani9910:fix/347-usermod-g-home-group

Conversation

@jayhemnani9910

@jayhemnani9910 jayhemnani9910 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #347

-g now re-groups the home directory the way -u already re-owns it: in the same walk, an entry whose group is the old primary GID gets the new one, and an entry owned by the old UID gets the new UID. Symlinks are changed themselves, not followed. As before, nothing is touched when -d is given or the home directory does not exist.

Like GNU, the walk now only runs when the home directory is a real directory owned by the user. A home owned by root (common for service accounts) or a symlinked home is left alone; before this, -u re-owned files under both. GNU also exits 12 for a symlinked home; shadow-rs still exits 0 there (#351).

Tests: root tests for -g and for -u -g on a home with files in the old group (one owned by root), one in another group, and a symlink in the old group to a file outside the home (the link changes, its target does not), and one for -g and -u on a root-owned and a symlinked home, which must be left alone. The first two fail on main; the third fails without the owner check. cargo test --workspace run as root in an Ubuntu 26.04 container: 946 passed (943 on main, plus the three new). cargo fmt --check and cargo clippy --workspace --all-targets -- -D warnings are clean; the pam configurations were not run locally. Against GNU shadow 4.17.4 in the same container, -g, -u -g, -u and -g -d, with a user-owned, root-owned and symlinked home, give the same ownership for every file in and outside the home directory.

AI tools assisted with this contribution.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 07:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

use std::os::unix::fs::MetadataExt;

// Like GNU, only a home directory the user owns is walked, and a
// symlinked home is not followed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GNU exits 12 for a symlinked home, could you please open an issue so we don't forget it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #351. GNU still updates /etc/passwd there, prints "Failed to change ownership of the home directory" and exits 12, for -u, -g and both.


// Like GNU, only a home directory the user owns is walked, and a
// symlinked home is not followed.
let home_path = root.resolve(&home_for_chown);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also changes -u on a root-owned or symlinked home
please add a test for -u too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, -u follows the same check now. test_home_not_owned_by_user_is_left_alone runs -g and -u on a root-owned home and on a symlinked one (c26923d). On main, -u re-owns the files under both.

("mine", 1000, 1000),
("root-owned", 0, 1000),
("other-group", 1000, 0),
] {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add a symlink in the old group pointing outside the home?
to check that the link is regrouped and its target is not

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to the shared setup (c26923d): link in the old group points to outside, a file next to the home. After -g and after -u -g, the link is regrouped and outside keeps 1000:1000.

std::os::unix::fs::chown(home.join("sub"), Some(1000), Some(1000)).expect("chown failed");

let code = run_with_prefix(&dir, &["-g", "dev", "testuser"]);
assert_eq!(code, 0, "changing the primary group should succeed");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a -u -g test too, both changes go through the same chownat

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test_change_uid_and_gid_rechowns_home_files (c26923d): -u 1500 -g dev on the same home. Each entry gets the new UID if it had the old one, and the new group if it had the old one; the root-owned file only changes group.

Comment thread tests/by-util/test_usermod.rs Outdated

let gid = |p: &str| {
std::fs::symlink_metadata(home.join(p))
.expect("stat failed")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same closure in both tests, could be a helper, no?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes: owner_of returns (uid, gid) without following symlinks, and setup_home_with_files builds the home for both regroup tests (c26923d). Root suite in the Ubuntu 26.04 container: 946 passed.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 18:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

usermod: -g does not move home directory files to the new primary group

3 participants