Support busybox user/group modification, more informational errors (#319)

This commit is contained in:
Cole Helbling 2023-03-10 14:00:20 -08:00 committed by GitHub
parent 51056b854a
commit 32dca2e846
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 191 additions and 97 deletions

18
Cargo.lock generated
View file

@ -360,6 +360,12 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "encoding_rs"
version = "0.8.32"
@ -980,6 +986,7 @@ dependencies = [
"typetag",
"url",
"uuid",
"which",
"xz2",
]
@ -2068,6 +2075,17 @@ dependencies = [
"webpki",
]
[[package]]
name = "which"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -58,6 +58,7 @@ os-release = { version = "0.1.0", default-features = false, optional = true }
is_ci = { version = "1.1.1", default-features = false, optional = true }
strum = { version = "0.24.1", features = ["derive"] }
nix-config-parser = { version = "0.1.2", features = ["serde"] }
which = "4.4.0"
[dev-dependencies]
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] }

View file

@ -202,14 +202,26 @@ impl Action for AddUserToGroup {
.await?;
},
_ => {
execute_command(
Command::new("gpasswd")
.process_group(0)
.args(["-a"])
.args([&name.to_string(), &groupname.to_string()])
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("gpasswd").is_ok() {
execute_command(
Command::new("gpasswd")
.process_group(0)
.args(["-a"])
.args([name, groupname])
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("addgroup").is_ok() {
execute_command(
Command::new("addgroup")
.process_group(0)
.args([name, groupname])
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingAddUserToGroupCommand);
}
},
}
@ -255,14 +267,26 @@ impl Action for AddUserToGroup {
.await?;
},
_ => {
execute_command(
Command::new("gpasswd")
.process_group(0)
.args(["-d"])
.args([&name.to_string(), &groupname.to_string()])
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("gpasswd").is_ok() {
execute_command(
Command::new("gpasswd")
.process_group(0)
.args(["-d"])
.args([&name.to_string(), &groupname.to_string()])
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("delgroup").is_ok() {
execute_command(
Command::new("delgroup")
.process_group(0)
.args([name, groupname])
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingRemoveUserFromGroupCommand);
}
},
};

View file

@ -92,20 +92,32 @@ impl Action for CreateGroup {
"Nix build group for nix-daemon",
"-i",
&format!("{gid}"),
name.as_str(),
name,
])
.stdin(std::process::Stdio::null()),
)
.await?;
},
_ => {
execute_command(
Command::new("groupadd")
.process_group(0)
.args(["-g", &gid.to_string(), "--system", &name])
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("groupadd").is_ok() {
execute_command(
Command::new("groupadd")
.process_group(0)
.args(["-g", &gid.to_string(), "--system", name])
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("addgroup").is_ok() {
execute_command(
Command::new("addgroup")
.process_group(0)
.args(["-g", &gid.to_string(), "--system", name])
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingGroupCreationCommand);
}
},
};
@ -143,13 +155,25 @@ impl Action for CreateGroup {
if !output.status.success() {}
},
_ => {
execute_command(
Command::new("groupdel")
.process_group(0)
.arg(&name)
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("groupdel").is_ok() {
execute_command(
Command::new("groupdel")
.process_group(0)
.arg(name)
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("delgroup").is_ok() {
execute_command(
Command::new("delgroup")
.process_group(0)
.arg(name)
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingGroupDeletionCommand);
}
},
};

View file

@ -98,7 +98,7 @@ impl Action for CreateUser {
let Self {
name,
uid,
groupname: _,
groupname,
gid,
} = self;
@ -178,31 +178,57 @@ impl Action for CreateUser {
.await?;
},
_ => {
execute_command(
Command::new("useradd")
.process_group(0)
.args([
"--home-dir",
"/var/empty",
"--comment",
&format!("\"Nix build user\""),
"--gid",
&gid.to_string(),
"--groups",
&gid.to_string(),
"--no-user-group",
"--system",
"--shell",
"/sbin/nologin",
"--uid",
&uid.to_string(),
"--password",
"\"!\"",
&name.to_string(),
])
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("useradd").is_ok() {
execute_command(
Command::new("useradd")
.process_group(0)
.args([
"--home-dir",
"/var/empty",
"--comment",
"Nix build user",
"--gid",
&gid.to_string(),
"--groups",
&gid.to_string(),
"--no-user-group",
"--system",
"--shell",
"/sbin/nologin",
"--uid",
&uid.to_string(),
"--password",
"!",
name,
])
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("adduser").is_ok() {
execute_command(
Command::new("adduser")
.process_group(0)
.args([
"--home",
"/var/empty",
"--gecos",
"Nix build user",
"--ingroup",
groupname,
"--system",
"--shell",
"/sbin/nologin",
"--uid",
&uid.to_string(),
"--disabled-password",
name,
])
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingUserCreationCommand);
}
},
}
@ -266,13 +292,25 @@ impl Action for CreateUser {
}
},
_ => {
execute_command(
Command::new("userdel")
.process_group(0)
.args([&name.to_string()])
.stdin(std::process::Stdio::null()),
)
.await?;
if which::which("userdel").is_ok() {
execute_command(
Command::new("userdel")
.process_group(0)
.arg(name)
.stdin(std::process::Stdio::null()),
)
.await?;
} else if which::which("deluser").is_ok() {
execute_command(
Command::new("deluser")
.process_group(0)
.arg(name)
.stdin(std::process::Stdio::null()),
)
.await?;
} else {
return Err(ActionError::MissingUserDeletionCommand);
}
},
};

View file

@ -5,8 +5,7 @@ use crate::{
},
settings::CommonSettings,
};
use tokio::task::JoinSet;
use tracing::{span, Instrument, Span};
use tracing::{span, Span};
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateUsersAndGroups {
@ -266,37 +265,11 @@ impl Action for CreateUsersAndGroups {
nix_build_user_prefix: _,
nix_build_user_id_base: _,
} = self;
let mut set = JoinSet::new();
let mut errors = Vec::default();
for (idx, create_user) in create_users.iter().enumerate() {
let span = tracing::Span::current().clone();
let mut create_user_clone = create_user.clone();
let _abort_handle = set.spawn(async move {
create_user_clone
.try_revert()
.instrument(span)
.await
.map_err(|e| ActionError::Child(create_user_clone.action_tag(), Box::new(e)))?;
Result::<_, ActionError>::Ok((idx, create_user_clone))
});
}
while let Some(result) = set.join_next().await {
match result {
Ok(Ok((idx, success))) => create_users[idx] = success,
Ok(Err(e)) => errors.push(Box::new(e)),
Err(e) => return Err(ActionError::Join(e))?,
};
}
if !errors.is_empty() {
if errors.len() == 1 {
return Err(*errors.into_iter().next().unwrap());
} else {
return Err(ActionError::Children(errors));
}
for create_user in create_users.iter_mut() {
create_user
.try_revert()
.await
.map_err(|e| ActionError::Child(create_user.action_tag(), Box::new(e)))?;
}
// We don't actually need to do this, when a user is deleted they are removed from groups

View file

@ -427,6 +427,22 @@ pub enum ActionError {
Plist(#[from] plist::Error),
#[error("Unexpected binary tarball contents found, the build result from `https://releases.nixos.org/?prefix=nix/` or `nix build nix#hydraJobs.binaryTarball.$SYSTEM` is expected")]
MalformedBinaryTarball,
#[error(
"Could not find a supported command to create users in PATH; please install `useradd` or `adduser`"
)]
MissingUserCreationCommand,
#[error("Could not find a supported command to create groups in PATH; please install `groupadd` or `addgroup`")]
MissingGroupCreationCommand,
#[error("Could not find a supported command to add users to groups in PATH; please install `gpasswd` or `addgroup`")]
MissingAddUserToGroupCommand,
#[error(
"Could not find a supported command to delete users in PATH; please install `userdel` or `deluser`"
)]
MissingUserDeletionCommand,
#[error("Could not find a supported command to delete groups in PATH; please install `groupdel` or `delgroup`")]
MissingGroupDeletionCommand,
#[error("Could not find a supported command to remove users from groups in PATH; please install `gpasswd` or `deluser`")]
MissingRemoveUserFromGroupCommand,
}
impl ActionError {