~noskcaj/ubuntu/trusty/xfce4-power-manager/systemd

« back to all changes in this revision

Viewing changes to .pc/0001-Solaris-specific-code-for-determining-the-start-time.patch/src/xfpm-polkit.c

  • Committer: Bazaar Package Importer
  • Author(s): Yves-Alexis Perez
  • Date: 2011-04-22 23:32:17 UTC
  • mto: (21.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: james.westby@ubuntu.com-20110422233217-u0b0sn29vari4v03
Tags: 1.0.10-3
* debian/patches:
  - 0001-Solaris-specific-code-for-determining-the-start-time cherry-picked
    from master. We don't have solaris but it should fix the build-failure
    on GNU/Hurd anyway.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * * Copyright (C) 2009-2011 Ali <aliov@xfce.org>
 
3
 *
 
4
 * Licensed under the GNU General Public License Version 2
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
 
 
29
#ifdef HAVE_UNISTD_H
 
30
#include <unistd.h>
 
31
#endif
 
32
 
 
33
#include <sys/types.h>
 
34
 
 
35
#if defined(__FreeBSD__)
 
36
#include <sys/stat.h>
 
37
#else
 
38
#include <sys/param.h>
 
39
#include <sys/sysctl.h>
 
40
#include <sys/user.h>
 
41
#endif
 
42
 
 
43
#include <errno.h>
 
44
 
 
45
#include <dbus/dbus-glib.h>
 
46
 
 
47
#include "xfpm-polkit.h"
 
48
#include "xfpm-debug.h"
 
49
 
 
50
#include "xfpm-common.h"
 
51
 
 
52
static void xfpm_polkit_finalize   (GObject *object);
 
53
 
 
54
#define XFPM_POLKIT_GET_PRIVATE(o) \
 
55
(G_TYPE_INSTANCE_GET_PRIVATE ((o), XFPM_TYPE_POLKIT, XfpmPolkitPrivate))
 
56
 
 
57
struct XfpmPolkitPrivate
 
58
{
 
59
    DBusGConnection   *bus;
 
60
 
 
61
#ifdef ENABLE_POLKIT
 
62
    DBusGProxy        *proxy;
 
63
    GValueArray       *subject;
 
64
    GHashTable        *details;
 
65
    GHashTable        *subject_hash;
 
66
 
 
67
    GType              subject_gtype;
 
68
    GType              details_gtype;
 
69
    GType              result_gtype;
 
70
 
 
71
    gulong             destroy_id;
 
72
    gboolean           subject_valid;
 
73
#endif
 
74
};
 
75
 
 
76
enum
 
77
{
 
78
    AUTH_CHANGED,
 
79
    LAST_SIGNAL
 
80
};
 
81
 
 
82
static guint signals [LAST_SIGNAL] = { 0 };
 
83
 
 
84
G_DEFINE_TYPE (XfpmPolkit, xfpm_polkit, G_TYPE_OBJECT)
 
85
 
 
86
#ifdef ENABLE_POLKIT
 
87
#if defined(__FreeBSD__)
 
88
/**
 
89
 * Taken from polkitunixprocess.c code to get process start
 
90
 * time from pid.
 
91
 *
 
92
 * Copyright (C) 2008 Red Hat, Inc.
 
93
 *
 
94
 **/
 
95
static gboolean
 
96
get_kinfo_proc (pid_t pid, struct kinfo_proc *p)
 
97
{
 
98
    int mib[4];
 
99
    size_t len;
 
100
    
 
101
    len = 4;
 
102
    sysctlnametomib ("kern.proc.pid", mib, &len);
 
103
    
 
104
    len = sizeof (struct kinfo_proc);
 
105
    mib[3] = pid;
 
106
    
 
107
    if (sysctl (mib, 4, p, &len, NULL, 0) == -1)
 
108
        return FALSE;
 
109
 
 
110
    return TRUE;
 
111
}
 
112
#endif /*if defined(__FreeBSD__)*/
 
113
 
 
114
static guint64
 
115
get_start_time_for_pid (pid_t pid)
 
116
{
 
117
    guint64 start_time;
 
118
#if !defined(__FreeBSD__)
 
119
    gchar *filename;
 
120
    gchar *contents;
 
121
    size_t length;
 
122
    gchar **tokens;
 
123
    guint num_tokens;
 
124
    gchar *p;
 
125
    gchar *endp;
 
126
  
 
127
    start_time = 0;
 
128
    contents = NULL;
 
129
    
 
130
    filename = g_strdup_printf ("/proc/%d/stat", pid);
 
131
    
 
132
    if (!g_file_get_contents (filename, &contents, &length, NULL))
 
133
        goto out;
 
134
 
 
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
 
138
     */
 
139
    p = strrchr (contents, ')');
 
140
    if (p == NULL)
 
141
    {
 
142
        goto out;
 
143
    }
 
144
    
 
145
    p += 2; /* skip ') ' */
 
146
 
 
147
    if (p - contents >= (int) length)
 
148
    {
 
149
        g_warning ("Error parsing file %s", filename);
 
150
        goto out;
 
151
    }
 
152
    
 
153
    tokens = g_strsplit (p, " ", 0);
 
154
    
 
155
    num_tokens = g_strv_length (tokens);
 
156
    
 
157
    if (num_tokens < 20)
 
158
    {
 
159
        g_warning ("Error parsing file %s", filename);
 
160
        goto out;
 
161
    }
 
162
 
 
163
    start_time = strtoull (tokens[19], &endp, 10);
 
164
    if (endp == tokens[19])
 
165
    {
 
166
        g_warning ("Error parsing file %s", filename);
 
167
        goto out;
 
168
    }
 
169
    g_strfreev (tokens);
 
170
 
 
171
 out:
 
172
    g_free (filename);
 
173
    g_free (contents);
 
174
    
 
175
#else /*if !defined(__FreeBSD__)*/
 
176
 
 
177
    struct kinfo_proc p;
 
178
    
 
179
    start_time = 0;
 
180
 
 
181
    if (! get_kinfo_proc (pid, &p))
 
182
    {
 
183
        g_warning ("Error obtaining start time for %d (%s)",
 
184
                   (gint) pid,
 
185
                   g_strerror (errno));
 
186
        goto out;
 
187
    }
 
188
 
 
189
    start_time = (guint64) p.ki_start.tv_sec;
 
190
    
 
191
out:
 
192
#endif
 
193
    
 
194
    return start_time;
 
195
}
 
196
#endif /*ENABLE_POLKIT*/
 
197
 
 
198
 
 
199
#ifdef ENABLE_POLKIT
 
200
static gboolean
 
201
xfpm_polkit_free_data (gpointer data)
 
202
{
 
203
    XfpmPolkit *polkit;
 
204
    
 
205
    polkit = XFPM_POLKIT (data);
 
206
 
 
207
    g_assert (polkit->priv->subject_valid);
 
208
 
 
209
    XFPM_DEBUG ("Destroying Polkit data");
 
210
 
 
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);
 
214
    
 
215
    polkit->priv->details      = NULL;
 
216
    polkit->priv->subject_hash = NULL;
 
217
    polkit->priv->subject      = NULL;
 
218
 
 
219
    polkit->priv->destroy_id = 0;
 
220
    polkit->priv->subject_valid = FALSE;
 
221
    
 
222
    return FALSE;
 
223
}
 
