diff options
Diffstat (limited to '')
-rw-r--r-- | src/auth.rs | 264 | ||||
-rw-r--r-- | src/flags.rs | 120 | ||||
-rw-r--r-- | src/help.rs | 10 | ||||
-rw-r--r-- | src/main.rs | 142 | ||||
-rw-r--r-- | src/persist.rs | 147 | ||||
-rw-r--r-- | src/secure.rs | 109 |
6 files changed, 555 insertions, 237 deletions
diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..99a8216 --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,264 @@ +use nix::unistd::{User, Group, Uid, Gid, self}; +use crate::persist; + + +pub struct Config { + pub permit: bool, + pub persist: bool, + pub nopass: bool, + pub user_uid: Option<Uid>, + pub user_gid: Option<Gid>, + pub privlaged_uid: Uid, +} + + +/// Returns a option containing the config ad the specific pile path. +/// This function will print out config syntax errors to the standard +/// output if it failes to parse certain lines. +/// #### Arguments +/// * `path` - The path to the config file +/// #### Returns +/// * `None` - If the config failed to load +/// * `Some(Vec<Config>)` - If the config was sucessfully parsed. +pub fn load_config_file(path: &str) -> Option<Vec<Config>> { + let file = match std::fs::read_to_string(path) { + Err(e) => { + eprintln!("{}: {}", &path, e); + return None + }, + Ok(data) => data + }; + + let mut configs = vec![]; + + for (line_num, line) in file.split("\n").enumerate() { + + let args: Vec<&str> = line.split(" ").collect(); + let len = args.len(); + + if line.starts_with("#") || line.trim() == "" { + continue; + } + + if len < 2 { + config_error(line_num, "Not enough arguments"); + continue; + } + + let permit = match args[0] { + "permit" => true, + "deny" => false, + _ => { + config_error(line_num, "The first argument must be `permit` or `deny"); + continue; + } + }; + + let (user_name, privlaged_name, name_index) = match args.iter().position(|&a| a == "as") { + Some(index) => { + if index != len - 2 { + config_error(line_num, "Target user not specified or to many arguments after `as`"); + continue; + } + (args[index-1].to_string(), args[index+1].to_string(), index-1) + }, + None => (args[len-1].to_string(), "root".to_string(), len-1) + }; + + let persist = args[1..name_index].contains(&"persist"); + + let nopass = args[1..name_index].contains(&"nopass"); + + + for &check in args[1..name_index].iter() { + match check { + "persist" => continue, + "nopass" => continue, + _ => { + config_error(line_num, &format!("Unexpected token `{}`", check)) + } + } + } + + + let (user_uid, user_gid) = + if user_name.starts_with(":") { + match get_gid_from_name(&user_name[1..]) { + Some(gid) => (None, Some(gid)), + None => { + config_error(line_num, &format!("Group `{}` does not exist", &user_name[1..])); + continue; + } + } + } else { + match get_uid_from_name(&user_name) { + Some(uid) => (Some(uid), None), + None => { + config_error(line_num, &format!("User `{}` does not exist", user_name)); + continue; + } + } + }; + + let privlaged_uid = match get_uid_from_name(&privlaged_name) { + Some(uid) => uid, + None => { + config_error(line_num, &format!("User `{}` does not exist", privlaged_name)); + continue; + } + }; + + configs.push(Config { + permit, + persist, + nopass, + user_uid, + user_gid, + privlaged_uid + }); + } + Some(configs) +} + + +/// Print a crab config error to the standard output +fn config_error(line_num: usize, message: &str) { + eprintln!("Error in config at line {}: {}", line_num, message); +} + + +/// Returns a Uid from a Users name +/// #### Arguments +/// * `name` - The name of the user +/// #### Returns +/// * `None` - If the user doesn't exist +/// * `Some(Gid)` - If the user exists +fn get_uid_from_name(name: &str) -> Option<Uid> { + return match User::from_name(name) { + Ok(result) => match result { + Some(data) => Some(data.uid), + None => None + }, + Err(_) => None + } +} + + +/// Returns a Uesrs name from a Uid +/// #### Arguments +/// * `uid` - The uid of the user +/// #### Returns +/// * `None` - If the user doesn't exist +/// * `Some(Gid)` - If the user exists +fn get_name_from_uid(uid: Uid) -> Option<String> { + return match User::from_uid(uid) { + Ok(result) => match result { + Some(data) => Some(data.name), + None => None + }, + Err(_) => None + } +} + + +/// Returns a Gid from a Groups name +/// #### Arguments +/// * `name` - The name of the group +/// #### Returns +/// * `None` - If the group doesn't exist +/// * `Some(Gid)` - If the group exists +fn get_gid_from_name(name: &str) -> Option<Gid> { + return match Group::from_name(name) { + Ok(result) => match result { + Some(data) => Some(data.gid), + None => None + }, + Err(_) => None + } +} + + +/// Returns a vector of group names of the groups the current effective uid is in +/// #### Returns +/// A vector of strings of the groups the user is in. If the vector is empty, +/// either the function coudn't retrieve the users groups, or the user is not in +/// any groups. +fn get_groups() -> Vec<Gid> { + let groups = match unistd::getgroups() { + Ok(data) => data, + Err(_) => return vec![] + }; + groups +} + + +/// Returns if the user is authorized given a sepcific config and user name. +/// #### Arguments +/// * `config` - A config struct contaning the authorization settings for crab +/// * `uid` - The uid to check is authorized +/// #### Returns +/// * `None` - If the uid is not authorized +/// * `Some(Config)` - If the uid is authorized, returns the specific index of the associated config +pub fn authorize(configs: &Vec<Config>, uid: Uid) -> Option<usize> { + let groups = get_groups(); + for (config_index, config) in configs.iter().enumerate() { + if config.user_gid.is_some() { + if groups.contains(&config.user_gid.unwrap()) { + if config.permit { + return Some(config_index) + } else { + return None + } + } + } else if config.user_uid.is_some() { + if config.user_uid.unwrap() == uid { + if config.permit { + return Some(config_index) + } else { + return None + } + } + } + } + None +} + + +/// Authenticates an authorized user for the current session. +/// If the user is already persisted, it will attempt to +/// read the persist file, and then skip authentication if +/// the is still persisted. +/// #### Arguments +/// * `config` - The config associated with the user to authenticate with +/// * `force_pass` - Force a password prompt even if persistance is set to true +/// * `uid` - The user uid that is authenticating +/// #### Returns +/// * `true` - If the user authenticated sucessfully +/// * `false` - If the user failed to authenticate +pub fn authenticate(config: &Config, force_pass: bool, uid: Uid) -> bool { + let name = match get_name_from_uid(uid) { + Some(data) => data, + None => return false + }; + if config.nopass || ( !force_pass && config.persist && persist::get_persist(&name) ) { + return true; + } + let input = match rpassword::prompt_password(format!("crab ({}) password: ", &name)) { + Ok(data) => data, + Err(_) => return false + }; + let mut auth = match pam::Authenticator::with_password("crab") { + Ok(data) => data, + Err(_) => return false + }; + auth.get_handler().set_credentials(&name, input); + if !auth.authenticate().is_ok() || !auth.open_session().is_ok() { + return false; + } + if !force_pass && config.persist { + persist::set_persist(&name); + } else if force_pass { + persist::remove_persist(&name); + } + return true; +} diff --git a/src/flags.rs b/src/flags.rs index 9432b8f..a945483 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -1,66 +1,92 @@ + +const HELP_FLAG: &str = "help h"; +const VERSION_FLAG: &str = "version v"; +const DONT_PERSIST: &str = "d"; + + pub struct Flags { - pub help: bool, - pub version: bool, - pub dont_persist: bool, - pub arg_count: usize + pub help: bool, + pub version: bool, + pub dont_persist: bool, + pub arg_count: usize } + +/// Parses an list of String arguments into a set of flags that can be used by crab +/// #### Arguments +/// * `args` - The list of String arguments +/// #### Returns +/// * `None` - If there is an invalid argument in the list +/// * `Some(Flags)` - If the arguments were secussfully parsed, returning the flags pub fn parse(args: &[String]) -> Option<Flags> { - let mut flags = Flags { - help: false, - version: false, - dont_persist: false, - arg_count: 0 - }; - for arg in args { - if !is_arg(&arg) { break; } - flags.arg_count += 1; - if arg.starts_with("--") { - let flag = &arg[2..]; - if !set_flag(&flag, &mut flags) { - eprintln!("Invalid argument: {}", arg); - return None - } - } else { - let flag = &arg[1..]; - for char in flag.chars() { - if !set_flag(&char.to_string(), &mut flags) { - eprintln!("Invalid argument: {}", arg); - return None + let mut flags = Flags { + help: false, + version: false, + dont_persist: false, + arg_count: 0 + }; + for arg in args { + if !is_arg(&arg) { break; } + flags.arg_count += 1; + if arg.starts_with("--") { + let flag = &arg[2..]; + if !set_flag(&flag, &mut flags) { + eprintln!("Invalid argument: {}", arg); + return None + } + } else { + let flag = &arg[1..]; + for char in flag.chars() { + if !set_flag(&char.to_string(), &mut flags) { + eprintln!("Invalid argument: {}", arg); + return None + } + } } - } } - } - Some(flags) + Some(flags) } + +/// Checks if a given string is a given argument fn is_arg(arg: &str) -> bool { return arg.starts_with("-"); } -const HELP_FLAG: &str = "help h"; -const VERSION_FLAG: &str = "version v"; -const DONT_PERSIST: &str = "d"; +/// Sets a flag in a `Flags` struct +/// #### Arguments +/// * `arg` - The argument to check +/// * `flags` - The `Flags` stuct to update +/// #### Returns +/// * `true` - If the argument passed is a valid flag +/// * `false` - If the argument passed is not a valid flag fn set_flag(arg: &str, flags: &mut Flags) -> bool { - if has_flag_set(&arg, HELP_FLAG) { - flags.help = true; - return true - } else if has_flag_set(&arg, VERSION_FLAG) { - flags.version = true; - return true - } else if has_flag_set(&arg, DONT_PERSIST) { - flags.dont_persist = true; - return true - } - false + if has_flag_set(&arg, HELP_FLAG) { + flags.help = true; + return true + } else if has_flag_set(&arg, VERSION_FLAG) { + flags.version = true; + return true + } else if has_flag_set(&arg, DONT_PERSIST) { + flags.dont_persist = true; + return true + } + false } + +/// Returns if a given argument is a certain flag +/// #### Arguments +/// * `arg` - The arch to check +/// #### Returns +/// * `true` - If the argument matches the flag +/// * `false` - If the argument doesn't match the flag fn has_flag_set(arg: &str, check: &str) -> bool { - for check_arg in check.split(" ") { - if check_arg == arg { - return true + for check_arg in check.split(" ") { + if check_arg == arg { + return true + } } - } - return false + return false } diff --git a/src/help.rs b/src/help.rs deleted file mode 100644 index e6f4a72..0000000 --- a/src/help.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn help() { - let help = -"Usage: - crab [-d] command [args] -Options: - -v --version Get the current version of the package - -h --help Generates the crab help message - -d If your user is set to persist, dont save persistance"; - println!("{}", help); -} diff --git a/src/main.rs b/src/main.rs index 28f08cd..56df611 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,142 +1,100 @@ use std::env; use std::process::ExitCode; -use pwd::Passwd; -use nix::unistd; -extern crate time; -const ERROR_ARGS: u8 = 1; -const ERROR_CONFIG: u8 = 2; -const ERROR_NO_USER: u8 = 3; -const ERROR_NOT_AUTHORIZED: u8 = 4; -const ERROR_AUTH_FAILED: u8 = 5; -const ERROR_RUN_ROOT: u8 = 6; - -mod persist; +mod auth; mod flags; -mod help; +mod persist; mod secure; + +const ERROR_ARGS: u8 = 1; +const ERROR_CONFIG: u8 = 2; +const ERROR_NOT_AUTHORIZED: u8 = 3; +const ERROR_AUTH_FAILED: u8 = 4; +const ERROR_ELEVATE_PRIVILEGES: u8 = 5; + + fn main() -> ExitCode { + + // gets the arguments from the env let args: Vec<String> = env::args().collect(); + + // pase the arguments into valid flags that are usuable by crab let flags = match flags::parse(&args[1..]) { Some(data) => data, + // if there is an invalid flag, print the help message and exit None => { - help::help(); + help(); return ExitCode::from(ERROR_ARGS); } }; + + // If the version arg flag is set, print the crab version if flags.version { - println!("crab version 0.0.5"); + println!("crab version 0.0.6"); return ExitCode::SUCCESS; } + + // If the help arg flag is set, print the crab help message if flags.help { - help::help(); + help(); return ExitCode::SUCCESS; } + + // If the amount of acutal command arguments is less than two, a.k.a just `crab`, print the command usage if args.len() - flags.arg_count < 2 { println!("usage: crab [-d] command [args]"); return ExitCode::SUCCESS; } - let config = match config("/etc/crab.conf") { + + // Load the command config from /etc + let configs = match auth::load_config_file("/etc/crab.conf") { Some(data) => data, None => return ExitCode::from(ERROR_CONFIG) }; - let user = match Passwd::current_user() { + + + // check if the user is authorized + let auth = match auth::authorize(&configs, nix::unistd::getuid()) { Some(data) => data, None => { - eprintln!("You dont exist."); - return ExitCode::from(ERROR_NO_USER); - } - }; - let persist = match allowed(&config, &user.name) { - Some(data) => data && !flags.dont_persist, - None => { eprintln!("Operation Not Permitted."); return ExitCode::from(ERROR_NOT_AUTHORIZED); } }; - if !validate(&user.name, persist) { + // authenticate the user + if !auth::authenticate(&configs[auth], flags.dont_persist, nix::unistd::getuid()) { eprintln!("Authentication failed."); return ExitCode::from(ERROR_AUTH_FAILED); } - if !unistd::setuid(unistd::geteuid()).is_ok() || !unistd::setgid(unistd::getegid()).is_ok() { - eprintln!("Failed to set root permissions"); - return ExitCode::from(ERROR_RUN_ROOT); + // elevate privileges + if nix::unistd::setuid(configs[auth].privlaged_uid).is_err() { + eprintln!("Failed to elevate privileges."); + return ExitCode::from(ERROR_ELEVATE_PRIVILEGES); }; + + // execute the passed command let start = 1 + flags.arg_count; let err = exec::execvp(&args[start], &args[start..]); + // print an error if an error was returned eprintln!("{}", err); ExitCode::SUCCESS } -struct Config { - users: Vec<(String, bool)> -} -fn validate(user: &str, persist: bool) -> bool { - if persist && persist::get_persist(user) { - return true; - } - let input = match rpassword::prompt_password(format!("crab ({}) password: ", user)) { - Ok(data) => data, - Err(_) => return false - }; - let mut auth = match pam::Authenticator::with_password("crab") { - Ok(data) => data, - Err(_) => return false - }; - auth.get_handler().set_credentials(user.to_owned(), input); - if !auth.authenticate().is_ok() || !auth.open_session().is_ok() { - return false; - } - if persist { - persist::set_persist(user); - } - return true; -} - -fn allowed(config: &Config, user: &str) -> Option<bool> { - for (name, persist) in &config.users { - if name == user { - return Some(persist.clone()); - } - } - None -} - -fn config(path: &str) -> Option<Config> { - let file = match std::fs::read_to_string(path) { - Err(e) => { - eprintln!("{}: {}", &path, e); - return None - }, - Ok(data) => data - }; - - let mut users = vec![]; - for (line_num, line) in file.split("\n").enumerate() { - let args: Vec<&str> = line.split(" ").collect(); - if line.trim() == "" { - continue; - } - if args.len() < 2 { - eprintln!("Error in config at line {}: Not enough arguments", line_num); - continue; - } - let user: String = args[0].to_string(); - let persist: bool = match args[1].parse() { - Err(e) => { - eprintln!("Error in config at line {}: {}", line_num, e); - continue; - }, - Ok(data) => data - }; - users.push((user, persist)); - } - Some(Config{users}) +/// Prints the help message to the standard output +fn help() { + let help = +"Usage: + crab [-d] command [args] +Options: + -v --version Get the current version of the package + -h --help Generates the crab help message + -d If your user is set to persist, dont save persistance"; + println!("{}", help); } diff --git a/src/persist.rs b/src/persist.rs index 6a813dc..2bca386 100644 --- a/src/persist.rs +++ b/src/persist.rs @@ -1,69 +1,116 @@ use std::time::SystemTime; use serde_json::Value; - use crate::secure; + const PERSIST_TIME: u64 = 60 * 3; const PERSIST_PATH: &str = "/var/run/crab"; + +/// Returns true or false if a user is currently persisted from +/// a prior authentication. If the persist file had been tampered +/// with, or not trusted, it will be ignored, and return false. +/// #### Arguments +/// * `user` - The user to check if is persisted +/// #### Returns +/// * `true` - If the user is persisted +/// * `false` - If the user is not persisted, or if the persist file is not trusted pub fn get_persist(user: &str) -> bool { - let json = match get_terminal_config() { - Some(data) => data, - None => return false - }; - let timestamp = match json[user].as_u64() { - Some(data) => data, - None => return false - }; - return now() - timestamp < PERSIST_TIME && timestamp - 1 < now(); + let json = match get_persist_config() { + Some(data) => data, + None => return false + }; + let timestamp = match json[user].as_u64() { + Some(data) => data, + None => return false + }; + return now() - timestamp < PERSIST_TIME && timestamp - 1 < now(); } + +/// Updates a user in the current sessions persist file +/// #### Arguments +/// * `user` - The user to set persisted pub fn set_persist(user: &str) { - let mut json = match get_terminal_config() { - Some(data) => data, - None => return - }; - json[user] = Value::from(now()); - let id = match get_terminal_process() { - Some(data) => data, - None => return - }; - match secure::write_file(PERSIST_PATH, &format!("{}", id), &json.to_string()) { - Ok(_) => {}, - Err(e) => { - eprintln!("Internal Error: {}", e) - } - }; + let mut json = match get_persist_config() { + Some(data) => data, + None => return + }; + json[user] = Value::from(now()); + let session = match get_current_session() { + Some(data) => data, + None => return + }; + match secure::write_file(PERSIST_PATH, &format!("{}", session), &json.to_string()) { + Ok(_) => {}, + Err(_) => { + eprintln!("crab: An internal error has occured"); + } + }; +} + + +/// Removes a user from the current sessions persist file +/// #### Arguments +/// * `user` - The user to set non-persisted +pub fn remove_persist(user: &str) { + let mut json = match get_persist_config() { + Some(data) => data, + None => return + }; + json[user] = Value::from(0); + let session = match get_current_session() { + Some(data) => data, + None => return + }; + match secure::write_file(PERSIST_PATH, &format!("{}", session), &json.to_string()) { + Ok(_) => {}, + Err(_) => { + eprintln!("crab: An internal error has occured"); + } + }; } -fn get_terminal_process() -> Option<i32> { - let id: i32 = match std::process::id().try_into() { - Ok(data) => data, - Err(_) => return None - }; - let stat = match procinfo::pid::stat(id) { - Ok(data) => data, - Err(_) => return None - }; - Some(stat.session) + +/// Gets the current session that crab is running in +/// #### Returns +/// * `None` - If crab failed to get the current session +/// * `Some(i32)` - If the session is retrieved, returns the i32/pid_t session id +fn get_current_session() -> Option<i32> { + let pid: i32 = match std::process::id().try_into() { + Ok(data) => data, + Err(_) => return None + }; + let pid_stat = match procinfo::pid::stat(pid) { + Ok(data) => data, + Err(_) => return None + }; + Some(pid_stat.session) } -fn get_terminal_config() -> Option<Value> { - let id = match get_terminal_process() { - Some(data) => data, - None => return None - }; - let data = match secure::read_file(PERSIST_PATH, &format!("{}", id)) { - Some(data) => data, - None => "{}".to_string() - }; - let json: Value = match serde_json::from_str(&data) { - Ok(data) => data, - Err(_) => return None - }; - Some(json) + +/// Gets the current persist file for the current session +/// #### Returns +/// * `None` - If the persist file is untrusted or doesnt exist +/// * `Some(Value)` - If the persist file is retrieved, returns the serde_json Value of the file +fn get_persist_config() -> Option<Value> { + let session = match get_current_session() { + Some(data) => data, + None => return None + }; + let data = match secure::read_file(PERSIST_PATH, &format!("{}", session)) { + Some(data) => data, + None => "{}".to_string() + }; + let json: Value = match serde_json::from_str(&data) { + Ok(data) => data, + Err(_) => return None + }; + Some(json) } + +// Gets the current time in seconds since the Unix Epoch fn now() -> u64 { - return SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + return SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); } diff --git a/src/secure.rs b/src/secure.rs index 1fc3a11..7c85ece 100644 --- a/src/secure.rs +++ b/src/secure.rs @@ -1,51 +1,84 @@ -use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io::ErrorKind}; -use nix::unistd; +use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io::{self, ErrorKind}, path::Path}; +use nix::unistd::{self, Uid, Gid}; -pub fn write_file(dir: &str, file: &str, data: &str) -> Result<(), Box<dyn std::error::Error>> { - std::fs::create_dir_all(dir)?; - make_file_root(dir)?; - let path = path(dir, file); - std::fs::write(&path, "")?; - make_file_root(&path)?; - std::fs::write(&path, data)?; - Ok(()) + +/// Writes a file securly to a specified path with given data +/// #### Arguments +/// * `dir` - The directory of the secure folder +/// * `file` - The file name to write +/// * `data` - The data to write +/// #### Returns +/// A ``io::Result<()>`` if the write succeded or failed +pub fn write_file(dir: &str, file: &str, data: &str) -> Result<(), io::Error> { + fs::create_dir_all(dir)?; + set_file_permissions(0, 0, 0o100600, dir)?; + let path = path(dir, file); + fs::write(&path, data)?; + set_file_permissions(0, 0, 0o100600, &path)?; + Ok(()) } + +/// Reads the file secutly to a specified path. If the file has +/// been tampered (permissions have been changed), it ignores the +/// file. +/// #### Arguments +/// * `dir` - The directory of the secure folder +/// * `file` - The file name to write +/// #### Returns +/// * `None` - If the files doesnt exist or isnt trusted +/// * `Some(String) - If the file is trusted, it returns the file's contents pub fn read_file(dir: &str, file: &str) -> Option<String> { - let path = path(dir,file); - if !is_file_root(&path) { - return None; - } - match std::fs::read_to_string(&path) { - Ok(data) => return Some(data), - Err(_) => return None - }; + let path = path(dir,file); + if !check_file_permissions(0, 0, 0o100600, &path) { + return None; + } + match fs::read_to_string(&path) { + Ok(data) => return Some(data), + Err(_) => return None + }; } -fn make_file_root(path: &str) -> Result<(), Box<dyn std::error::Error>> { - unistd::chown(std::path::Path::new(path), Some(unistd::Uid::from(0)), Some(unistd::Gid::from(0)))?; - let metadata = std::fs::metadata(path)?; - let mut perms = metadata.permissions(); - perms.set_mode(0o100600); - fs::set_permissions(path, perms)?; - Ok(()) -} -fn is_file_root(path: &str) -> bool { - return check_file_permissions(0, 0, 0o100600, path); +/// Sets the permission for a secure file +/// #### Arguments +/// * `uid` - The user to own the file +/// * `gid` - The group to own the file +/// * `mode` - The mode permissions of the file +/// * `path` - The path of the secure file +/// #### Returns +/// A ``io::Result<()>`` if the write succeded or failed +fn set_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> Result<(), io::Error> { + unistd::chown(Path::new(path), Some(Uid::from(uid)), Some(Gid::from(gid)))?; + let metadata = fs::metadata(path)?; + let mut perms = metadata.permissions(); + perms.set_mode(mode); + fs::set_permissions(path, perms)?; + Ok(()) } + +/// Checks if the files permissions equals the given parameters +/// #### Arguments +/// * `uid` - The user to own the file +/// * `gid` - The group to own the file +/// * `mode` - The mode permissions of the file +/// * `path` - The path of the secure file +/// #### Returns +/// True or false if the files permissions match fn check_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> bool { - let metadata = match std::fs::metadata(path) { - Ok(data) => data, - Err(e) => { - return e.kind() == ErrorKind::NotFound - } - }; - let perms = metadata.permissions(); - return perms.mode() == mode && metadata.st_uid() == uid && metadata.st_gid() == gid; + let metadata = match fs::metadata(path) { + Ok(data) => data, + Err(e) => { + return e.kind() == ErrorKind::NotFound; + } + }; + let perms = metadata.permissions(); + return perms.mode() == mode && metadata.st_uid() == uid && metadata.st_gid() == gid; } + +/// Get the path of a file given a directory and file name fn path(dir: &str, file: &str) -> String { - return format!("{}/{}", dir, file); -}
\ No newline at end of file + return format!("{}/{}.persist", dir, file); +} |