sshd-lint-0.1.0.1: src/System/SshdLint/Check.hs
module System.SshdLint.Check
( duplicatedValues
, activeSettings
, recommendations
, defaultAcceptedValues
, checkSafeSetting ) where
import Data.Char (toLower)
import qualified Data.Map as Map
import qualified Data.Set as Set
type RecommendedSettings = Map.Map String [String]
type ActiveSettings = Map.Map String [String]
defaultAcceptedValues :: [(String, [String])]
defaultAcceptedValues =
[ ("PermitEmptyPasswords", ["no"])
, ("PasswordAuthentication", ["no"])
, ("HostbasedAuthentication", ["no"])
, ("PermitRootLogin", ["no"])
, ("IgnoreRhosts", ["yes"])
, ("Protocol", ["2"])
, ("StrictModes", ["yes"])
, ("UsePrivilegeSeparation", ["yes"]) ]
duplicatedValues :: [String] -> Set.Set String
duplicatedValues values =
snd $ foldr checkDuplicate (Set.empty, Set.empty) values
activeSettings :: [(String, [String])] -> ActiveSettings
activeSettings =
foldr registerSetting Map.empty
where registerSetting (configOption, value) =
Map.insert (map toLower configOption) value
-- | Given a collection of recommendation strings and a current
-- setting, returns a new list of recommendations with new
-- recommendations added depending on the setting of the given
-- configOption and value.
checkSafeSetting :: Map.Map String [String]
-> String
-> [String]
-> [String]
-> [String]
checkSafeSetting recs configOption values previousRecommendations =
let recommendation = Map.lookup configOption recs in
case recommendation of
Nothing -> previousRecommendations
Just r -> if Set.fromList r == Set.fromList values then
previousRecommendations
else
previousRecommendations ++ [ configOption ++ " should be "
++ show r ++ ", found " ++
show values ]
recommendations :: RecommendedSettings -> ActiveSettings -> [String]
recommendations recommendedSettings settings =
Map.foldWithKey (checkSafeSetting normalizedRecommendedSettings) []
normalizedSettings
where normalizedRecommendedSettings = lowerCaseMapKeys recommendedSettings
normalizedSettings = lowerCaseMapKeys settings
-- | Some values legitimately appear multiple times in the configuration.
allowedDuplicates :: Set.Set String
allowedDuplicates = Set.fromList ["hostkey"]
checkDuplicate :: String
-> (Set.Set String, Set.Set String)
-> (Set.Set String, Set.Set String)
checkDuplicate aValue (allValues, dupes) =
if Set.notMember loweredValue allowedDuplicates &&
Set.member loweredValue allValues then
(allValues, Set.insert loweredValue dupes)
else
(Set.insert loweredValue allValues, dupes)
where loweredValue = map toLower aValue
lowerCaseMapKeys :: Map.Map String [String] -> Map.Map String [String]
lowerCaseMapKeys = Map.mapKeys (map toLower)