224
 
 
225
static void
 
226
xfpm_polkit_init_data (XfpmPolkit *polkit)
 
227
{
 
228
    //const gchar *consolekit_cookie;
 
229
    GValue hash_elem = { 0 };
 
230
    //gboolean subject_created = FALSE;
 
231
 
 
232
    if (polkit->priv->subject_valid)
 
233
        return;
 
234
    
 
235
    /**
 
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!
 
240
     **/
 
241
     /*
 
242
      * 
 
243
      * Disable for the moment
 
244
      * 
 
245
    consolekit_cookie = g_getenv ("XDG_SESSION_COOKIE");
 
246
  
 
247
    if ( consolekit_cookie )
 
248
    {
 
249
        DBusGProxy *proxy;
 
250
        GError *error = NULL;
 
251
        gboolean ret;
 
252
        gchar *consolekit_session;
 
253
        
 
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",
 
258
                                                  NULL);
 
259
 
 
260
        if ( proxy )
 
261
        {
 
262
            ret = dbus_g_proxy_call (proxy, "GetSessionForCookie", &error,
 
263
                                     G_TYPE_STRING, consolekit_cookie,
 
264
                                     G_TYPE_INVALID,
 
265
                                     DBUS_TYPE_G_OBJECT_PATH, &consolekit_session,
 
266
                                     G_TYPE_INVALID);
 
267
            
 
268
            if ( G_LIKELY (ret) )
 
269
            {
 
270
                GValue val  = { 0 };
 
271
                
 
272
                polkit->priv->subject = g_value_array_new (2);
 
273
                polkit->priv->subject_hash = g_hash_table_new_full (g_str_hash, 
 
274
                                                                    g_str_equal, 
 
275
                                                                    g_free, 
 
276
                                                                    NULL);
 
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);
 
280
                
 
281
                g_value_unset (&val);
 
282
                g_value_init (&val, G_TYPE_STRING);
 
283
                g_value_set_string (&val, consolekit_session);
 
284
                
 
285
                g_hash_table_insert (polkit->priv->subject_hash, 
 
286
                                     g_strdup ("session-id"), 
 
287
                                     &val);
 
288
                
 
289
                g_free (consolekit_session);
 
290
                XFPM_DEBUG ("Using ConsoleKit session Polkit subject");
 
291
                subject_created = TRUE;
 
292
            }
 
293
            g_object_unref (proxy);
 
294
        }
 
295
        else if (error)
 
296
        {
 
297
            g_warning ("'GetSessionForCookie' failed : %s", error->message);
 
298
            g_error_free (error);
 
299
        }
 
300
        
 
301
    }
 
302
    */
 
303
    
 
304
    //if ( subject_created == FALSE )
 
305
    {
 
306
        gint pid;
 
307
        guint64 start_time;
 
308
    
 
309
        pid = getpid ();
 
310
        
 
311
        start_time = get_start_time_for_pid (pid);
 
312
        
 
313
        if ( G_LIKELY (start_time != 0 ) )
 
314
        {
 
315
            GValue val = { 0 }, pid_val = { 0 }, start_time_val = { 0 };
 
316
            
 
317
            polkit->priv->subject = g_value_array_new (2);
 
318
            polkit->priv->subject_hash = g_hash_table_new_full (g_str_hash, 
 
319
                                                                g_str_equal, 
 
320
                                                                g_free, 
 
321
                                                                NULL);
 
322
        
 
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);
 
326
            
 
327
            g_value_unset (&val);
 
328
            
 
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);
 
333
            
 
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);
 
