servnest
/
maniver
Archived
2
0
Fork 0
This repository has been archived on 2022-10-07. You can view files and clone it, but cannot push or open issues or pull requests.
maniver/src/main.rs

246 lines
7.3 KiB
Rust
Executable File

use std::env;
use regex::Regex;
use std::io::prelude::*;
use std::process::{Command, Stdio, Output};
use std::fs;
use users::get_current_username;
use std::ffi::OsString;
fn exit(error: String) {
eprintln!("Error: {}", error);
std::process::exit(0);
}
fn main() {
let superuser = OsString::from("root");
match get_current_username() {
Some(user) => match user {
_ if user == superuser => println!("root: right user"),
_ => exit("must be run as root".to_string()),
}
None => exit("the current user does not exist".to_string()),
}
let args: Vec<String> = env::args().collect();
match args[1].as_ref() {
"setup-user" => setup_user(args[2].to_string(), args[3].to_string()),
"reload-nginx" => reload_nginx(),
"reload-tor" => reload_tor(),
"restart-gmnisrv" => restart_gmnisrv(),
"le-install" => le_install(args[2].to_string()),
"export-tor" => export_tor(args[2].to_string(), args[3].to_string()),
_ => println!("ERROR: You must specify a subcommand"),
}
}
fn export_tor(username: String, dir: String) {
if is_string_lowercase(username.to_string()) {
if is_string_lowercase(dir.to_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");
print_output(output);
} else {
println!("ERROR: The dirname must be composed only of lowercase letters");
}
} else {
println!("ERROR: The username must be composed only of lowercase letters");
}
}
fn le_install(domain: String) {
let output = Command::new("/usr/bin/certbot")
.arg("--nginx")
// Using ECDSA
.arg("--key-type")
.arg("ecdsa")
.arg("--elliptic-curve")
.arg("secp384r1")
// Using RSA
//.arg("--key-type")
//.arg("rsa")
//.arg("--rsa-key-size")
//.arg("3072")
.arg("-d")
.arg(&domain)
.output()
.expect("failed to execute process");
print_output(output);
}
fn reload_nginx() {
let output = Command::new("/usr/bin/systemctl")
.arg("reload")
.arg("nginx")
.output()
.expect("Error while reloading Nginx config");
print_output(output);
}
fn reload_tor() {
let output = Command::new("/usr/bin/systemctl")
.arg("reload")
.arg("tor@default")
.output()
.expect("Error while reloading Tor config");
print_output(output);
}
fn restart_gmnisrv() {
let output = Command::new("/usr/bin/systemctl")
.arg("restart")
.arg("gmnisrv")
.output()
.expect("Error while restarting Gmnisrv");
print_output(output);
}
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!("ERROR: The dirname must be composed only of lowercase letters");
}
} else {
println!("ERROR: The password must be shorter than 1024 characters");
}
} else {
println!("ERROR: The username must be shorter than 32 characters");
}
}
// 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");
print_output(output);
}
// 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/<username> to root:root");
print_output(output);
let output = Command::new("/usr/bin/chmod")
.arg("755")
.arg(path)
.output()
.expect("Failed to chmod /srv/hyper/<username> to 755");
print_output(output);
} 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");
print_output(output);
}
// 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;
}
}
fn print_output(output: Output) {
println!("status: {}", output.status);
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
assert!(output.status.success());
}