module HSH.Helpers.UnixUsers where
import HSH
import System.Directory (doesDirectoryExist)
import Text.Regex.PCRE
import qualified Data.String.Utils as SU
import Text.StringTemplate.Helpers
type SysUser = String
type SysGroup = String
type SysShell = String
data UseraddCmd = UseraddCmd {
useraddUsername :: SysUser
, useraddGrp :: Maybe SysGroup
, useraddShell :: Maybe SysShell
, useraddHomedir :: Maybe FilePath
, useraddAllowExistingHomedir :: Bool
, useraddExe :: Maybe FilePath
}
useraddIfMissing uaCmd = do
sysU <- isSystemUser (useraddUsername uaCmd)
if not sysU
then useradd uaCmd
else return ()
groupaddIfMissing g = do
sysG <- isSystemGroup g
if not sysG
then groupadd g
else return ()
groupadd g = runIO $ "groupadd " ++ g
useradd uaCmd = do
let uname = useraddUsername uaCmd
grp = maybe "" ("-g " ++ ) (useraddGrp uaCmd)
shell = maybe "" ("--shell " ++) (useraddShell uaCmd)
hdir = maybe "" ("--home-dir " ++) (useraddHomedir uaCmd)
useraddexe = maybe "useradd" id (useraddExe uaCmd)
homedirExists <- doesDirectoryExist hdir
if (not . null $ hdir) && (not . useraddAllowExistingHomedir $ uaCmd) && homedirExists
then fail $ "createUnixUser failed, homedir exists: " ++ hdir
else runIO $ render1 [ ("useraddexe",useraddexe)
, ("uname",uname)
, ("grp",grp)
, ("shell",shell)
, ("hdir",hdir) ]
"$useraddexe$ $uname$ $grp$ $shell$ $hdir$"
isSystemUser = isSystemUG' "/etc/passwd"
isSystemGroup = isSystemUG' "/etc/group"
isSystemUG' f u = return . elem u . map parseug . lines
=<< readFile f
where parseug ug = let ((_,match,_,_) :: (String,String,String,[String])) = ug =~ "^[^:]*"
in match
sysGroupMember u g = do
a <- getSysGroupsAll u
return $ elem g a
getSysGroupPrimary u = runSL $ render1 [("u",u)] "id -ng $u$"
getSysGroupsSecondary u = do
p <- getSysGroupPrimary u
all <- getSysGroupsAll u
return $ filter (p/=) all
getSysGroupsAll u = return . words =<< (runSL $ render1 [("u",u)] "id -nG $u$")
data AddUserToGroupArgs = AddUserToGroupArgs {addUserToGroupUser::String,addUserToGroupGroup::String}
tAddUserToGroup = addUserToGroup $ AddUserToGroupArgs {addUserToGroupUser="thartman",addUserToGroupGroup="thartman"}
addUserToGroup AddUserToGroupArgs {addUserToGroupUser=u,addUserToGroupGroup=g}
| null . SU.strip $ u = fail "addUserToGroup: blank user"
| null . SU.strip $ g = fail "addUserToGroup: blank group"
| otherwise = runIO $ render1 [("u",u),("g",g)]
"usermod -G $g$ -a $u$"
rmUserFromSecondaryGroup :: SysUser -> SysGroup -> IO ()
rmUserFromSecondaryGroup u g = do
sd <- getSysGroupsAll u
let sdMod = SU.join "," $ filter (g/=) sd
runIO $ render1 [("u",u),("sdMod",sdMod)] "usermod -G $sdMod$ $u$"
data ChownOptions = ChownOptions {
chownUser :: Maybe String
, chownGrp :: Maybe String
, chownR :: Bool
}
chown = chown' "chown"
chown' chownexe chownOptions path = do
let uname = maybe "" id (chownUser chownOptions)
grp = maybe "" id (chownGrp chownOptions)
getOwner u@(_:_) g@(_:_) = Right $ u++":"++g
getOwner u@(_:_) [] = Right u
getOwner [] g@(_:_) = Right $ ":"++g
getOwner [] [] = Left $ "chown error, no user and no group"
eOwner = getOwner uname grp
rFlag = if (chownR chownOptions) then "-R" else ""
case eOwner of
Left msg -> fail msg
Right owner -> runIO $ render1 [ ("chownexe",chownexe)
, ("owner",owner)
, ("rFlag",rFlag)
, ("path",path) ]
"$chownexe$ $owner$ $rFlag$ $path$"