Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Restrict vault.json permssion to owner and using random suffix for temp vault.json file #8932

Merged
merged 2 commits into from
Jun 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 36 additions & 25 deletions ethstore/src/accounts_dir/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,33 @@ const IGNORED_FILES: &'static [&'static str] = &[
"vault.json",
];

/// Find a unique filename that does not exist using four-letter random suffix.
pub fn find_unique_filename_using_random_suffix(parent_path: &Path, original_filename: &str) -> io::Result<String> {
let mut path = parent_path.join(original_filename);
let mut deduped_filename = original_filename.to_string();

if path.exists() {
const MAX_RETRIES: usize = 500;
let mut retries = 0;

while path.exists() {
if retries >= MAX_RETRIES {
return Err(io::Error::new(io::ErrorKind::Other, "Exceeded maximum retries when deduplicating filename."));
}

let suffix = ::random::random_string(4);
deduped_filename = format!("{}-{}", original_filename, suffix);
path.set_file_name(&deduped_filename);
retries += 1;
}
}

Ok(deduped_filename)
}

/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
#[cfg(unix)]
fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
use libc;
use std::os::unix::fs::OpenOptionsExt;

Expand All @@ -46,16 +70,18 @@ fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs:
.open(file_path)
}

/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
#[cfg(not(unix))]
fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(file_path)
}

/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
#[cfg(unix)]
fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
use libc;
use std::os::unix::fs::PermissionsExt;

Expand All @@ -67,8 +93,9 @@ fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::Fi
Ok(file)
}

/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
#[cfg(not(unix))]
fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
fs::File::create(file_path)
}

Expand Down Expand Up @@ -177,29 +204,13 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
/// true, a random suffix is appended to the filename.
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
// path to keyfile
let mut keyfile_path = self.path.join(filename.as_str());

// check for duplicate filename and append random suffix
if dedup && keyfile_path.exists() {
const MAX_RETRIES: usize = 500;
let mut retries = 0;
let mut deduped_filename = filename.clone();

while keyfile_path.exists() {
if retries >= MAX_RETRIES {
return Err(Error::Custom(format!("Exceeded maximum retries when deduplicating account filename.")));
}

let suffix = ::random::random_string(4);
deduped_filename = format!("{}-{}", filename, suffix);
keyfile_path.set_file_name(&deduped_filename);
retries += 1;
}

filename = deduped_filename;
if dedup {
filename = find_unique_filename_using_random_suffix(&self.path, &filename)?;
}

// path to keyfile
let keyfile_path = self.path.join(filename.as_str());

// update account filename
let original_account = account.clone();
let mut account = account;
Expand Down
11 changes: 5 additions & 6 deletions ethstore/src/accounts_dir/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use {json, SafeAccount, Error};
use crypto::Keccak256;
use super::super::account::Crypto;
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
use super::disk::{DiskDirectory, KeyFileManager};
use super::disk::{self, DiskDirectory, KeyFileManager};

/// Name of vault metadata file
pub const VAULT_FILE_NAME: &'static str = "vault.json";
Expand Down Expand Up @@ -237,14 +237,13 @@ fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result
let password_hash = key.password.keccak256();
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;

let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
vault_file_path.push(VAULT_FILE_NAME);
let mut temp_vault_file_path: PathBuf = vault_dir_path.as_ref().into();
temp_vault_file_path.push(VAULT_TEMP_FILE_NAME);
let vault_file_path = vault_dir_path.as_ref().join(VAULT_FILE_NAME);
let temp_vault_file_name = disk::find_unique_filename_using_random_suffix(vault_dir_path.as_ref(), &VAULT_TEMP_FILE_NAME)?;
let temp_vault_file_path = vault_dir_path.as_ref().join(&temp_vault_file_name);

// this method is used to rewrite existing vault file
// => write to temporary file first, then rename temporary file to vault file
let mut vault_file = fs::File::create(&temp_vault_file_path)?;
let mut vault_file = disk::create_new_file_with_permissions_to_owner(&temp_vault_file_path)?;
let vault_file_contents = json::VaultFile {
crypto: crypto.into(),
meta: Some(meta.to_owned()),
Expand Down