aboutsummaryrefslogtreecommitdiffhomepage
path: root/oxish/src
diff options
context:
space:
mode:
Diffstat (limited to 'oxish/src')
-rw-r--r--oxish/src/authentication.rs57
-rw-r--r--oxish/src/lib.rs5
2 files changed, 39 insertions, 23 deletions
diff --git a/oxish/src/authentication.rs b/oxish/src/authentication.rs
index c71381a..551f291 100644
--- a/oxish/src/authentication.rs
+++ b/oxish/src/authentication.rs
@@ -50,6 +50,25 @@ pub(crate) async fn authenticate<T: AsyncRead + AsyncWrite + Unpin>(
) -> Result<User, Error> {
let future = inner(session_id, conn, store, provider);
if let Ok(result) = timeout(Duration::from_secs(60), future).await {
+ if let Err(error) = &result {
+ let disconnect = match error {
+ Error::Auth(AuthError::TooManyAttempts) => Disconnect {
+ reason_code: DisconnectReason::ByApplication,
+ description: "too many authentication attempts",
+ },
+ Error::Proto(ProtoError::ServiceNotAvailable(description)) => Disconnect {
+ reason_code: DisconnectReason::ServiceNotAvailable,
+ description,
+ },
+ _ => Disconnect {
+ reason_code: DisconnectReason::ByApplication,
+ description: "authentication failed",
+ },
+ };
+
+ conn.send(&disconnect).await?;
+ }
+
return result;
}
@@ -77,13 +96,10 @@ async fn inner<T: AsyncRead + AsyncWrite + Unpin>(
"unsupported service requested"
);
- let disconnect = Disconnect {
- reason_code: DisconnectReason::ServiceNotAvailable,
- description: "only user authentication service is supported",
- };
-
- conn.send(&disconnect).await?;
- return Err(Error::InvalidState("unsupported service requested"));
+ return Err(ProtoError::ServiceNotAvailable(
+ "only user authentication service is supported",
+ )
+ .into());
}
let service_accept = ServiceAccept {
@@ -96,14 +112,7 @@ async fn inner<T: AsyncRead + AsyncWrite + Unpin>(
loop {
attempts -= 1;
if attempts == 0 {
- error!("too many authentication attempts");
- let disconnect = Disconnect {
- reason_code: DisconnectReason::ProtocolError,
- description: "too many authentication attempts",
- };
-
- conn.send(&disconnect).await?;
- return Err(Error::InvalidState("too many authentication attempts"));
+ return Err(AuthError::TooManyAttempts.into());
}
let packet = receive(&mut conn.stream, &mut conn.read).await?;
@@ -122,13 +131,9 @@ async fn inner<T: AsyncRead + AsyncWrite + Unpin>(
"unsupported service requested"
);
- let disconnect = Disconnect {
- reason_code: DisconnectReason::ServiceNotAvailable,
- description: "only connection service is supported",
- };
-
- conn.send(&disconnect).await?;
- return Err(Error::InvalidState("unsupported service requested"));
+ return Err(
+ ProtoError::ServiceNotAvailable("only connection service is supported").into(),
+ );
}
let Method::PublicKey(public_key) = user_auth_request.method else {
@@ -666,6 +671,14 @@ fn check_permissions(file: &File, uid: u32, level: &str) -> ControlFlow<()> {
}
}
+/// Errors that can occur during authentication
+#[derive(Debug, Error)]
+pub enum AuthError {
+ /// Too many authentication attempts for a single connection
+ #[error("too many authentication attempts")]
+ TooManyAttempts,
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/oxish/src/lib.rs b/oxish/src/lib.rs
index 65b3554..d1c299c 100644
--- a/oxish/src/lib.rs
+++ b/oxish/src/lib.rs
@@ -48,7 +48,7 @@ pub use graviola::DEFAULT_PROVIDER;
compile_error!("no crypto providers enabled -- enable at least one to fix this error");
mod authentication;
-pub use authentication::{DefaultStore, User, UserStore, Username};
+pub use authentication::{AuthError, DefaultStore, User, UserStore, Username};
mod session;
pub use session::Session;
mod server;
@@ -488,6 +488,9 @@ async fn buffer<'a>(
/// Error type for SSH connections
#[derive(Debug, Error)]
pub enum Error {
+ /// Authentication errors
+ #[error("authentication error: {0}")]
+ Auth(#[from] AuthError),
/// Invalid state encountered during SSH session
#[error("invalid state: {0}")]
InvalidState(&'static str),