#if __GLASGOW_HASKELL__ >= 704
#endif
module Hails.Database.MongoDB.TCB.DCAccess ( DBConf(..)
, DCAction
, dcAccess
, labelDatabase
, DatabasePolicy(..)
, PolicyGroup(..)
, relabelGroupsP
, relabelGroupsSafe
, PrivilegeGrantGate(..)
, withLabel, gateToLabeled
) where
import Control.Monad (foldM, liftM)
import Data.Bson (u)
import qualified Data.Bson as Bson
import Hails.Data.LBson (Document)
import Hails.Database.MongoDB.TCB.Types
import Hails.Database.MongoDB.TCB.Access
import Database.MongoDB ( runIOE
, connect
, host
, master
, slaveOk
, GetLastError
, AccessMode(..) )
import LIO
import LIO.TCB ( rtioTCB )
import LIO.MonadCatch
import LIO.DCLabel
import System.Environment
import Data.Maybe (fromMaybe)
import qualified Data.Map as Map
import qualified Data.List as List
import Text.Parsec hiding (label)
data DBConf = DBConf { dbConfName :: DatabaseName
, dbConfPriv :: DCPrivTCB
} deriving (Show)
type DCAction = Action DCLabel DCPrivTCB ()
dcAccess :: Database DCLabel
-> DCAction a
-> DC (Either Failure a)
dcAccess db act = do
env <- rtioTCB getEnvironment
let hostName = fromMaybe "localhost" (List.lookup "HAILS_MONGODB_SERVER" env)
let mode = maybe master parseMode (List.lookup "HAILS_MONGODB_MODE" env)
pipe <- rtioTCB $ runIOE $ connect (host hostName)
accessTCB pipe mode db act
labelDatabase :: DBConf
-> DCLabel
-> DCLabel
-> DC (Database DCLabel)
labelDatabase conf lcoll lacc = do
let dbName = dbConfName conf
p = dbConfPriv conf
initColl <- labelP p lcoll Map.empty
databaseP p dbName lacc initColl
class DatabasePolicy dbp where
createDatabasePolicy :: DBConf -> DCPrivTCB -> DC dbp
policyDB :: dbp -> Database DCLabel
class DatabasePolicy dbp => PolicyGroup dbp where
expandGroup :: dbp -> Principal -> DCAction [Principal]
expandGroup _ princ = return [princ]
relabelGroups :: dbp -> DCLabeled a -> DC (DCLabeled a)
relabelGroups _ = return
class DatabasePolicy dbp => PrivilegeGrantGate dbp where
grantPriv :: dbp
-> Principal
-> DC (DCGate DCPrivTCB)
relabelGroupsSafe :: PolicyGroup dbp
=> dbp
-> Labeled DCLabel a
-> DC (DCLabeled a)
relabelGroupsSafe dbp lbl = withPrivileges noPrivs $
relabelGroups dbp lbl
relabelGroupsP :: PolicyGroup dbp
=> dbp
-> DCPrivTCB
-> Labeled DCLabel a
-> DC (DCLabeled a)
relabelGroupsP dbp p inp = do
let (MkDCLabel sec' inte') = labelOf inp
sec <- expandComponent sec'
inte <- expandComponent inte'
let lbl = MkDCLabel sec inte
relabelP p lbl inp
where expandComponent l | l == (><) = return l
expandComponent comp = do
ds <- mapM gocmp $ componentToList comp
return $ listToComponent ds
gocmp d = do
let db = policyDB dbp
result <-
if p `owns` d
then dcAccess db $ liftM listToDisj $
foldM (\res grp -> do next <- expandGroup dbp grp
return $ res ++ next) [] $ disjToList d
else return $ Right d
return $ case result of
Right dr -> dr
Left _ -> d
parseMode :: String -> AccessMode
parseMode "slaveOk" = slaveOk
parseMode "unconfirmedWrites" = UnconfirmedWrites
parseMode xs = case parse wParser "" xs of
Right le -> ConfirmWrites le
Left _ -> master
where wParser = do _ <- string "confirmWrites"
spaces
_ <- char ':'
spaces
gle_opts
gle_opts :: Stream s m Char => ParsecT s u m GetLastError
gle_opts = do opt_first <- gle_opt
opt_rest <- gle_opts'
return $ opt_first ++ opt_rest
where gle_opt = gle_opt_fsync <|> gle_opt_journal <|> gle_opt_write
gle_opts' :: Stream s m Char => ParsecT s u m GetLastError
gle_opts' = (spaces >> char ',' >> spaces >> gle_opts) <|> (return [])
gle_opt_fsync :: Stream s m Char => ParsecT s u m GetLastError
gle_opt_fsync = string "fsync" >> return [ (u "fsync") Bson.=: True ]
gle_opt_journal :: Stream s m Char => ParsecT s u m GetLastError
gle_opt_journal = string "journal" >> return [ (u "j") Bson.=: True ]
gle_opt_write :: Stream s m Char => ParsecT s u m GetLastError
gle_opt_write = do _ <- string "write"
spaces
_ <- char '='
spaces
dgt <- many1 digit
return [ (u "w") Bson.=: (read dgt :: Integer) ]
gateToLabeled :: DCPrivTCB
-> DCLabeled (Document DCLabel)
-> (Document DCLabel -> DC a) -> DC (DCLabeled a)
gateToLabeled privs ldoc act = do
l <- getLabel
withLabel privs (newDC (secrecy l) (><)) $ do
doc <- unlabel ldoc
res <- act doc
lr <- getLabel
label lr res
withLabel :: DCPrivTCB -> DCLabel -> DC a -> DC a
withLabel privs l act = do
l0 <- getLabel
setLabelP privs $ lostar privs l0 l
act `finally` do l1 <- getLabel
setLabelP privs (lostar privs l1 l0)