polkit-authorization-db.c 55.2 KB
Newer Older
1
2
3
4
5
6
7
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/***************************************************************************
 *
 * polkit-authorization-db.c : Represents the authorization database
 *
 * Copyright (C) 2007 David Zeuthen, <david@fubar.dk>
 *
8
9
10
11
12
13
14
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
15
 *
16
17
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
18
 *
19
20
21
22
23
24
25
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
27
28
29
30
31
32
33
34
35
 *
 **************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
36
#include <sys/stat.h>
37
#include <sys/types.h>
38
39
#include <sys/time.h>
#include <sys/wait.h>
40
#include <errno.h>
41
42
43
44
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
45
46
47
48

#include "polkit-debug.h"
#include "polkit-authorization-db.h"
#include "polkit-utils.h"
49
#include "polkit-private.h"
50
51
#include "polkit-test.h"
#include "polkit-private.h"
52

53
54
55
/**
 * SECTION:polkit-authorization-db
 * @title: Authorization Database
56
 * @short_description: Reading from and writing to the database storing authorizations
57
 *
58
59
60
61
62
 * This class presents an abstraction of the authorization database as
 * well as methods for reading and writing to it.
 *
 * The reading parts are in <literal>libpolkit</literal> and the
 * writing parts are in <literal>libpolkit-grant</literal>.
63
64
65
66
67
68
69
 *
 * Since: 0.7
 **/

/**
 * PolKitAuthorizationDB:
 *
70
71
 * Objects of this class are used to represent the authorization
 * database.
72
73
74
 *
 * Since: 0.7
 **/
75
76
77
struct _PolKitAuthorizationDB;

/* PolKitAuthorizationDB structure is defined in polkit/polkit-private.h */
78

79
static kit_bool_t
80
clear_auth (void *data, void *user_data, KitList *list)
81
82
83
84
85
86
{
        PolKitAuthorization *auth = (PolKitAuthorization *) data;
        polkit_authorization_unref (auth);
        return FALSE;
}

87
static void
David Zeuthen's avatar
David Zeuthen committed
88
_free_authlist (KitList *authlist)
89
90
{
        if (authlist != NULL) {
91
                kit_list_foreach (authlist, clear_auth, NULL);
David Zeuthen's avatar
David Zeuthen committed
92
                kit_list_free (authlist);
93
94
95
        }
}

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

/**
 * polkit_authorization_db_get_capabilities:
 *
 * Determine what capabilities the authorization backend has.
 *
 * Returns: Flags from the #PolKitAuthorizationDBCapability enumeration
 *
 * Since: 0.7
 */
PolKitAuthorizationDBCapability
polkit_authorization_db_get_capabilities (void)
{
        return POLKIT_AUTHORIZATION_DB_CAPABILITY_CAN_OBTAIN;
}

112
/**
113
 * _polkit_authorization_db_new:
114
115
116
117
118
119
120
121
 * 
 * Create a new #PolKitAuthorizationDB object.
 * 
 * Returns: the new object
 *
 * Since: 0.7
 **/
PolKitAuthorizationDB *
122
_polkit_authorization_db_new (void)
123
124
{
        PolKitAuthorizationDB *authdb;
125

David Zeuthen's avatar
David Zeuthen committed
126
127
128
        authdb = kit_new0 (PolKitAuthorizationDB, 1);
        if (authdb == NULL)
                goto oom;
129
        authdb->refcount = 1;
130
131
132

        /* set up the hashtable */
        _polkit_authorization_db_invalidate_cache (authdb);
David Zeuthen's avatar
David Zeuthen committed
133
oom:
134
135
136
        return authdb;
}

137
polkit_bool_t
138
139
140
141
_polkit_authorization_db_pfe_foreach   (PolKitPolicyCache *policy_cache, 
                                        PolKitPolicyCacheForeachFunc callback,
                                        void *user_data)
{
142
        return FALSE;
143
144
145
146
147
148
149
150
151
152
}

PolKitPolicyFileEntry* 
_polkit_authorization_db_pfe_get_by_id (PolKitPolicyCache *policy_cache, 
                                        const char *action_id)
{
        return NULL;
}


153
154
155
156
157
158
159
160
161
162
163
164
165
/**
 * polkit_authorization_db_ref:
 * @authdb: the object
 * 
 * Increase reference count.
 * 
 * Returns: the object
 *
 * Since: 0.7
 **/
PolKitAuthorizationDB *
polkit_authorization_db_ref (PolKitAuthorizationDB *authdb)
{
166
        kit_return_val_if_fail (authdb != NULL, authdb);
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        authdb->refcount++;
        return authdb;
}

/**
 * polkit_authorization_db_unref:
 * @authdb: the object
 * 
 * Decreases the reference count of the object. If it becomes zero,
 * the object is freed. Before freeing, reference counts on embedded
 * objects are decresed by one.
 *
 * Since: 0.7
 **/
void
polkit_authorization_db_unref (PolKitAuthorizationDB *authdb)
{
184
        kit_return_if_fail (authdb != NULL);
185
186
187
        authdb->refcount--;
        if (authdb->refcount > 0) 
                return;
188
189
        if (authdb->uid_to_authlist != NULL)
                kit_hash_unref (authdb->uid_to_authlist);
David Zeuthen's avatar
David Zeuthen committed
190
        kit_free (authdb);
191
192
193
194
195
196
197
198
199
200
201
202
203
}

/**
 * polkit_authorization_db_debug:
 * @authdb: the object
 * 
 * Print debug details
 *
 * Since: 0.7
 **/
void
polkit_authorization_db_debug (PolKitAuthorizationDB *authdb)
{
204
        kit_return_if_fail (authdb != NULL);
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
        _pk_debug ("PolKitAuthorizationDB: refcount=%d", authdb->refcount);
}

/**
 * polkit_authorization_db_validate:
 * @authdb: the object
 * 
 * Validate the object
 * 
 * Returns: #TRUE iff the object is valid.
 *
 * Since: 0.7
 **/
polkit_bool_t
polkit_authorization_db_validate (PolKitAuthorizationDB *authdb)
{
221
        kit_return_val_if_fail (authdb != NULL, FALSE);
222
223
224
225

        return TRUE;
}

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/**
 * _polkit_authorization_db_invalidate_cache:
 * @authdb: authorization database
 *
 * Tell the authorization database to invalidate any caches it might
 * employ. This is called by #PolKitContext whenever configuration or
 * anything else changes.
 *
 * Since: 0.7
 */
