mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
fix install file with invalid uid (#7789)
* treat invalid user or group as uid or gid if it's an integer * install: add test for install with invalid user or group
This commit is contained in:
@@ -405,7 +405,14 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
||||
} else {
|
||||
match usr2uid(&owner) {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => return Err(InstallError::InvalidUser(owner.clone()).into()),
|
||||
// When using -o500 option and there's no user with uid 500 on the system
|
||||
// usr2uid returns an Err value and the whole install operation fails.
|
||||
// GNU coreutils installs a file with uid 500 in the same situation
|
||||
// so just return the supplied owner as uid if it's an integer value
|
||||
Err(_) => match owner.parse::<u32>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => return Err(InstallError::InvalidUser(owner.clone()).into()),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -419,7 +426,14 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
||||
} else {
|
||||
match grp2gid(&group) {
|
||||
Ok(g) => Some(g),
|
||||
Err(_) => return Err(InstallError::InvalidGroup(group.clone()).into()),
|
||||
// When using -g500 option and there's no group with gid 500 on the system
|
||||
// grp2gid returns an Err value and the whole install operation fails.
|
||||
// GNU coreutils installs a file with gid 500 in the same situation
|
||||
// so just return the supplied group as gid if it's an integer value
|
||||
Err(_) => match group.parse::<u32>() {
|
||||
Ok(g) => Some(g),
|
||||
Err(_) => return Err(InstallError::InvalidGroup(group.clone()).into()),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
use filetime::FileTime;
|
||||
use std::fs;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::fs::File;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::io::{BufRead, BufReader};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
||||
#[cfg(not(windows))]
|
||||
@@ -2695,3 +2699,86 @@ fn test_install_d_dangling_symlink_in_path_errors() {
|
||||
"The symlink target must not have been created"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_install_set_owner_nonexistent_uid_and_gid() {
|
||||
let file = File::open("/etc/login.defs").unwrap();
|
||||
let reader = BufReader::new(file);
|
||||
let mut uid_min: u32 = 0;
|
||||
let mut uid_max: u32 = 0;
|
||||
let mut gid_min: u32 = 0;
|
||||
let mut gid_max: u32 = 0;
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
if line.starts_with("UID_MIN") {
|
||||
let tokens: Vec<&str> = line.split_whitespace().collect();
|
||||
uid_min = tokens[1].parse().unwrap();
|
||||
}
|
||||
if line.starts_with("UID_MAX") {
|
||||
let tokens: Vec<&str> = line.split_whitespace().collect();
|
||||
uid_max = tokens[1].parse().unwrap();
|
||||
}
|
||||
if line.starts_with("GID_MIN") {
|
||||
let tokens: Vec<&str> = line.split_whitespace().collect();
|
||||
gid_min = tokens[1].parse().unwrap();
|
||||
}
|
||||
if line.starts_with("GID_MAX") {
|
||||
let tokens: Vec<&str> = line.split_whitespace().collect();
|
||||
gid_max = tokens[1].parse().unwrap();
|
||||
}
|
||||
}
|
||||
let file = File::open("/etc/passwd").unwrap();
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut uids: Vec<u32> = vec![];
|
||||
let mut gids: Vec<u32> = vec![];
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
let tokens: Vec<&str> = line.split(':').collect();
|
||||
let uid: u32 = tokens[2].parse().unwrap();
|
||||
if (uid_min..=uid_max).contains(&uid) {
|
||||
uids.push(uid);
|
||||
}
|
||||
let gid: u32 = tokens[3].parse().unwrap();
|
||||
if (gid_min..=gid_max).contains(&gid) {
|
||||
gids.push(gid);
|
||||
}
|
||||
}
|
||||
uids.sort_unstable();
|
||||
|
||||
let next_uid = if let Some(uid) = uids.last() {
|
||||
*uid + 1
|
||||
} else {
|
||||
uid_min
|
||||
};
|
||||
|
||||
let next_gid = if let Some(gid) = gids.last() {
|
||||
*gid + 1
|
||||
} else {
|
||||
gid_min
|
||||
};
|
||||
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
at.touch("a");
|
||||
|
||||
if let Ok(result) = run_ucmd_as_root(
|
||||
&ts,
|
||||
&[
|
||||
format!("-o{next_uid}").as_str(),
|
||||
format!("-g{next_gid}").as_str(),
|
||||
"a",
|
||||
"b",
|
||||
],
|
||||
) {
|
||||
result.success();
|
||||
assert!(at.file_exists("b"));
|
||||
|
||||
let metadata = fs::metadata(at.plus("b")).unwrap();
|
||||
assert_eq!(metadata.uid(), next_uid);
|
||||
assert_eq!(metadata.gid(), next_gid);
|
||||
} else {
|
||||
println!("Test skipped; requires root user");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user