Skip to content

Commit

Permalink
fix: image urls
Browse files Browse the repository at this point in the history
  • Loading branch information
osmancoskun committed May 30, 2024
1 parent e98d76e commit e7c301c
Showing 1 changed file with 51 additions and 32 deletions.
83 changes: 51 additions & 32 deletions src/routes/wiki/development/linux/polkit.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,38 @@

# Using Polkit to Perform Root Privilege Actions in a GTK Application Without Asking for Root Password

In many Linux distributions, performing administrative tasks typically requires root privileges.
In many Linux distributions, performing administrative tasks typically requires root privileges.

**However, constantly entering the root password can be cumbersome, especially for repetitive tasks within a graphical application. Another case is that an unprivileged user should be able to do something a privileged user can do but without entering a root password.**
**However, constantly entering the root password can be cumbersome, especially for repetitive tasks within a graphical application. Another case is that an unprivileged user should be able to do something a privileged user can do but without entering a root password.**

Polkit (PolicyKit) is a toolkit for defining and handling authorizations, providing a way to centralize the management of system-wide privileges. By configuring Polkit correctly, we can allow certain actions to be performed without requiring the user to enter the root password every time.

> This blog post will guide you through the process of using Polkit to perform an action that requires root privileges in a GTK application by clicking a button, without prompting the user for the root password.
## Prerequisites

Before we begin, ensure that you have the following:

- A Linux distribution with Polkit installed(most of them already have).
- Basic knowledge of creating Python + GTK applications.
- Root access to your system to add new Polkit configurations.

## Step 1: Understand Polkit and its Configuration

Polkit operates by defining actions that correspond to specific system-wide privileges.

You can define a policy in here:
- XML Policy *(.policy)*: `/usr/share/polkit-1/actions/`

- XML Policy _(.policy)_: `/usr/share/polkit-1/actions/`

And you can define additional rules for a policy or policies here:
- JavaScript Rules *(.rules)*: `/usr/share/polkit-1/rules.d/` ***(new way)***
- Local Authority Rules *(.pkla)*: `/etc/polkit-1/localauthority/50-local.d/` ***(old way)***

- JavaScript Rules _(.rules)_: `/usr/share/polkit-1/rules.d/` **_(new way)_**
- Local Authority Rules _(.pkla)_: `/etc/polkit-1/localauthority/50-local.d/` **_(old way)_**

## Step 2: Define a Custom Action (XML)
First, define a custom action for your application. Create an XML file, say `com.example.myapp.policy` *(usually your.application.id.policy is the filename)*, in `/usr/share/polkit-1/actions/`.

First, define a custom action for your application. Create an XML file, say `com.example.myapp.policy` _(usually your.application.id.policy is the filename)_, in `/usr/share/polkit-1/actions/`.

Here is a real life example .policy file content used in Pardus Software(pardus-software):