void
_polkit_authorization_db_invalidate_cache (PolKitAuthorizationDB *authdb)
{
        /* out with the old, in the with new */
        if (authdb->uid_to_authlist != NULL) {
241
                kit_hash_unref (authdb->uid_to_authlist);
242
                authdb->uid_to_authlist = NULL;
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
        }
}

/**
 * _authdb_get_auths_for_uid:
 * @authdb: authorization database
 * @uid: uid to get authorizations for. If -1 is passed authorizations
 * for all users will be returned.
 * @error: return location for error
 *
 * Internal function to get authorizations for a uid.
 *
 * Returns: A singly-linked list of #PolKitAuthorization
 * objects. Caller shall not free this list. Returns #NULL if either
 * calling process is not sufficiently privileged (error will be set)
 * or if there are no authorizations for the given uid.
 *
 * Since: 0.7
 */
262
static KitList *
263
_authdb_get_auths_for_uid (PolKitAuthorizationDB *authdb,
264
                           const uid_t            uid,
265
266
                           PolKitError          **error)
{
267
        KitList *ret;
268
        char *helper_argv[] = {NULL, NULL, NULL};
269
        int exit_status;
270
271
272
273
274
275
276
        char *standard_output;
        size_t len;
        off_t n;

        ret = NULL;
        standard_output = NULL;

277
278
279
280
281
282
283
284
285
286
287
288
289
#ifdef POLKIT_BUILD_TESTS
        char helper_buf[256];
        char *helper_bin_dir;
        if ((helper_bin_dir = getenv ("POLKIT_TEST_BUILD_DIR")) != NULL) {
                kit_assert ((size_t) snprintf (helper_buf, sizeof (helper_buf), "%s/src/polkit-dbus/polkit-read-auth-helper", helper_bin_dir) < sizeof (helper_buf));
                helper_argv[0] = helper_buf;
        } else {
                helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-read-auth-helper";
        }
#else
        helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-read-auth-helper";
#endif

290
        /* first, see if this is in the cache */
291
292
293
294
295
        if (authdb->uid_to_authlist != NULL) {
                ret = kit_hash_lookup (authdb->uid_to_authlist, (void *) uid, NULL);
                if (ret != NULL)
                        goto out;
        }
296

David Zeuthen's avatar
David Zeuthen committed
297
        helper_argv[1] = kit_strdup_printf ("%d", uid);
298
299
300
301
302
303
        if (helper_argv[1] == NULL) {
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_OUT_OF_MEMORY, 
                                        "No memory");
                goto out;
        }
304
305
306
307
308

        /* we need to do this through a setgid polkituser helper
         * because the auth file is readable only for uid 0 and gid
         * polkituser.
         */
309
        if (!kit_spawn_sync (NULL,             /* const char  *working_directory */
310
                             0,                /* flags */
311
312
313
314
315
316
                             helper_argv,      /* char       **argv */
                             NULL,             /* char       **envp */
                             NULL,             /* char        *stdin */
                             &standard_output, /* char       **stdout */
                             NULL,             /* char       **stderr */
                             &exit_status)) {  /* int         *exit_status */
317
318
319
320
321
322
323
324
325
                if (errno == ENOMEM) {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_OUT_OF_MEMORY, 
                                                "Error spawning read auth helper: OOM");
                } else {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_GENERAL_ERROR, 
                                                "Error spawning read auth helper: %m");
                }
326
327
328
329
                goto out;
        }

        if (!WIFEXITED (exit_status)) {
330
                kit_warning ("Read auth helper crashed!");
331
332
333
334
335
336
337
338
339
340
341
342
343
344
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_GENERAL_ERROR, 
                                        "Read auth helper crashed!");
                goto out;
        } else if (WEXITSTATUS(exit_status) != 0) {
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_NOT_AUTHORIZED_TO_READ_AUTHORIZATIONS_FOR_OTHER_USERS, 
                                        uid > 0 ?
                                        "uid %d is not authorized to read authorizations for uid %d (requires org.freedesktop.policykit.read)" : 
                                        "uid %d is not authorized to read all authorizations (requires org.freedesktop.policykit.read)",
                                        getuid (), uid);
                goto out;
        }

345
346
        //kit_warning ("standard_output='%s'", standard_output);

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
        if (standard_output != NULL) {
                uid_t uid2;
                len = strlen (standard_output);

                uid2 = uid;
                
                /* parse one line at a time (modifies standard_output in place) */
                n = 0;
                while (n < len) {
                        off_t m;
                        char *line;
                        PolKitAuthorization *auth;
                        
                        m = n;
                        while (m < len && standard_output[m] != '\0') {
                                if (standard_output[m] == '\n')
                                        break;
                                m++;
                        }
                        /* check EOF */
                        if (standard_output[m] == '\0')
368
                                break;
369
370
371
372
373
374
375
                        standard_output[m] = '\0';
                        
                        line = standard_output + n;
                        
                        if (strlen (line) >= 2 && strncmp (line, "#uid=", 5) == 0) {
                                uid2 = (uid_t) atoi (line + 5);
                        }
376
                        
377
378
                        if (strlen (line) >= 2 && line[0] != '#') {
                                auth = _polkit_authorization_new_for_uid (line, uid2);
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
                                if (auth == NULL) {
                                        if (errno == ENOMEM) {
                                                polkit_error_set_error (error, 
                                                                        POLKIT_ERROR_OUT_OF_MEMORY, 
                                                                        "No memory");
                                                _free_authlist (ret);
                                                ret = NULL;
                                                goto out;
                                        } else {
                                                kit_warning ("Skipping invalid authline '%s'", line);
                                        }
                                }

                                //kit_warning (" #got %s", line);

394
                                if (auth != NULL) {
395
                                        KitList *ret2;
396
397
398
                                        /* we need the authorizations in the chronological order... 
                                         * (TODO: optimized: prepend, then reverse after all items have been inserted)
                                         */
399
400
401
402
403
404
405
406
407
408
409
                                        ret2 = kit_list_append (ret, auth);
                                        if (ret2 == NULL) {
                                                polkit_error_set_error (error, 
                                                                        POLKIT_ERROR_OUT_OF_MEMORY, 
                                                                        "No memory");
                                                polkit_authorization_unref (auth);
                                                _free_authlist (ret);
                                                ret = NULL;
                                                goto out;
                                        }
                                        ret = ret2;
410
                                }
411
                        }
412
413
                        
                        n = m + 1;
414
415
416
                }
        }

