Codebase list policykit-1-gnome / upstream/0.5 examples / polkit-gnome-example-helper.c
upstream/0.5

Tree @upstream/0.5 (Download .tar.gz)

polkit-gnome-example-helper.c @upstream/0.5raw · history · blame

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <glib.h>
#include <polkit/polkit.h>
#include <polkit-dbus/polkit-dbus.h>

static gboolean
io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
{
        int fd;
        PolKitContext *pk_context = user_data;
        fd = g_io_channel_unix_get_fd (channel);
        polkit_context_io_func (pk_context, fd);
        return TRUE;
}

static int 
io_add_watch (PolKitContext *pk_context, int fd)
{
        guint id = 0;
        GIOChannel *channel;
        channel = g_io_channel_unix_new (fd);
        if (channel == NULL)
                goto out;
        id = g_io_add_watch (channel, G_IO_IN, io_watch_have_data, pk_context);
        if (id == 0) {
                g_io_channel_unref (channel);
                goto out;
        }
        g_io_channel_unref (channel);
out:
        return id;
}

static void 
io_remove_watch (PolKitContext *pk_context, int watch_id)
{
        g_source_remove (watch_id);
}


static void 
exit_not_privileged (PolKitResult pk_result, const char *pk_action)
{
        const char *pk_result_as_str;
        pk_result_as_str = polkit_result_to_string_representation (pk_result);
        fprintf (stderr, "%s %s", pk_result_as_str, pk_action);
        exit(1);
}

static gboolean
check_privileged (PolKitContext *pol_ctx,
                  pid_t caller_pid, 
                  const char *pk_action, 
                  PolKitResult *pk_result)
{
        DBusError error;
        DBusConnection *bus;
        PolKitCaller *caller;
        PolKitAction *action;

        dbus_error_init (&error);
        bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
        if (bus == NULL) {
                fprintf (stderr, "cannot connect to system bus: %s: %s\n", error.name, error.message);
                dbus_error_free (&error);
                goto out;
        }

        action = polkit_action_new ();
        polkit_action_set_action_id (action, pk_action);

        caller = polkit_caller_new_from_pid (bus, caller_pid, &error);
        if (caller == NULL) {
                fprintf (stderr, "cannot get caller from dbus name\n");
                goto out;
        }

        *pk_result = polkit_context_can_caller_do_action (pol_ctx, action, caller);
        return TRUE;
out:
        return FALSE;
}

static void
usage (void)
{
        fprintf (stderr, "usage: polkit-gnome-example-helper --frobnicate | --tweak\n");
        exit (2);
}

static char *kick_type = NULL;

static void
_cb (PolKitPolicyCache *policy_cache,
     PolKitPolicyFileEntry *entry,
     void *user_data)
{
        const char *value;
        char **target_action = (char **) user_data;

        /* have we already found one Action? */
        if (*target_action != NULL)
                return;

        value = polkit_policy_file_entry_get_annotation (entry, "org.gnome.policykit.examples.kick-path");
        if (value == NULL)
                return;

        if (strcmp (value, kick_type) != 0)
                return;

        *target_action = strdup (polkit_policy_file_entry_get_id (entry));
}

int
main (int argc, char *argv[])
{
        pid_t parent_pid;
        char *pk_action;
        PolKitResult pk_result = POLKIT_RESULT_NO;
        PolKitContext *pol_ctx;

        printf ("In polkit-gnome-example-helper\n");


        if (argc < 2) {
                usage ();
        }

        pol_ctx = polkit_context_new ();
        polkit_context_set_io_watch_functions (pol_ctx, io_add_watch, io_remove_watch);
        if (!polkit_context_init (pol_ctx, NULL)) {
                fprintf (stderr, "cannot init polkit\n");
                exit_not_privileged (POLKIT_RESULT_NO, pk_action);
        }

        if (strcmp (argv[1], "--frobnicate") == 0 && argc == 2) {
                pk_action = "org.gnome.policykit.examples.frobnicate";
        } else if (strcmp (argv[1], "--tweak") == 0 && argc == 2) {
                pk_action = "org.gnome.policykit.examples.tweak";
        } else if (strcmp (argv[1], "--twiddle") == 0 && argc == 2) {
                pk_action = "org.gnome.policykit.examples.twiddle";
        } else if (strcmp (argv[1], "--punch") == 0 && argc == 2) {
                pk_action = "org.gnome.policykit.examples.punch";
        } else if (strcmp (argv[1], "--kick") == 0 && argc == 3) {
                PolKitPolicyCache *policy_cache;
                policy_cache = polkit_context_get_policy_cache (pol_ctx);
                pk_action = NULL;
                kick_type = argv[2];
                polkit_policy_cache_foreach (policy_cache, _cb, &pk_action);
                if (pk_action == NULL) {
                        printf ("cannot find action for kick type '%s'\n", kick_type);
                        exit_not_privileged (POLKIT_RESULT_NO, pk_action);
                }
        } else {
                usage ();
        }

        /* check if parent is privileged */
        parent_pid = getppid ();
        if (!check_privileged (pol_ctx, parent_pid, pk_action, &pk_result)) {
                /* PolicyKit don't know - just return 'NO' for now */
                printf ("we're not privileged: PK inquiry failed\n");
                exit_not_privileged (POLKIT_RESULT_NO, pk_action);
        }

        if (pk_result != POLKIT_RESULT_YES) {
                /* Caller is not privileged */
                printf ("we're not privileged: pk_result='%s'\n", polkit_result_to_string_representation (pk_result));
                exit_not_privileged (pk_result, pk_action);
        }

        /* caller is indeed privileged; carry out the deed.. */
        printf ("we're privileged - yeay!\n");

        /* TODO: now either: "frobnicate", "tweak" or "twiddle", "punch", "kick", "poke" */

        return 0;
}