1{ pkgs, lib, ... }:
2
3# Based on
4# - https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html
5# - https://manpages.debian.org/unstable/heimdal-docs/krb5.conf.5heimdal.en.html
6
7let
8 inherit (lib) boolToString concatMapStringsSep concatStringsSep filter
9 isAttrs isBool isList mapAttrsToList mkOption singleton splitString;
10 inherit (lib.types) attrsOf bool coercedTo either int listOf oneOf path
11 str submodule;
12in
13{ }: {
14 type = let
15 section = attrsOf relation;
16 relation = either (attrsOf value) value;
17 value = either (listOf atom) atom;
18 atom = oneOf [int str bool];
19 in submodule {
20 freeformType = attrsOf section;
21 options = {
22 include = mkOption {
23 default = [ ];
24 description = ''
25 Files to include in the Kerberos configuration.
26 '';
27 type = coercedTo path singleton (listOf path);
28 };
29 includedir = mkOption {
30 default = [ ];
31 description = ''
32 Directories containing files to include in the Kerberos configuration.
33 '';
34 type = coercedTo path singleton (listOf path);
35 };
36 module = mkOption {
37 default = [ ];
38 description = ''
39 Modules to obtain Kerberos configuration from.
40 '';
41 type = coercedTo path singleton (listOf path);
42 };
43 };
44 };
45
46 generate = let
47 indent = str: concatMapStringsSep "\n" (line: " " + line) (splitString "\n" str);
48
49 formatToplevel = args @ {
50 include ? [ ],
51 includedir ? [ ],
52 module ? [ ],
53 ...
54 }: let
55 sections = removeAttrs args [ "include" "includedir" "module" ];
56 in concatStringsSep "\n" (filter (x: x != "") [
57 (concatStringsSep "\n" (mapAttrsToList formatSection sections))
58 (concatMapStringsSep "\n" (m: "module ${m}") module)
59 (concatMapStringsSep "\n" (i: "include ${i}") include)
60 (concatMapStringsSep "\n" (i: "includedir ${i}") includedir)
61 ]);
62
63 formatSection = name: section: ''
64 [${name}]
65 ${indent (concatStringsSep "\n" (mapAttrsToList formatRelation section))}
66 '';
67
68 formatRelation = name: relation:
69 if isAttrs relation
70 then ''
71 ${name} = {
72 ${indent (concatStringsSep "\n" (mapAttrsToList formatValue relation))}
73 }''
74 else formatValue name relation;
75
76 formatValue = name: value:
77 if isList value
78 then concatMapStringsSep "\n" (formatAtom name) value
79 else formatAtom name value;
80
81 formatAtom = name: atom: let
82 v = if isBool atom then boolToString atom else toString atom;
83 in "${name} = ${v}";
84 in
85 name: value: pkgs.writeText name ''
86 ${formatToplevel value}
87 '';
88}