Expand Down Expand Up @@ -60,6 +65,7 @@ Here is a real life example .policy file content used in Pardus Software(pardus-
Let's examine the .policy file line by line:

`<policyconfig>` is the base tag:

```xml
<?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">
Expand All @@ -71,12 +77,14 @@ Let's examine the .policy file line by line:
```

`<vendor>` to inform user about who is the developer of the application:

```xml
<vendor>Pardus Developers</vendor>
<vendor_url>https://www.pardus.org.tr</vendor_url>
```

`<action>` tag defines the action that is to be performed:

```xml
<action id="tr.org.pardus.pkexec.pardus-software-action">
<description>Pardus Software Center Authentication</description>
Expand All @@ -96,6 +104,7 @@ Let's examine the .policy file line by line:
```

`<defaults>` tag specifies implicit authorizations for clients [[1]]:

```xml
<defaults>
<allow_any>auth_admin</allow_any>
Expand All @@ -115,54 +124,57 @@ Each of the `allow_any`, `allow_inactive` and `allow_active` elements can contai
- `auth_self`: Asks the password of the user of the current session.

> Note that `auth_self` is not restrictive enough for most uses on multi-user systems. `auth_admin` is generally recommended.
>
>
> Because users are aware of their passwords but are unaware of the root or admin user password. Using auth_self can be acceptable if the modification just has an impact on the user itself.
- `auth_admin`: Asks the password of the **root or administrative user.**
- `auth_self_keep`: Like `auth_self` but the authorization is kept for a brief period (e.g. five minutes). *The warning about **auth_self** above applies likewise.*
- `auth_self_keep`: Like `auth_self` but the authorization is kept for a brief period (e.g. five minutes). _The warning about **auth_self** above applies likewise._

- `auth_admin_keep`: Like `auth_admin` but the authorization is kept for a brief period (e.g. five minutes).

`<annotate>` Used for annotating an action with a key/value pair:

```xml
<annotate key="org.freedesktop.policykit.exec.path">/usr/share/pardus/pardus-software/src/Actions.py</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
```

Here we defined `path` of the executable file, which can be executed with `pkexec`.
Here we defined `path` of the executable file, which can be executed with `pkexec`.

Setting the `allow_gui` true is important to make `pkexec` access the current user session environment of the user to work properly(`$DISPLAY` and `$XAUTHORITY` env variables are retained). [[2]]

Important annotations [[1]]:

- `org.freedesktop.policykit.exec.path`: is used by the pkexec program shipped with polkit.
<br> - (e.g.:`/usr/share/pardus/pardus-software/src/Actions.py`)
<br> - (e.g.:`/usr/share/pardus/pardus-software/src/Actions.py`)
- `org.freedesktop.policykit.imply`: can be used to define meta actions. The way it works is that if a subject is authorized for an action with this annotation, then it is also authorized for any action specified by the annotation. A typical use of this annotation is when defining an UI shell with a single lock button that should unlock multiple actions from distinct mechanisms.
<br> - (e.g.: `org.freedesktop.Flatpak.runtime-install org.freedesktop.Flatpak.runtime-update`) [[3]]
<br> - (e.g.: `org.freedesktop.Flatpak.runtime-install org.freedesktop.Flatpak.runtime-update`) [[3]]
- `org.freedesktop.policykit.owner`: can be used to define a set of users who can query whether a client is authorized to perform this action.
<br> - (e.g.: `unix-user:42 unix-user:colord unix-group:floppy`)
<br> - (e.g.: `unix-user:42 unix-user:colord unix-group:floppy`)

### Examples

- **Emin Fedar** is an Administrative User.
- **AUser** is a normal user.

1. When `auth_admin` action runs on **Administrative User**:

![auth_admin_keep example](images/auth_admin_on_admin.png)
![auth_admin_keep example](https://raw.githubusercontent.com/pardus/pardus.github.io/main/src/lib/assets/auth_admin_on_admin.png)

2. When `auth_admin` action runs on **Non Administrative User**:

![auth_admin_keep example](images/auth_admin_on_other_user.png)
![auth_admin_keep example](https://raw.githubusercontent.com/pardus/pardus.github.io/main/src/lib/assets/auth_admin_on_other_user.png)

3. When `auth_self` action runs on **Non Administrative User**:

![auth_admin_keep example](images/auth_self_on_other_user.png)

![auth_admin_keep example](https://raw.githubusercontent.com/pardus/pardus.github.io/main/src/lib/assets/auth_self_on_other_user.png)

As you can see, `auth_self` is asking password of the current user, `auth_admin` is asking the password of the administrative user.

`yes` is not asking for a password and **authorizing the user immediately.**

## Step 3: Create a Polkit Rule with JavaScript (Optional, polkit version >= 0.106)

Authorization rules are intended for two specific audiences

- System Administrators
Expand All @@ -177,30 +189,35 @@ Next, create a Polkit rule that allows this action without asking for the root p
Create a file, say `10-myapp.rules`, in `/usr/share/polkit-1/rules.d/` with the following content:

```javascript
polkit.addRule(function(action, subject) {
if (action.id == "com.example.myapp.do-something" && subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
})
polkit.addRule(function (action, subject) {
if (
action.id == "com.example.myapp.do-something" &&
subject.isInGroup("wheel")
) {
return polkit.Result.YES;
}
});
```

In this rule, we allow members of the `wheel` group to perform the action `com.example.myapp.do-something` **without being prompted for a password.**

`polkit.Result` enum values:

```javascript
polkit.Result = {
NO : "no",
YES : "yes",
AUTH_SELF : "auth_self",
AUTH_SELF_KEEP : "auth_self_keep",
AUTH_ADMIN : "auth_admin",
AUTH_ADMIN_KEEP : "auth_admin_keep",
NOT_HANDLED : null
NO: "no",
YES: "yes",
AUTH_SELF: "auth_self",
AUTH_SELF_KEEP: "auth_self_keep",
AUTH_ADMIN: "auth_admin",
AUTH_ADMIN_KEEP: "auth_admin_keep",
NOT_HANDLED: null,
};
```

Passwordless actions **are possible with just .policy files** too by setting `<allow_active>yes</allow_active>`.

But **if you need more details to authorize** the user *(like the user must be in a certain group)* you can add details with .rules file.
But **if you need more details to authorize** the user _(like the user must be in a certain group)_ you can add details with .rules file.

## Alternative Step 3: Local Authority Files (Optional)

Expand All @@ -218,6 +235,7 @@ ResultActive=yes
```

## Step 4: Implement the GTK4 Application

Now, implement the GTK4 application. Below is a simple example in Python using PyGObject:

```python
Expand All @@ -231,13 +249,13 @@ def run_privileged_script():
command = ['pkexec', '/usr/bin/my-script']
subprocess.run(command)

# When the application is launched
# When the application is launched
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)

btn = Gtk.Button(label='Hello, World!')
btn.connect('clicked', run_privileged_script)

win.set_child(btn)
win.present()

Expand All @@ -248,11 +266,13 @@ app.connect('activate', on_activate)
# Run the application
app.run(None)
```

In this example, when the button is clicked, it executes a command via `pkexec` (part of Polkit), which performs an administrative task.

Since our Polkit rules **allow this action without authentication for wheel group members**, the command executes **without prompting for a password.**

## Conclusion

By following these steps, you can configure Polkit to allow specific administrative actions to be performed without requiring the root password every time.

1. Create a .policy file with `<allow_active>yes</allow_active>` and a privileged script to run in `<annotate key="org.freedesktop.policykit.exec.path"></annotate>`
Expand All @@ -262,7 +282,6 @@ By following these steps, you can configure Polkit to allow specific administrat
**Remember to carefully manage the permissions and ensure that only trusted users are allowed to perform these actions without authentication to maintain the security of your system.**

Happy coding!


[1]: https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html
[2]: https://www.freedesktop.org/software/polkit/docs/latest/pkexec.1.html#pkexec-security-notes
Expand Down

0 comments on commit e7c301c

Please sign in to comment.