Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions crates/nac-core/src/sandbox/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,27 @@ printf '%s%s' "$base" "$suffix"
cmd: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
) -> (PtyCommandBuilder, Option<String>) {
self.pty_command(cmd, cwd, envs, false)
}

/// Prepares transparent human input on the selected backend. Admission is
/// deliberately separate: unqualified SSH/Podman remain unavailable.
pub(crate) fn user_terminal_pty_command(
&self,
cmd: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
) -> (PtyCommandBuilder, Option<String>) {
self.pty_command(cmd, cwd, envs, true)
}

fn pty_command(
&self,
cmd: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
human: bool,
) -> (PtyCommandBuilder, Option<String>) {
let (mut command, pidfile) = match self {
Self::Local { .. } => {
Expand All @@ -280,10 +301,10 @@ printf '%s%s' "$base" "$suffix"
(command, None)
}
Self::Sandbox(session) => {
let (cmd, pidfile) = session.terminal_pty_command(cmd, cwd, envs);
let (cmd, pidfile) = session.pty_command(cmd, cwd, envs, human);
(cmd, Some(pidfile))
}
Self::Ssh(ssh) => ssh.terminal_pty_command(cmd, cwd, envs),
Self::Ssh(ssh) => ssh.terminal_pty_command(cmd, cwd, envs, human),
};
remove_native_integration_credentials_from_pty(&mut command);
(command, pidfile)
Expand Down
16 changes: 15 additions & 1 deletion crates/nac-core/src/sandbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,19 @@ impl SandboxSession {
cmd: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
) -> (PtyCommandBuilder, String) {
self.pty_command(cmd, cwd, envs, false)
}

pub(crate) fn pty_command(
&self,
cmd: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
human: bool,
) -> (PtyCommandBuilder, String) {
match self {
Self::Podman(inner) => inner.terminal_pty_command(cmd, cwd, envs),
Self::Podman(inner) => inner.terminal_pty_command(cmd, cwd, envs, human),
}
}

Expand Down Expand Up @@ -1081,3 +1091,7 @@ mod tests {
let _ = std::fs::remove_dir_all(root);
}
}

#[cfg(test)]
#[path = "remote_pty_tests.rs"]
mod remote_pty_tests;
22 changes: 17 additions & 5 deletions crates/nac-core/src/sandbox/podman.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,18 @@ for child in $(group_members); do
done
rm -f "$pidfile"
exit "$status"'
if command -v setsid >/dev/null 2>&1 && setsid -w true >/dev/null 2>&1; then
# A PTY already has a controlling session. Forking into setsid would lose it;
# the monitor/foreground path preserves terminal ownership for all PTYs.
if [ "${3:-}" != pty ] && command -v setsid >/dev/null 2>&1 && setsid -w true >/dev/null 2>&1; then
exec setsid -w bash -c "$supervisor" nac-supervisor "$1" "$2"
else
set -m
bash -c "$supervisor" nac-supervisor "$1" "$2" &
supervisor_pid=$!
if [ "${3:-}" = pty ]; then
fg %1 >/dev/null 2>/dev/null
# Bash uses stderr for foreground terminal ownership. Redirecting it to
# /dev/null silently leaves the supervisor stopped in a background group.
fg %1 >/dev/null
else
wait "$supervisor_pid" 2>/dev/null
fi
Expand Down Expand Up @@ -221,7 +225,8 @@ if [ "$root_identity_state" = match ]; then
if [ ! -r "/proc/$pid/stat" ]; then
process_table=$(ps -eo pid=,ppid= 2>/dev/null || ps -ax -o pid= -o ppid= 2>/dev/null) || exit 1
fi
descendants() {
# Recursion must not overwrite its caller's parent/child/stat variables.
descendants() (
parent=$1
if [ -r "/proc/$pid/stat" ]; then
for stat in /proc/[0-9]*/stat; do
Expand All @@ -240,7 +245,7 @@ if [ "$root_identity_state" = match ]; then
printf '%s\n' "$child"
done
fi
}
)
pids=$(descendants "$pid")
uncertain=0
verified_descendants=
Expand Down Expand Up @@ -983,6 +988,7 @@ impl PodmanSession {
cmd_str: &str,
cwd: Option<&Path>,
envs: &[(String, String)],
human: bool,
) -> (PtyCommandBuilder, String) {
let pidfile = make_sandbox_pidfile();
let pty_args = vec![
Expand All @@ -994,7 +1000,13 @@ impl PodmanSession {
"pty".to_string(),
];
let mut cmd = PtyCommandBuilder::new("podman");
cmd.args(self.exec_args("bash", &pty_args, true, true, cwd, envs));
let mut args = self.exec_args("bash", &pty_args, true, true, cwd, envs);
if human {
// Human control bytes reach the program rather than detaching the
// owning transport. Model and non-PTY invocation defaults stay intact.
args.insert(1, OsString::from("--detach-keys="));
}
cmd.args(args);
(cmd, pidfile)
}

Expand Down
Loading
Loading