Add SSH config validation

This commit is contained in:
0xf8 2023-05-30 10:13:42 -04:00
parent 543e98faaf
commit 937a4c9010
Signed by: 0xf8
GPG Key ID: 446580D758689584
5 changed files with 234 additions and 15 deletions

218
Cargo.lock generated
View File

@ -14,6 +14,17 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8ebf5827e4ac4fd5946560e6a99776ea73b596d80898f357007317a7141e47" checksum = "3f8ebf5827e4ac4fd5946560e6a99776ea73b596d80898f357007317a7141e47"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -38,6 +49,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.9.0" version = "0.9.0"
@ -62,6 +79,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]] [[package]]
name = "cassowary" name = "cassowary"
version = "0.3.0" version = "0.3.0"
@ -80,6 +103,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.7" version = "0.15.7"
@ -188,13 +222,33 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys 0.3.7",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "5.0.1" version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [ dependencies = [
"dirs-sys", "dirs-sys 0.4.1",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
"winapi",
] ]
[[package]] [[package]]
@ -333,7 +387,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15d14128f06405808ce75bfebe11e9b0f9da18719ede6d7bdb1702d6bfe0f7e8" checksum = "15d14128f06405808ce75bfebe11e9b0f9da18719ede6d7bdb1702d6bfe0f7e8"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"byteorder", "byteorder",
"num_enum", "num_enum",
"serde", "serde",
@ -398,6 +452,15 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.1" version = "0.3.1"
@ -438,7 +501,7 @@ 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 = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.1",
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -449,12 +512,15 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argparse", "argparse",
"colored",
"dialoguer", "dialoguer",
"dirs", "dirs 5.0.1",
"flexbuffers", "flexbuffers",
"mktemp", "mktemp",
"openssh",
"serde", "serde",
"ssh-key", "ssh-key",
"ssh2-config",
"termion 2.0.1", "termion 2.0.1",
"toml", "toml",
"tui", "tui",
@ -493,6 +559,17 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mio"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eebffdb73fe72e917997fad08bdbf31ac50b0fa91cec93e69a0662e4264d454c"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "mktemp" name = "mktemp"
version = "0.5.0" version = "0.5.0"
@ -590,6 +667,22 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssh"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca6c277973fb549b36dd8980941b5ea3ecebea026f5b1f0060acde74d893c22"
dependencies = [
"dirs 4.0.0",
"libc",
"once_cell",
"shell-escape",
"tempfile",
"thiserror",
"tokio",
"tokio-pipe",
]
[[package]] [[package]]
name = "option-ext" name = "option-ext"
version = "0.2.0" version = "0.2.0"
@ -627,6 +720,12 @@ dependencies = [
"base64ct", "base64ct",
] ]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]] [[package]]
name = "pkcs1" name = "pkcs1"
version = "0.4.1" version = "0.4.1"
@ -760,7 +859,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
] ]
[[package]] [[package]]
@ -769,7 +868,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
] ]
[[package]] [[package]]
@ -830,7 +929,7 @@ version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"errno", "errno",
"io-lifetimes", "io-lifetimes",
"libc", "libc",
@ -916,12 +1015,27 @@ dependencies = [
"digest 0.10.7", "digest 0.10.7",
] ]
[[package]]
name = "shell-escape"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
[[package]] [[package]]
name = "shell-words" name = "shell-words"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "signature" name = "signature"
version = "1.6.4" version = "1.6.4"
@ -938,6 +1052,16 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "socket2"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@ -986,6 +1110,18 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "ssh2-config"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31d9bb8e97972d6541ccf32ed51294e4e16feeef06a0e77a6272d041f0f5bc7"
dependencies = [
"bitflags 2.3.1",
"dirs 5.0.1",
"thiserror",
"wildmatch",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.5.0" version = "2.5.0"
@ -1081,6 +1217,44 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tokio"
version = "1.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
dependencies = [
"autocfg",
"bytes",
"libc",
"mio",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
]
[[package]]
name = "tokio-pipe"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784"
dependencies = [
"libc",
"tokio",
]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.7.4" version = "0.7.4"
@ -1121,7 +1295,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"cassowary", "cassowary",
"termion 1.5.6", "termion 1.5.6",
"unicode-segmentation", "unicode-segmentation",
@ -1179,6 +1353,34 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wildmatch"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.45.0" version = "0.45.0"

View File

@ -8,12 +8,15 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.71"
argparse = "0.2.2" argparse = "0.2.2"
colored = "2.0.0"
dialoguer = { version = "0.10.4", features = ["fuzzy-select"] } dialoguer = { version = "0.10.4", features = ["fuzzy-select"] }
dirs = "5.0.1" dirs = "5.0.1"
flexbuffers = "2.0.0" flexbuffers = "2.0.0"
mktemp = "0.5.0" mktemp = "0.5.0"
openssh = "0.9.9"
serde = { version = "1.0.163", features = ["derive"] } serde = { version = "1.0.163", features = ["derive"] }
ssh-key = { version = "0.5.1", features = ["rsa", "ed25519", "dsa", "p256", "p384"] } ssh-key = { version = "0.5.1", features = ["rsa", "ed25519", "dsa", "p256", "p384"] }
ssh2-config = "0.2.0"
termion = "2.0.1" termion = "2.0.1"
toml = "0.7.4" toml = "0.7.4"
tui = { version = "0.19.0", default-features = false, features = ["termion"] } tui = { version = "0.19.0", default-features = false, features = ["termion"] }

View File

@ -24,19 +24,18 @@ impl std::fmt::Display for Host {
} }
impl Host { impl Host {
// todo: validate ssh config
pub fn edit(&mut self) -> Result<Self> { pub fn edit(&mut self) -> Result<Self> {
let mut data = toml::to_string_pretty(self)?; let mut data = toml::to_string_pretty(self)?;
{ {
let t = mktemp::Temp::new_file().unwrap(); let t = mktemp::Temp::new_file().unwrap();
fs::write(t.to_owned(), data)?; fs::write(t.to_owned(), data)?;
let editor = std::env::var("EDITOR").expect("EDITOR is not set"); let editor = std::env::var("EDITOR").expect("EDITOR is not set");
std::process::Command::new(editor) std::process::Command::new(editor)
.arg(t.to_owned().to_string_lossy().to_string()) .arg(t.to_owned().to_string_lossy().to_string())
.spawn()?.wait()?; .spawn()?.wait()?;
data = fs::read_to_string(t)?; data = fs::read_to_string(t)?;
} }

View File

@ -22,7 +22,8 @@ fn main() -> Result<()> {
parser.add_option(&["-V", "--version"], argparse::Print(env!("CARGO_PKG_VERSION").to_string()), "Show version"); parser.add_option(&["-V", "--version"], argparse::Print(env!("CARGO_PKG_VERSION").to_string()), "Show version");
parser.refer(&mut search_path).add_option(&["-s", "--search"], argparse::StoreOption, "Search path for keys"); parser.refer(&mut search_path).add_option(&["-s", "--search"], argparse::StoreOption, "Search path for keys");
parser.refer(&mut config_root).add_option(&["-c", "--config"], argparse::StoreOption, "Path to keyman's config dir"); parser.refer(&mut config_root).add_option(&["-c", "--config"], argparse::StoreOption, "Path to keyman's config dir");
// todo: actual dryrun // TODO: actual dryrun
// TODO: add back option to disable alt screen
// parser.refer(&mut dry_run).add_option(&["-d", "--dry-run", "--dryrun"], argparse::StoreTrue, "Do a dry run"); // parser.refer(&mut dry_run).add_option(&["-d", "--dry-run", "--dryrun"], argparse::StoreTrue, "Do a dry run");
parser.parse_args_or_exit(); parser.parse_args_or_exit();

View File

@ -1,7 +1,9 @@
use anyhow::Result; use anyhow::Result;
use colored::Colorize;
use crate::{ ConfigManager, config::Host, input }; use crate::{ ConfigManager, config::Host, input };
use dialoguer::{ Select, Input, Confirm, Editor, theme::ColorfulTheme }; use dialoguer::{ Select, Input, Confirm, Editor, theme::ColorfulTheme };
use serde::{ Serialize, Deserialize }; use serde::{ Serialize, Deserialize };
use ssh2_config::{ SshConfig, ParseRule };
use ssh_key::PrivateKey; use ssh_key::PrivateKey;
use std::fs; use std::fs;
@ -74,7 +76,7 @@ Host {host}
// New host // New host
fn ssh_new_host(&self, config: &mut ConfigManager) -> Result<Host> { fn ssh_new_host(&self, config: &mut ConfigManager) -> Result<Host> {
println!("- Creating new host entry"); println!(" ## Creating new SSH host entry ## ");
let keyid = input::get_key(config, self.to_owned())?; let keyid = input::get_key(config, self.to_owned())?;
let userhost = loop { let userhost = loop {
@ -86,7 +88,7 @@ Host {host}
let split: Vec<String> = split.map(|a| a.to_string()).collect(); let split: Vec<String> = split.map(|a| a.to_string()).collect();
if split.len() < 2 { if split.len() < 2 {
println!("Incorrect user@host given. Example: paul@example.com:34; <user>@<host>[:port]"); println!("{} Example: paul@example.com:34 - <user>@<host>[:port]", "Incorrect user@host given.".red());
} else { } else {
break split break split
} }
@ -170,10 +172,22 @@ Host {host}
// if let Some(cnf) = Editor::new().edit(fs::read_to_string(config.config_dir.join("config"))?.as_str())? { // if let Some(cnf) = Editor::new().edit(fs::read_to_string(config.config_dir.join("config"))?.as_str())? {
// fs::write(config.config_dir.join("config"), cnf)?; // fs::write(config.config_dir.join("config"), cnf)?;
// } // }
let t = mktemp::Temp::new_file()?;
fs::copy(&host.config, &t)?;
let editor = std::env::var("EDITOR").expect("EDITOR is not set"); let editor = std::env::var("EDITOR").expect("EDITOR is not set");
std::process::Command::new(editor) std::process::Command::new(editor)
.arg(host.config.to_owned()) .arg(&t.to_str().unwrap())
.spawn()?.wait()?; .spawn()?.wait()?;
let mut file = std::io::BufReader::new(fs::File::open(&t).expect(&format!("Couldn't open config ({})", &host.config)));
match SshConfig::default().parse(&mut file, ParseRule::STRICT) {
Ok(_) => {
println!(" ## {} ## ", "Config OK".green());
fs::copy(&t, &host.config)?;
},
Err(e) => println!(" ## {}: {} ## ", "Rejecting config".red(), e),
}
} }
2 => { // Edit definition 2 => { // Edit definition
let edited_host = host.edit()?; let edited_host = host.edit()?;