## Writing PolicyKit applications

PolicyKit applications are privileged mechanisms using the PolicyKit authority as a decider component. To do this, a mechanism use either the GObject API, the D-Bus API or the pkcheck command to communicate with the PolicyKit Authority.

Note that clients never use the PolicyKit API directly – it is intended solely for privileged mechanisms. If a client needs to disable, modify or remove UI elements to e.g. convey to the user that a certain action cannot be carried out (because e.g. the user is not authorized) or authentication is needed (by e.g. displaying a padlock icon in the UI), the mechanism will need to provide API for this.

As an example of code using the GObject API, see Example 1, “Querying the Authority”. For an example using the D-Bus API, see Example 2, “Accessing the Authority via D-Bus”.

Example 1. Querying the Authority

    /*
     * Copyright (C) 2009 Red Hat, Inc.
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2 of the License, or (at your option) any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General
     * Public License along with this library; if not, write to the
     * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     * Boston, MA 02111-1307, USA.
     *
     * Author: David Zeuthen <davidz@redhat.com>
     */

    /* Simple example that shows how to check for an authorization
     * including cancelling the check.
     *
     * Cancelling an authorization check is desirable in situations where
     * the object/action to check for vanishes.
     *
     * One concrete example of this is a disks service in which the user
     * needs to authenticate to modify a disk. If the disk is removed
     * while the authentication dialog is shown, the disks service should
     * cancel the authorization check. A side effect of this, is that the
     * authentication dialog is removed.
     */

    #include <polkit/polkit.h>

    static void
    check_authorization_cb (PolkitAuthority *authority,
                            GAsyncResult    *res,
                            GMainLoop       *loop)
    {
      GError *error;
      PolkitAuthorizationResult *result;

      error = NULL;
      result = polkit_authority_check_authorization_finish (authority, res, &error);
      if (error != NULL)
        {
          g_print ("Error checking authorization: %s\n", error->message);
          g_error_free (error);
        }
      else
        {
          const gchar *result_str;
          if (polkit_authorization_result_get_is_authorized (result))
            {
              result_str = "authorized";
            }
          else if (polkit_authorization_result_get_is_challenge (result))
            {
              result_str = "challenge";
            }
          else
            {
              result_str = "not authorized";
            }

          g_print ("Authorization result: %s\n", result_str);
        }

      g_main_loop_quit (loop);
    }

    static gboolean
    do_cancel (GCancellable *cancellable)
    {
      g_print ("Timer has expired; cancelling authorization check\n");
      g_cancellable_cancel (cancellable);
      return FALSE;
    }

    int
    main (int argc, char *argv[])
    {
      pid_t parent_pid;
      const gchar *action_id;
      GMainLoop *loop;
      PolkitSubject *subject;
      PolkitAuthority *authority;
      GCancellable *cancellable;

      g_type_init ();

      if (argc != 2)
        {
          g_printerr ("usage: %s <action_id>\n", argv[0]);
          return 1;
        }
      action_id = argv[1];

      loop = g_main_loop_new (NULL, FALSE);

      authority = polkit_authority_get ();

      /* Typically mechanisms will use a PolkitSystemBusName since most
       * clients communicate with the mechanism via D-Bus. However for
       * this simple example we use the process id of the calling process.
       *
       * Note that if the parent was reaped we have to be careful not to
       * check if init(1) is authorized (it always is).
       */
      parent_pid = getppid ();
      if (parent_pid == 1)
        {
          g_printerr ("Parent process was reaped by init(1)\n");
          return 1;
        }
      subject = polkit_unix_process_new (parent_pid);

      cancellable = g_cancellable_new ();

      g_print ("Will cancel authorization check in 10 seconds\n");

      /* Set up a 10 second timer to cancel the check */
      g_timeout_add (10 * 1000,
                     (GSourceFunc) do_cancel,
                     cancellable);

      polkit_authority_check_authorization (authority,
                                            subject,
                                            action_id,
                                            NULL, /* PolkitDetails */
                                            POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
                                            cancellable,
                                            (GAsyncReadyCallback) check_authorization_cb,
                                            loop);

      g_main_loop_run (loop);

      g_object_unref (authority);
      g_object_unref (subject);
      g_object_unref (cancellable);
      g_main_loop_unref (loop);

      return 0;
    }

Example 2. Accessing the Authority via D-Bus

    #!/usr/bin/env python

    # Copyright (C) 2009 Red Hat, Inc.
    #
    # This library is free software; you can redistribute it and/or
    # modify it under the terms of the GNU Lesser General Public
    # License as published by the Free Software Foundation; either
    # version 2 of the License, or (at your option) any later version.
    #
    # This library is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    # Lesser General Public License for more details.
    #
    # You should have received a copy of the GNU Lesser General
    # Public License along with this library; if not, write to the
    # Free Software Foundation, Inc., 59 Temple Place, Suite 330,
    # Boston, MA 02111-1307, USA.
    #
    # Author: David Zeuthen <davidz@redhat.com>

    # Simple example showing how to access the Authority via D-Bus calls
    #

    import dbus

    bus = dbus.SystemBus()
    proxy = bus.get_object('org.freedesktop.PolicyKit1', '/org/freedesktop/PolicyKit1/Authority')
    authority = dbus.Interface(proxy, dbus_interface='org.freedesktop.PolicyKit1.Authority')

    system_bus_name = bus.get_unique_name()

    subject = ('system-bus-name', {'name' : system_bus_name})
    action_id = 'org.freedesktop.policykit.exec'
    details = {}
    flags = 1            # AllowUserInteraction flag
    cancellation_id = '' # No cancellation id

    result = authority.CheckAuthorization(subject, action_id, details, flags, cancellation_id)

    print result