338
            
 
339
            XFPM_DEBUG ("Using unix session polkit subject");
 
340
        }
 
341
        else
 
342
        {
 
343
            g_warning ("Unable to create polkit subject");
 
344
        }
 
345
    }
 
346
    
 
347
    g_value_init (&hash_elem, 
 
348
                  dbus_g_type_get_map ("GHashTable", 
 
349
                                       G_TYPE_STRING, 
 
350
                                       G_TYPE_VALUE));
 
351
    
 
352
    g_value_set_static_boxed (&hash_elem, polkit->priv->subject_hash);
 
353
    g_value_array_append (polkit->priv->subject, &hash_elem);
 
354
    
 
355
    /**
 
356
     * Polkit details, will leave it empty.
 
357
     **/
 
358
    polkit->priv->details = g_hash_table_new_full (g_str_hash, 
 
359
                                                   g_str_equal, 
 
360
                                                   g_free, 
 
361
                                                   g_free);
 
362
    
 
363
    /*Clean these data after 1 minute*/
 
364
    polkit->priv->destroy_id = 
 
365
        g_timeout_add_seconds (60, (GSourceFunc) xfpm_polkit_free_data, polkit);
 
366
    
 
367
    polkit->priv->subject_valid = TRUE;
 
368
}
 
369
#endif /*ENABLE_POLKIT*/
 
