at 15.09-beta 16 kB view raw
1# This module provides configuration for the PAM (Pluggable 2# Authentication Modules) system. 3 4{ config, lib, pkgs, ... }: 5 6with lib; 7 8let 9 parentConfig = config; 10 11 pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in { 12 13 options = { 14 15 name = mkOption { 16 example = "sshd"; 17 type = types.str; 18 description = "Name of the PAM service."; 19 }; 20 21 unixAuth = mkOption { 22 default = true; 23 type = types.bool; 24 description = '' 25 Whether users can log in with passwords defined in 26 <filename>/etc/shadow</filename>. 27 ''; 28 }; 29 30 rootOK = mkOption { 31 default = false; 32 type = types.bool; 33 description = '' 34 If set, root doesn't need to authenticate (e.g. for the 35 <command>useradd</command> service). 36 ''; 37 }; 38 39 u2fAuth = mkOption { 40 default = config.security.pam.enableU2F; 41 type = types.bool; 42 description = '' 43 If set, users listed in 44 <filename>~/.yubico/u2f_keys</filename> are able to log in 45 with the associated U2F key. 46 ''; 47 }; 48 49 usbAuth = mkOption { 50 default = config.security.pam.usb.enable; 51 type = types.bool; 52 description = '' 53 If set, users listed in 54 <filename>/etc/pamusb.conf</filename> are able to log in 55 with the associated USB key. 56 ''; 57 }; 58 59 otpwAuth = mkOption { 60 default = config.security.pam.enableOTPW; 61 type = types.bool; 62 description = '' 63 If set, the OTPW system will be used (if 64 <filename>~/.otpw</filename> exists). 65 ''; 66 }; 67 68 fprintAuth = mkOption { 69 default = config.services.fprintd.enable; 70 type = types.bool; 71 description = '' 72 If set, fingerprint reader will be used (if exists and 73 your fingerprints are enrolled). 74 ''; 75 }; 76 77 oathAuth = mkOption { 78 default = config.security.pam.enableOATH; 79 type = types.bool; 80 description = '' 81 If set, the OATH Toolkit will be used. 82 ''; 83 }; 84 85 sshAgentAuth = mkOption { 86 default = false; 87 type = types.bool; 88 description = '' 89 If set, the calling user's SSH agent is used to authenticate 90 against the keys in the calling user's 91 <filename>~/.ssh/authorized_keys</filename>. This is useful 92 for <command>sudo</command> on password-less remote systems. 93 ''; 94 }; 95 96 startSession = mkOption { 97 default = false; 98 type = types.bool; 99 description = '' 100 If set, the service will register a new session with 101 systemd's login manager. For local sessions, this will give 102 the user access to audio devices, CD-ROM drives. In the 103 default PolicyKit configuration, it also allows the user to 104 reboot the system. 105 ''; 106 }; 107 108 setLoginUid = mkOption { 109 type = types.bool; 110 description = '' 111 Set the login uid of the process 112 (<filename>/proc/self/loginuid</filename>) for auditing 113 purposes. The login uid is only set by entry points like 114 <command>login</command> and <command>sshd</command>, not by 115 commands like <command>sudo</command>. 116 ''; 117 }; 118 119 forwardXAuth = mkOption { 120 default = false; 121 type = types.bool; 122 description = '' 123 Whether X authentication keys should be passed from the 124 calling user to the target user (e.g. for 125 <command>su</command>) 126 ''; 127 }; 128 129 pamMount = mkOption { 130 default = config.security.pam.mount.enable; 131 type = types.bool; 132 description = '' 133 Enable PAM mount (pam_mount) system to mount fileystems on user login. 134 ''; 135 }; 136 137 allowNullPassword = mkOption { 138 default = false; 139 type = types.bool; 140 description = '' 141 Whether to allow logging into accounts that have no password 142 set (i.e., have an empty password field in 143 <filename>/etc/passwd</filename> or 144 <filename>/etc/group</filename>). This does not enable 145 logging into disabled accounts (i.e., that have the password 146 field set to <literal>!</literal>). Note that regardless of 147 what the pam_unix documentation says, accounts with hashed 148 empty passwords are always allowed to log in. 149 ''; 150 }; 151 152 requireWheel = mkOption { 153 default = false; 154 type = types.bool; 155 description = '' 156 Whether to permit root access only to members of group wheel. 157 ''; 158 }; 159 160 limits = mkOption { 161 description = '' 162 Attribute set describing resource limits. Defaults to the 163 value of <option>security.pam.loginLimits</option>. 164 ''; 165 }; 166 167 showMotd = mkOption { 168 default = false; 169 type = types.bool; 170 description = "Whether to show the message of the day."; 171 }; 172 173 makeHomeDir = mkOption { 174 default = false; 175 type = types.bool; 176 description = '' 177 Whether to try to create home directories for users 178 with <literal>$HOME</literal>s pointing to nonexistent 179 locations on session login. 180 ''; 181 }; 182 183 updateWtmp = mkOption { 184 default = false; 185 type = types.bool; 186 description = "Whether to update <filename>/var/log/wtmp</filename>."; 187 }; 188 189 logFailures = mkOption { 190 default = false; 191 type = types.bool; 192 description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>."; 193 }; 194 195 text = mkOption { 196 type = types.nullOr types.lines; 197 description = "Contents of the PAM service file."; 198 }; 199 200 }; 201 202 config = { 203 name = mkDefault name; 204 setLoginUid = mkDefault cfg.startSession; 205 limits = mkDefault config.security.pam.loginLimits; 206 207 # !!! TODO: move the LDAP stuff to the LDAP module, and the 208 # Samba stuff to the Samba module. This requires that the PAM 209 # module provides the right hooks. 210 text = mkDefault 211 '' 212 # Account management. 213 account sufficient pam_unix.so 214 ${optionalString config.users.ldap.enable 215 "account sufficient ${pam_ldap}/lib/security/pam_ldap.so"} 216 ${optionalString config.krb5.enable 217 "account sufficient ${pam_krb5}/lib/security/pam_krb5.so"} 218 219 # Authentication management. 220 ${optionalString cfg.rootOK 221 "auth sufficient pam_rootok.so"} 222 ${optionalString cfg.requireWheel 223 "auth required pam_wheel.so use_uid"} 224 ${optionalString cfg.logFailures 225 "auth required pam_tally.so"} 226 ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) 227 "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"} 228 ${optionalString cfg.fprintAuth 229 "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"} 230 ${optionalString cfg.u2fAuth 231 "auth sufficient ${pkgs.pam_u2f}/lib/security/pam_u2f.so"} 232 ${optionalString cfg.usbAuth 233 "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"} 234 ${optionalString cfg.unixAuth 235 "auth ${if (config.security.pam.enableEcryptfs || cfg.pamMount) then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"} 236 ${optionalString cfg.pamMount 237 "auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} 238 ${optionalString config.security.pam.enableEcryptfs 239 "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} 240 ${optionalString cfg.otpwAuth 241 "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"} 242 ${optionalString cfg.oathAuth 243 "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} 244 ${optionalString config.users.ldap.enable 245 "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"} 246 ${optionalString config.krb5.enable '' 247 auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass 248 auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass 249 auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass 250 ''} 251 ${optionalString (!(config.security.pam.enableEcryptfs || cfg.pamMount)) "auth required pam_deny.so"} 252 253 # Password management. 254 password requisite pam_unix.so nullok sha512 255 ${optionalString config.security.pam.enableEcryptfs 256 "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 257 ${optionalString cfg.pamMount 258 "password optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} 259 ${optionalString config.users.ldap.enable 260 "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"} 261 ${optionalString config.krb5.enable 262 "password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass"} 263 ${optionalString config.services.samba.syncPasswordsByPam 264 "password optional ${pkgs.samba}/lib/security/pam_smbpass.so nullok use_authtok try_first_pass"} 265 266 # Session management. 267 session required pam_env.so envfile=${config.system.build.pamEnvironment} 268 session required pam_unix.so 269 ${optionalString cfg.setLoginUid 270 "session ${ 271 if config.boot.isContainer then "optional" else "required" 272 } pam_loginuid.so"} 273 ${optionalString cfg.makeHomeDir 274 "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=/etc/skel umask=0022"} 275 ${optionalString cfg.updateWtmp 276 "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"} 277 ${optionalString config.security.pam.enableEcryptfs 278 "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} 279 ${optionalString config.users.ldap.enable 280 "session optional ${pam_ldap}/lib/security/pam_ldap.so"} 281 ${optionalString config.krb5.enable 282 "session optional ${pam_krb5}/lib/security/pam_krb5.so"} 283 ${optionalString cfg.otpwAuth 284 "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"} 285 ${optionalString cfg.oathAuth 286 "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} 287 ${optionalString cfg.startSession 288 "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"} 289 ${optionalString cfg.forwardXAuth 290 "session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"} 291 ${optionalString (cfg.limits != []) 292 "session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}"} 293 ${optionalString (cfg.showMotd && config.users.motd != null) 294 "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"} 295 ${optionalString cfg.pamMount 296 "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} 297 ''; 298 }; 299 300 }; 301 302 303 inherit (pkgs) pam_krb5 pam_ccreds; 304 305 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap; 306 307 # Create a limits.conf(5) file. 308 makeLimitsConf = limits: 309 pkgs.writeText "limits.conf" 310 (concatMapStrings ({ domain, type, item, value }: 311 "${domain} ${type} ${item} ${toString value}\n") 312 limits); 313 314 motd = pkgs.writeText "motd" config.users.motd; 315 316 makePAMService = pamService: 317 { source = pkgs.writeText "${pamService.name}.pam" pamService.text; 318 target = "pam.d/${pamService.name}"; 319 }; 320 321in 322 323{ 324 325 ###### interface 326 327 options = { 328 329 security.pam.loginLimits = mkOption { 330 default = []; 331 example = 332 [ { domain = "ftp"; 333 type = "hard"; 334 item = "nproc"; 335 value = "0"; 336 } 337 { domain = "@student"; 338 type = "-"; 339 item = "maxlogins"; 340 value = "4"; 341 } 342 ]; 343 344 description = 345 '' Define resource limits that should apply to users or groups. 346 Each item in the list should be an attribute set with a 347 <varname>domain</varname>, <varname>type</varname>, 348 <varname>item</varname>, and <varname>value</varname> 349 attribute. The syntax and semantics of these attributes 350 must be that described in the limits.conf(5) man page. 351 ''; 352 }; 353 354 security.pam.services = mkOption { 355 default = []; 356 type = types.loaOf types.optionSet; 357 options = [ pamOpts ]; 358 description = 359 '' 360 This option defines the PAM services. A service typically 361 corresponds to a program that uses PAM, 362 e.g. <command>login</command> or <command>passwd</command>. 363 Each attribute of this set defines a PAM service, with the attribute name 364 defining the name of the service. 365 ''; 366 }; 367 368 security.pam.enableSSHAgentAuth = mkOption { 369 default = false; 370 description = 371 '' 372 Enable sudo logins if the user's SSH agent provides a key 373 present in <filename>~/.ssh/authorized_keys</filename>. 374 This allows machines to exclusively use SSH keys instead of 375 passwords. 376 ''; 377 }; 378 379 security.pam.enableOTPW = mkOption { 380 default = false; 381 description = '' 382 Enable the OTPW (one-time password) PAM module. 383 ''; 384 }; 385 386 security.pam.enableOATH = mkOption { 387 default = false; 388 description = '' 389 Enable the OATH (one-time password) PAM module. 390 ''; 391 }; 392 393 security.pam.enableU2F = mkOption { 394 default = false; 395 description = '' 396 Enable the U2F PAM module. 397 ''; 398 }; 399 400 security.pam.enableEcryptfs = mkOption { 401 default = false; 402 description = '' 403 Enable eCryptfs PAM module (mounting ecryptfs home directory on login). 404 ''; 405 }; 406 407 users.motd = mkOption { 408 default = null; 409 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178."; 410 type = types.nullOr types.string; 411 description = "Message of the day shown to users when they log in."; 412 }; 413 414 }; 415 416 417 ###### implementation 418 419 config = { 420 421 environment.systemPackages = 422 # Include the PAM modules in the system path mostly for the manpages. 423 [ pkgs.pam ] 424 ++ optional config.users.ldap.enable pam_ldap 425 ++ optionals config.krb5.enable [pam_krb5 pam_ccreds] 426 ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] 427 ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ] 428 ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ] 429 ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; 430 431 security.setuidPrograms = 432 optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ]; 433 434 environment.etc = 435 mapAttrsToList (n: v: makePAMService v) config.security.pam.services; 436 437 security.setuidOwners = [ { 438 program = "unix_chkpwd"; 439 source = "${pkgs.pam}/sbin/unix_chkpwd.orig"; 440 owner = "root"; 441 setuid = true; 442 } ]; 443 444 security.pam.services = 445 { other.text = 446 '' 447 auth required pam_warn.so 448 auth required pam_deny.so 449 account required pam_warn.so 450 account required pam_deny.so 451 password required pam_warn.so 452 password required pam_deny.so 453 session required pam_warn.so 454 session required pam_deny.so 455 ''; 456 457 # Most of these should be moved to specific modules. 458 cups = {}; 459 ftp = {}; 460 i3lock = {}; 461 screen = {}; 462 vlock = {}; 463 xlock = {}; 464 xscreensaver = {}; 465 }; 466 467 }; 468 469}