module Propellor.Property.Sudo where
import Data.List
import Propellor.Base
import Propellor.Property.File
import qualified Propellor.Property.Apt as Apt
import Propellor.Property.User
enabledFor :: User -> RevertableProperty DebianLike DebianLike
enabledFor :: User -> RevertableProperty DebianLike DebianLike
enabledFor user :: User
user@(User UserName
u) = Property UnixLike
setup Property UnixLike
-> Property DebianLike
-> CombinedType (Property UnixLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` [UserName] -> Property DebianLike
Apt.installed [UserName
"sudo"] Property DebianLike
-> Property DebianLike -> RevertableProperty DebianLike DebianLike
forall setupmetatypes undometatypes.
Property setupmetatypes
-> Property undometatypes
-> RevertableProperty setupmetatypes undometatypes
<!> Property DebianLike
cleanup
where
setup :: Property UnixLike
setup :: Property UnixLike
setup = UserName
-> (OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
-> Propellor Result)
-> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
UserName
-> (OuterMetaTypesWitness metatypes -> Propellor Result)
-> Property (MetaTypes metatypes)
property' UserName
desc ((OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
-> Propellor Result)
-> Property UnixLike)
-> (OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
-> Propellor Result)
-> Property UnixLike
forall a b. (a -> b) -> a -> b
$ \OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
w -> do
Bool
locked <- IO Bool -> Propellor Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> Propellor Bool) -> IO Bool -> Propellor Bool
forall a b. (a -> b) -> a -> b
$ User -> IO Bool
isLockedPassword User
user
OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
-> Property UnixLike -> Propellor Result
forall (inner :: [MetaType]) (outer :: [MetaType]).
EnsurePropertyAllowed inner outer =>
OuterMetaTypesWitness outer
-> Property (MetaTypes inner) -> Propellor Result
ensureProperty OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
w (Property UnixLike -> Propellor Result)
-> Property UnixLike -> Propellor Result
forall a b. (a -> b) -> a -> b
$ UserName -> Props UnixLike -> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
UserName
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
combineProperties UserName
desc (Props UnixLike -> Property UnixLike)
-> Props UnixLike -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ Props UnixLike
props
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Property UnixLike
includessudoersd
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& UserName
-> ([UserName] -> [UserName]) -> UserName -> Property UnixLike
forall c.
(FileContent c, Eq c) =>
UserName -> (c -> c) -> UserName -> Property UnixLike
fileProperty UserName
desc
(Bool -> [UserName] -> [UserName]
modify Bool
locked ([UserName] -> [UserName])
-> ([UserName] -> [UserName]) -> [UserName] -> [UserName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UserName -> Bool) -> [UserName] -> [UserName]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> UserName -> Bool
wanted Bool
locked))
UserName
dfile
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& UserName -> Property UnixLike
removeconflicting UserName
sudoers
where
desc :: UserName
desc = UserName
u UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" is sudoer"
cleanup :: Property DebianLike
cleanup :: Property DebianLike
cleanup = Property UnixLike -> Property DebianLike
forall (p :: * -> *) (untightened :: [MetaType])
(tightened :: [MetaType]).
(TightenTargets p, TightenTargetsAllowed untightened tightened,
SingI tightened) =>
p (MetaTypes untightened) -> p (MetaTypes tightened)
tightenTargets (Property UnixLike -> Property DebianLike)
-> Property UnixLike -> Property DebianLike
forall a b. (a -> b) -> a -> b
$ UserName -> Props UnixLike -> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
UserName
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
combineProperties UserName
desc (Props UnixLike -> Property UnixLike)
-> Props UnixLike -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ Props UnixLike
props
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& UserName -> Property UnixLike
removeconflicting UserName
sudoers
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& UserName -> Property UnixLike
removeconflicting UserName
dfile
where
desc :: UserName
desc = UserName
u UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" is not sudoer"
removeconflicting :: UserName -> Property UnixLike
removeconflicting = UserName
-> ([UserName] -> [UserName]) -> UserName -> Property UnixLike
forall c.
(FileContent c, Eq c) =>
UserName -> (c -> c) -> UserName -> Property UnixLike
fileProperty UserName
"remove conflicting" ((UserName -> Bool) -> [UserName] -> [UserName]
forall a. (a -> Bool) -> [a] -> [a]
filter UserName -> Bool
notuserline)
includessudoersd :: Property UnixLike
includessudoersd = UserName
-> ([UserName] -> [UserName]) -> UserName -> Property UnixLike
forall c.
(FileContent c, Eq c) =>
UserName -> (c -> c) -> UserName -> Property UnixLike
fileProperty (UserName
sudoers UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" includes " UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
sudoersd) [UserName] -> [UserName]
addl UserName
sudoers
where
addl :: [UserName] -> [UserName]
addl [UserName]
content = [UserName]
content [UserName] -> [UserName] -> [UserName]
forall a. [a] -> [a] -> [a]
++
if UserName
l UserName -> [UserName] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [UserName]
content Bool -> Bool -> Bool
&& UserName
oldl UserName -> [UserName] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [UserName]
content
then [UserName
l]
else []
l :: UserName
l = UserName
"@includedir /etc/sudoers.d"
oldl :: UserName
oldl = UserName
"#includedir /etc/sudoers.d"
sudoers :: UserName
sudoers = UserName
"/etc/sudoers"
sudoersd :: UserName
sudoersd = UserName
"/etc/sudoers.d"
dfile :: UserName
dfile = UserName
"/etc/sudoers.d/000users"
sudobaseline :: UserName
sudobaseline = UserName
u UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" ALL=(ALL:ALL)"
notuserline :: UserName -> Bool
notuserline UserName
l = Bool -> Bool
not (UserName
sudobaseline UserName -> UserName -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` UserName
l)
sudoline :: Bool -> UserName
sudoline Bool
True = UserName
sudobaseline UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" NOPASSWD:ALL"
sudoline Bool
False = UserName
sudobaseline UserName -> UserName -> UserName
forall a. [a] -> [a] -> [a]
++ UserName
" ALL"
wanted :: Bool -> UserName -> Bool
wanted Bool
locked UserName
l
| UserName -> Bool
notuserline UserName
l = Bool
True
| UserName
"NOPASSWD" UserName -> UserName -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` UserName
l = Bool
locked
| Bool
otherwise = Bool
True
modify :: Bool -> [UserName] -> [UserName]
modify Bool
locked [UserName]
ls
| Bool -> UserName
sudoline Bool
locked UserName -> [UserName] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [UserName]
ls = [UserName]
ls
| Bool
otherwise = [UserName]
ls [UserName] -> [UserName] -> [UserName]
forall a. [a] -> [a] -> [a]
++ [Bool -> UserName
sudoline Bool
locked]
sudoersDFile :: FilePath -> [Line] -> RevertableProperty DebianLike Linux
sudoersDFile :: UserName -> [UserName] -> RevertableProperty DebianLike Linux
sudoersDFile UserName
dfile [UserName]
content = Property UnixLike
setup Property UnixLike
-> Property DebianLike
-> CombinedType (Property UnixLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` [UserName] -> Property DebianLike
Apt.installed [UserName
"sudo"] Property DebianLike
-> Property Linux -> RevertableProperty DebianLike Linux
forall setupmetatypes undometatypes.
Property setupmetatypes
-> Property undometatypes
-> RevertableProperty setupmetatypes undometatypes
<!> Property Linux
cleanup
where
f :: UserName
f = UserName
"/etc/sudoers.d" UserName -> UserName -> UserName
</> UserName
dfile
setup :: Property UnixLike
setup = UserName -> [UserName] -> Property UnixLike
hasContentProtected UserName
f [UserName]
content
cleanup :: Property Linux
cleanup = Property UnixLike -> Property Linux
forall (p :: * -> *) (untightened :: [MetaType])
(tightened :: [MetaType]).
(TightenTargets p, TightenTargetsAllowed untightened tightened,
SingI tightened) =>
p (MetaTypes untightened) -> p (MetaTypes tightened)
tightenTargets (Property UnixLike -> Property Linux)
-> Property UnixLike -> Property Linux
forall a b. (a -> b) -> a -> b
$ UserName -> Property UnixLike
notPresent UserName
f