LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-dbus.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 69.6 % 115 80
Test Date: 2024-04-08 13:24:42 Functions: 81.8 % 11 9

            Line data    Source code
       1              : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
       2              : /* gkd-dbus.c - hook into dbus, call other bits
       3              : 
       4              :    Copyright (C) 2007, 2009, Stefan Walter
       5              : 
       6              :    The Gnome Keyring Library is free software; you can redistribute it and/or
       7              :    modify it under the terms of the GNU Library General Public License as
       8              :    published by the Free Software Foundation; either version 2 of the
       9              :    License, or (at your option) any later version.
      10              : 
      11              :    The Gnome Keyring Library is distributed in the hope that it will be useful,
      12              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :    Library General Public License for more details.
      15              : 
      16              :    You should have received a copy of the GNU Library General Public
      17              :    License along with the Gnome Library; see the file COPYING.LIB.  If not,
      18              :    <http://www.gnu.org/licenses/>.
      19              : 
      20              :    Author: Stef Walter <stef@memberwebs.com>
      21              : */
      22              : 
      23              : #include "config.h"
      24              : 
      25              : #include "gkd-daemon-generated.h"
      26              : #include "gkd-dbus.h"
      27              : #include "gkd-dbus-private.h"
      28              : 
      29              : #include "daemon/gkd-main.h"
      30              : #include "daemon/gkd-util.h"
      31              : 
      32              : #include "egg/egg-cleanup.h"
      33              : 
      34              : #include <glib.h>
      35              : #include <gio/gio.h>
      36              : 
      37              : static GDBusConnection *dbus_conn = NULL;
      38              : static gboolean object_registered = FALSE;
      39              : static gboolean acquired_asked = FALSE;
      40              : static gboolean acquired_service = FALSE;
      41              : 
      42              : #define GNOME_KEYRING_DAEMON_SERVICE    "org.gnome.keyring"
      43              : #define GNOME_KEYRING_DAEMON_PATH       "/org/gnome/keyring/daemon"
      44              : #define GNOME_KEYRING_DAEMON_INTERFACE  "org.gnome.keyring.Daemon"
      45              : 
      46              : static void
      47           27 : cleanup_session_bus (gpointer unused)
      48              : {
      49           27 :         if (!dbus_conn)
      50            0 :                 return;
      51              : 
      52           27 :         g_clear_object (&dbus_conn);
      53              : }
      54              : 
      55              : static void
      56            1 : on_connection_close (gpointer user_data)
      57              : {
      58            1 :         g_debug ("dbus connection closed, exiting");
      59            1 :         gkd_main_quit ();
      60            1 : }
      61              : 
      62              : static gboolean
      63           55 : connect_to_session_bus (void)
      64              : {
      65           55 :         GError *error = NULL;
      66              : 
      67           55 :         if (dbus_conn)
      68           28 :                 return TRUE;
      69              : 
      70           27 :         dbus_conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
      71           27 :         if (!dbus_conn) {
      72            0 :                 g_message ("couldn't connect to dbus session bus: %s", error->message);
      73            0 :                 g_error_free (error);
      74            0 :                 return FALSE;
      75              :         }
      76              : 
      77           27 :         g_signal_connect (dbus_conn, "closed",
      78              :                           G_CALLBACK (on_connection_close), NULL);
      79           27 :         egg_cleanup_register (cleanup_session_bus, NULL);
      80           27 :         return TRUE;
      81              : }
      82              : 
      83              : static gboolean
      84            0 : handle_get_environment (GkdExportedDaemon *skeleton,
      85              :                         GDBusMethodInvocation *invocation,
      86              :                         gpointer user_data)
      87              : {
      88              :         const gchar **env;
      89              :         gchar **parts;
      90              :         GVariantBuilder builder;
      91              : 
      92            0 :         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
      93              : 
      94            0 :         for (env = gkd_util_get_environment (); *env != NULL; env++) {
      95            0 :                 parts = g_strsplit (*env, "=", 2);
      96            0 :                 g_variant_builder_add (&builder, "{ss}", parts[0], parts[1]);
      97            0 :                 g_strfreev (parts);
      98              :         }
      99              : 
     100            0 :         gkd_exported_daemon_complete_get_environment (skeleton, invocation,
     101              :                                                       g_variant_builder_end (&builder));
     102            0 :         return TRUE;
     103              : }
     104              : 
     105              : static gboolean
     106            0 : handle_get_control_directory (GkdExportedDaemon *skeleton,
     107              :                               GDBusMethodInvocation *invocation,
     108              :                               gpointer user_data)
     109              : {
     110            0 :         gkd_exported_daemon_complete_get_control_directory (skeleton, invocation,
     111              :                                                             gkd_util_get_master_directory ());
     112            0 :         return TRUE;
     113              : }
     114              : 
     115              : static void
     116           27 : cleanup_singleton (gpointer user_data)
     117              : {
     118           27 :         GkdExportedDaemon *skeleton = user_data;
     119              : 
     120           27 :         g_return_if_fail (dbus_conn);
     121           27 :         if (object_registered) {
     122           27 :                 g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn);
     123           27 :                 g_object_unref (skeleton);
     124              :         }
     125           27 :         object_registered = FALSE;
     126              : }
     127              : 
     128              : gboolean
     129           27 : gkd_dbus_singleton_acquire (gboolean *acquired)
     130              : {
     131           27 :         const gchar *service = NULL;
     132           27 :         GBusNameOwnerFlags flags = G_BUS_NAME_OWNER_FLAGS_NONE;
     133              :         GVariant *acquire_variant;
     134              :         guint res;
     135           27 :         GError *error = NULL;
     136              :         GkdExportedDaemon *skeleton;
     137              : 
     138           27 :         g_assert (acquired);
     139              : 
     140           27 :         if (!connect_to_session_bus ())
     141            0 :                 return FALSE;
     142              : 
     143              :         /* First register the object */
     144           27 :         if (!object_registered) {
     145           27 :                 skeleton = gkd_exported_daemon_skeleton_new ();
     146              : 
     147           27 :                 g_signal_connect (skeleton, "handle-get-control-directory",
     148              :                                   G_CALLBACK (handle_get_control_directory), NULL);
     149           27 :                 g_signal_connect (skeleton, "handle-get-environment",
     150              :                                   G_CALLBACK (handle_get_environment), NULL);
     151              : 
     152           27 :                 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn,
     153              :                                                   GNOME_KEYRING_DAEMON_PATH, &error);
     154              : 
     155           27 :                 if (error == NULL) {
     156           27 :                         object_registered = TRUE;
     157           27 :                         egg_cleanup_register (cleanup_singleton, skeleton);
     158              :                 } else {
     159            0 :                         g_message ("couldn't register dbus object path: %s", error->message);
     160            0 :                         g_clear_error (&error);
     161              :                 }
     162              :         }
     163              : 
     164              :         /* Try and grab our name */
     165           27 :         if (!acquired_asked) {
     166              : #ifdef WITH_DEBUG
     167           27 :                 service = g_getenv ("GNOME_KEYRING_TEST_SERVICE");
     168           27 :                 if (service && service[0])
     169           16 :                         flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE;
     170              :                 else
     171              : #endif
     172           11 :                         service = GNOME_KEYRING_DAEMON_SERVICE;
     173              : 
     174              :                 /* attempt to acquire the name */
     175           27 :                 acquire_variant = g_dbus_connection_call_sync (dbus_conn,
     176              :                                                                "org.freedesktop.DBus",  /* bus name */
     177              :                                                                "/org/freedesktop/DBus", /* object path */
     178              :                                                                "org.freedesktop.DBus",  /* interface name */
     179              :                                                                "RequestName",           /* method name */
     180              :                                                                g_variant_new ("(su)",
     181              :                                                                               service,
     182              :                                                                               flags),
     183              :                                                                G_VARIANT_TYPE ("(u)"),
     184              :                                                                G_DBUS_CALL_FLAGS_NONE,
     185              :                                                                -1, NULL, &error);
     186              : 
     187           27 :                 if (error != NULL) {
     188            0 :                         g_message ("couldn't request name '%s' on session bus: %s", service, error->message);
     189            0 :                         g_error_free (error);
     190            0 :                         return FALSE;
     191              :                 }
     192              : 
     193           27 :                 acquired_asked = TRUE;
     194           27 :                 g_variant_get (acquire_variant, "(u)", &res);
     195           27 :                 g_variant_unref (acquire_variant);
     196              : 
     197           27 :                 switch (res) {
     198              :                 /* We acquired the service name */
     199           27 :                 case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
     200              :                 case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
     201           27 :                        acquired_service = TRUE;
     202           27 :                        break;
     203              :                 /* Another daemon is running */
     204            0 :                 case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
     205              :                 case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
     206            0 :                        acquired_service = FALSE;
     207            0 :                        break;
     208            0 :                 default:
     209            0 :                        acquired_service = FALSE;
     210            0 :                        g_return_val_if_reached (FALSE);
     211              :                        break;
     212              :                };
     213              :         }
     214              : 
     215           27 :         *acquired = acquired_service;
     216              : 
     217           27 :         return TRUE;
     218              : }
     219              : 
     220              : gchar*
     221            1 : gkd_dbus_singleton_control (void)
     222              : {
     223            1 :         gchar *control = NULL;
     224            1 :         GError *error = NULL;
     225              :         GVariant *control_variant;
     226              : 
     227              :         /* If tried to aquire the service must have failed */
     228            1 :         g_return_val_if_fail (!acquired_service, NULL);
     229              : 
     230            1 :         if (!connect_to_session_bus ())
     231            0 :                 return NULL;
     232              : 
     233            1 :         control_variant = g_dbus_connection_call_sync (dbus_conn,
     234              :                                                        GNOME_KEYRING_DAEMON_SERVICE,
     235              :                                                        GNOME_KEYRING_DAEMON_PATH,
     236              :                                                        GNOME_KEYRING_DAEMON_INTERFACE,
     237              :                                                        "GetControlDirectory",
     238              :                                                        NULL, NULL,
     239              :                                                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
     240              :                                                        1000, NULL, &error);
     241              : 
     242            1 :         if (error != NULL) {
     243            1 :                 if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
     244            0 :                         g_message ("couldn't communicate with already running daemon: %s", error->message);
     245            1 :                 g_error_free (error);
     246            1 :                 return NULL;
     247              :         }
     248              : 
     249            0 :         g_variant_get (control_variant, "(s)", &control);
     250            0 :         g_variant_unref (control_variant);
     251              : 
     252            0 :         return control;
     253              : }
     254              : 
     255              : static void
     256           27 : dbus_cleanup (gpointer unused)
     257              : {
     258           27 :         g_return_if_fail (dbus_conn);
     259           27 :         gkd_dbus_secrets_cleanup (dbus_conn);
     260           27 :         gkd_dbus_session_cleanup (dbus_conn);
     261           27 :         gkd_dbus_environment_cleanup (dbus_conn);
     262              : }
     263              : 
     264              : gboolean
     265           27 : gkd_dbus_setup (void)
     266              : {
     267              :         gboolean unused;
     268              : 
     269           27 :         if (!connect_to_session_bus ())
     270            0 :                 return FALSE;
     271              : 
     272              :         /* Our singleton, and internal service API */
     273           27 :         gkd_dbus_singleton_acquire (&unused);
     274              : 
     275              :         /* Session stuff */
     276           27 :         gkd_dbus_environment_init (dbus_conn);
     277           27 :         gkd_dbus_session_init (dbus_conn);
     278              : 
     279              :         /* Secrets API */
     280           27 :         gkd_dbus_secrets_init (dbus_conn);
     281              : 
     282           27 :         egg_cleanup_register (dbus_cleanup, NULL);
     283           27 :         return TRUE;
     284              : }
     285              : 
     286              : gboolean
     287            2 : gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
     288              :                                     const char            *caller)
     289              : {
     290              :         const char *invocation_caller;
     291              : 
     292            2 :         invocation_caller = g_dbus_method_invocation_get_sender (invocation);
     293            2 :         if (!g_str_equal (invocation_caller, caller)) {
     294            0 :                 g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
     295              :                                                                G_DBUS_ERROR_ACCESS_DENIED,
     296              :                                                                "Invalid caller");
     297            0 :                 return FALSE;
     298              :         }
     299              : 
     300            2 :         return TRUE;
     301              : }
        

Generated by: LCOV version 2.0-1