PolicyKit 0.5 Specification

David Zeuthen


           
          

Version 0.5


Table of Contents

1. Introduction
About
History and Prior Art
Defining the Problem
2. PolicyKit Model
Mechanims vs. Policy
Concepts
Theory of Operation
3. PolicyKit configuration
Declaring Actions
Beyond the Defaults

Chapter 1. Introduction

About

PolicyKit is a toolkit for defining and handling the policy that allows unprivileged processes to speak to privileged processes: It is a framework for centralizing the decision making process with respect to granting access to privileged operations for unprivileged applications. PolicyKit is specifically targeting applications in rich desktop environments on multi-user UNIX-like operating systems.

History and Prior Art

Traditionally UNIX-like operating systems have a clear distinction between ordinary unprivileged users and the almight and powerful super user 'root'. However, in order for a user to access and configure hardware additional privileges and rights are needed. Hitherto, this have been done in a number of often OS-specific ways. For example, Red Hat based systems usually grant access to devices to a user if, and only if, the user is logged in at a local console. In contrast, Debian-based systems often relies on group membership, e.g. users in the 'cdrom' group can access optical drives, users in the 'plugdev' group can mount removable media and so on.

In addition, access was not only granted to devices; Red Hat-based systems, for example, provides a mechanism to allow a user at a local system to run certain applications (such as the system-config-* family) as the super user provided they could authenticate as the super user (typically by entering the root password using a graphical utility). Other distributions rely on sudo (with various graphical frontends) to provide similar functionality. Both the pam-console and sudo approaches doesn't require applications to be modified.

Finally, some classes of software (such as HAL, NetworkManager and gnome-system-tools) utilizes IPC mechanism (typically D-Bus) to provide a very narrow and well-defined subset of privileged operations to unprivileged desktop applications. It varies what mechanism is used to deny users.

Defining the Problem

There's a couple of problems with the status quo

  • Mechanisms are coarsely grained: either you're at the console or you're not (pam_console). Either you're a member of a group or you're not (Debian). There is no easy way to specify that only a subset of privileged operations should be available for a given user (e.g. it's hard to express "it's fine to mount removable media; it's not fine to mount fixed media; it's not fine to change the timezone" in a coherent way).

  • The way most people use pam-console and sudo is fundamentally broken. Full-fledged GTK+ or Qt applications as the super user which means that millions of line of code (including code such as image loaders that historically have lots of security problems) runs privileged. This is in direct violation of the well-known "least privilege" principle. In addition, often applications look out of place because settings in such programs now read per-user settings from root's home directory.

  • UNIX group membership have always been problematic; if a user is a member of a group once, he can always become member of the group again (copy /bin/bash to $HOME; chown to group, set the setgid bit, done).

  • It is difficult for upstream projects (such as GNOME or KDE) to implement features that requires administrative privileges because most downstream consumers (e.g. operating systems) have different ways of implementing access control. As a result most of these features are punted to OS distributors who have their own code for doing the same thing e.g. setting the date/timezone etc.; there is no way for file sharing applications (such as gnome-user-share, Banshee, Rhythmbox) to punch a hole in the firewall.

  • Without a centralized framework, access control configuration is often scattered throughout the system which makes it hard for system administrators to grasp how to configure the system.

Chapter 2. PolicyKit Model

Mechanims vs. Policy

PolicyKit assumes a model where a program is split into two parts. One part, the Mechanism, runs privileged (with no user interface elements) and the other part, the policy agent, runs unprivileged. The two parts of the program are in different processes and communicate through some IPC mechanism such as pipes or the system message bus (D-Bus). In some instances the Mechanism can be considered part of the core OS and the policy agent part of the desktop stack.

A Mechanism should never trust any application that tries to use; it needs to carefully verify all data and requests passed to it from the application. This is the model employed by HAL and NetworkManager:

(TODO: diagram showing g-p-m, g-v-m, nm-applet, HAL and NM)

This model also applies to other security sensitive applications:

(TODO: diagram showing 1) gnome-screensaver / PAM-stack + /sbin/unix_chkpwd; and 2) gdm + gdm-greeter; 3) mount(8); 4) other setuid examples)

