commit 030bbcc10020e3e0c73161d2ce2bf42f29ef4b29 Author: Miraty Date: Sat Jan 23 19:51:20 2021 +0100 Initial commit diff --git a/Cargo.lock b/Cargo.lock new file mode 100755 index 0000000..e5e9b04 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,116 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[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]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" + +[[package]] +name = "maniver" +version = "0.1.0-dev" +dependencies = [ + "colored", + "regex", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "regex" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" + +[[package]] +name = "thread_local" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" +dependencies = [ + "lazy_static", +] + +[[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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..a618b26 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "maniver" +version = "0.1.0-dev" +authors = ["Miraty "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1" +colored = "2" diff --git a/src/main.rs b/src/main.rs new file mode 100755 index 0000000..721b077 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,262 @@ +use std::env; +use regex::Regex; +use std::io::prelude::*; +use std::process::{Command, Stdio}; +use colored::*; +use std::fs; + +fn main() { + let args: Vec = env::args().collect(); + + let tool = args[1].to_string(); + match tool.as_ref() { + "setup-user" => setup_user(args[2].to_string(), args[3].to_string()), + "reload-nginx" => reload_nginx(), + "reload-tor" => reload_tor(), + "le-install" => le_install(args[2].to_string()), + "export-tor" => export_tor(args[2].to_string(), args[3].to_string()), + _ => println!("{}{}{}{}\n{}{}{}{}{}{}{}{}{}", "maniver : ", "ERREUR : ".red(), tool.red(), " : argument non reconnu".red(), " > Utilisez ", "setup-user ".italic().green(), ", ", "reload-nginx".italic().green(), ", ", "reload-tor".italic().green(), " ou ", "le-install ".italic().green(), " comme argument"), + } + +} + +fn export_tor(username: String, dir: String) { + + let mut src_path: String = "/var/lib/tor/niver/".to_owned(); + src_path += &dir.to_string(); + src_path += &"/hostname".to_string().to_owned(); + + let mut dest_path: String = "/srv/hyper/".to_owned(); + dest_path += &username.to_string(); + dest_path += &"/hyper/".to_string().to_owned(); + dest_path += &dir.to_string(); + dest_path += &"/hostname".to_string().to_owned(); + + match fs::copy(src_path, &dest_path) { + Err(why) => panic!("Erreur lors d'une copie de fichier (fs::copy) : {}", why), + Ok(process) => process, + }; + + let output = Command::new("/usr/bin/chown") + .arg("www-data:www-data") + .arg(dest_path) + .output() + .expect("failed to execute process"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + assert!(output.status.success()); + + //let output = Command::new("/usr/bin/cp") + // .arg(src_path) + // .arg(dest_path) + // .output() + // .expect("failed to execute process"); + + //println!("status: {}", output.status); + //println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + //println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + //assert!(output.status.success()); + +} + +fn le_install(domain: String) { + + let output = Command::new("/usr/bin/certbot") + .arg("--nginx") + .arg("-d") + .arg(&domain) + .output() + .expect("failed to execute process"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); + +} + +fn reload_nginx() { + + let output = Command::new("/usr/bin/systemctl") + .arg("reload") + .arg("nginx") + .output() + .expect("Error while reloading Nginx config"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); +} + +fn reload_tor() { + + Command::new("/usr/bin/systemctl") + .arg("reload") + .arg("tor@default") + .output() + .expect("Error while reloading Tor config"); + + //let output = Command::new("/usr/bin/chown") + // .arg("-R") + // .arg("www-data:www-data") + // .arg("/var/lib/tor/niver") + // .output() + // .expect("failed to execute process"); + + //println!("status: {}", output.status); + //println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + //println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + //assert!(output.status.success()); + +} + +fn setup_user(username: String, password: String) { + + if username.chars().count() < 32 { + if password.chars().count() < 1024 { + if is_string_lowercase(username.to_string()) { + + let username1 = &username; + let username2 = &username; + let username3 = &username; + let username4 = &username; + newser(username1.to_string()); + pwd(username2.to_string(), password); + chroot(username3.to_string()); + quota(username4.to_string()); + + } else { + println!("Erreur : l'username doit être composé de lettres minuscules uniquement"); + } + } else { + println!("Erreur : le mot de passe doit faire moins de 1024 caractères"); + } + } else { + println!("Erreur : l'username doit faire moins de 32 caractères"); + } + +} + +// Set disk usage limit to the user by copying another user quota +fn quota(username: String) { + + let output = Command::new("/usr/sbin/edquota") + .arg("-p") + .arg("testfract") + .arg(&username) + .output() + .expect("failed to execute process"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); + +} + +// Chown /srv/hyper/username to root:root +fn chroot(username: String) { + + if username.chars().count() < 32 { + + let mut path = "/srv/hyper/".to_string(); + + path += &username; + + let output = Command::new("/usr/bin/chown") + .arg("root:root") + .arg(&path) + .output() + .expect("Failed to chown /srv/hyper/ to root:root"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + assert!(output.status.success()); + + let output = Command::new("/usr/bin/chmod") + .arg("755") + .arg(path) + .output() + .expect("Failed to chmod /srv/hyper/ to 755"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + assert!(output.status.success()); + + } else { + println!("Erreur : l'username doit faire moins de 32 caractères"); + } + +} + +// Creates a new user in the group 'hyper', which is available only over SFTP +fn newser(username: String) { + + let output = Command::new("/usr/sbin/useradd") + .arg(&username) + .arg("--create-home") + .arg("--base-dir") + .arg("/srv/hyper") + .arg("--gid") + .arg("hyper") + .arg("--shell") + .arg("/usr/sbin/nologin") + .output() + .expect("failed to execute process"); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); + +} + +// Changes password of the newly created user +fn pwd(username: String, password: String) { + + // line must be in the form username:password + let mut line: String = username.to_string(); + line += &":".to_string().to_owned(); + line += &password.to_owned(); + + let process = match Command::new("/usr/sbin/chpasswd") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() { + Err(why) => panic!("couldn't spawn chpasswd: {}", why), + Ok(process) => process, + }; + + match process.stdin.unwrap().write_all(line.as_bytes()) { + Err(why) => panic!("couldn't write to chpasswd stdin: {}", why), + Ok(_) => println!("sent username:password to chpasswd"), + } + + let mut s = String::new(); + match process.stdout.unwrap().read_to_string(&mut s) { + Err(why) => panic!("couldn't read chpasswd stdout: {}", why), + Ok(_) => print!("chpasswd responded with:\n{}", s), + } + +} + +fn is_string_lowercase(stri: String) -> bool { + + let re = Regex::new("^[[:lower:]]+$").unwrap(); + let matching = re.is_match(&stri); + if matching { + return true; + } else { + return false; + } + +}