diff --git a/Cargo.lock b/Cargo.lock index 3c329db..cf721dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1538,9 +1538,9 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rsasl" -version = "1.0.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8461935926602b09123ddb976f0fa4d54df63b23adff4da0a0e71b96d635fcb0" +checksum = "165e25c96193ef9f5eeb7e68e868c5543b30d6a68bef5470be45ae2416466817" dependencies = [ "discard", "gsasl-sys", diff --git a/Cargo.toml b/Cargo.toml index 7bca114..c7a5f41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ uuid = { version = "0.8.2", features = ["serde", "v4"] } clap = "2.33.3" # TODO update this if bindgen breaks (again) -rsasl = "1.0.1" +rsasl = "1.4.0" #rsasl = { path = "../../rsasl" } # rumqtt needs tokio which I'm trying to get away from diff --git a/src/api.rs b/src/api.rs index 5628c35..7fa5589 100644 --- a/src/api.rs +++ b/src/api.rs @@ -31,33 +31,33 @@ impl Bootstrap { use connection_capnp::bootstrap::*; impl connection_capnp::bootstrap::Server for Bootstrap { - fn auth(&mut self, - _: Params, - mut res: Results + fn authentication_system(&mut self, + _: AuthenticationSystemParams, + mut res: AuthenticationSystemResults ) -> Promise<(), capnp::Error> { // TODO: Forbid mutltiple authentication for now // TODO: When should we allow multiple auth and how do me make sure that does not leak // priviledges (e.g. due to previously issues caps)? - res.get().set_auth(capnp_rpc::new_client(auth::Auth::new(self.db.clone(), self.session.clone()))); + res.get().set_authentication_system(capnp_rpc::new_client(auth::Auth::new(self.db.clone(), self.session.clone()))); Promise::ok(()) } - fn permissions(&mut self, - _: Params, - _: Results + fn permission_system(&mut self, + _: PermissionSystemParams, + _: PermissionSystemResults ) -> Promise<(), capnp::Error> { Promise::ok(()) } - fn machines(&mut self, - _: Params, - mut res: Results + fn machine_system(&mut self, + _: MachineSystemParams, + mut res: MachineSystemResults ) -> Promise<(), capnp::Error> { // TODO actual permission check and stuff let c = capnp_rpc::new_client(Machines::new(self.session.clone(), self.db.clone(), self.nw.clone())); - res.get().set_machines(c); + res.get().set_machine_system(c); Promise::ok(()) } diff --git a/src/api/auth.rs b/src/api/auth.rs index 5f22951..419a32d 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -7,11 +7,11 @@ use std::sync::Arc; use rsasl::{ SASL, + RSASL, Property, Session as SaslSession, ReturnCode, Callback, - SaslCtx, Step, }; @@ -21,7 +21,7 @@ use capnp::capability::{Params, Results, Promise}; use crate::api::Session; -pub use crate::schema::auth_capnp; +pub use crate::schema::authenticationsystem_capnp as auth_system; use crate::db::Databases; use crate::db::pass::PassDB; use crate::db::user::{Internal as UserDB}; @@ -34,31 +34,29 @@ pub struct SessionData { session: Arc, } - struct CB; impl Callback for CB { - fn callback(mut sasl: SaslCtx, mut session: SaslSession, prop: Property) -> libc::c_int { + fn callback(sasl: &mut SASL, + session: &mut SaslSession, + prop: Property + ) -> Result<(), ReturnCode> + { let ret = match prop { Property::GSASL_VALIDATE_SIMPLE => { - // FIXME: get_property and retrive_mut can't be used interleaved but that's + // FIXME: get_property and retrieve_mut can't be used interleaved but that's // technically safe. let cap_session = session.retrieve_mut().map(|sd| sd.session.clone()); - let authid = match session.get_property(Property::GSASL_AUTHID) { - None => return ReturnCode::GSASL_NO_AUTHID as libc::c_int, - Some(a) => { - match a.to_str() { - Ok(s) => s, - Err(_) => return ReturnCode::GSASL_SASLPREP_ERROR as libc::c_int, - } - }, - }; + let authid: &str = session + .get_property(Property::GSASL_AUTHID) + .ok_or(ReturnCode::GSASL_NO_AUTHID) + .and_then(|a| match a.to_str() { + Ok(s) => Ok(s), + Err(_) => Err(ReturnCode::GSASL_SASLPREP_ERROR), + })?; - let pass = session.get_property(Property::GSASL_PASSWORD); - if pass.is_none() { - return ReturnCode::GSASL_NO_PASSWORD as libc::c_int; - } - let pass = pass.unwrap(); + let pass = session.get_property(Property::GSASL_PASSWORD) + .ok_or(ReturnCode::GSASL_NO_PASSWORD)?; if let Some(appdata) = sasl.retrieve_mut() { @@ -70,7 +68,8 @@ impl Callback for CB { } } - ReturnCode::GSASL_OK + // Early return, implicitly returns GSASL_OK + return Ok(()); } else { ReturnCode::GSASL_AUTHENTICATION_ERROR } @@ -86,12 +85,12 @@ impl Callback for CB { ReturnCode::GSASL_NO_CALLBACK } }; - ret as libc::c_int + Err(ret) } } pub struct Auth { - pub ctx: SASL, + pub ctx: RSASL, session: Arc, } @@ -111,11 +110,11 @@ impl Auth { } } -use auth_capnp::authentication::*; -impl auth_capnp::authentication::Server for Auth { +use crate::schema::authenticationsystem_capnp::*; +impl authentication_system::Server for Auth { fn mechanisms(&mut self, - _: Params, - mut res: Results + _: authentication_system::MechanismsParams, + mut res: authentication_system::MechanismsResults ) -> Promise<(), capnp::Error> { let mechs = match self.ctx.server_mech_list() { Ok(m) => m, @@ -139,8 +138,8 @@ impl auth_capnp::authentication::Server for Auth { // TODO: return Outcome instead of exceptions fn start(&mut self, - params: Params, - mut res: Results + params: authentication_system::StartParams, + mut res: authentication_system::StartResults ) -> Promise<(), capnp::Error> { let req = pry!(pry!(params.get()).get_request()); @@ -159,7 +158,7 @@ impl auth_capnp::authentication::Server for Auth { session.store(Box::new(SessionData { session: self.session.clone() })); // If the client has provided initial data go use that - use auth_capnp::request::initial_response::Which; + use request::initial_response::Which; let step_res = match req.get_initial_response().which() { Err(capnp::NotInSchema(_)) => return Promise::err(capnp::Error { @@ -180,7 +179,7 @@ impl auth_capnp::authentication::Server for Auth { // TODO: Set the session user. Needs a lookup though <.> match step_res { Ok(Step::Done(b)) => { - use auth_capnp::response::Result; + use response::Result; let mut outcome = pry!(res.get().get_response()).init_outcome(); outcome.reborrow().set_result(Result::Successful); diff --git a/src/api/machine.rs b/src/api/machine.rs index c9c3642..7a791d3 100644 --- a/src/api/machine.rs +++ b/src/api/machine.rs @@ -6,8 +6,7 @@ use capnp::Error; use futures::FutureExt; -use crate::schema::api_capnp::State; -use crate::schema::api_capnp::machine::*; +use crate::schema::machine_capnp::machine::*; use crate::connection::Session; use crate::db::Databases; use crate::db::machine::{Status, MachineState}; @@ -26,42 +25,9 @@ impl Machine { } pub fn fill(self: Arc, builder: &mut Builder) { - builder.set_read(capnp_rpc::new_client(Read(self.clone()))); - builder.set_write(capnp_rpc::new_client(Write(self.clone()))); builder.set_manage(capnp_rpc::new_client(Manage(self.clone()))); builder.set_admin(capnp_rpc::new_client(Admin(self.clone()))); } - - pub async fn fill_info(&self, builder: &mut m_info::Builder<'_>) { - let guard = self.machine.lock().await; - - builder.set_name(guard.desc.name.as_ref()); - - if let Some(desc) = guard.desc.description.as_ref() { - builder.set_description(desc); - } - - match guard.read_state().lock_ref().deref().state { - Status::Free => { - builder.set_state(State::Free); - } - Status::Disabled => { - builder.set_state(State::Disabled); - } - Status::Blocked(_) => { - builder.set_state(State::Blocked); - } - Status::InUse(_) => { - builder.set_state(State::InUse); - } - Status::ToCheck(_) => { - builder.set_state(State::ToCheck); - } - Status::Reserved(_) => { - builder.set_state(State::Reserved); - } - } - } } #[derive(Clone)] @@ -73,31 +39,15 @@ impl Read { } } -impl read::Server for Read { - fn info(&mut self, - _params: read::InfoParams, - mut results: read::InfoResults) - -> Promise<(), Error> - { - let this = self.clone(); - let f = async move { - let mut b = results.get().init_minfo(); - - this.0.fill_info(&mut b).await; - - Ok(()) - }; - - Promise::from_future(f) - } +impl info::Server for Read { } struct Write(Arc); -impl write::Server for Write { +impl use_::Server for Write { fn use_(&mut self, - _params: write::UseParams, - mut results: write::UseResults) + _params: use_::UseParams, + mut results: use_::UseResults) -> Promise<(), Error> { let uid = self.0.session.user.try_lock().unwrap().as_ref().map(|u| u.id.clone()); @@ -112,9 +62,6 @@ impl write::Server for Write { match res_token { // TODO: Do something with the token we get returned Ok(tok) => { - let gb = GiveBack(Some(tok)); - results.get().set_ret(capnp_rpc::new_client(gb)); - return Ok(()); }, Err(e) => Err(capnp::Error::failed(format!("State change request returned {}", e))), @@ -125,16 +72,19 @@ impl write::Server for Write { } fn reserve(&mut self, - _params: write::ReserveParams, - _results: write::ReserveResults) + _params: use_::ReserveParams, + _results: use_::ReserveResults) -> Promise<(), Error> { unimplemented!() } - fn get_give_back(&mut self, - _params: write::GetGiveBackParams, - mut results: write::GetGiveBackResults) +} + +impl in_use::Server for Write { + fn give_back(&mut self, + _params: in_use::GiveBackParams, + mut results: in_use::GiveBackResults) -> Promise<(), Error> { let this = self.0.clone(); @@ -148,9 +98,6 @@ impl write::Server for Write { let user = sess.user.lock().await; if let Some(u) = user.as_ref() { if u.id == uid { - let token = this.machine.create_token(); - let gb = GiveBack(Some(token)); - results.get().set_ret(capnp_rpc::new_client(gb)); } } }, @@ -164,33 +111,9 @@ impl write::Server for Write { } } -struct GiveBack(Option); - -impl write::give_back::Server for GiveBack { - fn ret(&mut self, - _params: write::give_back::RetParams, - _results: write::give_back::RetResults) - -> Promise<(), Error> - { - if let Some(rt) = self.0.take() { - // Err here just means machine was taken from us - Promise::from_future(rt.map(|()| Ok(()))) - } else { - Promise::ok(()) - } - } -} - struct Manage(Arc); impl manage::Server for Manage { - fn ok(&mut self, - _params: manage::OkParams, - _results: manage::OkResults) - -> Promise<(), Error> - { - unimplemented!() - } } struct Admin(Arc); diff --git a/src/api/machines.rs b/src/api/machines.rs index 2feaed9..91bf6ce 100644 --- a/src/api/machines.rs +++ b/src/api/machines.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use capnp::capability::Promise; use capnp::Error; -use crate::schema::api_capnp::machines; +use crate::schema::machinesystem_capnp::machine_system; +use crate::schema::machinesystem_capnp::machine_system::info as machines; use crate::connection::Session; use crate::db::Databases; @@ -29,40 +30,28 @@ impl Machines { } } +impl machine_system::Server for Machines { + +} + impl machines::Server for Machines { - fn list_machines(&mut self, - _params: machines::ListMachinesParams, - mut results: machines::ListMachinesResults) + fn get_machine_list(&mut self, + _params: machines::GetMachineListParams, + mut results: machines::GetMachineListResults) -> Promise<(), Error> { let v: Vec<(String, crate::machine::Machine)> = self.network.machines.iter() .map(|(n, m)| (n.clone(), m.clone())) .collect(); - let mut machines = results.get().init_machines(v.len() as u32); + /*let mut machines = results.get().init_machines(v.len() as u32); for (i, (name, machine)) in v.into_iter().enumerate() { trace!(self.session.log, "Adding machine #{} {}: {:?}", i, name, machine); let machine = Arc::new(Machine::new(self.session.clone(), machine, self.db.clone())); let mut builder = machines.reborrow().get(i as u32); machine.fill(&mut builder); - } - - Promise::ok(()) - } - - fn get_machine(&mut self, - params: machines::GetMachineParams, - mut results: machines::GetMachineResults) - -> Promise<(), Error> - { - if let Ok(uid) = params.get().and_then(|x| x.get_uid()) { - if let Some(machine_inner) = self.network.machines.get(uid) { - let machine = Arc::new(Machine::new(self.session.clone(), machine_inner.clone(), self.db.clone())); - let mut builder = results.get().init_machine(); - Machine::fill(machine, &mut builder); - } - } + }*/ Promise::ok(()) } diff --git a/src/db/machine.rs b/src/db/machine.rs index b7d8dfa..807a5b3 100644 --- a/src/db/machine.rs +++ b/src/db/machine.rs @@ -7,8 +7,6 @@ use std::sync::Arc; use crate::error::Result; use crate::config::Config; -use uuid::Uuid; - use crate::db::user::UserId; pub mod internal; @@ -34,19 +32,6 @@ pub enum Status { Reserved(UserId), } -pub fn uuid_from_api(uuid: crate::schema::api_capnp::u_u_i_d::Reader) -> Uuid { - let uuid0 = uuid.get_uuid0() as u128; - let uuid1 = uuid.get_uuid1() as u128; - let num: u128 = (uuid1 << 64) + uuid0; - Uuid::from_u128(num) -} -pub fn api_from_uuid(uuid: Uuid, mut wr: crate::schema::api_capnp::u_u_i_d::Builder) { - let num = uuid.as_u128(); - let uuid0 = num as u64; - let uuid1 = (num >> 64) as u64; - wr.set_uuid0(uuid0); - wr.set_uuid1(uuid1); -} #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] /// The status of the machine diff --git a/src/machine.rs b/src/machine.rs index 3ed3436..6e0c543 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,6 +27,29 @@ use crate::db::machine::{MachineIdentifier, MachineState, Status}; use crate::db::user::{User, UserData}; use crate::network::MachineMap; +use crate::space; + +// Registry of all machines configured. +// TODO: +// - Serialize machines into config +// - Deserialize machines from config +// - Index machines on deserialization to we can look them up efficiently +// - Maybe store that index too +// - Iterate over all or a subset of machines efficiently +pub struct Machines { + machines: Vec +} + +impl Machines { + /// Load machines from the config, looking up and linking the database entries as necessary + pub fn load() -> Self { + unimplemented!() + } + + pub fn lookup(id: String) -> Option { + unimplemented!() + } +} #[derive(Debug, Clone)] pub struct Index { @@ -49,15 +72,27 @@ impl Index { } } +// Access data of one machine efficiently, using getters/setters for data stored in LMDB backed +// memory #[derive(Debug, Clone)] pub struct Machine { + pub id: uuid::Uuid, + pub name: String, + pub description: String, + inner: Arc>, access: Arc, } impl Machine { pub fn new(inner: Inner, access: Arc) -> Self { - Self { inner: Arc::new(Mutex::new(inner)), access: access } + Self { + id: uuid::Uuid::default(), + name: "".to_string(), + description: "".to_string(), + inner: Arc::new(Mutex::new(inner)), + access: access, + } } pub fn construct diff --git a/src/main.rs b/src/main.rs index 2333e35..9366742 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod server; mod network; mod actor; mod initiator; +mod space; use clap::{App, Arg}; diff --git a/src/server.rs b/src/server.rs index eaf0eab..4c4a93f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -15,6 +15,9 @@ use std::io; use std::sync::Arc; +use std::os::unix::io::AsRawFd; +use signal_hook::low_level::pipe as sigpipe; + use crate::db::Databases; use crate::network::Network; @@ -27,7 +30,7 @@ pub fn serve_api_connections(log: Arc, config: Config, db: Databases, nw // Initialize signal handler. // We currently only care about Ctrl-C so SIGINT it is. // TODO: Make this do SIGHUP and a few others too. (By cloning the tx end of the pipe) - signal_hook::pipe::register(signal_hook::SIGINT, tx)?; + sigpipe::register(signal_hook::consts::SIGINT, tx.as_raw_fd())?; // When a signal is received this future can complete and read a byte from the underlying // socket — the actual data is discarded but the act of being able to receive data tells us // that we received a SIGINT. diff --git a/src/space.rs b/src/space.rs new file mode 100644 index 0000000..6e28bce --- /dev/null +++ b/src/space.rs @@ -0,0 +1,9 @@ +use uuid::Uuid; + +#[derive(Debug, Clone)] +pub struct Space { + pub id: Uuid, + pub name: String, + pub info: String, +} +