417
418
419
420
421
422
423
424
425
426
427
        if (authdb->uid_to_authlist == NULL) {
                authdb->uid_to_authlist = kit_hash_new (kit_hash_direct_hash_func,
                                                        kit_hash_direct_equal_func,
                                                        NULL,
                                                        NULL,
                                                        NULL,
                                                        (KitFreeFunc) _free_authlist);
        }

        if (authdb->uid_to_authlist == NULL || 
            !kit_hash_insert (authdb->uid_to_authlist, (void *) uid, ret)) {
428
429
430
431
432
433
434
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_OUT_OF_MEMORY, 
                                        "No memory");
                _free_authlist (ret);
                ret = NULL;
                goto out;
        }
435
436

out:
David Zeuthen's avatar
David Zeuthen committed
437
438
        kit_free (helper_argv[1]);
        kit_free (standard_output);
439
440
441
442
443
444
445
446
447
448
449
450
        return ret;
}


static polkit_bool_t 
_internal_foreach (PolKitAuthorizationDB       *authdb,
                   PolKitAction                *action,
                   uid_t                        uid,
                   PolKitAuthorizationDBForeach cb,
                   void                        *user_data,
                   PolKitError                **error)
{
451
452
        KitList *l;
        KitList *auths;
453
        KitList *auths_copy;
454
455
456
        polkit_bool_t ret;
        char *action_id;

457
458
        kit_return_val_if_fail (authdb != NULL, FALSE);
        kit_return_val_if_fail (cb != NULL, FALSE);
459
460
461
462
463
464
465
466
467
468
469
470
471
472

        ret = FALSE;

        if (action == NULL) {
                action_id = NULL;
        } else {
                if (!polkit_action_get_action_id (action, &action_id))
                        goto out;
        }

        auths = _authdb_get_auths_for_uid (authdb, uid, error);
        if (auths == NULL)
                goto out;

473
474
475
476
        /* have to copy the list and ref the auths because the authdb
         * may disappear from under us due to revoke_if_one_shot...
         */
        auths_copy = kit_list_copy (auths);
477
478
479
480
        if (auths_copy == NULL) {
                polkit_error_set_error (error,
                                        POLKIT_ERROR_OUT_OF_MEMORY,
                                        "No memory");
481
                goto out;
482
        }
483
484
485
486
        for (l = auths_copy; l != NULL; l = l->next)
                polkit_authorization_ref ((PolKitAuthorization *) l->data);

        for (l = auths_copy; l != NULL; l = l->next) {
487
488
                PolKitAuthorization *auth = l->data;

489
490
491
492
493
                //kit_warning ("%d: action_id=%s uid=%d", 
                //             uid,
                //             polkit_authorization_get_action_id (auth),
                //             polkit_authorization_get_uid (auth));

494
495
496
497
498
499
500
501
                if (action_id != NULL) {
                        if (strcmp (polkit_authorization_get_action_id (auth), action_id) != 0) {
                                continue;
                        }
                }

                if (cb (authdb, auth, user_data)) {
                        ret = TRUE;
502
                        break;
503
504
505
                }
        }

506
507
508
509
        for (l = auths_copy; l != NULL; l = l->next)
                polkit_authorization_unref ((PolKitAuthorization *) l->data);
        kit_list_free (auths_copy);

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
out:
        return ret;
}


/**
 * polkit_authorization_db_foreach:
 * @authdb: authorization database
 * @cb: callback
 * @user_data: user data to pass to callback
 * @error: return location for error
 *
 * Iterate over all entries in the authorization database.
 *
 * Note that unless the calling process has the authorization
 * org.freedesktop.policykit.read this function may return an error.
 *
 * Returns: #TRUE if the callback returned #TRUE to stop iterating. If
 * #FALSE, either error may be set or the callback returns #FALSE on
 * every invocation.
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_foreach (PolKitAuthorizationDB       *authdb,
                                 PolKitAuthorizationDBForeach cb,
                                 void                        *user_data,
                                 PolKitError                **error)
{
        return _internal_foreach (authdb, NULL, -1, cb, user_data, error);
}

/**
 * polkit_authorization_db_foreach_for_uid:
 * @authdb: authorization database
 * @uid: user to get authorizations for
 * @cb: callback
 * @user_data: user data to pass to callback
 * @error: return location for error
 *
 * Iterate over all entries in the authorization database for a given
 * user.
 *
 * Note that if the calling process asks for authorizations for a
 * different uid than itself and it lacks the authorization
 * org.freedesktop.policykit.read this function may return an error.
 *
 * Returns: #TRUE if the callback returned #TRUE to stop iterating. If
 * #FALSE, either error may be set or the callback returns #FALSE on
 * every invocation.
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_foreach_for_uid (PolKitAuthorizationDB       *authdb,
                                         uid_t                        uid,
                                         PolKitAuthorizationDBForeach cb,
                                         void                        *user_data,
                                         PolKitError                **error)
{
        return _internal_foreach (authdb, NULL, uid, cb, user_data, error);
}

/**
 * polkit_authorization_db_foreach_for_action:
 * @authdb: authorization database
 * @action: action to get authorizations for
 * @cb: callback
 * @user_data: user data to pass to callback
 * @error: return location for error
 *
 * Iterate over all entries in the authorization database for a given
 * action.
 *
 * Note that unless the calling process has the authorization
 * org.freedesktop.policykit.read this function may return an error.
 *
 * Returns: #TRUE if the callback returned #TRUE to stop iterating. If
 * #FALSE, either error may be set or the callback returns #FALSE on
 * every invocation.
 *
 * Since: 0.7
 */
polkit_bool_t 
polkit_authorization_db_foreach_for_action (PolKitAuthorizationDB       *authdb,
                                            PolKitAction                *action,
                                            PolKitAuthorizationDBForeach cb,
                                            void                        *user_data,
                                            PolKitError                **error)
{
600
        kit_return_val_if_fail (action != NULL, FALSE);
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
        return _internal_foreach (authdb, action, -1, cb, user_data, error);
}

