From 840e3904812dbf5d1172f0d1cde0f27aa2ac12e2 Mon Sep 17 00:00:00 2001 From: Dongsu Park Date: Tue, 24 Oct 2023 12:27:35 +0200 Subject: [PATCH 1/2] Cargo: update clap from 2 to 4 Update clap from 2.34.0 to 4.4.6, because clap both 2 and 3 rely on an unmaintained lib atty, which causes security issues. https://github.com/flatcar/update-ssh-keys/security/dependabot/3 To do that, it is required to turn on `cargo` features of clap, because clap 4 does not expose macros like crate_version by default. --- Cargo.lock | 188 ++++++++++++++++++++++++++++++++++++++--------------- Cargo.toml | 3 +- 2 files changed, 136 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9e965e..c0fc062 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,36 +3,58 @@ version = 3 [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anstream" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", ] [[package]] -name = "atty" -version = "0.2.14" +name = "anstyle" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "utf8parse", ] [[package]] -name = "base64" -version = "0.13.1" +name = "anstyle-query" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "block-buffer" @@ -57,19 +79,37 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "2.34.0" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ - "ansi_term", - "atty", - "bitflags", + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", "strsim", - "textwrap", - "unicode-width", - "vec_map", ] +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "cpufeatures" version = "0.2.5" @@ -128,15 +168,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "libc" version = "0.2.137" @@ -195,9 +226,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" @@ -210,15 +241,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.37" @@ -251,12 +273,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "update-ssh-keys" version = "0.4.2-alpha.0" @@ -278,10 +294,10 @@ dependencies = [ ] [[package]] -name = "vec_map" -version = "0.8.2" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version_check" @@ -310,3 +326,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index 1ac2081..5ec6423 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,12 @@ description = "A tool for managing authorized SSH keys" version = "0.4.2-alpha.0" [dependencies] -# Private dependencies. -clap = "2.33" fs2 = "0.4" # Public dependencies, exposed through library API. error-chain = { version = "0.12", default-features = false } openssh-keys = { git = "https://github.com/pothos/openssh-keys", branch = "add-sk-keys" } users = "0.9" +clap = { version = "4.4.6", features = ["cargo"] } [[bin]] name = "update-ssh-keys" From ae822ccdf864e12c56e780b69d3553a760d78f87 Mon Sep 17 00:00:00 2001 From: Dongsu Park Date: Tue, 24 Oct 2023 12:27:38 +0200 Subject: [PATCH 2/2] migrate command-line interface to clap 4 Now that clap was updated from 2 to 4, we need to also migrate update-ssh-keys from clap 2 to 4, to build with clap 4. * Rename Command to UssCommand to resolve naming conflicts. * Explicitly use clap::crate_version, as required in clap 4. * Replace help() with help_template() as well as rewritten templates. * Replace Arg::with_name with Arg::new. * Replace Arg::multiple with Arg::num_args. * Replace Arg::value_of with Arg::get_one. * Replace Arg::values_of with Arg::get_many. * Replace matches.is_present with matches.contains_id. * Remove deprecated takes_value(). * Change argument type of short() to char. --- src/main.rs | 167 +++++++++++++++++++++++++--------------------------- 1 file changed, 79 insertions(+), 88 deletions(-) diff --git a/src/main.rs b/src/main.rs index 171ecef..534eed6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,6 @@ //! //! this command allows users of container linux to administer ssh keys -#[macro_use] extern crate clap; #[macro_use] extern crate error_chain; @@ -25,7 +24,7 @@ extern crate users; extern crate update_ssh_keys; -use clap::{App, Arg}; +use clap::{crate_version, Arg, Command}; use std::fs::File; use std::path::PathBuf; use update_ssh_keys::errors::*; @@ -36,11 +35,11 @@ use users::get_current_username; struct Config { user: String, ssh_dir: Option, - command: Command, + command: UssCommand, } #[derive(Clone, Debug)] -enum Command { +enum UssCommand { Add { name: String, force: bool, @@ -74,7 +73,7 @@ fn run() -> Result<()> { })?; match config.command { - Command::Add { + UssCommand::Add { name, force, replace, @@ -115,7 +114,7 @@ fn run() -> Result<()> { } } } - Command::Delete { name } => { + UssCommand::Delete { name } => { println!("Removing {}:", name); for key in aks.remove_keys(&name) { if let AuthorizedKeyEntry::Valid { ref key } = key { @@ -123,7 +122,7 @@ fn run() -> Result<()> { } } } - Command::Disable { name } => { + UssCommand::Disable { name } => { println!("Disabling {}:", name); for key in aks.disable_keys(&name) { if let AuthorizedKeyEntry::Valid { ref key } = key { @@ -131,7 +130,7 @@ fn run() -> Result<()> { } } } - Command::List => { + UssCommand::List => { let keys = aks.get_all_keys(); println!("All keys for {}:", config.user); for (name, keyset) in keys { @@ -143,7 +142,7 @@ fn run() -> Result<()> { } } } - Command::Sync => {} + UssCommand::Sync => {} } aks.write() @@ -156,6 +155,23 @@ fn run() -> Result<()> { Ok(()) } +pub const USS_TEMPLATE: &str = "\ +{name} +{usage-heading} {usage} + +{all-args} + +{about-with-newline}"; + +pub const ABOUT_TEXT: &str = "\ +This tool provides a consistent way for different systems to add ssh public +keys to a given user account, usually the default current user. +If -a, -A, -d, nor -D are provided then the authorized_keys file is simply +regenerated using the existing keys. + +With the -a option keys may be provided as files on the command line. If no +files are provided with the -a option the keys will be read from stdin."; + fn config() -> Result { // get the default user by figuring out the current user; if the current user // is root (or doesn't exist) then use 'core'. @@ -169,125 +185,100 @@ fn config() -> Result { }); // setup cli - let matches = App::new("update-ssh-keys") + let matches = Command::new("update-ssh-keys") .version(crate_version!()) - .help( - format!( - r#"Usage: update-ssh-keys [-l] [-u user] [-a name file1... | -d name] -Options: - -u USER Update the given user's authorized_keys file [{0}] - -a NAME Add the given keys, using the given name to identify them. - -A NAME Add the given keys, even if it was disabled with '-D' - -n When adding, don't replace an existing key with the given name. - -d NAME Delete keys identified by the given name. - -D NAME Disable the given set from being added with '-a' - -l List the names and number of keys currently installed. - -h This ;-) - -This tool provides a consistent way for different systems to add ssh public -keys to a given user account, usually the default current user. -If -a, -A, -d, nor -D are provided then the authorized_keys file is simply -regenerated using the existing keys. - -With the -a option keys may be provided as files on the command line. If no -files are provided with the -a option the keys will be read from stdin."#, - default_user - ) - .as_ref(), - ) + .help_template(USS_TEMPLATE) + .about(ABOUT_TEXT) + .arg(Arg::new("user").short('u').help(format!( + "Update the given user's authorized_keys file. [{}]", + default_user + ))) .arg( - Arg::with_name("user") - .short("u") - .help("Update the given user's authorized_keys file.") - .takes_value(true), - ) - .arg( - Arg::with_name("no-replace") - .short("n") + Arg::new("no-replace") + .short('n') .help("When adding, don't replace an existing key with the given name."), ) .arg( - Arg::with_name("list") - .short("l") + Arg::new("list") + .short('l') .help("List the names and number of keys currently installed."), ) .arg( - Arg::with_name("add") - .short("a") - .help("Add the given keys, using the given name to identify them.") - .takes_value(true), + Arg::new("add") + .short('a') + .help("Add the given keys, using the given name to identify them."), ) .arg( - Arg::with_name("add-force") - .short("A") - .help("Add the given keys, even if it was disabled with '-D'.") - .takes_value(true), + Arg::new("add-force") + .short('A') + .help("Add the given keys, even if it was disabled with '-D'."), ) .arg( - Arg::with_name("delete") - .short("d") - .help("Delete keys identified by the given name.") - .takes_value(true), + Arg::new("delete") + .short('d') + .help("Delete keys identified by the given name."), ) .arg( - Arg::with_name("disable") - .short("D") - .help("Disable the given set from being added with '-a'.") - .takes_value(true), + Arg::new("disable") + .short('D') + .help("Disable the given set from being added with '-a'."), ) .arg( - Arg::with_name("ssh_dir") - .short("s") + Arg::new("ssh_dir") + .short('s') .long("ssh-dir") - .takes_value(true) .help("location of the ssh configuration directory (defaults to ~/.ssh)"), ) - .arg(Arg::with_name("keys").multiple(true)) + .arg(Arg::new("keys").num_args(1..).help("path to key files")) .get_matches(); let command = matches - .value_of("add") - .map(|name| Command::Add { + .get_one::("add") + .map(|name| UssCommand::Add { name: name.into(), force: false, - replace: !matches.is_present("no-replace"), - stdin: !matches.is_present("keys"), + replace: !matches.contains_id("no-replace"), + stdin: !matches.contains_id("keys"), keyfiles: matches - .values_of("keys") + .get_many::("keys") .map(|vals| vals.map(|s| s.into()).collect::>()) .unwrap_or_default(), }) .or_else(|| { - matches.value_of("add-force").map(|name| Command::Add { - name: name.into(), - force: true, - replace: !matches.is_present("no-replace"), - stdin: !matches.is_present("keys"), - keyfiles: matches - .values_of("keys") - .map(|vals| vals.map(|s| s.into()).collect::>()) - .unwrap_or_default(), - }) + matches + .get_one::("add-force") + .map(|name| UssCommand::Add { + name: name.into(), + force: true, + replace: !matches.contains_id("no-replace"), + stdin: !matches.contains_id("keys"), + keyfiles: matches + .get_many::("keys") + .map(|vals| vals.map(|s| s.into()).collect::>()) + .unwrap_or_default(), + }) }) .or_else(|| { matches - .value_of("delete") - .map(|name| Command::Delete { name: name.into() }) + .get_one::("delete") + .map(|name| UssCommand::Delete { name: name.into() }) }) .or_else(|| { matches - .value_of("disable") - .map(|name| Command::Disable { name: name.into() }) + .get_one::("disable") + .map(|name| UssCommand::Disable { name: name.into() }) }) - .unwrap_or(if matches.is_present("list") { - Command::List + .unwrap_or(if matches.contains_id("list") { + UssCommand::List } else { - Command::Sync + UssCommand::Sync }); - let user = matches.value_of("user").map_or(default_user, String::from); + let user = matches + .get_one::("user") + .map_or(default_user, String::from); - let ssh_dir = matches.value_of("ssh_dir").map(PathBuf::from); + let ssh_dir = matches.get_one::("ssh_dir").map(PathBuf::from); Ok(Config { user,