diff --git a/flake.nix b/flake.nix index e48769927..1a8c1d659 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,6 @@ fileset = lib.fileset.difference ./. (lib.fileset.unions [ ./.github ./.gitignore - ./.zed ./flake.nix ./flake.lock ./nix diff --git a/nix/heimdal/0001-Define-HAVE_DB_185_H.patch b/nix/heimdal/0001-Define-HAVE_DB_185_H.patch deleted file mode 100644 index f6e2c428c..000000000 --- a/nix/heimdal/0001-Define-HAVE_DB_185_H.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 08d719e96214f648ae95043acc308deca36e1f7a Mon Sep 17 00:00:00 2001 -From: Ihar Hrachyshka -Date: Tue, 15 Oct 2024 13:52:39 -0400 -Subject: [PATCH] Define HAVE_DB_185_H - ---- - cf/db.m4 | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/cf/db.m4 b/cf/db.m4 -index c0b4510b6..c95a9dee9 100644 ---- a/cf/db.m4 -+++ b/cf/db.m4 -@@ -57,6 +57,9 @@ AS_IF([test "x$with_berkeley_db" != xno], - db.h \ - ])]) - -+dnl detect if compat db_185.h is present -+AC_CHECK_HEADERS([db_185.h]) -+ - dnl db_create is used by db3 and db4 and db5 and db6 - - AC_FIND_FUNC_NO_LIBS(db_create, [$dbheader] db-6 db-5 db4 db3 db, [ --- -2.46.0 - diff --git a/nix/heimdal/package.nix b/nix/heimdal/package.nix index 6a5d83b59..2402937d1 100644 --- a/nix/heimdal/package.nix +++ b/nix/heimdal/package.nix @@ -22,6 +22,7 @@ pam, libmicrohttpd, cjson, + systemdLibs, CoreFoundation, Security, @@ -43,6 +44,7 @@ withOpenLDAPAsHDBModule ? false, withOpenSSL ? true, withSQLite3 ? true, + withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemdLibs, }: assert lib.assertMsg (withOpenLDAPAsHDBModule -> withOpenLDAP) '' @@ -89,7 +91,8 @@ stdenv.mkDerivation { ++ lib.optionals (withMicroHTTPD) [ libmicrohttpd ] ++ lib.optionals (withOpenLDAP) [ openldap ] ++ lib.optionals (withOpenSSL) [ openssl ] - ++ lib.optionals (withSQLite3) [ sqlite ]; + ++ lib.optionals (withSQLite3) [ sqlite ] + ++ lib.optionals (withSystemd) [ systemdLibs ]; doCheck = true; nativeCheckInputs = [ @@ -125,13 +128,11 @@ stdenv.mkDerivation { ] ++ lib.optionals (withSQLite3) [ "--with-sqlite3=${sqlite.dev}" + ] + ++ lib.optionals (withSystemd) [ + "--with-systemd" ]; - patches = [ - # Proposed @ https://github.com/heimdal/heimdal/pull/1264 - ./0001-Define-HAVE_DB_185_H.patch - ]; - # (check-ldap) slapd resides within ${openldap}/libexec, # which is not part of $PATH by default. # (check-ldap) prepending ${openldap}/bin to the path to avoid diff --git a/nix/module/default.nix b/nix/module/default.nix index f132a1530..3d4d8b6f4 100644 --- a/nix/module/default.nix +++ b/nix/module/default.nix @@ -30,6 +30,10 @@ in services.kerberos_server = { enable = lib.mkEnableOption "the kerberos authentication server"; + enableSocketActivation = lib.mkEnableOption '' + Systemd socket activation for the kerberos daemons. + ''; + settings = mkOption { type = format.type; description = '' @@ -59,7 +63,7 @@ in systemd.slices.system-kerberos-server = { }; systemd.targets.kerberos-server = { - wantedBy = [ "multi-user.target" ]; + wantedBy = lib.mkIf (!cfg.enableSocketActivation) [ "multi-user.target" ]; }; }; diff --git a/nix/module/heimdal.nix b/nix/module/heimdal.nix index 0bc9a96d1..6db06f767 100644 --- a/nix/module/heimdal.nix +++ b/nix/module/heimdal.nix @@ -10,6 +10,10 @@ let cfg = config.services.kerberos_server; package = config.security.krb5.package; + socketActivation = cfg.enableSocketActivation; + + serviceWantedBy = [ "kerberos-server.target" ]; + aclConfigs = lib.pipe cfg.settings.realms [ (mapAttrs ( name: @@ -69,11 +73,14 @@ in systemd.services.kadmind = { description = "Kerberos Administration Daemon"; partOf = [ "kerberos-server.target" ]; - wantedBy = [ "kerberos-server.target" ]; + wantedBy = serviceWantedBy; serviceConfig = { + Type = "notify"; ExecStart = "${package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; Slice = "system-kerberos-server.slice"; StateDirectory = "heimdal"; + + PrivateNetwork = socketActivation; }; restartTriggers = [ kdcConfFile ]; }; @@ -81,11 +88,13 @@ in systemd.services.kdc = { description = "Key Distribution Center daemon"; partOf = [ "kerberos-server.target" ]; - wantedBy = [ "kerberos-server.target" ]; + wantedBy = serviceWantedBy; serviceConfig = { + Type = "notify"; ExecStart = "${package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; Slice = "system-kerberos-server.slice"; StateDirectory = "heimdal"; + PrivateNetwork = socketActivation; }; restartTriggers = [ kdcConfFile ]; }; @@ -93,13 +102,63 @@ in systemd.services.kpasswdd = { description = "Kerberos Password Changing daemon"; partOf = [ "kerberos-server.target" ]; - wantedBy = [ "kerberos-server.target" ]; + wantedBy = serviceWantedBy; serviceConfig = { + Type = "notify"; ExecStart = "${package}/libexec/kpasswdd"; Slice = "system-kerberos-server.slice"; StateDirectory = "heimdal"; + PrivateNetwork = socketActivation; }; restartTriggers = [ kdcConfFile ]; }; + + systemd.sockets = lib.mkIf socketActivation { + kadmind = { + description = "Kerberos Administration Daemon socket"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ + "sockets.target" + "kerberos-server.target" + ]; + socketConfig = { + ListenStream = 749; + FileDescriptorName = "kadmind"; + Accept = false; + Slice = "system-kerberos-server.slice"; + }; + }; + + kdc = { + description = "Key Distribution Center daemon socket"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ + "sockets.target" + "kerberos-server.target" + ]; + socketConfig = { + ListenStream = 88; + ListenDatagram = 88; + FileDescriptorName = "kdc"; + Accept = false; + Slice = "system-kerberos-server.slice"; + }; + }; + + kpasswdd = { + description = "Kerberos Password Changing daemon socket"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ + "sockets.target" + "kerberos-server.target" + ]; + socketConfig = { + ListenDatagram = 464; + FileDescriptorName = "kpasswdd"; + Accept = false; + Slice = "system-kerberos-server.slice"; + }; + }; + }; }; } diff --git a/nix/nixosTest.nix b/nix/nixosTest.nix index 08ab8da8e..72f71da43 100644 --- a/nix/nixosTest.nix +++ b/nix/nixosTest.nix @@ -84,6 +84,10 @@ }; }; }; + + specialisation.socketActivation.configuration = { + services.kerberos_server.enableSocketActivation = true; + }; }; client = @@ -289,32 +293,58 @@ if not "host/client.foo.bar" in ktutil_list: exit(1) - with subtest("Client: kinit alice"): - kinit(client, "alice", alice_krb_pw) + def kerberos_auth_flow(mode): + global alice_krb_pw, alice_old_krb_pw - with subtest("Client: kpasswd alice"): - alice_old_krb_pw = alice_krb_pw - alice_krb_pw = random_password() - output = client.succeed(f"${lib.getExe kpasswd} {alice_old_krb_pw} {alice_krb_pw}") - assert "Success : Password changed" in output + with subtest(f"[{mode}] Client: kinit alice"): + kinit(client, "alice", alice_krb_pw) - with subtest("Client: kadmin get bob"): - output = kadmin(client, "get bob") - print(output) - assert "Principal: bob@FOO.BAR" in output + with subtest(f"[{mode}] Client: kpasswd alice"): + alice_old_krb_pw = alice_krb_pw + alice_krb_pw = random_password() + output = client.succeed(f"${lib.getExe kpasswd} {alice_old_krb_pw} {alice_krb_pw}") + assert "Success : Password changed" in output - with subtest("Server: kinit alice"): - kinit(server, "alice", alice_krb_pw) + with subtest(f"[{mode}] Client: kadmin get bob"): + output = kadmin(client, "get bob") + assert "Principal: bob@FOO.BAR" in output - with subtest("Server: kpasswd alice"): - alice_old_krb_pw = alice_krb_pw - alice_krb_pw = random_password() - output = server.succeed(f"${lib.getExe kpasswd} {alice_old_krb_pw} {alice_krb_pw}") - assert "Success : Password changed" in output + with subtest(f"[{mode}] Server: kinit alice"): + kinit(server, "alice", alice_krb_pw) - with subtest("Server: kadmin get bob"): - output = kadmin(server, "get bob") - assert "Principal: bob@FOO.BAR" in output + with subtest(f"[{mode}] Server: kpasswd alice"): + alice_old_krb_pw = alice_krb_pw + alice_krb_pw = random_password() + output = server.succeed(f"${lib.getExe kpasswd} {alice_old_krb_pw} {alice_krb_pw}") + assert "Success : Password changed" in output + + with subtest(f"[{mode}] Server: kadmin get bob"): + output = kadmin(server, "get bob") + assert "Principal: bob@FOO.BAR" in output + + # First run against the default, self-binding daemons. + kerberos_auth_flow("bind") + + with subtest("Server: daemons publish an sd_notify status line"): + for svc in ["kdc", "kadmind", "kpasswdd"]: + status = server.succeed(f"systemctl show {svc}.service -p StatusText") + assert "Serving" in status, \ + f"{svc}.service has no sd_notify status: {status}" + + server.succeed("systemctl stop kadmind.service kdc.service kpasswdd.service") + server.succeed( + "/run/current-system/specialisation/socketActivation/bin/switch-to-configuration test" + ) + for unit in ["kadmind.socket", "kdc.socket", "kpasswdd.socket"]: + server.wait_for_unit(unit) + + kerberos_auth_flow("socket-activation") + + with subtest("Server: daemons are wired to their activation sockets"): + for svc in ["kdc", "kadmind", "kpasswdd"]: + triggered = server.succeed(f"systemctl show {svc}.service -p TriggeredBy") + assert f"{svc}.socket" in triggered, \ + f"{svc}.service not triggered by {svc}.socket: {triggered}" ''; meta.maintainers = pkgs.heimdal.meta.maintainers; diff --git a/nix/shell.nix b/nix/shell.nix index 0db62bec6..758fb0823 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -31,6 +31,7 @@ pkgs.mkShell { openldap openssl sqlite + systemd ]; env = {