chiark / gitweb /
sort out some rawtoken permission check
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 13 Nov 2020 18:57:08 +0000 (18:57 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 13 Nov 2020 18:57:08 +0000 (18:57 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/accounts.rs
src/cmdlistener.rs
src/commands.rs
src/spec.rs

index d0039d7ab1ecf106fd92e1ab108742263e17492c..b9083c899b1be82f8a63ecc3ef1ca72f9cad112c 100644 (file)
@@ -32,7 +32,7 @@ pub struct AccountName {
 }
 
 /// Record of acess for a player.  Newtype prevents mutable access
-/// without invalidating old tokens.
+/// without invalidating old tokens and permissions check.
 #[derive(Serialize,Deserialize,Debug)]
 #[serde(transparent)]
 pub struct AccessRecord (Arc<dyn PlayerAccessSpec>);
@@ -221,11 +221,14 @@ impl Deref for AccessRecord {
 
 impl AccessRecord {
   pub fn new_unset() -> Self{ Self( Arc::new(PlayerAccessUnset) ) }
-}
 
-impl From<Box<dyn PlayerAccessSpec>> for AccessRecord {
-  // xxx get rid of this From impl and do a server permission check
-  fn from(spec: Box<dyn PlayerAccessSpec>) -> Self { Self(spec.into()) }
+  #[throws(MgmtError)]
+  pub fn from_spec(spec: Box<dyn PlayerAccessSpec>,
+                   superuser: Option<AuthorisationSuperuser>)
+                   -> AccessRecord {
+    spec.check_spec_permission(superuser)?;
+    AccessRecord(spec.into())
+  }
 }
 
 //---------- AccountsGuard and lookup ----------
index 30a54b6ca6add7dc6bb225a88d7bbd8d186b26cb..4e7784553d4bab162a7da7f3e12b9d9abb9db8a3 100644 (file)
@@ -34,6 +34,8 @@ const CREATE_PIECES_MAX : u32 = 300;
 const DEFAULT_POS_START : Pos = PosC([20,20]);
 const DEFAULT_POS_DELTA : Pos = PosC([5,5]);
 
+pub type AuthorisationSuperuser = Authorisation<authproofs::Global>;
+
 pub struct CommandListener {
   listener : UnixListener,
 }
@@ -48,7 +50,7 @@ struct CommandStream<'d> {
   euid : Result<Uid, ConnectionEuidDiscoverEerror>,
   desc : &'d str,
   account : Option<AccountSpecified>,
-  superuser: Option<Authorisation<authproofs::Global>>,
+  superuser: Option<AuthorisationSuperuser>,
   chan : MgmtChannel,
   who: Who,
 }
@@ -92,7 +94,7 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse {
     CreateAccont(AccountDetails { account, nick, timezone, access }) => {
       let mut ag = AccountsGuard::lock();
       let auth = authorise_for_account(cs, &ag, &account)?;
-      let access = access.map(Into::into)
+      let access = cs.accountrecord_from_spec(access)?
         .unwrap_or_else(|| AccessRecord::new_unset());
       let nick = nick.unwrap_or_else(|| account.to_string());
       let account = account.to_owned().into();
@@ -922,6 +924,15 @@ impl CommandStream<'_> {
     let auth = get_auth(self, ag, ig, how, p.into())?;
     (ig.by_mut(auth), auth)
   }
+
+  #[throws(MgmtError)]
+  fn accountrecord_from_spec(&self, spec: Option<Box<dyn PlayerAccessSpec>>)
+                             -> Option<AccessRecord> {
+    spec
+      .map(|spec| AccessRecord::from_spec(spec, self.superuser))
+      .transpose()?
+  }
+
 }
 
 #[throws(MgmtError)]
index bd79d44484059ec5f21e853b383c93ebef738562..65e96bc4c1081366284fea8fab7ca4dc3996029e 100644 (file)
@@ -152,6 +152,7 @@ pub enum MgmtGameUpdateMode {
 pub enum MgmtError {
   ParseFailed(String),
   AuthorisationError,
+  SuperuserAuthorisationRequired,
   ParameterMissing,
   SpecifyAccount,
   AlreadyExists,
index a545a9ae4d65b2a9ebc1bbf1909d18c3a7abadf5..b1395f63e4e64119b5bf1d4af663ea3990bb0ab0 100644 (file)
@@ -18,6 +18,8 @@ use num_derive::{ToPrimitive, FromPrimitive};
 
 pub use implementation::PlayerAccessSpec;
 
+type ME = crate::commands::MgmtError;
+
 //---------- common types ----------
 
 pub type Coord = isize;
@@ -316,6 +318,9 @@ pub mod implementation {
     fn override_token(&self) -> Option<&RawToken> {
       None
     }
+    #[throws(MgmtError)]
+    fn check_spec_permission(&self, _: Option<AuthorisationSuperuser>) {
+    }
     fn server_deliver<'t>(&self,
                           _gpl: &GPlayerState,
                           _ipl: &IPlayerState,
@@ -341,6 +346,10 @@ pub mod implementation {
 
   #[typetag::serde]
   impl PlayerAccessSpec for FixedToken {
+    #[throws(MgmtError)]
+    fn check_spec_permission(&self, auth: Option<AuthorisationSuperuser>) {
+      auth.ok_or(ME::SuperuserAuthorisationRequired)?
+    }
     fn override_token(&self) -> Option<&RawToken> {
       Some(&self.token)
     }