diff --git a/Cargo.lock b/Cargo.lock index 28195ab..5a088b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -739,6 +739,7 @@ dependencies = [ "futures-test", "futures-util", "inventory", + "lazy_static", "libc", "lmdb-rkv", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 66994d2..5885ab7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ serde_dhall = { version = "0.10.1", default-features = false } serde_json = "1.0" once_cell = "1.8" +lazy_static = "1.4.0" rustls = "0.20" futures-rustls = "0.22" diff --git a/bffhd/capnp/authentication.rs b/bffhd/capnp/authentication.rs new file mode 100644 index 0000000..7a55993 --- /dev/null +++ b/bffhd/capnp/authentication.rs @@ -0,0 +1,94 @@ +use std::io::Cursor; +use capnp::capability::Promise; +use capnp::Error; +use capnp_rpc::pry; +use rsasl::session::{Session, Step}; + +use api::auth::authentication::{ + Server, + AbortParams, + AbortResults, + StepParams, + StepResults, +}; +use api::auth::response::{ + Reason, + Action, +}; + +pub struct Authentication { + state: State, +} + +enum State { + InvalidMechanism, + Finished, + Aborted, + Running(Session) +} + +impl Server for Authentication { + fn step(&mut self, params: StepParams, mut results: StepResults) -> Promise<(), Error> { + use State::*; + let new = match self.state { + InvalidMechanism => { + let builder = results.get(); + let mut b = builder.init_error(); + b.set_reason(Reason::BadMechanism); + b.set_action(Action::Permanent); + None + }, + Finished => { + let builder = results.get(); + let mut b = builder.init_error(); + b.set_reason(Reason::Finished); + b.set_action(Action::Permanent); + None + }, + Aborted => { + let builder = results.get(); + let mut b = builder.init_error(); + b.set_reason(Reason::Aborted); + b.set_action(Action::Permanent); + None + }, + Running(ref mut session) => { + // TODO: If null what happens? + let data: &[u8] = pry!(pry!(params.get()).get_data()); + + let mut builder = results.get(); + let mut out = Cursor::new(Vec::new()); + match session.step(Some(data), &mut out) { + Ok(Step::Done(data)) => { + let mut b = builder.init_successful(); + let mut session_builder = b.init_session(); + let session = super::session::Session::new(); + session.build(&mut session_builder); + Some(State::Finished) + }, + Ok(Step::NeedsMore(data)) => { + //builder.set_challenge(data.deref()); + None + }, + Err(_) => { + let mut b = builder.init_error(); + b.set_reason(Reason::Aborted); + b.set_action(Action::Permanent); + Some(State::Aborted) + } + } + } + }; + + if let Some(new) = new { + std::mem::replace(&mut self.state, new); + } + + Promise::ok(()) + } + + fn abort(&mut self, _: AbortParams, _: AbortResults) -> Promise<(), Error> { + std::mem::replace(&mut self.state, State::Aborted); + Promise::ok(()) + } +} \ No newline at end of file diff --git a/bffhd/server/mod.rs b/bffhd/capnp/mod.rs similarity index 58% rename from bffhd/server/mod.rs rename to bffhd/capnp/mod.rs index e56c9bd..e7fdaaa 100644 --- a/bffhd/server/mod.rs +++ b/bffhd/capnp/mod.rs @@ -1,17 +1,12 @@ use std::future::Future; -use futures_util::future::FutureExt; -use async_rustls::TlsStream; use capnp::capability::Promise; use capnp::Error; -use capnp_rpc::rpc_twoparty_capnp::Side; -use capnp_rpc::RpcSystem; -use capnp_rpc::twoparty::VatNetwork; -use smol::io::{AsyncRead, AsyncWrite}; +use futures_rustls::server::TlsStream; +use futures_util::{AsyncRead, AsyncWrite}; use crate::error::Result; use api::bootstrap::{ - Client, Server, MechanismsParams, MechanismsResults, @@ -33,19 +28,8 @@ impl APIHandler { pub fn handle(&mut self, stream: TlsStream) -> impl Future> { - let (mut reader, mut writer) = smol::io::split(stream); - - let bootstrap = ApiSystem {}; - let rpc: Client = capnp_rpc::new_client(bootstrap); - let network = VatNetwork::new( - reader, - writer, - Side::Server, - Default::default(), - ); - let rpc_system = RpcSystem::new(Box::new(network), Some(rpc.client)); - - rpc_system.map(|r| r.map_err(Into::into)) + unimplemented!(); + futures_util::future::ready(Ok(())) } } diff --git a/bffhd/server/resources.rs b/bffhd/capnp/resources.rs similarity index 100% rename from bffhd/server/resources.rs rename to bffhd/capnp/resources.rs diff --git a/bffhd/server/session.rs b/bffhd/capnp/session.rs similarity index 86% rename from bffhd/server/session.rs rename to bffhd/capnp/session.rs index 522265d..8cec3d8 100644 --- a/bffhd/server/session.rs +++ b/bffhd/capnp/session.rs @@ -1,6 +1,6 @@ use api::session::Builder; -use crate::server::resources::Resources; -use crate::server::users::Users; +use crate::capnp::resources::Resources; +use crate::capnp::users::Users; #[derive(Debug, Clone)] pub struct Session { diff --git a/bffhd/server/users.rs b/bffhd/capnp/users.rs similarity index 100% rename from bffhd/server/users.rs rename to bffhd/capnp/users.rs diff --git a/bffhd/error.rs b/bffhd/error.rs index d07ed9a..a7a2ae8 100644 --- a/bffhd/error.rs +++ b/bffhd/error.rs @@ -1,12 +1,12 @@ use std::io; use std::fmt; -use rsasl::SaslError; +use rsasl::error::SessionError; use crate::db::DBError; #[derive(Debug)] /// Shared error type pub enum Error { - SASL(SaslError), + SASL(SessionError), IO(io::Error), Boxed(Box), Capnp(capnp::Error), @@ -39,8 +39,8 @@ impl fmt::Display for Error { } } -impl From for Error { - fn from(e: SaslError) -> Error { +impl From for Error { + fn from(e: SessionError) -> Error { Error::SASL(e) } } diff --git a/bffhd/initiators/mod.rs b/bffhd/initiators/mod.rs index 371fee8..ca70990 100644 --- a/bffhd/initiators/mod.rs +++ b/bffhd/initiators/mod.rs @@ -5,7 +5,6 @@ use async_channel as channel; use async_oneshot as oneshot; use futures_signals::signal::Signal; use futures_util::future::BoxFuture; -use smol::future::FutureExt; use crate::resource::{Error, Update}; use crate::resource::claim::{ResourceID, UserID}; use crate::resource::state::State; @@ -126,7 +125,7 @@ impl + Unpin, I: Initiator + Unpin> Future for Init // If we've send an update to the resource in question we have error channel set, so // we poll that first to determine if the resource has acted on it yet. if let Some(ref mut errchan) = self.error_channel { - match errchan.poll(cx) { + match Pin::new(errchan).poll(cx) { // In case there's an ongoing Poll::Pending => return Poll::Pending, Poll::Ready(Ok(error)) => { @@ -142,7 +141,7 @@ impl + Unpin, I: Initiator + Unpin> Future for Init } if let Some(ref mut init_fut) = self.initiator_future { - match init_fut.poll(cx) { + match init_fut.as_mut().poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(Ok(())) => {}, Poll::Ready(Err(_e)) => { diff --git a/bffhd/lib.rs b/bffhd/lib.rs index 19ec648..49cd862 100644 --- a/bffhd/lib.rs +++ b/bffhd/lib.rs @@ -5,7 +5,7 @@ //! Diflouroborane //! -//! This is the server component of the FabAccess project. +//! This is the capnp component of the FabAccess project. //! The entry point of bffhd can be found in [bin/bffhd/main.rs](../bin/bffhd/main.rs) /// Internal Databases build on top of LMDB, a mmap()'ed B-tree DB optimized for reads @@ -29,6 +29,6 @@ pub mod initiators; pub mod sensors; -pub mod server; +pub mod capnp; pub mod utils; \ No newline at end of file diff --git a/bffhd/server/authentication.rs b/bffhd/server/authentication.rs deleted file mode 100644 index e6ec2e9..0000000 --- a/bffhd/server/authentication.rs +++ /dev/null @@ -1,221 +0,0 @@ -use api::utils::l10n_string; -use crate::error; - -use std::ops::Deref; -use capnp::capability::Promise; -use capnp::Error; -use capnp_rpc::pry; - -use rsasl::{rsasl_err_to_str, SASL, Session as SaslSession, Property, ReturnCode, RSASL, DiscardOnDrop, Mechanisms}; -use rsasl::session::Step::{Done, NeedsMore}; - -use api::auth::authentication::{ - Server, - AbortParams, - AbortResults, - StepParams, - StepResults, -}; -use api::auth::response::{ - Reason, - Action, -}; -use crate::users::{UserDB, PassDB}; - -#[derive(Debug)] -pub struct AuthenticationProvider { - sasl: RSASL, -} - -impl AuthenticationProvider { - pub fn new() -> error::Result { - let sasl = SASL::new()?; - Ok(Self { sasl }) - } - - pub fn mechanisms(&self) -> error::Result { - Ok(self.sasl.server_mech_list()?) - } - - pub fn try_start_session(&mut self, mechanism: &str) -> error::Result { - let session = self.sasl.server_start(mechanism)?; - Ok(Authentication { - state: State::Running(session), - }) - } - - pub fn bad_mechanism(&self) -> Authentication { - Authentication { - state: State::InvalidMechanism, - } - } - - pub fn start_session(&mut self, mechanism: &str) -> Authentication { - self.try_start_session(mechanism) - .unwrap_or_else(|_| self.bad_mechanism()) - } -} - -#[derive(Debug)] -struct Callback; - -#[derive(Debug)] -struct AppData { - userdb: UserDB, - passdb: PassDB, -} - -#[derive(Debug)] -struct SessionData; - -impl rsasl::Callback for Callback { - fn callback(sasl: &mut SASL, - session: &mut SaslSession, - prop: Property - ) -> Result<(), ReturnCode> - { - match prop { - Property::GSASL_VALIDATE_SIMPLE => { - // Access the authentication id, i.e. the username to check the password for - let authcid = session - .get_property(Property::GSASL_AUTHID) - .ok_or(rsasl::GSASL_NO_AUTHID) - .map_err(|_| rsasl::GSASL_NO_AUTHID) - .and_then(|cstr| cstr.to_str() - .map_err(|_| rsasl::GSASL_NO_AUTHID))?; - - // Access the password itself - let password = session - .get_property(Property::GSASL_PASSWORD) - .ok_or(rsasl::GSASL_NO_PASSWORD) - .and_then(|cstr| cstr.to_str() - .map_err(|_| rsasl::GSASL_NO_AUTHID))?; - - let AppData { userdb: _, passdb } = sasl.retrieve_mut() - .ok_or(rsasl::GSASL_NO_CALLBACK)?; - - if let Ok(Some(Ok(true))) = passdb.verify_password(authcid, &password.as_bytes()) { - Ok(()) - } else { - Err(rsasl::GSASL_AUTHENTICATION_ERROR) - } - }, - _ => Err(rsasl::GSASL_NO_CALLBACK), - } - } -} - -#[derive(Debug)] -pub struct Authentication { - state: State, -} - -#[derive(Debug)] -enum State { - InvalidMechanism, - Finished, - Aborted, - Running(DiscardOnDrop>) -} - -impl Server for Authentication { - fn step(&mut self, params: StepParams, mut results: StepResults) -> Promise<(), Error> { - use State::*; - let new = match self.state { - InvalidMechanism => { - let builder = results.get(); - let mut b = builder.init_error(); - b.set_reason(Reason::BadMechanism); - b.set_action(Action::Permanent); - None - }, - Finished => { - let builder = results.get(); - let mut b = builder.init_error(); - b.set_reason(Reason::Finished); - b.set_action(Action::Permanent); - None - }, - Aborted => { - let builder = results.get(); - let mut b = builder.init_error(); - b.set_reason(Reason::Aborted); - b.set_action(Action::Permanent); - None - }, - Running(ref mut session) => { - // TODO: If null what happens? - let data: &[u8] = pry!(pry!(params.get()).get_data()); - - let mut builder = results.get(); - match session.step(data) { - Ok(Done(data)) => { - let mut b = builder.init_successful(); - if !data.is_empty() { - b.reborrow().set_additional_data(data.deref()) - } - let mut session_builder = b.init_session(); - let session = super::session::Session::new(); - session.build(&mut session_builder); - Some(State::Finished) - }, - Ok(NeedsMore(data)) => { - builder.set_challenge(data.deref()); - None - }, - Err(_) => { - let mut b = builder.init_error(); - b.set_reason(Reason::Aborted); - b.set_action(Action::Permanent); - Some(State::Aborted) - } - } - } - }; - - if let Some(new) = new { - std::mem::replace(&mut self.state, new); - } - - Promise::ok(()) - } - - fn abort(&mut self, _: AbortParams, _: AbortResults) -> Promise<(), Error> { - std::mem::replace(&mut self.state, State::Aborted); - Promise::ok(()) - } -} - -#[repr(transparent)] -struct SaslE { - e: ReturnCode, -} - -impl l10n_string::Server for SaslE { - fn get(&mut self, - params: l10n_string::GetParams, - mut results: l10n_string::GetResults - ) -> Promise<(), Error> - { - let lang = pry!(pry!(params.get()).get_lang()); - if lang == "en" { - let mut builder = results.get(); - builder.set_lang("en"); - builder.set_content(rsasl_err_to_str(self.e) - .unwrap_or("Unknown gsasl error")); - } - - Promise::ok(()) - } - - fn available( - &mut self, - _: l10n_string::AvailableParams, - mut results: l10n_string::AvailableResults - ) -> Promise<(), Error> { - let builder = results.get(); - let mut langs = builder.init_langs(1); - langs.set(0, "en"); - Promise::ok(()) - } -} \ No newline at end of file diff --git a/bin/bffhd/main.rs b/bin/bffhd/main.rs index 4fef228..be5f4f3 100644 --- a/bin/bffhd/main.rs +++ b/bin/bffhd/main.rs @@ -150,7 +150,7 @@ fn main() -> Result<(), Error> { ex.spawn(init).detach(); } - server::serve_api_connections(log.clone(), config, db, network, ex) + capnp::serve_api_connections(log.clone(), config, db, network, ex) } */ diff --git a/runtime/executor/src/lib.rs b/runtime/executor/src/lib.rs index 98fcd04..cc22f00 100644 --- a/runtime/executor/src/lib.rs +++ b/runtime/executor/src/lib.rs @@ -10,7 +10,7 @@ //! Main differences between other executors are: //! * Uses SMP based execution scheme to exploit cache affinity on multiple cores and execution is //! equally distributed over the system resources, which means utilizing the all system. -//! * Uses NUMA-aware allocation for scheduler's queues and exploit locality on server workloads. +//! * Uses NUMA-aware allocation for scheduler's queues and exploit locality on capnp workloads. //! * Tailored for creating middleware and working with actor model like concurrency and distributed communication. //! //! **NOTE:** Bastion Executor is independent of it's framework implementation.