Modify UDS server startup to set permissions for sockets
authorHrvoje Ribicic <riba@google.com>
Wed, 6 May 2015 15:55:02 +0000 (15:55 +0000)
committerHrvoje Ribicic <riba@google.com>
Thu, 7 May 2015 15:49:53 +0000 (17:49 +0200)
When opening domain sockets for communication, the Haskell daemons did
not set any permissions for the sockets, defaulting to 0700. This was
fine when all of them ran as root, but was bound to cause trouble in a
split-user setup. The first issue is RAPI access after master-failover,
where RAPI could not send make any inquiries until the watcher restored
the desired permissions of the socket.

This patch modifies Luxid to use a g+rw socket, and leaves other servers
to their default of 0600.

Signed-off-by: Hrvoje Ribicic <riba@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

src/Ganeti/JQueue.hs
src/Ganeti/Luxi.hs
src/Ganeti/Metad/ConfigServer.hs
src/Ganeti/UDSServer.hs
src/Ganeti/Utils.hs
src/Ganeti/WConfd/Server.hs

index f0a5f08..ecdd7b0 100644 (file)
@@ -123,6 +123,7 @@ import Ganeti.Path
 import Ganeti.Query.Exec as Exec
 import Ganeti.Rpc (executeRpcCall, ERpcError, logRpcErrors,
                    RpcCallJobqueueUpdate(..), RpcCallJobqueueRename(..))
+import Ganeti.Runtime (GanetiDaemon(..), GanetiGroup(..), MiscGroup(..))
 import Ganeti.Types
 import Ganeti.Utils
 import Ganeti.Utils.Atomic
@@ -643,8 +644,8 @@ notifyJob pid = runResultT $ do
 
 -- | Permissions for the archive directories.
 queueDirPermissions :: FilePermissions