/**
 * polkit_authorization_db_foreach_for_action_for_uid:
 * @authdb: authorization database
 * @action: action to get authorizations for
 * @uid: user to get authorizations for
 * @cb: callback
 * @user_data: user data to pass to callback
 * @error: return location for error
 *
 * Iterate over all entries in the authorization database for a given
 * action and user.
 *
 * Note that if the calling process asks for authorizations for a
 * different uid than itself and it lacks the authorization
 * org.freedesktop.policykit.read this function may return an error.
 *
 * Returns: #TRUE if the callback returned #TRUE to stop iterating. If
 * #FALSE, either error may be set or the callback returns #FALSE on
 * every invocation.
 *
 * Since: 0.7
 */
polkit_bool_t 
polkit_authorization_db_foreach_for_action_for_uid (PolKitAuthorizationDB       *authdb,
                                                    PolKitAction                *action,
                                                    uid_t                        uid,
                                                    PolKitAuthorizationDBForeach cb,
                                                    void                        *user_data,
                                                    PolKitError                **error)
{
634
        kit_return_val_if_fail (action != NULL, FALSE);
635
636
637
638
639
640
641
642
643
        return _internal_foreach (authdb, action, uid, cb, user_data, error);
}


typedef struct {
        char *action_id;
        uid_t session_uid; 
        char *session_objpath;
        PolKitSession *session;
644
645
646

        polkit_bool_t *out_is_authorized;
        polkit_bool_t *out_is_negative_authorized;
647
648
} CheckDataSession;

649
650
651
652
653
654
655
656
657
658
659
660
661
static polkit_bool_t 
_check_constraint_session (PolKitAuthorization *auth, PolKitAuthorizationConstraint *authc, void *user_data)
{
        PolKitSession *session = (PolKitSession *) user_data;

        if (!polkit_authorization_constraint_check_session (authc, session))
                goto no_match;

        return FALSE;
no_match:
        return TRUE;
}

662
663
664
static polkit_bool_t 
_check_auth_for_session (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth, void *user_data)
{
665
        polkit_bool_t ret;
666
667
        uid_t pimp_uid;
        polkit_bool_t is_negative;
668
669
670
671
672
673
674
        CheckDataSession *cd = (CheckDataSession *) user_data;

        ret = FALSE;

        if (strcmp (polkit_authorization_get_action_id (auth), cd->action_id) != 0)
                goto no_match;

675
        if (polkit_authorization_constraints_foreach (auth, _check_constraint_session, cd->session))
676
677
678
679
                goto no_match;

        switch (polkit_authorization_get_scope (auth))
        {
680
        case POLKIT_AUTHORIZATION_SCOPE_PROCESS_ONE_SHOT:
681
682
683
684
685
686
687
688
689
690
691
692
        case POLKIT_AUTHORIZATION_SCOPE_PROCESS:
                goto no_match;

        case POLKIT_AUTHORIZATION_SCOPE_SESSION:
                if (strcmp (polkit_authorization_scope_session_get_ck_objref (auth), cd->session_objpath) != 0)
                        goto no_match;
                break;

        case POLKIT_AUTHORIZATION_SCOPE_ALWAYS:
                break;
        }

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
                is_negative = FALSE;

        if (is_negative) {
                *(cd->out_is_authorized) = FALSE;
                *(cd->out_is_negative_authorized) = TRUE;
        } else {
                *(cd->out_is_authorized) = TRUE;
                *(cd->out_is_negative_authorized) = FALSE;
        }

        /* keep iterating; we may find negative auths... */

        if (is_negative) {
                *(cd->out_is_authorized) = FALSE;
                *(cd->out_is_negative_authorized) = TRUE;
                /* it only takes a single negative auth to block things so stop iterating */
                ret = TRUE;
        } else {
                *(cd->out_is_authorized) = TRUE;
                *(cd->out_is_negative_authorized) = FALSE;
                /* keep iterating; we may find negative auths... */
        }
716
717
718
719

no_match:
        return ret;
}
720
721
722
723
724
725
726

