This repository has no description
4.7 kB
147 lines
1{ config, lib, pkgs, ... }@args: with lib; let
2
3 cfg = config.lass.usershadow;
4
5 out = {
6 options.lass.usershadow = api;
7 config = lib.mkIf cfg.enable imp;
8 };
9
10 api = {
11 enable = mkEnableOption "usershadow";
12 pattern = mkOption {
13 type = types.str;
14 default = "/home/%/.shadow";
15 };
16 path = mkOption {
17 type = types.str;
18 };
19 };
20
21 debugscript = pkgs.writeDash "testpam" ''
22 env > /tmp/xxx
23 echo xxx >> /tmp/xxx
24 ${pkgs.coreutils}/bin/cat /home/testuser/.shadow >> /tmp/xxx
25 echo yyy >> /tmp/xxx
26 env >> /tmp/xxx
27 exit 23
28 '';
29
30 imp = {
31 environment.systemPackages = [ usershadow ];
32 lass.usershadow.path = "${usershadow}";
33 security.pam.services.sshd.text = ''
34 auth required pam_exec.so expose_authtok /run/wrappers/bin/shadow_verify_pam ${cfg.pattern}
35 auth required pam_permit.so
36 account required pam_permit.so
37 session required pam_permit.so
38 '';
39
40 security.pam.services.dovecot2.text = ''
41 auth required pam_exec.so expose_authtok /run/wrappers/bin/shadow_verify_pam ${cfg.pattern}
42 auth required pam_permit.so
43 account required pam_permit.so
44 session required pam_permit.so
45 '';
46
47 security.wrappers.shadow_verify_pam = {
48 setuid = true;
49 source = "${usershadow}/bin/verify_pam";
50 owner = "root";
51 group = "root";
52 };
53 security.wrappers.shadow_verify_arg = {
54 setuid = true;
55 source = "${usershadow}/bin/verify_arg";
56 owner = "root";
57 group = "root";
58 };
59 };
60
61 usershadow = let
62 deps = [
63 "pwstore-fast"
64 "bytestring"
65 ];
66 in 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 out