filepwn/src/main.rs
2024-03-17 23:18:14 +02:00

136 lines
4 KiB
Rust

use clap::Parser;
use std::fs::{self, DirEntry, FileType, ReadDir};
use std::collections::HashMap;
use std::num::ParseIntError;
use std::path::Path;
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
#[arg(short='P', long, help="Path to directory you want to be filepwn'd")]
path: String,
#[arg(short='u', long, help="name of user, as string")]
user: String,
#[arg(short='g', long, help="name of group, as string")]
group: String,
#[arg(short='f', long, help="File permissions, in octal")]
file_permissions: String,
#[arg(short='d', long, help="Directory permissions, in octal")]
directory_permissions: String
}
#[derive(Debug)]
enum ParserError {
FileError(std::io::Error),
UserIdError(String, ParseIntError)
}
impl From<std::io::Error> for ParserError {
fn from(value: std::io::Error) -> Self {
Self::FileError(value)
}
}
fn parse_etc_file(path: &str) -> Result<HashMap<String, u32>, ParserError> {
fs::read_to_string(path)?
.lines()
.filter(|line| !line.is_empty())
.map(|line| {
let line = line.to_owned();
let values = line
.split(':')
.collect::<Vec<&str>>();
let name = values[0].to_owned();
let id: u32 = match str::parse(values[2]) {
Ok(id) => id,
Err(e) => return Err(ParserError::UserIdError(name, e))
};
Ok((name, id))
})
.collect()
}
#[cfg(debug_assertions)]
const PASSWD_PATH: &str = "passwd";
#[cfg(not(debug_assertions))]
const PASSWD_PATH: &str = "/etc/passwd";
#[cfg(debug_assertions)]
const GROUP_PATH: &str = "group";
#[cfg(not(debug_assertions))]
const GROUP_PATH: &str = "/etc/group";
fn traverse_filesystem(path: &Path) -> (Vec<String>, Vec<String>){
let mut files: Vec<String> = Vec::new();
let mut directories: Vec<String> = Vec::new();
let entries: Vec<DirEntry> = fs::read_dir(path)
.unwrap()
.filter_map(|f| f.ok())
.collect();
let mut entry_list: Vec<Vec<DirEntry>> = vec!{entries};
loop {
let drained: Vec<Vec<DirEntry>> = entry_list.drain(..).collect();
for entries in drained {
for entry in entries {
let path = match entry.path().canonicalize() {
Ok(path) => match path.to_str() {
Some(path) => path.to_owned(),
None => {
eprintln!("failed to convert {:?} into a string", path);
continue
}
},
Err(e) => {
eprintln!("failed to get absolute path: {e}");
continue;
}
};
let file_type = match entry.file_type() {
Ok(file_type) => file_type,
Err(e) => {
eprintln!("error {} getting file type for {}", e, path);
continue;
}
};
if file_type.is_file() {
files.push(path);
} else if file_type.is_dir() {
let entries: Vec<DirEntry> = fs::read_dir(&path)
.unwrap()
.filter_map(|f| f.ok())
.collect();
entry_list.push(entries);
directories.push(path);
}
}
}
if entry_list.is_empty() {
break;
}
}
(files, directories)
}
fn main() {
let args = Args::parse();
let users = parse_etc_file(PASSWD_PATH)
.expect("failed to parse passwd file");
let groups = parse_etc_file(GROUP_PATH)
.expect("failed to parse group file");
let uid = users.get(&args.user).expect("user not found");
let gid = groups.get(&args.group).expect("group not found");
dbg!(traverse_filesystem(Path::new(&args.path)));
}