gdbus: Fix double free and use after free of object path
[platform/upstream/glib.git] / gio / gdbusobjectskeleton.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include "gdbusobject.h"
26 #include "gdbusobjectskeleton.h"
27 #include "gdbusinterfaceskeleton.h"
28 #include "gdbusprivate.h"
29 #include "gdbusmethodinvocation.h"
30 #include "gdbusintrospection.h"
31 #include "gdbusinterface.h"
32 #include "gdbusutils.h"
33
34 #include "glibintl.h"
35
36 /**
37  * SECTION:gdbusobjectskeleton
38  * @short_description: Service-side D-Bus object
39  * @include: gio/gio.h
40  *
41  * A #GDBusObjectSkeleton instance is essentially a group of D-Bus
42  * interfaces. The set of exported interfaces on the object may be
43  * dynamic and change at runtime.
44  *
45  * This type is intended to be used with #GDBusObjectManager.
46  */
47
48 struct _GDBusObjectSkeletonPrivate
49 {
50   GMutex lock;
51   gchar *object_path;
52   GHashTable *map_name_to_iface;
53 };
54
55 enum
56 {
57   PROP_0,
58   PROP_G_OBJECT_PATH
59 };
60
61 enum
62 {
63   AUTHORIZE_METHOD_SIGNAL,
64   LAST_SIGNAL,
65 };
66
67 static guint signals[LAST_SIGNAL] = {0};
68
69 static void dbus_object_interface_init (GDBusObjectIface *iface);
70
71 G_DEFINE_TYPE_WITH_CODE (GDBusObjectSkeleton, g_dbus_object_skeleton, G_TYPE_OBJECT,
72                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
73
74
75 static void
76 g_dbus_object_skeleton_finalize (GObject *_object)
77 {
78   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
79
80   g_free (object->priv->object_path);
81   g_hash_table_unref (object->priv->map_name_to_iface);
82
83   g_mutex_clear (&object->priv->lock);
84
85   if (G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize != NULL)
86     G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize (_object);
87 }
88
89 static void
90 g_dbus_object_skeleton_get_property (GObject    *_object,
91                                      guint       prop_id,
92                                      GValue     *value,
93                                      GParamSpec *pspec)
94 {
95   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
96
97   switch (prop_id)
98     {
99     case PROP_G_OBJECT_PATH:
100       g_mutex_lock (&object->priv->lock);
101       g_value_set_string (value, object->priv->object_path);
102       g_mutex_unlock (&object->priv->lock);
103       break;
104
105     default:
106       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
107       break;
108     }
109 }
110
111 static void
112 g_dbus_object_skeleton_set_property (GObject       *_object,
113                                      guint          prop_id,
114                                      const GValue  *value,
115                                      GParamSpec    *pspec)
116 {
117   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
118
119   switch (prop_id)
120     {
121     case PROP_G_OBJECT_PATH:
122       g_dbus_object_skeleton_set_object_path (object, g_value_get_string (value));
123       break;
124
125     default:
126       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
127       break;
128     }
129 }
130
131 static gboolean
132 g_dbus_object_skeleton_authorize_method_default (GDBusObjectSkeleton    *object,
133                                                  GDBusInterfaceSkeleton *interface,
134                                                  GDBusMethodInvocation  *invocation)
135 {
136   return TRUE;
137 }
138
139 static void
140 g_dbus_object_skeleton_class_init (GDBusObjectSkeletonClass *klass)
141 {
142   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
143
144   gobject_class->finalize     = g_dbus_object_skeleton_finalize;
145   gobject_class->set_property = g_dbus_object_skeleton_set_property;
146   gobject_class->get_property = g_dbus_object_skeleton_get_property;
147
148   klass->authorize_method = g_dbus_object_skeleton_authorize_method_default;
149
150   /**
151    * GDBusObjectSkeleton:g-object-path:
152    *
153    * The object path where the object is exported.
154    *
155    * Since: 2.30
156    */
157   g_object_class_install_property (gobject_class,
158                                    PROP_G_OBJECT_PATH,
159                                    g_param_spec_string ("g-object-path",
160                                                         "Object Path",
161                                                         "The object path where the object is exported",
162                                                         NULL,
163                                                         G_PARAM_READABLE |
164                                                         G_PARAM_WRITABLE |
165                                                         G_PARAM_CONSTRUCT |
166                                                         G_PARAM_STATIC_STRINGS));
167
168   /**
169    * GDBusObjectSkeleton::authorize-method:
170    * @object: The #GDBusObjectSkeleton emitting the signal.
171    * @interface: The #GDBusInterfaceSkeleton that @invocation is for.
172    * @invocation: A #GDBusMethodInvocation.
173    *
174    * Emitted when a method is invoked by a remote caller and used to
175    * determine if the method call is authorized.
176    *
177    * This signal is like #GDBusInterfaceSkeleton<!-- -->'s
178    * #GDBusInterfaceSkeleton::g-authorize-method signal, except that it is
179    * for the enclosing object.
180    *
181    * The default class handler just returns %TRUE.
182    *
183    * Returns: %TRUE if the call is authorized, %FALSE otherwise.
184    *
185    * Since: 2.30
186    */
187   signals[AUTHORIZE_METHOD_SIGNAL] =
188     g_signal_new ("authorize-method",
189                   G_TYPE_DBUS_OBJECT_SKELETON,
190                   G_SIGNAL_RUN_LAST,
191                   G_STRUCT_OFFSET (GDBusObjectSkeletonClass, authorize_method),
192                   _g_signal_accumulator_false_handled,
193                   NULL,
194                   NULL,
195                   G_TYPE_BOOLEAN,
196                   2,
197                   G_TYPE_DBUS_INTERFACE_SKELETON,
198                   G_TYPE_DBUS_METHOD_INVOCATION);
199
200   g_type_class_add_private (klass, sizeof (GDBusObjectSkeletonPrivate));
201 }
202
203 static void
204 g_dbus_object_skeleton_init (GDBusObjectSkeleton *object)
205 {
206   object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, G_TYPE_DBUS_OBJECT_SKELETON, GDBusObjectSkeletonPrivate);
207   g_mutex_init (&object->priv->lock);
208   object->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
209                                                            g_str_equal,
210                                                            g_free,
211                                                            (GDestroyNotify) g_object_unref);
212 }
213
214 /**
215  * g_dbus_object_skeleton_new:
216  * @object_path: An object path.
217  *
218  * Creates a new #GDBusObjectSkeleton.
219  *
220  * Returns: A #GDBusObjectSkeleton. Free with g_object_unref().
221  *
222  * Since: 2.30
223  */
224 GDBusObjectSkeleton *
225 g_dbus_object_skeleton_new (const gchar *object_path)
226 {
227   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
228   return G_DBUS_OBJECT_SKELETON (g_object_new (G_TYPE_DBUS_OBJECT_SKELETON,
229                                                "g-object-path", object_path,
230                                                NULL));
231 }
232
233 /**
234  * g_dbus_object_skeleton_set_object_path:
235  * @object: A #GDBusObjectSkeleton.
236  * @object_path: A valid D-Bus object path.
237  *
238  * Sets the object path for @object.
239  *
240  * Since: 2.30
241  */
242 void
243 g_dbus_object_skeleton_set_object_path (GDBusObjectSkeleton *object,
244                                         const gchar     *object_path)
245 {
246   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
247   g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path));
248   g_mutex_lock (&object->priv->lock);
249   /* TODO: fail if object is currently exported */
250   if (g_strcmp0 (object->priv->object_path, object_path) != 0)
251     {
252       g_free (object->priv->object_path);
253       object->priv->object_path = g_strdup (object_path);
254       g_mutex_unlock (&object->priv->lock);
255       g_object_notify (G_OBJECT (object), "g-object-path");
256     }
257   else
258     {
259       g_mutex_unlock (&object->priv->lock);
260     }
261 }
262
263 static const gchar *
264 g_dbus_object_skeleton_get_object_path (GDBusObject *_object)
265 {
266   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
267   const gchar *ret;
268   g_mutex_lock (&object->priv->lock);
269   ret = object->priv->object_path;
270   g_mutex_unlock (&object->priv->lock);
271   return ret;
272 }
273
274 /**
275  * g_dbus_object_skeleton_add_interface:
276  * @object: A #GDBusObjectSkeleton.
277  * @interface_: A #GDBusInterfaceSkeleton.
278  *
279  * Adds @interface_ to @object.
280  *
281  * If @object already contains a #GDBusInterfaceSkeleton with the same
282  * interface name, it is removed before @interface_ is added.
283  *
284  * Note that @object takes its own reference on @interface_ and holds
285  * it until removed.
286  *
287  * Since: 2.30
288  */
289 void
290 g_dbus_object_skeleton_add_interface (GDBusObjectSkeleton     *object,
291                                       GDBusInterfaceSkeleton  *interface_)
292 {
293   GDBusInterfaceInfo *info;
294   GDBusInterface *interface_to_remove;
295
296   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
297   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
298
299   g_mutex_lock (&object->priv->lock);
300
301   info = g_dbus_interface_skeleton_get_info (interface_);
302   g_object_ref (interface_);
303
304   interface_to_remove = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
305   if (interface_to_remove != NULL)
306     {
307       g_object_ref (interface_to_remove);
308       g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
309     }
310   g_hash_table_insert (object->priv->map_name_to_iface,
311                        g_strdup (info->name),
312                        g_object_ref (interface_));
313   g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), G_DBUS_OBJECT (object));
314
315   g_mutex_unlock (&object->priv->lock);
316
317   if (interface_to_remove != NULL)
318     {
319       g_dbus_interface_set_object (interface_to_remove, NULL);
320       g_signal_emit_by_name (object,
321                              "interface-removed",
322                              interface_to_remove);
323       g_object_unref (interface_to_remove);
324     }
325
326   g_signal_emit_by_name (object,
327                          "interface-added",
328                          interface_);
329   g_object_unref (interface_);
330 }
331
332 /**
333  * g_dbus_object_skeleton_remove_interface:
334  * @object: A #GDBusObjectSkeleton.
335  * @interface_: A #GDBusInterfaceSkeleton.
336  *
337  * Removes @interface_ from @object.
338  *
339  * Since: 2.30
340  */
341 void
342 g_dbus_object_skeleton_remove_interface  (GDBusObjectSkeleton    *object,
343                                           GDBusInterfaceSkeleton *interface_)
344 {
345   GDBusInterfaceSkeleton *other_interface;
346   GDBusInterfaceInfo *info;
347
348   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
349   g_return_if_fail (G_IS_DBUS_INTERFACE (interface_));
350
351   g_mutex_lock (&object->priv->lock);
352
353   info = g_dbus_interface_skeleton_get_info (interface_);
354
355   other_interface = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
356   if (other_interface == NULL)
357     {
358       g_mutex_unlock (&object->priv->lock);
359       g_warning ("Tried to remove interface with name %s from object "
360                  "at path %s but no such interface exists",
361                  info->name,
362                  object->priv->object_path);
363     }
364   else if (other_interface != interface_)
365     {
366       g_mutex_unlock (&object->priv->lock);
367       g_warning ("Tried to remove interface %p with name %s from object "
368                  "at path %s but the object has the interface %p",
369                  interface_,
370                  info->name,
371                  object->priv->object_path,
372                  other_interface);
373     }
374   else
375     {
376       g_object_ref (interface_);
377       g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
378       g_mutex_unlock (&object->priv->lock);
379       g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), NULL);
380       g_signal_emit_by_name (object,
381                              "interface-removed",
382                              interface_);
383       g_object_unref (interface_);
384     }
385 }
386
387
388 /**
389  * g_dbus_object_skeleton_remove_interface_by_name:
390  * @object: A #GDBusObjectSkeleton.
391  * @interface_name: A D-Bus interface name.
392  *
393  * Removes the #GDBusInterface with @interface_name from @object.
394  *
395  * If no D-Bus interface of the given interface exists, this function
396  * does nothing.
397  *
398  * Since: 2.30
399  */
400 void
401 g_dbus_object_skeleton_remove_interface_by_name (GDBusObjectSkeleton *object,
402                                                  const gchar         *interface_name)
403 {
404   GDBusInterface *interface;
405
406   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
407   g_return_if_fail (g_dbus_is_interface_name (interface_name));
408
409   g_mutex_lock (&object->priv->lock);
410   interface = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
411   if (interface != NULL)
412     {
413       g_object_ref (interface);
414       g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, interface_name));
415       g_mutex_unlock (&object->priv->lock);
416       g_dbus_interface_set_object (interface, NULL);
417       g_signal_emit_by_name (object,
418                              "interface-removed",
419                              interface);
420       g_object_unref (interface);
421     }
422   else
423     {
424       g_mutex_unlock (&object->priv->lock);
425     }
426 }
427
428 static GDBusInterface *
429 g_dbus_object_skeleton_get_interface (GDBusObject  *_object,
430                                       const gchar  *interface_name)
431 {
432   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
433   GDBusInterface *ret;
434
435   g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
436   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
437
438   g_mutex_lock (&object->priv->lock);
439   ret = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
440   if (ret != NULL)
441     g_object_ref (ret);
442   g_mutex_unlock (&object->priv->lock);
443   return ret;
444 }
445
446 static GList *
447 g_dbus_object_skeleton_get_interfaces (GDBusObject *_object)
448 {
449   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
450   GList *ret;
451
452   g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
453
454   ret = NULL;
455
456   g_mutex_lock (&object->priv->lock);
457   ret = g_hash_table_get_values (object->priv->map_name_to_iface);
458   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
459   g_mutex_unlock (&object->priv->lock);
460
461   return ret;
462 }
463
464 /**
465  * g_dbus_object_skeleton_flush:
466  * @object: A #GDBusObjectSkeleton.
467  *
468  * This method simply calls g_dbus_interface_skeleton_flush() on all
469  * interfaces belonging to @object. See that method for when flushing
470  * is useful.
471  *
472  * Since: 2.30
473  */
474 void
475 g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object)
476 {
477   GList *to_flush, *l;
478
479   g_mutex_lock (&object->priv->lock);
480   to_flush = g_hash_table_get_values (object->priv->map_name_to_iface);
481   g_list_foreach (to_flush, (GFunc) g_object_ref, NULL);
482   g_mutex_unlock (&object->priv->lock);
483
484   for (l = to_flush; l != NULL; l = l->next)
485     g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (l->data));
486
487   g_list_free_full (to_flush, g_object_unref);
488 }
489
490 static void
491 dbus_object_interface_init (GDBusObjectIface *iface)
492 {
493   iface->get_object_path = g_dbus_object_skeleton_get_object_path;
494   iface->get_interfaces  = g_dbus_object_skeleton_get_interfaces;
495   iface->get_interface  = g_dbus_object_skeleton_get_interface;
496 }
497
498 gboolean
499 _g_dbus_object_skeleton_has_authorize_method_handlers (GDBusObjectSkeleton *object)
500 {
501   gboolean has_handlers;
502   gboolean has_default_class_handler;
503
504   has_handlers = g_signal_has_handler_pending (object,
505                                                signals[AUTHORIZE_METHOD_SIGNAL],
506                                                0,
507                                                TRUE);
508   has_default_class_handler = (G_DBUS_OBJECT_SKELETON_GET_CLASS (object)->authorize_method ==
509                                g_dbus_object_skeleton_authorize_method_default);
510
511   return has_handlers || !has_default_class_handler;
512 }