/* -*- 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;
}