/**
 * polkit_authorization_db_is_session_authorized:
 * @authdb: the authorization database
 * @action: the action to check for
 * @session: the session to check for
 * @out_is_authorized: return location
727
 * @out_is_negative_authorized: return location
728
 * @error: return location for error
729
 *
730
 * Looks in the authorization database and determine if processes from
731
732
733
734
735
 * the given session are authorized to do the given specific
 * action. If there is an authorization record that matches the
 * session, @out_is_authorized will be set to %TRUE. If there is a
 * negative authorization record matching the session
 * @out_is_negative_authorized will be set to %TRUE.
736
737
738
 *
 * Returns: #TRUE if the look up was performed; #FALSE if the caller
 * of this function lacks privileges to ask this question (e.g. asking
739
 * about a user that is not himself) or OOM (and @error will be set)
740
741
742
743
744
745
746
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_is_session_authorized (PolKitAuthorizationDB *authdb,
                                               PolKitAction          *action,
                                               PolKitSession         *session,
747
                                               polkit_bool_t         *out_is_authorized,
748
749
                                               polkit_bool_t         *out_is_negative_authorized,
                                               PolKitError          **error)
750
{
751
752
753
754
755
        polkit_bool_t ret;
        CheckDataSession cd;

        ret = FALSE;

756
757
758
759
        kit_return_val_if_fail (authdb != NULL, FALSE);
        kit_return_val_if_fail (action != NULL, FALSE);
        kit_return_val_if_fail (session != NULL, FALSE);
        kit_return_val_if_fail (out_is_authorized != NULL, FALSE);
760
761
762
763
764
765
766
767
768
769
770
771
772
773

        if (!polkit_action_get_action_id (action, &cd.action_id))
                return FALSE;

        if (!polkit_session_get_uid (session, &cd.session_uid))
                return FALSE;

        cd.session = session;

        if (!polkit_session_get_ck_objref (session, &cd.session_objpath) || cd.session_objpath == NULL)
                return FALSE;

        ret = TRUE;

774
775
        cd.out_is_authorized = out_is_authorized;
        cd.out_is_negative_authorized = out_is_negative_authorized;
776
        *out_is_authorized = FALSE;
777
778
        *out_is_negative_authorized = FALSE;

779
780
781
782
783
        if (polkit_authorization_db_foreach_for_uid (authdb,
                                                     cd.session_uid, 
                                                     _check_auth_for_session,
                                                     &cd,
                                                     NULL)) {
784
                ;
785
786
787
788
789
790
791
792
793
794
795
796
        }

        return ret;
}

typedef struct {
        char *action_id;
        uid_t caller_uid; 
        pid_t caller_pid;
        polkit_uint64_t caller_pid_start_time;
        char *session_objpath;
        PolKitCaller *caller;
797
        polkit_bool_t revoke_if_one_shot;
798
799
800

        polkit_bool_t *out_is_authorized;
        polkit_bool_t *out_is_negative_authorized;
801
802

        PolKitError *error;
803
804
} CheckData;

805
806
807
808
809
810
811
812
813
814
815
816
817
static polkit_bool_t 
_check_constraint_caller (PolKitAuthorization *auth, PolKitAuthorizationConstraint *authc, void *user_data)
{
        PolKitCaller *caller = (PolKitCaller *) user_data;

        if (!polkit_authorization_constraint_check_caller (authc, caller))
                goto no_match;

        return FALSE;
no_match:
        return TRUE;
}

818
819
820
static polkit_bool_t 
_check_auth_for_caller (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth, void *user_data)
{
821
        polkit_bool_t ret;
822
823
        uid_t pimp_uid;
        polkit_bool_t is_negative;
824
825
826
827
828
829
830
831
832
        pid_t caller_pid;
        polkit_uint64_t caller_pid_start_time;
        CheckData *cd = (CheckData *) user_data;

        ret = FALSE;

        if (strcmp (polkit_authorization_get_action_id (auth), cd->action_id) != 0)
                goto no_match;

833
        if (polkit_authorization_constraints_foreach (auth, _check_constraint_caller, cd->caller))
834
835
836
837
                goto no_match;

        switch (polkit_authorization_get_scope (auth))
        {
838
        case POLKIT_AUTHORIZATION_SCOPE_PROCESS_ONE_SHOT:
839
840
841
842
843
        case POLKIT_AUTHORIZATION_SCOPE_PROCESS:
                if (!polkit_authorization_scope_process_get_pid (auth, &caller_pid, &caller_pid_start_time))
                        goto no_match;
                if (!(caller_pid == cd->caller_pid && caller_pid_start_time == cd->caller_pid_start_time))
                        goto no_match;
844
845
846
847
848

                if (polkit_authorization_get_scope (auth) == POLKIT_AUTHORIZATION_SCOPE_PROCESS_ONE_SHOT) {

                        /* it's a match already; revoke if asked to do so */
                        if (cd->revoke_if_one_shot) {
849
850
                                cd->error = NULL;
                                if (!polkit_authorization_db_revoke_entry (authdb, auth, &(cd->error))) {
851
                                        //kit_warning ("Cannot revoke one-shot auth: %s: %s",
852
853
854
855
856
                                        //           polkit_error_get_error_name (cd->error),
                                        //           polkit_error_get_error_message (cd->error));
                                        /* stop iterating */
                                        ret = TRUE;
                                        goto no_match;
857
                                }
858
859
                                /* revoked; now purge internal cache */
                                _polkit_authorization_db_invalidate_cache (authdb);
860
861
                        }
                }
862
863
864
865
866
867
868
869
870
871
872
873
874
                break;

        case POLKIT_AUTHORIZATION_SCOPE_SESSION:
                if (cd->session_objpath == NULL)
                        goto no_match;
                if (strcmp (polkit_authorization_scope_session_get_ck_objref (auth), cd->session_objpath) != 0)
                        goto no_match;
                break;

        case POLKIT_AUTHORIZATION_SCOPE_ALWAYS:
                break;
        }

875
876
877
878
879
880
881
882
883
884
885
886
887
        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
                is_negative = FALSE;

        if (is_negative) {
                *(cd->out_is_authorized) = FALSE;
                *(cd->out_is_negative_authorized) = TRUE;
                /* it only takes a single negative auth to block things so stop iterating */
                ret = TRUE;
        } else {
                *(cd->out_is_authorized) = TRUE;
                *(cd->out_is_negative_authorized) = FALSE;
                /* keep iterating; we may find negative auths... */
        }
888

889

890
891
no_match:
        return ret;
892
893
894
895
896
897
898
}

/**
 * polkit_authorization_db_is_caller_authorized:
 * @authdb: the authorization database
 * @action: the action to check for
 * @caller: the caller to check for
899
900
 * @revoke_if_one_shot: Whether to revoke one-shot authorizations. See
 * discussion in polkit_context_is_caller_authorized() for details.
901
 * @out_is_authorized: return location
902
 * @out_is_negative_authorized: return location
903
 * @error: return location for error
904
905
 *
 * Looks in the authorization database if the given caller is
906
907
908
909
 * authorized to do the given action. If there is an authorization
 * record that matches the caller, @out_is_authorized will be set to
 * %TRUE. If there is a negative authorization record matching the
 * caller @out_is_negative_authorized will be set to %TRUE.
910
911
912
 *
 * Returns: #TRUE if the look up was performed; #FALSE if the caller
 * of this function lacks privileges to ask this question (e.g. asking
913
 * about a user that is not himself) or if OOM (and @error will be set)
914
915
916
917
918
919
920
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_is_caller_authorized (PolKitAuthorizationDB *authdb,
                                              PolKitAction          *action,
                                              PolKitCaller          *caller,
921
                                              polkit_bool_t          revoke_if_one_shot,
922
                                              polkit_bool_t         *out_is_authorized,
923
924
                                              polkit_bool_t         *out_is_negative_authorized,
                                              PolKitError          **error)
925
{
926
927
928
        PolKitSession *session;
        polkit_bool_t ret;
        CheckData cd;
929
        PolKitError *error2;
930
931
932

        ret = FALSE;

933
934
935
936
        kit_return_val_if_fail (authdb != NULL, FALSE);
        kit_return_val_if_fail (action != NULL, FALSE);
        kit_return_val_if_fail (caller != NULL, FALSE);
        kit_return_val_if_fail (out_is_authorized != NULL, FALSE);
937
938

        if (!polkit_action_get_action_id (action, &cd.action_id))
939
                goto out;
940
941

        if (!polkit_caller_get_pid (caller, &cd.caller_pid))
942
                goto out;
943
944

        if (!polkit_caller_get_uid (caller, &cd.caller_uid))
945
                goto out;
946
947

        cd.caller = caller;
948
        cd.revoke_if_one_shot = revoke_if_one_shot;
949
        cd.error = NULL;
950

951
        cd.caller_pid_start_time = polkit_sysdeps_get_start_time_for_pid (cd.caller_pid);
952
953
954
955
956
957
958
959
960
961
962
963
        if (cd.caller_pid_start_time == 0) {
                if (errno == ENOMEM) {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_OUT_OF_MEMORY, 
                                                "No memory");
                } else {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_GENERAL_ERROR, 
                                                "Errno %d: %m", errno);
                }
                goto out;
        }
964
965
966
967
968
969
970
971

        /* Caller does not _have_ to be member of a session */
        cd.session_objpath = NULL;
        if (polkit_caller_get_ck_session (caller, &session) && session != NULL) {
                if (!polkit_session_get_ck_objref (session, &cd.session_objpath))
                        cd.session_objpath = NULL;
        }