In general, such an architecture is thought of as secure as long as the Mechanism (and it's dependent libraries) have been verified to be secure.

Concepts

Typically the entities that a Mechanism cares about can be split into three groups:

  • Subject: the entity requesting the Action; ie. an unprivileged application. To make a decision about whether to carry out the Action, the Mechanism needs to know as much about the Subject as possible, e.g. UNIX user id, UNIX process id, possible security attributes (such as SELinux security context) and other data such as if the Subject is a participant in a local or remote desktop session, whether said desktop session is currently active and so forth.

  • Object: some canonical representation of the Object; some Objects represent tangible things such as a UNIX device file, other Objects can be more abstract and represent e.g. a network connection to a specific destination, a reference to the power management subsystem, a reference to a piece of software tracked by the native package manager.

  • Action: what the Subject is attempting to do to the Object; this depends of the nature of the Object and examples include mounting a block device, formatting a block device with a file system, establishing a dial-up connection to connect to private or public networks, putting the system into a suspended state, installing an unsigned piece of software, updating the system with signed software, changing the timezone, gaining access to a webcam and so forth.

(TODO: mention that libpolkit represents the Subject as either a Caller (e.g. a process) or a Session (e.g. a group of processes in a desktop session) and what the implications are here; e.g. for granting/removing ACL's on device nodes. etc. etc. etc.)

One way to think about a Mechanism is that the Mechanism is split into an enforcer and a decider component. When an application attempts to access the Mechanism, the enforcer component will only carry out the Action if the decider component (supplied with the appropriate input parameters about the Subject, Object and Action) says it's OK.

Theory of Operation

The core of PolicyKit is implemented as a shared library that Mechanisms can link to and use as the decider component. There's a small set of (extensible) data structures that establish a vocabulary for libpolkit and the Mechanism to describe the Subject and Action in question. The Mechanism should think about libpolkit as a black box; it's sole purpose is to answer whether a given Subject is permitted to do a specific Action. The answer, obviously, comes from a configuration source read by the library and maintained by the system administrator; see Chapter 3, PolicyKit configuration for details on PolicyKit configuration.

The answer from libpolkit is not limited to a boolean value; essentially the following values can be returned

  • Yes: It is ok for the Mechanism to carry out the Action requsted by the given Subject.

    No: The Mechanism should not carry out the Action requested by the given Subject.

    Require authentication: The Subject (e.g. the UI application) needs to ask the user to authenticate in order for the Mechanism to carry out this Action.

In addition,

  • Authentication can be specified (in the return value from libpolkit) as either user authentication (user puts in his own password) or super user authentication (user puts in the root password or a user in an administrator group authenticates).

    The authorization can be kept (this is also specified in the return value from libpolkit) either 1) indefinitely (e.g. it persists across reboots and different desktop sessions); 2) for the remainer of the desktop session the Subject is part of; or 3) confined to the process life-time of the Subject.

To facilitate the authentication step, there's a shared library called libpolkit-grant. Given an Action, this library uses a privileged helper (as in it's a setgid polkit application) to authenticate the user (using PAM) and upon successful authentication leave a cookie specifying that the given Action can be carried out. It is the presence and contents of this cookie that will allow libpolkit to return Yes when the Subject asks the Mechanism to carry out the Action again.

