Created
October 2, 2019 12:39
-
-
Save unclechu/138700572e6f01e30a38ab404db0409e to your computer and use it in GitHub Desktop.
Application that grants ACL read access to all input devices to specific set of users, intended to be used for https://github.com/unclechu/xlib-keys-hack with root SUID
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Compile with this command, get rid of access to run by random users, | |
-- set SUID (to run by root), give ACL read+executing access | |
-- to your own user only ('uc' for instance, replace to your own user name): | |
-- | |
-- stack ghc --resolver=lts-14.7 \ | |
-- --package=directory \ | |
-- --package=filepath \ | |
-- --package=typed-process \ | |
-- --package=unix \ | |
-- -- -Wall -O2 -j$(nproc --all) grant-access-to-input-devices.hs && | |
-- chmod 4550 grant-access-to-input-devices && | |
-- setfacl -m u:uc:rx grant-access-to-input-devices | |
-- | |
{-# LANGUAGE UnicodeSyntax, BangPatterns #-} | |
{-# OPTIONS_GHC -Wno-missing-signatures #-} | |
module Main (main) where | |
import Prelude hiding (fail) | |
import Data.Functor ((<&>)) | |
import qualified Text.Read as Read (Read (readPrec), lift, choice, readEither) | |
import qualified Text.ParserCombinators.ReadP as Read (string) | |
import Control.Monad (join, filterM) | |
import Control.Monad.Fail (fail) | |
import System.Environment (getEnv) | |
import System.FilePath ((</>)) | |
import System.Directory (listDirectory) | |
import System.Posix.Files (fileExist, getFileStatus, isDirectory) | |
import System.Process.Typed (proc, runProcess_) | |
main ∷ IO () | |
main = do | |
!user ← getUser | |
let grantAccess f = do | |
putStrLn $ | |
"Granting ACL read access to '" ◇ f ◇ "' input device for '" ◇ | |
show user ◇ "' user…" | |
runProcess_ $ proc "setfacl" ["-m", "u:" ◇ show user ◇ ":r", "--", f] | |
traverse (\dir → fmap (dir </>) <$> listDirectory dir) dirs | |
>>= filterM fileExist ∘ join | |
>>= filterM (fmap (not ∘ isDirectory) ∘ getFileStatus) | |
>>= mapM_ grantAccess | |
getUser ∷ IO User | |
getUser = go where | |
go = getEnv "USER" >>= \u → either (failure u) pure (Read.readEither u) | |
failure u = fail ∘ mappend ("Failed to recognize user '" ◇ u ◇ "': ") | |
data User = UC deriving (Enum, Bounded) | |
instance Show User where | |
show UC = "uc" | |
instance Read User where | |
readPrec | |
= Read.choice | |
$ [minBound .. maxBound] <&> \u → Read.lift $ u <$ Read.string (show u) | |
dirs ∷ [FilePath] | |
dirs = ("/dev/input/by-" ◇) <$> ["id", "path"] | |
(∘) = (.); (◇) = (<>) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment