documentation and group support
This commit is contained in:
parent
f7a13253e7
commit
83d045a58c
4 changed files with 204 additions and 24 deletions
32
src/flags.rs
32
src/flags.rs
|
@ -1,3 +1,9 @@
|
||||||
|
|
||||||
|
const HELP_FLAG: &str = "help h";
|
||||||
|
const VERSION_FLAG: &str = "version v";
|
||||||
|
const DONT_PERSIST: &str = "d";
|
||||||
|
|
||||||
|
|
||||||
pub struct Flags {
|
pub struct Flags {
|
||||||
pub help: bool,
|
pub help: bool,
|
||||||
pub version: bool,
|
pub version: bool,
|
||||||
|
@ -5,6 +11,13 @@ pub struct Flags {
|
||||||
pub arg_count: usize
|
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> {
|
pub fn parse(args: &[String]) -> Option<Flags> {
|
||||||
let mut flags = Flags {
|
let mut flags = Flags {
|
||||||
help: false,
|
help: false,
|
||||||
|
@ -34,14 +47,20 @@ pub fn parse(args: &[String]) -> Option<Flags> {
|
||||||
Some(flags)
|
Some(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Checks if a given string is a given argument
|
||||||
fn is_arg(arg: &str) -> bool {
|
fn is_arg(arg: &str) -> bool {
|
||||||
return arg.starts_with("-");
|
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 {
|
fn set_flag(arg: &str, flags: &mut Flags) -> bool {
|
||||||
if has_flag_set(&arg, HELP_FLAG) {
|
if has_flag_set(&arg, HELP_FLAG) {
|
||||||
flags.help = true;
|
flags.help = true;
|
||||||
|
@ -56,6 +75,13 @@ fn set_flag(arg: &str, flags: &mut Flags) -> bool {
|
||||||
false
|
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 {
|
fn has_flag_set(arg: &str, check: &str) -> bool {
|
||||||
for check_arg in check.split(" ") {
|
for check_arg in check.split(" ") {
|
||||||
if check_arg == arg {
|
if check_arg == arg {
|
||||||
|
|
115
src/main.rs
115
src/main.rs
|
@ -1,9 +1,13 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use pwd::Passwd;
|
use pwd::Passwd;
|
||||||
use nix::unistd;
|
use nix::unistd::{self, Uid, Group};
|
||||||
|
|
||||||
|
|
||||||
|
mod persist;
|
||||||
|
mod flags;
|
||||||
|
mod secure;
|
||||||
|
|
||||||
extern crate time;
|
|
||||||
|
|
||||||
const ERROR_ARGS: u8 = 1;
|
const ERROR_ARGS: u8 = 1;
|
||||||
const ERROR_CONFIG: u8 = 2;
|
const ERROR_CONFIG: u8 = 2;
|
||||||
|
@ -12,35 +16,47 @@ const ERROR_NOT_AUTHORIZED: u8 = 4;
|
||||||
const ERROR_AUTH_FAILED: u8 = 5;
|
const ERROR_AUTH_FAILED: u8 = 5;
|
||||||
const ERROR_RUN_ROOT: u8 = 6;
|
const ERROR_RUN_ROOT: u8 = 6;
|
||||||
|
|
||||||
mod persist;
|
|
||||||
mod flags;
|
|
||||||
mod secure;
|
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
|
|
||||||
|
// gets the arguments from the env
|
||||||
let args: Vec<String> = env::args().collect();
|
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..]) {
|
let flags = match flags::parse(&args[1..]) {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
|
// if there is an invalid flag, print the help message and exit
|
||||||
None => {
|
None => {
|
||||||
help();
|
help();
|
||||||
return ExitCode::from(ERROR_ARGS);
|
return ExitCode::from(ERROR_ARGS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If the version arg flag is set, print the crab version
|
||||||
if flags.version {
|
if flags.version {
|
||||||
println!("crab version 0.0.5");
|
println!("crab version 0.0.5");
|
||||||
return ExitCode::SUCCESS;
|
return ExitCode::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the help arg flag is set, print the crab help message
|
||||||
if flags.help {
|
if flags.help {
|
||||||
help();
|
help();
|
||||||
return ExitCode::SUCCESS;
|
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 {
|
if args.len() - flags.arg_count < 2 {
|
||||||
println!("usage: crab [-d] command [args]");
|
println!("usage: crab [-d] command [args]");
|
||||||
return ExitCode::SUCCESS;
|
return ExitCode::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the command config from /etc
|
||||||
let config = match config("/etc/crab.conf") {
|
let config = match config("/etc/crab.conf") {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return ExitCode::from(ERROR_CONFIG)
|
None => return ExitCode::from(ERROR_CONFIG)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// get the current user login
|
||||||
let user = match Passwd::current_user() {
|
let user = match Passwd::current_user() {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => {
|
None => {
|
||||||
|
@ -48,6 +64,8 @@ fn main() -> ExitCode {
|
||||||
return ExitCode::from(ERROR_NO_USER);
|
return ExitCode::from(ERROR_NO_USER);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// check if the user is authorized
|
||||||
let persist = match allowed(&config, &user.name) {
|
let persist = match allowed(&config, &user.name) {
|
||||||
Some(data) => data && !flags.dont_persist,
|
Some(data) => data && !flags.dont_persist,
|
||||||
None => {
|
None => {
|
||||||
|
@ -56,23 +74,31 @@ fn main() -> ExitCode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// authenticate the user
|
||||||
if !validate(&user.name, persist) {
|
if !validate(&user.name, persist) {
|
||||||
eprintln!("Authentication failed.");
|
eprintln!("Authentication failed.");
|
||||||
return ExitCode::from(ERROR_AUTH_FAILED);
|
return ExitCode::from(ERROR_AUTH_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the uid and gid of the process to root to run the command as root
|
||||||
if !unistd::setuid(unistd::geteuid()).is_ok() || !unistd::setgid(unistd::getegid()).is_ok() {
|
if !unistd::setuid(unistd::geteuid()).is_ok() || !unistd::setgid(unistd::getegid()).is_ok() {
|
||||||
eprintln!("Failed to set root permissions");
|
eprintln!("Failed to set root permissions");
|
||||||
return ExitCode::from(ERROR_RUN_ROOT);
|
return ExitCode::from(ERROR_RUN_ROOT);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// execute the passed command
|
||||||
let start = 1 + flags.arg_count;
|
let start = 1 + flags.arg_count;
|
||||||
let err = exec::execvp(&args[start], &args[start..]);
|
let err = exec::execvp(&args[start], &args[start..]);
|
||||||
|
|
||||||
|
// print an error if an error was returned
|
||||||
eprintln!("{}", err);
|
eprintln!("{}", err);
|
||||||
|
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Prints the help message to the standard output
|
||||||
fn help() {
|
fn help() {
|
||||||
let help =
|
let help =
|
||||||
"Usage:
|
"Usage:
|
||||||
|
@ -84,10 +110,22 @@ Options:
|
||||||
println!("{}", help);
|
println!("{}", help);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
users: Vec<(String, bool)>
|
identitys: Vec<(String, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Validates the authorized user, and authenticates them 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
|
||||||
|
/// * `user` - The login name of the linux user
|
||||||
|
/// * `persist` - If the user's login should persist
|
||||||
|
/// #### Returns
|
||||||
|
/// * `true` - If the user authenticated sucessfully, or the user is persisted
|
||||||
|
/// * `false` - If the user failed to authenticate
|
||||||
fn validate(user: &str, persist: bool) -> bool {
|
fn validate(user: &str, persist: bool) -> bool {
|
||||||
if persist && persist::get_persist(user) {
|
if persist && persist::get_persist(user) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -110,15 +148,68 @@ fn validate(user: &str, persist: bool) -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns if the user is authorized given a sepcific config and user name.
|
||||||
|
/// #### Arguments
|
||||||
|
/// * `config` - A config struct contaning the authorization settings for crab
|
||||||
|
/// * `user` - The name of the user to check is authorized
|
||||||
|
/// #### Returns
|
||||||
|
/// * `None` - If the user is not authorized
|
||||||
|
/// * `Some(bool)` - If the user is authorized, returning the boolean if the
|
||||||
|
/// user is set to persist
|
||||||
fn allowed(config: &Config, user: &str) -> Option<bool> {
|
fn allowed(config: &Config, user: &str) -> Option<bool> {
|
||||||
for (name, persist) in &config.users {
|
// get user groups
|
||||||
if name == user {
|
let groups = get_groups(Uid::current());
|
||||||
|
// check each config identiy
|
||||||
|
for (identity, persist) in &config.identitys {
|
||||||
|
// if it starts with a :, its a group
|
||||||
|
if identity.starts_with(":") {
|
||||||
|
let group = &identity[1..];
|
||||||
|
if groups.contains(&group.to_string()) {
|
||||||
|
return Some(persist.clone());
|
||||||
|
};
|
||||||
|
// else its a user
|
||||||
|
} else if identity == user {
|
||||||
return Some(persist.clone());
|
return Some(persist.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a vector of group names of the groups a specific linux user is in
|
||||||
|
/// #### Arguments
|
||||||
|
/// * 'uid' - The user id od the linux user to get groups from
|
||||||
|
/// #### 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(uid: Uid) -> Vec<String> {
|
||||||
|
let no_change = Uid::from_raw(u32::MAX);
|
||||||
|
if unistd::setresuid(no_change, uid, no_change).is_err() {
|
||||||
|
return vec![]
|
||||||
|
};
|
||||||
|
let groups = match nix::unistd::getgroups() {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return vec![]
|
||||||
|
};
|
||||||
|
let names = groups.iter()
|
||||||
|
.map(|gid| Group::from_gid(*gid))
|
||||||
|
.flatten().flatten()
|
||||||
|
.map(|group| group.name)
|
||||||
|
.collect();
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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(Config)` - If the config was sucessfully parsed.
|
||||||
fn config(path: &str) -> Option<Config> {
|
fn config(path: &str) -> Option<Config> {
|
||||||
let file = match std::fs::read_to_string(path) {
|
let file = match std::fs::read_to_string(path) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -128,7 +219,7 @@ fn config(path: &str) -> Option<Config> {
|
||||||
Ok(data) => data
|
Ok(data) => data
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut users = vec![];
|
let mut identitys = vec![];
|
||||||
for (line_num, line) in file.split("\n").enumerate() {
|
for (line_num, line) in file.split("\n").enumerate() {
|
||||||
let args: Vec<&str> = line.split(" ").collect();
|
let args: Vec<&str> = line.split(" ").collect();
|
||||||
if line.trim() == "" {
|
if line.trim() == "" {
|
||||||
|
@ -138,7 +229,7 @@ fn config(path: &str) -> Option<Config> {
|
||||||
eprintln!("Error in config at line {}: Not enough arguments", line_num);
|
eprintln!("Error in config at line {}: Not enough arguments", line_num);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let user: String = args[0].to_string();
|
let identity: String = args[0].to_string();
|
||||||
let persist: bool = match args[1].parse() {
|
let persist: bool = match args[1].parse() {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error in config at line {}: {}", line_num, e);
|
eprintln!("Error in config at line {}: {}", line_num, e);
|
||||||
|
@ -146,7 +237,7 @@ fn config(path: &str) -> Option<Config> {
|
||||||
},
|
},
|
||||||
Ok(data) => data
|
Ok(data) => data
|
||||||
};
|
};
|
||||||
users.push((user, persist));
|
identitys.push((identity, persist));
|
||||||
}
|
}
|
||||||
Some(Config{users})
|
Some(Config{identitys})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::secure;
|
use crate::secure;
|
||||||
|
|
||||||
|
|
||||||
const PERSIST_TIME: u64 = 60 * 3;
|
const PERSIST_TIME: u64 = 60 * 3;
|
||||||
const PERSIST_PATH: &str = "/var/run/crab";
|
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 {
|
pub fn get_persist(user: &str) -> bool {
|
||||||
let json = match get_terminal_config() {
|
let json = match get_persist_config() {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return false
|
None => return false
|
||||||
};
|
};
|
||||||
|
@ -18,17 +27,21 @@ pub fn get_persist(user: &str) -> bool {
|
||||||
return now() - timestamp < PERSIST_TIME && timestamp - 1 < now();
|
return now() - timestamp < PERSIST_TIME && timestamp - 1 < now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Updates the current sessions persist file
|
||||||
|
/// #### Arguments
|
||||||
|
/// * `user` - The user to set persisted
|
||||||
pub fn set_persist(user: &str) {
|
pub fn set_persist(user: &str) {
|
||||||
let mut json = match get_terminal_config() {
|
let mut json = match get_persist_config() {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => serde_json::from_str("{}").unwrap()
|
None => serde_json::from_str("{}").unwrap()
|
||||||
};
|
};
|
||||||
json[user] = Value::from(now());
|
json[user] = Value::from(now());
|
||||||
let id = match get_terminal_process() {
|
let session = match get_current_session() {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return
|
None => return
|
||||||
};
|
};
|
||||||
match secure::write_file(PERSIST_PATH, &format!("{}", id), &json.to_string()) {
|
match secure::write_file(PERSIST_PATH, &format!("{}", session), &json.to_string()) {
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
eprintln!("crab: An Internal Has Error")
|
eprintln!("crab: An Internal Has Error")
|
||||||
|
@ -36,7 +49,12 @@ pub fn set_persist(user: &str) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_terminal_process() -> Option<i32> {
|
|
||||||
|
/// 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() {
|
let pid: i32 = match std::process::id().try_into() {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(_) => return None
|
Err(_) => return None
|
||||||
|
@ -48,12 +66,17 @@ fn get_terminal_process() -> Option<i32> {
|
||||||
Some(pid_stat.session)
|
Some(pid_stat.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_terminal_config() -> Option<Value> {
|
|
||||||
let id = match get_terminal_process() {
|
/// 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,
|
Some(data) => data,
|
||||||
None => return None
|
None => return None
|
||||||
};
|
};
|
||||||
let data = match secure::read_file(PERSIST_PATH, &format!("{}", id)) {
|
let data = match secure::read_file(PERSIST_PATH, &format!("{}", session)) {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => "{}".to_string()
|
None => "{}".to_string()
|
||||||
};
|
};
|
||||||
|
@ -64,6 +87,8 @@ fn get_terminal_config() -> Option<Value> {
|
||||||
Some(json)
|
Some(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Gets the current time in seconds since the Unix Epoch
|
||||||
fn now() -> u64 {
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io};
|
use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io};
|
||||||
use nix::unistd;
|
use nix::unistd;
|
||||||
|
|
||||||
|
|
||||||
|
/// 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> {
|
pub fn write_file(dir: &str, file: &str, data: &str) -> Result<(), io::Error> {
|
||||||
fs::create_dir_all(dir)?;
|
fs::create_dir_all(dir)?;
|
||||||
set_file_permissions(0, 0, 0o100600, dir)?;
|
set_file_permissions(0, 0, 0o100600, dir)?;
|
||||||
|
@ -11,6 +19,16 @@ pub fn write_file(dir: &str, file: &str, data: &str) -> Result<(), io::Error> {
|
||||||
Ok(())
|
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> {
|
pub fn read_file(dir: &str, file: &str) -> Option<String> {
|
||||||
let path = path(dir,file);
|
let path = path(dir,file);
|
||||||
if !check_file_permissions(0, 0, 0o100600, &path) {
|
if !check_file_permissions(0, 0, 0o100600, &path) {
|
||||||
|
@ -22,6 +40,15 @@ pub fn read_file(dir: &str, file: &str) -> Option<String> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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> {
|
fn set_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> Result<(), io::Error> {
|
||||||
unistd::chown(std::path::Path::new(path), Some(unistd::Uid::from(uid)), Some(unistd::Gid::from(gid)))?;
|
unistd::chown(std::path::Path::new(path), Some(unistd::Uid::from(uid)), Some(unistd::Gid::from(gid)))?;
|
||||||
let metadata = fs::metadata(path)?;
|
let metadata = fs::metadata(path)?;
|
||||||
|
@ -31,6 +58,15 @@ fn set_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> Result<(),
|
||||||
Ok(())
|
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 {
|
fn check_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> bool {
|
||||||
let metadata = match fs::metadata(path) {
|
let metadata = match fs::metadata(path) {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
|
@ -40,6 +76,8 @@ fn check_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> bool {
|
||||||
return perms.mode() == mode && metadata.st_uid() == uid && metadata.st_gid() == gid;
|
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 {
|
fn path(dir: &str, file: &str) -> String {
|
||||||
return format!("{}/{}", dir, file);
|
return format!("{}/{}", dir, file);
|
||||||
}
|
}
|
Loading…
Reference in a new issue