Skip to content

Commit

Permalink
su: reject repeated boolean flags
Browse files Browse the repository at this point in the history
  • Loading branch information
japaric authored and pvdrz committed Nov 2, 2023
1 parent 33aeaf4 commit 4aa086e
Showing 1 changed file with 35 additions and 5 deletions.
40 changes: 35 additions & 5 deletions src/su/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ impl SuOptions {
long: "login",
takes_argument: false,
set: |sudo_options, _| {
sudo_options.login = true;
if sudo_options.login {
return Err(more_than_once("--login"));
} else {
sudo_options.login = true;
}
Ok(())
},
},
Expand All @@ -109,7 +113,11 @@ impl SuOptions {
long: "preserve-environment",
takes_argument: false,
set: |sudo_options, _| {
sudo_options.preserve_environment = true;
if sudo_options.preserve_environment {
return Err(more_than_once("--preserve-environment"));
} else {
sudo_options.preserve_environment = true;
}
Ok(())
},
},
Expand Down Expand Up @@ -178,21 +186,27 @@ impl SuOptions {
];

pub fn from_env() -> Result<SuOptions, String> {
let args = std::env::args().collect();
let args = std::env::args();

Self::parse_arguments(args)
}

/// parse su arguments into SuOptions struct
pub(crate) fn parse_arguments(arguments: Vec<String>) -> Result<SuOptions, String> {
pub(crate) fn parse_arguments(
arguments: impl IntoIterator<Item = String>,
) -> Result<SuOptions, String> {
let mut options: SuOptions = SuOptions::default();
let mut arg_iter = arguments.into_iter().skip(1);

let mut first_positional_argument = true;
while let Some(arg) = arg_iter.next() {
// - or -l or --login indicates a login shell should be started
if arg == "-" {
options.login = true;
if options.login {
return Err(more_than_once("--login"));
} else {
options.login = true;
}
} else if arg == "--" {
// only positional arguments after this point
if let Some(next_arg) = arg_iter.next() {
Expand Down Expand Up @@ -276,6 +290,10 @@ impl SuOptions {
}
}

fn more_than_once(flag: &str) -> String {
format!("argument '{flag}' was provided more than once, but cannot be used multiple times")
}

#[cfg(test)]
mod tests {
use std::vec;
Expand Down Expand Up @@ -543,4 +561,16 @@ mod tests {
};
assert_eq!(expected, parse(&["--", "ferris", "-c", "echo"]));
}

#[test]
fn repeated_boolean_flag() {
let f = |s: &str| s.to_string();

assert!(SuOptions::parse_arguments(["su", "-l", "-l"].map(f)).is_err());
assert!(SuOptions::parse_arguments(["su", "-", "-l"].map(f)).is_err());
assert!(SuOptions::parse_arguments(["su", "--login", "-l"].map(f)).is_err());

assert!(SuOptions::parse_arguments(["su", "-p", "-p"].map(f)).is_err());
assert!(SuOptions::parse_arguments(["su", "-p", "--preserve-environment"].map(f)).is_err());
}
}

0 comments on commit 4aa086e

Please sign in to comment.