diff --git a/Cargo.lock b/Cargo.lock index 389e940..ecc2d45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,10 @@ # It is not intended for manual editing. [[package]] name = "agreety" -version = "0.1.0" +version = "0.2.0" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "greet_proto 0.2.0", + "greet_proto 0.3.0", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rust-ini 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "greet_proto" -version = "0.2.0" +version = "0.3.0" dependencies = [ "async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -174,12 +174,12 @@ dependencies = [ [[package]] name = "greetd" -version = "0.1.1" +version = "0.2.0" dependencies = [ "async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "greet_proto 0.2.0", + "greet_proto 0.3.0", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "pam-sys 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/README.md b/README.md index 1a97850..d5eb683 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,13 @@ The greeter runs as a configured user, which is supposed to be one with no inter # Protocol ``` - ________________________________________________________ -| | | | | -| magic u32 | version u32 | payload_length u32 | payload | -|___________|_____________|____________________|_________| + _______________________________ +| | | +| payload_length u32 | payload | +|____________________|_________| ``` -Magic is always `0xAFBFCFDF`, version is `1`, payload is JSON. +`payload_length` is native endianness, payload is JSON. Requests and responses are encoded the same. @@ -79,14 +79,14 @@ Create a new session for the given user. This may result in authentication quest } ``` -### AnswerAuthQuestion +### PostAuthMessageResponse Answer an authentication question. ``` { - "type": "answer_auth_question", - "answer": "password" + "type": "post_auth_message_response", + "response": "password" } ``` @@ -140,14 +140,14 @@ The action failed. ``` -### AuthQuestion +### AuthMessage The action resulted in authentication questions. ``` { - "type": "auth_question", - "question": "Password: ", - "style": "secret" + "type": "auth_message", + "message": "Password: ", + "message_type": "secret" } ``` \ No newline at end of file diff --git a/agreety/src/main.rs b/agreety/src/main.rs index 3c8ea23..1047d8c 100644 --- a/agreety/src/main.rs +++ b/agreety/src/main.rs @@ -9,7 +9,7 @@ use ini::Ini; use nix::sys::utsname::uname; use rpassword::prompt_password_stderr; -use greet_proto::{codec::SyncCodec, ErrorType, QuestionStyle, Request, Response}; +use greet_proto::{codec::SyncCodec, AuthMessageType, ErrorType, Request, Response}; fn prompt_stderr(prompt: &str) -> Result> { let stdin = io::stdin(); @@ -65,22 +65,25 @@ fn login(node: &str, cmd: &Option) -> Result { - let answer = match style { - QuestionStyle::Visible => prompt_stderr(&question)?, - QuestionStyle::Secret => prompt_password_stderr(&question)?, - QuestionStyle::Info => { - eprintln!("info: {}", question); + Response::AuthMessage { + auth_message, + auth_message_type, + } => { + let answer = match auth_message_type { + AuthMessageType::Visible => prompt_stderr(&auth_message)?, + AuthMessageType::Secret => prompt_password_stderr(&auth_message)?, + AuthMessageType::Info => { + eprintln!("info: {}", auth_message); "".to_string() } - QuestionStyle::Error => { - eprintln!("error: {}", question); + AuthMessageType::Error => { + eprintln!("error: {}", auth_message); "".to_string() } }; - next_request = Request::AnswerAuthQuestion { - answer: Some(answer), + next_request = Request::PostAuthMessageResponse { + response: Some(answer), }; } Response::Success => { diff --git a/greet_proto/src/lib.rs b/greet_proto/src/lib.rs index 09dcf1b..0637e8c 100644 --- a/greet_proto/src/lib.rs +++ b/greet_proto/src/lib.rs @@ -46,28 +46,28 @@ use serde::{Deserialize, Serialize}; #[serde(tag = "type")] pub enum Request { /// CreateSession initiates a login attempt for the given user. - /// CreateSession returns either a Response::AuthQuestion, + /// CreateSession returns either a Response::AuthMessage, /// Response::Success or Response::Failure. /// - /// If a question is returned, it should be answered with a - /// Request::AnswerAuthQuestion. If a success is returned, the session can - /// then be started with Request::StartSession. + /// If an auth message is returned, it should be answered with a + /// Request::PostAuthMessageResponse. If a success is returned, the session + /// can then be started with Request::StartSession. /// /// If a login flow needs to be aborted at any point, send /// Request::CancelSession. Note that the session is cancelled /// automatically on error. CreateSession { username: String }, - /// AnswerAuthQuestion answers the last auth question, and returns either - /// a Response::AuthQuestion, Response::Success or Response::Failure. + /// PostAuthMessageResponse responds to the last auth message, and returns + /// either a Response::AuthMessage, Response::Success or Response::Failure. /// - /// If a question is returned, it should be answered with a - /// Request::AnswerAuthQuestion. If a success is returned, the session can - /// then be started with Request::StartSession. - AnswerAuthQuestion { answer: Option }, + /// If an auth message is returned, it should be answered with a + /// Request::PostAuthMessageResponse. If a success is returned, the session + /// can then be started with Request::StartSession. + PostAuthMessageResponse { response: Option }, /// Start a successfully logged in session. This will fail if the session - /// has pending questions or has encountered an error. + /// has pending messages or has encountered an error. StartSession { cmd: Vec, env: Vec }, /// Cancel a session. This can only be done if the session has not been @@ -87,10 +87,10 @@ pub enum ErrorType { AuthError, } -/// A question style for a Response::AuthQuestion. Serialized as snake_case. +/// A message type for a Response::AuthMessage. Serialized as snake_case. #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] -pub enum QuestionStyle { +pub enum AuthMessageType { /// A question whose answer should be visible during input. Visible, @@ -111,9 +111,9 @@ pub enum QuestionStyle { /// /// ```json /// { -/// "type": "auth_question", -/// "question": "Password:", -/// "style": "secret" +/// "type": "auth_message", +/// "message": "Password:", +/// "message_type": "secret" /// } /// ``` #[derive(Debug, Deserialize, Serialize)] @@ -130,18 +130,18 @@ pub enum Response { description: String, }, - /// An authentication question needs to be answered to continue through the + /// An authentication message needs to be answered to continue through the /// authentication flow. /// - /// An authentication question can consist of anything. While it will + /// An authentication message can consist of anything. While it will /// commonly just be a request for the users' password, it could also ask /// for TOTP codes, or whether or not you felt sad when Littlefoot's mother /// died in the original "Land Before Time". It is therefore important that /// no assumptions are made about the questions that will be asked, and /// attempts to automatically answer these questions should not be made. - AuthQuestion { - style: QuestionStyle, - question: String, + AuthMessage { + auth_message_type: AuthMessageType, + auth_message: String, }, } diff --git a/greetd/src/context.rs b/greetd/src/context.rs index c470d11..a89be51 100644 --- a/greetd/src/context.rs +++ b/greetd/src/context.rs @@ -10,10 +10,10 @@ use crate::{ error::Error, session::{ interface::{Session, SessionChild, SessionState}, - worker::QuestionStyle as SessQuestionStyle, + worker::AuthMessageType as SessAuthMessageType, }, }; -use greet_proto::QuestionStyle; +use greet_proto::AuthMessageType; struct SessionChildSet { child: SessionChild, @@ -139,17 +139,17 @@ impl Context { } /// Retrieve a question from the session under configuration. - pub async fn get_question(&self) -> Result, Error> { + pub async fn get_question(&self) -> Result, Error> { let mut inner = self.inner.write().await; match &mut inner.configuring { Some(s) => match s.session.get_state().await? { SessionState::Ready => Ok(None), SessionState::Question(style, string) => Ok(Some(( match style { - SessQuestionStyle::Visible => QuestionStyle::Visible, - SessQuestionStyle::Secret => QuestionStyle::Secret, - SessQuestionStyle::Info => QuestionStyle::Info, - SessQuestionStyle::Error => QuestionStyle::Error, + SessAuthMessageType::Visible => AuthMessageType::Visible, + SessAuthMessageType::Secret => AuthMessageType::Secret, + SessAuthMessageType::Info => AuthMessageType::Info, + SessAuthMessageType::Error => AuthMessageType::Error, }, string, ))), @@ -159,10 +159,10 @@ impl Context { } /// Answer a question to the session under configuration. - pub async fn post_answer(&self, answer: Option) -> Result<(), Error> { + pub async fn post_response(&self, answer: Option) -> Result<(), Error> { let mut inner = self.inner.write().await; match &mut inner.configuring { - Some(s) => s.session.post_answer(answer).await, + Some(s) => s.session.post_response(answer).await, None => Err("no session under configuration".into()), } } diff --git a/greetd/src/server.rs b/greetd/src/server.rs index 7d43f9c..6183d4b 100644 --- a/greetd/src/server.rs +++ b/greetd/src/server.rs @@ -42,9 +42,9 @@ fn wrap_result(res: Result) -> Response { async fn client_get_question(ctx: &Context) -> Response { match ctx.get_question().await { - Ok(Some((style, msg))) => Response::AuthQuestion { - style, - question: msg, + Ok(Some((auth_message_type, auth_message))) => Response::AuthMessage { + auth_message_type, + auth_message, }, res => wrap_result(res), } @@ -63,10 +63,12 @@ async fn client_handler(ctx: Rc, mut s: UnixStream) -> Result<(), Error Ok(()) => client_get_question(&ctx).await, res => wrap_result(res), }, - Request::AnswerAuthQuestion { answer } => match ctx.post_answer(answer).await { - Ok(()) => client_get_question(&ctx).await, - res => wrap_result(res), - }, + Request::PostAuthMessageResponse { response } => { + match ctx.post_response(response).await { + Ok(()) => client_get_question(&ctx).await, + res => wrap_result(res), + } + } Request::StartSession { cmd, env } => wrap_result(ctx.start(cmd, env).await), Request::CancelSession => wrap_result(ctx.cancel().await), }; diff --git a/greetd/src/session/conv.rs b/greetd/src/session/conv.rs index 6ae2a4b..e3867c9 100644 --- a/greetd/src/session/conv.rs +++ b/greetd/src/session/conv.rs @@ -1,4 +1,4 @@ -use super::worker::{ParentToSessionChild, QuestionStyle, SessionChildToParent}; +use super::worker::{AuthMessageType, ParentToSessionChild, SessionChildToParent}; use crate::pam::converse::Converse; /// SessionConv is a PAM conversation implementation that forwards questions @@ -8,7 +8,7 @@ pub struct SessionConv<'a> { } impl<'a> SessionConv<'a> { - fn question(&self, msg: &str, style: QuestionStyle) -> Result { + fn question(&self, msg: &str, style: AuthMessageType) -> Result { let msg = SessionChildToParent::PamMessage { style, msg: msg.to_string(), @@ -34,15 +34,15 @@ impl<'a> SessionConv<'a> { impl<'a> Converse for SessionConv<'a> { fn prompt_echo(&self, msg: &str) -> Result { - self.question(msg, QuestionStyle::Visible) + self.question(msg, AuthMessageType::Visible) } fn prompt_blind(&self, msg: &str) -> Result { - self.question(msg, QuestionStyle::Secret) + self.question(msg, AuthMessageType::Secret) } fn info(&self, msg: &str) -> Result<(), ()> { - self.question(msg, QuestionStyle::Info).map(|_| ()) + self.question(msg, AuthMessageType::Info).map(|_| ()) } fn error(&self, msg: &str) -> Result<(), ()> { - self.question(msg, QuestionStyle::Error).map(|_| ()) + self.question(msg, AuthMessageType::Error).map(|_| ()) } } diff --git a/greetd/src/session/interface.rs b/greetd/src/session/interface.rs index 9e88c61..e654a3b 100644 --- a/greetd/src/session/interface.rs +++ b/greetd/src/session/interface.rs @@ -13,7 +13,7 @@ use async_trait::async_trait; use tokio::net::UnixDatagram as TokioUnixDatagram; -use super::worker::{ParentToSessionChild, QuestionStyle, SessionChildToParent}; +use super::worker::{AuthMessageType, ParentToSessionChild, SessionChildToParent}; use crate::error::Error; #[async_trait] @@ -78,7 +78,7 @@ impl SessionChild { #[derive(Debug)] pub enum SessionState { - Question(QuestionStyle, String), + Question(AuthMessageType, String), Ready, } @@ -158,9 +158,9 @@ impl Session { Ok(()) } - /// Send an answer to an authentication question, or None to cahncel the + /// Send a response to an authentication question, or None to cancel the /// authentication attempt. - pub async fn post_answer(&mut self, answer: Option) -> Result<(), Error> { + pub async fn post_response(&mut self, answer: Option) -> Result<(), Error> { self.last_msg = None; let msg = match answer { Some(resp) => ParentToSessionChild::PamResponse { resp }, diff --git a/greetd/src/session/worker.rs b/greetd/src/session/worker.rs index 248fc0e..c5a7ecc 100644 --- a/greetd/src/session/worker.rs +++ b/greetd/src/session/worker.rs @@ -15,7 +15,7 @@ use super::{ use crate::{error::Error, pam::session::PamSession, terminal}; #[derive(Clone, Debug, Serialize, Deserialize)] -pub enum QuestionStyle { +pub enum AuthMessageType { Visible, Secret, Info, @@ -55,7 +55,7 @@ impl ParentToSessionChild { pub enum SessionChildToParent { Success, Error(Error), - PamMessage { style: QuestionStyle, msg: String }, + PamMessage { style: AuthMessageType, msg: String }, FinalChildPid(u64), }