forked from lix-project/lix-installer
Support busybox user/group modification, more informational errors (#319)
This commit is contained in:
parent
51056b854a
commit
32dca2e846
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -360,6 +360,12 @@ version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.32"
|
version = "0.8.32"
|
||||||
|
@ -980,6 +986,7 @@ dependencies = [
|
||||||
"typetag",
|
"typetag",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"which",
|
||||||
"xz2",
|
"xz2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2068,6 +2075,17 @@ dependencies = [
|
||||||
"webpki",
|
"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]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
|
@ -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 }
|
is_ci = { version = "1.1.1", default-features = false, optional = true }
|
||||||
strum = { version = "0.24.1", features = ["derive"] }
|
strum = { version = "0.24.1", features = ["derive"] }
|
||||||
nix-config-parser = { version = "0.1.2", features = ["serde"] }
|
nix-config-parser = { version = "0.1.2", features = ["serde"] }
|
||||||
|
which = "4.4.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] }
|
eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] }
|
||||||
|
|
|
@ -202,14 +202,26 @@ impl Action for AddUserToGroup {
|
||||||
.await?;
|
.await?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(
|
if which::which("gpasswd").is_ok() {
|
||||||
Command::new("gpasswd")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("gpasswd")
|
||||||
.args(["-a"])
|
.process_group(0)
|
||||||
.args([&name.to_string(), &groupname.to_string()])
|
.args(["-a"])
|
||||||
.stdin(std::process::Stdio::null()),
|
.args([name, groupname])
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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?;
|
.await?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(
|
if which::which("gpasswd").is_ok() {
|
||||||
Command::new("gpasswd")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("gpasswd")
|
||||||
.args(["-d"])
|
.process_group(0)
|
||||||
.args([&name.to_string(), &groupname.to_string()])
|
.args(["-d"])
|
||||||
.stdin(std::process::Stdio::null()),
|
.args([&name.to_string(), &groupname.to_string()])
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -92,20 +92,32 @@ impl Action for CreateGroup {
|
||||||
"Nix build group for nix-daemon",
|
"Nix build group for nix-daemon",
|
||||||
"-i",
|
"-i",
|
||||||
&format!("{gid}"),
|
&format!("{gid}"),
|
||||||
name.as_str(),
|
name,
|
||||||
])
|
])
|
||||||
.stdin(std::process::Stdio::null()),
|
.stdin(std::process::Stdio::null()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(
|
if which::which("groupadd").is_ok() {
|
||||||
Command::new("groupadd")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("groupadd")
|
||||||
.args(["-g", &gid.to_string(), "--system", &name])
|
.process_group(0)
|
||||||
.stdin(std::process::Stdio::null()),
|
.args(["-g", &gid.to_string(), "--system", name])
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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() {}
|
if !output.status.success() {}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(
|
if which::which("groupdel").is_ok() {
|
||||||
Command::new("groupdel")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("groupdel")
|
||||||
.arg(&name)
|
.process_group(0)
|
||||||
.stdin(std::process::Stdio::null()),
|
.arg(name)
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ impl Action for CreateUser {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
uid,
|
uid,
|
||||||
groupname: _,
|
groupname,
|
||||||
gid,
|
gid,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
@ -178,31 +178,57 @@ impl Action for CreateUser {
|
||||||
.await?;
|
.await?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
execute_command(
|
if which::which("useradd").is_ok() {
|
||||||
Command::new("useradd")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("useradd")
|
||||||
.args([
|
.process_group(0)
|
||||||
"--home-dir",
|
.args([
|
||||||
"/var/empty",
|
"--home-dir",
|
||||||
"--comment",
|
"/var/empty",
|
||||||
&format!("\"Nix build user\""),
|
"--comment",
|
||||||
"--gid",
|
"Nix build user",
|
||||||
&gid.to_string(),
|
"--gid",
|
||||||
"--groups",
|
&gid.to_string(),
|
||||||
&gid.to_string(),
|
"--groups",
|
||||||
"--no-user-group",
|
&gid.to_string(),
|
||||||
"--system",
|
"--no-user-group",
|
||||||
"--shell",
|
"--system",
|
||||||
"/sbin/nologin",
|
"--shell",
|
||||||
"--uid",
|
"/sbin/nologin",
|
||||||
&uid.to_string(),
|
"--uid",
|
||||||
"--password",
|
&uid.to_string(),
|
||||||
"\"!\"",
|
"--password",
|
||||||
&name.to_string(),
|
"!",
|
||||||
])
|
name,
|
||||||
.stdin(std::process::Stdio::null()),
|
])
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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(
|
if which::which("userdel").is_ok() {
|
||||||
Command::new("userdel")
|
execute_command(
|
||||||
.process_group(0)
|
Command::new("userdel")
|
||||||
.args([&name.to_string()])
|
.process_group(0)
|
||||||
.stdin(std::process::Stdio::null()),
|
.arg(name)
|
||||||
)
|
.stdin(std::process::Stdio::null()),
|
||||||
.await?;
|
)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
settings::CommonSettings,
|
settings::CommonSettings,
|
||||||
};
|
};
|
||||||
use tokio::task::JoinSet;
|
use tracing::{span, Span};
|
||||||
use tracing::{span, Instrument, Span};
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CreateUsersAndGroups {
|
pub struct CreateUsersAndGroups {
|
||||||
|
@ -266,37 +265,11 @@ impl Action for CreateUsersAndGroups {
|
||||||
nix_build_user_prefix: _,
|
nix_build_user_prefix: _,
|
||||||
nix_build_user_id_base: _,
|
nix_build_user_id_base: _,
|
||||||
} = self;
|
} = self;
|
||||||
let mut set = JoinSet::new();
|
for create_user in create_users.iter_mut() {
|
||||||
|
create_user
|
||||||
let mut errors = Vec::default();
|
.try_revert()
|
||||||
|
.await
|
||||||
for (idx, create_user) in create_users.iter().enumerate() {
|
.map_err(|e| ActionError::Child(create_user.action_tag(), Box::new(e)))?;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't actually need to do this, when a user is deleted they are removed from groups
|
// We don't actually need to do this, when a user is deleted they are removed from groups
|
||||||
|
|
|
@ -427,6 +427,22 @@ pub enum ActionError {
|
||||||
Plist(#[from] plist::Error),
|
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")]
|
#[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,
|
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 {
|
impl ActionError {
|
||||||
|
|
Loading…
Reference in a new issue