diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix index 0a1c2fe50cdd..c716e7f98a59 100644 --- a/nixos/lib/utils.nix +++ b/nixos/lib/utils.nix @@ -541,6 +541,33 @@ let - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh */ binfmtMagics = import ./binfmt-magics.nix; + + # Utilities for working with the security.pam module (pam.nix) + pam = { + /* + Set up the ordering for a set of PAM rules using an ordered list of rules. + + The input is an ordered list of PAM rules. Each rule is an attrset similar to the options + in `security.pam.services..rules.`, with two modifications: + + 1. The `order` option may not be given. + 2. The `name` option is required. + + The output is an attrset of rules suitable for `security.pam.services..rules`. + + The `order` option on the resulting rules will automatically be configured according to the + (implied) ordering of the input rules. + */ + autoOrderRules = lib.flip lib.pipe [ + (lib.imap1 ( + index: rule: + assert lib.assertMsg (!rule ? order) "the 'order' option may not be set when using autoOrderRules"; + rule // { order = lib.mkDefault (10000 + index * 100); } + )) + (map (rule: lib.nameValuePair rule.name (removeAttrs rule [ "name" ]))) + lib.listToAttrs + ]; + }; }; in utils diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 539029e16978..46b9d71ac2ed 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -3,6 +3,7 @@ { config, lib, + utils, pkgs, ... }: @@ -173,6 +174,28 @@ let }; }; + useDefaultRules = lib.mkOption { + # This option is experimental and subject to breaking changes without notice. + visible = false; + default = true; + type = lib.types.bool; + description = '' + Whether to set up the default NixOS rule stack for this service. + + Set this to `false` if you want to define the entire rule stack for this service. + + ::: {.warning} + This option is experimental and subject to breaking changes without notice. + + If you use this option in your system configuration, you will need to manually monitor this module for any changes. Otherwise, failure to adjust your configuration properly could lead to you being locked out of your system, or worse, your system could be left wide open to attackers. + + If you share configuration examples that use this option, you MUST include this warning so that users are informed. + + You may freely use this option within `nixpkgs`, and future changes will account for those use sites. + ::: + ''; + }; + unixAuth = lib.mkOption { default = true; type = lib.types.bool; @@ -899,16 +922,9 @@ let # !!! TODO: move the LDAP stuff to the LDAP module, and the # Samba stuff to the Samba module. This requires that the PAM # module provides the right hooks. - rules = - let - autoOrderRules = lib.flip lib.pipe [ - (lib.imap1 (index: rule: rule // { order = lib.mkDefault (10000 + index * 100); })) - (map (rule: lib.nameValuePair rule.name (removeAttrs rule [ "name" ]))) - lib.listToAttrs - ]; - in - { - account = autoOrderRules [ + rules = ( + lib.optionalAttrs cfg.useDefaultRules { + account = utils.pam.autoOrderRules [ { name = "ldap"; enable = use_ldap; @@ -989,7 +1005,7 @@ let ]; - auth = autoOrderRules ( + auth = utils.pam.autoOrderRules ( [ { name = "oslogin_login"; @@ -1362,7 +1378,7 @@ let ] ); - password = autoOrderRules [ + password = utils.pam.autoOrderRules [ { name = "systemd_home"; enable = config.services.homed.enable; @@ -1447,7 +1463,7 @@ let } ]; - session = autoOrderRules [ + session = utils.pam.autoOrderRules [ { name = "env"; enable = cfg.setEnvironment; @@ -1679,7 +1695,8 @@ let modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; } ]; - }; + } + ); }; }; @@ -2554,16 +2571,30 @@ in }; security.pam.services = { - other.text = '' - auth required pam_warn.so - auth required pam_deny.so - account required pam_warn.so - account required pam_deny.so - password required pam_warn.so - password required pam_deny.so - session required pam_warn.so - session required pam_deny.so - ''; + other = { + useDefaultRules = false; + rules = + let + rules = utils.pam.autoOrderRules [ + { + name = "warn"; + control = "required"; + modulePath = "${package}/lib/security/pam_warn.so"; + } + { + name = "deny"; + control = "required"; + modulePath = "${package}/lib/security/pam_deny.so"; + } + ]; + in + { + auth = rules; + account = rules; + password = rules; + session = rules; + }; + }; # Most of these should be moved to specific modules. i3lock.enable = lib.mkDefault config.programs.i3lock.enable; diff --git a/nixos/modules/services/display-managers/gdm.nix b/nixos/modules/services/display-managers/gdm.nix index 62b90efa92b9..6de21115eb2a 100644 --- a/nixos/modules/services/display-managers/gdm.nix +++ b/nixos/modules/services/display-managers/gdm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -383,67 +384,280 @@ in # GDM LFS PAM modules, adapted somehow to NixOS security.pam.services = { - gdm-launch-environment.text = '' - auth required pam_succeed_if.so audit quiet_success user ingroup gdm - auth optional pam_permit.so + gdm-launch-environment = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required pam_succeed_if.so audit quiet_success user ingroup gdm - account sufficient pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required pam_succeed_if.so audit quiet_success user ingroup gdm - session required pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional pam_keyinit.so force revoke - session optional pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - gdm-password.text = '' - auth substack login - account include login - password substack login - session include login - ''; + gdm-password = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - gdm-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_succeed_if.so uid >= 1000 quiet - ${lib.optionalString (pamLogin.enable && pamLogin.enableGnomeKeyring) '' - auth [success=ok default=1] ${gdm}/lib/security/pam_gdm.so - auth optional ${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so - ''} - auth required pam_permit.so + gdm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "gdm-normal-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "gdm"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "[success=ok default=1]"; + modulePath = "${gdm}/lib/security/pam_gdm.so"; + } + { + name = "gnome_keyring"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "optional"; + modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account sufficient pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password requisite pam_unix.so nullok yescrypt + password = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + settings.yescrypt = true; + } + ]; - session optional pam_keyinit.so revoke - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.revoke = true; + } + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; # This would block password prompt when included by gdm-password. # GDM will instead run gdm-fingerprint in parallel. login.fprintAuth = lib.mkIf config.services.fprintd.enable false; - gdm-fingerprint.text = lib.mkIf config.services.fprintd.enable '' - auth required pam_shells.so - auth requisite pam_nologin.so - auth requisite pam_faillock.so preauth - auth required ${pkgs.fprintd}/lib/security/pam_fprintd.so - auth required pam_env.so conffile=/etc/pam/environment readenv=0 - ${lib.optionalString (pamLogin.enable && pamLogin.enableGnomeKeyring) '' - auth [success=ok default=1] ${gdm}/lib/security/pam_gdm.so - auth optional ${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so - ''} + gdm-fingerprint = lib.mkIf config.services.fprintd.enable { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "shells"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_shells.so"; + } + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "faillock"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_faillock.so"; + settings.preauth = true; + } + { + name = "fprintd"; + control = "required"; + modulePath = "${pkgs.fprintd}/lib/security/pam_fprintd.so"; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "gdm"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "[success=ok default=1]"; + modulePath = "${gdm}/lib/security/pam_gdm.so"; + } + { + name = "gnome_keyring"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "optional"; + modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; + } + ]; - account include login + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; - password required pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; }; }; diff --git a/nixos/modules/services/display-managers/ly.nix b/nixos/modules/services/display-managers/ly.nix index 8d671ca5242f..a75da6f68078 100644 --- a/nixos/modules/services/display-managers/ly.nix +++ b/nixos/modules/services/display-managers/ly.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -105,17 +106,58 @@ in }; } // optionalAttrs dmcfg.autoLogin.enable { - ly-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_succeed_if.so uid >= 1000 quiet - auth required pam_permit.so + ly-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "pam_nologin.so"; + } + { + name = "ly-normal-user"; + control = "required"; + modulePath = "pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - account include ly + account = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; - password include ly + password = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; - session include ly - ''; + session = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; + }; + }; }; environment = { diff --git a/nixos/modules/services/display-managers/plasma-login-manager.nix b/nixos/modules/services/display-managers/plasma-login-manager.nix index 8bfcfc37f4f7..4c98f75b8973 100644 --- a/nixos/modules/services/display-managers/plasma-login-manager.nix +++ b/nixos/modules/services/display-managers/plasma-login-manager.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -83,39 +84,133 @@ in environment.etc."plasmalogin.conf.d/99-user.conf".source = userConfigFile; security.pam.services = { - plasmalogin.text = '' - auth substack login - account include login - password substack login - session include login - ''; + plasmalogin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - plasmalogin-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_permit.so + plasmalogin-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "pam_nologin.so"; + } + { + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - account include plasmalogin - password include plasmalogin - session include plasmalogin - ''; + account = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + }; + }; - plasmalogin-greeter.text = '' - # Load environment from /etc/environment and ~/.pam_environment - auth required pam_env.so conffile=/etc/pam/environment readenv=0 + plasmalogin-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + # Load environment from /etc/environment and ~/.pam_environment + name = "env"; + control = "required"; + modulePath = "pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + # Always let the greeter start without authentication + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - # Always let the greeter start without authentication - auth required pam_permit.so + account = utils.pam.autoOrderRules [ + { + # No action required for account management + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - # No action required for account management - account required pam_permit.so + password = utils.pam.autoOrderRules [ + { + # Can't change password + name = "deny"; + control = "required"; + modulePath = "pam_deny.so"; + } + ]; - # Can't change password - password required pam_deny.so - - # Setup session - session required pam_unix.so - session optional ${config.systemd.package}/lib/security/pam_systemd.so - ''; + session = utils.pam.autoOrderRules [ + { + # Setup session + name = "unix"; + control = "required"; + modulePath = "pam_unix.so"; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + ]; + }; + }; }; # FIXME: use upstream sysusers diff --git a/nixos/modules/services/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix index b960c7e63d8d..5cb750786b00 100644 --- a/nixos/modules/services/display-managers/sddm.nix +++ b/nixos/modules/services/display-managers/sddm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -368,40 +369,184 @@ in }; security.pam.services = { - sddm.text = '' - auth substack login - account include login - password substack login - session include login - ''; + sddm = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - sddm-greeter.text = '' - auth required pam_succeed_if.so audit quiet_success user = sddm - auth optional pam_permit.so + sddm-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required pam_succeed_if.so audit quiet_success user = sddm - account sufficient pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required pam_succeed_if.so audit quiet_success user = sddm - session required pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional pam_keyinit.so force revoke - session optional pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - sddm-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_succeed_if.so uid >= ${toString cfg.autoLogin.minimumUid} quiet - auth required pam_permit.so + sddm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "sddm-autologin-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + (toString cfg.autoLogin.minimumUid) + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account include sddm + account = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; - password include sddm + password = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; - session include sddm - ''; + session = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; + }; + }; }; users.users.sddm = { diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix index 3a129f1a610e..481ceb74886e 100644 --- a/nixos/modules/services/networking/vsftpd.nix +++ b/nixos/modules/services/networking/vsftpd.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -333,9 +334,23 @@ in }; }; - security.pam.services.vsftpd.text = mkIf (cfg.enableVirtualUsers && cfg.userDbPath != null) '' - auth required pam_userdb.so db=${cfg.userDbPath} - account required pam_userdb.so db=${cfg.userDbPath} - ''; + security.pam.services.vsftpd = mkIf (cfg.enableVirtualUsers && cfg.userDbPath != null) { + useDefaultRules = false; + rules = + let + rules = utils.pam.autoOrderRules [ + { + name = "userdb"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_userdb.so"; + settings.db = cfg.userDbPath; + } + ]; + in + { + auth = rules; + account = rules; + }; + }; }; } diff --git a/nixos/modules/services/wayland/cage.nix b/nixos/modules/services/wayland/cage.nix index e39e31ef6272..006520ea9b63 100644 --- a/nixos/modules/services/wayland/cage.nix +++ b/nixos/modules/services/wayland/cage.nix @@ -2,6 +2,7 @@ config, pkgs, lib, + utils, ... }: @@ -105,13 +106,45 @@ in security.polkit.enable = true; - security.pam.services.cage.text = '' - auth required pam_unix.so nullok - account required pam_unix.so - session required pam_unix.so - session required pam_env.so conffile=/etc/pam/environment readenv=0 - session required ${config.systemd.package}/lib/security/pam_systemd.so - ''; + security.pam.services.cage = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "required"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + ]; + }; + }; hardware.graphics.enable = mkDefault true; diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 467207ecd92b..699a9a9a07f3 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -279,47 +280,201 @@ in security.polkit.enable = true; - security.pam.services.lightdm.text = '' - auth substack login - account include login - password substack login - session include login - '' - # https://github.com/elementary/switchboard-plug-parental-controls/blob/8.0.1/src/daemon/Server.vala#L325 - # Must specify conffile since pam_time defaults to ${linux-pam}/etc/security/time.conf. - + lib.optionalString config.services.pantheon.parental-controls.enable '' - account required pam_time.so conffile=/etc/security/time.conf - ''; + security.pam.services.lightdm = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + { + name = "time"; + # https://github.com/elementary/switchboard-plug-parental-controls/blob/8.0.1/src/daemon/Server.vala#L325 + enable = config.services.pantheon.parental-controls.enable; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_time.so"; + # Must specify conffile since pam_time defaults to ${linux-pam}/etc/security/time.conf. + settings.conffile = "/etc/security/time.conf"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - security.pam.services.lightdm-greeter.text = '' - auth required pam_succeed_if.so audit quiet_success user = lightdm - auth optional pam_permit.so + security.pam.services.lightdm-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required pam_succeed_if.so audit quiet_success user = lightdm - account sufficient pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required pam_succeed_if.so audit quiet_success user = lightdm - session required pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional pam_keyinit.so force revoke - session optional pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - security.pam.services.lightdm-autologin.text = '' - auth requisite pam_nologin.so + security.pam.services.lightdm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "lightdm-normal-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - auth required pam_succeed_if.so uid >= 1000 quiet - auth required pam_permit.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - account sufficient pam_unix.so + password = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + settings.yescrypt = true; + } + ]; - password requisite pam_unix.so nullok yescrypt - - session optional pam_keyinit.so revoke - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.revoke = true; + } + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; users.users.lightdm = { home = "/var/lib/lightdm";