Update to upstream 1.0.1
[profile/ivi/gsignond.git] / src / daemon / dbus / gsignond-dbus-auth-session-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 gsignond
5  *
6  * Copyright (C) 2012-2013 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.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 "gsignond/gsignond-log.h"
28 #include "gsignond/gsignond-utils.h"
29 #include "gsignond/gsignond-error.h"
30 #include "gsignond-dbus-auth-session-adapter.h"
31 #include "gsignond-dbus.h"
32
33 enum
34 {
35     PROP_0,
36     PROP_SESSION,
37     PROP_CONNECTION,
38     PROP_APP_CONTEXT,
39     N_PROPERTIES
40 };
41
42 static GParamSpec *properties[N_PROPERTIES];
43
44 struct _GSignondDbusAuthSessionAdapterPrivate
45 {
46     GDBusConnection     *connection;
47     GSignondDbusAuthSession *dbus_auth_session;
48     GSignondAuthSession *session;
49     gchar *app_context;
50     gboolean is_process_active;
51     GSignondSecurityContext *ctx;
52 };
53
54 G_DEFINE_TYPE (GSignondDbusAuthSessionAdapter, gsignond_dbus_auth_session_adapter, GSIGNOND_TYPE_DISPOSABLE)
55
56
57 #define GSIGNOND_DBUS_AUTH_SESSION_ADAPTER_GET_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_DBUS_AUTH_SESSION_ADAPTER, GSignondDbusAuthSessionAdapterPrivate)
58
59 #define PREPARE_SECURITY_CONTEXT(dbus_object, invocation) \
60 { \
61     GSignondDbusAuthSessionAdapterPrivate *priv = dbus_object->priv; \
62     GSignondAccessControlManager *acm = gsignond_auth_session_get_acm (priv->session); \
63     const gchar *sender = NULL; \
64     int fd = -1; \
65     sender = g_dbus_method_invocation_get_sender (invocation); \
66     if (!sender) {\
67         GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation);\
68         fd = g_socket_get_fd(g_socket_connection_get_socket(G_SOCKET_CONNECTION(g_dbus_connection_get_stream (connection))));\
69     }\
70     gsignond_access_control_manager_security_context_of_peer( \
71             acm, \
72             priv->ctx, \
73             fd, \
74             sender, \
75             priv->app_context); \
76 }
77
78 static gboolean _handle_query_available_mechanisms (GSignondDbusAuthSessionAdapter *, GDBusMethodInvocation *, const gchar **, gpointer);
79 static gboolean _handle_process (GSignondDbusAuthSessionAdapter *, GDBusMethodInvocation *, const GVariant *, const gchar *, gpointer);
80 static gboolean _handle_cancel (GSignondDbusAuthSessionAdapter *, GDBusMethodInvocation *, gpointer);
81
82 static void
83 gsignond_dbus_auth_session_adapter_set_property (GObject *object,
84         guint property_id,
85         const GValue *value, GParamSpec *pspec)
86 {
87     GSignondDbusAuthSessionAdapter *self = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER (object);
88
89     switch (property_id) {
90         case PROP_SESSION: {
91             gpointer object = g_value_get_object (value);
92             self->priv->session = GSIGNOND_AUTH_SESSION ((object));
93             break;
94         }
95         case PROP_CONNECTION: {
96             if (self->priv->connection) g_object_unref (self->priv->connection);
97             self->priv->connection = G_DBUS_CONNECTION (g_value_dup_object (value));
98             break;
99         }
100         case PROP_APP_CONTEXT: {
101             if (self->priv->app_context) g_free (self->priv->app_context);
102             self->priv->app_context = g_strdup (g_value_get_string (value));
103             break;
104         }
105         default:
106             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
107     }
108 }
109
110 static void
111 gsignond_dbus_auth_session_adapter_get_property (GObject *object,
112         guint property_id,
113         GValue *value, 
114         GParamSpec *pspec)
115 {
116     GSignondDbusAuthSessionAdapter *self = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER (object);
117
118     switch (property_id) {
119         case PROP_SESSION: {
120             g_value_set_object (value, self->priv->session);
121             break;
122         }
123         case PROP_CONNECTION:
124             g_value_set_object (value, self->priv->connection);
125             break;
126         case PROP_APP_CONTEXT:
127             g_value_set_string (value, self->priv->app_context);
128             break;
129         default:
130             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
131     }
132 }
133
134 static void
135 gsignond_dbus_auth_session_adapter_dispose (GObject *object)
136 {
137     GSignondDbusAuthSessionAdapter *self = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER (object);
138
139     if (self->priv->session) {
140         if (self->priv->is_process_active) {
141             gsignond_auth_session_abort_process (self->priv->session);
142             self->priv->is_process_active = FALSE;
143         }
144
145         g_object_unref (self->priv->session);
146         self->priv->session = NULL;
147     }
148
149     if (self->priv->dbus_auth_session) {
150         gsignond_dbus_auth_session_emit_unregistered (self->priv->dbus_auth_session);
151         DBG("(-)'%s' object unexported", g_dbus_interface_skeleton_get_object_path (
152             G_DBUS_INTERFACE_SKELETON(self->priv->dbus_auth_session)));
153         g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON(self->priv->dbus_auth_session));
154         g_object_unref (self->priv->dbus_auth_session);
155         self->priv->dbus_auth_session = NULL;
156     }
157
158     if (self->priv->connection) {
159         g_object_unref (self->priv->connection);
160         self->priv->connection = NULL;
161     }
162
163     G_OBJECT_CLASS(gsignond_dbus_auth_session_adapter_parent_class)->dispose (object);
164 }
165
166 static void
167 gsignond_dbus_auth_session_adapter_finalize (GObject *object)
168 {
169     GSignondDbusAuthSessionAdapter *self = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER (object);
170
171     if (self->priv->ctx) {
172         gsignond_security_context_free (self->priv->ctx);
173         self->priv->ctx = NULL;
174     }
175
176     if (self->priv->app_context) {
177         g_free (self->priv->app_context);
178         self->priv->app_context = NULL;
179     }
180
181     G_OBJECT_CLASS (gsignond_dbus_auth_session_adapter_parent_class)->finalize (object);
182 }
183
184 static void
185 gsignond_dbus_auth_session_adapter_class_init (GSignondDbusAuthSessionAdapterClass *klass)
186 {
187     GObjectClass* object_class = G_OBJECT_CLASS (klass);
188
189     g_type_class_add_private (object_class, sizeof (GSignondDbusAuthSessionAdapterPrivate));
190
191     object_class->get_property = gsignond_dbus_auth_session_adapter_get_property;
192     object_class->set_property = gsignond_dbus_auth_session_adapter_set_property;
193     object_class->dispose = gsignond_dbus_auth_session_adapter_dispose;
194     object_class->finalize = gsignond_dbus_auth_session_adapter_finalize;
195
196     properties[PROP_SESSION] = g_param_spec_object ("auth-session",
197                                                     "Core auth session object",
198                                                     "Core AuthSession Object",
199                                                     GSIGNOND_TYPE_AUTH_SESSION,
200                                                     G_PARAM_READWRITE |
201                                                     G_PARAM_CONSTRUCT_ONLY |
202                                                     G_PARAM_STATIC_STRINGS);
203
204     properties[PROP_CONNECTION] = g_param_spec_object ("connection",
205                                                        "Dbus connection used",
206                                                        "Dbus connection used",
207                                                        G_TYPE_DBUS_CONNECTION,
208                                                        G_PARAM_READWRITE |
209                                                        G_PARAM_CONSTRUCT_ONLY | 
210                                                        G_PARAM_STATIC_STRINGS);
211     properties[PROP_APP_CONTEXT] = g_param_spec_string (
212                 "app-context",
213                 "application security context",
214                 "Application security context of the identity object creater",
215                 NULL,
216                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
217
218     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
219 }
220
221 static void
222 gsignond_dbus_auth_session_adapter_init (GSignondDbusAuthSessionAdapter *self)
223 {
224     self->priv = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER_GET_PRIV(self);
225
226     self->priv->connection = 0;
227     self->priv->session = 0;
228     self->priv->app_context = 0;
229     self->priv->is_process_active = FALSE;
230     self->priv->dbus_auth_session = gsignond_dbus_auth_session_skeleton_new ();
231     self->priv->ctx = gsignond_security_context_new ();
232
233     g_signal_connect_swapped (self->priv->dbus_auth_session,
234         "handle-query-available-mechanisms", 
235         G_CALLBACK (_handle_query_available_mechanisms), self);
236     g_signal_connect_swapped (self->priv->dbus_auth_session, "handle-process", G_CALLBACK(_handle_process), self);
237     g_signal_connect_swapped (self->priv->dbus_auth_session, "handle-cancel", G_CALLBACK(_handle_cancel), self);
238 }
239
240 static gboolean
241 _handle_query_available_mechanisms (GSignondDbusAuthSessionAdapter *self,
242                                     GDBusMethodInvocation *invocation,
243                                     const gchar **wanted_mechanisms,
244                                     gpointer user_data)
245 {
246     gchar **mechanisms = NULL;
247     GError *error = NULL;
248
249     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER (self), FALSE);
250
251     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), FALSE);
252
253     PREPARE_SECURITY_CONTEXT (self, invocation);
254
255     mechanisms = gsignond_auth_session_query_available_mechanisms (
256         self->priv->session, wanted_mechanisms, self->priv->ctx, &error);
257
258     if (mechanisms) {
259         gsignond_dbus_auth_session_complete_query_available_mechanisms (
260             self->priv->dbus_auth_session, invocation, (const gchar * const *)mechanisms);
261         g_free (mechanisms);
262     }
263     else {
264         g_dbus_method_invocation_return_gerror (invocation, error);
265         g_error_free (error);
266     }
267
268     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), TRUE);
269
270     return TRUE;
271 }
272
273 typedef struct {
274     GSignondDbusAuthSessionAdapter *adapter;
275     GDBusMethodInvocation *invocation;
276 } _AuthSessionDbusInfo;
277
278 static _AuthSessionDbusInfo*
279 _auth_session_dbus_info_new (GSignondDbusAuthSessionAdapter *self, GDBusMethodInvocation *invocation)
280 {
281     _AuthSessionDbusInfo *info = g_slice_new0(_AuthSessionDbusInfo);
282
283     info->adapter = g_object_ref (self);
284     info->invocation = g_object_ref (invocation);
285
286     return info;
287 }
288
289 static void
290 _auth_session_dbus_info_free (_AuthSessionDbusInfo *info)
291 {
292     if (!info) return;
293
294     g_object_unref (info->adapter);
295     g_object_unref (info->invocation);
296
297     g_slice_free (_AuthSessionDbusInfo, info);
298 }
299
300 static void
301 _emit_state_changed (gint state, const gchar *message, gpointer user_data)
302 {
303     GSignondDbusAuthSessionAdapter *self = NULL;
304     _AuthSessionDbusInfo *info = (_AuthSessionDbusInfo*) user_data;
305
306     if (!info || !GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER(info->adapter)) return ;
307
308     self = info->adapter;
309     gsignond_dbus_auth_session_emit_state_changed (
310             self->priv->dbus_auth_session, state, message);
311 }
312
313 static void
314 _on_process_done (GSignondSessionData *reply, const GError *error, gpointer user_data)
315 {
316     GSignondDbusAuthSessionAdapter *self = NULL;
317     _AuthSessionDbusInfo *info = (_AuthSessionDbusInfo*) user_data;
318
319     if (!info || !GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER(info->adapter)) return ;
320
321     self = info->adapter;
322
323     if (self->priv->is_process_active) {
324         self->priv->is_process_active = FALSE;
325
326         if (error) {
327             DBG("ERROR : %s(%d)", error->message, error->code);
328             GError *dbus_err = gsignond_get_gerror_for_id (error->code, error->message, NULL);
329             g_dbus_method_invocation_take_error (info->invocation, dbus_err);
330         }
331         else {
332             GVariant *result = gsignond_dictionary_to_variant ((GSignondDictionary *)reply); 
333             gsignond_dbus_auth_session_complete_process (
334                     self->priv->dbus_auth_session, info->invocation, result);
335         }
336     }
337     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), TRUE);
338
339     _auth_session_dbus_info_free (info);
340 }
341
342 static gboolean
343 _handle_process (GSignondDbusAuthSessionAdapter *self,
344                  GDBusMethodInvocation *invocation,
345                  const GVariant *session_data,
346                  const gchar *mechanisms,
347                  gpointer user_data)
348 {
349     _AuthSessionDbusInfo *info = 0;
350     GError *error = NULL;
351     GSignondSessionData *data = NULL;
352
353     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER (self), FALSE);
354
355     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), FALSE);
356
357     PREPARE_SECURITY_CONTEXT (self, invocation);
358
359     data = (GSignondSessionData *)gsignond_dictionary_new_from_variant ((GVariant *)session_data);
360     info = _auth_session_dbus_info_new (self, invocation);
361     self->priv->is_process_active = TRUE;
362     if (!gsignond_auth_session_process (self->priv->session, data, mechanisms, 
363                 self->priv->ctx, _on_process_done,
364                 _emit_state_changed, info, &error)) {
365         g_dbus_method_invocation_return_gerror (invocation, error);
366         g_error_free (error);
367  
368         _auth_session_dbus_info_free (info);
369         
370         self->priv->is_process_active = FALSE;
371
372         gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), TRUE);
373     }
374
375     gsignond_dictionary_unref (data);
376
377     return TRUE;
378 }
379
380 static gboolean
381 _handle_cancel (GSignondDbusAuthSessionAdapter *self,
382                 GDBusMethodInvocation *invocation,
383                 gpointer user_data)
384 {
385     GError *error = NULL;
386
387     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER (self), FALSE);
388
389     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), FALSE);
390
391     PREPARE_SECURITY_CONTEXT (self, invocation);
392
393     if (gsignond_auth_session_cancel (self->priv->session, self->priv->ctx, &error))
394         gsignond_dbus_auth_session_complete_cancel (self->priv->dbus_auth_session, invocation);
395     else {
396         g_dbus_method_invocation_return_gerror (invocation, error);
397         g_error_free (error);
398     }
399
400     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (self), TRUE);
401
402     return TRUE;
403 }
404
405 const gchar *
406 gsignond_dbus_auth_session_adapter_get_object_path (GSignondDbusAuthSessionAdapter *self)
407 {
408     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER(self), NULL);
409
410     return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON(self->priv->dbus_auth_session));
411 }
412
413 gboolean
414 gsignond_dbus_auth_session_adapter_is_process_active (GSignondDbusAuthSessionAdapter *self)
415 {
416     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER (self), FALSE);
417
418     return self->priv->is_process_active;
419 }
420
421 gboolean
422 gsignond_dbus_auth_session_adapter_abort_process (GSignondDbusAuthSessionAdapter *self)
423 {
424     g_return_val_if_fail (self && GSIGNOND_IS_DBUS_AUTH_SESSION_ADAPTER (self), FALSE);
425
426     if (self->priv->is_process_active) {
427         gsignond_auth_session_abort_process (self->priv->session);
428         self->priv->is_process_active = FALSE;
429     }
430
431     return TRUE;
432 }
433
434 GSignondDbusAuthSessionAdapter *
435 gsignond_dbus_auth_session_adapter_new_with_connection (GDBusConnection *connection, 
436                                                         GSignondAuthSession *session,
437                                                         const gchar *app_context,
438                                                         guint timeout)
439 {
440     static guint32 object_counter = 0;
441     gchar *nonce;
442     gchar *object_path = NULL;
443     GSignondDbusAuthSessionAdapter *adapter = NULL;
444     GError *error = NULL;
445     
446     adapter = GSIGNOND_DBUS_AUTH_SESSION_ADAPTER (
447         g_object_new (GSIGNOND_TYPE_DBUS_AUTH_SESSION_ADAPTER, 
448             "connection", connection, "auth-session", session, "app-context", app_context, NULL));
449
450     if (!adapter) return NULL;
451
452     nonce = gsignond_generate_nonce ();
453     object_path = g_strdup_printf ("%s/AuthSession_%s_%d",
454                                    GSIGNOND_DAEMON_OBJECTPATH,
455                                    nonce,
456                                    object_counter++);
457     g_free (nonce);
458     if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (adapter->priv->dbus_auth_session),
459                                            adapter->priv->connection,
460                                            object_path,
461                                            &error)) {
462         ERR ("failed to register object: %s", error->message);
463         g_error_free (error);
464         g_free (object_path);
465         g_object_unref (adapter);
466         return NULL;
467     }
468     DBG("(+) '%s' object exported", object_path);
469     g_free (object_path);
470
471     gsignond_disposable_set_timeout (GSIGNOND_DISPOSABLE(adapter), timeout);
472
473     return adapter;
474 }
475
476 #ifndef USE_P2P
477 GSignondDbusAuthSessionAdapter *
478 gsignond_dbus_auth_session_adapter_new (GSignondAuthSession *session, const gchar *app_context, guint timeout)
479 {
480     GError *error = NULL;
481     GDBusConnection *connection = g_bus_get_sync (GSIGNOND_BUS_TYPE, NULL, &error);
482     if (error) {
483         ERR ("Error getting session bus :%s", error->message);
484         g_error_free (error);
485         return NULL;
486     }
487
488     return gsignond_dbus_auth_session_adapter_new_with_connection (connection, session, app_context, timeout);
489 }
490 #endif