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