aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore6
-rw-r--r--.github/workflows/tests.yml26
-rw-r--r--.gitignore13
-rw-r--r--Dockerfile14
-rw-r--r--LICENSE23
-rw-r--r--Makefile97
-rw-r--r--README8
-rw-r--r--README.md18
-rw-r--r--basic-conf52
-rw-r--r--linux-pam-conf31
-rw-r--r--login.in10
-rw-r--r--openpam-conf24
-rw-r--r--other.in4
-rwxr-xr-xpambase.py112
-rw-r--r--passwd.in6
-rw-r--r--su.in11
-rw-r--r--system-auth.in41
-rw-r--r--system-login.in62
-rw-r--r--system-session.inc25
-rw-r--r--templates/login.tpl9
-rw-r--r--templates/other.tpl4
-rw-r--r--templates/passwd.tpl8
-rw-r--r--templates/su.tpl8
-rw-r--r--templates/system-auth.tpl88
-rw-r--r--templates/system-local-login.tpl (renamed from system-local-login.in)0
-rw-r--r--templates/system-login.tpl40
-rw-r--r--templates/system-remote-login.tpl (renamed from system-remote-login.in)0
-rw-r--r--templates/system-services.tpl (renamed from system-services.in)6
-rw-r--r--templates/system-session.tpl19
-rw-r--r--tests/rendered/custom/login5
-rw-r--r--tests/rendered/custom/other4
-rw-r--r--tests/rendered/custom/passwd4
-rw-r--r--tests/rendered/custom/su8
-rw-r--r--tests/rendered/custom/system-auth11
-rw-r--r--tests/rendered/custom/system-local-login4
-rw-r--r--tests/rendered/custom/system-login15
-rw-r--r--tests/rendered/custom/system-remote-login4
-rw-r--r--tests/rendered/custom/system-services6
-rw-r--r--tests/rendered/default/login5
-rw-r--r--tests/rendered/default/other4
-rw-r--r--tests/rendered/default/passwd4
-rw-r--r--tests/rendered/default/su8
-rw-r--r--tests/rendered/default/system-auth10
-rw-r--r--tests/rendered/default/system-local-login4
-rw-r--r--tests/rendered/default/system-login14
-rw-r--r--tests/rendered/default/system-remote-login4
-rw-r--r--tests/rendered/default/system-services6
-rw-r--r--tests/rendered/minimal/login5
-rw-r--r--tests/rendered/minimal/other4
-rw-r--r--tests/rendered/minimal/passwd4
-rw-r--r--tests/rendered/minimal/su8
-rw-r--r--tests/rendered/minimal/system-auth10
-rw-r--r--tests/rendered/minimal/system-local-login4
-rw-r--r--tests/rendered/minimal/system-login11
-rw-r--r--tests/rendered/minimal/system-remote-login4
-rw-r--r--tests/rendered/minimal/system-services6
-rw-r--r--tox.ini18
57 files changed, 573 insertions, 386 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..f502e63
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,6 @@
+.git/
+.github/
+stack/
+.dockerignore
+.gitignore
+Dockerfile
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..652d733
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,26 @@
+name: Tests
+
+on:
+ push:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build the Docker image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+ load: true
+ tags: pambase
+ - name: Run tox
+ run: docker run pambase
diff --git a/.gitignore b/.gitignore
index 2c63905..73c8fab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,3 @@
-login
-passwd
-su
-system-auth
-system-login
-system-local-login
-system-remote-login
-system-services
-other
-pambase-*.tar.bz2
+stack/
+.idea/
+.tox/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..1d3d150
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,14 @@
+# based on https://github.com/gentoo/gentoo-docker-images
+
+FROM gentoo/portage:latest as portage
+FROM gentoo/stage3:latest
+
+COPY --from=portage /var/db/repos/gentoo /var/db/repos/gentoo
+
+ENV ACCEPT_KEYWORDS="~amd64"
+RUN emerge -qvu python:3.{10..12} dev-python/tox
+
+COPY . /usr/src/pambase
+WORKDIR /usr/src/pambase
+
+CMD tox --colored yes
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6e891ee
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+MIT License
+
+Copyright (c) 2020 Mikhail Koliada
+Copyright (c) 2020 Sam James
+Copyright (c) 2020 Gentoo Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
deleted file mode 100644
index a459fd0..0000000
--- a/Makefile
+++ /dev/null
@@ -1,97 +0,0 @@
-# Reset this to 'cpp' so it gets traditional syntax; cc -E will not work
-# properly.
-CPP=cpp
-
-# The pam.d file to create
-PAMD=login passwd su system-auth system-login system-local-login system-remote-login system-services other
-
-# command for git (the DVCS); set this to "true" to ignore GIT support
-# (i.e.: in the ebuild)
-GIT=git
-
-# Get this by default, even if I'd like avoid it...
-ifeq "$(IMPLEMENTATION)" ""
-IMPLEMENTATION=linux-pam
-endif
-
-PAMFLAGS = -include $(IMPLEMENTATION)-conf -include basic-conf -DLINUX_PAM_VERSION=$(LINUX_PAM_VERSION)
-
-ifeq "$(CRACKLIB)" "yes"
-PAMFLAGS += -DHAVE_CRACKLIB=1
-endif
-
-ifeq "$(PASSWDQC)" "yes"
-PAMFLAGS += -DHAVE_PASSWDQC=1
-endif
-
-ifeq "$(CONSOLEKIT)" "yes"
-PAMFLAGS += -DHAVE_CONSOLEKIT=1
-endif
-
-ifeq "$(SYSTEMD)" "yes"
-PAMFLAGS += -DHAVE_SYSTEMD=1
-endif
-
-ifeq "$(GNOME_KEYRING)" "yes"
-PAMFLAGS += -DHAVE_GNOME_KEYRING=1
-endif
-
-ifeq "$(SECURETTY)" "yes"
-PAMFLAGS += -DHAVE_SECURETTY=1
-endif
-
-ifeq "$(SELINUX)" "yes"
-PAMFLAGS += -DHAVE_SELINUX=1
-endif
-
-ifeq "$(MKTEMP)" "yes"
-PAMFLAGS += -DHAVE_MKTEMP=1
-endif
-
-ifeq "$(PAM_SSH)" "yes"
-PAMFLAGS += -DHAVE_PAM_SSH=1
-endif
-
-ifeq "$(KRB5)" "yes"
-PAMFLAGS += -DHAVE_KRB5=1
-endif
-
-ifeq "$(NULLOK)" "yes"
-PAMFLAGS += -DWANT_NULLOK=1
-endif
-
-ifeq "$(SHA512)" "yes"
-PAMFLAGS += -DWANT_SHA512=1
-endif
-
-ifeq "$(DEBUG)" "yes"
-PAMFLAGS += -DDEBUG=debug
-endif
-
-ifeq "$(MINIMAL)" "yes"
-PAMFLAGS += -DMINIMAL
-endif
-
-all: $(PAMD)
-
-install: $(PAMD)
- install -d "$(DESTDIR)/etc/pam.d"
- install -m0644 $(PAMD) "$(DESTDIR)/etc/pam.d"
-
-PACKAGE=pambase
-ifeq "$(VERSION)" ""
-VERSION = $(shell date +"%Y%m%d")
-endif
-
-dist: $(PACKAGE)-$(VERSION).tar.xz
-
-$(PACKAGE)-$(VERSION).tar.xz: $(shell $(GIT) ls-files)
- $(GIT) tag $(PACKAGE)-$(VERSION)
- $(GIT) archive --format=tar --prefix=$(PACKAGE)-$(VERSION)/ HEAD | xz > $@
-
-$(PAMD): %: %.in
- $(CPP) -traditional-cpp -P $(PAMFLAGS) $< -o $@
- sed -i -e '/^$$/d' -e '/^\/\//d' $@
-
-clean:
- rm -f $(PAMD) *~
diff --git a/README b/README
deleted file mode 100644
index 20f2e5e..0000000
--- a/README
+++ /dev/null
@@ -1,8 +0,0 @@
-This repository contains the PAM configuration base for Gentoo Linux
-and Gentoo FreeBSD, this mostly means the system-auth and system-login
-configuration file that provides the basic support for generical
-authentication for services, and console login (on tty or on various
-desktop managers).
-
-The Makefile manages the choice of optional features that will be
-enabled in the final file.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..59f4ecd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# pambase
+
+[PAM](https://wiki.gentoo.org/wiki/PAM) base configuration files.
+
+This repository contains a small [Python](https://wiki.gentoo.org/wiki/Python) script that renders `PAM` configuration templates for [Gentoo Linux](https://www.gentoo.org).
+
+## Dependencies
+
+`pambase` depends on [jinja](https://packages.gentoo.org/packages/dev-python/jinja).
+
+## Testing
+
+In order to perform tests, run [tox](https://packages.gentoo.org/packages/dev-python/tox).
+
+Alternatively, you can run tests with [Docker](https://wiki.gentoo.org/wiki/Docker):
+```sh
+docker run --rm -it $(docker build -q .)
+```
diff --git a/basic-conf b/basic-conf
deleted file mode 100644
index 5ab72c0..0000000
--- a/basic-conf
+++ /dev/null
@@ -1,52 +0,0 @@
-// Only use_authtok (authentication token) when using cracklib or some other module
-// that checks for passwords, or pam_krb5
-#define AUTHTOK use_authtok
-
-#if HAVE_CRACKLIB || HAVE_PASSWDQC
-# define PASSWORD_STRENGTH 1
-#endif
-
-#if HAVE_KRB5 && PASSWORD_STRENGTH
-# define KRB5_AUTHTOK AUTHTOK
-#endif
-
-#if HAVE_KRB5 || PASSWORD_STRENGTH
-# define UNIX_AUTHTOK AUTHTOK
-#else
-# define UNIX_AUTHTOK
-#endif
-
-// Define DEBUG to an empty string unless it was required by the user
-#ifndef DEBUG
-#define DEBUG
-#endif
-
-#ifndef UNIX_EXTENDED_ENCRYPTION
-#define UNIX_EXTENDED_ENCRYPTION
-#endif
-
-#ifndef LIKEAUTH
-#define LIKEAUTH
-#endif
-
-#if WANT_NULLOK
-#define NULLOK nullok
-#else
-#define NULLOK
-#endif
-
-#define KRB5_PARAMS DEBUG ignore_root try_first_pass
-
-/* By using the extended Linux-PAM syntax for this, it is possible to
- fine-tune the Kerberos handling so that it works out of hte box on
- most desktop systems.
-
- What this control operation does is ignore failures and errors from
- Kerberos (falling back on local pam_unix auth), but if it's good,
- it'll skip over the following module (pam_unix) with an accepted
- status.
-
- IMPORTANT! Make sure that the only thing that comes right after
- pam_krb5 with KRB5_CONTROL is pam_unix!
- */
-#define KRB5_CONTROL [success=1 default=ignore]
diff --git a/linux-pam-conf b/linux-pam-conf
deleted file mode 100644
index ecd5697..0000000
--- a/linux-pam-conf
+++ /dev/null
@@ -1,31 +0,0 @@
-#define HAVE_LIMITS 1
-#define HAVE_ENV 1
-#define HAVE_ACCESS 1
-#define HAVE_SHELLS 1
-#define HAVE_LOGINUID 1
-
-#define SUPPORT_UNIX_SESSION 1
-#define SUPPORT_NOLOGIN_ACCOUNT 1
-#define SUPPORT_NOLOGIN_AUTH 1
-
-#if !MINIMAL
-# define HAVE_MOTD 1
-# define HAVE_MAIL 1
-# define HAVE_LASTLOG 1
-
-# if LINUX_PAM_VERSION > 0x010100 /* 1.1.0 */
-# define TALLY_MODULE pam_tally2.so
-# else
-# define TALLY_MODULE pam_tally.so
-# endif
-
-#endif
-
-#if WANT_SHA512
-# define UNIX_EXTENDED_ENCRYPTION sha512 shadow
-#else
-# define UNIX_EXTENDED_ENCRYPTION md5 shadow
-#endif
-
-#define LIKEAUTH likeauth
-#define DEBUG_NOLOGIN
diff --git a/login.in b/login.in
deleted file mode 100644
index 5067bc7..0000000
--- a/login.in
+++ /dev/null
@@ -1,10 +0,0 @@
-#if HAVE_SECURETTY
-auth required pam_securetty.so
-#endif
-auth include system-local-login
-
-account include system-local-login
-password include system-local-login
-
-session optional pam_lastlog.so DEBUG
-session include system-local-login
diff --git a/openpam-conf b/openpam-conf
deleted file mode 100644
index e38107c..0000000
--- a/openpam-conf
+++ /dev/null
@@ -1,24 +0,0 @@
-#if HAVE_CRACKLIB
-# error "pam_cracklib is only supported with Linux-PAM"
-#endif
-
-// OpenPAM only provides basic modules, it's FreeBSD that provides the
-// extended modules, so check for FreeBSD building first.
-#ifdef __FreeBSD__
-# define HAVE_LOGIN_ACCESS 1
-# define SUPPORT_UNIX_SESSION 0
-
-# if defined(DEBUG)
-# define DEBUG_NOLOGIN DEBUG
-# else
-# define DEBUG_NOLOGIN
-# endif
-
-# define SUPPORT_NOLOGIN_ACCOUNT 1
-# define SUPPORT_NOLOGIN_AUTH 0
-
-# if defined(WANT_SHA512)
-# error "SHA512 support is not present for FreeBSD!"
-# endif
-
-#endif /* __FreeBSD__ */
diff --git a/other.in b/other.in
deleted file mode 100644
index d8cb1fe..0000000
--- a/other.in
+++ /dev/null
@@ -1,4 +0,0 @@
-auth required pam_deny.so
-account required pam_deny.so
-password required pam_deny.so
-session required pam_deny.so
diff --git a/pambase.py b/pambase.py
new file mode 100755
index 0000000..ceec8cb
--- /dev/null
+++ b/pambase.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+
+import argparse
+from jinja2 import Template, Environment, FileSystemLoader
+import pathlib
+
+
+def main():
+ parser = argparse.ArgumentParser(description='basic Gentoo PAM configuration files')
+ parser.add_argument('--gnome-keyring', action="store_true", help='enable pam_gnome_keyring.so module')
+ parser.add_argument('--caps', action="store_true", help='enable pam_cap.so module')
+ parser.add_argument('--passwdqc', action="store_true", help='enable pam_passwdqc.so module')
+ parser.add_argument('--pwhistory', action="store_true", help='enable pam_pwhistory.so module')
+ parser.add_argument('--pwquality', action="store_true", help='enable pam_pwquality.so module')
+ parser.add_argument('--elogind', action="store_true", help='enable pam_elogind.so module')
+ parser.add_argument('--systemd', action="store_true", help='enable pam_systemd.so module')
+ parser.add_argument('--homed', action="store_true", help='enable pam_systemd_home.so module')
+ parser.add_argument('--selinux', action="store_true", help='enable pam_selinux.so module')
+ parser.add_argument('--mktemp', action="store_true", help='enable pam_mktemp.so module')
+ parser.add_argument('--pam-ssh', action="store_true", help='enable pam_ssh.so module')
+ parser.add_argument('--securetty', action="store_true", help='enable pam_securetty.so module')
+ parser.add_argument('--sssd', action="store_true", help='enable sssd.so module')
+ parser.add_argument('--yescrypt', action="store_true", help='enable yescrypt option for pam_unix.so module')
+ parser.add_argument('--sha512', action="store_true", help='enable sha512 option for pam_unix.so module')
+ parser.add_argument('--krb5', action="store_true", help='enable pam_krb5.so module')
+ parser.add_argument('--minimal', action="store_true", help='install minimalistic PAM stack')
+ parser.add_argument('--debug', action="store_true", help='enable debug for selected modules')
+ parser.add_argument('--nullok', action="store_true", help='enable nullok option for pam_unix.so module')
+
+ parsed_args = parser.parse_args()
+ processed = process_args(parsed_args)
+
+ parse_templates(processed)
+
+
+def process_args(args):
+ # make sure that output directory exists
+ pathlib.Path("stack").mkdir(parents=True, exist_ok=True)
+
+ blank_variables = [
+ "krb5_authtok",
+ "unix_authtok",
+ "unix_extended_encryption",
+ "likeauth",
+ "nullok",
+ "local_users_only"
+ ]
+
+ # create a blank dictionary
+ # then add in our parsed args
+ output = dict.fromkeys(blank_variables, "")
+ output.update(vars(args))
+
+ # unconditional variables
+ output["likeauth"] = "likeauth"
+ output["unix_authtok"] = "use_authtok"
+
+ if args.debug:
+ output["debug"] = "debug"
+
+ if args.nullok:
+ output["nullok"] = "nullok"
+
+ if args.krb5:
+ output["krb5_params"] = "{0} ignore_root try_first_pass".format("debug").strip()
+
+ if args.sssd:
+ output["local_users_only"] = "local_users_only"
+
+ if args.yescrypt:
+ output["unix_extended_encryption"] = "yescrypt shadow"
+ elif args.sha512:
+ output["unix_extended_encryption"] = "sha512 shadow"
+ else:
+ output["unix_extended_encryption"] = "md5 shadow"
+
+ return output
+
+
+def parse_templates(processed_args):
+ load = FileSystemLoader('')
+ env = Environment(loader=load, trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True)
+
+ templates = [
+ "login",
+ "other",
+ "passwd",
+ "system-local-login",
+ "system-remote-login",
+ "su",
+ "system-auth",
+ "system-login",
+ "system-services"
+ ]
+
+ for template_name in templates:
+ template = env.get_template('templates/{0}.tpl'.format(template_name))
+
+ with open('stack/{0}'.format(template_name), "w+") as output:
+ rendered_template = template.render(processed_args)
+
+ # Strip all intermediate lines to not worry about appeasing Jinja
+ lines = rendered_template.split("\n")
+ lines = [line.strip() for line in lines if line]
+ rendered_template = "\n".join(lines)
+
+ if rendered_template:
+ output.write(rendered_template + "\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/passwd.in b/passwd.in
deleted file mode 100644
index 7eabf3d..0000000
--- a/passwd.in
+++ /dev/null
@@ -1,6 +0,0 @@
-auth sufficient pam_rootok.so
-auth include system-auth
-
-account include system-auth
-
-password include system-auth
diff --git a/su.in b/su.in
deleted file mode 100644
index 889ecfe..0000000
--- a/su.in
+++ /dev/null
@@ -1,11 +0,0 @@
-auth sufficient pam_rootok.so
-auth required pam_wheel.so use_uid
-auth include system-auth
-
-account include system-auth
-
-password include system-auth
-
-session include system-auth
-session required pam_env.so
-session optional pam_xauth.so
diff --git a/system-auth.in b/system-auth.in
deleted file mode 100644
index c729004..0000000
--- a/system-auth.in
+++ /dev/null
@@ -1,41 +0,0 @@
-#if HAVE_ENV
-auth required pam_env.so DEBUG
-#endif
-#if HAVE_PAM_SSH
-auth sufficient pam_ssh.so
-#endif
-#if HAVE_KRB5
-auth KRB5_CONTROL pam_krb5.so KRB5_PARAMS
-#endif
-auth required pam_unix.so try_first_pass LIKEAUTH NULLOK DEBUG
-/* This is needed to make sure that the Kerberos skip-on-success won't cause a bad jump. */
-auth optional pam_permit.so
-
-#if HAVE_KRB5
-account KRB5_CONTROL pam_krb5.so KRB5_PARAMS
-#endif
-account required pam_unix.so DEBUG
-/* This is needed to make sure that the Kerberos skip-on-success won't cause a bad jump. */
-account optional pam_permit.so
-
-#if HAVE_CRACKLIB
-password required pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 retry=3 DEBUG
-#endif
-#if HAVE_PASSWDQC
-password required pam_passwdqc.so min=8,8,8,8,8 retry=3
-#endif
-#if HAVE_KRB5
-password KRB5_CONTROL pam_krb5.so KRB5_PARAMS
-#endif
-password required pam_unix.so try_first_pass UNIX_AUTHTOK NULLOK UNIX_EXTENDED_ENCRYPTION DEBUG
-/* This is needed to make sure that the Kerberos skip-on-success won't cause a bad jump. */
-password optional pam_permit.so
-
-#if HAVE_PAM_SSH
-session optional pam_ssh.so
-#endif
-#include "system-session.inc"
-
-#if HAVE_SYSTEMD
--session optional pam_systemd.so
-#endif
diff --git a/system-login.in b/system-login.in
deleted file mode 100644
index e630918..0000000
--- a/system-login.in
+++ /dev/null
@@ -1,62 +0,0 @@
-#if defined(TALLY_MODULE)
-auth required TALLY_MODULE onerr=succeed
-#endif
-#if HAVE_SHELLS
-auth required pam_shells.so DEBUG
-#endif
-#if SUPPORT_NOLOGIN_AUTH
-auth required pam_nologin.so DEBUG_NOLOGIN
-#endif
-auth include system-auth
-#if HAVE_GNOME_KEYRING
-auth optional pam_gnome_keyring.so
-#endif
-
-#if HAVE_ACCESS
-account required pam_access.so DEBUG
-#endif
-#if HAVE_LOGIN_ACCESS
-account required pam_login_access.so
-#endif
-#if SUPPORT_NOLOGIN_ACCOUNT
-account required pam_nologin.so DEBUG_NOLOGIN
-#endif
-account include system-auth
-#if defined(TALLY_MODULE)
-account required TALLY_MODULE onerr=succeed DEBUG
-#endif
-
-password include system-auth
-#if HAVE_GNOME_KEYRING
-password optional pam_gnome_keyring.so
-#endif
-
-#if HAVE_LOGINUID
-session optional pam_loginuid.so
-#endif
-#if HAVE_SELINUX
-session required pam_selinux.so close
-#endif
-#if HAVE_ENV
-session required pam_env.so DEBUG
-#endif
-#if HAVE_LASTLOG
-session optional pam_lastlog.so silent DEBUG
-#endif
-session include system-auth
-#if HAVE_CONSOLEKIT
-session optional pam_ck_connector.so nox11
-#endif
-#if HAVE_SELINUX
-# Note: modules that run in the user's context must come after this line.
-session required pam_selinux.so multiple open
-#endif
-#if HAVE_GNOME_KEYRING
-session optional pam_gnome_keyring.so auto_start
-#endif
-#if HAVE_MOTD
-session optional pam_motd.so motd=/etc/motd
-#endif
-#if HAVE_MAIL
-session optional pam_mail.so
-#endif
diff --git a/system-session.inc b/system-session.inc
deleted file mode 100644
index 2ba6964..0000000
--- a/system-session.inc
+++ /dev/null
@@ -1,25 +0,0 @@
-#if HAVE_LIMITS
-session required pam_limits.so DEBUG
-#endif
-#if HAVE_ENV
-session required pam_env.so DEBUG
-#endif
-#if HAVE_MKTEMP
-session optional pam_mktemp.so
-#endif
-
-/* Only Linux-PAM supports session chain for pam_unix; but if it were
- to not support it for whatever reason, still execute pam_krb5, with
- sufficient level instead. */
-#if SUPPORT_UNIX_SESSION
-# if HAVE_KRB5
-session KRB5_CONTROL pam_krb5.so KRB5_PARAMS
-# endif
-session required pam_unix.so DEBUG
-#else
-# if HAVE_KRB5
-session sufficient pam_krb5.so KRB5_PARAMS
-# endif
-#endif
-
-session optional pam_permit.so
diff --git a/templates/login.tpl b/templates/login.tpl
new file mode 100644
index 0000000..cb85249
--- /dev/null
+++ b/templates/login.tpl
@@ -0,0 +1,9 @@
+{% if securetty %}
+auth required pam_securetty.so
+{% endif %}
+
+auth include system-local-login
+account include system-local-login
+password include system-local-login
+session optional pam_lastlog.so {{ debug|default('', true) }}
+session include system-local-login
diff --git a/templates/other.tpl b/templates/other.tpl
new file mode 100644
index 0000000..9544f8e
--- /dev/null
+++ b/templates/other.tpl
@@ -0,0 +1,4 @@
+auth required pam_deny.so
+account required pam_deny.so
+password required pam_deny.so
+session required pam_deny.so
diff --git a/templates/passwd.tpl b/templates/passwd.tpl
new file mode 100644
index 0000000..101a5fc
--- /dev/null
+++ b/templates/passwd.tpl
@@ -0,0 +1,8 @@
+auth sufficient pam_rootok.so
+auth include system-auth
+account include system-auth
+password include system-auth
+
+{% if gnome_keyring %}
+password optional pam_gnome_keyring.so {{ unix_authtok }}
+{% endif %}
diff --git a/templates/su.tpl b/templates/su.tpl
new file mode 100644
index 0000000..a36b633
--- /dev/null
+++ b/templates/su.tpl
@@ -0,0 +1,8 @@
+auth sufficient pam_rootok.so
+auth required pam_wheel.so use_uid
+auth include system-auth
+account include system-auth
+password include system-auth
+session include system-auth
+session required pam_env.so
+session optional pam_xauth.so
diff --git a/templates/system-auth.tpl b/templates/system-auth.tpl
new file mode 100644
index 0000000..9a274a4
--- /dev/null
+++ b/templates/system-auth.tpl
@@ -0,0 +1,88 @@
+auth required pam_env.so {{ debug|default('', true) }}
+{% if pam_ssh %}
+auth sufficient pam_ssh.so
+{% endif %}
+
+{% if krb5 %}
+auth [success={{ 4 if homed else 3 }} default=ignore] pam_krb5.so {{ krb5_params }}
+{% endif %}
+
+{% if sssd %}
+auth [default=1 ignore=ignore success=ok] pam_usertype.so isregular
+auth [default=3 ignore=ignore success=ok] pam_localuser.so
+{% endif %}
+
+auth requisite pam_faillock.so preauth
+
+{% if homed %}
+auth [success=2 default=ignore] pam_systemd_home.so
+{% endif %}
+
+{% if sssd %}
+auth sufficient pam_unix.so {{ nullok|default('', true) }} {{ debug|default('', true) }}
+{% else %}
+auth [success=1 new_authtok_reqd=1 ignore=ignore default=bad] pam_unix.so {{ nullok|default('', true) }} {{ debug|default('', true) }} try_first_pass
+{% endif %}
+auth [default=die] pam_faillock.so authfail
+{% if sssd %}
+auth sufficient pam_sss.so forward_pass {{ debug|default('', true) }}
+{% endif %}
+{% if caps %}
+auth optional pam_cap.so
+{% endif %}
+{% if sssd %}
+auth required pam_deny.so
+{% endif %}
+{% if krb5 %}
+account [success=2 default=ignore] pam_krb5.so {{ krb5_params }}
+{% endif %}
+
+{% if homed %}
+account [success={{ 2 if sssd else 1 }} default=ignore] pam_systemd_home.so
+{% endif %}
+
+account required pam_unix.so {{ debug|default('', true) }}
+account required pam_faillock.so
+{% if sssd %}
+account sufficient pam_localuser.so
+account sufficient pam_usertype.so issystem
+account [default=bad success=ok user_unknown=ignore] pam_sss.so {{ debug|default('', true) }}
+account required pam_permit.so
+{% endif %}
+
+{% if passwdqc %}
+password required pam_passwdqc.so config=/etc/security/passwdqc.conf
+{% endif %}
+
+{% if pwquality %}
+password required pam_pwquality.so {{ local_users_only|default('', true ) }}
+{% endif %}
+
+{% if pwhistory %}
+password required pam_pwhistory.so use_authtok remember=5 retry=3
+{% endif %}
+
+{% if krb5 %}
+password [success=1 default=ignore] pam_krb5.so {{ krb5_params }}
+{% endif %}
+
+{% if homed %}
+password [success=1 default=ignore] pam_systemd_home.so
+{% endif %}
+
+{% if passwdqc or pwquality %}
+password {{ 'sufficient' if sssd else 'required' }} pam_unix.so try_first_pass {{ unix_authtok|default('', true) }} {{ nullok|default('', true) }} {{ unix_extended_encryption|default('', true) }} {{ debug|default('', true) }}
+{% else %}
+password {{ 'sufficient' if sssd else 'required' }} pam_unix.so try_first_pass {{ nullok|default('', true) }} {{ unix_extended_encryption|default('', true) }} {{ debug|default('', true) }}
+{% endif %}
+
+{% if sssd %}
+password sufficient pam_sss.so use_authtok
+password required pam_deny.so
+{% endif %}
+
+{% if pam_ssh %}
+session optional pam_ssh.so
+{% endif %}
+
+{% include "templates/system-session.tpl" %}
diff --git a/system-local-login.in b/templates/system-local-login.tpl
index 2f415ed..2f415ed 100644
--- a/system-local-login.in
+++ b/templates/system-local-login.tpl
diff --git a/templates/system-login.tpl b/templates/system-login.tpl
new file mode 100644
index 0000000..0269296
--- /dev/null
+++ b/templates/system-login.tpl
@@ -0,0 +1,40 @@
+auth required pam_shells.so {{ debug|default('', true) }}
+auth required pam_nologin.so
+auth include system-auth
+
+account required pam_access.so {{ debug|default('', true) }}
+account required pam_nologin.so
+account required pam_time.so
+account include system-auth
+
+password include system-auth
+session optional pam_loginuid.so
+{% if selinux %}
+session required pam_selinux.so close
+{% endif %}
+
+session required pam_env.so envfile=/etc/profile.env {{ debug|default('', true) }}
+{% if not minimal %}
+session optional pam_lastlog.so silent {{ debug|default('', true) }}
+{% endif %}
+session include system-auth
+{% if selinux %}
+ # Note: modules that run in the user's context must come after this line.
+session required pam_selinux.so multiple open
+{% endif %}
+
+{% if not minimal %}
+session optional pam_motd.so motd=/etc/motd
+{% endif %}
+
+{% if not minimal %}
+session optional pam_mail.so
+{% endif %}
+
+{% if systemd %}
+-session optional pam_systemd.so
+{% endif %}
+
+{% if elogind %}
+-session optional pam_elogind.so
+{% endif %}
diff --git a/system-remote-login.in b/templates/system-remote-login.tpl
index 2f415ed..2f415ed 100644
--- a/system-remote-login.in
+++ b/templates/system-remote-login.tpl
diff --git a/system-services.in b/templates/system-services.tpl
index 989267f..cbfab6f 100644
--- a/system-services.in
+++ b/templates/system-services.tpl
@@ -1,8 +1,4 @@
auth sufficient pam_permit.so
-
account include system-auth
-
-#if HAVE_LOGINUID
session optional pam_loginuid.so
-#endif
-#include "system-session.inc"
+{% include "templates/system-session.tpl" %}
diff --git a/templates/system-session.tpl b/templates/system-session.tpl
new file mode 100644
index 0000000..4c5585b
--- /dev/null
+++ b/templates/system-session.tpl
@@ -0,0 +1,19 @@
+session required pam_limits.so {{ debug|default('', true) }}
+session required pam_env.so {{ debug|default('', true) }}
+{% if mktemp %}
+session optional pam_mktemp.so
+{% endif %}
+
+{%if krb5 %}
+session [success=1 default=ignore] pam_krb5.so {{ krb5_params }}
+{% endif %}
+
+{% if homed %}
+session [success=1 default=ignore] pam_systemd_home.so
+{% endif %}
+
+session required pam_unix.so {{ debug|default('', true) }}
+
+{% if sssd %}
+session optional pam_sss.so {{ debug|default('', true) }}
+{% endif %}
diff --git a/tests/rendered/custom/login b/tests/rendered/custom/login
new file mode 100644
index 0000000..e5a66f2
--- /dev/null
+++ b/tests/rendered/custom/login
@@ -0,0 +1,5 @@
+auth include system-local-login
+account include system-local-login
+password include system-local-login
+session optional pam_lastlog.so
+session include system-local-login
diff --git a/tests/rendered/custom/other b/tests/rendered/custom/other
new file mode 100644
index 0000000..9544f8e
--- /dev/null
+++ b/tests/rendered/custom/other
@@ -0,0 +1,4 @@
+auth required pam_deny.so
+account required pam_deny.so
+password required pam_deny.so
+session required pam_deny.so
diff --git a/tests/rendered/custom/passwd b/tests/rendered/custom/passwd
new file mode 100644
index 0000000..0bde2a3
--- /dev/null
+++ b/tests/rendered/custom/passwd
@@ -0,0 +1,4 @@
+auth sufficient pam_rootok.so
+auth include system-auth
+account include system-auth
+password include system-auth
diff --git a/tests/rendered/custom/su b/tests/rendered/custom/su
new file mode 100644
index 0000000..a36b633
--- /dev/null
+++ b/tests/rendered/custom/su
@@ -0,0 +1,8 @@
+auth sufficient pam_rootok.so
+auth required pam_wheel.so use_uid
+auth include system-auth
+account include system-auth
+password include system-auth
+session include system-auth
+session required pam_env.so
+session optional pam_xauth.so
diff --git a/tests/rendered/custom/system-auth b/tests/rendered/custom/system-auth
new file mode 100644
index 0000000..aae3914
--- /dev/null
+++ b/tests/rendered/custom/system-auth
@@ -0,0 +1,11 @@
+auth required pam_env.so
+auth requisite pam_faillock.so preauth
+auth [success=1 new_authtok_reqd=1 ignore=ignore default=bad] pam_unix.so nullok try_first_pass
+auth [default=die] pam_faillock.so authfail
+account required pam_unix.so
+account required pam_faillock.so
+password required pam_passwdqc.so config=/etc/security/passwdqc.conf
+password required pam_unix.so try_first_pass use_authtok nullok sha512 shadow
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tests/rendered/custom/system-local-login b/tests/rendered/custom/system-local-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/custom/system-local-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/custom/system-login b/tests/rendered/custom/system-login
new file mode 100644
index 0000000..161a600
--- /dev/null
+++ b/tests/rendered/custom/system-login
@@ -0,0 +1,15 @@
+auth required pam_shells.so
+auth required pam_nologin.so
+auth include system-auth
+account required pam_access.so
+account required pam_nologin.so
+account required pam_time.so
+account include system-auth
+password include system-auth
+session optional pam_loginuid.so
+session required pam_env.so envfile=/etc/profile.env
+session optional pam_lastlog.so silent
+session include system-auth
+session optional pam_motd.so motd=/etc/motd
+session optional pam_mail.so
+-session optional pam_elogind.so
diff --git a/tests/rendered/custom/system-remote-login b/tests/rendered/custom/system-remote-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/custom/system-remote-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/custom/system-services b/tests/rendered/custom/system-services
new file mode 100644
index 0000000..857363a
--- /dev/null
+++ b/tests/rendered/custom/system-services
@@ -0,0 +1,6 @@
+auth sufficient pam_permit.so
+account include system-auth
+session optional pam_loginuid.so
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tests/rendered/default/login b/tests/rendered/default/login
new file mode 100644
index 0000000..e5a66f2
--- /dev/null
+++ b/tests/rendered/default/login
@@ -0,0 +1,5 @@
+auth include system-local-login
+account include system-local-login
+password include system-local-login
+session optional pam_lastlog.so
+session include system-local-login
diff --git a/tests/rendered/default/other b/tests/rendered/default/other
new file mode 100644
index 0000000..9544f8e
--- /dev/null
+++ b/tests/rendered/default/other
@@ -0,0 +1,4 @@
+auth required pam_deny.so
+account required pam_deny.so
+password required pam_deny.so
+session required pam_deny.so
diff --git a/tests/rendered/default/passwd b/tests/rendered/default/passwd
new file mode 100644
index 0000000..0bde2a3
--- /dev/null
+++ b/tests/rendered/default/passwd
@@ -0,0 +1,4 @@
+auth sufficient pam_rootok.so
+auth include system-auth
+account include system-auth
+password include system-auth
diff --git a/tests/rendered/default/su b/tests/rendered/default/su
new file mode 100644
index 0000000..a36b633
--- /dev/null
+++ b/tests/rendered/default/su
@@ -0,0 +1,8 @@
+auth sufficient pam_rootok.so
+auth required pam_wheel.so use_uid
+auth include system-auth
+account include system-auth
+password include system-auth
+session include system-auth
+session required pam_env.so
+session optional pam_xauth.so
diff --git a/tests/rendered/default/system-auth b/tests/rendered/default/system-auth
new file mode 100644
index 0000000..4c069c3
--- /dev/null
+++ b/tests/rendered/default/system-auth
@@ -0,0 +1,10 @@
+auth required pam_env.so
+auth requisite pam_faillock.so preauth
+auth [success=1 new_authtok_reqd=1 ignore=ignore default=bad] pam_unix.so try_first_pass
+auth [default=die] pam_faillock.so authfail
+account required pam_unix.so
+account required pam_faillock.so
+password required pam_unix.so try_first_pass md5 shadow
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tests/rendered/default/system-local-login b/tests/rendered/default/system-local-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/default/system-local-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/default/system-login b/tests/rendered/default/system-login
new file mode 100644
index 0000000..ae763fc
--- /dev/null
+++ b/tests/rendered/default/system-login
@@ -0,0 +1,14 @@
+auth required pam_shells.so
+auth required pam_nologin.so
+auth include system-auth
+account required pam_access.so
+account required pam_nologin.so
+account required pam_time.so
+account include system-auth
+password include system-auth
+session optional pam_loginuid.so
+session required pam_env.so envfile=/etc/profile.env
+session optional pam_lastlog.so silent
+session include system-auth
+session optional pam_motd.so motd=/etc/motd
+session optional pam_mail.so
diff --git a/tests/rendered/default/system-remote-login b/tests/rendered/default/system-remote-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/default/system-remote-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/default/system-services b/tests/rendered/default/system-services
new file mode 100644
index 0000000..857363a
--- /dev/null
+++ b/tests/rendered/default/system-services
@@ -0,0 +1,6 @@
+auth sufficient pam_permit.so
+account include system-auth
+session optional pam_loginuid.so
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tests/rendered/minimal/login b/tests/rendered/minimal/login
new file mode 100644
index 0000000..e5a66f2
--- /dev/null
+++ b/tests/rendered/minimal/login
@@ -0,0 +1,5 @@
+auth include system-local-login
+account include system-local-login
+password include system-local-login
+session optional pam_lastlog.so
+session include system-local-login
diff --git a/tests/rendered/minimal/other b/tests/rendered/minimal/other
new file mode 100644
index 0000000..9544f8e
--- /dev/null
+++ b/tests/rendered/minimal/other
@@ -0,0 +1,4 @@
+auth required pam_deny.so
+account required pam_deny.so
+password required pam_deny.so
+session required pam_deny.so
diff --git a/tests/rendered/minimal/passwd b/tests/rendered/minimal/passwd
new file mode 100644
index 0000000..0bde2a3
--- /dev/null
+++ b/tests/rendered/minimal/passwd
@@ -0,0 +1,4 @@
+auth sufficient pam_rootok.so
+auth include system-auth
+account include system-auth
+password include system-auth
diff --git a/tests/rendered/minimal/su b/tests/rendered/minimal/su
new file mode 100644
index 0000000..a36b633
--- /dev/null
+++ b/tests/rendered/minimal/su
@@ -0,0 +1,8 @@
+auth sufficient pam_rootok.so
+auth required pam_wheel.so use_uid
+auth include system-auth
+account include system-auth
+password include system-auth
+session include system-auth
+session required pam_env.so
+session optional pam_xauth.so
diff --git a/tests/rendered/minimal/system-auth b/tests/rendered/minimal/system-auth
new file mode 100644
index 0000000..4c069c3
--- /dev/null
+++ b/tests/rendered/minimal/system-auth
@@ -0,0 +1,10 @@
+auth required pam_env.so
+auth requisite pam_faillock.so preauth
+auth [success=1 new_authtok_reqd=1 ignore=ignore default=bad] pam_unix.so try_first_pass
+auth [default=die] pam_faillock.so authfail
+account required pam_unix.so
+account required pam_faillock.so
+password required pam_unix.so try_first_pass md5 shadow
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tests/rendered/minimal/system-local-login b/tests/rendered/minimal/system-local-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/minimal/system-local-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/minimal/system-login b/tests/rendered/minimal/system-login
new file mode 100644
index 0000000..cb63f65
--- /dev/null
+++ b/tests/rendered/minimal/system-login
@@ -0,0 +1,11 @@
+auth required pam_shells.so
+auth required pam_nologin.so
+auth include system-auth
+account required pam_access.so
+account required pam_nologin.so
+account required pam_time.so
+account include system-auth
+password include system-auth
+session optional pam_loginuid.so
+session required pam_env.so envfile=/etc/profile.env
+session include system-auth
diff --git a/tests/rendered/minimal/system-remote-login b/tests/rendered/minimal/system-remote-login
new file mode 100644
index 0000000..2f415ed
--- /dev/null
+++ b/tests/rendered/minimal/system-remote-login
@@ -0,0 +1,4 @@
+auth include system-login
+account include system-login
+password include system-login
+session include system-login
diff --git a/tests/rendered/minimal/system-services b/tests/rendered/minimal/system-services
new file mode 100644
index 0000000..857363a
--- /dev/null
+++ b/tests/rendered/minimal/system-services
@@ -0,0 +1,6 @@
+auth sufficient pam_permit.so
+account include system-auth
+session optional pam_loginuid.so
+session required pam_limits.so
+session required pam_env.so
+session required pam_unix.so
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..818a012
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,18 @@
+[tox]
+min_version = 4.0
+skipsdist = true
+env_list = py3{10,11,12}-{default,minimal,custom}
+
+[testenv]
+description = check template rendering stability
+deps =
+ jinja2
+allowlist_externals = /usr/bin/diff
+commands =
+ python --version
+ default: python pambase.py
+ default: diff -Nru tests/rendered/default stack
+ minimal: python pambase.py --minimal
+ minimal: diff -Nru tests/rendered/minimal stack
+ custom: python pambase.py --elogind --nullok --passwdqc --sha512
+ custom: diff -Nru tests/rendered/custom stack