summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess2016-11-12 01:34:19 -0400
committerJoey Hess2016-11-12 01:34:19 -0400
commitb4adaf75a36d6d6425df820c46023a32e79bb6df (patch)
tree6f780bcb3c4bd9148d5770e389e854d8f025d15f
parent8d79d072dad51c9f7eb147f12bbe33742708f4b5 (diff)
The propellor wrapper checks if ./config.hs exists; if so it runs using the configuration in the current directory, rather than ~/.propellor/config.hs
The config,hs name now seems a bit badly chosen, propellor.hs would be less ambiguous. To avoid accidentially running with a config.hs for something else, the file content has to contain "Propellor". Note that checkRepoUpToDate is only run for ~/.propellor/. I guess propellor configs in other directories won't have been set up that way, and it would take some changes to make that not hardcode use of dotPropellor. There's a new security boundary here, since running propellor looks at the cwd, whose contents might not be user the user's control. The security checks I added for this seem pretty good, but even if they can be bypassed, this is not much different than `make` using the Makefile in cwd. This commit was sponsored by Ole-Morten Duesund on Patreon.
-rw-r--r--debian/changelog3
-rw-r--r--doc/usage.mdwn17
-rw-r--r--src/wrapper.hs43
3 files changed, 54 insertions, 9 deletions
diff --git a/debian/changelog b/debian/changelog
index 509734dd..f3442116 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,9 @@
propellor (3.2.3) UNRELEASED; urgency=medium
* Improve extraction of gpg secret key id list, to work with gpg 2.1.
+ * The propellor wrapper checks if ./config.hs exists; if so it runs
+ using the configuration in the current directory, rather than
+ ~/.propellor/config.hs
-- Joey Hess <id@joeyh.name> Fri, 11 Nov 2016 19:32:54 -0400
diff --git a/doc/usage.mdwn b/doc/usage.mdwn
index 02686d5f..ac23799e 100644
--- a/doc/usage.mdwn
+++ b/doc/usage.mdwn
@@ -24,8 +24,8 @@ and configured in haskell.
Once propellor is configured, running it without any options will take
action as needed to satisfy the configured properties of the local host.
- If there's a central git repository, it will first fetch from the
- repository, check the gpg signature and merge, and rebuild propellor,
+ If there's a central git repository, it will first fetch from it,
+ check the gpg signature and merge, and rebuild propellor,
so that any configuration changes will immediately take effect.
If propellor is run by a non-root user without any options, this is
@@ -116,6 +116,19 @@ and configured in haskell.
This is useful when the local host doesn't yet have its hostname set
correctly.
+# FILES
+
+* ~/.propellor/config.hs
+
+ This is the default config file used by propellor.
+
+* ./config.hs
+
+ If propellor is run in a directory containing a config.hs, it
+ assumes that the current directory is a propellor repository, and
+ uses the configuration from the current directory, rather tnan
+ ~/.propellor/
+
# ENVIRONMENT
Set `PROPELLOR_DEBUG=1` to make propellor output each command it runs and
diff --git a/src/wrapper.hs b/src/wrapper.hs
index dab77358..6b24a368 100644
--- a/src/wrapper.hs
+++ b/src/wrapper.hs
@@ -6,6 +6,9 @@
-- This is not the propellor main program (that's config.hs).
-- This bootstraps ~/.propellor/config.hs, builds it if
-- it's not already built, and runs it.
+--
+-- If ./config.hs exists, it instead builds and runs in the
+-- current working directory.
module Main where
@@ -14,31 +17,57 @@ import Propellor.Message
import Propellor.Bootstrap
import Utility.Monad
import Utility.Directory
+import Utility.FileMode
import Utility.Process
import Utility.Process.NonConcurrent
import System.Environment (getArgs)
import System.Exit
-import System.Posix.Directory
+import System.Posix
import Control.Monad.IfElse
main :: IO ()
main = withConcurrentOutput $ go =<< getArgs
where
go ["--init"] = interactiveInit
- go args = ifM (doesDirectoryExist =<< dotPropellor)
- ( do
- checkRepoUpToDate
- buildRunConfig args
- , error "Seems that ~/.propellor/ does not exist. To set it up, run: propellor --init"
+ go args = ifM configInCurrentWorkingDirectory
+ ( buildRunConfig args
+ , ifM (doesDirectoryExist =<< dotPropellor)
+ ( do
+ checkRepoUpToDate
+ changeWorkingDirectory =<< dotPropellor
+ buildRunConfig args
+ , error "Seems that ~/.propellor/ does not exist. To set it up, run: propellor --init"
+ )
)
buildRunConfig :: [String] -> IO ()
buildRunConfig args = do
- changeWorkingDirectory =<< dotPropellor
unlessM (doesFileExist "propellor") $ do
buildPropellor Nothing
putStrLn ""
putStrLn ""
(_, _, _, pid) <- createProcessNonConcurrent (proc "./propellor" args)
exitWith =<< waitForProcessNonConcurrent pid
+
+configInCurrentWorkingDirectory :: IO Bool
+configInCurrentWorkingDirectory = ifM (doesFileExist "config.hs")
+ ( do
+ -- This is a security check to avoid using the current
+ -- working directory as the propellor configuration
+ -- if it's not owned by the user, or is world-writable,
+ -- or group writable. (Some umasks may make directories
+ -- group writable, but typical ones do not.)
+ s <- getFileStatus "."
+ uid <- getRealUserID
+ if fileOwner s /= uid
+ then unsafe "you don't own the current directory"
+ else if checkMode groupWriteMode (fileMode s)
+ then unsafe "the current directory is group writable"
+ else if checkMode otherWriteMode (fileMode s)
+ then unsafe "the current directory is world-writable"
+ else return True
+ , return False
+ )
+ where
+ unsafe s = error $ "Not using ./config.hs because " ++ s ++ ". This seems unsafe."