summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess2018-08-26 10:44:25 -0400
committerJoey Hess2018-08-26 10:44:25 -0400
commite4ce2792bbd7ab7495ea86fd4228ad3595d8b48a (patch)
tree51d2083f9456cc86c28976d0dd069faaf0531d03
parentd595fdfa25eab311d2407f86efbb85f6d52c5603 (diff)
parent2a499012b680db73df20b6b5b0bc4959ab65006d (diff)
Merge branch 'joeyconfig'
-rw-r--r--debian/changelog9
-rw-r--r--propellor.cabal1
-rw-r--r--src/Propellor/Property/HostingProvider/CloudAtCost.hs34
-rw-r--r--src/Propellor/Property/SiteSpecific/JoeySites.hs24
-rw-r--r--src/Propellor/Property/Sudo.hs41
5 files changed, 61 insertions, 48 deletions
diff --git a/debian/changelog b/debian/changelog
index eff0efd3..225b71b0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -3,8 +3,17 @@ propellor (5.5.0) UNRELEASED; urgency=medium
* letsencrypt': Pass --expand to support expanding the list of domains
* Split mailname property out of Hostname.sane, since bad mailname
guesses can lead to ugly surprises. (API change)
+ * Removed HostingProvider.CloudatCost module as it lacks a maintainer.
+ (If anyone would like to maintain it, send a patch adding it back.)
+ (API change)
* Added Systemd.escapePath helper function useful when creating mount
units.
+ * Added Sudo.sudoersDFile property.
+ * Sudo.enabledFor: Write to /etc/sudoers.d/000users rather than to
+ /etc/sudoers. (Any old lines it wrote to /etc/sudoers will be removed.)
+ This fixes a potential ordering problem; the property used to append
+ the line to /etc/sudoers, but that would override more specific lines
+ in the include directory.
-- Joey Hess <id@joeyh.name> Thu, 09 Aug 2018 10:54:41 -0400
diff --git a/propellor.cabal b/propellor.cabal
index 904a8f64..0454fc92 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -144,7 +144,6 @@ Library
Propellor.Property.ZFS
Propellor.Property.ZFS.Process
Propellor.Property.ZFS.Properties
- Propellor.Property.HostingProvider.CloudAtCost
Propellor.Property.HostingProvider.DigitalOcean
Propellor.Property.HostingProvider.Exoscale
Propellor.Property.HostingProvider.Linode
diff --git a/src/Propellor/Property/HostingProvider/CloudAtCost.hs b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
deleted file mode 100644
index 839aa14e..00000000
--- a/src/Propellor/Property/HostingProvider/CloudAtCost.hs
+++ /dev/null
@@ -1,34 +0,0 @@
--- | Maintainer: currently unmaintained; your name here!
-
-module Propellor.Property.HostingProvider.CloudAtCost
- {-# WARNING "This module does not have a maintainer. It might not work right anymore. If you use it, please consider becoming its maintainer." #-}
- where
-
-import Propellor.Base
-import qualified Propellor.Property.Hostname as Hostname
-import qualified Propellor.Property.File as File
-import qualified Propellor.Property.User as User
-
--- Clean up a system as installed by cloudatcost.com
-decruft :: Property DebianLike
-decruft = propertyList "cloudatcost cleanup" $ props
- & Hostname.sane
- & Hostname.mailname
- & grubbugfix
- & nukecruft
- where
- grubbugfix :: Property DebianLike
- grubbugfix = tightenTargets $
- "/etc/default/grub" `File.containsLine` "GRUB_DISABLE_LINUX_UUID=true"
- `describe` "worked around grub/lvm boot bug #743126"
- `onChange` (cmdProperty "update-grub" [] `assume` MadeChange)
- `onChange` (cmdProperty "update-initramfs" ["-u"] `assume` MadeChange)
- nukecruft :: Property Linux
- nukecruft = tightenTargets $
- combineProperties "nuked cloudatcost cruft" $ props
- & File.notPresent "/etc/rc.local"
- & File.notPresent "/etc/init.d/S97-setup.sh"
- & File.notPresent "/zang-debian.sh"
- & File.notPresent "/bin/npasswd"
- & User.nuked (User "user") User.YesReallyDeleteHome
-
diff --git a/src/Propellor/Property/SiteSpecific/JoeySites.hs b/src/Propellor/Property/SiteSpecific/JoeySites.hs
index 2425ddb9..fa7cb064 100644
--- a/src/Propellor/Property/SiteSpecific/JoeySites.hs
+++ b/src/Propellor/Property/SiteSpecific/JoeySites.hs
@@ -16,6 +16,7 @@ import qualified Propellor.Property.Cron as Cron
import qualified Propellor.Property.Service as Service
import qualified Propellor.Property.User as User
import qualified Propellor.Property.Group as Group
+import qualified Propellor.Property.Sudo as Sudo
import qualified Propellor.Property.Borg as Borg
import qualified Propellor.Property.Apache as Apache
import qualified Propellor.Property.Postfix as Postfix
@@ -1214,9 +1215,14 @@ cubieTruckOneWire =
-- My home networked attached storage server.
homeNAS :: Property DebianLike
homeNAS = propertyList "home NAS" $ props
- & autoMountDrive "archive-10" (USBHubPort 1) (Just "archive")
+ & Apt.installed ["uhubctl"]
+ & "/etc/udev/rules.d/52-startech-hub.rules" `File.hasContent`
+ [ "# let users power control startech hub with uhubctl"
+ , "ATTR{idVendor}==\"0409\", ATTR{idProduct}==\"005a\", MODE=\"0666\""
+ ]
+ & autoMountDrive "archive-10" (USBHubPort 1) (Just "archive-older")
& autoMountDrive "archive-11" (USBHubPort 2) (Just "archive-old")
- & autoMountDrive "archive-12" (USBHubPort 3) (Just "archive-older")
+ & autoMountDrive "archive-12" (USBHubPort 3) (Just "archive")
& autoMountDrive "passport" (USBHubPort 4) Nothing
& Apt.installed ["git-annex", "borgbackup"]
@@ -1229,7 +1235,6 @@ newtype USBHubPort = USBHubPort Int
-- uhubctl.
autoMountDrive :: Mount.Label -> USBHubPort -> Maybe FilePath -> Property DebianLike
autoMountDrive label (USBHubPort port) malias = propertyList desc $ props
- & Apt.installed ["uhubctl"]
& File.ownerGroup mountpoint (User "joey") (Group "joey")
& File.dirExists mountpoint
& case malias of
@@ -1238,11 +1243,13 @@ autoMountDrive label (USBHubPort port) malias = propertyList desc $ props
Nothing -> doNothing <!> doNothing
& File.hasContent ("/etc/systemd/system/" ++ mount)
[ "[Unit]"
- , "Description=Mount " ++ label
+ , "Description=" ++ label
, "Requires=" ++ hub
, "After=" ++ hub
, "[Mount]"
- , "Type=auto"
+ -- avoid mounting whenever the block device is available,
+ -- only want to automount on deman
+ , "Options=noauto"
, "What=/dev/disk/by-label/" ++ label
, "Where=" ++ mountpoint
, "[Install]"
@@ -1277,6 +1284,9 @@ autoMountDrive label (USBHubPort port) malias = propertyList desc $ props
`onChange` Systemd.daemonReloaded
& Systemd.enabled automount
& Systemd.started automount
+ & Sudo.sudoersDFile ("automount-" ++ label)
+ [ "joey ALL= NOPASSWD: " ++ sudocommands
+ ]
where
mountpoint = "/media/joey/" ++ label
desc = "auto mount " ++ mountpoint
@@ -1284,3 +1294,7 @@ autoMountDrive label (USBHubPort port) malias = propertyList desc $ props
automount = svcbase ++ ".automount"
mount = svcbase ++ ".mount"
svcbase = Systemd.escapePath mountpoint
+ sudocommands = intercalate " , " $ map (\c -> "/bin/systemctl " ++ c)
+ [ "stop " ++ mountpoint
+ , "start " ++ mountpoint
+ ]
diff --git a/src/Propellor/Property/Sudo.hs b/src/Propellor/Property/Sudo.hs
index 1614801d..12660aa9 100644
--- a/src/Propellor/Property/Sudo.hs
+++ b/src/Propellor/Property/Sudo.hs
@@ -7,37 +7,62 @@ import Propellor.Property.File
import qualified Propellor.Property.Apt as Apt
import Propellor.Property.User
--- | Allows a user to sudo. If the user has a password, sudo is configured
--- to require it. If not, NOPASSWORD is enabled for the user.
+-- | Allows a user to run any command with sudo.
+-- If the user has a password, sudo is configured to require it.
+-- If not, NOPASSWORD is enabled for the user.
+--
+-- Writes to the file /etc/sudoers.d/000users rather than the main sudoers
+-- file. This file should come before other include files that may eg,
+-- allow running more specific commands without a password, since sudo
+-- uses the last matching configuration line.
+--
+-- If the main sudoers file contains a conflicting line for
+-- the user for ALL commands, the line will be removed.
enabledFor :: User -> RevertableProperty DebianLike DebianLike
enabledFor user@(User u) = setup `requires` Apt.installed ["sudo"] <!> cleanup
where
setup :: Property UnixLike
setup = property' desc $ \w -> do
locked <- liftIO $ isLockedPassword user
- ensureProperty w $
- fileProperty desc
+ ensureProperty w $ combineProperties desc $ props
+ & fileProperty desc
(modify locked . filter (wanted locked))
- sudoers
+ dfile
+ & removeconflicting sudoers
where
desc = u ++ " is sudoer"
cleanup :: Property DebianLike
- cleanup = tightenTargets $
- fileProperty desc (filter notuserline) sudoers
+ cleanup = tightenTargets $ combineProperties desc $ props
+ & removeconflicting sudoers
+ & removeconflicting dfile
where
desc = u ++ " is not sudoer"
+ removeconflicting = fileProperty "remove conflicting" (filter notuserline)
+
sudoers = "/etc/sudoers"
+ dfile = "/etc/sudoers.d/000users"
sudobaseline = u ++ " ALL=(ALL:ALL)"
notuserline l = not (sudobaseline `isPrefixOf` l)
sudoline True = sudobaseline ++ " NOPASSWD:ALL"
sudoline False = sudobaseline ++ " ALL"
wanted locked l
- -- TOOD: Full sudoers file format parse..
| notuserline l = True
| "NOPASSWD" `isInfixOf` l = locked
| otherwise = True
modify locked ls
| sudoline locked `elem` ls = ls
| otherwise = ls ++ [sudoline locked]
+
+-- | Sets up a file in /etc/sudoers.d/, which /etc/sudoers includes,
+-- with the specified content.
+--
+-- The FilePath can be relative to that directory.
+sudoersDFile :: FilePath -> [Line] -> RevertableProperty DebianLike Linux
+sudoersDFile dfile content = setup `requires` Apt.installed ["sudo"] <!> cleanup
+ where
+ f = "/etc/sudoers.d" </> dfile
+ -- sudoers.d files should not be world readable
+ setup = hasContentProtected f content
+ cleanup = tightenTargets $ notPresent f