-queueDirPermissions = FilePermissions { fpOwner = Just C.masterdUser
-                                      , fpGroup = Just C.daemonsGroup
+queueDirPermissions = FilePermissions { fpOwner = Just GanetiMasterd
+                                      , fpGroup = Just $ ExtraGroup DaemonsGroup
                                       , fpPermissions = 0o0750
                                       }
 
index 0b31fe1..03e71cc 100644 (file)
@@ -76,10 +76,11 @@ import Ganeti.UDSServer
 import Ganeti.OpParams (pTagsObject)
 import Ganeti.OpCodes
 import qualified Ganeti.Query.Language as Qlang
-import Ganeti.Runtime (GanetiDaemon(..))
+import Ganeti.Runtime (GanetiDaemon(..), GanetiGroup(..), MiscGroup(..))
 import Ganeti.THH
 import Ganeti.THH.Field
 import Ganeti.Types
+import Ganeti.Utils
 
 
 -- | Currently supported Luxi operations and JSON serialization.
@@ -181,7 +182,13 @@ $(genStrOfOp ''LuxiOp "strOfOp")
 
 
 luxiConnectConfig :: ServerConfig
-luxiConnectConfig = ServerConfig GanetiLuxid
+luxiConnectConfig = ServerConfig
+                      -- The rapi daemon talks to the luxi one, and for this
+                      -- purpose we need group rw permissions.
+                      FilePermissions { fpOwner = Just GanetiLuxid
+                                      , fpGroup = Just $ ExtraGroup DaemonsGroup
+                                      , fpPermissions = 0o0660
+                                      }
                       ConnectConfig { recvTmo    = luxiDefRwto
                                     , sendTmo    = luxiDefRwto
                                     }
index fa492f1..62ea43c 100644 (file)
@@ -43,9 +43,10 @@ import System.IO.Error (isEOFError)
 import Ganeti.Path as Path
 import Ganeti.Daemon (DaemonOptions, cleanupSocket, describeError)
 import qualified Ganeti.Logging as Logging
-import Ganeti.Runtime (GanetiDaemon(..))
+import Ganeti.Runtime (GanetiDaemon(..), GanetiGroup(..), MiscGroup(..))
 import Ganeti.UDSServer (Client, ConnectConfig(..), Server, ServerConfig(..))
 import qualified Ganeti.UDSServer as UDSServer
+import Ganeti.Utils (FilePermissions(..))
 
 import Ganeti.Metad.Config as Config
 import Ganeti.Metad.Types (InstanceParams)
@@ -100,4 +101,15 @@ start _ config = do
        (acceptClients config server)
        (UDSServer.closeServer server)
   where
-    metadConfig = ServerConfig GanetiMetad $ ConnectConfig 60 60
+    metadConfig =
+      ServerConfig
+        -- The permission 0600 is completely acceptable because only the node
+        -- daemon talks to the metadata daemon, and the node daemon runs as
+        -- root.
+        FilePermissions { fpOwner = Just GanetiMetad
+                        , fpGroup = Just $ ExtraGroup DaemonsGroup
+                        , fpPermissions = 0o0600
+                        }
+        ConnectConfig { recvTmo = 60
+                      , sendTmo = 60
+                      }
index f36ddca..55bde15 100644 (file)
@@ -98,7 +98,6 @@ import Ganeti.BasicTypes
 import Ganeti.Errors (GanetiException(..), ErrorResult)
 import Ganeti.JSON
 import Ganeti.Logging
-import Ganeti.Runtime (GanetiDaemon(..), MiscGroup(..), GanetiGroup(..))
 import Ganeti.THH
 import Ganeti.Utils
 import Ganeti.Constants (privateParametersBlacklist)
@@ -143,7 +142,7 @@ $(genStrOfKey ''MsgKeys "strOfKey")
 
 -- Information required for creating a server connection.
 data ServerConfig = ServerConfig
-                    { connDaemon :: GanetiDaemon
+                    { connPermissions :: FilePermissions
                     , connConfig :: ConnectConfig
                     }
 
@@ -226,8 +225,10 @@ connectClient conf tmo path = do
 connectServer :: ServerConfig -> Bool -> FilePath -> IO Server
 connectServer sconf setOwner path = do
   s <- openServerSocket path
-  when setOwner . setOwnerAndGroupFromNames path (connDaemon sconf) $
-    ExtraGroup DaemonsGroup
+  when setOwner $ do
+    res <- ensurePermissions path (connPermissions sconf)
+    exitIfBad "Error - could not set socket properties" res
+
   S.listen s 5 -- 5 is the max backlog
   return Server { sSocket = s, sPath = path, serverConfig = connConfig sconf }
 
index db10ed6..e3d865f 100644 (file)
@@ -122,7 +122,6 @@ import System.IO
 import System.Exit
 import System.Posix.Files
 import System.Posix.IO
-import System.Posix.User
 import System.Time
 
 -- * Debug functions
@@ -694,8 +693,8 @@ watchFile fpath timeout old = watchFileBy fpath timeout (/= old)
 -- directories and files. All parameters are optional, with nothing
 -- meaning that the default value should be left untouched.
 
-data FilePermissions = FilePermissions { fpOwner :: Maybe String
-                                       , fpGroup :: Maybe String
+data FilePermissions = FilePermissions { fpOwner :: Maybe GanetiDaemon
+                                       , fpGroup :: Maybe GanetiGroup
                                        , fpPermissions :: FileMode
                                        }
 
@@ -703,22 +702,29 @@ data FilePermissions = FilePermissions { fpOwner :: Maybe String
 -- possibly ownerships, as required.
 ensurePermissions :: FilePath -> FilePermissions -> IO (Result ())
 ensurePermissions fpath perms = do
+  -- Fetch the list of entities
+  runtimeEnts <- runResultT getEnts
+  ents <- exitIfBad "Can't determine user/group ids" runtimeEnts
+
+  -- Get the existing file properties
   eitherFileStatus <- try $ getFileStatus fpath
                       :: IO (Either IOError FileStatus)
+
+  -- And see if any modifications are needed
   (flip $ either (return . Bad . show)) eitherFileStatus $ \fstat -> do
     ownertry <- case fpOwner perms of
       Nothing -> return $ Right ()
       Just owner -> try $ do
-        ownerid <- userID `liftM` getUserEntryForName owner
+        let ownerid = reUserToUid ents M.! owner
         unless (ownerid == fileOwner fstat) $ do
-          logDebug $ "Changing owner of " ++ fpath ++ " to " ++ owner
+          logDebug $ "Changing owner of " ++ fpath ++ " to " ++ show owner
           setOwnerAndGroup fpath ownerid (-1)
     grouptry <- case fpGroup perms of
       Nothing -> return $ Right ()
       Just grp -> try $ do
-        groupid <- groupID `liftM` getGroupEntryForName grp
+        let groupid = reGroupToGid ents M.! grp
         unless (groupid == fileGroup fstat) $ do
-          logDebug $ "Changing group of " ++ fpath ++ " to " ++ grp
+          logDebug $ "Changing group of " ++ fpath ++ " to " ++ show grp
           setOwnerAndGroup fpath (-1) groupid
     let fp = fpPermissions perms
     permtry <- if fileMode fstat == fp
index 17a658b..5b4b5f2 100644 (file)
@@ -55,6 +55,7 @@ import Ganeti.THH.RPC
 import Ganeti.UDSServer
 import Ganeti.Errors (formatError)
 import Ganeti.Runtime
+import Ganeti.Utils
 import Ganeti.Utils.Livelock (mkLivelockFile)
 import Ganeti.WConfd.ConfigState
 import Ganeti.WConfd.ConfigVerify
@@ -109,7 +110,17 @@ prepMain _ _ = do
   return (s, dh)
 
 serverConfig :: ServerConfig
-serverConfig = ServerConfig GanetiWConfd $ ConnectConfig 60 60
+serverConfig = ServerConfig
+                 -- All the daemons that need to talk to WConfd should be
+                 -- running as the same user - the former master daemon user.
+                 FilePermissions { fpOwner = Just GanetiWConfd
+                                 , fpGroup = Just $ ExtraGroup DaemonsGroup
+                                 , fpPermissions = 0o0600
+                                 }
+                 ConnectConfig { recvTmo = 60
+                               , sendTmo = 60
+                               }
+
 
 -- | Main function.
 main :: MainFn () PrepResult