1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.physlock;
9in
10
11{
12
13 ###### interface
14
15 options = {
16
17 services.physlock = {
18
19 enable = lib.mkOption {
20 type = lib.types.bool;
21 default = false;
22 description = ''
23 Whether to enable the {command}`physlock` screen locking mechanism.
24
25 Enable this and then run {command}`systemctl start physlock`
26 to securely lock the screen.
27
28 This will switch to a new virtual terminal, turn off console
29 switching and disable SysRq mechanism (when
30 {option}`services.physlock.disableSysRq` is set)
31 until the root or user password is given.
32 '';
33 };
34
35 allowAnyUser = lib.mkOption {
36 type = lib.types.bool;
37 default = false;
38 description = ''
39 Whether to allow any user to lock the screen. This will install a
40 setuid wrapper to allow any user to start physlock as root, which
41 is a minor security risk. Call the physlock binary to use this instead
42 of using the systemd service.
43 '';
44 };
45
46 disableSysRq = lib.mkOption {
47 type = lib.types.bool;
48 default = true;
49 description = ''
50 Whether to disable SysRq when locked with physlock.
51 '';
52 };
53
54 lockMessage = lib.mkOption {
55 type = lib.types.str;
56 default = "";
57 description = ''
58 Message to show on physlock login terminal.
59 '';
60 };
61
62 muteKernelMessages = lib.mkOption {
63 type = lib.types.bool;
64 default = false;
65 description = ''
66 Disable kernel messages on console while physlock is running.
67 '';
68 };
69
70 lockOn = {
71
72 suspend = lib.mkOption {
73 type = lib.types.bool;
74 default = true;
75 description = ''
76 Whether to lock screen with physlock just before suspend.
77 '';
78 };
79
80 hibernate = lib.mkOption {
81 type = lib.types.bool;
82 default = true;
83 description = ''
84 Whether to lock screen with physlock just before hibernate.
85 '';
86 };
87
88 extraTargets = lib.mkOption {
89 type = lib.types.listOf lib.types.str;
90 default = [ ];
91 example = [ "display-manager.service" ];
92 description = ''
93 Other targets to lock the screen just before.
94
95 Useful if you want to e.g. both autologin to X11 so that
96 your {file}`~/.xsession` gets executed and
97 still to have the screen locked so that the system can be
98 booted relatively unattended.
99 '';
100 };
101
102 };
103
104 };
105
106 };
107
108 ###### implementation
109
110 config = lib.mkIf cfg.enable (
111 lib.mkMerge [
112 {
113
114 # for physlock -l and physlock -L
115 environment.systemPackages = [ pkgs.physlock ];
116
117 systemd.services.physlock = {
118 enable = true;
119 documentation = [ "man:physlock(1)" ];
120 description = "Physlock";
121 wantedBy =
122 lib.optional cfg.lockOn.suspend "suspend.target"
123 ++ lib.optional cfg.lockOn.hibernate "hibernate.target"
124 ++ cfg.lockOn.extraTargets;
125 before =
126 lib.optional cfg.lockOn.suspend "systemd-suspend.service"
127 ++ lib.optional cfg.lockOn.hibernate "systemd-hibernate.service"
128 ++ lib.optional (
129 cfg.lockOn.hibernate || cfg.lockOn.suspend
130 ) "systemd-suspend-then-hibernate.service"
131 ++ cfg.lockOn.extraTargets;
132 serviceConfig = {
133 Type = "forking";
134 ExecStart = "${pkgs.physlock}/bin/physlock -d${lib.optionalString cfg.muteKernelMessages "m"}${lib.optionalString cfg.disableSysRq "s"}${
135 lib.optionalString (cfg.lockMessage != "") " -p \"${cfg.lockMessage}\""
136 }";
137 };
138 };
139
140 security.pam.services.physlock = { };
141
142 }
143
144 (lib.mkIf cfg.allowAnyUser {
145
146 security.wrappers.physlock = {
147 setuid = true;
148 owner = "root";
149 group = "root";
150 source = "${pkgs.physlock}/bin/physlock";
151 };
152
153 })
154 ]
155 );
156
157}