Revision 129bde01

b/src/Ganeti/Daemon.hs
406 406
  exitUnless (null args) "This program doesn't take any arguments"
407 407

  
408 408
  unless (optNoUserChecks opts) $ do
409
    runtimeEnts <- getEnts
409
    runtimeEnts <- runResultT getEnts
410 410
    ents <- exitIfBad "Can't find required user/groups" runtimeEnts
411 411
    verifyDaemonUser daemon ents
412 412

  
b/src/Ganeti/Runtime.hs
27 27
  ( GanetiDaemon(..)
28 28
  , MiscGroup(..)
29 29
  , GanetiGroup(..)
30
  , RuntimeEnts
30
  , RuntimeEnts(..)
31 31
  , daemonName
32 32
  , daemonOnlyOnMaster
33 33
  , daemonLogBase
......
42 42
  , verifyDaemonUser
43 43
  ) where
44 44

  
45
import Control.Exception
46 45
import Control.Monad
46
import Control.Monad.Error
47 47
import qualified Data.Map as M
48 48
import System.Exit
49 49
import System.FilePath
50 50
import System.IO
51
import System.IO.Error
52 51
import System.Posix.Types
53 52
import System.Posix.User
54 53
import Text.Printf
......
78 77
                 | ExtraGroup MiscGroup
79 78
                   deriving (Show, Eq, Ord)
80 79

  
81
type RuntimeEnts = (M.Map GanetiDaemon UserID, M.Map GanetiGroup GroupID)
80
data RuntimeEnts = RuntimeEnts
81
  { reUserToUid :: M.Map GanetiDaemon UserID
82
  , reUidToUser :: M.Map UserID String
83
  , reGroupToGid :: M.Map GanetiGroup GroupID
84
  , reGidToGroup :: M.Map GroupID String
85
  }
82 86

  
83 87
-- | Returns the daemon name for a given daemon.
84 88
daemonName :: GanetiDaemon -> String
......
175 179
allGroups = map DaemonGroup [minBound..maxBound] ++
176 180
            map ExtraGroup  [minBound..maxBound]
177 181

  
178
ignoreDoesNotExistErrors :: IO a -> IO (Result a)
179
ignoreDoesNotExistErrors value = do
180
  result <- tryJust (\e -> if isDoesNotExistError e
181
                             then Just (show e)
182
                             else Nothing) value
183
  return $ eitherToResult result
184

  
185 182
-- | Computes the group/user maps.
186
getEnts :: IO (Result RuntimeEnts)
183
getEnts :: (Error e) => ResultT e IO RuntimeEnts
187 184
getEnts = do
188
  users <- mapM (\daemon -> do
189
                   entry <- ignoreDoesNotExistErrors .
190
                            getUserEntryForName .
191
                            daemonUser $ daemon
192
                   return (entry >>= \e -> return (daemon, userID e))
193
                ) [minBound..maxBound]
194
  groups <- mapM (\group -> do
195
                    entry <- ignoreDoesNotExistErrors .
196
                             getGroupEntryForName .
197
                             daemonGroup $ group
198
                    return (entry >>= \e -> return (group, groupID e))
199
                 ) allGroups
200
  return $ do -- 'Result' monad
201
    users'  <- sequence users
202
    groups' <- sequence groups
203
    let usermap = M.fromList users'
204
        groupmap = M.fromList groups'
205
    return (usermap, groupmap)
185
  let userOf = liftM userID . liftIO . getUserEntryForName . daemonUser
186
  let groupOf = liftM groupID . liftIO . getGroupEntryForName . daemonGroup
187
  let allDaemons = [minBound..maxBound] :: [GanetiDaemon]
188
  users <- mapM userOf allDaemons
189
  groups <- mapM groupOf allGroups
190
  return $ RuntimeEnts
191
            (M.fromList $ zip allDaemons users)
192
            (M.fromList $ zip users (map daemonUser allDaemons))
193
            (M.fromList $ zip allGroups groups)
194
            (M.fromList $ zip groups (map daemonGroup allGroups))
206 195

  
207 196
-- | Checks whether a daemon runs as the right user.
208 197
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
......
210 199
  myuid <- getEffectiveUserID
211 200
  -- note: we use directly ! as lookup failues shouldn't happen, due
212 201
  -- to the above map construction
213
  checkUidMatch (daemonName daemon) ((M.!) (fst ents) daemon) myuid
202
  checkUidMatch (daemonName daemon) ((M.!) (reUserToUid ents) daemon) myuid
214 203

  
215 204
-- | Check that two UIDs are matching or otherwise exit.
216 205
checkUidMatch :: String -> UserID -> UserID -> IO ()
b/src/Ganeti/Utils.hs
525 525
setOwnerAndGroupFromNames filename daemon dGroup = do
526 526
  -- TODO: it would be nice to rework this (or getEnts) so that runtimeEnts
527 527
  -- is read only once per daemon startup, and then cached for further usage.
528
  runtimeEnts <- getEnts
528
  runtimeEnts <- runResultT getEnts
529 529
  ents <- exitIfBad "Can't find required user/groups" runtimeEnts
530 530
  -- note: we use directly ! as lookup failures shouldn't happen, due
531 531
  -- to the map construction
532
  let uid = fst ents M.! daemon
533
  let gid = snd ents M.! dGroup
532
  let uid = reUserToUid ents M.! daemon
533
  let gid = reGroupToGid ents M.! dGroup
534 534
  setOwnerAndGroup filename uid gid
535 535

  
536 536
-- | Resets permissions so that the owner can read/write and the group only

Also available in: Unified diff