Merge branch 'devel' into upstream
[platform/upstream/gumd.git] / src / daemon / dbus / gumd-dbus-user-service-adapter.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gumd
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include "config.h"
27 #include "common/gum-log.h"
28 #include "common/gum-error.h"
29 #include "common/gum-dbus.h"
30 #include "common/gum-defines.h"
31 #include "common/gum-string-utils.h"
32
33 #include "gumd-dbus-user-service-adapter.h"
34 #include "gumd-dbus-user-adapter.h"
35
36 enum
37 {
38     PROP_0,
39
40     PROP_CONNECTION,
41     PROP_SERVER_BUSTYPE,
42     PROP_DAEMON,
43
44     N_PROPERTIES
45 };
46
47 static GParamSpec *properties[N_PROPERTIES];
48
49 typedef struct
50 {
51     gchar *peer_name;
52     GumdDbusUserAdapter *user_adapter;
53     GumdDbusUserServiceAdapter *user_service;
54 }PeerUserService;
55
56 struct _GumdDbusUserServiceAdapterPrivate
57 {
58     GDBusConnection *connection;
59     GumDbusUserService *dbus_user_service;
60     GumdDaemon  *daemon;
61     GumdDbusServerBusType  dbus_server_type;
62     GList *peer_users;
63     GHashTable *caller_watchers; //(dbus_caller:watcher_id)
64 };
65
66 G_DEFINE_TYPE (GumdDbusUserServiceAdapter, gumd_dbus_user_service_adapter, \
67         GUM_TYPE_DISPOSABLE)
68
69 #define GUMD_DBUS_USER_SERVICE_ADAPTER_GET_PRIV(obj) \
70     G_TYPE_INSTANCE_GET_PRIVATE ((obj), GUMD_TYPE_USER_SERVICE_ADAPTER, \
71             GumdDbusUserServiceAdapterPrivate)
72
73 static gboolean
74 _handle_create_new_user (
75         GumdDbusUserServiceAdapter *self,
76         GDBusMethodInvocation *invocation,
77         gpointer user_data);
78
79 static gboolean
80 _handle_get_user (
81         GumdDbusUserServiceAdapter *self,
82         GDBusMethodInvocation *invocation,
83         guint32 uid,
84         gpointer user_data);
85
86 static gboolean
87 _handle_get_user_by_name (
88         GumdDbusUserServiceAdapter *self,
89         GDBusMethodInvocation *invocation,
90         const gchar *username,
91         gpointer user_data);
92
93 static void
94 _on_dbus_user_adapter_disposed (
95         gpointer data,
96         GObject *object);
97
98 static void
99 _set_property (
100         GObject *object,
101         guint property_id,
102         const GValue *value,
103         GParamSpec *pspec)
104 {
105     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (object);
106
107     switch (property_id) {
108         case PROP_DAEMON: {
109             self->priv->daemon = g_value_dup_object(value);
110             break;
111         }
112         case PROP_CONNECTION:
113             self->priv->connection = g_value_dup_object(value);
114             break;
115         case PROP_SERVER_BUSTYPE:
116             self->priv->dbus_server_type =
117                     (GumdDbusServerBusType)g_value_get_uint(value);
118             break;
119         default:
120             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
121     }
122 }
123
124 static void
125 _get_property (
126         GObject *object,
127         guint property_id,
128         GValue *value,
129         GParamSpec *pspec)
130 {
131     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (object);
132
133     switch (property_id) {
134         case PROP_DAEMON: {
135             g_value_set_object (value, self->priv->daemon);
136             break;
137         }
138         case PROP_CONNECTION:
139             g_value_set_object (value, self->priv->connection);
140             break;
141         case PROP_SERVER_BUSTYPE:
142             g_value_set_uint (value, (guint)self->priv->dbus_server_type);
143             break;
144         default:
145             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
146     }
147 }
148
149 static void
150 _on_user_added (
151         GObject *object,
152         guint uid,
153         gpointer user_data)
154 {
155     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (
156             user_data);
157     gum_dbus_user_service_emit_user_added (self->priv->dbus_user_service, uid);
158 }
159
160 static void
161 _on_user_deleted (
162         GObject *object,
163         guint uid,
164         gpointer user_data)
165 {
166     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (
167             user_data);
168     gum_dbus_user_service_emit_user_deleted (self->priv->dbus_user_service,
169             uid);
170 }
171
172 static void
173 _on_user_updated (
174         GObject *object,
175         guint uid,
176         gpointer user_data)
177 {
178     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (
179             user_data);
180     gum_dbus_user_service_emit_user_updated (self->priv->dbus_user_service,
181             uid);
182 }
183
184 static PeerUserService *
185 _dbus_peer_user_new (
186         GumdDbusUserServiceAdapter *self,
187         gchar *peer_name,
188         GumdDbusUserAdapter *user_adapter)
189 {
190     PeerUserService *peer_user = g_malloc0 (sizeof (PeerUserService));
191     peer_user->peer_name = peer_name;
192     peer_user->user_adapter = user_adapter;
193     peer_user->user_service = self;
194     return peer_user;
195 }
196
197 static void
198 _dbus_peer_user_free (
199         PeerUserService *peer_user,
200         gpointer user_data)
201 {
202     if (peer_user) {
203         GUM_STR_FREE (peer_user->peer_name);
204         GUM_OBJECT_UNREF (peer_user->user_adapter);
205         peer_user->user_service = NULL;
206         g_free (peer_user);
207     }
208 }
209
210 static void
211 _dbus_peer_user_remove (
212         PeerUserService *peer_user,
213         gpointer user_data)
214 {
215     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (
216             user_data);
217     if (peer_user && GUMD_IS_DBUS_USER_ADAPTER(peer_user->user_adapter)) {
218         g_object_weak_unref (G_OBJECT (peer_user->user_adapter),
219                 _on_dbus_user_adapter_disposed, user_data);
220         _dbus_peer_user_free (peer_user, NULL);
221         self->priv->peer_users = g_list_remove (self->priv->peer_users,
222                 (gpointer)peer_user);
223     }
224 }
225
226 static void
227 _dispose (
228         GObject *object)
229 {
230     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (object);
231
232     DBG("- unregistering dbus user service adapter (%p). %d", object,
233             G_OBJECT (self->priv->daemon)->ref_count);
234
235     if (self->priv->peer_users) {
236         g_list_foreach (self->priv->peer_users, (GFunc)_dbus_peer_user_remove,
237                 self);
238     }
239
240     g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->daemon),
241             _on_user_added, self);
242     g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->daemon),
243             _on_user_deleted, self);
244     g_signal_handlers_disconnect_by_func (G_OBJECT (self->priv->daemon),
245             _on_user_updated, self);
246
247     GUM_OBJECT_UNREF (self->priv->daemon);
248
249     if (self->priv->dbus_user_service) {
250         g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (
251                 self->priv->dbus_user_service));
252         g_object_unref (self->priv->dbus_user_service);
253         self->priv->dbus_user_service = NULL;
254     }
255
256     if (self->priv->connection) {
257         /* NOTE: There seems to be some bug in glib's dbus connection's
258          * https://bugzilla.gnome.org/show_bug.cgi?id=734281
259          * worker thread such that it does not closes the stream. The problem
260          * is hard to be tracked exactly as it is more of timing issue.
261          * Following code snippet at least closes the stream to avoid any
262          * descriptors leak.
263          * */
264         GIOStream *stream = g_dbus_connection_get_stream (
265                 self->priv->connection);
266         if (stream) g_io_stream_close (stream, NULL, NULL);
267         g_object_unref (self->priv->connection);
268         self->priv->connection = NULL;
269     }
270
271     GUM_HASHTABLE_UNREF (self->priv->caller_watchers);
272
273     G_OBJECT_CLASS (gumd_dbus_user_service_adapter_parent_class)->dispose (
274             object);
275     DBG ("user service adapter (%p) dispose end", object);
276 }
277
278 static void
279 _finalize (
280         GObject *object)
281 {
282     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (object);
283     DBG ("user service adapter (%p) finalise beg", object);
284
285     if (self->priv->peer_users) {
286         g_list_free (self->priv->peer_users);
287         self->priv->peer_users = NULL;
288     }
289
290     DBG ("user service adapter (%p) finalize end", object);
291     G_OBJECT_CLASS (gumd_dbus_user_service_adapter_parent_class)->finalize (
292             object);
293 }
294
295 static void
296 gumd_dbus_user_service_adapter_class_init (
297         GumdDbusUserServiceAdapterClass *klass)
298 {
299     GObjectClass* object_class = G_OBJECT_CLASS (klass);
300
301     g_type_class_add_private (object_class,
302             sizeof (GumdDbusUserServiceAdapterPrivate));
303
304     object_class->get_property = _get_property;
305     object_class->set_property = _set_property;
306     object_class->dispose = _dispose;
307     object_class->finalize = _finalize;
308
309     properties[PROP_DAEMON] = g_param_spec_object (
310             "daemon",
311             "Daemon",
312             "Daemon object",
313             GUMD_TYPE_DAEMON,
314             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
315
316     properties[PROP_CONNECTION] = g_param_spec_object (
317             "connection",
318             "Bus connection",
319             "DBus connection used",
320             G_TYPE_DBUS_CONNECTION,
321             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
322
323     properties[PROP_SERVER_BUSTYPE] =  g_param_spec_uint ("bustype",
324             "BusType",
325             "DBus server bus type",
326             0,
327             G_MAXUINT,
328             GUMD_DBUS_SERVER_BUSTYPE_NONE /* default value */,
329             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
330             G_PARAM_CONSTRUCT_ONLY);
331
332     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
333 }
334
335 static void
336 gumd_dbus_user_service_adapter_init (GumdDbusUserServiceAdapter *self)
337 {
338     self->priv = GUMD_DBUS_USER_SERVICE_ADAPTER_GET_PRIV(self);
339
340     self->priv->connection = 0;
341     self->priv->daemon = NULL;
342     self->priv->peer_users = NULL;
343     self->priv->dbus_user_service = gum_dbus_user_service_skeleton_new ();
344     self->priv->caller_watchers = g_hash_table_new_full (g_str_hash,
345             g_str_equal, g_free, (GDestroyNotify)g_bus_unwatch_name);
346 }
347
348 static void
349 _clear_cache_for_peer_name (
350         PeerUserService *peer_user,
351         PeerUserService *user_data)
352 {
353     g_return_if_fail (peer_user && user_data);
354     g_return_if_fail (GUMD_IS_DBUS_USER_ADAPTER (peer_user->user_adapter));
355
356     if (g_strcmp0 (peer_user->peer_name, user_data->peer_name) == 0) {
357         DBG ("removing dbus user '%p' for peer name %s from cache",
358                 peer_user->user_adapter, peer_user->peer_name);
359         g_object_weak_unref (G_OBJECT (peer_user->user_adapter),
360                 _on_dbus_user_adapter_disposed, peer_user->user_service);
361         _dbus_peer_user_free (peer_user, NULL);
362         user_data->user_service->priv->peer_users = g_list_remove (
363                 user_data->user_service->priv->peer_users,
364                 (gpointer)peer_user);
365     }
366 }
367
368 static void
369 _on_bus_name_lost (
370         GDBusConnection *conn,
371         const char *peer_name,
372         gpointer user_data)
373 {
374     PeerUserService peer_user;
375
376     g_return_if_fail (peer_name && user_data &&
377             GUMD_IS_DBUS_USER_SERVICE_ADAPTER (user_data));
378
379     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (
380             user_data);
381     DBG ("(-)peer disappeared : %s", peer_name);
382
383     peer_user.peer_name = (gchar *)peer_name;
384     peer_user.user_adapter = NULL;
385     peer_user.user_service = self;
386     g_list_foreach (self->priv->peer_users, (GFunc)_clear_cache_for_peer_name,
387             (gpointer)&peer_user);
388
389     g_hash_table_remove (self->priv->caller_watchers, (gpointer)peer_name);
390 }
391
392 static void
393 _add_bus_name_watcher (
394         GumdDbusUserServiceAdapter *self,
395         GumdDbusUserAdapter *user_adapter,
396         GDBusMethodInvocation *invocation)
397 {
398     if (self->priv->dbus_server_type == GUMD_DBUS_SERVER_BUSTYPE_MSG_BUS) {
399         const gchar *sender = g_dbus_method_invocation_get_sender (invocation);
400         GDBusConnection *connection = g_dbus_method_invocation_get_connection (
401                     invocation);
402         if (!g_hash_table_contains (self->priv->caller_watchers, sender)) {
403             guint watcher_id = g_bus_watch_name_on_connection (connection,
404                     sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
405                     _on_bus_name_lost, self, NULL);
406             g_hash_table_insert (self->priv->caller_watchers,
407                     (gpointer)g_strdup (sender),
408                     GUINT_TO_POINTER(watcher_id));
409         }
410     }
411 }
412
413 static void
414 _clear_cache_for_user (
415         PeerUserService *peer_user,
416         PeerUserService *user_data)
417 {
418     g_return_if_fail (peer_user && user_data);
419     g_return_if_fail (GUMD_IS_DBUS_USER_ADAPTER (peer_user->user_adapter));
420
421     if (peer_user->user_adapter == user_data->user_adapter) {
422         DBG ("removing dbus user adapter '%p' from cache",
423                 peer_user->user_adapter);
424         peer_user->user_adapter = NULL;
425         _dbus_peer_user_free (peer_user, NULL);
426         user_data->user_service->priv->peer_users = g_list_remove (
427                 user_data->user_service->priv->peer_users,
428                 (gpointer)peer_user);
429     }
430 }
431
432 static void
433 _on_dbus_user_adapter_disposed (
434         gpointer data,
435         GObject *object)
436 {
437     PeerUserService peer_user;
438
439     GumdDbusUserServiceAdapter *self = GUMD_DBUS_USER_SERVICE_ADAPTER (data);
440
441     DBG ("Dbus user adapter object %p disposed", object);
442
443     peer_user.user_adapter = GUMD_DBUS_USER_ADAPTER (object);
444     peer_user.user_service = self;
445     g_list_foreach (self->priv->peer_users, (GFunc)_clear_cache_for_user,
446             (gpointer)&peer_user);
447
448     if (g_list_length (self->priv->peer_users) == 0) {
449         gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), TRUE);
450     }
451 }
452
453 static gchar *
454 _get_sender (
455         GumdDbusUserServiceAdapter *self,
456         GDBusMethodInvocation *invocation)
457 {
458     gchar *sender = NULL;
459     if (self->priv->dbus_server_type == GUMD_DBUS_SERVER_BUSTYPE_MSG_BUS) {
460         sender = g_strdup (g_dbus_method_invocation_get_sender (invocation));
461     } else {
462         GDBusConnection *connection =  g_dbus_method_invocation_get_connection (
463                 invocation);
464         sender = g_strdup_printf ("%d", g_socket_get_fd (
465                 g_socket_connection_get_socket (G_SOCKET_CONNECTION (
466                         g_dbus_connection_get_stream(connection)))));
467     }
468     return sender;
469 }
470
471 static GumdDbusUserAdapter *
472 _create_and_cache_user_adapter (
473         GumdDbusUserServiceAdapter *self,
474         GumdDaemonUser *user,
475         GDBusMethodInvocation *invocation)
476 {
477     GDBusConnection *connection = g_dbus_method_invocation_get_connection (
478             invocation);
479
480     GumdDbusUserAdapter *user_adapter =
481             gumd_dbus_user_adapter_new_with_connection (
482                     connection, user,
483                     gumd_daemon_get_user_timeout (self->priv->daemon));
484
485     /* keep alive till this user object gets disposed */
486     if (g_list_length (self->priv->peer_users) == 0)
487         gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), FALSE);
488
489     self->priv->peer_users = g_list_append (self->priv->peer_users,
490             _dbus_peer_user_new (self, _get_sender (self, invocation),
491                     user_adapter));
492     g_object_weak_ref (G_OBJECT (user_adapter), _on_dbus_user_adapter_disposed,
493             self);
494
495     /* watchers used for msg-bus only */
496     _add_bus_name_watcher (self, user_adapter, invocation);
497
498     DBG ("created user adapter %p for user %p", user_adapter, user);
499     return user_adapter;
500 }
501
502 static GumdDbusUserAdapter *
503 _get_user_adapter_from_cache (
504         GumdDbusUserServiceAdapter *self,
505         GDBusMethodInvocation *invocation,
506         uid_t uid)
507 {
508     GumdDbusUserAdapter *user_adapter = NULL;
509     PeerUserService *peer_user = NULL;
510     GList *list = self->priv->peer_users;
511     gchar *peer_name = NULL;
512     gboolean delete_later = FALSE;
513
514     if (uid == GUM_USER_INVALID_UID) {
515         return NULL;
516     }
517
518     peer_name = _get_sender (self, invocation);
519     DBG ("peername:%s uid %u", peer_name, uid);
520     for ( ; list != NULL; list = g_list_next (list)) {
521         peer_user = (PeerUserService *) list->data;
522         if (g_strcmp0 (peer_name, peer_user->peer_name) == 0 &&
523             gumd_dbus_user_adapter_get_uid (peer_user->user_adapter) == uid) {
524
525             g_object_get (G_OBJECT (peer_user->user_adapter), "delete-later",
526                     &delete_later, NULL);
527             if (!delete_later) {
528                 user_adapter = peer_user->user_adapter;
529                 break;
530             }
531         }
532     }
533     g_free (peer_name);
534
535     DBG ("user adapter %p", user_adapter);
536     return user_adapter;
537 }
538
539 static gboolean
540 _handle_create_new_user (
541         GumdDbusUserServiceAdapter *self,
542         GDBusMethodInvocation *invocation,
543         gpointer user_data)
544 {
545     GumdDaemonUser *user = NULL;
546     GError *error = NULL;
547
548     g_return_val_if_fail (self && GUMD_IS_DBUS_USER_SERVICE_ADAPTER(self),
549             FALSE);
550     DBG ("");
551
552     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), FALSE);
553
554     user = gumd_daemon_user_new (gumd_daemon_get_config (self->priv->daemon));
555     if (user) {
556         GumdDbusUserAdapter *user_adapter = _create_and_cache_user_adapter (
557                 self, user, invocation);
558         gum_dbus_user_service_complete_create_new_user (
559                 self->priv->dbus_user_service, invocation,
560                 gumd_dbus_user_adapter_get_object_path (user_adapter));
561     } else {
562         g_dbus_method_invocation_return_gerror (invocation, error);
563         g_error_free (error);
564     }
565     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), TRUE);
566     
567     return TRUE;
568 }
569
570 static gboolean
571 _handle_get_user (
572         GumdDbusUserServiceAdapter *self,
573         GDBusMethodInvocation *invocation,
574         guint32 uid,
575         gpointer user_data)
576 {
577     GumdDaemonUser *user = NULL;
578     GError *error = NULL;
579     GumdDbusUserAdapter *user_adapter = NULL;
580     DBG ("uid %d", uid);
581
582     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), FALSE);
583
584     user_adapter = _get_user_adapter_from_cache (self, invocation, uid);
585     if (!user_adapter) {
586         user = gumd_daemon_get_user (self->priv->daemon, (uid_t)uid, &error);
587         if (user) {
588             user_adapter = _create_and_cache_user_adapter (self, user,
589                 invocation);
590         }
591     }
592
593     if (user_adapter) {
594         gum_dbus_user_service_complete_get_user (self->priv->dbus_user_service,
595                 invocation, gumd_dbus_user_adapter_get_object_path (
596                         user_adapter));
597     } else {
598         if (!error) {
599             error = GUM_GET_ERROR_FOR_ID (GUM_ERROR_USER_NOT_FOUND,
600                     "User Not Found");
601         }
602         g_dbus_method_invocation_return_gerror (invocation, error);
603         g_error_free (error);
604     }
605
606     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), TRUE);
607
608     return TRUE;
609 }
610
611 static gboolean
612 _handle_get_user_by_name (
613         GumdDbusUserServiceAdapter *self,
614         GDBusMethodInvocation *invocation,
615         const gchar *username,
616         gpointer user_data)
617 {
618     GumdDaemonUser *user = NULL;
619     GError *error = NULL;
620     GumdDbusUserAdapter *user_adapter = NULL;
621     uid_t uid = GUM_USER_INVALID_UID;
622
623     DBG ("username %s", username);
624
625     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), FALSE);
626
627     uid = gumd_daemon_user_get_uid_by_name (username, gumd_daemon_get_config (
628                 self->priv->daemon));
629
630     user_adapter = _get_user_adapter_from_cache (self, invocation, uid);
631     if (!user_adapter) {
632         user = gumd_daemon_get_user (self->priv->daemon, (uid_t)uid, &error);
633         if (user) {
634             user_adapter = _create_and_cache_user_adapter (self, user,
635                     invocation);
636         }
637     }
638
639     if (user_adapter) {
640         gum_dbus_user_service_complete_get_user_by_name (
641                         self->priv->dbus_user_service, invocation,
642                 gumd_dbus_user_adapter_get_object_path (user_adapter));
643     } else {
644         if (!error) {
645             error = GUM_GET_ERROR_FOR_ID (GUM_ERROR_USER_NOT_FOUND,
646                     "User Not Found");
647         }
648         g_dbus_method_invocation_return_gerror (invocation, error);
649         g_error_free (error);
650     }
651
652     gum_disposable_set_auto_dispose (GUM_DISPOSABLE (self), TRUE);
653
654     return TRUE;
655 }
656
657 GumdDbusUserServiceAdapter *
658 gumd_dbus_user_service_adapter_new_with_connection (
659         GDBusConnection *bus_connection,
660         GumdDaemon *daemon,
661         GumdDbusServerBusType bus_type)
662 {
663     GError *err = NULL;
664     guint timeout = 0;
665     GumdDbusUserServiceAdapter *adapter = GUMD_DBUS_USER_SERVICE_ADAPTER (
666         g_object_new (GUMD_TYPE_USER_SERVICE_ADAPTER,
667             "daemon", daemon,
668             "bustype", bus_type,
669             "connection", bus_connection,
670             NULL));
671
672     if (!g_dbus_interface_skeleton_export (
673             G_DBUS_INTERFACE_SKELETON(adapter->priv->dbus_user_service),
674             adapter->priv->connection, GUM_USER_SERVICE_OBJECTPATH, &err)) {
675         WARN ("failed to register object: %s", err->message);
676         g_error_free (err);
677         g_object_unref (adapter);
678         return NULL;
679     }
680     DBG("(+) started user service interface '%p' at path '%s' on connection"
681             " '%p'", adapter, GUM_USER_SERVICE_OBJECTPATH, bus_connection);
682
683     timeout = gumd_daemon_get_timeout (adapter->priv->daemon);
684     if (timeout && bus_type != GUMD_DBUS_SERVER_BUSTYPE_P2P) {
685         gum_disposable_set_timeout (GUM_DISPOSABLE (adapter), timeout);
686     }
687
688     g_signal_connect_swapped (adapter->priv->dbus_user_service,
689         "handle-create-new-user", G_CALLBACK (_handle_create_new_user),
690         adapter);
691     g_signal_connect_swapped (adapter->priv->dbus_user_service,
692         "handle-get-user", G_CALLBACK(_handle_get_user), adapter);
693     g_signal_connect_swapped (adapter->priv->dbus_user_service,
694         "handle-get-user-by-name", G_CALLBACK(_handle_get_user_by_name),
695         adapter);
696
697     g_signal_connect (G_OBJECT (adapter->priv->daemon), "user-added",
698             G_CALLBACK (_on_user_added), adapter);
699     g_signal_connect (G_OBJECT (adapter->priv->daemon), "user-deleted",
700             G_CALLBACK (_on_user_deleted), adapter);
701     g_signal_connect (G_OBJECT (adapter->priv->daemon), "user-updated",
702             G_CALLBACK (_on_user_updated), adapter);
703
704     return adapter;
705 }