972
973
        cd.out_is_authorized = out_is_authorized;
        cd.out_is_negative_authorized = out_is_negative_authorized;
974
        *out_is_authorized = FALSE;
975
976
        *out_is_negative_authorized = FALSE;

977
        error2 = NULL;
978
979
980
981
        if (polkit_authorization_db_foreach_for_uid (authdb,
                                                     cd.caller_uid, 
                                                     _check_auth_for_caller,
                                                     &cd,
982
                                                     &error2)) {
983
                ;
984
985
        }

986
987
988
989
990
991
992
993
994
        if (polkit_error_is_set (error2)) {
                if (error != NULL) {
                        *error = error2;
                } else {
                        polkit_error_free (error2);
                }
                goto out;
        }

995
996
997
998
999
1000
1001
1002
1003
        if (polkit_error_is_set (cd.error)) {
                if (error != NULL) {
                        *error = cd.error;
                } else {
                        polkit_error_free (cd.error);
                }
                goto out;
        }

1004
1005
1006
        ret = TRUE;

out:
1007
1008
        return ret;
}
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

/**
 * polkit_authorization_db_revoke_entry:
 * @authdb: the authorization database
 * @auth: the authorization to revoke
 * @error: return location for error
 *
 * Removes an authorization from the authorization database. This uses
 * a privileged helper /usr/libexec/polkit-revoke-helper.
 *
 * Returns: #TRUE if the authorization was revoked, #FALSE otherwise and error is set
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_revoke_entry (PolKitAuthorizationDB *authdb,
                                      PolKitAuthorization   *auth,
                                      PolKitError           **error)
{
1028
        char *helper_argv[] = {NULL, "", NULL, NULL, NULL};
1029
        const char *auth_file_entry;
1030
1031
        polkit_bool_t ret;
        int exit_status;
1032
1033
1034

        ret = FALSE;

1035
1036
        kit_return_val_if_fail (authdb != NULL, FALSE);
        kit_return_val_if_fail (auth != NULL, FALSE);
1037
1038
1039
1040

        auth_file_entry = _polkit_authorization_get_authfile_entry (auth);
        //g_debug ("should delete line '%s'", auth_file_entry);

1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
#ifdef POLKIT_BUILD_TESTS
        char helper_buf[256];
        char *helper_bin_dir;
        if ((helper_bin_dir = getenv ("POLKIT_TEST_BUILD_DIR")) != NULL) {
                kit_assert ((size_t) snprintf (helper_buf, sizeof (helper_buf), "%s/src/polkit-grant/polkit-revoke-helper", helper_bin_dir) < sizeof (helper_buf));
                helper_argv[0] = helper_buf;
        } else {
                helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-revoke-helper";
        }
#else
        helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-revoke-helper";
#endif

1054
1055
        helper_argv[1] = (char *) auth_file_entry;
        helper_argv[2] = "uid";
David Zeuthen's avatar
David Zeuthen committed
1056
        helper_argv[3] = kit_strdup_printf ("%d", polkit_authorization_get_uid (auth));
1057
1058
1059
1060
1061
1062
        if (helper_argv[3] == NULL) {
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_OUT_OF_MEMORY, 
                                        "Out of memory");
                goto out;
        }
1063

1064
        if (!kit_spawn_sync (NULL,             /* const char  *working_directory */
1065
                             0,                /* flags */
1066
1067
1068
1069
1070
1071
                             helper_argv,      /* char       **argv */
                             NULL,             /* char       **envp */
                             NULL,             /* char        *stdin */
                             NULL,             /* char       **stdout */
                             NULL,             /* char       **stderr */
                             &exit_status)) {  /* int         *exit_status */
1072
1073
1074
1075
1076
1077
1078
1079
1080
                if (errno == ENOMEM) {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_OUT_OF_MEMORY, 
                                                "Error spawning revoke helper: OOM");
                } else {
                        polkit_error_set_error (error, 
                                                POLKIT_ERROR_GENERAL_ERROR, 
                                                "Error spawning revoke helper: %m");
                }
1081
1082
1083
1084
                goto out;
        }

        if (!WIFEXITED (exit_status)) {
1085
                kit_warning ("Revoke helper crashed!");
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_GENERAL_ERROR, 
                                        "Revoke helper crashed!");
                goto out;
        } else if (WEXITSTATUS(exit_status) != 0) {
                polkit_error_set_error (error, 
                                        POLKIT_ERROR_NOT_AUTHORIZED_TO_REVOKE_AUTHORIZATIONS_FROM_OTHER_USERS, 
                                        "uid %d is not authorized to revoke authorizations from uid %d (requires org.freedesktop.policykit.revoke)",
                                        getuid (), polkit_authorization_get_uid (auth));
        } else {
                ret = TRUE;
        }
        
out:
David Zeuthen's avatar
David Zeuthen committed
1100
        kit_free (helper_argv[3]);
1101
1102
        return ret;
}
1103

1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
static polkit_bool_t
_check_self_block_foreach (PolKitAuthorizationDB *authdb,
                           PolKitAuthorization   *auth, 
                           void                  *user_data)
{
        polkit_bool_t *is_self_blocked = (polkit_bool_t *) user_data;
        polkit_bool_t is_negative;
        uid_t pimp_uid;
        polkit_bool_t ret;

        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
                is_negative = FALSE;

        if (is_negative) {
                if (pimp_uid == getuid ()) {
                        *is_self_blocked = TRUE;
                        /* can't stop iterating.. there may be another one who blocked us too! */
                } else {
                        *is_self_blocked = FALSE;
                        ret = TRUE;
                        /* nope; someone else blocked us.. that's enough to ruin it */
                }                        
        }
        
        return ret;
}

