pam-0.2.0.0: src/System/Posix/PAM/LowLevel.hs
module System.Posix.PAM.LowLevel where
import Foreign.C
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
import System.Posix.PAM.Internals hiding ( conv, resp )
import System.Posix.PAM.Types
-- | `retCodeFromC` @responseCode@ converts @responseCode@ from PAM to
-- a PamRetCode
retCodeFromC :: CInt -> PamRetCode
retCodeFromC rc = case rc of
0 -> PamSuccess
a -> PamRetCode $ fromIntegral a
-- | `retCodeToC` @retCode@ converts @retCode@ to the corresponding integer
-- used in the PAM C library
retCodeToC :: PamRetCode -> CInt
retCodeToC PamSuccess = 0
retCodeToC (PamRetCode a) = fromIntegral a
responseToC :: PamResponse -> IO CPamResponse
responseToC (PamResponse resp) = do
resp' <- newCString resp
return $ CPamResponse resp' 0
messageFromC :: CPamMessage -> IO PamMessage
messageFromC cmes =
let style = case msg_style cmes of
1 -> PamPromptEchoOff
2 -> PamPromptEchoOn
3 -> PamErrorMsg
4 -> PamTextInfo
a -> error $ "unknown style value: " ++ show a
in do
str <- peekCString $ msg cmes
return $ PamMessage str style
cConv :: (Ptr () -> [PamMessage] -> IO [PamResponse]) -> CInt -> Ptr (Ptr ()) -> Ptr (Ptr ()) -> Ptr () -> IO CInt
cConv customConv num mesArrPtr respArrPtr appData =
if num <= 0
then return 19
else do
-- get array pointer (pointer to first element)
voidArr <- peek mesArrPtr
-- cast pointer type from ()
let mesArr = castPtr voidArr :: Ptr CPamMessage
-- peek message list from array
cMessages <- peekArray (fromIntegral num) mesArr
-- convert messages into high-level types
messages <- mapM messageFromC cMessages
-- create response list
responses <- customConv appData messages
-- convert responses into low-level types
cResponses <- mapM responseToC responses
-- alloc memory for response array
respArr <- mallocArray (fromIntegral num)
-- poke resonse list into array
pokeArray respArr cResponses
-- poke array pointer into respArrPtr
poke respArrPtr $ castPtr respArr
-- return PAM_SUCCESS
return 0
pamStart :: String -> String -> (PamConv, Ptr ()) -> IO (PamHandle, PamRetCode)
pamStart serviceName userName (pamConv, appData) = do
cServiceName <- newCString serviceName
cUserName <- newCString userName
-- create FunPtr pointer to function and embedd PamConv function into cConv
pamConvPtr <- mkconvFunc $ cConv pamConv
let conv = CPamConv pamConvPtr appData
convPtr <- malloc
poke convPtr conv
pamhPtr <- malloc
poke pamhPtr nullPtr
r1 <- c_pam_start cServiceName cUserName convPtr pamhPtr
cPamHandle_ <- peek pamhPtr
let retCode = retCodeFromC r1
free cServiceName
free cUserName
free convPtr
free pamhPtr
return (PamHandle cPamHandle_ pamConvPtr, retCode)
pamEnd :: PamHandle -> PamRetCode -> IO PamRetCode
pamEnd pamHandle inRetCode = do
r <- c_pam_end (cPamHandle pamHandle) $ retCodeToC inRetCode
freeHaskellFunPtr $ cPamCallback pamHandle
return $ retCodeFromC r
pamAuthenticate :: PamHandle -> PamFlag -> IO PamRetCode
pamAuthenticate pamHandle flag = do
let cFlag = fromIntegral $ fromEnum flag
r <- c_pam_authenticate (cPamHandle pamHandle) cFlag
return $ retCodeFromC r
pamAcctMgmt :: PamHandle -> PamFlag -> IO PamRetCode
pamAcctMgmt pamHandle flag = do
let cFlag = fromIntegral $ fromEnum flag
r <- c_pam_acct_mgmt (cPamHandle pamHandle) cFlag
return $ retCodeFromC r