From 47233b4bf477cb70241be8193ef08aa683f12cf8 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 19 Oct 2020 19:12:47 +0100 Subject: [PATCH] wip new account etc. Signed-off-by: Ian Jackson --- src/accounts.rs | 8 ++-- src/cmdlistener.rs | 114 +++++++++++++++++++++++---------------------- src/commands.rs | 2 +- src/global.rs | 9 ++-- src/spec.rs | 22 +++------ 5 files changed, 76 insertions(+), 79 deletions(-) diff --git a/src/accounts.rs b/src/accounts.rs index e588b82c..9b53b257 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -101,19 +101,21 @@ pub fn save_accounts_now() -> Result<(), InternalError> { } impl AccountRecord { - pub fn lookup(account: &AccountName) + pub fn lookup(account: &AccountName, _: Authorised) -> Option> { ACCOUNTS.read().map( |accounts| accounts?.get(account) ) } - pub fn lookup_mut_caller_must_save(account: &AccountName) + pub fn lookup_mut_caller_must_save(account: &AccountName, + _: Authorised) -> Option> { ACCOUNTS.write().map( |accounts| accounts?.get(account) ) } - pub fn with_entry_mut(account: &AccountName, f: F) + pub fn with_entry_mut(account: &AccountName, f: F, + _: Authorised) -> Result where F: FnOnce(Option<&mut AccountRecord>) -> T { diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index e7241d27..f4c1a568 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -55,8 +55,7 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { Noop => Fine, SetAccount(wanted_account) => { - let authorised : AuthorisedSatisfactory = - authorise_scope(cs, &wanted_account.scope)?; + let authorised = authorise_scope(cs, &wanted_account.scope)?; cs.account = ScopedName { scope: Some(authorised.into_inner()), scoped_nmae: wanted_account.scoped_name, @@ -64,7 +63,9 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { Fine }, - CreateGame { name, insns } => { + CreateGame { game, insns } => { + let authorised = authorise_scope(cs, &game.scope)?; + let gs = crate::gamestate::GameState { table_size : DEFAULT_TABLE_SIZE, pieces : Default::default(), @@ -74,12 +75,7 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { max_z: default(), }; - let name = ScopedName { - scope : cs.get_scope()?.clone(), - scoped_name : name, - }; - - let gref = Instance::new(name, gs)?; + let gref = Instance::new(game, gs, authorised)?; let mut ig = gref.lock()?; execute_for_game(cs, &mut ig, insns, MgmtGameUpdateMode::Bulk) @@ -97,15 +93,13 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { }, ListGames { all } => { - let scope = if all == Some(true) { - let _authorise : AuthorisedSatisfactory = - authorise_scope(cs, &AS::Server)?; - None + let (scope, authorised) = if all == Some(true) { + let auth = authorise_scope(cs, &AS::Server)?; + (None, auth) } else { - let scope = cs.get_scope()?; - Some(scope) + cs.current_account()?; }; - let mut games = Instance::list_names(scope); + let mut games = Instance::list_names(scope, authorised); games.sort_unstable(); GamesList(games) }, @@ -425,7 +419,7 @@ impl UpdateHandler { struct CommandStream<'d> { euid : Result, desc : &'d str, - account : Option, + account : Option<(AccountName, Authorised)>, chan : MgmtChannel, who: Who, } @@ -449,8 +443,10 @@ impl CommandStream<'_> { } #[throws(MgmtError)] - fn get_scope(&self) -> &AccountScope { - self.scope.as_ref().ok_or(NoScope)? + fn current_account(&self) -> (&AccountName, Authorised) { + self.scope.as_ref() + .ok_or(ME::SpecifyAccount)? + .map(|(account,auth)| (account,*auth)) } } @@ -561,35 +557,35 @@ impl CommandStream<'_> { #[throws(MgmtError)] fn authorise_scope(cs: &CommandStream, wanted: &AccountScope) - -> AuthorisedSatisfactory { + -> Authorised { do_authorise_scope(cs, wanted) .map_err(|e| cs.map_auth_err(e))? } #[throws(AuthorisationError)] fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) - -> AuthorisedSatisfactory { - type AS = (T, AccountScope); - + -> Authorised { match &wanted { AccountScope::Server => { - let y : AS< - Authorised<(Passwd,Uid)>, - > = { - let ok = cs.authorised_uid(None,None)?; - (ok, - AccountScope::Server) + let y : Authorised<(Passwd,Uid)> = { + cs.authorised_uid(None,None)?; }; - return y.into() + y.therefore_ok() }, AccountScope::Unix { user: wanted } => { - let y : AS< - Authorised<(Passwd,Uid)>, - > = { + struct InUserList; + + let y : Authorised<(Passwd,Uid,InUserList)> = { + struct AuthorisedIf { authorised_for : Option }; + const SERVER_ONLY : (AuthorisedIf, Authorised) = ( + AuthorisedIf { authorised_for: None }, + Authorised::authorised(InUserList), + ); + let pwent = Passwd::from_name(&wanted) .map_err( |e| anyhow!("looking up requested username {:?}: {:?}", @@ -600,25 +596,29 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) "requested username {:?} not found", &wanted )) )?; + let pwent_ok = Authorised::authorised(pwent); - let (in_userlist, xinfo) = (||{ >::Ok({ + let ((uid, in_userlist_ok), xinfo) = (||{ >::Ok({ let allowed = BufReader::new(match File::open(USERLIST) { Err(e) if e.kind() == ErrorKind::NotFound => { return Ok(( - AuthorisedIf{ authorised_for: None }, + SERVER_ONLY, Some(format!(" user list {} does not exist", USERLIST)) )) }, r => r, }?); + allowed .lines() .filter_map(|le| match le { Ok(l) if l.trim() == wanted => Some( Ok(( - AuthorisedIf{ authorised_for: Some( + (AuthorisedIf{ authorised_for: Some( Uid::from_raw(pwent.uid) - ) }, + )}, + Authorised::authorised(InUserList), + ), None )) ), @@ -628,20 +628,19 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope) .next() .unwrap_or_else( || Ok(( - AuthorisedIf{ authorised_for: None }, + SERVER_ONLY, Some(format!(" requested username {:?} not in {}", &wanted, USERLIST)), )) )? })})()?; - let AuthorisedIf{ authorised_for } = in_userlist; let info = xinfo.as_deref(); - let ok = cs.authorised_uid(authorised_for, info)?; - (ok, - AccountScope::Unix { user: pwent.name }) + let uid_ok = cs.authorised_uid(uid.authorised_for, info)?; + + (pwent_ok, uid_ok, in_userlist_ok).combine() }; - y.into() + y.therefore_ok() }, } @@ -660,22 +659,14 @@ mod authproofs { pub struct AuthorisationError(pub String); pub struct Authorised (PhantomData); - //struct AuthorisedScope (Authorised, ManagementScope); - pub struct AuthorisedSatisfactory (AccountScope); - - impl AuthorisedSatisfactory { - pub fn into_inner(self) -> AccountScope { self.0 } - } impl Authorised { - pub fn authorise() -> Authorised { Authorised(PhantomData) } + pub const fn authorise_any() -> Authorised { Authorised(PhantomData) } + pub const fn authorised(v: &T) -> Authorised { Authorised(PhantomData) } } - impl From<(Authorised, AccountScope)> for AuthorisedSatisfactory { - fn from((_,s): (Authorised, AccountScope)) -> Self { Self(s) } - } - impl From<((Authorised, Authorised), AccountScope)> for AuthorisedSatisfactory { - fn from(((..),s): ((Authorised, Authorised), AccountScope)) -> Self { Self(s) } + impl Authorised { + pub fn therefore_ok(self) -> Authorised { Authorised(PhantomData) } } impl From for AuthorisationError { @@ -688,4 +679,17 @@ mod authproofs { AuthorisationError(format!("{}",e)) } } + + pub trait AuthorisedCombine { + type Output; + fn combine(self) -> Authorised { Authorised(PhantomData) } + } + impl AuthorisedCombine + for (Authorised, Authorised) { + type Output = Authorised<(A, B)>; + } + impl AuthorisedCombine + for (Authorised, Authorised, Authorised) { + type Output = Authorised<(A, B, C)>; + } } diff --git a/src/commands.rs b/src/commands.rs index f32a174b..a02b601e 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -137,7 +137,7 @@ pub enum MgmtGameUpdateMode { pub enum MgmtError { ParseFailed(String), AuthorisationError, - NoScope, + SpecifyAccount, AlreadyExists, NickCollision, GameBeingDestroyed, diff --git a/src/global.rs b/src/global.rs index 77ff8349..065f721c 100644 --- a/src/global.rs +++ b/src/global.rs @@ -255,7 +255,7 @@ 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) + pub fn new(name: InstanceName, gs: GameState, _: Authorised) -> InstanceRef { let name = Arc::new(name); @@ -301,7 +301,8 @@ impl Instance { } #[throws(MgmtError)] - pub fn lookup_by_name(name: &InstanceName) -> InstanceRef { + pub fn lookup_by_name(name: &InstanceName, _: Authorised) + -> InstanceRef { GLOBAL.games.read().unwrap() .get(name) .ok_or(MgmtError::GameNotFound)? @@ -309,7 +310,7 @@ impl Instance { } #[throws(InternalError)] - pub fn destroy_game(mut g: InstanceGuard) { + pub fn destroy_game(mut g: InstanceGuard, _: Authorised) { let a_savefile = savefilename(&g.name, "a-", ""); let mut gw = GLOBAL.games.write().unwrap(); @@ -334,7 +335,7 @@ impl Instance { ); } - pub fn list_names(scope: Option<&AccountScope>) + pub fn list_names(scope: Option<&AccountScope>, _: Authorised) -> Vec> { let games = GLOBAL.games.read().unwrap(); let out : Vec> = diff --git a/src/spec.rs b/src/spec.rs index ab520b59..44772e85 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -243,11 +243,9 @@ pub mod implementation { // xxx check this on setting access None } - fn client_mgi(&self, _player: PlayerId) -> Option { - None - } - fn server_deliver(&self, pst: &PlayerState, token: &AccessTokenReport) - -> Result, TDE> { + fn server_deliver<'t>(&self, pst: &PlayerState, + token: &'t AccessTokenReport) + -> Result, TDE> { Ok(None) } fn client_deliver(&self, pst: &PlayerState, token: &AccessTokenReport) @@ -269,22 +267,14 @@ pub mod implementation { fn override_token(&self) -> Option<&RawToken> { Some(&self.token) } - fn client_mgi(&self, player: PlayerId) -> Option { - Some(Insn::SetFixedPlayerAccess { - player, - token: self.token.clone(), - }) - } } #[typetag::serde] impl PlayerAccessSpec for UrlOnStdout { - fn client_mgi(&self, player: PlayerId) -> Option { - Some(Insn::ReportPlayerAccesses(player)) - } #[throws(TDE)] - fn server_deliver(&self, ps: &PlayerState, token: &AccessTokenReport) - -> Option<&AccessTokenReport> { + fn server_deliver<'t>(&self, ps: &PlayerState, + token: &'t AccessTokenReport) + -> Option<&'t AccessTokenReport> { Some(token) } #[throws(TDE)] -- 2.30.2