Skip to content

Commit

Permalink
Execute power-button-shutdown with user
Browse files Browse the repository at this point in the history
Stop executing power-button-shutdown service as root, but rather as a
specific user. Give the possibility to the user to shutdown the computer
using a polkit rule.
  • Loading branch information
guyonvarch committed Apr 30, 2024
1 parent 1b347ab commit 9578319
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
47 changes: 39 additions & 8 deletions application/power-management/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

let

user = "power-button-shutdown";
group = "power-button-shutdown";

power-button-shutdown = pkgs.stdenv.mkDerivation {
name = "power-button-shutdown";
propagatedBuildInputs = [
Expand All @@ -15,34 +18,62 @@ let

in {

# Ignore system control keys that do not make sense for kiosk applications
# Ignore system control keys that do not make sense for kiosk applications.
# Ignore power key as well, but set up a systemd service shutting down the
# computer on Power Button key press.
services.logind.extraConfig = ''
HandleSuspendKey=ignore
HandlePowerKey=ignore
HandleRebootKey=ignore
HandleSuspendKey=ignore
HandleHibernateKey=ignore
HandlePowerKey=ignore
HandlePowerKeyLongPress=poweroff
HandleRebootKeyLongPress=poweroff
HandleSuspendKeyLongPress=poweroff
HandleHibernateKeyLongPress=poweroff
'';

users = {
users.${user} = {
description = "User executing power-button-shutdown.service";
group = group;
createHome = false;
isSystemUser = true;
};
groups.${group} = {};
};

hardware.uinput.enable = lib.mkDefault true;

# Allow user of power-button-shutdown.service to shutdown the service
security.polkit = {
enable = true;
extraConfig = ''
polkit.addRule(function(action, subject) {
if (subject.user == "${user}" &&
subject.isInGroup("${group}") &&
action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "poweroff.target" &&
action.lookup("verb") == "start") {
return polkit.Result.YES;
}
})
'';
};

systemd.services.power-button-shutdown = {
enable = true;
description = "Detect power off key press, by power button device only, then shutdown computer";
description = "Detect Power Button key presses, by Power Button device only and not remote controls, then shutdown computer";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${power-button-shutdown}/bin/power-button-shutdown";
Restart = "always";

# Access to input devices without being root
# DynamicUser = true; # Currently prevent to shutdown the system
User = user;
Group = group;
SupplementaryGroups = with config.users.groups; [ input.name uinput.name ];

# Hardening, see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/hardware/kanata.nix#L117
# Not using DeviceAllow and DevicePolicy, as I couldn’t get access to device list with that.
# Hardening, see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/hardware/kanata.nix#L117 for inspiration.
# Not using DeviceAllow and DevicePolicy, as this prevent listing devices otherwise.
CapabilityBoundingSet = [ "" ];
IPAddressDeny = [ "any" ];
LockPersonality = true;
Expand Down
8 changes: 4 additions & 4 deletions application/power-management/power-button-shutdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@

power_off_device = next((d for d in devices if d.name == 'Power Button'), None)
if power_off_device is None:
logging.error(f'Power Off device not found')
logging.error(f'Power Button device not found')
sys.exit(1)

logging.info(f'Listenning to Power Off on device {power_off_device.path}')
logging.info(f'Listenning to Power Button on device {power_off_device.path}')
for event in power_off_device.read_loop():
if event.type == evdev.ecodes.EV_KEY and evdev.ecodes.KEY[event.code] == 'KEY_POWER' and event.value:
logging.info('KEY_POWER detected on Power Off device, shutting down')
os.system('shutdown now')
logging.info('KEY_POWER detected on Power Button device, shutting down')
os.system('systemctl start poweroff.target')

0 comments on commit 9578319

Please sign in to comment.