370
 
 
371
static gboolean
 
372
xfpm_polkit_check_auth_intern (XfpmPolkit *polkit, const gchar *action_id)
 
373
{
 
374
#ifdef ENABLE_POLKIT
 
375
    GValueArray *result;
 
376
    GValue result_val = { 0 };
 
377
    GError *error = NULL;
 
378
    gboolean is_authorized = FALSE;
 
379
    gboolean ret;
 
380
    
 
381
    /**
 
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"/>     
 
389
     * </method>
 
390
     *
 
391
     **/
 
392
    
 
393
    g_return_val_if_fail (polkit->priv->proxy != NULL, FALSE);
 
394
    g_return_val_if_fail (polkit->priv->subject_valid, FALSE);
 
395
     
 
396
    result = g_value_array_new (0);
 
397
    
 
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,
 
402
                             G_TYPE_UINT, 0, 
 
403
                             G_TYPE_STRING, NULL,
 
404
                             G_TYPE_INVALID,
 
405
                             polkit->priv->result_gtype, &result,
 
406
                             G_TYPE_INVALID);
 
407
    
 
408
    if ( G_LIKELY (ret) )
 
409
    {
 
410
        g_value_init (&result_val, polkit->priv->result_gtype);
 
411
        g_value_set_static_boxed (&result_val, result);
 
412
        
 
413
        dbus_g_type_struct_get (&result_val,
 
414
                                0, &is_authorized,
 
415
                                G_MAXUINT);
 
416
        g_value_unset (&result_val);
 
417
    }
 
418
    else if ( error )
 
419
    {
 
420
        g_warning ("'CheckAuthorization' failed with %s", error->message);
 
421
        g_error_free (error);
 
422
    }
 
423
 
 
424
    g_value_array_free (result);
 
425
    
 
426
    XFPM_DEBUG ("Action=%s is authorized=%s", action_id, xfpm_bool_to_string (is_authorized));
 
427
    
 
428
    return is_authorized;
 
429
#endif /*ENABLE_POLKIT*/
 
430
    return TRUE;
 
431
}
 
432
 
 
433
#ifdef ENABLE_POLKIT
 
434
static void
 
435
xfpm_polkit_changed_cb (DBusGProxy *proxy, XfpmPolkit *polkit)
 
436
{
 
437
    XFPM_DEBUG ("Auth changed");
 
438
    g_signal_emit (G_OBJECT (polkit), signals [AUTH_CHANGED], 0);
 
439
}
 
440
#endif
 
441
 
 
442
static void
 
443
xfpm_polkit_class_init (XfpmPolkitClass *klass)
 
444
{
 
445
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
446
 
 
447
    object_class->finalize = xfpm_polkit_finalize;
 
448
 
 
449
    signals [AUTH_CHANGED] = 
 
450
        g_signal_new ("auth-changed",
 
451
                      XFPM_TYPE_POLKIT,
 
452
                      G_SIGNAL_RUN_LAST,
 
453
                      G_STRUCT_OFFSET(XfpmPolkitClass, auth_changed),
 
454
                      NULL, NULL,
 
455
                      g_cclosure_marshal_VOID__VOID,
 
456
                      G_TYPE_NONE, 0, G_TYPE_NONE);
 
457
 
 
458
    g_type_class_add_private (klass, sizeof (XfpmPolkitPrivate));
 
459
}
 
460
 
 
461
static void
 
462
xfpm_polkit_init (XfpmPolkit *polkit)
 