/**
 * polkit_authorization_db_is_uid_blocked_by_self:
 * @authdb: the authorization database
 * @action: the action to check for
 * @uid: the user to check for
 * @error: return location for error
 *
 * Determine whether there exists negative authorizations for the
 * particular uid on the given action and whether those negative
 * authorization are "granted" by the uid itself.
 *
 * If uid is different from getuid(), e.g. if the calling process asks
 * for auths of another user this function will set an error if the
 * calling user is not authorized for org.freedesktop.policykit.read.
 *
 * Returns: Result of computation described above; if error is set
 * will return %FALSE.
 *
 * Since: 0.7
 */
polkit_bool_t
polkit_authorization_db_is_uid_blocked_by_self (PolKitAuthorizationDB *authdb,
                                                PolKitAction          *action,
                                                uid_t                  uid,
                                                PolKitError          **error)
{
        polkit_bool_t is_self_blocked;

        kit_return_val_if_fail (authdb != NULL, FALSE);
        kit_return_val_if_fail (action != NULL, FALSE);
                                
        is_self_blocked = FALSE;
        polkit_authorization_db_foreach_for_action_for_uid (authdb,
                                                            action,
                                                            uid,
                                                            _check_self_block_foreach,
                                                            &is_self_blocked,
                                                            error);

        return is_self_blocked;
}



1175
1176
1177
1178
1179
1180
1181
#ifdef POLKIT_BUILD_TESTS

static polkit_bool_t
_run_test (void)
{
        PolKitAuthorizationDB *adb;
        const char test_passwd[] = 
1182
1183
1184
1185
1186
                "root:x:0:0:PolKit root user:/root:/bin/bash\n"
                POLKIT_USER ":x:50400:50400:PolKit user:/:/sbin/nologin\n"
                "pu1:x:50401:50401:PolKit Test user 0:/home/polkittest1:/bin/bash\n"
                "pu2:x:50402:50402:PolKit Test user 1:/home/polkittest2:/bin/bash\n"
                "pu3:x:50403:50403:PolKit Test user 2:/home/polkittest3:/bin/bash\n";
1187
1188
1189
        const char test_pu1_run[] =
                "";
        const char test_pu1_lib[] =
1190
                "scope=grant:action-id=org.freedesktop.policykit.read:when=1194634242:granted-by=0\n";
1191
1192
1193
1194
        const char test_pu2_run[] =
                "";
        const char test_pu2_lib[] =
                "";
1195
        char test_pu3_run[512];
1196
1197
1198
1199
        const char test_pu3_lib[] =
                "";
        PolKitCaller *caller;
        PolKitAction *action;
1200
        PolKitSession *session;
1201
1202
1203
        polkit_bool_t is_auth;
        polkit_bool_t is_neg;
        PolKitError *error;
1204
1205
        polkit_uint64_t start_time;

1206
1207
1208
1209

        adb = NULL;
        caller = NULL;
        action = NULL;
1210
        session = NULL;
1211
1212
1213
1214
1215
1216

        start_time = polkit_sysdeps_get_start_time_for_pid (getpid ());
        if (start_time == 0)
                goto out;
        
        if (snprintf (test_pu3_run, sizeof (test_pu3_run), 
1217
1218
1219
                      "scope=process:pid=%d:pid-start-time=%lld:action-id=org.example.per-process:when=1196307507:auth-as=500\n"
                      "scope=process-one-shot:pid=%d:pid-start-time=%lld:action-id=org.example.per-process-one-shot:when=1196307507:auth-as=500\n"
                      "scope=session:session-id=%%2FSession1:action-id=org.example.per-session:when=1196307507:auth-as=500\n",
1220
1221
1222
                      getpid (), start_time,
                      getpid (), start_time) >= (int) sizeof (test_pu3_run))
                goto fail;
1223
1224
1225
1226
        
        if (setenv ("POLKIT_TEST_LOCALSTATE_DIR", TEST_DATA_DIR "authdb-test", 1) != 0)
                goto fail;

1227
1228
1229
        if (setenv ("POLKIT_TEST_BUILD_DIR", TEST_BUILD_DIR, 1) != 0)
                goto fail;

1230
        if (setenv ("KIT_TEST_PASSWD_FILE", TEST_DATA_DIR "authdb-test/passwd", 1) != 0)
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
                goto fail;

        /* create test users */
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/passwd", 0644, 
                                    test_passwd, sizeof (test_passwd) - 1))
                goto out;

        /* seed the authdb with known defaults */
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/run/PolicyKit/user-pu1.auths", 0644, 
                                    test_pu1_run, sizeof (test_pu1_run) - 1))
                goto out;
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/lib/PolicyKit/user-pu1.auths", 0644, 
                                    test_pu1_lib, sizeof (test_pu1_lib) - 1))
                goto out;
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/run/PolicyKit/user-pu2.auths", 0644, 
                                    test_pu2_run, sizeof (test_pu2_run) - 1))
                goto out;
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/lib/PolicyKit/user-pu2.auths", 0644, 
                                    test_pu2_lib, sizeof (test_pu2_lib) - 1))
                goto out;
1251
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/run/PolicyKit/user-pu3.auths", 0644, 
1252
                                    test_pu3_run, strlen (test_pu3_run)))
1253
1254
1255
1256
                goto out;
        if (!kit_file_set_contents (TEST_DATA_DIR "authdb-test/lib/PolicyKit/user-pu3.auths", 0644, 
                                    test_pu3_lib, sizeof (test_pu3_lib) - 1))
                goto out;
1257
1258
1259
1260

        if ((adb = _polkit_authorization_db_new ()) == NULL)
                goto out;

1261
1262
1263
1264
1265
1266
1267

        if ((action = polkit_action_new ()) == NULL)
                goto out;
        if ((caller = polkit_caller_new ()) == NULL)
                goto out;
        kit_assert (polkit_caller_set_pid (caller, getpid ()));

1268
1269
1270
        /* initialize all pretend environment variables */
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_CK_SESSION_OBJPATH", "", 1) != 0)
                goto fail;
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285

        /*
         * test: "org.freedesktop.policykit.read" 
         */
        if (!polkit_action_set_action_id (action, "org.freedesktop.policykit.read"))
                goto out;

        /* test: pu1 has the auth org.freedesktop.policykit.read */
        kit_assert (polkit_caller_set_uid (caller, 50401));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50401", 1) != 0)
                goto fail;
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && is_auth && !is_neg);
        } else {
1286
1287
1288
                //kit_warning ("%p: %d: %s: %s", 
                //             error, 
                //             polkit_error_get_error_code (error), 
1289
                //             polkit_error_get_error_name (error),
1290
                //             polkit_error_get_error_message (error));
1291
1292
1293
1294
1295
1296
1297
1298
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }

        /* test: pu2 does not have the auth org.freedesktop.policykit.read */
        kit_assert (polkit_caller_set_uid (caller, 50402));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50402", 1) != 0)
