From: Ian Jackson Date: Tue, 20 Oct 2020 18:05:22 +0000 (+0100) Subject: wip new account etc. X-Git-Tag: otter-0.2.0~617 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=811909c0f1a8af3b53a707ceb12f74795d0610d5;p=otter.git wip new account etc. Signed-off-by: Ian Jackson --- diff --git a/src/accounts.rs b/src/accounts.rs index 9b53b257..4dc20f46 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -101,21 +101,22 @@ pub fn save_accounts_now() -> Result<(), InternalError> { } impl AccountRecord { - pub fn lookup(account: &AccountName, _: Authorised) + pub fn lookup(account: &AccountName, _: Authorisation) -> Option> { ACCOUNTS.read().map( |accounts| accounts?.get(account) ) } pub fn lookup_mut_caller_must_save(account: &AccountName, - _: Authorised) + _: Authorisation) -> Option> { ACCOUNTS.write().map( |accounts| accounts?.get(account) ) } - pub fn with_entry_mut(account: &AccountName, f: F, - _: Authorised) + pub fn with_entry_mut(account: &AccountName, + _: Authorisation, + f: F) -> Result where F: FnOnce(Option<&mut AccountRecord>) -> T { diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index f4c1a568..a725dae1 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -56,15 +56,16 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { SetAccount(wanted_account) => { let authorised = authorise_scope(cs, &wanted_account.scope)?; - cs.account = ScopedName { - scope: Some(authorised.into_inner()), - scoped_nmae: wanted_account.scoped_name, - }; + cs.account = Some(( + wanted_account, + authorised.therefore_ok(), + )); Fine }, CreateGame { game, insns } => { let authorised = authorise_scope(cs, &game.scope)?; + let authorised : Authorisation = authorised.therefore_ok(); let gs = crate::gamestate::GameState { table_size : DEFAULT_TABLE_SIZE, @@ -81,7 +82,7 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { execute_for_game(cs, &mut ig, insns, MgmtGameUpdateMode::Bulk) .map_err(|e|{ let name = ig.name.clone(); - Instance::destroy_game(ig) + Instance::destroy_game(ig, authorised) .unwrap_or_else(|e| warn!( "failed to tidy up failecd creation of {:?}: {:?}", &name, &e @@ -104,12 +105,8 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { GamesList(games) }, - MgmtCommand::AlterGame { name, insns, how} => { - let name = ScopedName { - scope: cs.get_scope()?.clone(), - scoped_name: name - }; - let gref = Instance::lookup_by_name(&name)?; + MgmtCommand::AlterGame { game, insns, how } => { + let gref = Instance::lookup_by_name_unauth(&game)?; let mut g = gref.lock()?; execute_for_game(cs, &mut g, insns, how)? }, @@ -229,7 +226,7 @@ fn execute_game_insn(cs: &CommandStream, let authorised : AuthorisedSatisfactory = authorise_scope(cs, &AS::Server)?; let authorised = match authorised.into_inner() { - AS::Server => Authorised::::authorise(), + AS::Server => Authorisation::::authorise(), _ => panic!(), }; ig.player_access_register_fixed( @@ -419,7 +416,7 @@ impl UpdateHandler { struct CommandStream<'d> { euid : Result, desc : &'d str, - account : Option<(AccountName, Authorised)>, + account : Option<(AccountName, Authorisation)>, chan : MgmtChannel, who: Who, } @@ -443,7 +440,7 @@ impl CommandStream<'_> { } #[throws(MgmtError)] - fn current_account(&self) -> (&AccountName, Authorised) { + fn current_account(&self) -> (&AccountName, Authorisation) { self.scope.as_ref() .ok_or(ME::SpecifyAccount)? .map(|(account,auth)| (account,*auth)) @@ -534,14 +531,14 @@ pub struct ConnectionEuidDiscoverEerror(String); impl CommandStream<'_> { #[throws(AuthorisationError)] fn authorised_uid(&self, wanted: Option, xinfo: Option<&str>) - -> Authorised<(Passwd,Uid),> { + -> Authorisation<(Passwd,Uid),> { let client_euid = *self.euid.as_ref().map_err(|e| e.clone())?; let server_uid = Uid::current(); if client_euid.is_root() || client_euid == server_uid || Some(client_euid) == wanted { - return Authorised::authorise(); + return Authorisation::authorise(); } throw!(anyhow!("{}: euid mismatch: client={:?} server={:?} wanted={:?}{}", &self.desc, client_euid, server_uid, wanted, @@ -557,18 +554,18 @@ impl CommandStream<'_> { #[throws(MgmtError)] fn authorise_scope(cs: &CommandStream, wanted: &AccountScope) - -> Authorised { + -> Authorisation { do_authorise_scope(cs, wanted) .map_err(|e| cs.map_auth_err(e))? } #[throws(AuthorisationError)] fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) - -> Authorised { + -> Authorisation { match &wanted { AccountScope::Server => { - let y : Authorised<(Passwd,Uid)> = { + let y : Authorisation<(Passwd,Uid)> = { cs.authorised_uid(None,None)?; }; y.therefore_ok() @@ -577,13 +574,13 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) AccountScope::Unix { user: wanted } => { struct InUserList; - let y : Authorised<(Passwd,Uid,InUserList)> = { + let y : Authorisation<(Passwd,Uid,InUserList)> = { struct AuthorisedIf { authorised_for : Option }; - const SERVER_ONLY : (AuthorisedIf, Authorised) = ( + const SERVER_ONLY : (AuthorisedIf, Authorisation) = ( AuthorisedIf { authorised_for: None }, - Authorised::authorised(InUserList), + Authorisation::authorised(&InUserList), ); let pwent = Passwd::from_name(&wanted) @@ -596,7 +593,7 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) "requested username {:?} not found", &wanted )) )?; - let pwent_ok = Authorised::authorised(pwent); + let pwent_ok = Authorisation::authorised(pwent); let ((uid, in_userlist_ok), xinfo) = (||{ >::Ok({ let allowed = BufReader::new(match File::open(USERLIST) { @@ -617,7 +614,7 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) (AuthorisedIf{ authorised_for: Some( Uid::from_raw(pwent.uid) )}, - Authorised::authorised(InUserList), + Authorisation::authorised(InUserList), ), None )) @@ -649,24 +646,38 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) use authproofs::*; use authproofs::AuthorisationError; -pub use authproofs::Authorised; +pub use authproofs::Authorisation; +pub use authproofs::Unauthorised; mod authproofs { use crate::imports::*; + #[derive(Debug,Copy,Clone)] + pub struct Unauthorised (T, PhantomData); + impl Unauthorised { + pub fn of(t: T) -> Self { Unauthorised(t, PhantomData) } + pub fn by(self, _auth: Authorisation) -> T { self.0 } + } + impl From for Unauthorised { + fn from(t: T) -> Self { Self::of(t) } + } + #[derive(Error,Debug)] #[error("internal AuthorisationError {0}")] pub struct AuthorisationError(pub String); - pub struct Authorised (PhantomData); + pub struct Authorisation (PhantomData); - impl Authorised { - pub const fn authorise_any() -> Authorised { Authorised(PhantomData) } - pub const fn authorised(v: &T) -> Authorised { Authorised(PhantomData) } - } - - impl Authorised { - pub fn therefore_ok(self) -> Authorised { Authorised(PhantomData) } + impl Authorisation { + pub const fn authorise_any() -> Authorisation { + Authorisation(PhantomData) + } + pub const fn authorised(v: &T) -> Authorisation { + Authorisation(PhantomData) + } + pub fn therefore_ok(self) -> Authorisation { + Authorisation(PhantomData) + } } impl From for AuthorisationError { @@ -680,16 +691,18 @@ mod authproofs { } } - pub trait AuthorisedCombine { + pub trait AuthorisationCombine { type Output; - fn combine(self) -> Authorised { Authorised(PhantomData) } + fn combine(self) -> Authorisation { + Authorisation(PhantomData) + } } - impl AuthorisedCombine - for (Authorised, Authorised) { - type Output = Authorised<(A, B)>; + impl AuthorisationCombine + for (Authorisation, Authorisation) { + type Output = Authorisation<(A, B)>; } - impl AuthorisedCombine - for (Authorised, Authorised, Authorised) { - type Output = Authorised<(A, B, C)>; + impl AuthorisationCombine + for (Authorisation, Authorisation, Authorisation) { + type Output = Authorisation<(A, B, C)>; } } diff --git a/src/global.rs b/src/global.rs index 065f721c..44289704 100644 --- a/src/global.rs +++ b/src/global.rs @@ -251,11 +251,19 @@ impl InstanceRef { } } +impl Unauthorised { + #[throws(InstanceLockError)] + pub fn lock(&self) -> Unauthorised, A> { + let must_not_escape = self.by(Authorisation::authorise_any()); + Unauthorised::of(must_not_escape.lock()?) + } +} + impl Instance { /// Returns `None` if a game with this name already exists #[allow(clippy::new_ret_no_self)] #[throws(MgmtError)] - pub fn new(name: InstanceName, gs: GameState, _: Authorised) + pub fn new(name: InstanceName, gs: GameState, _: Authorisation) -> InstanceRef { let name = Arc::new(name); @@ -301,16 +309,25 @@ impl Instance { } #[throws(MgmtError)] - pub fn lookup_by_name(name: &InstanceName, _: Authorised) + pub fn lookup_by_name_unauth(name: &InstanceName) + -> Unauthorised { + Unauthorised::of( + GLOBAL.games.read().unwrap() + .get(name) + .ok_or(MgmtError::GameNotFound)? + .clone() + .into() + ) + } + + #[throws(MgmtError)] + pub fn lookup_by_name(name: &InstanceName, auth: Authorisation) -> InstanceRef { - GLOBAL.games.read().unwrap() - .get(name) - .ok_or(MgmtError::GameNotFound)? - .clone() + Self::lookup_by_name_unauth(name)?.by(auth) } #[throws(InternalError)] - pub fn destroy_game(mut g: InstanceGuard, _: Authorised) { + pub fn destroy_game(mut g: InstanceGuard, _: Authorisation) { let a_savefile = savefilename(&g.name, "a-", ""); let mut gw = GLOBAL.games.write().unwrap(); @@ -335,7 +352,8 @@ impl Instance { ); } - pub fn list_names(scope: Option<&AccountScope>, _: Authorised) + pub fn list_names(scope: Option<&AccountScope>, + _: Authorisation) -> Vec> { let games = GLOBAL.games.read().unwrap(); let out : Vec> = @@ -511,7 +529,7 @@ impl InstanceGuard<'_> { #[throws(MgmtError)] pub fn player_access_register_fixed(&mut self, player: PlayerId, token: RawToken, - _safe: Authorised + _safe: Authorisation ) { // xxx get rid of this or something ? self.tokens_deregister_for_id(|id:PlayerId| id==player); @@ -524,7 +542,8 @@ impl InstanceGuard<'_> { } #[throws(MgmtError)] - pub fn player_access_reset(&mut self, player: PlayerId) + pub fn player_access_reset(&mut self, player: PlayerId, + authorised: Authorisation) -> Option { // xxx call this function when access changes @@ -533,7 +552,10 @@ impl InstanceGuard<'_> { .pst; self.save_access_now()?; - let access = AccountRecord::with_entry_mut(&pst.account, |acct|{ + let access = AccountRecord::with_entry_mut( + &pst.account, authorised, + |acct| + { let acct = acct.ok_or(MgmtError::AccountNotFound)?; let access = acct.access; let desc = access.describe_html();