packages feed

pam 0.1 → 0.2.0.0

raw patch · 9 files changed

+257/−69 lines, 9 filesnew-uploader

Files

+ CONTRIBUTING.md view
@@ -0,0 +1,26 @@+# Contributing:++## Feature requests:+If you have a feature request open an issue and use the `enhancement` label. Make sure you describe the feature you want in sufficient detail++## Issues:+If you find an issue then firstly search to see if it has already been reported. If not then open a new issue with the label `bug`. Make sure you include details of:+- The events leading to the issue+- What the issue is/how it manifests+- The PAM logs relating to the issue++Try to give the "minimum" example to reproduce the bug where possible++## Pull requests:+When opening a pull request:+- Open a draft PR when you start working. This allows others to see you are working on a bug/feature and avoids duplicate work+- Ensure your code meets the coding conventions listed below+- Try to stick to 1 feature/bug per PR+- Include details of what your changes do, for example what feature you implement or which bug you fix++## Code Conventions:+- Use 4 spaces for tabs+- Include type signatures for all top level functions+- Include Haddock comments for all functions/type definitions, as well as inline comments explaining logic where it may not be clear+- Try to avoid long lines - if a line is looking long then split it across 2 lines, or use `let...in...` or `...where` if it makes your code more readable+- Update the README with new features or changes to existing ones
+ ChangeLog.md view
@@ -0,0 +1,13 @@+# Change Log:++## v0.2.0.0:+- `authenticate` function now returns `MonadIO m => m PamRetCode` rather than `IO (Either Int ())`+- `authSuccess :: PamRetCode -> Bool` added which checks if the given `PamRetCode` is `PamSuccess` or not+- `whenSuccess :: MonadIO m => PamRetCode -> m PamRetCode -> m PamRetCode` added, which returns the second argument if the given response code is `PamSuccess`, otherwise it returns the given response code (useful for continuing only if the PAM action succeeded).+- `pamCodeToMessage`, `pamCodeToCDefine` and `pamCodeDetails` now take a `PamRetCode` rather than an `Int`+- `checkAccount` function has now been implemented+- Switched to PVP versioning+- Some documentation added++## v0.1:+Initial release
+ README.md view
@@ -0,0 +1,43 @@+# pam++![Haskell CI](https://github.com/oscar-h64/pam-haskell/workflows/Haskell%20CI/badge.svg)+![Hackage](https://img.shields.io/hackage/v/pam.svg)++Haskell bindings for PAM. Note that this does not currently include the required bindings to write PAM modules++## Usage:++To authenticate a user `test` using the `system-local-login` PAM configuration:+```haskell+authenticate "system-local-login" "test" "PASSWORD"+```++To check if a user `test` exists using the `system-auth` PAM configuration:+```haskell+checkAccount "system-auth" "test"+```++If the operation was successful then `PamSuccess` will be returned, otherwise `PamCode a`, where `a` represents the reason for the failure.++`pamCodeToMessage`, `pamCodeToCDefine` and `pamCodeDetails` can be used to get further details about the response, and `isSuccess` can be used to check if the operation was successful. See the Haddock documentation for more details on these functions.++## Documentation:++The documentation is available on [Hackage](https://hackage.haskell.org/package/pam)++## Changes in v0.2.0.0:+- `authenticate` function now returns `MonadIO m => m PamRetCode` rather than `IO (Either Int ())`+- `authSuccess :: PamRetCode -> Bool` added which checks if the given `PamRetCode` is `PamSuccess` or not+- `whenSuccess :: MonadIO m => PamRetCode -> m PamRetCode -> m PamRetCode` added, which returns the second argument if the given response code is `PamSuccess`, otherwise it returns the given response code (useful for continuing only if the PAM action succeeded).+- `pamCodeToMessage`, `pamCodeToCDefine` and `pamCodeDetails` now take a `PamRetCode` rather than an `Int`+- `checkAccount` function has now been implemented++## Planned Changes:+- Document and refactoring the code (started)+- Add ability to give multiple passwords (for 2FA systems) (see [#2](https://github.com/oscar-h64/pam-haskell/issues/2))+- Add functions that do the prompting rather than being given details - useful as if a program using the library is intended to be distributed the number of prompts will not be known (see [#3](https://github.com/oscar-h64/pam-haskell/issues/3))+- Add functions to allow writing PAM modules in Haskell (see [#8](https://github.com/oscar-h64/pam-haskell/issues/8))++## Contributing:++See [here](https://github.com/oscar-h64/pam-haskell/blob/master/CONTRIBUTING.md) for more information
pam.cabal view
@@ -1,32 +1,45 @@-Name:           pam-Version:        0.1-Cabal-Version:  >= 1.2.3-Build-type:     Simple-License:        BSD3-License-File:   LICENSE-Copyright:      Copyright (c) 2011 Evgeny Tarasov-Maintainer:     etarasov.ekb@gmail.com-Stability:      alpha-Synopsis:       Haskell binding for C PAM API-Description:    This package provides PAM interface for Haskell programs. It contains subset of C PAM API bindings. The bindings don't include functions for writing PAM modules.-Category:       System-Tested-with:    GHC==6.12.3-Extra-source-files: Setup.hs+cabal-version:  3.0+name:           pam+version:        0.2.0.0+build-type:     Simple+license:        BSD-3-Clause+license-file:   LICENSE+copyright:      (c) 2011 Evgeny Tarasov+                (c) 2020 Oscar Harris+author:         Evgeny Tarasov <etarasov.ekb@gmail.com>+maintainer:     Oscar Harris <oscar@oscar-h.com>+stability:      provisional+synopsis:       Haskell binding for C PAM API+description:    This package provides PAM interface for Haskell programs. See the README on GitHub at <Please see the README on GitHub at <https://github.com/oscar-h64/pam-haskell#readme> for more information.+bug-reports:    https://github.com/oscar-h64/pam-haskell/issues+category:       System, Authentication+tested-with:    GHC==8.8.3+homepage:       https://github.com/oscar-h64/pam-haskell -Library+extra-source-files:+    Setup.hs+    +extra-doc-files:+    README.md+    CONTRIBUTING.md+    ChangeLog.md++source-repository head+  type:     git+  location: https://github.com/oscar-h64/pam-haskell++library+    default-language: Haskell2010+     exposed-modules: System.Posix.PAM                      System.Posix.PAM.LowLevel                      System.Posix.PAM.Types                      System.Posix.PAM.Internals -    --other-modules:   System.Posix.PAM.Internals--    extensions: ForeignFunctionInterface--    Build-Depends:  base >= 4 && < 5-    Hs-Source-Dirs: src-    Ghc-options:    -Wall+    build-depends:  base >= 4 && < 5+    hs-source-dirs: src+    ghc-options:    -Wall -    extra-libraries : pam+    extra-libraries: pam -    build-tools: c2hs+    build-tool-depends: c2hs:c2hs
src/System/Posix/PAM.hs view
@@ -1,42 +1,62 @@  module System.Posix.PAM where +import Control.Monad.IO.Class    ( MonadIO, liftIO )+ import Foreign.Ptr+ import System.Posix.PAM.LowLevel import System.Posix.PAM.Types -authenticate :: String -> String -> String -> IO (Either Int ())+-- | `isSuccess` @responseCode@ checks if @responseCode@ is equal to `PamSuccess`,+--   i.e. checking if the account check/authentication succeeded+isSuccess :: PamRetCode -> Bool+isSuccess = (== PamSuccess)++-- | `whenSuccess` @responseCode action@ returns @action@ if @responseCode@ is+--   `PamSuccess`, otherwise returns @responseCode@+whenSuccess :: MonadIO m => PamRetCode -> m PamRetCode -> m PamRetCode+whenSuccess code action = if isSuccess code then action else pure code++-- | `authenticate` @service user password@ attempts to authenticate @user@ and+--   @password@ with PAM using @service@ to determine which file in /etc/pam.d to+--   use+authenticate :: MonadIO m => String -> String -> String -> m PamRetCode authenticate serviceName userName password = do-    let custConv :: String -> PamConv-        custConv pass _ messages = do-            let rs = map (\ _ -> PamResponse pass) messages-            return rs-    (pamH, r1) <- pamStart serviceName userName (custConv password, nullPtr)-    case r1 of-        PamRetCode code -> return $ Left $ fromInteger $ toInteger code-        PamSuccess -> do-            r2 <- pamAuthenticate pamH (PamFlag 0)-            case r2 of-                PamRetCode code -> return $ Left $ fromInteger $ toInteger code-                PamSuccess -> do-                    r3 <- pamEnd pamH r2-                    case r3 of-                        PamSuccess -> return $ Right ()-                        PamRetCode code -> return $ Left $ fromInteger $ toInteger code+    let custConv :: PamConv+        custConv _ messages = return $ map (\ _ -> PamResponse password) messages -checkAccount :: String -> String -> IO (Either Int ())-checkAccount = undefined+    (pamH, r1) <- liftIO $ pamStart serviceName userName (custConv, nullPtr) +    whenSuccess r1 $ do+        status <- liftIO $ pamAuthenticate pamH PamSilent+        whenSuccess status $ liftIO $ pamEnd pamH PamSuccess -pamCodeToMessage :: Int -> String+-- | `checkAccount` @service user@ checks if @user@ is a valid user. @service@ is+--   is the service name given to PAM (see `authenticate`)+checkAccount :: MonadIO m => String -> String -> m PamRetCode+checkAccount serviceName userName = do+    (pamH, r1) <- liftIO $ pamStart serviceName userName (\_ _ -> pure [], nullPtr)++    whenSuccess r1 $ do+        status <- liftIO $ pamAcctMgmt pamH PamSilent+        whenSuccess status $ liftIO $ pamEnd pamH PamSuccess++-- | `pamCodeToMessage` @responseCode@ returns a description of @responseCode@+--   in the context of PAM+pamCodeToMessage :: PamRetCode -> String pamCodeToMessage = snd . pamCodeDetails -pamCodeToCDefine :: Int -> String+-- | `pamCodeToMessage` @responseCode@ returns the name of the define used in C+--   to represent @responseCode@+pamCodeToCDefine :: PamRetCode -> String pamCodeToCDefine = fst . pamCodeDetails -pamCodeDetails :: Int -> (String, String)-pamCodeDetails code = case code of-    0 -> ("PAM_SUCCESS", "Successful function return")+-- | `pamCodeDetails` @responseCode@ returns a tuple of the name of the C define+--   and a description of @responseCode@+pamCodeDetails :: PamRetCode -> (String, String)+pamCodeDetails PamSuccess        = ("PAM_SUCCESS", "Successful function return")+pamCodeDetails (PamRetCode code) = case code of     1 -> ("PAM_OPEN_ERR", "dlopen() failure when dynamically loading a service module")     2 -> ("PAM_SYMBOL_ERR", "Symbol not found")     3 -> ("PAM_SERVICE_ERR", "Error in service module")
src/System/Posix/PAM/Internals.chs view
@@ -1,7 +1,6 @@ {-# LANGUAGE CPP, ForeignFunctionInterface #-} module System.Posix.PAM.Internals where -import Control.Applicative import Foreign.C import Foreign.Ptr import Foreign.Storable
src/System/Posix/PAM/LowLevel.hs view
@@ -2,21 +2,26 @@ module System.Posix.PAM.LowLevel where  import Foreign.C-import Foreign.Marshal.Array 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-import System.Posix.PAM.Internals hiding (resp, conv) +-- | `retCodeFromC` @responseCode@ converts @responseCode@ from PAM to+--   a PamRetCode retCodeFromC :: CInt -> PamRetCode retCodeFromC rc = case rc of             0 -> PamSuccess-            a -> PamRetCode $ fromInteger $ toInteger a+            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) = fromInteger $ toInteger a+retCodeToC PamSuccess     = 0+retCodeToC (PamRetCode a) = fromIntegral a  responseToC :: PamResponse -> IO CPamResponse responseToC (PamResponse resp) = do@@ -47,7 +52,7 @@             let mesArr = castPtr voidArr :: Ptr CPamMessage              -- peek message list from array-            cMessages <- peekArray (fromInteger $ toInteger num) mesArr+            cMessages <- peekArray (fromIntegral num) mesArr              -- convert messages into high-level types             messages <- mapM messageFromC cMessages@@ -59,7 +64,7 @@             cResponses <- mapM responseToC responses              -- alloc memory for response array-            respArr <- mallocArray (fromInteger $ toInteger num)+            respArr <- mallocArray (fromIntegral num)              -- poke resonse list into array             pokeArray respArr cResponses@@ -90,9 +95,7 @@      cPamHandle_ <- peek pamhPtr -    let retCode = case r1 of-            0 -> PamSuccess-            a -> PamRetCode $ fromInteger $ toInteger a+    let retCode = retCodeFromC r1      free cServiceName     free cUserName@@ -104,22 +107,19 @@  pamEnd :: PamHandle -> PamRetCode -> IO PamRetCode pamEnd pamHandle inRetCode = do-    let cRetCode = case inRetCode of-            PamSuccess -> 0-            PamRetCode a -> fromInteger $ toInteger a-    r <- c_pam_end (cPamHandle pamHandle) cRetCode+    r <- c_pam_end (cPamHandle pamHandle) $ retCodeToC inRetCode     freeHaskellFunPtr $ cPamCallback pamHandle      return $ retCodeFromC r  pamAuthenticate :: PamHandle -> PamFlag -> IO PamRetCode-pamAuthenticate pamHandle (PamFlag flag) = do-    let cFlag = fromInteger $ toInteger flag+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 (PamFlag flag) = do-    let cFlag = fromInteger $ toInteger flag+pamAcctMgmt pamHandle flag = do+    let cFlag = fromIntegral $ fromEnum flag     r <- c_pam_acct_mgmt (cPamHandle pamHandle) cFlag     return $ retCodeFromC r
src/System/Posix/PAM/Types.hs view
@@ -5,7 +5,7 @@ import Foreign.Ptr  data PamMessage = PamMessage { pmString :: String-                             , pmStyle :: PamStyle+                             , pmStyle  :: PamStyle                              }                              deriving (Show, Eq) @@ -25,7 +25,15 @@                 | PamRetCode Int                 deriving (Show, Eq) -data PamFlag = PamFlag Int+data PamFlag = PamSilent+             | PamDisallowNullAuthTok+             | PamEstablishCred+             | PamDeleteCred+             | PamReinitializeCred+             | PamRefreshCred+             | PamChangeExpiredAuthTok+             | PamNone+             deriving (Show, Eq, Enum)  type PamConv = Ptr () -> [PamMessage] -> IO [PamResponse] 
+ stack.yaml view
@@ -0,0 +1,66 @@+# This file was automatically generated by 'stack init'+#+# Some commonly used options have been documented as comments in this file.+# For advanced use and comprehensive documentation of the format, please see:+# https://docs.haskellstack.org/en/stable/yaml_configuration/++# Resolver to choose a 'specific' stackage snapshot or a compiler version.+# A snapshot resolver dictates the compiler version and the set of packages+# to be used for project dependencies. For example:+#+# resolver: lts-3.5+# resolver: nightly-2015-09-21+# resolver: ghc-7.10.2+#+# The location of a snapshot can be provided as a file or url. Stack assumes+# a snapshot provided as a file might change, whereas a url resource does not.+#+# resolver: ./custom-snapshot.yaml+# resolver: https://example.com/snapshots/2018-01-01.yaml+resolver: lts-16.2++# User packages to be built.+# Various formats can be used as shown in the example below.+#+# packages:+# - some-directory+# - https://example.com/foo/bar/baz-0.0.2.tar.gz+#   subdirs:+#   - auto-update+#   - wai+packages:+- .+# Dependency packages to be pulled from upstream that are not in the resolver.+# These entries can reference officially published versions as well as+# forks / in-progress versions pinned to a git hash. For example:+#+# extra-deps:+# - acme-missiles-0.3+# - git: https://github.com/commercialhaskell/stack.git+#   commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a+#+# extra-deps: []++# Override default flag values for local packages and extra-deps+# flags: {}++# Extra package databases containing global packages+# extra-package-dbs: []++# Control whether we use the GHC we find on the path+# system-ghc: true+#+# Require a specific version of stack, using version ranges+# require-stack-version: -any # Default+# require-stack-version: ">=2.3"+#+# Override the architecture used by stack, especially useful on Windows+# arch: i386+# arch: x86_64+#+# Extra directories used by stack for building+# extra-include-dirs: [/path/to/dir]+# extra-lib-dirs: [/path/to/dir]+#+# Allow a newer minor version of GHC than the snapshot specifies+# compiler-check: newer-minor