Skip to content

Commit

Permalink
Explicitly tell visudo which editor to use
Browse files Browse the repository at this point in the history
On FreeBSD sudo doesn't use /usr/bin/editor as default editor.
  • Loading branch information
bjorn3 committed Dec 9, 2024
1 parent b126a0c commit a24130d
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 369 deletions.
199 changes: 94 additions & 105 deletions test-framework/sudo-compliance-tests/src/visudo.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{thread, time::Duration};

use sudo_test::EnvBuilder;
use sudo_test::{
helpers::assert_ls_output, Command, Env, TextFile, ETC_DIR, ETC_SUDOERS, ROOT_GROUP,
};
Expand Down Expand Up @@ -38,20 +39,26 @@ const CHMOD_EXEC: &str = "100";
const EDITOR_TRUE: &str = "#!/bin/sh
true";

fn visudo_env(sudoers: impl Into<TextFile>, editor: impl Into<TextFile>) -> EnvBuilder {
let mut env = Env(sudoers);
env.file(DEFAULT_EDITOR, editor)
.env("EDITOR", DEFAULT_EDITOR);
env
}

#[test]
fn default_editor_is_usr_bin_editor() -> Result<()> {
let expected = "default editor was called";
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(format!(
"#!/bin/sh
let env = visudo_env(
"",
TextFile(format!(
"#!/bin/sh
echo '{expected}' > {LOGS_PATH}"
))
.chmod(CHMOD_EXEC),
)
.build()?;
))
.chmod(CHMOD_EXEC),
)
.build()?;

Command::new("visudo").output(&env)?.assert_success()?;

Expand All @@ -64,9 +71,7 @@ echo '{expected}' > {LOGS_PATH}"

#[test]
fn creates_sudoers_file_with_default_ownership_and_perms_if_it_doesnt_exist() -> Result<()> {
let env = Env("")
.file(DEFAULT_EDITOR, TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC))
.build()?;
let env = visudo_env("", TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC)).build()?;

Command::new("rm")
.args(["-f", ETC_SUDOERS])
Expand All @@ -87,16 +92,15 @@ fn creates_sudoers_file_with_default_ownership_and_perms_if_it_doesnt_exist() ->

#[test]
fn errors_if_currently_being_edited() -> Result<()> {
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
"",
TextFile(
"#!/bin/sh
sleep 3",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let child = Command::new("visudo").spawn(&env)?;

Expand All @@ -119,16 +123,15 @@ sleep 3",

#[test]
fn passes_temporary_file_to_editor() -> Result<()> {
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(format!(
r#"#!/bin/sh
let env = visudo_env(
"",
TextFile(format!(
r#"#!/bin/sh
echo "$@" > {LOGS_PATH}"#
))
.chmod(CHMOD_EXEC),
)
.build()?;
))
.chmod(CHMOD_EXEC),
)
.build()?;

Command::new("visudo").output(&env)?.assert_success()?;

Expand Down Expand Up @@ -157,9 +160,7 @@ ls -l /tmp/sudoers-*/sudoers > {LOGS_PATH}"#
)
};

let env = Env("")
.file(DEFAULT_EDITOR, TextFile(editor_script).chmod(CHMOD_EXEC))
.build()?;
let env = visudo_env("", TextFile(editor_script).chmod(CHMOD_EXEC)).build()?;

Command::new("visudo").output(&env)?.assert_success()?;

Expand All @@ -173,16 +174,15 @@ ls -l /tmp/sudoers-*/sudoers > {LOGS_PATH}"#
#[test]
fn saves_file_if_no_syntax_errors() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(format!(
r#"#!/bin/sh
let env = visudo_env(
"",
TextFile(format!(
r#"#!/bin/sh
echo '{expected}' >> $2"#
))
.chmod("100"),
)
.build()?;
))
.chmod("100"),
)
.build()?;

Command::new("rm")
.args(["-f", ETC_SUDOERS])
Expand All @@ -204,9 +204,7 @@ echo '{expected}' >> $2"#
#[test]
fn stderr_message_when_file_is_not_modified() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(expected)
.file(DEFAULT_EDITOR, TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC))
.build()?;
let env = visudo_env(expected, TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC)).build()?;

