diff --git a/Cargo.lock b/Cargo.lock index dccc8b116..f915b4cb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1707,6 +1707,7 @@ dependencies = [ "env_logger", "kanidm_client", "kanidm_proto", + "libc", "log", "qrcode", "rayon", diff --git a/kanidm_tools/Cargo.toml b/kanidm_tools/Cargo.toml index f1c453dbf..2bf084925 100644 --- a/kanidm_tools/Cargo.toml +++ b/kanidm_tools/Cargo.toml @@ -31,6 +31,7 @@ kanidm_client = { path = "../kanidm_client", version = "1.1.0-alpha.2" } kanidm_proto = { path = "../kanidm_proto", version = "1.1.0-alpha.2" } rpassword = "5.0" structopt = { version = "0.3", default-features = false } +libc = "0.2" log = "0.4" env_logger = "0.8" serde = "1.0" diff --git a/kanidm_tools/src/cli/login.rs b/kanidm_tools/src/cli/login.rs index c01d968b5..3c66d2ac9 100644 --- a/kanidm_tools/src/cli/login.rs +++ b/kanidm_tools/src/cli/login.rs @@ -1,18 +1,29 @@ use crate::common::CommonOpt; use kanidm_client::{ClientError, KanidmClient}; use kanidm_proto::v1::{AuthAllowed, AuthResponse, AuthState}; +use libc::umask; use std::collections::BTreeMap; -use std::fs::File; +use std::fs::{create_dir, File}; use std::io::{self, BufReader, BufWriter}; +use std::path::PathBuf; use structopt::StructOpt; use webauthn_authenticator_rs::{u2fhid::U2FHid, RequestChallengeResponse, WebauthnAuthenticator}; +static TOKEN_DIR: &str = "~/.cache"; static TOKEN_PATH: &str = "~/.cache/kanidm_tokens"; pub fn read_tokens() -> Result, ()> { - let token_path: String = shellexpand::tilde(TOKEN_PATH).into_owned(); + let token_path = PathBuf::from(shellexpand::tilde(TOKEN_PATH).into_owned()); + if !token_path.exists() { + debug!( + "Token path {} does not exist, assuming empty ... ", + TOKEN_PATH + ); + return Ok(BTreeMap::new()); + } + // If the file does not exist, return Ok - let file = match File::open(token_path) { + let file = match File::open(&token_path) { Ok(f) => f, Err(e) => { warn!("Can not read from {}, continuing ... {:?}", TOKEN_PATH, e); @@ -28,11 +39,42 @@ pub fn read_tokens() -> Result, ()> { } pub fn write_tokens(tokens: &BTreeMap) -> Result<(), ()> { - let token_path: String = shellexpand::tilde(TOKEN_PATH).into_owned(); - let file = File::create(token_path).map_err(|e| { + let token_dir = PathBuf::from(shellexpand::tilde(TOKEN_DIR).into_owned()); + let token_path = PathBuf::from(shellexpand::tilde(TOKEN_PATH).into_owned()); + + token_dir + .parent() + .ok_or_else(|| { + error!( + "Parent directory to {} is invalid (root directory?).", + TOKEN_DIR + ); + }) + .and_then(|parent_dir| { + if parent_dir.exists() { + Ok(()) + } else { + error!("Parent directory to {} does not exist.", TOKEN_DIR); + Err(()) + } + })?; + + if !token_dir.exists() { + create_dir(token_dir).map_err(|e| { + error!("Unable to create directory - {} {:?}", TOKEN_DIR, e); + })?; + } + + // Take away group/everyone read/write + let before = unsafe { umask(0o177) }; + + let file = File::create(&token_path).map_err(|e| { + let _ = unsafe { umask(before) }; error!("Can not write to {} -> {:?}", TOKEN_PATH, e); })?; + let _ = unsafe { umask(before) }; + let writer = BufWriter::new(file); serde_json::to_writer_pretty(writer, tokens).map_err(|e| { error!("JSON/IO error -> {:?}", e);