diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-07-03 12:49:15 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-07-03 12:49:15 +0200 |
| commit | e0ba08fb3ac8198b7184bd73fb82d35fae704e09 (patch) | |
| tree | 384c09ff013f72dfd2958f354357b44558c84663 /talpid_core | |
| parent | 39e704f76cd74f1700db2efe7622110d52f82951 (diff) | |
| parent | adb58cdfbd60c9779db9e42aee018595f7eff9da (diff) | |
| download | mullvadvpn-e0ba08fb3ac8198b7184bd73fb82d35fae704e09.tar.xz mullvadvpn-e0ba08fb3ac8198b7184bd73fb82d35fae704e09.zip | |
Merge branch 'support-user-pass-auth'
Diffstat (limited to 'talpid_core')
| -rw-r--r-- | talpid_core/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid_core/src/lib.rs | 1 | ||||
| -rw-r--r-- | talpid_core/src/process/openvpn.rs | 19 | ||||
| -rw-r--r-- | talpid_core/src/tunnel/mod.rs | 50 |
4 files changed, 65 insertions, 6 deletions
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/process/openvpn.rs b/talpid_core/src/process/openvpn.rs index ba6688b034..09e845b640 100644 --- a/talpid_core/src/process/openvpn.rs +++ b/talpid_core/src/process/openvpn.rs @@ -35,6 +35,7 @@ pub struct OpenVpnCommand { openvpn_bin: OsString, config: Option<PathBuf>, remote: Option<net::Endpoint>, + user_pass_path: Option<PathBuf>, plugin: Option<(PathBuf, Vec<String>)>, } @@ -46,6 +47,7 @@ impl OpenVpnCommand { openvpn_bin: OsString::from(openvpn_bin.as_ref()), config: None, remote: None, + user_pass_path: None, plugin: None, } } @@ -62,6 +64,13 @@ impl OpenVpnCommand { self } + /// Sets the path to the file where the username and password for user-pass authentication is + /// stored. See the `--auth-user-pass` OpenVPN documentation for details. + pub fn user_pass<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.user_pass_path = Some(path.as_ref().to_path_buf()); + self + } + /// Sets a plugin and its arguments that OpenVPN will be started with. pub fn plugin<P: AsRef<Path>>(&mut self, path: P, args: Vec<String>) -> &mut Self { self.plugin = Some((path.as_ref().to_path_buf(), args)); @@ -84,6 +93,7 @@ impl OpenVpnCommand { } args.extend(self.remote_arguments().iter().map(OsString::from)); + args.extend(self.authentication_arguments()); if let Some((ref path, ref plugin_args)) = self.plugin { args.push(OsString::from("--plugin")); @@ -129,6 +139,15 @@ impl OpenVpnCommand { } args } + + fn authentication_arguments(&self) -> Vec<OsString> { + let mut args = vec![]; + if let Some(ref user_pass_path) = self.user_pass_path { + args.push(OsString::from("--auth-user-pass")); + args.push(OsString::from(user_pass_path)); + } + args + } } impl fmt::Display for OpenVpnCommand { 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 { |
