From 55550e1a6ec98e8657bb7b0807f2675424f4fc78 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sat, 23 Apr 2022 12:39:43 -0400 Subject: [PATCH] chown: allow setting arbitrary numeric user ID Update `chown` to allow setting the owner of a file to a numeric user ID regardless of whether a corresponding username exists on the system. For example, $ touch f && sudo chown 12345 f succeeds even though there is no named user with ID 12345. Fixes #3380. --- src/uu/chown/src/chown.rs | 15 +++++++++++---- tests/by-util/test_chown.rs | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index 3add9df1f..c58696121 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -197,10 +197,17 @@ fn parse_spec(spec: &str, sep: char) -> UResult<(Option, Option)> { // So, try to parse it this way return parse_spec(spec, '.'); } else { - return Err(USimpleError::new( - 1, - format!("invalid user: {}", spec.quote()), - )); + // It's possible that the `user` string contains a + // numeric user ID, in which case, we respect that. + match user.parse() { + Ok(uid) => uid, + Err(_) => { + return Err(USimpleError::new( + 1, + format!("invalid user: {}", spec.quote()), + )) + } + } } } }) diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index 4470260f4..05a10fb65 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -418,6 +418,29 @@ fn test_chown_only_user_id() { .stderr_contains(&"failed to change"); } +/// Test for setting the owner to a user ID for a user that does not exist. +/// +/// For example: +/// +/// $ touch f && chown 12345 f +/// +/// succeeds with exit status 0 and outputs nothing. The owner of the +/// file is set to 12345, even though no user with that ID exists. +/// +/// This test must be run as root, because only the root user can +/// transfer ownership of a file. +#[test] +fn test_chown_only_user_id_nonexistent_user() { + let ts = TestScenario::new(util_name!()); + let at = ts.fixtures.clone(); + at.touch("f"); + if let Ok(result) = run_ucmd_as_root(&ts, &["12345", "f"]) { + result.success().no_stdout().no_stderr(); + } else { + print!("Test skipped; requires root user"); + } +} + #[test] // FixME: stderr = chown: ownership of 'test_chown_file1' retained as cuuser:wheel #[cfg(not(target_os = "freebsd"))]