1299
                goto fail;
1300
1301
1302
1303
1304
1305
1306
1307
1308
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error));
                kit_assert (!is_auth && !is_neg);
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }
1309

1310
1311
1312
        /************************/
        /* INVALIDATE THE CACHE */
        /************************/
1313
        _polkit_authorization_db_invalidate_cache (adb);
1314

1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
        /* test: pu1 can check that pu2 does not have the auth org.freedesktop.policykit.read */
        kit_assert (polkit_caller_set_uid (caller, 50402));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50401", 1) != 0)
                goto fail;
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && !is_auth && !is_neg);
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }
1327

1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
        /* test: pu2 cannot check if pu1 have the auth org.freedesktop.policykit.read */
        kit_assert (polkit_caller_set_uid (caller, 50401));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50402", 1) != 0)
                goto fail;
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_warning ("pu2 shouldn't be able to read auths for pu1: %d %d", is_auth, is_neg);
                goto fail;
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            (polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY ||
                             polkit_error_get_error_code (error) == POLKIT_ERROR_NOT_AUTHORIZED_TO_READ_AUTHORIZATIONS_FOR_OTHER_USERS));
                polkit_error_free (error);
        }

1343
        /* test: pu3 is authorized for org.example.per-process for just this process id */
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
        if (!polkit_action_set_action_id (action, "org.example.per-process"))
                goto out;

        kit_assert (polkit_caller_set_uid (caller, 50403));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50403", 1) != 0)
                goto fail;
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && is_auth && !is_neg);
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }

        /* test: pu3 is authorized for org.example.per-process-one-shot just once */
        if (!polkit_action_set_action_id (action, "org.example.per-process-one-shot"))
                goto out;

        kit_assert (polkit_caller_set_uid (caller, 50403));
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_UID", "50403", 1) != 0)
                goto fail;
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, TRUE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && is_auth && !is_neg);

1370
1371
1372
                /************************/
                /* INVALIDATE THE CACHE */
                /************************/
1373
1374
1375
1376
1377
1378
1379
1380
                _polkit_authorization_db_invalidate_cache (adb);

                if (polkit_authorization_db_is_caller_authorized (adb, action, caller, TRUE, &is_auth, &is_neg, &error)) {
                        if (is_auth || is_neg) {
                                kit_warning ("pu3 shouldn't be authorized for something twice: %d %d", is_auth, is_neg);
                                goto fail;
                        }
                } else {
1381
1382
1383
                        kit_assert (polkit_error_is_set (error));
                        kit_assert (polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                        polkit_error_free (error);
1384
1385
1386
1387
1388
1389
1390
                }
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }

1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
        if ((session = polkit_session_new ()) == NULL)
                goto out;

        /* test: pu3 only in the right session is authorized for org.example.per-session */
        if (!polkit_action_set_action_id (action, "org.example.per-session"))
                goto out;

        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_CK_SESSION_OBJPATH", "/Session1", 1) != 0)
                goto fail;
        kit_assert (polkit_session_set_ck_is_local (session, TRUE));
        if (!polkit_session_set_ck_objref (session, "/Session1"))
                goto out;
        kit_assert (polkit_caller_set_ck_session (caller, session));
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && is_auth && !is_neg);
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }
        
        if (setenv ("POLKIT_TEST_PRETEND_TO_BE_CK_SESSION_OBJPATH", "/Session2", 1) != 0)
                goto fail;
        if (!polkit_session_set_ck_objref (session, "/Session2"))
                goto out;
        kit_assert (polkit_session_set_ck_is_local (session, TRUE));
        kit_assert (polkit_caller_set_ck_session (caller, session));
        error = NULL;
        if (polkit_authorization_db_is_caller_authorized (adb, action, caller, FALSE, &is_auth, &is_neg, &error)) {
                kit_assert (! polkit_error_is_set (error) && !is_auth && !is_neg);
        } else {
                kit_assert (polkit_error_is_set (error) && 
                            polkit_error_get_error_code (error) == POLKIT_ERROR_OUT_OF_MEMORY);
                polkit_error_free (error);
        }
        
1428
out:
1429
1430
1431
1432
1433
1434
1435

        if (action != NULL)
                polkit_action_unref (action);

        if (caller != NULL)
                polkit_caller_unref (caller);

1436
1437
1438
        if (session != NULL)
                polkit_session_unref (session);

1439
1440
1441
1442
1443
1444
1445
1446
        if (adb != NULL) {
                polkit_authorization_db_debug (adb);
                polkit_authorization_db_validate (adb);
                polkit_authorization_db_ref (adb);
                polkit_authorization_db_unref (adb);
                polkit_authorization_db_unref (adb);
        }

1447
1448
1449
        if (unsetenv ("POLKIT_TEST_PRETEND_TO_BE_UID") != 0)
                goto fail;

1450
1451
1452
1453
1454
1455
1456
1457
1458
        if (unsetenv ("POLKIT_TEST_PRETEND_TO_BE_CK_SESSION_OBJPATH") != 0)
                goto fail;

        if (unsetenv ("POLKIT_TEST_PRETEND_TO_BE_SELINUX_CONTEXT") != 0)
                goto fail;

        if (unsetenv ("POLKIT_TEST_PRETEND_TO_BE_PID") != 0)
                goto fail;

1459
1460
1461
        if (unsetenv ("POLKIT_TEST_LOCALSTATE_DIR") != 0)
                goto fail;

1462
1463
1464
        if (unsetenv ("POLKIT_TEST_BUILD_DIR") != 0)
                goto fail;

1465
        if (unsetenv ("KIT_TEST_PASSWD_FILE") != 0)
1466
1467
1468
1469
1470
1471
1472
1473
                goto fail;

        return TRUE;
fail:
        return FALSE;
}


1474
KitTest _test_authorization_db = {
1475
1476
1477
1478
1479
1480
1481
        "polkit_authorization_db",
        NULL,
        NULL,
        _run_test
};

#endif /* POLKIT_BUILD_TESTS */