summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-06-27 19:27:03 +0200
committerLinus Färnstrand <linus@mullvad.net>2017-06-30 15:58:40 +0200
commitdf6c8a8a60a7fbbb971c02c8a5483430b1db029e (patch)
tree8bbc20100313c2582c4a67a9623954fc777209c6
parentba1ed122e8f1e2ad19c3dfb6f40696bfa2d57fd1 (diff)
downloadmullvadvpn-df6c8a8a60a7fbbb971c02c8a5483430b1db029e.tar.xz
mullvadvpn-df6c8a8a60a7fbbb971c02c8a5483430b1db029e.zip
Write credentials to file for user-pass auth
-rw-r--r--mullvad_daemon/src/main.rs8
-rw-r--r--talpid_core/Cargo.toml1
-rw-r--r--talpid_core/src/lib.rs1
-rw-r--r--talpid_core/src/tunnel/mod.rs50
4 files changed, 50 insertions, 10 deletions
diff --git a/mullvad_daemon/src/main.rs b/mullvad_daemon/src/main.rs
index 53faed7f6f..2ac5922bee 100644
--- a/mullvad_daemon/src/main.rs
+++ b/mullvad_daemon/src/main.rs
@@ -228,7 +228,7 @@ impl Daemon {
if let Err(_) = tx.send(self.last_broadcasted_state) {
warn!("Unable to send current state to management interface client",);
}
- },
+ }
TunnelCommand::SetAccount(account_token) => self.account_token = account_token,
}
Ok(())
@@ -310,7 +310,7 @@ impl Daemon {
ErrorKind::InvalidState
);
let remote = self.remote_iter.next().unwrap();
- let tunnel_monitor = self.spawn_tunnel_monitor(remote)?;
+ let tunnel_monitor = self.spawn_tunnel_monitor(remote, self.account_token.as_str())?;
self.tunnel_close_handle = Some(tunnel_monitor.close_handle());
self.spawn_tunnel_monitor_wait_thread(tunnel_monitor);
@@ -318,13 +318,13 @@ impl Daemon {
Ok(())
}
- fn spawn_tunnel_monitor(&self, remote: Endpoint) -> Result<TunnelMonitor> {
+ fn spawn_tunnel_monitor(&self, remote: Endpoint, account_token: &str) -> Result<TunnelMonitor> {
// Must wrap the channel in a Mutex because TunnelMonitor forces the closure to be Sync
let event_tx = Arc::new(Mutex::new(self.tx.clone()));
let on_tunnel_event = move |event| {
let _ = event_tx.lock().unwrap().send(DaemonEvent::TunnelEvent(event));
};
- TunnelMonitor::new(remote, on_tunnel_event)
+ TunnelMonitor::new(remote, account_token, on_tunnel_event)
.chain_err(|| ErrorKind::TunnelError("Unable to start tunnel monitor"))
}
diff --git a/talpid_core/Cargo.toml b/talpid_core/Cargo.toml
index 573cc0b328..4538630f39 100644
--- a/talpid_core/Cargo.toml
+++ b/talpid_core/Cargo.toml
@@ -9,6 +9,7 @@ duct = "0.9.1"
error-chain = "0.10"
log = "0.3"
lazy_static = "0.2"
+mktemp = "0.3"
jsonrpc-core = { git = "https://github.com/faern/jsonrpc", branch = "ws-close-handle" }
jsonrpc-macros = { git = "https://github.com/faern/jsonrpc", branch = "ws-close-handle" }
diff --git a/talpid_core/src/lib.rs b/talpid_core/src/lib.rs
index 52213ebee0..1fc92f8fe4 100644
--- a/talpid_core/src/lib.rs
+++ b/talpid_core/src/lib.rs
@@ -12,6 +12,7 @@ extern crate duct;
extern crate lazy_static;
#[macro_use]
extern crate log;
+extern crate mktemp;
#[macro_use]
extern crate error_chain;
diff --git a/talpid_core/src/tunnel/mod.rs b/talpid_core/src/tunnel/mod.rs
index 45b518ad9e..7f4fa7ff5f 100644
--- a/talpid_core/src/tunnel/mod.rs
+++ b/talpid_core/src/tunnel/mod.rs
@@ -1,7 +1,9 @@
+use mktemp;
use net;
use openvpn_ffi::OpenVpnPluginEvent;
use process::openvpn::OpenVpnCommand;
-use std::io;
+use std::fs;
+use std::io::{self, Write};
use std::path::{Path, PathBuf};
/// A module for all OpenVPN related tunnel management.
@@ -20,6 +22,10 @@ mod errors {
PluginNotFound {
description("No OpenVPN plugin found")
}
+ /// There was an error when writing authentication credentials to temporary file.
+ CredentialsWriteError {
+ description("Error while writing credentials to temporary file")
+ }
}
}
}
@@ -51,30 +57,62 @@ impl TunnelEvent {
/// Abstraction for monitoring a generic VPN tunnel.
pub struct TunnelMonitor {
monitor: OpenVpnMonitor,
+ _user_pass_file: mktemp::Temp,
}
impl TunnelMonitor {
/// Creates a new `TunnelMonitor` that connects to the given remote and notifies `on_event`
/// on tunnel state changes.
- pub fn new<L>(remote: net::Endpoint, on_event: L) -> Result<Self>
+ pub fn new<L>(remote: net::Endpoint, account_token: &str, on_event: L) -> Result<Self>
where L: Fn(TunnelEvent) + Send + Sync + 'static
{
let on_openvpn_event = move |event, _env| match TunnelEvent::from_openvpn_event(&event) {
Some(tunnel_event) => on_event(tunnel_event),
None => debug!("Ignoring OpenVpnEvent {:?}", event),
};
- let cmd = Self::create_openvpn_cmd(remote);
+ let user_pass_file = Self::create_user_pass_file(account_token)
+ .chain_err(|| ErrorKind::CredentialsWriteError)?;
+ let cmd = Self::create_openvpn_cmd(remote, user_pass_file.as_ref());
let monitor = openvpn::OpenVpnMonitor::new(cmd, on_openvpn_event, get_plugin_path()?)
.chain_err(|| ErrorKind::TunnelMonitoringError)?;
- Ok(TunnelMonitor { monitor })
+ Ok(
+ TunnelMonitor {
+ monitor,
+ _user_pass_file: user_pass_file,
+ },
+ )
}
- fn create_openvpn_cmd(remote: net::Endpoint) -> OpenVpnCommand {
+ fn create_openvpn_cmd(remote: net::Endpoint, user_pass_file: &Path) -> OpenVpnCommand {
let mut cmd = OpenVpnCommand::new("openvpn");
- cmd.config(get_config_path()).remote(remote);
+ cmd.config(get_config_path()).remote(remote).user_pass(user_pass_file);
cmd
}
+ fn create_user_pass_file(account_token: &str) -> io::Result<mktemp::Temp> {
+ let path = mktemp::Temp::new_file()?;
+ debug!(
+ "Writing user-pass credentials to {}",
+ path.as_ref().to_string_lossy()
+ );
+ let mut file = fs::File::create(&path)?;
+ Self::set_user_pass_file_permissions(&file)?;
+ write!(file, "{}\n-\n", account_token)?;
+ Ok(path)
+ }
+
+ #[cfg(unix)]
+ fn set_user_pass_file_permissions(file: &fs::File) -> io::Result<()> {
+ use std::os::unix::fs::PermissionsExt;
+ file.set_permissions(PermissionsExt::from_mode(0o400))
+ }
+
+ #[cfg(windows)]
+ fn set_user_pass_file_permissions(file: &fs::File) -> io::Result<()> {
+ // TODO(linus): Lock permissions correctly on Windows.
+ Ok(())
+ }
+
/// Creates a handle to this monitor, allowing the tunnel to be closed while some other thread
/// is blocked in `wait`.
pub fn close_handle(&self) -> CloseHandle {