In order to keep the PolicyKit model reasonably simple, there is no representation of the Object. Instead, a Mechanism that cares about Objects (and many don't; for example, Mechanisms to change the timezone, punch a hole in the firewall or add a user all operate on a singleton Object: the system as a whole) must instead divide a given Action into multiple sub-Actions depending on the nature of the Object.

For example, consider a Mechanism for dial-up networking. Here, the Subject is a UI applet running in a desktop session, the Object is the phone number to dial and the Action is to establish the connection (another Action could be to hang-up an existing connection). Suppose that the Mechanism has a white-list of phone numbers that are trusted; this could simply be a directory /var/lib/dialup-helper/trusted-dialup.d where the system administrator can drop simple text or XML files with phone numbers that are considered safe to dial. If the phone number given by the client matches this white-list, the Mechanism chooses the Action to be dialup-connect-trusted. If it's not in the white-list, the Action will be dialup-connect-untrusted. Hence, depending on how PolicyKit is configured it may return different answers since these are different Actions; one sensible thing in a default desktop rollout would be to always allow the Action dialup-connect-trusted for local active sessions and always require authentication for the Action dialup-connect-untrusted.

When authentication is involved, the interaction diagram for having a Mechanism carry out an Action on behalf of a Subject looks roughly like this

TODO: include diagram

Chapter 3. PolicyKit configuration

Declaring Actions

A Mechanism needs to declare what Actions it supports. This is achieved by dropping one or more XML files with the suffix .policy into the /usr/share/PolicyKit/policy directory. An example:

      
<policyconfig>
  <group id="polkit-gnome-examples">
    <description>PolicyKit examples for PolicyKit-gnome</description>

    <policy id="polkit-gnome-examples-frobnicate">
      <description>Let the example Frobnicate</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_self</allow_active>
      </defaults>
    </policy>

    <policy id="polkit-gnome-examples-tweak">
      <description>Let the example Tweak</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin</allow_active>
      </defaults>
    </policy>

    <policy id="polkit-gnome-examples-twiddle">
      <description>Twiddle</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin_keep_always</allow_active>
      </defaults>
    </policy>

    <policy id="polkit-gnome-examples-punch">
      <description>Punch</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_self_keep_session</allow_active>
      </defaults>
    </policy>

  </group>
</policyconfig> 

    

Here's a more real-world example from HAL:

      
<policyconfig> 
  <group id="hal-storage">
    <description>Storage Drives and Media</description>

    <policy id="hal-storage-mount-fixed">
      <description>Mount file systems from internal drives</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin_keep_always</allow_active>
      </defaults>
    </policy>

    <policy id="hal-storage-unmount-others">
      <description>Unmount file systems mounted by other users</description>
      <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin_keep_always</allow_active>
      </defaults>
    </policy>

  </group>
</policyconfig> 

    

The policy declaration includes:

  • Action Identifier: This identifies the action - it needs to be namespaced accordingly using some unique name of the mechanism. This could be e.g. dialup-connect-trusted or dialup-connect-untrusted.

  • Defaults: The allow_inactive and allow_active specify the default answer that libpolkit will return for respectively inactive and active sessions. See below for valid values and their meaning.

  • Grouping: This is purely for organizational purposes. The group identifier needs to be properly namespaced as well.

  • Textual descriptions: Simply included for convenience and organizational purposes (TODO: think about i18n).

The following values for the defaults are

  • no

  • auth_self

  • auth_self_keep_session

  • auth_self_keep_always

  • auth_admin

  • auth_admin_keep_session

  • auth_admin_keep_always

  • yes

The main point here is that individual upstream software projects can provide sensible defaults, e.g. it's sensible for the example with a dial-up mechanism to configure the dialup-connect-trusted Action to return yes for local active sessions and the Action dialup-connect-untrusted to perhaps return auth_admin_keep_session. See the section called “Beyond the Defaults” for how individual machines and sites can customize this.

The polkit-list-actions(1) tool will list all the Actions known to libpolkit in a convenient format.

Beyond the Defaults

System administrators and sites can tweak what answer libpolkit returns depending on the Action and Subject and other factors through the configuration file /etc/PolicyKit/PolicyKit.conf. The configuration file format, along with examples, is described in the associated manual page of the same name. Note that this file is not supposed to be modified by individual packages, it is solely the responsibility of the system administrator to make changes to this file.