463
{
 
464
    GError *error = NULL;
 
465
    
 
466
    polkit->priv = XFPM_POLKIT_GET_PRIVATE (polkit);
 
467
 
 
468
#ifdef ENABLE_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;
 
475
    
 
476
    polkit->priv->subject_gtype = 
 
477
        dbus_g_type_get_struct ("GValueArray", 
 
478
                                G_TYPE_STRING, 
 
479
                                dbus_g_type_get_map ("GHashTable", 
 
480
                                                     G_TYPE_STRING, 
 
481
                                                     G_TYPE_VALUE),
 
482
                                G_TYPE_INVALID);
 
483
    
 
484
    polkit->priv->details_gtype = dbus_g_type_get_map ("GHashTable", 
 
485
                                                       G_TYPE_STRING, 
 
486
                                                       G_TYPE_STRING);
 
487
    
 
488
    polkit->priv->result_gtype =
 
489
        dbus_g_type_get_struct ("GValueArray", 
 
490
                                G_TYPE_BOOLEAN, 
 
491
                                G_TYPE_BOOLEAN, 
 
492
                                dbus_g_type_get_map ("GHashTable", 
 
493
                                                     G_TYPE_STRING, 
 
494
                                                     G_TYPE_STRING),
 
495
                                G_TYPE_INVALID);
 
496
#endif /*ENABLE_POLKIT*/
 
497
    
 
498
    polkit->priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
499
    
 
500
    if ( error )
 
501
    {
 
502
        g_critical ("Error getting system bus connection : %s", error->message);
 
503
        g_error_free (error);
 
504
        goto out;
 
505
    }
 
506
 
 
507
#ifdef ENABLE_POLKIT
 
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");
 
513
    
 
514
    if (G_LIKELY (polkit->priv->proxy) )
 
515
    {
 
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);
 
519
    }
 
520
    else
 
521
    {
 
522
        g_warning ("Failed to create proxy for 'org.freedesktop.PolicyKit1'");
 
523
    }
 
524
#endif /*ENABLE_POLKIT*/
 
525
 
 
526
out:
 
527
    ;
 
528
}
 
529
 
 
530
static void
 
531
xfpm_polkit_finalize (GObject *object)
 
532
{
 
533
    XfpmPolkit *polkit;
 
534
 
 
535
    polkit = XFPM_POLKIT (object);
 
536
 
 
537
#ifdef ENABLE_POLKIT
 
538
    if ( polkit->priv->proxy )
 
539
    {
 
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);
 
543
    }
 
544
 
 
545
    if ( polkit->priv->subject_valid )
 
546
    {
 
547
        xfpm_polkit_free_data (polkit);
 
548
        if (polkit->priv->destroy_id != 0 )
 
549
            g_source_remove (polkit->priv->destroy_id);
 
550
    }
 
551
#endif /*ENABLE_POLKIT*/
 
552
 
 
553
 
 
554
    if ( polkit->priv->bus )
 
555
        dbus_g_connection_unref (polkit->priv->bus);
 
556
 
 
557
    G_OBJECT_CLASS (xfpm_polkit_parent_class)->finalize (object);
 
558
}
 
559
 
 
560
XfpmPolkit *
 
561
xfpm_polkit_get (void)
 
562
{
 
563
    static gpointer xfpm_polkit_obj = NULL;
 
564
    
 
565
    if ( G_LIKELY (xfpm_polkit_obj) )
 
566
    {
 
567
        g_object_ref (xfpm_polkit_obj);
 
568
    }
 
569
    else
 
570
    {
 
571
        xfpm_polkit_obj = g_object_new (XFPM_TYPE_POLKIT, NULL);
 
572
        g_object_add_weak_pointer (xfpm_polkit_obj, &xfpm_polkit_obj);
 
573
    }
 
574
    
 
575
    return XFPM_POLKIT (xfpm_polkit_obj);
 
576
}
 
577
 
 
578
gboolean xfpm_polkit_check_auth (XfpmPolkit *polkit, const gchar *action_id)
 
579
{
 
580
#ifdef ENABLE_POLKIT
 
581
    xfpm_polkit_init_data (polkit);
 
582
#endif
 
583
    return xfpm_polkit_check_auth_intern (polkit, action_id);
 
584
}