From 9f1d465ac411ef2efc5930bbdf56b8ea67b48690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 7 Jun 2021 20:42:01 +0200 Subject: specify if we accept invalid server certs or not --- mumctl/src/main.rs | 31 +++++++++++++++++++++++++------ mumd/src/command.rs | 23 +++++++++++++---------- mumd/src/network/tcp.rs | 33 ++++++++++++++++++++++++++------- mumd/src/state.rs | 45 ++++++++++++++++++++++++++------------------- mumlib/src/command.rs | 1 + mumlib/src/config.rs | 14 ++++++++++++++ 6 files changed, 105 insertions(+), 42 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index bde24a1..cb0ec2f 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -236,7 +236,7 @@ fn match_opt() -> Result<(), Error> { } => { let port = port.unwrap_or(mumlib::DEFAULT_PORT); - let (host, username, password, port) = + let (host, username, password, port, accept_invalid_cert) = match config.servers.iter().find(|e| e.name == host) { Some(server) => ( &server.host, @@ -247,27 +247,45 @@ fn match_opt() -> Result<(), Error> { .ok_or(CliError::NoUsername)?, server.password.as_ref().or(password.as_ref()), server.port.unwrap_or(port), + server.accept_invalid_cert, ), None => ( &host, username.as_ref().ok_or(CliError::NoUsername)?, password.as_ref(), port, + None, ), }; + let accept_invalid_cert = accept_invalid_cert + .or(config.allow_invalid_server_cert); + let specified_accept_invalid_cert = accept_invalid_cert.is_some(); + let response = send_command(MumCommand::ServerConnect { host: host.to_string(), port, username: username.to_string(), password: password.map(|x| x.to_string()), - accept_invalid_cert: true, //TODO + accept_invalid_cert: accept_invalid_cert.unwrap_or(false), //TODO force true/false via flags })??; - if let Some(CommandResponse::ServerConnect { welcome_message }) = response { - println!("Connected to {}", host); - if let Some(message) = welcome_message { - println!("Welcome: {}", message); + match response { + Some(CommandResponse::ServerConnect { welcome_message }) => { + println!("Connected to {}", host); + if let Some(message) = welcome_message { + println!("Welcome: {}", message); + } + } + Some(CommandResponse::ServerCertReject) => { + error!("Connection rejected since the server supplied an invalid certificate."); + if !specified_accept_invalid_cert { + eprintln!("help: If you trust this server anyway, you can do any of the following to connect:"); + // eprintln!(" 1. Temporarily trust this server by passing --accept-invalid-cert when connecting."); + eprintln!(" 1. Permanently trust this server by setting accept_invalid_cert=true in the server's config."); + eprintln!(" 2. Permantently trust all invalid certificates by setting accept_all_invalid_certs=true globally"); + } } + other => unreachable!("Response should only be a ServerConnect or ServerCertReject. Got {:?}", other) } } Command::Disconnect => { @@ -536,6 +554,7 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( port, username, password, + accept_invalid_cert: None, //TODO }); } } diff --git a/mumd/src/command.rs b/mumd/src/command.rs index 410751a..73ab3bd 100644 --- a/mumd/src/command.rs +++ b/mumd/src/command.rs @@ -32,16 +32,19 @@ pub async fn handle( &mut connection_info_sender, ); match event { - ExecutionContext::TcpEventCallback(event, generator) => { - tcp_event_queue.register_callback( - event, - Box::new(move |e| { - let response = generator(e); - for response in response { - response_sender.send(response).unwrap(); - } - }), - ); + ExecutionContext::TcpEventCallback(callbacks) => { + for (event, generator) in callbacks { + let response_sender = response_sender.clone(); + tcp_event_queue.register_callback( + event, + Box::new(move |e| { + let response = generator(e); + for response in response { + response_sender.send(response).unwrap(); + } + }), + ); + } } ExecutionContext::TcpEventSubscriber(event, mut handler) => tcp_event_queue .register_subscriber( diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs index 5cc2bf7..1c7123f 100644 --- a/mumd/src/network/tcp.rs +++ b/mumd/src/network/tcp.rs @@ -35,17 +35,23 @@ type TcpReceiver = pub(crate) type TcpEventCallback = Box; pub(crate) type TcpEventSubscriber = Box bool>; //the bool indicates if it should be kept or not -#[derive(Debug, Clone, Hash, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum DisconnectedReason { + InvalidTls, + Other, +} + +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum TcpEvent { Connected, //fires when the client has connected to a server - Disconnected, //fires when the client has disconnected from a server + Disconnected(DisconnectedReason), //fires when the client has disconnected from a server TextMessage, //fires when a text message comes in } #[derive(Clone)] pub enum TcpEventData<'a> { Connected(Result<&'a msgs::ServerSync, mumlib::Error>), - Disconnected, + Disconnected(DisconnectedReason), TextMessage(&'a msgs::TextMessage), } @@ -53,7 +59,7 @@ impl<'a> From<&TcpEventData<'a>> for TcpEvent { fn from(t: &TcpEventData) -> Self { match t { TcpEventData::Connected(_) => TcpEvent::Connected, - TcpEventData::Disconnected => TcpEvent::Disconnected, + TcpEventData::Disconnected(reason) => TcpEvent::Disconnected(*reason), TcpEventData::TextMessage(_) => TcpEvent::TextMessage, } } @@ -141,12 +147,25 @@ pub async fn handle( } return Err(TcpError::NoConnectionInfoReceived); }; - let (mut sink, stream) = connect( + let connect_result = connect( connection_info.socket_addr, connection_info.hostname, connection_info.accept_invalid_cert, ) - .await?; + .await; + + let (mut sink, stream) = match connect_result { + Ok(ok) => ok, + Err(TcpError::TlsConnectError(_)) => { + warn!("Invalid TLS"); + state.read().unwrap().broadcast_phase(StatePhase::Disconnected); + event_queue.resolve(TcpEventData::Disconnected(DisconnectedReason::InvalidTls)); + continue; + } + Err(e) => { + return Err(e); + } + }; // Handshake (omitting `Version` message for brevity) let (username, password) = { @@ -193,7 +212,7 @@ pub async fn handle( .await .unwrap_or(Ok(()))?; - event_queue.resolve(TcpEventData::Disconnected); + event_queue.resolve(TcpEventData::Disconnected(DisconnectedReason::Other)); debug!("Fully disconnected TCP stream, waiting for new connection info"); } diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 84583e0..e0e3ccd 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -2,7 +2,7 @@ pub mod channel; pub mod server; pub mod user; -use crate::audio::{AudioInput, AudioOutput, NotificationEvents}; +use crate::{audio::{AudioInput, AudioOutput, NotificationEvents}, network::tcp::DisconnectedReason}; use crate::error::StateError; use crate::network::tcp::{TcpEvent, TcpEventData}; use crate::network::{ConnectionInfo, VoiceStreamType}; @@ -26,8 +26,10 @@ use std::{ use tokio::sync::{mpsc, watch}; macro_rules! at { - ($event:expr, $generator:expr) => { - ExecutionContext::TcpEventCallback($event, Box::new($generator)) + ( $( $event:expr => $generator:expr ),+ $(,)? ) => { + ExecutionContext::TcpEventCallback(vec![ + $( ($event, Box::new($generator)), )* + ]) }; } @@ -41,7 +43,7 @@ type Responses = Box Responses>), + TcpEventCallback(Vec<(TcpEvent, Box Responses>)>), TcpEventSubscriber( TcpEvent, Box< @@ -555,22 +557,27 @@ pub fn handle_command( accept_invalid_cert, ))) .unwrap(); - at!(TcpEvent::Connected, |res| { - //runs the closure when the client is connected - if let TcpEventData::Connected(res) = res { - Box::new(iter::once(res.map(|msg| { - Some(CommandResponse::ServerConnect { - welcome_message: if msg.has_welcome_text() { - Some(msg.get_welcome_text().to_string()) - } else { - None - }, - }) - }))) - } else { - unreachable!("callback should be provided with a TcpEventData::Connected"); + at!( + TcpEvent::Connected => |res| { + //runs the closure when the client is connected + if let TcpEventData::Connected(res) = res { + Box::new(iter::once(res.map(|msg| { + Some(CommandResponse::ServerConnect { + welcome_message: if msg.has_welcome_text() { + Some(msg.get_welcome_text().to_string()) + } else { + None + }, + }) + }))) + } else { + unreachable!("callback should be provided with a TcpEventData::Connected"); + } + }, + TcpEvent::Disconnected(DisconnectedReason::InvalidTls) => |_| { + Box::new(iter::once(Ok(Some(CommandResponse::ServerCertReject)))) } - }) + ) } Command::ServerDisconnect => { if !matches!(*state.phase_receiver().borrow(), StatePhase::Connected(_)) { diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 351d7f6..36bda72 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -53,6 +53,7 @@ pub enum CommandResponse { ServerConnect { welcome_message: Option, }, + ServerCertReject, ServerStatus { version: u32, users: u32, diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index 1bd3784..3edef37 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -10,8 +10,15 @@ use std::path::{Path, PathBuf}; use toml::value::Array; use toml::Value; +/// A TOML-friendly version of [Config]. +/// +/// Values need to be placed before tables due to how TOML works. #[derive(Debug, Deserialize, Serialize)] struct TOMLConfig { + // Values + accept_all_invalid_certs: Option, + + // Tables audio: Option, servers: Option, } @@ -20,6 +27,10 @@ struct TOMLConfig { pub struct Config { pub audio: AudioConfig, pub servers: Vec, + /// Whether we allow connecting to servers with invalid server certificates. + /// + /// None implies false but we can show a better message to the user. + pub allow_invalid_server_cert: Option, } impl Config { @@ -64,6 +75,7 @@ pub struct ServerConfig { pub port: Option, pub username: Option, pub password: Option, + pub accept_invalid_cert: Option, } impl ServerConfig { @@ -105,6 +117,7 @@ impl TryFrom for Config { }) .transpose()? .unwrap_or_default(), + allow_invalid_server_cert: config.accept_all_invalid_certs, }) } } @@ -125,6 +138,7 @@ impl From for TOMLConfig { .map(|s| Value::try_from::(s).unwrap()) .collect(), ), + accept_all_invalid_certs: config.allow_invalid_server_cert, } } } -- cgit v1.2.1 From 8744d7bff9941302dba05ddbfa98d50a255fc8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 7 Jun 2021 22:09:27 +0200 Subject: mumctl config for invalid certs --- mumctl/src/main.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index cb0ec2f..c7f2335 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -331,6 +331,11 @@ fn match_opt() -> Result<(), Error> { config.audio.output_volume = Some(volume); } } + "accept_all_invalid_certs" => { + if let Ok(b) = value.parse() { + config.allow_invalid_server_cert = Some(b); + } + } _ => { return Err(CliError::ConfigKeyNotFound(key).into()); } @@ -461,7 +466,7 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( match (key.as_deref(), value) { (None, _) => { print!( - "{}{}{}{}", + "{}{}{}{}{}", format!("host: {}\n", server.host.to_string()), server .port @@ -477,6 +482,10 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( .as_ref() .map(|s| format!("password: {}\n", s)) .unwrap_or_else(|| "".to_string()), + server + .accept_invalid_cert + .map(|b| format!("accept_invalid_cert: {}\n", if b { "true" } else { "false" })) + .unwrap_or_else(|| "".to_string()), ); } (Some("name"), None) => { @@ -509,6 +518,15 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( .ok_or(CliError::NotSet("password".to_string()))? ); } + (Some("accept_invalid_cert"), None) => { + println!( + "{}", + server + .accept_invalid_cert + .map(|b| if b { "true" } else { "false "}) + .ok_or(CliError::NotSet("accept_invalid_cert".to_string()))? + ); + } (Some("name"), Some(_)) => { return Err(CliError::UseServerRename)?; } @@ -525,6 +543,13 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( server.password = Some(value); //TODO ask stdin if empty } + (Some("accept_invalid_cert"), Some(value)) => { + match value.as_ref() { + "true" => server.accept_invalid_cert = Some(true), + "false" => server.accept_invalid_cert = Some(false), + v => warn!("Couldn't parse '{}' as bool", v), + } + } (Some(_), _) => { return Err(CliError::ConfigKeyNotFound(key.unwrap()))?; } -- cgit v1.2.1 From 7072e0fdc79fca1f8de07032dab163ef2a2d0e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 7 Jun 2021 23:02:30 +0200 Subject: only call one callback per event callback registration --- mumd/src/command.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mumd/src/command.rs b/mumd/src/command.rs index 73ab3bd..2a3f148 100644 --- a/mumd/src/command.rs +++ b/mumd/src/command.rs @@ -4,10 +4,7 @@ use crate::state::{ExecutionContext, State}; use log::*; use mumble_protocol::{control::ControlPacket, Serverbound}; use mumlib::command::{Command, CommandResponse}; -use std::sync::{ - atomic::{AtomicU64, Ordering}, - Arc, RwLock, -}; +use std::{rc::Rc, sync::{Arc, RwLock, atomic::{AtomicBool, AtomicU64, Ordering}}}; use tokio::sync::{mpsc, watch}; pub async fn handle( @@ -33,14 +30,18 @@ pub async fn handle( ); match event { ExecutionContext::TcpEventCallback(callbacks) => { + let should_handle = Rc::new(AtomicBool::new(true)); for (event, generator) in callbacks { + let should_handle = Rc::clone(&should_handle); let response_sender = response_sender.clone(); tcp_event_queue.register_callback( event, Box::new(move |e| { - let response = generator(e); - for response in response { - response_sender.send(response).unwrap(); + if should_handle.fetch_and(false, Ordering::Relaxed) { + let response = generator(e); + for response in response { + response_sender.send(response).unwrap(); + } } }), ); -- cgit v1.2.1 From 10757e986d0627c868fbcb457d895deb0c092dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 8 Jun 2021 10:10:21 +0200 Subject: manpage --- documentation/mumdrc.5 | 17 +++++++++++++++-- documentation/mumdrc.txt | 9 +++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/documentation/mumdrc.5 b/documentation/mumdrc.5 index ac0a2f5..00e8265 100644 --- a/documentation/mumdrc.5 +++ b/documentation/mumdrc.5 @@ -2,12 +2,12 @@ .\" Title: mumdrc .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.15 -.\" Date: 2021-04-10 +.\" Date: 2021-06-08 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "MUMDRC" "5" "2021-04-10" "\ \&" "\ \&" +.TH "MUMDRC" "5" "2021-06-08" "\ \&" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -36,6 +36,12 @@ using mumctl(1). .sp The following configuration values are supported: .sp +accept_all_invalid_certs +.RS 4 +Whether to connect to a server that supplies an invalid server certificate. +This is overriden by server\-specific settings. Default false. +.RE +.sp audio.input_volume .RS 4 Default 1.0. @@ -73,6 +79,13 @@ password .RS 4 The password to supply to the server. (Optional) .RE +.sp +accept_invalid_cert +.RS 4 +Whether to connect to this server even if it supplies an invalid server +certificate. This overrides the global accept_all_invalid_certs if set. +Default false. +.RE .SH "AUTHORS" .sp Gustav Sörnäs and Eskil Queseth. diff --git a/documentation/mumdrc.txt b/documentation/mumdrc.txt index ed54b87..0579581 100644 --- a/documentation/mumdrc.txt +++ b/documentation/mumdrc.txt @@ -14,6 +14,10 @@ using mumctl(1). The following configuration values are supported: +accept_all_invalid_certs :: + Whether to connect to a server that supplies an invalid server certificate. + This is overriden by server-specific settings. Default false. + audio.input_volume :: Default 1.0. @@ -38,6 +42,11 @@ username :: password :: The password to supply to the server. (Optional) +accept_invalid_cert :: + Whether to connect to this server even if it supplies an invalid server + certificate. This overrides the global accept_all_invalid_certs if set. + Default false. + Authors ------- -- cgit v1.2.1 From 31aceba9be762e5b8d05ff15dbb4a574e47c5e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 8 Jun 2021 10:11:15 +0200 Subject: changelog --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 63c01a2..21a71a0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,8 @@ Added * --version now includes the current commit hash. * Server passwords. Thanks @rbran! * Added support for sending and receiving text messages + * Invalid server certificates are now rejected by default and need to be + explicitly allowed either per server or globally. Changed ~~~~~~~ -- cgit v1.2.1 From a1d831bb330961e37292910584d31c85afb6c137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 17:36:46 +0200 Subject: add cli-option --accept-invalid-cert --- CHANGELOG | 3 ++- mumctl/src/main.rs | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 21a71a0..e4bc446 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,7 +23,8 @@ Added * Server passwords. Thanks @rbran! * Added support for sending and receiving text messages * Invalid server certificates are now rejected by default and need to be - explicitly allowed either per server or globally. + explicitly allowed either when connecting or permanently per server or + globally. Changed ~~~~~~~ diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index c7f2335..2c73f7b 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -55,6 +55,8 @@ enum Command { password: Option, #[structopt(short = "p", long = "port")] port: Option, + #[structopt(long = "accept-invalid-cert")] + accept_invalid_cert: bool, }, /// Disconnect from the currently connected server Disconnect, @@ -233,10 +235,12 @@ fn match_opt() -> Result<(), Error> { username, password, port, + accept_invalid_cert: cli_accept_invalid_cert, } => { let port = port.unwrap_or(mumlib::DEFAULT_PORT); - let (host, username, password, port, accept_invalid_cert) = + + let (host, username, password, port, server_accept_invalid_cert) = match config.servers.iter().find(|e| e.name == host) { Some(server) => ( &server.host, @@ -258,16 +262,16 @@ fn match_opt() -> Result<(), Error> { ), }; - let accept_invalid_cert = accept_invalid_cert + let config_accept_invalid_cert = server_accept_invalid_cert .or(config.allow_invalid_server_cert); - let specified_accept_invalid_cert = accept_invalid_cert.is_some(); + let specified_accept_invalid_cert = cli_accept_invalid_cert || config_accept_invalid_cert.is_some(); let response = send_command(MumCommand::ServerConnect { host: host.to_string(), port, username: username.to_string(), password: password.map(|x| x.to_string()), - accept_invalid_cert: accept_invalid_cert.unwrap_or(false), //TODO force true/false via flags + accept_invalid_cert: cli_accept_invalid_cert || config_accept_invalid_cert.unwrap_or(false), })??; match response { Some(CommandResponse::ServerConnect { welcome_message }) => { @@ -280,9 +284,9 @@ fn match_opt() -> Result<(), Error> { error!("Connection rejected since the server supplied an invalid certificate."); if !specified_accept_invalid_cert { eprintln!("help: If you trust this server anyway, you can do any of the following to connect:"); - // eprintln!(" 1. Temporarily trust this server by passing --accept-invalid-cert when connecting."); - eprintln!(" 1. Permanently trust this server by setting accept_invalid_cert=true in the server's config."); - eprintln!(" 2. Permantently trust all invalid certificates by setting accept_all_invalid_certs=true globally"); + eprintln!(" 1. Temporarily trust this server by passing --accept-invalid-cert when connecting."); + eprintln!(" 2. Permanently trust this server by setting accept_invalid_cert=true in the server's config."); + eprintln!(" 3. Permantently trust all invalid certificates by setting accept_all_invalid_certs=true globally"); } } other => unreachable!("Response should only be a ServerConnect or ServerCertReject. Got {:?}", other) -- cgit v1.2.1 From f9b258d41e1224e273198abb45bca2343fa7cca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 17:39:19 +0200 Subject: stringbools --- mumctl/src/main.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 2c73f7b..9019f71 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -527,7 +527,7 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( "{}", server .accept_invalid_cert - .map(|b| if b { "true" } else { "false "}) + .map(|b| b.to_string()) .ok_or(CliError::NotSet("accept_invalid_cert".to_string()))? ); } @@ -548,10 +548,9 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( //TODO ask stdin if empty } (Some("accept_invalid_cert"), Some(value)) => { - match value.as_ref() { - "true" => server.accept_invalid_cert = Some(true), - "false" => server.accept_invalid_cert = Some(false), - v => warn!("Couldn't parse '{}' as bool", v), + match value.parse() { + Ok(b) => server.accept_invalid_cert = Some(b), + Err(e) => warn!("{}", e) } } (Some(_), _) => { -- cgit v1.2.1 From 47eb3c8835695ffba375d79efc8a91989003ea2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 17:39:52 +0200 Subject: remove todo --- mumctl/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 9019f71..9de946e 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -582,7 +582,7 @@ fn match_server_command(server_command: Server, config: &mut Config) -> Result<( port, username, password, - accept_invalid_cert: None, //TODO + accept_invalid_cert: None, }); } } -- cgit v1.2.1 From f072343eb4be3ebb60c2d3736b095ab59c630705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 18:24:56 +0200 Subject: doc tcpevent --- mumd/src/network/tcp.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs index 1c7123f..d7b7c0d 100644 --- a/mumd/src/network/tcp.rs +++ b/mumd/src/network/tcp.rs @@ -1,14 +1,12 @@ +use crate::error::{ServerSendError, TcpError}; use crate::network::ConnectionInfo; +use crate::notifications; use crate::state::{State, StatePhase}; -use crate::{ - error::{ServerSendError, TcpError}, - notifications, -}; -use log::*; use futures_util::select; use futures_util::stream::{SplitSink, SplitStream, Stream}; use futures_util::{FutureExt, SinkExt, StreamExt}; +use log::*; use mumble_protocol::control::{msgs, ClientControlCodec, ControlCodec, ControlPacket}; use mumble_protocol::crypt::ClientCryptState; use mumble_protocol::voice::VoicePacket; @@ -35,12 +33,14 @@ type TcpReceiver = pub(crate) type TcpEventCallback = Box; pub(crate) type TcpEventSubscriber = Box bool>; //the bool indicates if it should be kept or not +/// Why the TCP was disconnected. #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum DisconnectedReason { InvalidTls, Other, } +/// Something a callback can register to. Data is sent via a respective [TcpEventData]. #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum TcpEvent { Connected, //fires when the client has connected to a server @@ -48,6 +48,13 @@ pub enum TcpEvent { TextMessage, //fires when a text message comes in } +/// When a [TcpEvent] occurs, this contains the data for the event. +/// +/// The events are picked up by a [crate::state::ExecutionContext]. +/// +/// Having two different types might feel a bit confusing. Essentially, a +/// callback _registers_ to a [TcpEvent] but _takes_ a [TcpEventData] as +/// parameter. #[derive(Clone)] pub enum TcpEventData<'a> { Connected(Result<&'a msgs::ServerSync, mumlib::Error>), -- cgit v1.2.1 From 589560ae3a7ae7a46f4cdfe814393bda261fa53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 18:30:16 +0200 Subject: disconnectedreason::user --- mumd/src/network/tcp.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs index d7b7c0d..cac1533 100644 --- a/mumd/src/network/tcp.rs +++ b/mumd/src/network/tcp.rs @@ -37,7 +37,8 @@ pub(crate) type TcpEventSubscriber = Box bool>; //the #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum DisconnectedReason { InvalidTls, - Other, + User, + TcpError, } /// Something a callback can register to. Data is sent via a respective [TcpEventData]. @@ -195,7 +196,7 @@ pub async fn handle( let phase_watcher_inner = phase_watcher.clone(); - run_until( + let result = run_until( |phase| matches!(phase, StatePhase::Disconnected), async { select! { @@ -217,9 +218,12 @@ pub async fn handle( phase_watcher, ) .await - .unwrap_or(Ok(()))?; + .unwrap_or(Ok(())); - event_queue.resolve(TcpEventData::Disconnected(DisconnectedReason::Other)); + match result { + Ok(()) => event_queue.resolve(TcpEventData::Disconnected(DisconnectedReason::User)), + Err(_) => event_queue.resolve(TcpEventData::Disconnected(DisconnectedReason::TcpError)), + } debug!("Fully disconnected TCP stream, waiting for new connection info"); } -- cgit v1.2.1 From 24ab81363b18f874c68690ae54ba8a27bd46acd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 18:35:00 +0200 Subject: servert cert reject is error --- mumctl/src/main.rs | 9 +++++---- mumd/src/state.rs | 2 +- mumlib/src/command.rs | 1 - mumlib/src/error.rs | 2 ++ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 9de946e..bf1ffdc 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -272,15 +272,15 @@ fn match_opt() -> Result<(), Error> { username: username.to_string(), password: password.map(|x| x.to_string()), accept_invalid_cert: cli_accept_invalid_cert || config_accept_invalid_cert.unwrap_or(false), - })??; + })?; match response { - Some(CommandResponse::ServerConnect { welcome_message }) => { + Ok(Some(CommandResponse::ServerConnect { welcome_message })) => { println!("Connected to {}", host); if let Some(message) = welcome_message { println!("Welcome: {}", message); } } - Some(CommandResponse::ServerCertReject) => { + Err(mumlib::error::Error::ServerCertReject) => { error!("Connection rejected since the server supplied an invalid certificate."); if !specified_accept_invalid_cert { eprintln!("help: If you trust this server anyway, you can do any of the following to connect:"); @@ -289,7 +289,8 @@ fn match_opt() -> Result<(), Error> { eprintln!(" 3. Permantently trust all invalid certificates by setting accept_all_invalid_certs=true globally"); } } - other => unreachable!("Response should only be a ServerConnect or ServerCertReject. Got {:?}", other) + Ok(other) => unreachable!("Response should only be a ServerConnect or ServerCertReject. Got {:?}", other), + Err(e) => return Err(e.into()), } } Command::Disconnect => { diff --git a/mumd/src/state.rs b/mumd/src/state.rs index e0e3ccd..d93181a 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -575,7 +575,7 @@ pub fn handle_command( } }, TcpEvent::Disconnected(DisconnectedReason::InvalidTls) => |_| { - Box::new(iter::once(Ok(Some(CommandResponse::ServerCertReject)))) + Box::new(iter::once(Err(Error::ServerCertReject))) } ) } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 36bda72..351d7f6 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -53,7 +53,6 @@ pub enum CommandResponse { ServerConnect { welcome_message: Option, }, - ServerCertReject, ServerStatus { version: u32, users: u32, diff --git a/mumlib/src/error.rs b/mumlib/src/error.rs index e88bd97..91c15e1 100644 --- a/mumlib/src/error.rs +++ b/mumlib/src/error.rs @@ -11,6 +11,7 @@ pub enum Error { InvalidServerAddr(String, u16), InvalidUsername(String), InvalidServerPassword, + ServerCertReject, } impl std::error::Error for Error {} @@ -26,6 +27,7 @@ impl fmt::Display for Error { } Error::InvalidUsername(username) => write!(f, "Invalid username: {}", username), Error::InvalidServerPassword => write!(f, "Invalid server password"), + Error::ServerCertReject => write!(f, "Invalid server certificate"), } } } -- cgit v1.2.1 From b7701a6f61b525c116e29981f122a58552751f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 11 Jun 2021 18:40:05 +0200 Subject: AtomicBool::swap --- mumd/src/command.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mumd/src/command.rs b/mumd/src/command.rs index 2a3f148..2069178 100644 --- a/mumd/src/command.rs +++ b/mumd/src/command.rs @@ -30,6 +30,7 @@ pub async fn handle( ); match event { ExecutionContext::TcpEventCallback(callbacks) => { + // A shared bool ensures that only one of the supplied callbacks is run. let should_handle = Rc::new(AtomicBool::new(true)); for (event, generator) in callbacks { let should_handle = Rc::clone(&should_handle); @@ -37,7 +38,8 @@ pub async fn handle( tcp_event_queue.register_callback( event, Box::new(move |e| { - if should_handle.fetch_and(false, Ordering::Relaxed) { + // If should_handle == true no other callback has been run yet. + if should_handle.swap(false, Ordering::Relaxed) { let response = generator(e); for response in response { response_sender.send(response).unwrap(); -- cgit v1.2.1