let output = Command::new("visudo").output(&env)?;

Expand Down Expand Up @@ -234,17 +232,16 @@ fn stderr_message_when_file_is_not_modified() -> Result<()> {
#[test]
fn does_not_save_the_file_if_there_are_syntax_errors() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(expected)
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
expected,
TextFile(
"#!/bin/sh
echo 'this is fine' > $2",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let output = Command::new("visudo").output(&env)?;

Expand All @@ -264,16 +261,15 @@ echo 'this is fine' > $2",
#[test]
fn editor_exits_with_a_nonzero_code() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(SUDOERS_ALL_ALL_NOPASSWD)
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
SUDOERS_ALL_ALL_NOPASSWD,
TextFile(
"#!/bin/sh
exit 11",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let output = Command::new("visudo").output(&env)?;

Expand All @@ -291,16 +287,15 @@ exit 11",

#[test]
fn temporary_file_is_deleted_during_edition() -> Result<()> {
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
"",
TextFile(
"#!/bin/sh
rm $2",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let output = Command::new("visudo").output(&env)?;

Expand All @@ -322,16 +317,15 @@ rm $2",
#[test]
fn temp_file_initial_contents() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(expected)
.file(
DEFAULT_EDITOR,
TextFile(format!(
"#!/bin/sh
let env = visudo_env(
expected,
TextFile(format!(
"#!/bin/sh
cp $2 {LOGS_PATH}"
))
.chmod(CHMOD_EXEC),
)
.build()?;
))
.chmod(CHMOD_EXEC),
)
.build()?;

Command::new("visudo").output(&env)?.assert_success()?;

Expand All @@ -345,9 +339,7 @@ cp $2 {LOGS_PATH}"
#[test]
fn temporary_file_is_deleted_when_done() -> Result<()> {
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(expected)
.file(DEFAULT_EDITOR, TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC))
.build()?;
let env = visudo_env(expected, TextFile(EDITOR_TRUE).chmod(CHMOD_EXEC)).build()?;

Command::new("visudo").output(&env)?.assert_success()?;

Expand All @@ -365,18 +357,17 @@ fn temporary_file_is_deleted_when_done() -> Result<()> {
fn temporary_file_is_deleted_when_terminated_by_signal() -> Result<()> {
let kill_visudo = "/root/kill-visudo.sh";
let expected = SUDOERS_ALL_ALL_NOPASSWD;
let env = Env(expected)
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
expected,
TextFile(
"#!/bin/sh
touch /tmp/barrier
sleep 2",
)
.chmod(CHMOD_EXEC),
)
.file(kill_visudo, include_str!("visudo/kill-visudo.sh"))
.build()?;
.chmod(CHMOD_EXEC),
)
.file(kill_visudo, include_str!("visudo/kill-visudo.sh"))
.build()?;

let child = Command::new("visudo").spawn(&env)?;

Expand All @@ -399,17 +390,16 @@ sleep 2",

#[test]
fn does_not_panic_on_io_errors_parse_ok() -> Result<()> {
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
"",
TextFile(
"#!/bin/sh
echo ' ' >> $2",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let output = Command::new("bash")
.args(["-c", "visudo | true; echo \"${PIPESTATUS[0]}\""])
Expand All @@ -427,17 +417,16 @@ echo ' ' >> $2",

#[test]
fn does_not_panic_on_io_errors_parse_error() -> Result<()> {
let env = Env("")
.file(
DEFAULT_EDITOR,
TextFile(
"#!/bin/sh
let env = visudo_env(
"",
TextFile(
"#!/bin/sh
echo 'bad syntax' >> $2",
)
.chmod(CHMOD_EXEC),
)
.build()?;
.chmod(CHMOD_EXEC),
)
.build()?;

let output = Command::new("bash")
.args(["-c", "visudo | true; echo \"${PIPESTATUS[0]}\""])
Expand Down
Loading

0 comments on commit a24130d

Please sign in to comment.