{-# LANGUAGE ForeignFunctionInterface #-} module MOO.Builtins.Crypt (crypt) where import Control.Applicative ((<$>)) import Control.Concurrent.MVar (MVar, newMVar, takeMVar, putMVar) import Control.Exception (bracket) import Foreign (nullPtr) import Foreign.C (CString, withCString, peekCString) import System.IO.Unsafe (unsafePerformIO) foreign import ccall safe "static unistd.h crypt" c_crypt :: CString -> CString -> IO CString -- | Encrypt a password using the POSIX @crypt()@ function. crypt :: String -- ^ key -> String -- ^ salt -> IO (Maybe String) -- ^ encrypted password (or 'Nothing' on error) crypt key salt = withCString key $ \c_key -> withCString salt $ \c_salt -> bracket (takeMVar mutex) (putMVar mutex) $ \_ -> do result <- c_crypt c_key c_salt if result == nullPtr then return Nothing else Just <$> peekCString result -- Shared mutex to prevent simultaneous calls to non-reentrant C crypt() mutex :: MVar () {-# NOINLINE mutex #-} mutex = unsafePerformIO $ newMVar ()