This repository has no description
4.5 kB
148 lines
1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7with lib;
8let
9
10 cfg = config.lass.usershadow;
11
12 out = {
13 options.lass.usershadow = api;
14 config = lib.mkIf cfg.enable imp;
15 };
16
17 api = {
18 enable = mkEnableOption "usershadow";
19 pattern = mkOption {
20 type = types.str;
21 default = "/home/%/.shadow";
22 };
23 path = mkOption {
24 type = types.str;
25 };
26 };
27
28 imp = {
29 environment.systemPackages = [ usershadow ];
30 lass.usershadow.path = "${usershadow}";
31 security.pam.services.sshd.text = ''
32 auth required pam_exec.so expose_authtok /run/wrappers/bin/shadow_verify_pam ${cfg.pattern}
33 auth required pam_permit.so
34 account required pam_permit.so
35 session required pam_permit.so
36 '';
37
38 security.pam.services.dovecot2.text = ''
39 auth required pam_exec.so expose_authtok /run/wrappers/bin/shadow_verify_pam ${cfg.pattern}
40 auth required pam_permit.so
41 account required pam_permit.so
42 session required pam_permit.so
43 '';
44
45 security.wrappers.shadow_verify_pam = {
46 setuid = true;
47 source = "${usershadow}/bin/verify_pam";
48 owner = "root";
49 group = "root";
50 };
51 security.wrappers.shadow_verify_arg = {
52 setuid = true;
53 source = "${usershadow}/bin/verify_arg";
54 owner = "root";
55 group = "root";
56 };
57 };
58
59 usershadow =
60 let
61 deps = [
62 "pwstore-fast"
63 "bytestring"
64 ];
65 in
66 pkgs.writeHaskellPackage "passwords" {
67 ghc-options = [
68 "-rtsopts"
69 "-Wall"
70 ];
71 executables.verify_pam = {
72 extra-depends = deps;
73 text = ''
74 import System.IO
75 import Data.Char (chr)
76 import System.Environment (getEnv, getArgs)
77 import Crypto.PasswordStore (verifyPasswordWith, pbkdf2)
78 import qualified Data.ByteString.Char8 as BS8
79 import System.Exit (exitFailure, exitSuccess)
80
81 main :: IO ()
82 main = do
83 user <- getEnv "PAM_USER"
84 shadowFilePattern <- head <$> getArgs
85 let shadowFile = lhs <> user <> tail rhs
86 (lhs, rhs) = span (/= '%') shadowFilePattern
87 hash <- readFile shadowFile
88 password <- takeWhile (/= (chr 0)) <$> hGetLine stdin
89 let res = verifyPasswordWith pbkdf2 (2^) (BS8.pack password) (BS8.pack hash)
90 if res then exitSuccess else exitFailure
91 '';
92 };
93 executables.verify_arg = {
94 extra-depends = deps;
95 text = ''
96 import System.Environment (getArgs)
97 import Crypto.PasswordStore (verifyPasswordWith, pbkdf2)
98 import qualified Data.ByteString.Char8 as BS8
99 import System.Exit (exitFailure, exitSuccess)
100
101 main :: IO ()
102 main = do
103 argsList <- getArgs
104 let shadowFilePattern = argsList !! 0
105 let user = argsList !! 1
106 let password = argsList !! 2
107 let shadowFile = lhs <> user <> tail rhs
108 (lhs, rhs) = span (/= '%') shadowFilePattern
109 hash <- readFile shadowFile
110 let res = verifyPasswordWith pbkdf2 (2^) (BS8.pack password) (BS8.pack hash)
111 if res then do (putStr "yes") else exitFailure
112 '';
113 };
114 executables.passwd = {
115 extra-depends = deps;
116 text = ''
117 import System.Environment (getEnv)
118 import Crypto.PasswordStore (makePasswordWith, pbkdf2)
119 import qualified Data.ByteString.Char8 as BS8
120 import System.IO (stdin, stdout, hSetEcho, hFlush, putStr, putStrLn)
121 import Control.Exception (bracket_)
122
123 main :: IO ()
124 main = do
125 home <- getEnv "HOME"
126 mb_password <- bracket_ (hSetEcho stdin False) (hSetEcho stdin True) $ do
127 putStr "Enter new UNIX password: "
128 hFlush stdout
129 password <- BS8.hGetLine stdin
130 putStrLn ""
131 putStr "Retype new UNIX password: "
132 hFlush stdout
133 password2 <- BS8.hGetLine stdin
134 return $ if password == password2
135 then Just password
136 else Nothing
137 case mb_password of
138 Just password -> do
139 hash <- makePasswordWith pbkdf2 password 10
140 BS8.writeFile (home ++ "/.shadow") hash
141 putStrLn "passwd: all authentication tokens updated successfully."
142 Nothing -> putStrLn "Sorry, passwords do not match"
143 '';
144 };
145 };
146
147in
148out