From e778520f714aac4f2fee751a6f8ab83f1d777c38 Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 28 Jun 2025 19:50:59 -0400 Subject: [PATCH 1/5] nixos: use full path to PAM modules PAM rules with non-absolute module paths are rejected when apparmor is used. In general, it helps (aside from readability) for all the module paths to be absolute, especially when the user overrides the PAM package. --- nixos/modules/security/pam.nix | 16 ++++---- .../modules/services/display-managers/gdm.nix | 40 +++++++++---------- .../services/display-managers/sddm.nix | 24 +++++------ nixos/modules/services/networking/vsftpd.nix | 4 +- nixos/modules/services/wayland/cage.nix | 8 ++-- .../services/x11/display-managers/lightdm.nix | 32 +++++++-------- 6 files changed, 62 insertions(+), 62 deletions(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index d568b32a45a3..15a889ac7e11 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -2532,14 +2532,14 @@ 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 + auth required ${package}/lib/security/pam_warn.so + auth required ${package}/lib/security/pam_deny.so + account required ${package}/lib/security/pam_warn.so + account required ${package}/lib/security/pam_deny.so + password required ${package}/lib/security/pam_warn.so + password required ${package}/lib/security/pam_deny.so + session required ${package}/lib/security/pam_warn.so + session required ${package}/lib/security/pam_deny.so ''; # Most of these should be moved to specific modules. diff --git a/nixos/modules/services/display-managers/gdm.nix b/nixos/modules/services/display-managers/gdm.nix index 62b90efa92b9..18998ddeb34f 100644 --- a/nixos/modules/services/display-managers/gdm.nix +++ b/nixos/modules/services/display-managers/gdm.nix @@ -384,19 +384,19 @@ 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 + auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm + auth optional ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm + account sufficient ${config.security.pam.package}/lib/security/pam_unix.so - password required pam_deny.so + password required ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm + session required ${config.security.pam.package}/lib/security/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 optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke + session optional ${config.security.pam.package}/lib/security/pam_permit.so ''; gdm-password.text = '' @@ -407,19 +407,19 @@ in ''; gdm-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_succeed_if.so uid >= 1000 quiet + auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so + auth required ${config.security.pam.package}/lib/security/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 + auth required ${config.security.pam.package}/lib/security/pam_permit.so - account sufficient pam_unix.so + account sufficient ${config.security.pam.package}/lib/security/pam_unix.so - password requisite pam_unix.so nullok yescrypt + password requisite ${config.security.pam.package}/lib/security/pam_unix.so nullok yescrypt - session optional pam_keyinit.so revoke + session optional ${config.security.pam.package}/lib/security/pam_keyinit.so revoke session include login ''; @@ -428,11 +428,11 @@ in 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 ${config.security.pam.package}/lib/security/pam_shells.so + auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so + auth requisite ${config.security.pam.package}/lib/security/pam_faillock.so preauth auth required ${pkgs.fprintd}/lib/security/pam_fprintd.so - auth required pam_env.so conffile=/etc/pam/environment readenv=0 + auth required ${config.security.pam.package}/lib/security/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 @@ -440,7 +440,7 @@ in account include login - password required pam_deny.so + password required ${config.security.pam.package}/lib/security/pam_deny.so session include login ''; diff --git a/nixos/modules/services/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix index b960c7e63d8d..25f63007f9ac 100644 --- a/nixos/modules/services/display-managers/sddm.nix +++ b/nixos/modules/services/display-managers/sddm.nix @@ -376,25 +376,25 @@ in ''; sddm-greeter.text = '' - auth required pam_succeed_if.so audit quiet_success user = sddm - auth optional pam_permit.so + auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm + auth optional ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm + account sufficient ${config.security.pam.package}/lib/security/pam_unix.so - password required pam_deny.so + password required ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm + session required ${config.security.pam.package}/lib/security/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 optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke + session optional ${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 + auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so + auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= ${toString cfg.autoLogin.minimumUid} quiet + auth required ${config.security.pam.package}/lib/security/pam_permit.so account include sddm diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix index 3a129f1a610e..070f77115829 100644 --- a/nixos/modules/services/networking/vsftpd.nix +++ b/nixos/modules/services/networking/vsftpd.nix @@ -334,8 +334,8 @@ 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} + auth required ${config.security.pam.package}/lib/security/pam_userdb.so db=${cfg.userDbPath} + account required ${config.security.pam.package}/lib/security/pam_userdb.so db=${cfg.userDbPath} ''; }; } diff --git a/nixos/modules/services/wayland/cage.nix b/nixos/modules/services/wayland/cage.nix index e39e31ef6272..76731622d50a 100644 --- a/nixos/modules/services/wayland/cage.nix +++ b/nixos/modules/services/wayland/cage.nix @@ -106,10 +106,10 @@ 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 + auth required ${config.security.pam.package}/lib/security/pam_unix.so nullok + account required ${config.security.pam.package}/lib/security/pam_unix.so + session required ${config.security.pam.package}/lib/security/pam_unix.so + session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 session required ${config.systemd.package}/lib/security/pam_systemd.so ''; diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 467207ecd92b..b0e757b21f5f 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -288,36 +288,36 @@ in # 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 + account required ${config.security.pam.package}/lib/security/pam_time.so conffile=/etc/security/time.conf ''; security.pam.services.lightdm-greeter.text = '' - auth required pam_succeed_if.so audit quiet_success user = lightdm - auth optional pam_permit.so + auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm + auth optional ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm + account sufficient ${config.security.pam.package}/lib/security/pam_unix.so - password required pam_deny.so + password required ${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 required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm + session required ${config.security.pam.package}/lib/security/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 optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke + session optional ${config.security.pam.package}/lib/security/pam_permit.so ''; security.pam.services.lightdm-autologin.text = '' - auth requisite pam_nologin.so + auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so - auth required pam_succeed_if.so uid >= 1000 quiet - auth required pam_permit.so + auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= 1000 quiet + auth required ${config.security.pam.package}/lib/security/pam_permit.so - account sufficient pam_unix.so + account sufficient ${config.security.pam.package}/lib/security/pam_unix.so - password requisite pam_unix.so nullok yescrypt + password requisite ${config.security.pam.package}/lib/security/pam_unix.so nullok yescrypt - session optional pam_keyinit.so revoke + session optional ${config.security.pam.package}/lib/security/pam_keyinit.so revoke session include login ''; From 6954501f5310e922889ccd935120ced246b0e84d Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 28 Jun 2025 14:21:11 -0400 Subject: [PATCH 2/5] nixos/pam: add useDefaultRules option This option is enabled by default to preserve the current behavior when a new service is declared. Users may disable this option to more easily create a service without any rules. In nixpkgs, we can use this option to eliminate usage of the 'text' option where the entire service rule stack is replaced. --- nixos/modules/security/pam.nix | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 15a889ac7e11..720f2229d084 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -172,6 +172,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; @@ -884,7 +906,7 @@ let lib.listToAttrs ]; in - { + lib.optionalAttrs cfg.useDefaultRules { account = autoOrderRules [ { name = "ldap"; From a6144954c6283ac14692579a6c746afe3fedf233 Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 3 Jan 2026 23:32:09 -0500 Subject: [PATCH 3/5] nixos/pam: add assertion for autoOrderRules --- nixos/modules/security/pam.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 720f2229d084..ff996943efa1 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -901,7 +901,11 @@ let rules = let autoOrderRules = lib.flip lib.pipe [ - (lib.imap1 (index: rule: rule // { order = lib.mkDefault (10000 + index * 100); })) + (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 ]; From ab27ce1f9647882076f3c7efa17d4d0bdce9be9b Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 28 Jun 2025 17:28:12 -0400 Subject: [PATCH 4/5] nixos/pam: extract autoOrderRules to utils This function is used to convert an ordered list of rules into an attrset of rules with reasonable 'order' values. This reduces boilerplate to define 'order' and makes it simple to switch how ordering is managed in the future. --- nixos/lib/utils.nix | 27 +++++++++++++++++++++++++++ nixos/modules/security/pam.nix | 25 ++++++++----------------- 2 files changed, 35 insertions(+), 17 deletions(-) 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 ff996943efa1..a9c2d5fe6413 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -3,6 +3,7 @@ { config, lib, + utils, pkgs, ... }: @@ -898,20 +899,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: - 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 + rules = ( lib.optionalAttrs cfg.useDefaultRules { - account = autoOrderRules [ + account = utils.pam.autoOrderRules [ { name = "ldap"; enable = use_ldap; @@ -992,7 +982,7 @@ let ]; - auth = autoOrderRules ( + auth = utils.pam.autoOrderRules ( [ { name = "oslogin_login"; @@ -1365,7 +1355,7 @@ let ] ); - password = autoOrderRules [ + password = utils.pam.autoOrderRules [ { name = "systemd_home"; enable = config.services.homed.enable; @@ -1450,7 +1440,7 @@ let } ]; - session = autoOrderRules [ + session = utils.pam.autoOrderRules [ { name = "env"; enable = cfg.setEnvironment; @@ -1682,7 +1672,8 @@ let modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; } ]; - }; + } + ); }; }; From 4b864991aa141958fc701e4925527fbf45ff1bf0 Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 28 Jun 2025 19:53:19 -0400 Subject: [PATCH 5/5] nixos: replace 'text' with structured PAM rules Several modules define whole PAM service rule stacks by overwriting the default value of the 'text' option. Instead, we disable useDefaultRules for these services and declare a new set of rules using the 'rules' option. This option is considered experimental and hidden from users, but it is supported for use within nixpkgs. --- nixos/modules/security/pam.nix | 34 +- .../modules/services/display-managers/gdm.nix | 304 +++++++++++++++--- .../modules/services/display-managers/ly.nix | 58 +++- .../display-managers/plasma-login-manager.nix | 149 +++++++-- .../services/display-managers/sddm.nix | 197 ++++++++++-- nixos/modules/services/networking/vsftpd.nix | 23 +- nixos/modules/services/wayland/cage.nix | 47 ++- .../services/x11/display-managers/lightdm.nix | 221 +++++++++++-- 8 files changed, 873 insertions(+), 160 deletions(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index a9c2d5fe6413..2c6b3419bf2f 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -2548,16 +2548,30 @@ in }; security.pam.services = { - other.text = '' - auth required ${package}/lib/security/pam_warn.so - auth required ${package}/lib/security/pam_deny.so - account required ${package}/lib/security/pam_warn.so - account required ${package}/lib/security/pam_deny.so - password required ${package}/lib/security/pam_warn.so - password required ${package}/lib/security/pam_deny.so - session required ${package}/lib/security/pam_warn.so - session required ${package}/lib/security/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 18998ddeb34f..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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - auth optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - account sufficient ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_nologin.so - auth required ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password requisite ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_shells.so - auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so - auth requisite ${config.security.pam.package}/lib/security/pam_faillock.so preauth - auth required ${pkgs.fprintd}/lib/security/pam_fprintd.so - auth required ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/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 25f63007f9ac..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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - auth optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - account sufficient ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_nologin.so - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= ${toString cfg.autoLogin.minimumUid} quiet - auth required ${config.security.pam.package}/lib/security/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 070f77115829..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 ${config.security.pam.package}/lib/security/pam_userdb.so db=${cfg.userDbPath} - account required ${config.security.pam.package}/lib/security/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 76731622d50a..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 ${config.security.pam.package}/lib/security/pam_unix.so nullok - account required ${config.security.pam.package}/lib/security/pam_unix.so - session required ${config.security.pam.package}/lib/security/pam_unix.so - session required ${config.security.pam.package}/lib/security/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 b0e757b21f5f..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 ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - auth optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - account sufficient ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= 1000 quiet - auth required ${config.security.pam.package}/lib/security/pam_permit.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - account sufficient ${config.security.pam.package}/lib/security/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 ${config.security.pam.package}/lib/security/pam_unix.so nullok yescrypt - - session optional ${config.security.pam.package}/lib/security/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";