1. Introduction

The polkitd system daemon is a way to control authentication and authorization of actions. In short, Polkit verifies the identity of users before they run actions.

In this tutorial, we’ll explore polkitd and what feedback it provides while operating. First, we go over Polkit in general. After that, we check common status messages generated by polkitd and explain their meaning.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15. It should work in most POSIX-compliant environments unless otherwise specified.

2. Polkit and polkitd

As an administrator, having control over the users of a given system is imperative. So much so that there are different mechanisms at the kernel level to handle privileges:

Despite such facilities, we might often require more fine-grained rules for granting or denying access to given resources. Thus, polkitd fills this spot between the kernel and userspace in the form of a service that others can call upon to perform privileged actions on their behalf. In fact, Polkit uses the DBus system message bus.

2.1. Installation

To install Polkit, we can use the polkitd package with apt:

$ apt-get install polkitd

Once installed, we should have polkitd running in the background:

$ pgrep --list-full polkitd
666 /usr/libexec/polkitd --no-debug

In this case, we use the –list-full switch of pgrep to verify that Polkit is running in the background.

2.2. Authentication Agents

In the context of Polkit, an authentication agent is a process that receives requests and ensures that each requesting user is who they claim to be. Due to the way such an agent functions, there are different implementations when it comes to the command-line terminal and a graphical user interface (GUI).

Most major desktop environments have an authentication agent built-in. Other desktops either have separate packages or are compatible with a major desktop environment.

In our case, we’re going to look at the default textual authentication agent.

2.3. pkttyagent

When no other agent is available, pkttyagent is the fallback Polkit systems use. While it doesn’t provide the convenience of a GUI, it’s fairly universal.

To start pkttyagent for a given subject, we use the –process or –system-bus-name options. If neither is specified, the parent process is used as the subject:

$ pkttyagent &

We background the process via the & ampersand operator to ensure its continued operation. In practice, if we skip any of the switches, the subject of the agent becomes the current shell.

Once it’s attached, we can make requests to pkttyagent.

2.4. Rules and Actions

The main purpose of Polkit is to have rules that regulate how we authenticate and authorize given actions.

To begin with, two directories contain JavaScript .rules files:

  • /usr/share/polkit-1/rules.d/
  • /etc/polkit-1/rules.d/

Rules specify users and may refer to actions, as defined in XML .policy files under /usr/share/polkit-1/actions/:

$ ls /usr/share/polkit-1/actions/
io.snapcraft.snapd.policy                   org.freedesktop.network1.policy
org.dpkg.pkexec.update-alternatives.policy  org.freedesktop.policykit.policy
org.freedesktop.color.policy                org.freedesktop.resolve1.policy
org.freedesktop.hostname1.policy            org.freedesktop.systemd1.policy
org.freedesktop.locale1.policy              org.freedesktop.timedate1.policy
org.freedesktop.login1.policy               org.freedesktop.UDisks2.policy

For completeness, let’s see a sample action file:

$ cat /usr/share/polkit-1/actions/io.snapcraft.snapd.policy
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
 "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>

  <vendor>Snapcraft</vendor>
  <vendor_url>http://snapcraft.io</vendor_url>

  <action id="io.snapcraft.snapd.login">
    <description gettext-domain="snappy">Authenticate on snap daemon</description>
    <message gettext-domain="snappy">Authorization is required to authenticate on the snap daemon</message>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin_keep</allow_active>
    </defaults>
  </action>

  <action id="io.snapcraft.snapd.manage">
    <description gettext-domain="snappy">Install, update, or remove packages</description>
    <message gettext-domain="snappy">Authentication is required to install, update, or remove packages</message>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin_keep</allow_active>
    </defaults>
  </action>

  <action id="io.snapcraft.snapd.manage-interfaces">
    <description gettext-domain="snappy">Connect, disconnect interfaces</description>
    <message gettext-domain="snappy">Authentication is required to connect or disconnect interfaces</message>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin_keep</allow_active>
    </defaults>
  </action>

</policyconfig>

Actions are based on the current packages and future installations within the system. Further, each action contains default permissions, which we can override but not within the .policy files.

Now, let’s take a look at a basic .rules file:

$ cat /etc/polkit-1/rules.d/xgapp.rules
polkit.addRule(function(action, subject) {
  if (action.id == "io.snapcraft.snapd.policy" && subject.isInGroup("hex")) {
    return polkit.Result.YES;
  }
});

In essence, the main function is addRule(), called after checking authorization. Here, we check for a given action (io.snapcraft.snapd.policy) and the membership of a given group (hex) before allowing the process to go forward. In short, we can’t use snapd unless we authenticate as a user from the hex group.

2.5. Check Agent

To ensure we have a working Polkit system, we can combine the previous points with the pkcheck command:

$ pkcheck --process $$ --action-id io.snapcraft.snapd.manage --allow-user-interaction
Authorization requires authentication but no agent is available.

In this case, pkcheck tries to run an action by its action-id for the current shell as identified by its $$ process identifier (PID). Importantly, the current user doesn’t have permission for this action, so we need to –allow-user-interaction with an agent to continue. However, Polkit informs us that the pkttyagent isn’t running.

So, let’s run an agent and retry:

$ pkttyagent &
[1] 666
$ pkcheck --process $$ --action-id io.snapcraft.snapd.manage --allow-user-interaction
$ echo $?
0

At this point, we encounter no issues with the command or its exit status. Yet, problems can sometimes remain hidden.

3. Polkit Logging and Agent Registration

Polkit stores information in two main logs:

  • /var/log/auth.log authentication log
  • /var/log/secure login session log on Fedora and RedHat distributions

For example, let’s explore the entry related to agent registration:

$ pkttyagent &
[1] 666
$ tail -1 /var/log/auth.log
2023-09-09T09:00:00.411102-01:00 xost polkitd[6660]: Registered Authentication Agent for unix-process:6670:8661022 (system bus name :1.55 [pkttyagent], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)

Here, we use tail to get the last 1 line of the log after running pkttyagent in the background as process 666. From the entry, we can get the PID of both polkitd (6660) and the current shell session (6670).

Of course, we might sometimes see Polkit-related messages that look like errors:

$ kill -KILL 666
$ tail -1 /var/log/auth.log
2023-09-09T09:00:09.862999-01:00 xost polkitd[6660]: Unregistered Authentication Agent for unix-process:6670:8776555 (system bus name :1.57, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8) (disconnected from bus)

In this example, we kill the agent process and check the last log entry. As expected, polkitd notes that the agent has been Unregistered. Outside the context of our other actions, we might see this line as an error. Yet, it’s a regular status message as long as we know why the agent stopped.

4. Conclusion

In this article, we looked at the Polkit mechanism to regulate, authenticate, and authorize user access.

In conclusion, polkitd is a secure and sophisticated way to ensure granular control and thus may provide a lot of feedback to an administrator.