2
* * Copyright (C) 2009-2011 Ali <aliov@xfce.org>
4
* Licensed under the GNU General Public License Version 2
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33
#include <sys/types.h>
35
#if defined(__FreeBSD__)
38
#include <sys/param.h>
39
#include <sys/sysctl.h>
45
#include <dbus/dbus-glib.h>
47
#include "xfpm-polkit.h"
48
#include "xfpm-debug.h"
50
#include "xfpm-common.h"
52
static void xfpm_polkit_finalize (GObject *object);
54
#define XFPM_POLKIT_GET_PRIVATE(o) \
55
(G_TYPE_INSTANCE_GET_PRIVATE ((o), XFPM_TYPE_POLKIT, XfpmPolkitPrivate))
57
struct XfpmPolkitPrivate
65
GHashTable *subject_hash;
72
gboolean subject_valid;
82
static guint signals [LAST_SIGNAL] = { 0 };
84
G_DEFINE_TYPE (XfpmPolkit, xfpm_polkit, G_TYPE_OBJECT)
87
#if defined(__FreeBSD__)
89
* Taken from polkitunixprocess.c code to get process start
92
* Copyright (C) 2008 Red Hat, Inc.
96
get_kinfo_proc (pid_t pid, struct kinfo_proc *p)
102
sysctlnametomib ("kern.proc.pid", mib, &len);
104
len = sizeof (struct kinfo_proc);
107
if (sysctl (mib, 4, p, &len, NULL, 0) == -1)
112
#endif /*if defined(__FreeBSD__)*/
115
get_start_time_for_pid (pid_t pid)
118
#if !defined(__FreeBSD__)
130
filename = g_strdup_printf ("/proc/%d/stat", pid);
132
if (!g_file_get_contents (filename, &contents, &length, NULL))
135
/* start time is the token at index 19 after the '(process name)' entry - since only this
136
* field can contain the ')' character, search backwards for this to avoid malicious
137
* processes trying to fool us
139
p = strrchr (contents, ')');
145
p += 2; /* skip ') ' */
147
if (p - contents >= (int) length)
149
g_warning ("Error parsing file %s", filename);
153
tokens = g_strsplit (p, " ", 0);
155
num_tokens = g_strv_length (tokens);
159
g_warning ("Error parsing file %s", filename);
163
start_time = strtoull (tokens[19], &endp, 10);
164
if (endp == tokens[19])
166
g_warning ("Error parsing file %s", filename);
175
#else /*if !defined(__FreeBSD__)*/
181
if (! get_kinfo_proc (pid, &p))
183
g_warning ("Error obtaining start time for %d (%s)",
189
start_time = (guint64) p.ki_start.tv_sec;
196
#endif /*ENABLE_POLKIT*/
201
xfpm_polkit_free_data (gpointer data)
205
polkit = XFPM_POLKIT (data);
207
g_assert (polkit->priv->subject_valid);
209
XFPM_DEBUG ("Destroying Polkit data");
211
g_hash_table_destroy (polkit->priv->details);
212
g_hash_table_destroy (polkit->priv->subject_hash);
213
g_value_array_free (polkit->priv->subject);
215
polkit->priv->details = NULL;
216
polkit->priv->subject_hash = NULL;
217
polkit->priv->subject = NULL;
219
polkit->priv->destroy_id = 0;
220
polkit->priv->subject_valid = FALSE;
226
xfpm_polkit_init_data (XfpmPolkit *polkit)
228
//const gchar *consolekit_cookie;
229
GValue hash_elem = { 0 };
230
//gboolean subject_created = FALSE;
232
if (polkit->priv->subject_valid)
236
* This variable should be set by the session manager or by
237
* the login manager (gdm?). under clean Xfce environment
238
* it is set by the session manager (4.8 and above)
239
* since we don't have a login manager, yet!
243
* Disable for the moment
245
consolekit_cookie = g_getenv ("XDG_SESSION_COOKIE");
247
if ( consolekit_cookie )
250
GError *error = NULL;
252
gchar *consolekit_session;
254
proxy = dbus_g_proxy_new_for_name_owner (polkit->priv->bus,
255
"org.freedesktop.ConsoleKit",
256
"/org/freedesktop/ConsoleKit/Manager",
257
"org.freedesktop.ConsoleKit.Manager",
262
ret = dbus_g_proxy_call (proxy, "GetSessionForCookie", &error,
263
G_TYPE_STRING, consolekit_cookie,
265
DBUS_TYPE_G_OBJECT_PATH, &consolekit_session,
268
if ( G_LIKELY (ret) )
272
polkit->priv->subject = g_value_array_new (2);
273
polkit->priv->subject_hash = g_hash_table_new_full (g_str_hash,
277
g_value_init (&val, G_TYPE_STRING);
278
g_value_set_string (&val, "unix-session");
279
g_value_array_append (polkit->priv->subject, &val);
281
g_value_unset (&val);
282
g_value_init (&val, G_TYPE_STRING);
283
g_value_set_string (&val, consolekit_session);
285
g_hash_table_insert (polkit->priv->subject_hash,
286
g_strdup ("session-id"),
289
g_free (consolekit_session);
290
XFPM_DEBUG ("Using ConsoleKit session Polkit subject");
291
subject_created = TRUE;
293
g_object_unref (proxy);
297
g_warning ("'GetSessionForCookie' failed : %s", error->message);
298
g_error_free (error);
304
//if ( subject_created == FALSE )
311
start_time = get_start_time_for_pid (pid);
313
if ( G_LIKELY (start_time != 0 ) )
315
GValue val = { 0 }, pid_val = { 0 }, start_time_val = { 0 };
317
polkit->priv->subject = g_value_array_new (2);
318
polkit->priv->subject_hash = g_hash_table_new_full (g_str_hash,
323
g_value_init (&val, G_TYPE_STRING);
324
g_value_set_string (&val, "unix-process");
325
g_value_array_append (polkit->priv->subject, &val);
327
g_value_unset (&val);
329
g_value_init (&pid_val, G_TYPE_UINT);
330
g_value_set_uint (&pid_val, pid);
331
g_hash_table_insert (polkit->priv->subject_hash,
332
g_strdup ("pid"), &pid_val);
334
g_value_init (&start_time_val, G_TYPE_UINT64);
335
g_value_set_uint64 (&start_time_val, start_time);
336
g_hash_table_insert (polkit->priv->subject_hash,
337
g_strdup ("start-time"), &start_time_val);
339
XFPM_DEBUG ("Using unix session polkit subject");
343
g_warning ("Unable to create polkit subject");
347
g_value_init (&hash_elem,
348
dbus_g_type_get_map ("GHashTable",
352
g_value_set_static_boxed (&hash_elem, polkit->priv->subject_hash);
353
g_value_array_append (polkit->priv->subject, &hash_elem);
356
* Polkit details, will leave it empty.
358
polkit->priv->details = g_hash_table_new_full (g_str_hash,
363
/*Clean these data after 1 minute*/
364
polkit->priv->destroy_id =
365
g_timeout_add_seconds (60, (GSourceFunc) xfpm_polkit_free_data, polkit);
367
polkit->priv->subject_valid = TRUE;
369
#endif /*ENABLE_POLKIT*/
372
xfpm_polkit_check_auth_intern (XfpmPolkit *polkit, const gchar *action_id)
376
GValue result_val = { 0 };
377
GError *error = NULL;
378
gboolean is_authorized = FALSE;
382
* <method name="CheckAuthorization">
383
* <arg type="(sa{sv})" name="subject" direction="in"/>
384
* <arg type="s" name="action_id" direction="in"/>
385
* <arg type="a{ss}" name="details" direction="in"/>
386
* <arg type="u" name="flags" direction="in"/>
387
* <arg type="s" name="cancellation_id" direction="in"/>
388
* <arg type="(bba{ss})" name="result" direction="out"/>
393
g_return_val_if_fail (polkit->priv->proxy != NULL, FALSE);
394
g_return_val_if_fail (polkit->priv->subject_valid, FALSE);
396
result = g_value_array_new (0);
398
ret = dbus_g_proxy_call (polkit->priv->proxy, "CheckAuthorization", &error,
399
polkit->priv->subject_gtype, polkit->priv->subject,
400
G_TYPE_STRING, action_id,
401
polkit->priv->details_gtype, polkit->priv->details,
405
polkit->priv->result_gtype, &result,
408
if ( G_LIKELY (ret) )
410
g_value_init (&result_val, polkit->priv->result_gtype);
411
g_value_set_static_boxed (&result_val, result);
413
dbus_g_type_struct_get (&result_val,
416
g_value_unset (&result_val);
420
g_warning ("'CheckAuthorization' failed with %s", error->message);
421
g_error_free (error);
424
g_value_array_free (result);
426
XFPM_DEBUG ("Action=%s is authorized=%s", action_id, xfpm_bool_to_string (is_authorized));
428
return is_authorized;
429
#endif /*ENABLE_POLKIT*/
435
xfpm_polkit_changed_cb (DBusGProxy *proxy, XfpmPolkit *polkit)
437
XFPM_DEBUG ("Auth changed");
438
g_signal_emit (G_OBJECT (polkit), signals [AUTH_CHANGED], 0);
443
xfpm_polkit_class_init (XfpmPolkitClass *klass)
445
GObjectClass *object_class = G_OBJECT_CLASS (klass);
447
object_class->finalize = xfpm_polkit_finalize;
449
signals [AUTH_CHANGED] =
450
g_signal_new ("auth-changed",
453
G_STRUCT_OFFSET(XfpmPolkitClass, auth_changed),
455
g_cclosure_marshal_VOID__VOID,
456
G_TYPE_NONE, 0, G_TYPE_NONE);
458
g_type_class_add_private (klass, sizeof (XfpmPolkitPrivate));
462
xfpm_polkit_init (XfpmPolkit *polkit)
464
GError *error = NULL;
466
polkit->priv = XFPM_POLKIT_GET_PRIVATE (polkit);
469
polkit->priv->destroy_id = 0;
470
polkit->priv->subject_valid = FALSE;
471
polkit->priv->proxy = NULL;
472
polkit->priv->subject = NULL;
473
polkit->priv->details = NULL;
474
polkit->priv->subject_hash = NULL;
476
polkit->priv->subject_gtype =
477
dbus_g_type_get_struct ("GValueArray",
479
dbus_g_type_get_map ("GHashTable",
484
polkit->priv->details_gtype = dbus_g_type_get_map ("GHashTable",
488
polkit->priv->result_gtype =
489
dbus_g_type_get_struct ("GValueArray",
492
dbus_g_type_get_map ("GHashTable",
496
#endif /*ENABLE_POLKIT*/
498
polkit->priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
502
g_critical ("Error getting system bus connection : %s", error->message);
503
g_error_free (error);
508
polkit->priv->proxy =
509
dbus_g_proxy_new_for_name (polkit->priv->bus,
510
"org.freedesktop.PolicyKit1",
511
"/org/freedesktop/PolicyKit1/Authority",
512
"org.freedesktop.PolicyKit1.Authority");
514
if (G_LIKELY (polkit->priv->proxy) )
516
dbus_g_proxy_add_signal (polkit->priv->proxy, "Changed", G_TYPE_INVALID);
517
dbus_g_proxy_connect_signal (polkit->priv->proxy, "Changed",
518
G_CALLBACK (xfpm_polkit_changed_cb), polkit, NULL);
522
g_warning ("Failed to create proxy for 'org.freedesktop.PolicyKit1'");
524
#endif /*ENABLE_POLKIT*/
531
xfpm_polkit_finalize (GObject *object)
535
polkit = XFPM_POLKIT (object);
538
if ( polkit->priv->proxy )
540
dbus_g_proxy_disconnect_signal (polkit->priv->proxy, "Changed",
541
G_CALLBACK (xfpm_polkit_changed_cb), polkit);
542
g_object_unref (polkit->priv->proxy);
545
if ( polkit->priv->subject_valid )
547
xfpm_polkit_free_data (polkit);
548
if (polkit->priv->destroy_id != 0 )
549
g_source_remove (polkit->priv->destroy_id);
551
#endif /*ENABLE_POLKIT*/
554
if ( polkit->priv->bus )
555
dbus_g_connection_unref (polkit->priv->bus);
557
G_OBJECT_CLASS (xfpm_polkit_parent_class)->finalize (object);
561
xfpm_polkit_get (void)
563
static gpointer xfpm_polkit_obj = NULL;
565
if ( G_LIKELY (xfpm_polkit_obj) )
567
g_object_ref (xfpm_polkit_obj);
571
xfpm_polkit_obj = g_object_new (XFPM_TYPE_POLKIT, NULL);
572
g_object_add_weak_pointer (xfpm_polkit_obj, &xfpm_polkit_obj);
575
return XFPM_POLKIT (xfpm_polkit_obj);
578
gboolean xfpm_polkit_check_auth (XfpmPolkit *polkit, const gchar *action_id)
581
xfpm_polkit_init_data (polkit);
583
return xfpm_polkit_check_auth_intern (polkit, action_id);