Group based Permissions using polkit
Access things like NetworkManager based on UNIX groups.
Table of Contents
What and why?
I'm the kind of creature that really likes NetworkManager and avoids systemd when possible.
The problem arises that, when one isn't using (e)logind things like being able to configure networks don't work anymore. Reason being that polkit is configured to only allow these actions for logged in sessions, but nothing told it that a session is active.
Luckily those rules are not set in stone and one can reconfigure polkit however they like.
Note: NetworkManager only supports polkit for configuring who can do what. This is okay because it is supposed to manage networks, not permissions.
For my purposes I want to be able to send basic commands to NetworkManager because I'm in the wheel
(aka. sudo
) group, independent of me being logged in.
Update on 2024-04-18: Previously I forgot to include the org.freedesktop.NetworkManager.settings.modify.system
action which prevented connecting to new wireless networks.
Understanding polkit
This was the first time I messed with polkit which is very well documented in the polkit(8) manpage.
Polkit is a service with its only task being to answer one question
Is subject allowed to do action?
The subject is roughly equivalent to a user.
The action is a more or less rough description of what the subject wants to do identified by an id.
Actions are described by XML-Files in /usr/share/polkit-1/actions/
. These contain localised names, icon-names and some sane default permissions for each action.
In addition to actions and the default permissions, polkit supports rules written in JavaScript. These live in files in /etc/polkit-1/rules.d/
.
Note: There is also /usr/share/polkit-1/rules.d/
but that one is intended for packages. As an admin /etc
is the preferred place.
NetworkManager rules
Before writing the rule I need the action ids that are used to configure NetworkManager. These can be found by searching the /usr/share/polkit-1/actions/org.freedesktop.NetworkManager.policy
file for all rules that work without any extra authentication given an active session.
The results are:
org.freedesktop.NetworkManager.enable-disable-network
org.freedesktop.NetworkManager.enable-disable-wifi
org.freedesktop.NetworkManager.enable-disable-wimax
org.freedesktop.NetworkManager.enable-disable-wwan
org.freedesktop.NetworkManager.network-control
org.freedesktop.NetworkManager.settings.modify.own
org.freedesktop.NetworkManager.settings.modify.system
org.freedesktop.NetworkManager.wifi.scan
org.freedesktop.NetworkManager.wifi.share.open
org.freedesktop.NetworkManager.wifi.share.protected
Note on inactive sessions: Even if an action is allowed for inactive sessions it isn't allowed when that session state can't be determined which is the case when (e)logind is missing.
Polkit debug mode
To save you some frustration with debugging: Polkit has a debug mode which is probably turned off when launched through your service manager of choice using the --no-debug
option.
To get the debug output.
- Stop the
polkit
service - Run
/usr/lib/polkit-1/polkitd
as root in a terminal - Start the service again when done with debugging
Note: Polkit will drop privileges automatically after setting itself up.
Adding a rule
According to the manual I should be able to just place a .rules
file in /etc/polkit/rules.d/
and polkit will pick it up automatically. If you have polkit in debug mode you'll even get feedback whether your rules are valid JavaScript or not.
For the NetworkManager scenario my script adds a rule function that first checks if the action id is in an array of allowed actions, then checks if the subject is in the wheel
group and if so returns that the action is allowed.
If the rule doesn't return a result polkit will fall back to other rules and eventually the defaults.
Translated to JavaScript the result is the following.
Other Things polkit Rules could do
By testing for an action id prefix and (non-)membership of a group you could also deny access to a service by returning polkit.Result.NO
.
Polkit can also call external commands and make a decision based on success or failure of a command.
Bye
I hope that was a useful bit of information about a thing that mostly stays out of the way and comes with an extra bit of suprise when it doesn't work.