module Propellor.Property.Gpg where import Propellor.Base import qualified Propellor.Property.Apt as Apt import System.PosixCompat installed :: Property DebianLike installed = Apt.installed ["gnupg"] -- A numeric id, or a description of the key, in a form understood by gpg. newtype GpgKeyId = GpgKeyId { getGpgKeyId :: String } data GpgKeyType = GpgPubKey | GpgPrivKey -- | Sets up a user with a gpg key from the privdata. -- -- Note that if a secret key is exported using gpg -a --export-secret-key, -- the public key is also included. Or just a public key could be -- exported, and this would set it up just as well. -- -- Recommend only using this for low-value dedicated role keys. -- No attempt has been made to scrub the key out of memory once it's used. keyImported :: GpgKeyId -> User -> Property (HasInfo + DebianLike) keyImported key@(GpgKeyId keyid) user@(User u) = prop `requires` installed where desc = u ++ " has gpg key " ++ show keyid prop :: Property (HasInfo + DebianLike) prop = withPrivData src (Context keyid) $ \getkey -> property desc $ getkey $ \key' -> do let keylines = privDataLines key' ifM (liftIO $ hasGpgKey (parse keylines)) ( return NoChange , makeChange $ withHandle StdinHandle createProcessSuccess (proc "su" ["--login", "-c", "gpg --import", u]) $ \h -> do hPutStr h (unlines keylines) hClose h ) src = PrivDataSource GpgKey "Either a gpg public key, exported with gpg --export -a, or a gpg private key, exported with gpg --export-secret-key -a" parse ("-----BEGIN PGP PUBLIC KEY BLOCK-----":_) = Just GpgPubKey parse ("-----BEGIN PGP PRIVATE KEY BLOCK-----":_) = Just GpgPrivKey parse _ = Nothing hasGpgKey Nothing = error $ "Failed to run gpg parser on armored key " ++ keyid hasGpgKey (Just GpgPubKey) = hasPubKey key user hasGpgKey (Just GpgPrivKey) = hasPrivKey key user hasPrivKey :: GpgKeyId -> User -> IO Bool hasPrivKey (GpgKeyId keyid) (User u) = catchBoolIO $ snd <$> processTranscript "su" ["--login", "-c", "gpg --list-secret-keys " ++ shellEscape keyid, u] Nothing hasPubKey :: GpgKeyId -> User -> IO Bool hasPubKey (GpgKeyId keyid) (User u) = catchBoolIO $ snd <$> processTranscript "su" ["--login", "-c", "gpg --list-public-keys " ++ shellEscape keyid, u] Nothing dotDir :: User -> IO FilePath dotDir (User u) = do home <- homeDirectory <$> getUserEntryForName u return $ home ".gnupg"