1 /*
2 * Copyright (C) 2008 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Author: David Zeuthen <davidz@redhat.com>
20 */
21
22 #include "config.h"
23 #include <errno.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #ifdef HAVE_NETGROUP_H
27 #include <netgroup.h>
28 #else
29 #include <netdb.h>
30 #endif
31 #include <string.h>
32 #include <glib/gstdio.h>
33 #include <locale.h>
34
35 #include <polkit/polkit.h>
36 #include "polkitbackendinteractiveauthority.h"
37 #include "polkitbackendactionpool.h"
38 #include "polkitbackendsessionmonitor.h"
39
40 #include <polkit/polkitprivate.h>
41
42 /**
43 * SECTION:polkitbackendinteractiveauthority
44 * @title: PolkitBackendInteractiveAuthority
45 * @short_description: Interactive Authority
46 * @stability: Unstable
47 *
48 * An subclass of #PolkitBackendAuthority that supports interaction
49 * with authentication agents.
50 */
51
52 /* ---------------------------------------------------------------------------------------------------- */
53
54 typedef struct TemporaryAuthorizationStore TemporaryAuthorizationStore;
55
56 static TemporaryAuthorizationStore *temporary_authorization_store_new (PolkitBackendInteractiveAuthority *authority);
57 static void temporary_authorization_store_free (TemporaryAuthorizationStore *store);
58
59 static gboolean temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store,
60 PolkitSubject *subject,
61 const gchar *action_id,
62 const gchar **out_tmp_authz_id);
63
64 static const gchar *temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store,
65 PolkitSubject *subject,
66 PolkitSubject *session,
67 const gchar *action_id);
68
69 static void temporary_authorization_store_remove_authorizations_for_system_bus_name (TemporaryAuthorizationStore *store,
70 const gchar *name);
71
72 /* ---------------------------------------------------------------------------------------------------- */
73
74 struct AuthenticationAgent;
75 typedef struct AuthenticationAgent AuthenticationAgent;
76
77 struct AuthenticationSession;
78 typedef struct AuthenticationSession AuthenticationSession;
79
80 typedef void (*AuthenticationAgentCallback) (AuthenticationAgent *agent,
81 PolkitSubject *subject,
82 PolkitIdentity *user_of_subject,
83 PolkitSubject *caller,
84 PolkitBackendInteractiveAuthority *authority,
85 const gchar *action_id,
86 PolkitDetails *details,
87 PolkitImplicitAuthorization implicit_authorization,
88 gboolean authentication_success,
89 gboolean was_dismissed,
90 PolkitIdentity *authenticated_identity,
91 gpointer user_data);
92
93 static AuthenticationAgent *authentication_agent_ref (AuthenticationAgent *agent);
94 static void authentication_agent_unref (AuthenticationAgent *agent);
95
96 static void authentication_agent_initiate_challenge (AuthenticationAgent *agent,
97 PolkitSubject *subject,
98 PolkitIdentity *user_of_subject,
99 PolkitBackendInteractiveAuthority *authority,
100 const gchar *action_id,
101 PolkitDetails *details,
102 PolkitSubject *caller,
103 PolkitImplicitAuthorization implicit_authorization,
104 GCancellable *cancellable,
105 AuthenticationAgentCallback callback,
106 gpointer user_data);
107
108 static PolkitSubject *authentication_agent_get_scope (AuthenticationAgent *agent);
109
110 static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authority,
111 PolkitSubject *subject);
112
113
114 static AuthenticationSession *get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority,
115 uid_t uid,
116 const gchar *cookie);
117
118 static GList *get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendInteractiveAuthority *authority,
119 const gchar *system_bus_unique_name);
120
121 static void authentication_session_cancel (AuthenticationSession *session);
122
123 /* ---------------------------------------------------------------------------------------------------- */
124
125 static void polkit_backend_interactive_authority_system_bus_name_owner_changed (PolkitBackendInteractiveAuthority *authority,
126 const gchar *name,
127 const gchar *old_owner,
128 const gchar *new_owner);
129
130 static GList *polkit_backend_interactive_authority_enumerate_actions (PolkitBackendAuthority *authority,
131 PolkitSubject *caller,
132 const gchar *locale,
133 GError **error);
134
135 static void polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority,
136 PolkitSubject *caller,
137 PolkitSubject *subject,
138 const gchar *action_id,
139 PolkitDetails *details,
140 PolkitCheckAuthorizationFlags flags,
141 GCancellable *cancellable,
142 GAsyncReadyCallback callback,
143 gpointer user_data);
144
145 static PolkitAuthorizationResult *polkit_backend_interactive_authority_check_authorization_finish (
146 PolkitBackendAuthority *authority,
147 GAsyncResult *res,
148 GError **error);
149
150 static PolkitAuthorizationResult *check_authorization_sync (PolkitBackendAuthority *authority,
151 PolkitSubject *caller,
152 PolkitSubject *subject,
153 const gchar *action_id,
154 PolkitDetails *details,
155 PolkitCheckAuthorizationFlags flags,
156 PolkitImplicitAuthorization *out_implicit_authorization,
157 gboolean checking_imply,
158 GError **error);
159
160 static gboolean polkit_backend_interactive_authority_register_authentication_agent (PolkitBackendAuthority *authority,
161 PolkitSubject *caller,
162 PolkitSubject *subject,
163 const gchar *locale,
164 const gchar *object_path,
165 GVariant *options,
166 GError **error);
167
168 static gboolean polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBackendAuthority *authority,
169 PolkitSubject *caller,
170 PolkitSubject *subject,
171 const gchar *object_path,
172 GError **error);
173
174 static gboolean polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority *authority,
175 PolkitSubject *caller,
176 uid_t uid,
177 const gchar *cookie,
178 PolkitIdentity *identity,
179 GError **error);
180
181 static GList *polkit_backend_interactive_authority_enumerate_temporary_authorizations (PolkitBackendAuthority *authority,
182 PolkitSubject *caller,
183 PolkitSubject *subject,
184 GError **error);
185
186
187 static gboolean polkit_backend_interactive_authority_revoke_temporary_authorizations (PolkitBackendAuthority *authority,
188 PolkitSubject *caller,
189 PolkitSubject *subject,
190 GError **error);
191
192 static gboolean polkit_backend_interactive_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority,
193 PolkitSubject *caller,
194 const gchar *id,
195 GError **error);
196
197
198 /* ---------------------------------------------------------------------------------------------------- */
199
200 typedef struct
201 {
202 PolkitBackendActionPool *action_pool;
203
204 PolkitBackendSessionMonitor *session_monitor;
205
206 TemporaryAuthorizationStore *temporary_authorization_store;
207
208 /* Maps from PolkitSubject* to AuthenticationAgent* - currently the
209 * following PolkitSubject-derived types are used
210 *
211 * - PolkitSystemBusName - for authentication agents handling interaction for a single well-known name
212 * - typically pkexec(1) launched via e.g. ssh(1) or login(1)
213 *
214 * - PolkitUnixSession - for authentication agents handling interaction for a whole login session
215 * - typically a desktop environment session
216 *
217 */
218 GHashTable *hash_scope_to_authentication_agent;
219
220 GDBusConnection *system_bus_connection;
221 guint name_owner_changed_signal_id;
222
223 guint64 agent_serial;
224 } PolkitBackendInteractiveAuthorityPrivate;
225
226 /* ---------------------------------------------------------------------------------------------------- */
227
228 G_DEFINE_TYPE (PolkitBackendInteractiveAuthority,
229 polkit_backend_interactive_authority,
230 POLKIT_BACKEND_TYPE_AUTHORITY);
231
232 #define POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY, PolkitBackendInteractiveAuthorityPrivate))
233
234 static gboolean
identity_is_root_user(PolkitIdentity * user)235 identity_is_root_user (PolkitIdentity *user)
236 {
237 if (!POLKIT_IS_UNIX_USER (user))
238 return FALSE;
239 return polkit_unix_user_get_uid (POLKIT_UNIX_USER (user)) == 0;
240 }
241
242 /* ---------------------------------------------------------------------------------------------------- */
243
244 static void
action_pool_changed(PolkitBackendActionPool * action_pool,PolkitBackendInteractiveAuthority * authority)245 action_pool_changed (PolkitBackendActionPool *action_pool,
246 PolkitBackendInteractiveAuthority *authority)
247 {
248 g_signal_emit_by_name (authority, "changed");
249 }
250
251
252 /* ---------------------------------------------------------------------------------------------------- */
253
254 static void
on_name_owner_changed_signal(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)255 on_name_owner_changed_signal (GDBusConnection *connection,
256 const gchar *sender_name,
257 const gchar *object_path,
258 const gchar *interface_name,
259 const gchar *signal_name,
260 GVariant *parameters,
261 gpointer user_data)
262 {
263 PolkitBackendInteractiveAuthority *authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (user_data);
264 const gchar *name;
265 const gchar *old_owner;
266 const gchar *new_owner;
267
268 g_variant_get (parameters,
269 "(&s&s&s)",
270 &name,
271 &old_owner,
272 &new_owner);
273
274 polkit_backend_interactive_authority_system_bus_name_owner_changed (authority,
275 name,
276 old_owner,
277 new_owner);
278 }
279
280 /* ---------------------------------------------------------------------------------------------------- */
281
282 static void
on_session_monitor_changed(PolkitBackendSessionMonitor * monitor,gpointer user_data)283 on_session_monitor_changed (PolkitBackendSessionMonitor *monitor,
284 gpointer user_data)
285 {
286 PolkitBackendInteractiveAuthority *authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (user_data);
287 g_signal_emit_by_name (authority, "changed");
288 }
289
290 static void
polkit_backend_interactive_authority_init(PolkitBackendInteractiveAuthority * authority)291 polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *authority)
292 {
293 PolkitBackendInteractiveAuthorityPrivate *priv;
294 GFile *directory;
295 GError *error;
296
297 /* Force registering error domain */
298 (void)POLKIT_ERROR;
299
300 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
301
302 directory = g_file_new_for_path (PACKAGE_DATA_DIR "/polkit-1/actions");
303 priv->action_pool = polkit_backend_action_pool_new (directory);
304 g_object_unref (directory);
305 g_signal_connect (priv->action_pool,
306 "changed",
307 (GCallback) action_pool_changed,
308 authority);
309
310 priv->temporary_authorization_store = temporary_authorization_store_new (authority);
311
312 priv->hash_scope_to_authentication_agent = g_hash_table_new_full ((GHashFunc) polkit_subject_hash,
313 (GEqualFunc) polkit_subject_equal,
314 (GDestroyNotify) g_object_unref,
315 (GDestroyNotify) authentication_agent_unref);
316
317 priv->session_monitor = polkit_backend_session_monitor_new ();
318 g_signal_connect (priv->session_monitor,
319 "changed",
320 G_CALLBACK (on_session_monitor_changed),
321 authority);
322
323 error = NULL;
324 priv->system_bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
325 if (priv->system_bus_connection == NULL)
326 {
327 g_warning ("Error getting system bus: %s", error->message);
328 g_error_free (error);
329 }
330 else
331 {
332 /* TODO: this is a bit inefficient */
333 priv->name_owner_changed_signal_id =
334 g_dbus_connection_signal_subscribe (priv->system_bus_connection,
335 "org.freedesktop.DBus", /* sender */
336 "org.freedesktop.DBus", /* interface */
337 "NameOwnerChanged", /* member */
338 "/org/freedesktop/DBus", /* path */
339 NULL, /* arg0 */
340 G_DBUS_SIGNAL_FLAGS_NONE,
341 on_name_owner_changed_signal,
342 authority,
343 NULL); /* GDestroyNotify */
344 }
345 }
346
347 static void
polkit_backend_interactive_authority_finalize(GObject * object)348 polkit_backend_interactive_authority_finalize (GObject *object)
349 {
350 PolkitBackendInteractiveAuthority *interactive_authority;
351 PolkitBackendInteractiveAuthorityPrivate *priv;
352
353 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (object);
354 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
355
356 if (priv->name_owner_changed_signal_id > 0)
357 g_dbus_connection_signal_unsubscribe (priv->system_bus_connection, priv->name_owner_changed_signal_id);
358
359 if (priv->system_bus_connection != NULL)
360 g_object_unref (priv->system_bus_connection);
361
362 if (priv->action_pool != NULL)
363 g_object_unref (priv->action_pool);
364
365 if (priv->session_monitor != NULL)
366 g_object_unref (priv->session_monitor);
367
368 temporary_authorization_store_free (priv->temporary_authorization_store);
369
370 g_hash_table_unref (priv->hash_scope_to_authentication_agent);
371
372 G_OBJECT_CLASS (polkit_backend_interactive_authority_parent_class)->finalize (object);
373 }
374
375 static const gchar *
polkit_backend_interactive_authority_get_name(PolkitBackendAuthority * authority)376 polkit_backend_interactive_authority_get_name (PolkitBackendAuthority *authority)
377 {
378 return "interactive";
379 }
380
381 static const gchar *
polkit_backend_interactive_authority_get_version(PolkitBackendAuthority * authority)382 polkit_backend_interactive_authority_get_version (PolkitBackendAuthority *authority)
383 {
384 return PACKAGE_VERSION;
385 }
386
387 static PolkitAuthorityFeatures
polkit_backend_interactive_authority_get_features(PolkitBackendAuthority * authority)388 polkit_backend_interactive_authority_get_features (PolkitBackendAuthority *authority)
389 {
390 return POLKIT_AUTHORITY_FEATURES_TEMPORARY_AUTHORIZATION;
391 }
392
393 static void
polkit_backend_interactive_authority_class_init(PolkitBackendInteractiveAuthorityClass * klass)394 polkit_backend_interactive_authority_class_init (PolkitBackendInteractiveAuthorityClass *klass)
395 {
396 GObjectClass *gobject_class;
397 PolkitBackendAuthorityClass *authority_class;
398
399 gobject_class = G_OBJECT_CLASS (klass);
400 authority_class = POLKIT_BACKEND_AUTHORITY_CLASS (klass);
401
402 gobject_class->finalize = polkit_backend_interactive_authority_finalize;
403
404 authority_class->get_name = polkit_backend_interactive_authority_get_name;
405 authority_class->get_version = polkit_backend_interactive_authority_get_version;
406 authority_class->get_features = polkit_backend_interactive_authority_get_features;
407 authority_class->enumerate_actions = polkit_backend_interactive_authority_enumerate_actions;
408 authority_class->check_authorization = polkit_backend_interactive_authority_check_authorization;
409 authority_class->check_authorization_finish = polkit_backend_interactive_authority_check_authorization_finish;
410 authority_class->register_authentication_agent = polkit_backend_interactive_authority_register_authentication_agent;
411 authority_class->unregister_authentication_agent = polkit_backend_interactive_authority_unregister_authentication_agent;
412 authority_class->authentication_agent_response = polkit_backend_interactive_authority_authentication_agent_response;
413 authority_class->enumerate_temporary_authorizations = polkit_backend_interactive_authority_enumerate_temporary_authorizations;
414 authority_class->revoke_temporary_authorizations = polkit_backend_interactive_authority_revoke_temporary_authorizations;
415 authority_class->revoke_temporary_authorization_by_id = polkit_backend_interactive_authority_revoke_temporary_authorization_by_id;
416
417
418
419 g_type_class_add_private (klass, sizeof (PolkitBackendInteractiveAuthorityPrivate));
420 }
421
422 /* ---------------------------------------------------------------------------------------------------- */
423
424 static GList *
polkit_backend_interactive_authority_enumerate_actions(PolkitBackendAuthority * authority,PolkitSubject * caller,const gchar * interactivee,GError ** error)425 polkit_backend_interactive_authority_enumerate_actions (PolkitBackendAuthority *authority,
426 PolkitSubject *caller,
427 const gchar *interactivee,
428 GError **error)
429 {
430 PolkitBackendInteractiveAuthority *interactive_authority;
431 PolkitBackendInteractiveAuthorityPrivate *priv;
432 GList *actions;
433
434 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
435 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
436
437 actions = polkit_backend_action_pool_get_all_actions (priv->action_pool, interactivee);
438
439 return actions;
440 }
441
442 /* ---------------------------------------------------------------------------------------------------- */
443
444 struct AuthenticationAgent
445 {
446 volatile gint ref_count;
447
448 uid_t creator_uid;
449 PolkitSubject *scope;
450 guint64 serial;
451
452 gchar *locale;
453 GVariant *registration_options;
454 gchar *object_path;
455 gchar *unique_system_bus_name;
456 GRand *cookie_pool;
457 gchar *cookie_prefix;
458 guint64 cookie_serial;
459
460 GDBusProxy *proxy;
461
462 GList *active_sessions;
463 };
464
465 /* TODO: should probably move to PolkitSubject
466 * (also see copy in src/programs/pkcheck.c)
467 *
468 * Also, can't really trust the cmdline... but might be useful in the logs anyway.
469 */
470 static gchar *
_polkit_subject_get_cmdline(PolkitSubject * subject)471 _polkit_subject_get_cmdline (PolkitSubject *subject)
472 {
473 PolkitSubject *process;
474 gchar *ret;
475 gint pid;
476 gchar *filename;
477 gchar *contents;
478 gsize contents_len;
479 GError *error;
480 guint n;
481
482 g_return_val_if_fail (subject != NULL, NULL);
483
484 error = NULL;
485
486 ret = NULL;
487 process = NULL;
488 filename = NULL;
489 contents = NULL;
490
491 if (POLKIT_IS_UNIX_PROCESS (subject))
492 {
493 process = g_object_ref (subject);
494 }
495 else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
496 {
497 process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
498 NULL,
499 &error);
500 if (process == NULL)
501 {
502 g_printerr ("Error getting process for system bus name `%s': %s\n",
503 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
504 error->message);
505 g_error_free (error);
506 goto out;
507 }
508 }
509 else
510 {
511 g_warning ("Unknown subject type passed to _polkit_subject_get_cmdline()");
512 goto out;
513 }
514
515 pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (process));
516
517 filename = g_strdup_printf ("/proc/%d/cmdline", pid);
518
519 if (!g_file_get_contents (filename,
520 &contents,
521 &contents_len,
522 &error))
523 {
524 g_printerr ("Error opening `%s': %s\n",
525 filename,
526 error->message);
527 g_error_free (error);
528 goto out;
529 }
530
531 if (contents == NULL || contents_len == 0)
532 {
533 goto out;
534 }
535 else
536 {
537 /* The kernel uses '\0' to separate arguments - replace those with a space. */
538 for (n = 0; n < contents_len - 1; n++)
539 {
540 if (contents[n] == '\0')
541 contents[n] = ' ';
542 }
543 ret = g_strdup (contents);
544 g_strstrip (ret);
545 }
546
547 out:
548 g_free (filename);
549 g_free (contents);
550 if (process != NULL)
551 g_object_unref (process);
552 return ret;
553 }
554
555 /* TODO: possibly remove this function altogether */
556 G_GNUC_UNUSED static void
log_result(PolkitBackendInteractiveAuthority * authority,const gchar * action_id,PolkitSubject * subject,PolkitSubject * caller,PolkitAuthorizationResult * result)557 log_result (PolkitBackendInteractiveAuthority *authority,
558 const gchar *action_id,
559 PolkitSubject *subject,
560 PolkitSubject *caller,
561 PolkitAuthorizationResult *result)
562 {
563 PolkitBackendInteractiveAuthorityPrivate *priv;
564 PolkitIdentity *user_of_subject;
565 const gchar *log_result_str;
566 gchar *subject_str;
567 gchar *user_of_subject_str;
568 gchar *caller_str;
569 gchar *subject_cmdline;
570 gchar *caller_cmdline;
571
572 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
573
574 log_result_str = "DENYING";
575 if (polkit_authorization_result_get_is_authorized (result))
576 log_result_str = "ALLOWING";
577
578 user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL, NULL);
579
580 subject_str = polkit_subject_to_string (subject);
581
582 if (user_of_subject != NULL)
583 user_of_subject_str = polkit_identity_to_string (user_of_subject);
584 else
585 user_of_subject_str = g_strdup ("<unknown>");
586 caller_str = polkit_subject_to_string (caller);
587
588 subject_cmdline = _polkit_subject_get_cmdline (subject);
589 if (subject_cmdline == NULL)
590 subject_cmdline = g_strdup ("<unknown>");
591
592 caller_cmdline = _polkit_subject_get_cmdline (caller);
593 if (caller_cmdline == NULL)
594 caller_cmdline = g_strdup ("<unknown>");
595
596 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
597 "%s action %s for %s [%s] owned by %s (check requested by %s [%s])",
598 log_result_str,
599 action_id,
600 subject_str,
601 subject_cmdline,
602 user_of_subject_str,
603 caller_str,
604 caller_cmdline);
605
606 if (user_of_subject != NULL)
607 g_object_unref (user_of_subject);
608 g_free (subject_str);
609 g_free (user_of_subject_str);
610 g_free (caller_str);
611 g_free (subject_cmdline);
612 g_free (caller_cmdline);
613 }
614
615 static void
check_authorization_challenge_cb(AuthenticationAgent * agent,PolkitSubject * subject,PolkitIdentity * user_of_subject,PolkitSubject * caller,PolkitBackendInteractiveAuthority * authority,const gchar * action_id,PolkitDetails * details,PolkitImplicitAuthorization implicit_authorization,gboolean authentication_success,gboolean was_dismissed,PolkitIdentity * authenticated_identity,gpointer user_data)616 check_authorization_challenge_cb (AuthenticationAgent *agent,
617 PolkitSubject *subject,
618 PolkitIdentity *user_of_subject,
619 PolkitSubject *caller,
620 PolkitBackendInteractiveAuthority *authority,
621 const gchar *action_id,
622 PolkitDetails *details,
623 PolkitImplicitAuthorization implicit_authorization,
624 gboolean authentication_success,
625 gboolean was_dismissed,
626 PolkitIdentity *authenticated_identity,
627 gpointer user_data)
628 {
629 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
630 PolkitBackendInteractiveAuthorityPrivate *priv;
631 PolkitAuthorizationResult *result;
632 gchar *scope_str;
633 gchar *subject_str;
634 gchar *user_of_subject_str;
635 gchar *authenticated_identity_str;
636 gchar *subject_cmdline;
637 gboolean is_temp;
638
639 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
640
641 result = NULL;
642
643 scope_str = polkit_subject_to_string (agent->scope);
644 subject_str = polkit_subject_to_string (subject);
645 user_of_subject_str = polkit_identity_to_string (user_of_subject);
646 authenticated_identity_str = NULL;
647 if (authenticated_identity != NULL)
648 authenticated_identity_str = polkit_identity_to_string (authenticated_identity);
649
650 subject_cmdline = _polkit_subject_get_cmdline (subject);
651 if (subject_cmdline == NULL)
652 subject_cmdline = g_strdup ("<unknown>");
653
654 g_debug ("In check_authorization_challenge_cb\n"
655 " subject %s\n"
656 " action_id %s\n"
657 " was_dismissed %d\n"
658 " authentication_success %d\n",
659 subject_str,
660 action_id,
661 was_dismissed,
662 authentication_success);
663
664 if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED ||
665 implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
666 polkit_details_insert (details, "polkit.retains_authorization_after_challenge", "true");
667
668 is_temp = FALSE;
669 if (authentication_success)
670 {
671 /* store temporary authorization depending on value of implicit_authorization */
672 if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED ||
673 implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
674 {
675 const gchar *id;
676
677 is_temp = TRUE;
678
679 id = temporary_authorization_store_add_authorization (priv->temporary_authorization_store,
680 subject,
681 authentication_agent_get_scope (agent),
682 action_id);
683
684 polkit_details_insert (details, "polkit.temporary_authorization_id", id);
685
686 /* we've added a temporary authorization, let the user know */
687 g_signal_emit_by_name (authority, "changed");
688 }
689 result = polkit_authorization_result_new (TRUE, FALSE, details);
690 }
691 else
692 {
693 /* TODO: maybe return set is_challenge? */
694 if (was_dismissed)
695 polkit_details_insert (details, "polkit.dismissed", "true");
696 result = polkit_authorization_result_new (FALSE, FALSE, details);
697 }
698
699 /* Log the event */
700 if (authentication_success)
701 {
702 if (is_temp)
703 {
704 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
705 "Operator of %s successfully authenticated as %s to gain "
706 "TEMPORARY authorization for action %s for %s [%s] (owned by %s)",
707 scope_str,
708 authenticated_identity_str,
709 action_id,
710 subject_str,
711 subject_cmdline,
712 user_of_subject_str);
713 }
714 else
715 {
716 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
717 "Operator of %s successfully authenticated as %s to gain "
718 "ONE-SHOT authorization for action %s for %s [%s] (owned by %s)",
719 scope_str,
720 authenticated_identity_str,
721 action_id,
722 subject_str,
723 subject_cmdline,
724 user_of_subject_str);
725 }
726 }
727 else
728 {
729 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
730 "Operator of %s FAILED to authenticate to gain "
731 "authorization for action %s for %s [%s] (owned by %s)",
732 scope_str,
733 action_id,
734 subject_str,
735 subject_cmdline,
736 user_of_subject_str);
737 }
738
739 /* log_result (authority, action_id, subject, caller, result); */
740
741 g_simple_async_result_set_op_res_gpointer (simple,
742 result,
743 g_object_unref);
744 g_simple_async_result_complete (simple);
745 g_object_unref (simple);
746
747 g_free (subject_cmdline);
748 g_free (authenticated_identity_str);
749 g_free (user_of_subject_str);
750 g_free (subject_str);
751 g_free (scope_str);
752 }
753
754 static PolkitAuthorizationResult *
polkit_backend_interactive_authority_check_authorization_finish(PolkitBackendAuthority * authority,GAsyncResult * res,GError ** error)755 polkit_backend_interactive_authority_check_authorization_finish (PolkitBackendAuthority *authority,
756 GAsyncResult *res,
757 GError **error)
758 {
759 GSimpleAsyncResult *simple;
760 PolkitAuthorizationResult *result;
761
762 simple = G_SIMPLE_ASYNC_RESULT (res);
763
764 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_backend_interactive_authority_check_authorization);
765
766 result = NULL;
767
768 if (g_simple_async_result_propagate_error (simple, error))
769 goto out;
770
771 result = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
772
773 out:
774 return result;
775 }
776
777 static gboolean
may_identity_check_authorization(PolkitBackendInteractiveAuthority * interactive_authority,const gchar * action_id,PolkitIdentity * identity)778 may_identity_check_authorization (PolkitBackendInteractiveAuthority *interactive_authority,
779 const gchar *action_id,
780 PolkitIdentity *identity)
781 {
782 PolkitBackendInteractiveAuthorityPrivate *priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
783 gboolean ret = FALSE;
784 PolkitActionDescription *action_desc = NULL;
785 const gchar *owners = NULL;
786 gchar **tokens = NULL;
787 guint n;
788
789 /* uid 0 may check anything */
790 if (identity_is_root_user (identity))
791 {
792 ret = TRUE;
793 goto out;
794 }
795
796 action_desc = polkit_backend_action_pool_get_action (priv->action_pool, action_id, NULL);
797 if (action_desc == NULL)
798 goto out;
799
800 owners = polkit_action_description_get_annotation (action_desc, "org.freedesktop.policykit.owner");
801 if (owners == NULL)
802 goto out;
803
804 tokens = g_strsplit (owners, " ", 0);
805 for (n = 0; tokens != NULL && tokens[n] != NULL; n++)
806 {
807 PolkitIdentity *owner_identity;
808 GError *error = NULL;
809 owner_identity = polkit_identity_from_string (tokens[n], &error);
810 if (owner_identity == NULL)
811 {
812 g_warning ("Error parsing owner identity %d of action_id %s: %s (%s, %d)",
813 n, action_id, error->message, g_quark_to_string (error->domain), error->code);
814 g_error_free (error);
815 continue;
816 }
817 if (polkit_identity_equal (identity, owner_identity))
818 {
819 ret = TRUE;
820 g_object_unref (owner_identity);
821 goto out;
822 }
823 g_object_unref (owner_identity);
824 }
825
826 out:
827 g_clear_object (&action_desc);
828 g_strfreev (tokens);
829
830 return ret;
831 }
832
833 static void
polkit_backend_interactive_authority_check_authorization(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,const gchar * action_id,PolkitDetails * details,PolkitCheckAuthorizationFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)834 polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority,
835 PolkitSubject *caller,
836 PolkitSubject *subject,
837 const gchar *action_id,
838 PolkitDetails *details,
839 PolkitCheckAuthorizationFlags flags,
840 GCancellable *cancellable,
841 GAsyncReadyCallback callback,
842 gpointer user_data)
843 {
844 PolkitBackendInteractiveAuthority *interactive_authority;
845 PolkitBackendInteractiveAuthorityPrivate *priv;
846 gchar *caller_str;
847 gchar *subject_str;
848 PolkitIdentity *user_of_caller;
849 PolkitIdentity *user_of_subject;
850 gboolean user_of_subject_matches;
851 gchar *user_of_caller_str;
852 gchar *user_of_subject_str;
853 PolkitAuthorizationResult *result;
854 PolkitImplicitAuthorization implicit_authorization;
855 GError *error;
856 GSimpleAsyncResult *simple;
857 gboolean has_details;
858 gchar **detail_keys;
859
860 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
861 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
862
863 error = NULL;
864 caller_str = NULL;
865 subject_str = NULL;
866 user_of_caller = NULL;
867 user_of_subject = NULL;
868 user_of_caller_str = NULL;
869 user_of_subject_str = NULL;
870 result = NULL;
871
872 simple = g_simple_async_result_new (G_OBJECT (authority),
873 callback,
874 user_data,
875 polkit_backend_interactive_authority_check_authorization);
876
877 /* handle being called from ourselves */
878 if (caller == NULL)
879 {
880 /* TODO: this is kind of a hack */
881 GDBusConnection *system_bus;
882 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
883 caller = polkit_system_bus_name_new (g_dbus_connection_get_unique_name (system_bus));
884 g_object_unref (system_bus);
885 }
886
887 caller_str = polkit_subject_to_string (caller);
888 subject_str = polkit_subject_to_string (subject);
889
890 g_debug ("%s is inquiring whether %s is authorized for %s",
891 caller_str,
892 subject_str,
893 action_id);
894
895 user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
896 caller, NULL,
897 &error);
898 if (error != NULL)
899 {
900 g_simple_async_result_set_from_error (simple, error);
901 g_simple_async_result_complete (simple);
902 g_object_unref (simple);
903 g_error_free (error);
904 goto out;
905 }
906
907 user_of_caller_str = polkit_identity_to_string (user_of_caller);
908 g_debug (" user of caller is %s", user_of_caller_str);
909
910 user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
911 subject, &user_of_subject_matches,
912 &error);
913 if (error != NULL)
914 {
915 g_simple_async_result_set_from_error (simple, error);
916 g_simple_async_result_complete (simple);
917 g_object_unref (simple);
918 g_error_free (error);
919 goto out;
920 }
921
922 user_of_subject_str = polkit_identity_to_string (user_of_subject);
923 g_debug (" user of subject is %s", user_of_subject_str);
924
925 has_details = FALSE;
926 if (details != NULL)
927 {
928 detail_keys = polkit_details_get_keys (details);
929 if (detail_keys != NULL)
930 {
931 if (g_strv_length (detail_keys) > 0)
932 has_details = TRUE;
933 g_strfreev (detail_keys);
934 }
935 }
936
937 /* Not anyone is allowed to check that process XYZ is allowed to do ABC.
938 * We allow this if, and only if,
939 *
940 * - processes may check for another process owned by the *same* user but not
941 * if details are passed (otherwise you'd be able to spoof the dialog);
942 * the caller supplies the user_of_subject value, so we additionally
943 * require it to match at least at one point in time (via
944 * user_of_subject_matches).
945 *
946 * - processes running as uid 0 may check anything and pass any details
947 *
948 * - if the action_id has the "org.freedesktop.policykit.owner" annotation
949 * then any uid referenced by that annotation is also allowed to check
950 * anything and pass any details
951 */
952 if (!user_of_subject_matches
953 || !polkit_identity_equal (user_of_caller, user_of_subject)
954 || has_details)
955 {
956 if (!may_identity_check_authorization (interactive_authority, action_id, user_of_caller))
957 {
958 if (has_details)
959 {
960 g_simple_async_result_set_error (simple,
961 POLKIT_ERROR,
962 POLKIT_ERROR_NOT_AUTHORIZED,
963 "Only trusted callers (e.g. uid 0 or an action owner) can use CheckAuthorization() and "
964 "pass details");
965 }
966 else
967 {
968 g_simple_async_result_set_error (simple,
969 POLKIT_ERROR,
970 POLKIT_ERROR_NOT_AUTHORIZED,
971 "Only trusted callers (e.g. uid 0 or an action owner) can use CheckAuthorization() for "
972 "subjects belonging to other identities");
973 }
974 g_simple_async_result_complete (simple);
975 g_object_unref (simple);
976 goto out;
977 }
978 }
979
980 implicit_authorization = POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED;
981 result = check_authorization_sync (authority,
982 caller,
983 subject,
984 action_id,
985 details,
986 flags,
987 &implicit_authorization,
988 FALSE, /* checking_imply */
989 &error);
990 if (error != NULL)
991 {
992 g_simple_async_result_set_from_error (simple, error);
993 g_simple_async_result_complete (simple);
994 g_object_unref (simple);
995 g_error_free (error);
996 goto out;
997 }
998
999 /* Caller is up for a challenge! With light sabers! Use an authentication agent if one exists... */
1000 if (polkit_authorization_result_get_is_challenge (result) &&
1001 (flags & POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION))
1002 {
1003 AuthenticationAgent *agent;
1004
1005 agent = get_authentication_agent_for_subject (interactive_authority, subject);
1006 if (agent != NULL)
1007 {
1008 g_object_unref (result);
1009 result = NULL;
1010
1011 g_debug (" using authentication agent for challenge");
1012
1013 authentication_agent_initiate_challenge (agent,
1014 subject,
1015 user_of_subject,
1016 interactive_authority,
1017 action_id,
1018 details,
1019 caller,
1020 implicit_authorization,
1021 cancellable,
1022 check_authorization_challenge_cb,
1023 simple);
1024
1025 /* keep going */
1026 goto out;
1027 }
1028 }
1029
1030 /* log_result (interactive_authority, action_id, subject, caller, result); */
1031
1032 /* Otherwise just return the result */
1033 g_simple_async_result_set_op_res_gpointer (simple,
1034 g_object_ref (result),
1035 g_object_unref);
1036 g_simple_async_result_complete (simple);
1037 g_object_unref (simple);
1038
1039 out:
1040
1041 if (user_of_caller != NULL)
1042 g_object_unref (user_of_caller);
1043
1044 if (user_of_subject != NULL)
1045 g_object_unref (user_of_subject);
1046
1047 g_free (caller_str);
1048 g_free (subject_str);
1049 g_free (user_of_caller_str);
1050 g_free (user_of_subject_str);
1051
1052 if (result != NULL)
1053 g_object_unref (result);
1054 }
1055
1056 /* ---------------------------------------------------------------------------------------------------- */
1057
1058 static PolkitAuthorizationResult *
check_authorization_sync(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,const gchar * action_id,PolkitDetails * details,PolkitCheckAuthorizationFlags flags,PolkitImplicitAuthorization * out_implicit_authorization,gboolean checking_imply,GError ** error)1059 check_authorization_sync (PolkitBackendAuthority *authority,
1060 PolkitSubject *caller,
1061 PolkitSubject *subject,
1062 const gchar *action_id,
1063 PolkitDetails *details,
1064 PolkitCheckAuthorizationFlags flags,
1065 PolkitImplicitAuthorization *out_implicit_authorization,
1066 gboolean checking_imply,
1067 GError **error)
1068 {
1069 PolkitBackendInteractiveAuthority *interactive_authority;
1070 PolkitBackendInteractiveAuthorityPrivate *priv;
1071 PolkitAuthorizationResult *result;
1072 PolkitIdentity *user_of_subject;
1073 PolkitSubject *session_for_subject;
1074 gchar *subject_str;
1075 GList *groups_of_user;
1076 PolkitActionDescription *action_desc;
1077 gboolean session_is_local;
1078 gboolean session_is_active;
1079 PolkitImplicitAuthorization implicit_authorization;
1080 const gchar *tmp_authz_id;
1081 GList *actions;
1082 GList *l;
1083
1084 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
1085 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
1086
1087 result = NULL;
1088
1089 actions = NULL;
1090 user_of_subject = NULL;
1091 groups_of_user = NULL;
1092 subject_str = NULL;
1093 session_for_subject = NULL;
1094
1095 session_is_local = FALSE;
1096 session_is_active = FALSE;
1097
1098 subject_str = polkit_subject_to_string (subject);
1099
1100 g_debug ("checking whether %s is authorized for %s",
1101 subject_str,
1102 action_id);
1103
1104 /* get the action description */
1105 action_desc = polkit_backend_action_pool_get_action (priv->action_pool,
1106 action_id,
1107 NULL);
1108
1109 if (action_desc == NULL)
1110 {
1111 g_set_error (error,
1112 POLKIT_ERROR,
1113 POLKIT_ERROR_FAILED,
1114 "Action %s is not registered",
1115 action_id);
1116 goto out;
1117 }
1118
1119 /* every subject has a user; this is supplied by the client, so we rely
1120 * on the caller to validate its acceptability. */
1121 user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
1122 subject, NULL,
1123 error);
1124 if (user_of_subject == NULL)
1125 goto out;
1126
1127 /* special case: uid 0, root, is _always_ authorized for anything */
1128 if (identity_is_root_user (user_of_subject))
1129 {
1130 result = polkit_authorization_result_new (TRUE, FALSE, NULL);
1131 goto out;
1132 }
1133
1134 /* a subject *may* be in a session */
1135 session_for_subject = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
1136 subject,
1137 NULL);
1138 g_debug (" %p", session_for_subject);
1139 if (session_for_subject != NULL)
1140 {
1141 session_is_local = polkit_backend_session_monitor_is_session_local (priv->session_monitor, session_for_subject);
1142 session_is_active = polkit_backend_session_monitor_is_session_active (priv->session_monitor, session_for_subject);
1143
1144 g_debug (" subject is in session %s (local=%d active=%d)",
1145 polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (session_for_subject)),
1146 session_is_local,
1147 session_is_active);
1148 }
1149
1150 /* find the implicit authorization to use; it depends on is_local and is_active */
1151 if (session_is_local)
1152 {
1153 if (session_is_active)
1154 implicit_authorization = polkit_action_description_get_implicit_active (action_desc);
1155 else
1156 implicit_authorization = polkit_action_description_get_implicit_inactive (action_desc);
1157 }
1158 else
1159 {
1160 implicit_authorization = polkit_action_description_get_implicit_any (action_desc);
1161 }
1162
1163 /* allow subclasses to rewrite implicit_authorization */
1164 implicit_authorization = polkit_backend_interactive_authority_check_authorization_sync (interactive_authority,
1165 caller,
1166 subject,
1167 user_of_subject,
1168 session_is_local,
1169 session_is_active,
1170 action_id,
1171 details,
1172 implicit_authorization);
1173 /* first see if there's an implicit authorization for subject available */
1174 if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED)
1175 {
1176 g_debug (" is authorized (has implicit authorization local=%d active=%d)",
1177 session_is_local,
1178 session_is_active);
1179 result = polkit_authorization_result_new (TRUE, FALSE, details);
1180 goto out;
1181 }
1182
1183 /* then see if there's a temporary authorization for the subject */
1184 if (temporary_authorization_store_has_authorization (priv->temporary_authorization_store,
1185 subject,
1186 action_id,
1187 &tmp_authz_id))
1188 {
1189
1190 g_debug (" is authorized (has temporary authorization)");
1191 polkit_details_insert (details, "polkit.temporary_authorization_id", tmp_authz_id);
1192 result = polkit_authorization_result_new (TRUE, FALSE, details);
1193 goto out;
1194 }
1195
1196 /* then see if implied by another action that the subject is authorized for
1197 * (but only one level deep to avoid infinite recursion)
1198 *
1199 * TODO: if this is slow, we can maintain a hash table for looking up what
1200 * actions implies a given action
1201 */
1202 if (!checking_imply)
1203 {
1204 actions = polkit_backend_action_pool_get_all_actions (priv->action_pool, NULL);
1205 for (l = actions; l != NULL; l = l->next)
1206 {
1207 PolkitActionDescription *imply_ad = POLKIT_ACTION_DESCRIPTION (l->data);
1208 const gchar *imply;
1209 imply = polkit_action_description_get_annotation (imply_ad, "org.freedesktop.policykit.imply");
1210 if (imply != NULL)
1211 {
1212 gchar **tokens;
1213 guint n;
1214 tokens = g_strsplit (imply, " ", 0);
1215 for (n = 0; tokens[n] != NULL; n++)
1216 {
1217 if (g_strcmp0 (tokens[n], action_id) == 0)
1218 {
1219 PolkitAuthorizationResult *implied_result = NULL;
1220 PolkitImplicitAuthorization implied_implicit_authorization;
1221 GError *implied_error = NULL;
1222 const gchar *imply_action_id;
1223
1224 imply_action_id = polkit_action_description_get_action_id (imply_ad);
1225
1226 /* g_debug ("%s is implied by %s, checking", action_id, imply_action_id); */
1227 implied_result = check_authorization_sync (authority, caller, subject,
1228 imply_action_id,
1229 details, flags,
1230 &implied_implicit_authorization, TRUE,
1231 &implied_error);
1232 if (implied_result != NULL)
1233 {
1234 if (polkit_authorization_result_get_is_authorized (implied_result))
1235 {
1236 g_debug (" is authorized (implied by %s)", imply_action_id);
1237 result = implied_result;
1238 /* cleanup */
1239 g_strfreev (tokens);
1240 goto out;
1241 }
1242 g_object_unref (implied_result);
1243 }
1244 if (implied_error != NULL)
1245 g_error_free (implied_error);
1246 }
1247 }
1248 g_strfreev (tokens);
1249 }
1250 }
1251 }
1252
1253 if (implicit_authorization != POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED)
1254 {
1255 if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED ||
1256 implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
1257 {
1258 polkit_details_insert (details, "polkit.retains_authorization_after_challenge", "1");
1259 }
1260
1261 result = polkit_authorization_result_new (FALSE, TRUE, details);
1262
1263 /* return implicit_authorization so the caller can use an authentication agent if applicable */
1264 if (out_implicit_authorization != NULL)
1265 *out_implicit_authorization = implicit_authorization;
1266
1267 g_debug (" challenge (implicit_authorization = %s)",
1268 polkit_implicit_authorization_to_string (implicit_authorization));
1269 }
1270 else
1271 {
1272 result = polkit_authorization_result_new (FALSE, FALSE, details);
1273 g_debug (" not authorized");
1274 }
1275 out:
1276 g_list_foreach (actions, (GFunc) g_object_unref, NULL);
1277 g_list_free (actions);
1278
1279 g_free (subject_str);
1280
1281 g_list_foreach (groups_of_user, (GFunc) g_object_unref, NULL);
1282 g_list_free (groups_of_user);
1283
1284 if (user_of_subject != NULL)
1285 g_object_unref (user_of_subject);
1286
1287 if (session_for_subject != NULL)
1288 g_object_unref (session_for_subject);
1289
1290 if (action_desc != NULL)
1291 g_object_unref (action_desc);
1292
1293 g_debug (" ");
1294
1295 return result;
1296 }
1297
1298 /* ---------------------------------------------------------------------------------------------------- */
1299
1300 /**
1301 * polkit_backend_interactive_authority_get_admin_identities:
1302 * @authority: A #PolkitBackendInteractiveAuthority.
1303 * @caller: The subject that is inquiring whether @subject is authorized.
1304 * @subject: The subject we are about to authenticate for.
1305 * @user_for_subject: The user of the subject we are about to authenticate for.
1306 * @subject_is_local: %TRUE if the session for @subject is local.
1307 * @subject_is_active: %TRUE if the session for @subject is active.
1308 * @action_id: The action we are about to authenticate for.
1309 * @details: Details about the action.
1310 *
1311 * Gets a list of identities to use for administrator authentication.
1312 *
1313 * The default implementation returns a list with a single element for the super user.
1314 *
1315 * Returns: A list of #PolkitIdentity objects. Free each element
1316 * g_object_unref(), then free the list with g_list_free().
1317 */
1318 GList *
polkit_backend_interactive_authority_get_admin_identities(PolkitBackendInteractiveAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,PolkitIdentity * user_for_subject,gboolean subject_is_local,gboolean subject_is_active,const gchar * action_id,PolkitDetails * details)1319 polkit_backend_interactive_authority_get_admin_identities (PolkitBackendInteractiveAuthority *authority,
1320 PolkitSubject *caller,
1321 PolkitSubject *subject,
1322 PolkitIdentity *user_for_subject,
1323 gboolean subject_is_local,
1324 gboolean subject_is_active,
1325 const gchar *action_id,
1326 PolkitDetails *details)
1327 {
1328 PolkitBackendInteractiveAuthorityClass *klass;
1329 GList *ret = NULL;
1330
1331 klass = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_CLASS (authority);
1332
1333 if (klass->get_admin_identities != NULL)
1334 {
1335 ret = klass->get_admin_identities (authority,
1336 caller,
1337 subject,
1338 user_for_subject,
1339 subject_is_local,
1340 subject_is_active,
1341 action_id,
1342 details);
1343 }
1344
1345 return ret;
1346 }
1347
1348 /**
1349 * polkit_backend_interactive_authority_check_authorization_sync:
1350 * @authority: A #PolkitBackendInteractiveAuthority.
1351 * @caller: The subject that is inquiring whether @subject is authorized.
1352 * @subject: The subject we are checking an authorization for.
1353 * @user_for_subject: The user of the subject we are checking an authorization for.
1354 * @subject_is_local: %TRUE if the session for @subject is local.
1355 * @subject_is_active: %TRUE if the session for @subject is active.
1356 * @action_id: The action we are checking an authorization for.
1357 * @details: Details about the action.
1358 * @implicit: A #PolkitImplicitAuthorization value computed from the policy file and @subject.
1359 *
1360 * Checks whether @subject is authorized to perform the action
1361 * specified by @action_id and @details. The implementation may append
1362 * key/value pairs to @details to return extra information to @caller.
1363 *
1364 * The default implementation of this method simply returns @implicit.
1365 *
1366 * Returns: A #PolkitImplicitAuthorization that specifies if the subject is authorized or whether
1367 * authentication is required.
1368 */
1369 PolkitImplicitAuthorization
polkit_backend_interactive_authority_check_authorization_sync(PolkitBackendInteractiveAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,PolkitIdentity * user_for_subject,gboolean subject_is_local,gboolean subject_is_active,const gchar * action_id,PolkitDetails * details,PolkitImplicitAuthorization implicit)1370 polkit_backend_interactive_authority_check_authorization_sync (PolkitBackendInteractiveAuthority *authority,
1371 PolkitSubject *caller,
1372 PolkitSubject *subject,
1373 PolkitIdentity *user_for_subject,
1374 gboolean subject_is_local,
1375 gboolean subject_is_active,
1376 const gchar *action_id,
1377 PolkitDetails *details,
1378 PolkitImplicitAuthorization implicit)
1379 {
1380 PolkitBackendInteractiveAuthorityClass *klass;
1381 PolkitImplicitAuthorization ret;
1382
1383 klass = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_CLASS (authority);
1384
1385 if (klass->check_authorization_sync == NULL)
1386 {
1387 ret = implicit;
1388 }
1389 else
1390 {
1391 ret = klass->check_authorization_sync (authority,
1392 caller,
1393 subject,
1394 user_for_subject,
1395 subject_is_local,
1396 subject_is_active,
1397 action_id,
1398 details,
1399 implicit);
1400 }
1401
1402 return ret;
1403 }
1404
1405 /* ---------------------------------------------------------------------------------------------------- */
1406
1407 struct AuthenticationSession
1408 {
1409 AuthenticationAgent *agent;
1410
1411 gchar *cookie;
1412
1413 PolkitSubject *subject;
1414
1415 PolkitIdentity *user_of_subject;
1416
1417 PolkitSubject *caller;
1418
1419 PolkitBackendInteractiveAuthority *authority;
1420
1421 GList *identities;
1422
1423 gchar *action_id;
1424
1425 PolkitDetails *details;
1426
1427 gchar *initiated_by_system_bus_unique_name;
1428
1429 PolkitImplicitAuthorization implicit_authorization;
1430
1431 AuthenticationAgentCallback callback;
1432
1433 gpointer user_data;
1434
1435 guint call_id;
1436
1437 gboolean is_authenticated;
1438 PolkitIdentity *authenticated_identity;
1439
1440 GCancellable *cancellable;
1441
1442 gulong cancellable_signal_handler_id;
1443 };
1444
1445 static void
authentication_session_cancelled_cb(GCancellable * cancellable,AuthenticationSession * session)1446 authentication_session_cancelled_cb (GCancellable *cancellable,
1447 AuthenticationSession *session)
1448 {
1449 authentication_session_cancel (session);
1450 }
1451
1452 /* We're not calling this a UUID, but it's basically
1453 * the same thing, just not formatted that way because:
1454 *
1455 * - I'm too lazy to do it
1456 * - If we did, people might think it was actually
1457 * generated from /dev/random, which we're not doing
1458 * because this value doesn't actually need to be
1459 * globally unique.
1460 */
1461 static void
append_rand_u128_str(GString * buf,GRand * pool)1462 append_rand_u128_str (GString *buf,
1463 GRand *pool)
1464 {
1465 g_string_append_printf (buf, "%08x%08x%08x%08x",
1466 g_rand_int (pool),
1467 g_rand_int (pool),
1468 g_rand_int (pool),
1469 g_rand_int (pool));
1470 }
1471
1472 /* A value that should be unique to the (AuthenticationAgent, AuthenticationSession)
1473 * pair, and not guessable by other agents.
1474 *
1475 * <agent serial> - <agent uuid> - <session serial> - <session uuid>
1476 *
1477 * See http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html
1478 *
1479 */
1480 static gchar *
authentication_agent_generate_cookie(AuthenticationAgent * agent)1481 authentication_agent_generate_cookie (AuthenticationAgent *agent)
1482 {
1483 GString *buf = g_string_new ("");
1484
1485 g_string_append (buf, agent->cookie_prefix);
1486
1487 g_string_append_c (buf, '-');
1488 agent->cookie_serial++;
1489 g_string_append_printf (buf, "%" G_GUINT64_FORMAT,
1490 agent->cookie_serial);
1491 g_string_append_c (buf, '-');
1492 append_rand_u128_str (buf, agent->cookie_pool);
1493
1494 return g_string_free (buf, FALSE);
1495 }
1496
1497
1498 static AuthenticationSession *
authentication_session_new(AuthenticationAgent * agent,PolkitSubject * subject,PolkitIdentity * user_of_subject,PolkitSubject * caller,PolkitBackendInteractiveAuthority * authority,GList * identities,const gchar * action_id,PolkitDetails * details,const gchar * initiated_by_system_bus_unique_name,PolkitImplicitAuthorization implicit_authorization,GCancellable * cancellable,AuthenticationAgentCallback callback,gpointer user_data)1499 authentication_session_new (AuthenticationAgent *agent,
1500 PolkitSubject *subject,
1501 PolkitIdentity *user_of_subject,
1502 PolkitSubject *caller,
1503 PolkitBackendInteractiveAuthority *authority,
1504 GList *identities,
1505 const gchar *action_id,
1506 PolkitDetails *details,
1507 const gchar *initiated_by_system_bus_unique_name,
1508 PolkitImplicitAuthorization implicit_authorization,
1509 GCancellable *cancellable,
1510 AuthenticationAgentCallback callback,
1511 gpointer user_data)
1512 {
1513 AuthenticationSession *session;
1514
1515 session = g_new0 (AuthenticationSession, 1);
1516 session->agent = authentication_agent_ref (agent);
1517 session->cookie = authentication_agent_generate_cookie (agent);
1518 session->subject = g_object_ref (subject);
1519 session->user_of_subject = g_object_ref (user_of_subject);
1520 session->caller = g_object_ref (caller);
1521 session->authority = g_object_ref (authority);
1522 session->identities = g_list_copy (identities);
1523 g_list_foreach (session->identities, (GFunc) g_object_ref, NULL);
1524 session->action_id = g_strdup (action_id);
1525 session->details = g_object_ref (details);
1526 session->initiated_by_system_bus_unique_name = g_strdup (initiated_by_system_bus_unique_name);
1527 session->implicit_authorization = implicit_authorization;
1528 session->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
1529 session->callback = callback;
1530 session->user_data = user_data;
1531
1532 if (session->cancellable != NULL)
1533 {
1534 session->cancellable_signal_handler_id = g_signal_connect (session->cancellable,
1535 "cancelled",
1536 G_CALLBACK (authentication_session_cancelled_cb),
1537 session);
1538 }
1539
1540 return session;
1541 }
1542
1543 static void
authentication_session_free(AuthenticationSession * session)1544 authentication_session_free (AuthenticationSession *session)
1545 {
1546 authentication_agent_unref (session->agent);
1547 g_free (session->cookie);
1548 g_list_foreach (session->identities, (GFunc) g_object_unref, NULL);
1549 g_list_free (session->identities);
1550 g_object_unref (session->subject);
1551 g_object_unref (session->user_of_subject);
1552 g_object_unref (session->caller);
1553 g_object_unref (session->authority);
1554 g_free (session->action_id);
1555 g_object_unref (session->details);
1556 g_free (session->initiated_by_system_bus_unique_name);
1557 if (session->cancellable_signal_handler_id > 0)
1558 g_signal_handler_disconnect (session->cancellable, session->cancellable_signal_handler_id);
1559 if (session->authenticated_identity != NULL)
1560 g_object_unref (session->authenticated_identity);
1561 if (session->cancellable != NULL)
1562 g_object_unref (session->cancellable);
1563 g_free (session);
1564 }
1565
1566 static PolkitSubject *
authentication_agent_get_scope(AuthenticationAgent * agent)1567 authentication_agent_get_scope (AuthenticationAgent *agent)
1568 {
1569 return agent->scope;
1570 }
1571
1572 static void
authentication_agent_cancel_all_sessions(AuthenticationAgent * agent)1573 authentication_agent_cancel_all_sessions (AuthenticationAgent *agent)
1574 {
1575 /* cancel all active authentication sessions; use a copy of the list since
1576 * callbacks will modify the list
1577 */
1578 if (agent->active_sessions != NULL)
1579 {
1580 GList *l;
1581 GList *active_sessions;
1582
1583 active_sessions = g_list_copy (agent->active_sessions);
1584 for (l = active_sessions; l != NULL; l = l->next)
1585 {
1586 AuthenticationSession *session = l->data;
1587 authentication_session_cancel (session);
1588 }
1589 g_list_free (active_sessions);
1590 }
1591 }
1592
1593 static AuthenticationAgent *
authentication_agent_ref(AuthenticationAgent * agent)1594 authentication_agent_ref (AuthenticationAgent *agent)
1595 {
1596 g_atomic_int_inc (&agent->ref_count);
1597 return agent;
1598 }
1599
1600 static void
authentication_agent_unref(AuthenticationAgent * agent)1601 authentication_agent_unref (AuthenticationAgent *agent)
1602 {
1603 if (g_atomic_int_dec_and_test (&agent->ref_count))
1604 {
1605 if (agent->proxy != NULL)
1606 g_object_unref (agent->proxy);
1607 g_object_unref (agent->scope);
1608 g_free (agent->locale);
1609 g_free (agent->object_path);
1610 g_free (agent->unique_system_bus_name);
1611 if (agent->registration_options != NULL)
1612 g_variant_unref (agent->registration_options);
1613 g_rand_free (agent->cookie_pool);
1614 g_free (agent->cookie_prefix);
1615 g_free (agent);
1616 }
1617 }
1618
1619 static AuthenticationAgent *
authentication_agent_new(guint64 serial,PolkitSubject * scope,PolkitIdentity * creator,const gchar * unique_system_bus_name,const gchar * locale,const gchar * object_path,GVariant * registration_options,GError ** error)1620 authentication_agent_new (guint64 serial,
1621 PolkitSubject *scope,
1622 PolkitIdentity *creator,
1623 const gchar *unique_system_bus_name,
1624 const gchar *locale,
1625 const gchar *object_path,
1626 GVariant *registration_options,
1627 GError **error)
1628 {
1629 AuthenticationAgent *agent;
1630 GDBusProxy *proxy;
1631 PolkitUnixUser *creator_user;
1632
1633 g_assert (POLKIT_IS_UNIX_USER (creator));
1634 creator_user = POLKIT_UNIX_USER (creator);
1635
1636 if (!g_variant_is_object_path (object_path))
1637 {
1638 g_set_error (error, POLKIT_ERROR, POLKIT_ERROR_FAILED,
1639 "Invalid object path '%s'", object_path);
1640 return NULL;
1641 }
1642
1643 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
1644 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1645 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1646 NULL, /* GDBusInterfaceInfo* */
1647 unique_system_bus_name,
1648 object_path,
1649 "org.freedesktop.PolicyKit1.AuthenticationAgent",
1650 NULL, /* GCancellable* */
1651 error);
1652 if (proxy == NULL)
1653 {
1654 g_prefix_error (error, "Failed to construct proxy for agent: " );
1655 return NULL;
1656 }
1657
1658 agent = g_new0 (AuthenticationAgent, 1);
1659 agent->ref_count = 1;
1660 agent->serial = serial;
1661 agent->scope = g_object_ref (scope);
1662 agent->creator_uid = (uid_t)polkit_unix_user_get_uid (creator_user);
1663 agent->object_path = g_strdup (object_path);
1664 agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
1665 agent->locale = g_strdup (locale);
1666 agent->registration_options = registration_options != NULL ? g_variant_ref (registration_options) : NULL;
1667 agent->proxy = proxy;
1668
1669 {
1670 GString *cookie_prefix = g_string_new ("");
1671 GRand *agent_private_rand = g_rand_new ();
1672
1673 g_string_append_printf (cookie_prefix, "%" G_GUINT64_FORMAT "-", agent->serial);
1674
1675 /* Use a uniquely seeded PRNG to get a prefix cookie for this agent,
1676 * whose sequence will not correlate with the per-authentication session
1677 * cookies.
1678 */
1679 append_rand_u128_str (cookie_prefix, agent_private_rand);
1680 g_rand_free (agent_private_rand);
1681
1682 agent->cookie_prefix = g_string_free (cookie_prefix, FALSE);
1683
1684 /* And a newly seeded pool for per-session cookies */
1685 agent->cookie_pool = g_rand_new ();
1686 }
1687
1688 return agent;
1689 }
1690
1691 static AuthenticationAgent *
get_authentication_agent_for_subject(PolkitBackendInteractiveAuthority * authority,PolkitSubject * subject)1692 get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authority,
1693 PolkitSubject *subject)
1694 {
1695 PolkitBackendInteractiveAuthorityPrivate *priv;
1696 PolkitSubject *session_for_subject = NULL;
1697 AuthenticationAgent *agent = NULL;
1698 AuthenticationAgent *agent_fallback = NULL;
1699 gboolean fallback = FALSE;
1700
1701 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
1702
1703 agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
1704
1705 if (agent == NULL && POLKIT_IS_SYSTEM_BUS_NAME (subject))
1706 {
1707 PolkitSubject *process;
1708 process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
1709 NULL,
1710 NULL);
1711 if (process != NULL)
1712 {
1713 agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, process);
1714 g_object_unref (process);
1715 }
1716 }
1717
1718 if (agent != NULL)
1719 {
1720 /* We have an agent! Now see if we should use this as a fallback only */
1721 if (agent->registration_options != NULL &&
1722 g_variant_lookup (agent->registration_options, "fallback", "b", &fallback) &&
1723 fallback)
1724 {
1725 agent_fallback = agent;
1726 agent = NULL;
1727 }
1728 else
1729 {
1730 /* Nope, use it */
1731 goto out;
1732 }
1733 }
1734
1735 /* Now, we should also cover the case where @subject is a
1736 * UnixProcess but the agent is a SystemBusName. However, this can't
1737 * happen because we only allow registering agents for UnixProcess
1738 * and UnixSession subjects!
1739 */
1740
1741 session_for_subject = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
1742 subject,
1743 NULL);
1744 if (session_for_subject == NULL)
1745 goto out;
1746
1747 agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, session_for_subject);
1748
1749 /* use fallback, if available */
1750 if (agent == NULL && agent_fallback != NULL)
1751 agent = agent_fallback;
1752
1753 out:
1754 if (session_for_subject != NULL)
1755 g_object_unref (session_for_subject);
1756
1757 return agent;
1758 }
1759
1760 static AuthenticationSession *
get_authentication_session_for_uid_and_cookie(PolkitBackendInteractiveAuthority * authority,uid_t uid,const gchar * cookie)1761 get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority,
1762 uid_t uid,
1763 const gchar *cookie)
1764 {
1765 PolkitBackendInteractiveAuthorityPrivate *priv;
1766 GHashTableIter hash_iter;
1767 AuthenticationAgent *agent;
1768 AuthenticationSession *result;
1769
1770 result = NULL;
1771
1772 /* TODO: perhaps use a hash on the cookie to speed this up */
1773
1774 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
1775
1776 g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
1777 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
1778 {
1779 GList *l;
1780
1781 /* We need to ensure that if somehow we have duplicate cookies
1782 * due to wrapping, that the cookie used is matched to the user
1783 * who called AuthenticationAgentResponse2. See
1784 * http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html
1785 *
1786 * Except if the legacy AuthenticationAgentResponse is invoked,
1787 * we don't know the uid and hence use -1. Continue to support
1788 * the old behavior for backwards compatibility, although everyone
1789 * who is using our own setuid helper will automatically be updated
1790 * to the new API.
1791 */
1792 if (uid != (uid_t)-1)
1793 {
1794 if (agent->creator_uid != uid)
1795 continue;
1796 }
1797
1798 for (l = agent->active_sessions; l != NULL; l = l->next)
1799 {
1800 AuthenticationSession *session = l->data;
1801
1802 if (strcmp (session->cookie, cookie) == 0)
1803 {
1804 result = session;
1805 goto out;
1806 }
1807 }
1808 }
1809
1810 out:
1811 return result;
1812 }
1813
1814 static GList *
get_authentication_sessions_initiated_by_system_bus_unique_name(PolkitBackendInteractiveAuthority * authority,const gchar * system_bus_unique_name)1815 get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendInteractiveAuthority *authority,
1816 const gchar *system_bus_unique_name)
1817 {
1818 PolkitBackendInteractiveAuthorityPrivate *priv;
1819 GHashTableIter hash_iter;
1820 AuthenticationAgent *agent;
1821 GList *result;
1822
1823 result = NULL;
1824
1825 /* TODO: perhaps use a hash on the cookie to speed this up */
1826
1827 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
1828
1829 g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
1830 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
1831 {
1832 GList *l;
1833
1834 for (l = agent->active_sessions; l != NULL; l = l->next)
1835 {
1836 AuthenticationSession *session = l->data;
1837
1838 if (strcmp (session->initiated_by_system_bus_unique_name, system_bus_unique_name) == 0)
1839 {
1840 result = g_list_prepend (result, session);
1841 }
1842 }
1843 }
1844
1845 return result;
1846 }
1847
1848 static GList *
get_authentication_sessions_for_system_bus_unique_name_subject(PolkitBackendInteractiveAuthority * authority,const gchar * system_bus_unique_name)1849 get_authentication_sessions_for_system_bus_unique_name_subject (PolkitBackendInteractiveAuthority *authority,
1850 const gchar *system_bus_unique_name)
1851 {
1852 PolkitBackendInteractiveAuthorityPrivate *priv;
1853 GHashTableIter hash_iter;
1854 AuthenticationAgent *agent;
1855 GList *result;
1856
1857 result = NULL;
1858
1859 /* TODO: perhaps use a hash on the cookie to speed this up */
1860
1861 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
1862
1863 g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
1864 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
1865 {
1866 GList *l;
1867
1868 for (l = agent->active_sessions; l != NULL; l = l->next)
1869 {
1870 AuthenticationSession *session = l->data;
1871
1872 if (POLKIT_IS_SYSTEM_BUS_NAME (session->subject) &&
1873 strcmp (polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (session->subject)),
1874 system_bus_unique_name) == 0)
1875 {
1876 result = g_list_prepend (result, session);
1877 }
1878 }
1879 }
1880
1881 return result;
1882 }
1883
1884
1885 static AuthenticationAgent *
get_authentication_agent_by_unique_system_bus_name(PolkitBackendInteractiveAuthority * authority,const gchar * unique_system_bus_name)1886 get_authentication_agent_by_unique_system_bus_name (PolkitBackendInteractiveAuthority *authority,
1887 const gchar *unique_system_bus_name)
1888 {
1889 PolkitBackendInteractiveAuthorityPrivate *priv;
1890 GHashTableIter hash_iter;
1891 AuthenticationAgent *agent;
1892
1893 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
1894
1895 g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
1896 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
1897 {
1898 if (strcmp (agent->unique_system_bus_name, unique_system_bus_name) == 0)
1899 goto out;
1900 }
1901
1902 agent = NULL;
1903
1904 out:
1905 return agent;
1906 }
1907
1908 static void
authentication_agent_begin_cb(GDBusProxy * proxy,GAsyncResult * res,gpointer user_data)1909 authentication_agent_begin_cb (GDBusProxy *proxy,
1910 GAsyncResult *res,
1911 gpointer user_data)
1912 {
1913 AuthenticationSession *session = user_data;
1914 gboolean gained_authorization;
1915 gboolean was_dismissed;
1916 GVariant *result;
1917 GError *error;
1918
1919 was_dismissed = FALSE;
1920 gained_authorization = FALSE;
1921
1922 error = NULL;
1923 result = g_dbus_proxy_call_finish (proxy, res, &error);
1924 if (result == NULL)
1925 {
1926 g_printerr ("Error performing authentication: %s (%s %d)\n",
1927 error->message,
1928 g_quark_to_string (error->domain),
1929 error->code);
1930 if (error->domain == POLKIT_ERROR && error->code == POLKIT_ERROR_CANCELLED)
1931 was_dismissed = TRUE;
1932 g_error_free (error);
1933 }
1934 else
1935 {
1936 g_variant_unref (result);
1937 gained_authorization = session->is_authenticated;
1938 g_debug ("Authentication complete, is_authenticated = %d", session->is_authenticated);
1939 }
1940
1941 session->agent->active_sessions = g_list_remove (session->agent->active_sessions, session);
1942
1943 session->callback (session->agent,
1944 session->subject,
1945 session->user_of_subject,
1946 session->caller,
1947 session->authority,
1948 session->action_id,
1949 session->details,
1950 session->implicit_authorization,
1951 gained_authorization,
1952 was_dismissed,
1953 session->authenticated_identity,
1954 session->user_data);
1955
1956 authentication_session_free (session);
1957 }
1958
1959 static void
append_property(GString * dest,PolkitDetails * details,const gchar * key,PolkitBackendInteractiveAuthority * authority,const gchar * message,const gchar * action_id)1960 append_property (GString *dest,
1961 PolkitDetails *details,
1962 const gchar *key,
1963 PolkitBackendInteractiveAuthority *authority,
1964 const gchar *message,
1965 const gchar *action_id)
1966 {
1967 const gchar *value;
1968
1969 value = polkit_details_lookup (details, key);
1970 if (value != NULL)
1971 {
1972 g_string_append (dest, value);
1973 }
1974 else
1975 {
1976 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
1977 "Error substituting value for property $(%s) when preparing message `%s' for action-id %s",
1978 key,
1979 message,
1980 action_id);
1981 g_string_append (dest, "$(");
1982 g_string_append (dest, key);
1983 g_string_append (dest, ")");
1984 }
1985 }
1986
1987 static gchar *
expand_properties(const gchar * message,PolkitDetails * details,PolkitBackendInteractiveAuthority * authority,const gchar * action_id)1988 expand_properties (const gchar *message,
1989 PolkitDetails *details,
1990 PolkitBackendInteractiveAuthority *authority,
1991 const gchar *action_id)
1992 {
1993 GString *ret;
1994 GString *var;
1995 guint n;
1996 gboolean in_resolve;
1997
1998 ret = g_string_new (NULL);
1999 var = g_string_new (NULL);
2000
2001 in_resolve = FALSE;
2002 for (n = 0; message[n] != '\0'; n++)
2003 {
2004 gint c = message[n];
2005 if (c == '$' && message[n+1] == '(')
2006 {
2007 in_resolve = TRUE;
2008 n += 1;
2009 }
2010 else
2011 {
2012 if (in_resolve)
2013 {
2014 if (c == ')')
2015 {
2016 append_property (ret, details, var->str, authority, message, action_id);
2017 g_string_set_size (var, 0);
2018 in_resolve = FALSE;
2019 }
2020 else
2021 {
2022 g_string_append_c (var, c);
2023 }
2024 }
2025 else
2026 {
2027 g_string_append_c (ret, c);
2028 }
2029 }
2030 }
2031 g_string_free (var, TRUE);
2032
2033 return g_string_free (ret, FALSE);
2034 }
2035
2036 static void
get_localized_data_for_challenge(PolkitBackendInteractiveAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,PolkitIdentity * user_of_subject,const gchar * action_id,PolkitDetails * details,const gchar * locale,gchar ** out_localized_message,gchar ** out_localized_icon_name,PolkitDetails ** out_localized_details)2037 get_localized_data_for_challenge (PolkitBackendInteractiveAuthority *authority,
2038 PolkitSubject *caller,
2039 PolkitSubject *subject,
2040 PolkitIdentity *user_of_subject,
2041 const gchar *action_id,
2042 PolkitDetails *details,
2043 const gchar *locale,
2044 gchar **out_localized_message,
2045 gchar **out_localized_icon_name,
2046 PolkitDetails **out_localized_details)
2047 {
2048 PolkitBackendInteractiveAuthorityPrivate *priv;
2049 PolkitActionDescription *action_desc;
2050 gchar *message;
2051 gchar *icon_name;
2052 PolkitDetails *localized_details;
2053 const gchar *message_to_use;
2054 const gchar *gettext_domain;
2055 gchar *s;
2056
2057 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
2058
2059 message = NULL;
2060 icon_name = NULL;
2061 localized_details = NULL;
2062 action_desc = NULL;
2063
2064 *out_localized_message = NULL;
2065 *out_localized_icon_name = NULL;
2066 *out_localized_details = NULL;
2067
2068 action_desc = polkit_backend_action_pool_get_action (priv->action_pool,
2069 action_id,
2070 locale);
2071 if (action_desc == NULL)
2072 goto out;
2073
2074 /* Set LANG and locale so g_dgettext() + friends work below */
2075 if (setlocale (LC_ALL, locale) == NULL)
2076 {
2077 g_printerr ("Invalid locale '%s'\n", locale);
2078 }
2079 g_setenv ("LANG", locale, TRUE);
2080
2081 gettext_domain = polkit_details_lookup (details, "polkit.gettext_domain");
2082 message_to_use = polkit_details_lookup (details, "polkit.message");
2083 if (message_to_use != NULL)
2084 {
2085 message = g_strdup (g_dgettext (gettext_domain, message_to_use));
2086 /* g_print ("locale=%s, domain=%s, msg=`%s' -> `%s'\n", locale, gettext_domain, message_to_use, message); */
2087 }
2088 icon_name = g_strdup (polkit_details_lookup (details, "polkit.icon_name"));
2089
2090 /* fall back to action description */
2091 if (message == NULL)
2092 {
2093 message = g_strdup (polkit_action_description_get_message (action_desc));
2094 }
2095 if (icon_name == NULL)
2096 {
2097 icon_name = g_strdup (polkit_action_description_get_icon_name (action_desc));
2098 }
2099
2100 /* replace $(property) with values */
2101 if (message != NULL)
2102 {
2103 s = message;
2104 message = expand_properties (message, details, authority, action_id);
2105 g_free (s);
2106 }
2107
2108 /* Back to C! */
2109 setlocale (LC_ALL, "C");
2110 g_setenv ("LANG", "C", TRUE);
2111
2112 out:
2113 if (message == NULL)
2114 message = g_strdup ("");
2115 if (icon_name == NULL)
2116 icon_name = g_strdup ("");
2117 *out_localized_message = message;
2118 *out_localized_icon_name = icon_name;
2119 *out_localized_details = localized_details;
2120 if (action_desc != NULL)
2121 g_object_unref (action_desc);
2122 }
2123
2124 static void
add_pid(PolkitDetails * details,PolkitSubject * subject,const gchar * key)2125 add_pid (PolkitDetails *details,
2126 PolkitSubject *subject,
2127 const gchar *key)
2128 {
2129 gchar buf[32];
2130 gint pid;
2131
2132 if (POLKIT_IS_UNIX_PROCESS (subject))
2133 {
2134 pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject));
2135 }
2136 else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
2137 {
2138 PolkitSubject *process;
2139 GError *error;
2140
2141 error = NULL;
2142 process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
2143 NULL,
2144 &error);
2145 if (process == NULL)
2146 {
2147 g_printerr ("Error getting process for system bus name `%s': %s\n",
2148 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
2149 error->message);
2150 g_error_free (error);
2151 goto out;
2152 }
2153 pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (process));
2154 g_object_unref (process);
2155 }
2156 else if (POLKIT_IS_UNIX_SESSION (subject))
2157 {
2158 goto out;
2159 }
2160 else
2161 {
2162 gchar *s;
2163 s = polkit_subject_to_string (subject);
2164 g_printerr ("Don't know how to get pid from subject of type %s: %s\n",
2165 g_type_name (G_TYPE_FROM_INSTANCE (subject)),
2166 s);
2167 g_free (s);
2168 goto out;
2169 }
2170
2171 g_snprintf (buf, sizeof (buf), "%d", pid);
2172 polkit_details_insert (details, key, buf);
2173
2174 out:
2175 ;
2176 }
2177
2178 /* ---------------------------------------------------------------------------------------------------- */
2179
2180 /* ---------------------------------------------------------------------------------------------------- */
2181
2182 static GList *
get_users_in_group(PolkitIdentity * group,gboolean include_root)2183 get_users_in_group (PolkitIdentity *group,
2184 gboolean include_root)
2185 {
2186 gid_t gid;
2187 struct group *grp;
2188 GList *ret;
2189 guint n;
2190
2191 ret = NULL;
2192
2193 gid = polkit_unix_group_get_gid (POLKIT_UNIX_GROUP (group));
2194 grp = getgrgid (gid);
2195 if (grp == NULL)
2196 {
2197 g_warning ("Error looking up group with gid %d: %s", gid, g_strerror (errno));
2198 goto out;
2199 }
2200
2201 for (n = 0; grp->gr_mem != NULL && grp->gr_mem[n] != NULL; n++)
2202 {
2203 PolkitIdentity *user;
2204 GError *error;
2205
2206 if (!include_root && g_strcmp0 (grp->gr_mem[n], "root") == 0)
2207 continue;
2208
2209 error = NULL;
2210 user = polkit_unix_user_new_for_name (grp->gr_mem[n], &error);
2211 if (user == NULL)
2212 {
2213 g_warning ("Unknown username '%s' in group: %s", grp->gr_mem[n], error->message);
2214 g_error_free (error);
2215 }
2216 else
2217 {
2218 ret = g_list_prepend (ret, user);
2219 }
2220 }
2221
2222 ret = g_list_reverse (ret);
2223
2224 out:
2225 return ret;
2226 }
2227
2228 static GList *
get_users_in_net_group(PolkitIdentity * group,gboolean include_root)2229 get_users_in_net_group (PolkitIdentity *group,
2230 gboolean include_root)
2231 {
2232 const gchar *name;
2233 GList *ret;
2234
2235 ret = NULL;
2236 name = polkit_unix_netgroup_get_name (POLKIT_UNIX_NETGROUP (group));
2237
2238 #ifdef HAVE_SETNETGRENT_RETURN
2239 if (setnetgrent (name) == 0)
2240 {
2241 g_warning ("Error looking up net group with name %s: %s", name, g_strerror (errno));
2242 goto out;
2243 }
2244 #else
2245 setnetgrent (name);
2246 #endif
2247
2248 for (;;)
2249 {
2250 #if defined(HAVE_NETBSD) || defined(HAVE_OPENBSD)
2251 const char *hostname, *username, *domainname;
2252 #else
2253 char *hostname, *username, *domainname;
2254 #endif
2255 PolkitIdentity *user;
2256 GError *error = NULL;
2257
2258 if (getnetgrent (&hostname, &username, &domainname) == 0)
2259 break;
2260
2261 /* Skip NULL entries since we never want to make everyone an admin
2262 * Skip "-" entries which mean "no match ever" in netgroup land */
2263 if (username == NULL || g_strcmp0 (username, "-") == 0)
2264 continue;
2265
2266 /* TODO: Should we match on hostname? Maybe only allow "-" as a hostname
2267 * for safety. */
2268
2269 user = polkit_unix_user_new_for_name (username, &error);
2270 if (user == NULL)
2271 {
2272 g_warning ("Unknown username '%s' in unix-netgroup: %s", username, error->message);
2273 g_error_free (error);
2274 }
2275 else
2276 {
2277 ret = g_list_prepend (ret, user);
2278 }
2279 }
2280
2281 ret = g_list_reverse (ret);
2282
2283 out:
2284 endnetgrent ();
2285 return ret;
2286 }
2287
2288 /* ---------------------------------------------------------------------------------------------------- */
2289
2290 static void
authentication_agent_initiate_challenge(AuthenticationAgent * agent,PolkitSubject * subject,PolkitIdentity * user_of_subject,PolkitBackendInteractiveAuthority * authority,const gchar * action_id,PolkitDetails * details,PolkitSubject * caller,PolkitImplicitAuthorization implicit_authorization,GCancellable * cancellable,AuthenticationAgentCallback callback,gpointer user_data)2291 authentication_agent_initiate_challenge (AuthenticationAgent *agent,
2292 PolkitSubject *subject,
2293 PolkitIdentity *user_of_subject,
2294 PolkitBackendInteractiveAuthority *authority,
2295 const gchar *action_id,
2296 PolkitDetails *details,
2297 PolkitSubject *caller,
2298 PolkitImplicitAuthorization implicit_authorization,
2299 GCancellable *cancellable,
2300 AuthenticationAgentCallback callback,
2301 gpointer user_data)
2302 {
2303 PolkitBackendInteractiveAuthorityPrivate *priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
2304 AuthenticationSession *session;
2305 GList *l;
2306 GList *identities;
2307 gchar *localized_message;
2308 gchar *localized_icon_name;
2309 PolkitDetails *localized_details;
2310 GList *user_identities = NULL;
2311 GVariantBuilder identities_builder;
2312 GVariant *parameters;
2313
2314 get_localized_data_for_challenge (authority,
2315 caller,
2316 subject,
2317 user_of_subject,
2318 action_id,
2319 details,
2320 agent->locale,
2321 &localized_message,
2322 &localized_icon_name,
2323 &localized_details);
2324
2325 identities = NULL;
2326
2327 /* select admin user if required by the implicit authorization */
2328 if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED ||
2329 implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
2330 {
2331 gboolean is_local = FALSE;
2332 gboolean is_active = FALSE;
2333 PolkitSubject *session_for_subject = NULL;
2334
2335 session_for_subject = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
2336 subject,
2337 NULL);
2338 if (session_for_subject != NULL)
2339 {
2340 is_local = polkit_backend_session_monitor_is_session_local (priv->session_monitor, session_for_subject);
2341 is_active = polkit_backend_session_monitor_is_session_active (priv->session_monitor, session_for_subject);
2342 }
2343
2344 identities = polkit_backend_interactive_authority_get_admin_identities (authority,
2345 caller,
2346 subject,
2347 user_of_subject,
2348 is_local,
2349 is_active,
2350 action_id,
2351 details);
2352 g_clear_object (&session_for_subject);
2353 }
2354 else
2355 {
2356 identities = g_list_prepend (identities, g_object_ref (user_of_subject));
2357 }
2358
2359 /* expand groups/netgroups to users */
2360 user_identities = NULL;
2361 for (l = identities; l != NULL; l = l->next)
2362 {
2363 PolkitIdentity *identity = POLKIT_IDENTITY (l->data);
2364 if (POLKIT_IS_UNIX_USER (identity))
2365 {
2366 user_identities = g_list_append (user_identities, g_object_ref (identity));
2367 }
2368 else if (POLKIT_IS_UNIX_GROUP (identity))
2369 {
2370 user_identities = g_list_concat (user_identities, get_users_in_group (identity, FALSE));
2371 }
2372 else if (POLKIT_IS_UNIX_NETGROUP (identity))
2373 {
2374 user_identities = g_list_concat (user_identities, get_users_in_net_group (identity, FALSE));
2375 }
2376 else
2377 {
2378 g_warning ("Unsupported identity");
2379 }
2380 }
2381
2382 /* Fall back to uid 0 if no users are available (rhbz #834494) */
2383 if (user_identities == NULL)
2384 user_identities = g_list_prepend (NULL, polkit_unix_user_new (0));
2385
2386 session = authentication_session_new (agent,
2387 subject,
2388 user_of_subject,
2389 caller,
2390 authority,
2391 user_identities,
2392 action_id,
2393 details,
2394 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
2395 implicit_authorization,
2396 cancellable,
2397 callback,
2398 user_data);
2399
2400 agent->active_sessions = g_list_prepend (agent->active_sessions, session);
2401
2402 if (localized_details == NULL)
2403 localized_details = polkit_details_new ();
2404 add_pid (localized_details, caller, "polkit.caller-pid");
2405 add_pid (localized_details, subject, "polkit.subject-pid");
2406
2407 g_variant_builder_init (&identities_builder, G_VARIANT_TYPE ("a(sa{sv})"));
2408 for (l = user_identities; l != NULL; l = l->next)
2409 {
2410 PolkitIdentity *identity = POLKIT_IDENTITY (l->data);
2411 g_variant_builder_add_value (&identities_builder,
2412 polkit_identity_to_gvariant (identity)); /* A floating value */
2413 }
2414
2415 parameters = g_variant_new ("(sss@a{ss}sa(sa{sv}))",
2416 action_id,
2417 localized_message,
2418 localized_icon_name,
2419 polkit_details_to_gvariant (localized_details), /* A floating value */
2420 session->cookie,
2421 &identities_builder);
2422
2423 g_dbus_proxy_call (agent->proxy,
2424 "BeginAuthentication",
2425 parameters, /* consumes the floating GVariant */
2426 G_DBUS_CALL_FLAGS_NONE,
2427 G_MAXINT, /* timeout_msec - no timeout */
2428 session->cancellable,
2429 (GAsyncReadyCallback) authentication_agent_begin_cb,
2430 session);
2431
2432 g_list_free_full (user_identities, g_object_unref);
2433 g_list_foreach (identities, (GFunc) g_object_unref, NULL);
2434 g_list_free (identities);
2435
2436 g_free (localized_message);
2437 g_free (localized_icon_name);
2438 if (localized_details != NULL)
2439 g_object_unref (localized_details);
2440 }
2441
2442 static void
authentication_agent_cancel_cb(GDBusProxy * proxy,GAsyncResult * res,gpointer user_data)2443 authentication_agent_cancel_cb (GDBusProxy *proxy,
2444 GAsyncResult *res,
2445 gpointer user_data)
2446 {
2447 GVariant *result;
2448 GError *error;
2449
2450 error = NULL;
2451 result = g_dbus_proxy_call_finish (proxy, res, &error);
2452 if (result == NULL)
2453 {
2454 g_printerr ("Error cancelling authentication: %s\n", error->message);
2455 g_error_free (error);
2456 }
2457 else
2458 g_variant_unref (result);
2459 }
2460
2461 static void
authentication_session_cancel(AuthenticationSession * session)2462 authentication_session_cancel (AuthenticationSession *session)
2463 {
2464 g_dbus_proxy_call (session->agent->proxy,
2465 "CancelAuthentication",
2466 g_variant_new ("(s)", session->cookie),
2467 G_DBUS_CALL_FLAGS_NONE,
2468 -1, /* timeout_msec */
2469 NULL, /* GCancellable* */
2470 (GAsyncReadyCallback) authentication_agent_cancel_cb,
2471 NULL);
2472 }
2473
2474 /* ---------------------------------------------------------------------------------------------------- */
2475
2476 static gboolean
polkit_backend_interactive_authority_register_authentication_agent(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,const gchar * locale,const gchar * object_path,GVariant * options,GError ** error)2477 polkit_backend_interactive_authority_register_authentication_agent (PolkitBackendAuthority *authority,
2478 PolkitSubject *caller,
2479 PolkitSubject *subject,
2480 const gchar *locale,
2481 const gchar *object_path,
2482 GVariant *options,
2483 GError **error)
2484 {
2485 PolkitBackendInteractiveAuthority *interactive_authority;
2486 PolkitBackendInteractiveAuthorityPrivate *priv;
2487 PolkitSubject *session_for_caller;
2488 PolkitIdentity *user_of_caller;
2489 PolkitIdentity *user_of_subject;
2490 gboolean user_of_subject_matches;
2491 AuthenticationAgent *agent;
2492 gboolean ret;
2493 gchar *caller_cmdline;
2494 gchar *subject_as_string;
2495
2496 ret = FALSE;
2497
2498 session_for_caller = NULL;
2499 user_of_caller = NULL;
2500 user_of_subject = NULL;
2501 subject_as_string = NULL;
2502 caller_cmdline = NULL;
2503 agent = NULL;
2504
2505 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
2506 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
2507
2508 if (POLKIT_IS_UNIX_SESSION (subject))
2509 {
2510 session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
2511 caller,
2512 NULL);
2513 if (session_for_caller == NULL)
2514 {
2515 g_set_error (error,
2516 POLKIT_ERROR,
2517 POLKIT_ERROR_FAILED,
2518 "Cannot determine session the caller is in");
2519 goto out;
2520 }
2521 if (!polkit_subject_equal (session_for_caller, subject))
2522 {
2523 g_set_error (error,
2524 POLKIT_ERROR,
2525 POLKIT_ERROR_FAILED,
2526 "Passed session and the session the caller is in differs. They must be equal for now.");
2527 goto out;
2528 }
2529 }
2530 else if (POLKIT_IS_UNIX_PROCESS (subject))
2531 {
2532 /* explicitly OK */
2533 }
2534 else
2535 {
2536 g_set_error (error,
2537 POLKIT_ERROR,
2538 POLKIT_ERROR_FAILED,
2539 "Only unix-process and unix-session subjects can be used for authentication agents.");
2540 goto out;
2541 }
2542
2543 user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL);
2544 if (user_of_caller == NULL)
2545 {
2546 g_set_error (error,
2547 POLKIT_ERROR,
2548 POLKIT_ERROR_FAILED,
2549 "Cannot determine user of caller");
2550 goto out;
2551 }
2552 user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL);
2553 if (user_of_subject == NULL)
2554 {
2555 g_set_error (error,
2556 POLKIT_ERROR,
2557 POLKIT_ERROR_FAILED,
2558 "Cannot determine user of subject");
2559 goto out;
2560 }
2561 if (!user_of_subject_matches
2562 || !polkit_identity_equal (user_of_caller, user_of_subject))
2563 {
2564 if (identity_is_root_user (user_of_caller))
2565 {
2566 /* explicitly allow uid 0 to register for other users */
2567 }
2568 else
2569 {
2570 g_set_error (error,
2571 POLKIT_ERROR,
2572 POLKIT_ERROR_FAILED,
2573 "User of caller and user of subject differs.");
2574 goto out;
2575 }
2576 }
2577
2578 agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
2579 if (agent != NULL)
2580 {
2581 g_set_error (error,
2582 POLKIT_ERROR,
2583 POLKIT_ERROR_FAILED,
2584 "An authentication agent already exists for the given subject");
2585 goto out;
2586 }
2587
2588 priv->agent_serial++;
2589 agent = authentication_agent_new (priv->agent_serial,
2590 subject,
2591 user_of_caller,
2592 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
2593 locale,
2594 object_path,
2595 options,
2596 error);
2597 if (!agent)
2598 goto out;
2599
2600 g_hash_table_insert (priv->hash_scope_to_authentication_agent,
2601 g_object_ref (subject),
2602 agent);
2603
2604 caller_cmdline = _polkit_subject_get_cmdline (caller);
2605 if (caller_cmdline == NULL)
2606 caller_cmdline = g_strdup ("<unknown>");
2607
2608 subject_as_string = polkit_subject_to_string (subject);
2609
2610 g_debug ("Added authentication agent for %s at name %s [%s], object path %s, locale %s",
2611 subject_as_string,
2612 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
2613 caller_cmdline,
2614 object_path,
2615 locale);
2616
2617 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
2618 "Registered Authentication Agent for %s "
2619 "(system bus name %s [%s], object path %s, locale %s)",
2620 subject_as_string,
2621 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
2622 caller_cmdline,
2623 object_path,
2624 locale);
2625
2626 g_signal_emit_by_name (authority, "changed");
2627
2628 ret = TRUE;
2629
2630 out:
2631 g_free (caller_cmdline);
2632 g_free (subject_as_string);
2633 if (user_of_caller != NULL)
2634 g_object_unref (user_of_caller);
2635 if (user_of_subject != NULL)
2636 g_object_unref (user_of_subject);
2637 if (session_for_caller != NULL)
2638 g_object_unref (session_for_caller);
2639
2640 return ret;
2641 }
2642
2643 static gboolean
polkit_backend_interactive_authority_unregister_authentication_agent(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,const gchar * object_path,GError ** error)2644 polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBackendAuthority *authority,
2645 PolkitSubject *caller,
2646 PolkitSubject *subject,
2647 const gchar *object_path,
2648 GError **error)
2649 {
2650 PolkitBackendInteractiveAuthority *interactive_authority;
2651 PolkitBackendInteractiveAuthorityPrivate *priv;
2652 PolkitSubject *session_for_caller;
2653 PolkitIdentity *user_of_caller;
2654 PolkitIdentity *user_of_subject;
2655 gboolean user_of_subject_matches;
2656 AuthenticationAgent *agent;
2657 gboolean ret;
2658 gchar *scope_str;
2659
2660 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
2661 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
2662
2663 ret = FALSE;
2664 session_for_caller = NULL;
2665 user_of_caller = NULL;
2666 user_of_subject = NULL;
2667
2668 if (POLKIT_IS_UNIX_SESSION (subject))
2669 {
2670 session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
2671 caller,
2672 NULL);
2673 if (session_for_caller == NULL)
2674 {
2675 g_set_error (error,
2676 POLKIT_ERROR,
2677 POLKIT_ERROR_FAILED,
2678 "Cannot determine session the caller is in");
2679 goto out;
2680 }
2681
2682 if (!polkit_subject_equal (session_for_caller, subject))
2683 {
2684 g_set_error (error,
2685 POLKIT_ERROR,
2686 POLKIT_ERROR_FAILED,
2687 "Passed session and the session the caller is in differs. They must be equal for now.");
2688 goto out;
2689 }
2690 }
2691 else if (POLKIT_IS_UNIX_PROCESS (subject))
2692 {
2693 /* explicitly OK */
2694 }
2695 else
2696 {
2697 g_set_error (error,
2698 POLKIT_ERROR,
2699 POLKIT_ERROR_FAILED,
2700 "Only unix-process and unix-session subjects can be used for authentication agents.");
2701 goto out;
2702 }
2703
2704 user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL);
2705 if (user_of_caller == NULL)
2706 {
2707 g_set_error (error,
2708 POLKIT_ERROR,
2709 POLKIT_ERROR_FAILED,
2710 "Cannot determine user of caller");
2711 goto out;
2712 }
2713 user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL);
2714 if (user_of_subject == NULL)
2715 {
2716 g_set_error (error,
2717 POLKIT_ERROR,
2718 POLKIT_ERROR_FAILED,
2719 "Cannot determine user of subject");
2720 goto out;
2721 }
2722 if (!user_of_subject_matches
2723 || !polkit_identity_equal (user_of_caller, user_of_subject))
2724 {
2725 if (identity_is_root_user (user_of_caller))
2726 {
2727 /* explicitly allow uid 0 to register for other users */
2728 }
2729 else
2730 {
2731 g_set_error (error,
2732 POLKIT_ERROR,
2733 POLKIT_ERROR_FAILED,
2734 "User of caller and user of subject differs.");
2735 goto out;
2736 }
2737 }
2738
2739 agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
2740 if (agent == NULL)
2741 {
2742 g_set_error (error,
2743 POLKIT_ERROR,
2744 POLKIT_ERROR_FAILED,
2745 "No such agent registered");
2746 goto out;
2747 }
2748
2749 if (g_strcmp0 (agent->unique_system_bus_name, polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller))) != 0)
2750 {
2751 g_set_error (error,
2752 POLKIT_ERROR,
2753 POLKIT_ERROR_FAILED,
2754 "System bus names do not match");
2755 goto out;
2756 }
2757
2758 if (g_strcmp0 (agent->object_path, object_path) != 0)
2759 {
2760 g_set_error (error,
2761 POLKIT_ERROR,
2762 POLKIT_ERROR_FAILED,
2763 "Object paths do not match");
2764 goto out;
2765 }
2766
2767 scope_str = polkit_subject_to_string (agent->scope);
2768 g_debug ("Removing authentication agent for %s at name %s, object path %s, locale %s",
2769 scope_str,
2770 agent->unique_system_bus_name,
2771 agent->object_path,
2772 agent->locale);
2773
2774 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
2775 "Unregistered Authentication Agent for %s "
2776 "(system bus name %s, object path %s, locale %s)",
2777 scope_str,
2778 agent->unique_system_bus_name,
2779 agent->object_path,
2780 agent->locale);
2781 g_free (scope_str);
2782
2783 authentication_agent_cancel_all_sessions (agent);
2784 /* this works because we have exactly one agent per session */
2785 /* this frees agent... */
2786 g_hash_table_remove (priv->hash_scope_to_authentication_agent, agent->scope);
2787
2788 g_signal_emit_by_name (authority, "changed");
2789
2790 ret = TRUE;
2791
2792 out:
2793 if (user_of_caller != NULL)
2794 g_object_unref (user_of_caller);
2795 if (user_of_subject != NULL)
2796 g_object_unref (user_of_subject);
2797 if (session_for_caller != NULL)
2798 g_object_unref (session_for_caller);
2799 return ret;
2800 }
2801
2802 /* ---------------------------------------------------------------------------------------------------- */
2803
2804 static gboolean
polkit_backend_interactive_authority_authentication_agent_response(PolkitBackendAuthority * authority,PolkitSubject * caller,uid_t uid,const gchar * cookie,PolkitIdentity * identity,GError ** error)2805 polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority *authority,
2806 PolkitSubject *caller,
2807 uid_t uid,
2808 const gchar *cookie,
2809 PolkitIdentity *identity,
2810 GError **error)
2811 {
2812 PolkitBackendInteractiveAuthority *interactive_authority;
2813 PolkitBackendInteractiveAuthorityPrivate *priv;
2814 PolkitIdentity *user_of_caller;
2815 gchar *identity_str;
2816 AuthenticationSession *session;
2817 GList *l;
2818 gboolean ret;
2819
2820 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
2821 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
2822
2823 ret = FALSE;
2824 user_of_caller = NULL;
2825
2826 identity_str = polkit_identity_to_string (identity);
2827
2828 g_debug ("In authentication_agent_response for cookie '%s' and identity %s",
2829 cookie,
2830 identity_str);
2831
2832 user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
2833 caller, NULL,
2834 error);
2835 if (user_of_caller == NULL)
2836 goto out;
2837
2838 /* only uid 0 is allowed to invoke this method */
2839 if (!identity_is_root_user (user_of_caller))
2840 {
2841 g_set_error (error,
2842 POLKIT_ERROR,
2843 POLKIT_ERROR_FAILED,
2844 "Only uid 0 may invoke this method. This incident has been logged.");
2845 /* TODO: actually log this */
2846 goto out;
2847 }
2848
2849 /* find the authentication session */
2850 session = get_authentication_session_for_uid_and_cookie (interactive_authority, uid, cookie);
2851 if (session == NULL)
2852 {
2853 g_set_error (error,
2854 POLKIT_ERROR,
2855 POLKIT_ERROR_FAILED,
2856 "No session for cookie");
2857 goto out;
2858 }
2859
2860 /* check that the authentication identity was one of the possibilities we allowed */
2861 for (l = session->identities; l != NULL; l = l->next)
2862 {
2863 PolkitIdentity *i = POLKIT_IDENTITY (l->data);
2864
2865 if (polkit_identity_equal (i, identity))
2866 break;
2867 }
2868
2869 if (l == NULL)
2870 {
2871 g_set_error (error,
2872 POLKIT_ERROR,
2873 POLKIT_ERROR_FAILED,
2874 "The authenticated identity is wrong");
2875 goto out;
2876 }
2877
2878 /* checks out, mark the session as authenticated */
2879 session->is_authenticated = TRUE;
2880 session->authenticated_identity = g_object_ref (identity);
2881
2882 ret = TRUE;
2883
2884 out:
2885 g_free (identity_str);
2886
2887 if (user_of_caller != NULL)
2888 g_object_unref (user_of_caller);
2889
2890 return ret;
2891 }
2892
2893 /* ---------------------------------------------------------------------------------------------------- */
2894
2895 static void
polkit_backend_interactive_authority_system_bus_name_owner_changed(PolkitBackendInteractiveAuthority * authority,const gchar * name,const gchar * old_owner,const gchar * new_owner)2896 polkit_backend_interactive_authority_system_bus_name_owner_changed (PolkitBackendInteractiveAuthority *authority,
2897 const gchar *name,
2898 const gchar *old_owner,
2899 const gchar *new_owner)
2900 {
2901 PolkitBackendInteractiveAuthority *interactive_authority;
2902 PolkitBackendInteractiveAuthorityPrivate *priv;
2903
2904 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
2905 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
2906
2907 //g_debug ("name-owner-changed: '%s' '%s' '%s'", name, old_owner, new_owner);
2908
2909 if (name[0] == ':' && strlen (new_owner) == 0)
2910 {
2911 AuthenticationAgent *agent;
2912 GList *sessions;
2913 GList *l;
2914
2915 agent = get_authentication_agent_by_unique_system_bus_name (interactive_authority, name);
2916 if (agent != NULL)
2917 {
2918 gchar *scope_str;
2919
2920 scope_str = polkit_subject_to_string (agent->scope);
2921 g_debug ("Removing authentication agent for %s at name %s, object path %s (disconnected from bus)",
2922 scope_str,
2923 agent->unique_system_bus_name,
2924 agent->object_path);
2925
2926 polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
2927 "Unregistered Authentication Agent for %s "
2928 "(system bus name %s, object path %s, locale %s) (disconnected from bus)",
2929 scope_str,
2930 agent->unique_system_bus_name,
2931 agent->object_path,
2932 agent->locale);
2933 g_free (scope_str);
2934
2935 authentication_agent_cancel_all_sessions (agent);
2936 /* this works because we have exactly one agent per session */
2937 /* this frees agent... */
2938 g_hash_table_remove (priv->hash_scope_to_authentication_agent, agent->scope);
2939
2940 g_signal_emit_by_name (authority, "changed");
2941 }
2942
2943 /* cancel all authentication sessions initiated by the process owning the vanished name */
2944 sessions = get_authentication_sessions_initiated_by_system_bus_unique_name (interactive_authority, name);
2945 for (l = sessions; l != NULL; l = l->next)
2946 {
2947 AuthenticationSession *session = l->data;
2948
2949 authentication_session_cancel (session);
2950 }
2951 g_list_free (sessions);
2952
2953 /* cancel all authentication sessions that is about the vanished name */
2954 sessions = get_authentication_sessions_for_system_bus_unique_name_subject (interactive_authority, name);
2955 for (l = sessions; l != NULL; l = l->next)
2956 {
2957 AuthenticationSession *session = l->data;
2958
2959 authentication_session_cancel (session);
2960 }
2961 g_list_free (sessions);
2962
2963 /* remove all temporary authorizations that applies to the vanished name
2964 * (temporary_authorization_store_add_authorization for the code path for handling processes)
2965 */
2966 temporary_authorization_store_remove_authorizations_for_system_bus_name (priv->temporary_authorization_store,
2967 name);
2968
2969 }
2970
2971 }
2972
2973 /* ---------------------------------------------------------------------------------------------------- */
2974
2975 typedef struct TemporaryAuthorization TemporaryAuthorization;
2976
2977 struct TemporaryAuthorizationStore
2978 {
2979 GList *authorizations;
2980 PolkitBackendInteractiveAuthority *authority;
2981 guint64 serial;
2982 };
2983
2984 struct TemporaryAuthorization
2985 {
2986 TemporaryAuthorizationStore *store;
2987 PolkitSubject *subject;
2988 PolkitSubject *scope;
2989 gchar *id;
2990 gchar *action_id;
2991 /* both of these are obtained using g_get_monotonic_time(),
2992 * so the resolution is usec
2993 */
2994 gint64 time_granted;
2995 gint64 time_expires;
2996 guint expiration_timeout_id;
2997 guint check_vanished_timeout_id;
2998 };
2999
3000 static void
temporary_authorization_free(TemporaryAuthorization * authorization)3001 temporary_authorization_free (TemporaryAuthorization *authorization)
3002 {
3003 g_free (authorization->id);
3004 g_object_unref (authorization->subject);
3005 g_object_unref (authorization->scope);
3006 g_free (authorization->action_id);
3007 if (authorization->expiration_timeout_id > 0)
3008 g_source_remove (authorization->expiration_timeout_id);
3009 if (authorization->check_vanished_timeout_id > 0)
3010 g_source_remove (authorization->check_vanished_timeout_id);
3011 g_free (authorization);
3012 }
3013
3014 static TemporaryAuthorizationStore *
temporary_authorization_store_new(PolkitBackendInteractiveAuthority * authority)3015 temporary_authorization_store_new (PolkitBackendInteractiveAuthority *authority)
3016 {
3017 TemporaryAuthorizationStore *store;
3018
3019 store = g_new0 (TemporaryAuthorizationStore, 1);
3020 store->authority = authority;
3021 store->authorizations = NULL;
3022
3023 return store;
3024 }
3025
3026 static void
temporary_authorization_store_free(TemporaryAuthorizationStore * store)3027 temporary_authorization_store_free (TemporaryAuthorizationStore *store)
3028 {
3029 g_list_foreach (store->authorizations, (GFunc) temporary_authorization_free, NULL);
3030 g_list_free (store->authorizations);
3031 g_free (store);
3032 }
3033
3034 /* See the comment at the top of polkitunixprocess.c */
3035 static gboolean
subject_equal_for_authz(PolkitSubject * a,PolkitSubject * b)3036 subject_equal_for_authz (PolkitSubject *a,
3037 PolkitSubject *b)
3038 {
3039 if (!polkit_subject_equal (a, b))
3040 return FALSE;
3041
3042 /* Now special case unix processes, as we want to protect against
3043 * pid reuse by including the UID.
3044 */
3045 if (POLKIT_IS_UNIX_PROCESS (a) && POLKIT_IS_UNIX_PROCESS (b)) {
3046 int uid_a = polkit_unix_process_get_uid ((PolkitUnixProcess*)a);
3047 int uid_b = polkit_unix_process_get_uid ((PolkitUnixProcess*)b);
3048
3049 if (uid_a != -1 && uid_b != -1)
3050 {
3051 if (uid_a == uid_b)
3052 {
3053 return TRUE;
3054 }
3055 else
3056 {
3057 g_printerr ("denying slowfork; pid %d uid %d != %d!\n",
3058 polkit_unix_process_get_pid ((PolkitUnixProcess*)a),
3059 uid_a, uid_b);
3060 return FALSE;
3061 }
3062 }
3063 /* Fall through; one of the uids is unset so we can't reliably compare */
3064 }
3065
3066 return TRUE;
3067 }
3068
3069 static gboolean
temporary_authorization_store_has_authorization(TemporaryAuthorizationStore * store,PolkitSubject * subject,const gchar * action_id,const gchar ** out_tmp_authz_id)3070 temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store,
3071 PolkitSubject *subject,
3072 const gchar *action_id,
3073 const gchar **out_tmp_authz_id)
3074 {
3075 GList *l;
3076 gboolean ret;
3077 PolkitSubject *subject_to_use;
3078
3079 g_return_val_if_fail (store != NULL, FALSE);
3080 g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), FALSE);
3081 g_return_val_if_fail (action_id != NULL, FALSE);
3082
3083 /* XXX: for now, prefer to store the process */
3084 if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
3085 {
3086 GError *error;
3087 error = NULL;
3088 subject_to_use = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
3089 NULL,
3090 &error);
3091 if (subject_to_use == NULL)
3092 {
3093 g_printerr ("Error getting process for system bus name `%s': %s\n",
3094 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
3095 error->message);
3096 g_error_free (error);
3097 subject_to_use = g_object_ref (subject);
3098 }
3099 }
3100 else
3101 {
3102 subject_to_use = g_object_ref (subject);
3103 }
3104
3105 ret = FALSE;
3106
3107 for (l = store->authorizations; l != NULL; l = l->next) {
3108 TemporaryAuthorization *authorization = l->data;
3109
3110 if (strcmp (action_id, authorization->action_id) == 0 &&
3111 subject_equal_for_authz (subject_to_use, authorization->subject))
3112 {
3113 ret = TRUE;
3114 if (out_tmp_authz_id != NULL)
3115 *out_tmp_authz_id = authorization->id;
3116 goto out;
3117 }
3118 }
3119
3120 out:
3121 g_object_unref (subject_to_use);
3122 return ret;
3123 }
3124
3125 static gboolean
on_expiration_timeout(gpointer user_data)3126 on_expiration_timeout (gpointer user_data)
3127 {
3128 TemporaryAuthorization *authorization = user_data;
3129 gchar *s;
3130
3131 s = polkit_subject_to_string (authorization->subject);
3132 g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
3133 "authorization has expired",
3134 authorization->id,
3135 authorization->action_id,
3136 s);
3137 g_free (s);
3138
3139 authorization->store->authorizations = g_list_remove (authorization->store->authorizations,
3140 authorization);
3141 authorization->expiration_timeout_id = 0;
3142 g_signal_emit_by_name (authorization->store->authority, "changed");
3143 temporary_authorization_free (authorization);
3144
3145 /* remove source */
3146 return FALSE;
3147 }
3148
3149 static gboolean
on_unix_process_check_vanished_timeout(gpointer user_data)3150 on_unix_process_check_vanished_timeout (gpointer user_data)
3151 {
3152 TemporaryAuthorization *authorization = user_data;
3153 GError *error;
3154
3155 /* we know that this is a PolkitUnixProcess so the check is fast (no IPC involved) */
3156 error = NULL;
3157 if (!polkit_subject_exists_sync (authorization->subject,
3158 NULL,
3159 &error))
3160 {
3161 if (error != NULL)
3162 {
3163 g_printerr ("Error checking if process exists: %s\n", error->message);
3164 g_error_free (error);
3165 }
3166 else
3167 {
3168 gchar *s;
3169
3170 s = polkit_subject_to_string (authorization->subject);
3171 g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
3172 "subject has vanished",
3173 authorization->id,
3174 authorization->action_id,
3175 s);
3176 g_free (s);
3177
3178 authorization->store->authorizations = g_list_remove (authorization->store->authorizations,
3179 authorization);
3180 g_signal_emit_by_name (authorization->store->authority, "changed");
3181 temporary_authorization_free (authorization);
3182 }
3183 }
3184
3185 /* keep source around */
3186 return TRUE;
3187 }
3188
3189 static void
temporary_authorization_store_remove_authorizations_for_system_bus_name(TemporaryAuthorizationStore * store,const gchar * name)3190 temporary_authorization_store_remove_authorizations_for_system_bus_name (TemporaryAuthorizationStore *store,
3191 const gchar *name)
3192 {
3193 guint num_removed;
3194 GList *l, *ll;
3195
3196 num_removed = 0;
3197 for (l = store->authorizations; l != NULL; l = ll)
3198 {
3199 TemporaryAuthorization *ta = l->data;
3200 gchar *s;
3201
3202 ll = l->next;
3203
3204 if (!POLKIT_IS_SYSTEM_BUS_NAME (ta->subject))
3205 continue;
3206
3207 if (g_strcmp0 (name, polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (ta->subject))) != 0)
3208 continue;
3209
3210
3211 s = polkit_subject_to_string (ta->subject);
3212 g_debug ("Removing tempoary authorization with id `%s' for action-id `%s' for subject `%s': "
3213 "subject has vanished",
3214 ta->id,
3215 ta->action_id,
3216 s);
3217 g_free (s);
3218
3219 store->authorizations = g_list_remove (store->authorizations, ta);
3220 temporary_authorization_free (ta);
3221
3222 num_removed++;
3223 }
3224
3225 if (num_removed > 0)
3226 g_signal_emit_by_name (store->authority, "changed");
3227 }
3228
3229 static const gchar *
temporary_authorization_store_add_authorization(TemporaryAuthorizationStore * store,PolkitSubject * subject,PolkitSubject * scope,const gchar * action_id)3230 temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store,
3231 PolkitSubject *subject,
3232 PolkitSubject *scope,
3233 const gchar *action_id)
3234 {
3235 TemporaryAuthorization *authorization;
3236 guint expiration_seconds;
3237 PolkitSubject *subject_to_use;
3238
3239 g_return_val_if_fail (store != NULL, NULL);
3240 g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), NULL);
3241 g_return_val_if_fail (action_id != NULL, NULL);
3242 g_return_val_if_fail (!temporary_authorization_store_has_authorization (store, subject, action_id, NULL), NULL);
3243
3244 /* XXX: for now, prefer to store the process */
3245 if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
3246 {
3247 GError *error;
3248 error = NULL;
3249 subject_to_use = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
3250 NULL,
3251 &error);
3252 if (subject_to_use == NULL)
3253 {
3254 g_printerr ("Error getting process for system bus name `%s': %s\n",
3255 polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
3256 error->message);
3257 g_error_free (error);
3258 subject_to_use = g_object_ref (subject);
3259 }
3260 }
3261 else
3262 {
3263 subject_to_use = g_object_ref (subject);
3264 }
3265
3266 /* TODO: right now the time the temporary authorization is kept is hard-coded - we
3267 * could make it a propery on the PolkitBackendInteractiveAuthority class (so
3268 * the local authority could read it from a config file) or a vfunc
3269 * (so the local authority could read it from an annotation on the action).
3270 */
3271 expiration_seconds = 5 * 60;
3272
3273 authorization = g_new0 (TemporaryAuthorization, 1);
3274 authorization->id = g_strdup_printf ("tmpauthz%" G_GUINT64_FORMAT, store->serial++);
3275 authorization->store = store;
3276 authorization->subject = g_object_ref (subject_to_use);
3277 authorization->scope = g_object_ref (scope);
3278 authorization->action_id = g_strdup (action_id);
3279 /* store monotonic time and convert to secs-since-epoch when returning TemporaryAuthorization structs */
3280 authorization->time_granted = g_get_monotonic_time ();
3281 authorization->time_expires = authorization->time_granted + expiration_seconds * G_USEC_PER_SEC;
3282 /* g_timeout_add() is using monotonic time since 2.28 */
3283 authorization->expiration_timeout_id = g_timeout_add (expiration_seconds * 1000,
3284 on_expiration_timeout,
3285 authorization);
3286
3287 if (POLKIT_IS_UNIX_PROCESS (authorization->subject))
3288 {
3289 /* For now, set up a timer to poll every two seconds - this is used to determine
3290 * when the process vanishes. We want to do this so we can remove the temporary
3291 * authorization - this is because we want agents to update e.g. a notification
3292 * area icon saying the user has temporary authorizations (e.g. remove the icon).
3293 *
3294 * Ideally we'd just do
3295 *
3296 * g_signal_connect (kernel, "process-exited", G_CALLBACK (on_process_exited), user_data);
3297 *
3298 * but that is not how things work right now (and, hey, it's not like the kernel
3299 * is a GObject either!) - so we poll.
3300 *
3301 * TODO: On Linux, it might be possible to obtain notifications by connecting
3302 * to the netlink socket. Needs looking into.
3303 */
3304
3305 authorization->check_vanished_timeout_id = g_timeout_add_seconds (2,
3306 on_unix_process_check_vanished_timeout,
3307 authorization);
3308 }
3309 #if 0
3310 else if (POLKIT_IS_SYSTEM_BUS_NAME (authorization->subject))
3311 {
3312 /* This is currently handled in polkit_backend_interactive_authority_system_bus_name_owner_changed() */
3313 }
3314 #endif
3315
3316
3317 store->authorizations = g_list_prepend (store->authorizations, authorization);
3318
3319 g_object_unref (subject_to_use);
3320
3321 return authorization->id;
3322 }
3323
3324 /* ---------------------------------------------------------------------------------------------------- */
3325
3326 static GList *
polkit_backend_interactive_authority_enumerate_temporary_authorizations(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,GError ** error)3327 polkit_backend_interactive_authority_enumerate_temporary_authorizations (PolkitBackendAuthority *authority,
3328 PolkitSubject *caller,
3329 PolkitSubject *subject,
3330 GError **error)
3331 {
3332 PolkitBackendInteractiveAuthority *interactive_authority;
3333 PolkitBackendInteractiveAuthorityPrivate *priv;
3334 PolkitSubject *session_for_caller;
3335 GList *ret;
3336 GList *l;
3337 gint64 monotonic_now;
3338 GTimeVal real_now;
3339
3340 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
3341 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
3342
3343 ret = NULL;
3344 session_for_caller = NULL;
3345
3346 if (!POLKIT_IS_UNIX_SESSION (subject))
3347 {
3348 g_set_error (error,
3349 POLKIT_ERROR,
3350 POLKIT_ERROR_FAILED,
3351 "Can only handle PolkitUnixSession objects for now.");
3352 goto out;
3353 }
3354
3355 session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
3356 caller,
3357 NULL);
3358 if (session_for_caller == NULL)
3359 {
3360 g_set_error (error,
3361 POLKIT_ERROR,
3362 POLKIT_ERROR_FAILED,
3363 "Cannot determine session the caller is in");
3364 goto out;
3365 }
3366
3367 if (!polkit_subject_equal (session_for_caller, subject))
3368 {
3369 g_set_error (error,
3370 POLKIT_ERROR,
3371 POLKIT_ERROR_FAILED,
3372 "Passed session and the session the caller is in differs. They must be equal for now.");
3373 goto out;
3374 }
3375
3376 monotonic_now = g_get_monotonic_time ();
3377 g_get_current_time (&real_now);
3378
3379 for (l = priv->temporary_authorization_store->authorizations; l != NULL; l = l->next)
3380 {
3381 TemporaryAuthorization *ta = l->data;
3382 PolkitTemporaryAuthorization *tmp_authz;
3383 guint64 real_granted;
3384 guint64 real_expires;
3385
3386 if (!polkit_subject_equal (ta->scope, subject))
3387 continue;
3388
3389 real_granted = (ta->time_granted - monotonic_now) / G_USEC_PER_SEC + real_now.tv_sec;
3390 real_expires = (ta->time_expires - monotonic_now) / G_USEC_PER_SEC + real_now.tv_sec;
3391
3392 tmp_authz = polkit_temporary_authorization_new (ta->id,
3393 ta->action_id,
3394 ta->subject,
3395 real_granted,
3396 real_expires);
3397
3398 ret = g_list_prepend (ret, tmp_authz);
3399 }
3400
3401 out:
3402 if (session_for_caller != NULL)
3403 g_object_unref (session_for_caller);
3404
3405 return ret;
3406 }
3407
3408 /* ---------------------------------------------------------------------------------------------------- */
3409
3410 static gboolean
polkit_backend_interactive_authority_revoke_temporary_authorizations(PolkitBackendAuthority * authority,PolkitSubject * caller,PolkitSubject * subject,GError ** error)3411 polkit_backend_interactive_authority_revoke_temporary_authorizations (PolkitBackendAuthority *authority,
3412 PolkitSubject *caller,
3413 PolkitSubject *subject,
3414 GError **error)
3415 {
3416 PolkitBackendInteractiveAuthority *interactive_authority;
3417 PolkitBackendInteractiveAuthorityPrivate *priv;
3418 PolkitSubject *session_for_caller;
3419 gboolean ret;
3420 GList *l;
3421 GList *ll;
3422 guint num_removed;
3423
3424 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
3425 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
3426
3427 ret = FALSE;
3428 session_for_caller = NULL;
3429
3430 if (!POLKIT_IS_UNIX_SESSION (subject))
3431 {
3432 g_set_error (error,
3433 POLKIT_ERROR,
3434 POLKIT_ERROR_FAILED,
3435 "Can only handle PolkitUnixSession objects for now.");
3436 goto out;
3437 }
3438
3439 session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
3440 caller,
3441 NULL);
3442 if (session_for_caller == NULL)
3443 {
3444 g_set_error (error,
3445 POLKIT_ERROR,
3446 POLKIT_ERROR_FAILED,
3447 "Cannot determine session the caller is in");
3448 goto out;
3449 }
3450
3451 if (!polkit_subject_equal (session_for_caller, subject))
3452 {
3453 g_set_error (error,
3454 POLKIT_ERROR,
3455 POLKIT_ERROR_FAILED,
3456 "Passed session and the session the caller is in differs. They must be equal for now.");
3457 goto out;
3458 }
3459
3460 num_removed = 0;
3461 for (l = priv->temporary_authorization_store->authorizations; l != NULL; l = ll)
3462 {
3463 TemporaryAuthorization *ta = l->data;
3464
3465 ll = l->next;
3466
3467 if (!polkit_subject_equal (ta->scope, subject))
3468 continue;
3469
3470 priv->temporary_authorization_store->authorizations = g_list_remove (priv->temporary_authorization_store->authorizations, ta);
3471 temporary_authorization_free (ta);
3472
3473 num_removed++;
3474 }
3475
3476 if (num_removed > 0)
3477 g_signal_emit_by_name (authority, "changed");
3478
3479 ret = TRUE;
3480
3481 out:
3482 if (session_for_caller != NULL)
3483 g_object_unref (session_for_caller);
3484
3485 return ret;
3486 }
3487
3488 /* ---------------------------------------------------------------------------------------------------- */
3489
3490 static gboolean
polkit_backend_interactive_authority_revoke_temporary_authorization_by_id(PolkitBackendAuthority * authority,PolkitSubject * caller,const gchar * id,GError ** error)3491 polkit_backend_interactive_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority,
3492 PolkitSubject *caller,
3493 const gchar *id,
3494 GError **error)
3495 {
3496 PolkitBackendInteractiveAuthority *interactive_authority;
3497 PolkitBackendInteractiveAuthorityPrivate *priv;
3498 PolkitSubject *session_for_caller;
3499 gboolean ret;
3500 GList *l;
3501 GList *ll;
3502 guint num_removed;
3503
3504 interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
3505 priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
3506
3507 ret = FALSE;
3508 session_for_caller = NULL;
3509
3510 session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
3511 caller,
3512 NULL);
3513 if (session_for_caller == NULL)
3514 {
3515 g_set_error (error,
3516 POLKIT_ERROR,
3517 POLKIT_ERROR_FAILED,
3518 "Cannot determine session the caller is in");
3519 goto out;
3520 }
3521
3522 num_removed = 0;
3523 for (l = priv->temporary_authorization_store->authorizations; l != NULL; l = ll)
3524 {
3525 TemporaryAuthorization *ta = l->data;
3526
3527 ll = l->next;
3528
3529 if (strcmp (ta->id, id) != 0)
3530 continue;
3531
3532 if (!polkit_subject_equal (session_for_caller, ta->scope))
3533 {
3534 g_set_error (error,
3535 POLKIT_ERROR,
3536 POLKIT_ERROR_FAILED,
3537 "Cannot remove a temporary authorization belonging to another subject.");
3538 goto out;
3539 }
3540
3541 priv->temporary_authorization_store->authorizations = g_list_remove (priv->temporary_authorization_store->authorizations, ta);
3542 temporary_authorization_free (ta);
3543
3544 num_removed++;
3545 }
3546
3547 if (num_removed > 0)
3548 {
3549 g_signal_emit_by_name (authority, "changed");
3550 }
3551 else
3552 {
3553 g_set_error (error,
3554 POLKIT_ERROR,
3555 POLKIT_ERROR_FAILED,
3556 "No such authorization with id `%s'",
3557 id);
3558 goto out;
3559 }
3560
3561 ret = TRUE;
3562
3563 out:
3564 if (session_for_caller != NULL)
3565 g_object_unref (session_for_caller);
3566
3567 return ret;
3568 }
3569
3570 /* ---------------------------------------------------------------------------------------------------- */
3571