FIX TIVI-2641: Fix issue in trusted ports with no valid certificate info.
[profile/ivi/message-port.git] / lib / msgport-manager.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 message-port.
5  *
6  * Copyright (C) 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 #include "config.h" /* MESSAGEPORT_BUS_ADDRESS */
26
27 #include "msgport-manager.h"
28 #include "msgport-service.h"
29 #include "msgport-utils.h" /* msgport_daemon_error_to_error */
30 #include "message-port.h" /* messageport_error_e */
31 #include "common/dbus-manager-glue.h"
32 #ifdef  USE_SESSION_BUS
33 #include "common/dbus-server-glue.h"
34 #endif
35 #include "common/log.h"
36 #include <gio/gio.h>
37
38 struct _MsgPortManager
39 {
40     GObject parent;
41
42     MsgPortDbusGlueManager *proxy;
43     GHashTable *services; /* {gchar*:MsgPortService*} */
44     GHashTable *local_services; /* {gint: gchar *} */ 
45     GHashTable *remote_services; /* {gint: gchar *} */
46 };
47
48 G_DEFINE_TYPE (MsgPortManager, msgport_manager, G_TYPE_OBJECT)
49
50 static void
51 _unregister_service_cb (int service_id, const gchar *object_path, MsgPortManager *manager)
52 {
53     MsgPortService *service = g_hash_table_lookup (manager->services, object_path);
54
55     if (service) msgport_service_unregister (service);
56 }
57
58 static void
59 _finalize (GObject *self)
60 {
61     MsgPortManager *manager = MSGPORT_MANAGER (self);
62
63     if (manager->local_services) {
64         g_hash_table_unref (manager->local_services);
65         manager->local_services = NULL;
66     }
67
68     if (manager->remote_services) {
69         g_hash_table_unref (manager->remote_services);
70         manager->remote_services = NULL;
71     }
72
73     G_OBJECT_CLASS (msgport_manager_parent_class)->finalize (self);
74 }
75
76 static void
77 _dispose (GObject *self)
78 {
79     MsgPortManager *manager = MSGPORT_MANAGER (self);
80
81     g_hash_table_foreach (manager->local_services, (GHFunc)_unregister_service_cb, manager);
82
83     if (manager->services) {
84         g_hash_table_unref (manager->services);
85         manager->services = NULL;
86     }
87
88     g_clear_object (&manager->proxy);
89
90     G_OBJECT_CLASS (msgport_manager_parent_class)->dispose (self);
91 }
92
93 static void
94 msgport_manager_class_init (MsgPortManagerClass *klass)
95 {
96     GObjectClass *g_klass = G_OBJECT_CLASS (klass);
97
98     g_klass->finalize = _finalize;
99     g_klass->dispose = _dispose;
100 }
101
102 static void
103 msgport_manager_init (MsgPortManager *manager)
104 {
105     GError          *error = NULL;
106     GDBusConnection *connection = NULL;
107     gchar           *bus_address = NULL;
108
109     manager->services = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
110     manager->local_services = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
111     manager->remote_services = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
112
113 #ifdef USE_SESSION_BUS
114     MsgPortDbusGlueServer *server = NULL;
115     server = msgport_dbus_glue_server_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
116             G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
117             "org.tizen.messageport", "/", NULL, &error);
118
119     if (error) {
120         WARN ("fail to get server proxy : %s",  error->message);
121         g_error_free (error);
122     }
123     else {
124         msgport_dbus_glue_server_call_get_bus_address_sync (server, &bus_address, NULL, &error);
125         if (error) {
126             WARN ("Fail to get server bus address : %s", error->message);
127             g_error_free (error);
128         }
129     }
130
131     g_object_unref (server);
132 #endif
133     if (!bus_address) {
134         if (g_getenv("MESSAGEPORT_BUS_ADDRESS")) {
135             bus_address = g_strdup (g_getenv ("MESSAGEPORT_BUS_ADDRESS"));
136         }
137         else {
138 #       ifdef MESSAGEPORT_BUS_ADDRESS
139             bus_address = g_strdup_printf (MESSAGEPORT_BUS_ADDRESS);
140 #       endif
141         }
142     }
143     if (!bus_address)
144         bus_address = g_strdup_printf ("unix:path=%s/.message-port", g_get_user_runtime_dir());
145
146     connection = g_dbus_connection_new_for_address_sync (bus_address,
147             G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, NULL, &error);
148     if (error) {
149         WARN ("Fail to connect messageport server at address %s: %s", bus_address, error->message);
150         g_error_free (error);
151     }
152     else {
153         manager->proxy = msgport_dbus_glue_manager_proxy_new_sync (
154             connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, "/", NULL, &error);
155         if (error) {
156             WARN ("Fail to get manager proxy : %s", error->message);
157             g_error_free (error);
158         }
159     }
160
161     g_free (bus_address);
162 }
163
164 MsgPortManager * msgport_manager_new ()
165 {
166     return g_object_new (MSGPORT_TYPE_MANAGER, NULL);
167 }
168
169 static messageport_error_e
170 _create_and_cache_service (MsgPortManager *manager, gchar *object_path, messageport_message_cb cb, int *service_id)
171 {
172     int id;
173     MsgPortService *service = msgport_service_new (
174             g_dbus_proxy_get_connection (G_DBUS_PROXY(manager->proxy)),
175             object_path, cb);
176     if (!service) {
177         g_free (object_path);
178         return MESSAGEPORT_ERROR_OUT_OF_MEMORY;
179     }
180
181     id = msgport_service_id (service);
182
183     g_hash_table_insert (manager->services, object_path, service);
184     g_hash_table_insert (manager->local_services, GINT_TO_POINTER (id), object_path);
185
186     if (service_id) *service_id = id;
187
188     return MESSAGEPORT_ERROR_NONE;
189 }
190
191 typedef struct {
192     const gchar *name;
193     gboolean is_trusted;
194 } FindServiceData ;
195
196 static gboolean
197 _find_service (gpointer key, gpointer value, gpointer data)
198 {
199     FindServiceData *service_data = (FindServiceData*)data;
200     MsgPortService *service = (MsgPortService *)value;
201
202     return g_strcmp0 (msgport_service_name (service), service_data->name) == 0
203            && msgport_service_is_trusted (service) == service_data->is_trusted;
204 }
205     
206
207 messageport_error_e
208 msgport_manager_register_service (MsgPortManager *manager, const gchar *port_name, gboolean is_trusted, messageport_message_cb message_cb, int *service_id)
209 {
210     GError *error = NULL;
211     gchar *object_path = NULL;
212     FindServiceData service_data;
213     MsgPortService *service = NULL;
214
215     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
216     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
217     g_return_val_if_fail (service_id && port_name && message_cb, MESSAGEPORT_ERROR_INVALID_PARAMETER);
218
219     /* first check in cached services if found any */
220     service_data.name = port_name;
221     service_data.is_trusted = is_trusted;
222     service = g_hash_table_find (manager->services, _find_service, &service_data);
223
224     if (service) {
225         int id = msgport_service_id (service);
226         DBG ("Cached local port found for name '%s:%d' with ID : %d", port_name, is_trusted, id);
227
228         /* update message handler */
229         msgport_service_set_message_handler (service, message_cb);
230         *service_id = id;
231
232         return MESSAGEPORT_ERROR_NONE;
233     }
234
235     msgport_dbus_glue_manager_call_register_service_sync (manager->proxy,
236             port_name, is_trusted, &object_path, NULL, &error);
237
238     if (error) {
239         messageport_error_e err = msgport_daemon_error_to_error (error);
240         WARN ("unable to register service (%s): %s", port_name, error->message);
241         g_error_free (error);
242         return err; 
243     }
244
245     return _create_and_cache_service (manager, object_path, message_cb, service_id);
246 }
247
248 static MsgPortService *
249 _get_local_port (MsgPortManager *manager, int service_id)
250 {
251     const gchar *object_path = NULL;
252     MsgPortService *service = NULL;
253
254     object_path = g_hash_table_lookup (manager->local_services, GINT_TO_POINTER(service_id));
255     if (!object_path) return NULL;
256
257     service = MSGPORT_SERVICE (g_hash_table_lookup (manager->services, object_path));
258     if (!service) {
259         g_hash_table_remove (manager->local_services, GINT_TO_POINTER (service_id));
260         return NULL;
261     }
262
263     return service;
264 }
265
266 messageport_error_e
267 msgport_manager_unregister_servcie (MsgPortManager *manager, int service_id)
268 {
269     const gchar *object_path = NULL;
270     MsgPortService *service = NULL;
271     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), FALSE);
272     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
273
274     service = _get_local_port (manager, service_id);
275     if (!service) {
276         WARN ("No local service found for service id '%d'", service_id);
277         return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
278     }
279
280     if (!msgport_service_unregister (service)) 
281         return MESSAGEPORT_ERROR_IO_ERROR;
282
283     object_path = (const gchar *)g_hash_table_lookup (manager->local_services,
284                                                       GINT_TO_POINTER(service_id));
285     g_hash_table_remove (manager->local_services, GINT_TO_POINTER(service_id));
286     g_hash_table_remove (manager->services, object_path);
287
288     return MESSAGEPORT_ERROR_NONE;
289 }
290
291 messageport_error_e 
292 msgport_manager_check_remote_service (MsgPortManager *manager, const gchar *app_id, const gchar *port, gboolean is_trusted, guint *service_id_out)
293 {
294     GError *error = NULL;
295     guint remote_service_id = 0;
296
297     if (service_id_out) *service_id_out = 0;
298
299     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
300     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
301     g_return_val_if_fail (app_id && port, MESSAGEPORT_ERROR_INVALID_PARAMETER);
302
303     if (!app_id || !port) return MESSAGEPORT_ERROR_INVALID_PARAMETER;
304
305     msgport_dbus_glue_manager_call_check_for_remote_service_sync (manager->proxy,
306             app_id, port, is_trusted, &remote_service_id, NULL, &error);
307
308     if (error) {
309         messageport_error_e err = msgport_daemon_error_to_error (error);
310         WARN ("No %sservice found for app_id %s, port name %s: %s", 
311                 is_trusted ? "trusted " : "", app_id, port, error->message);
312         g_error_free (error);
313         return err;
314     }
315     else {
316         DBG ("Got service id %d for %s, %s", remote_service_id, app_id, port);
317         if (service_id_out)  *service_id_out = remote_service_id;
318     }
319
320     return MESSAGEPORT_ERROR_NONE;
321 }
322
323 messageport_error_e
324 msgport_manager_get_service_name (MsgPortManager *manager, int service_id, gchar **name_out)
325 {
326     MsgPortService *service = NULL;
327     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
328     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
329     g_return_val_if_fail (name_out && service_id, MESSAGEPORT_ERROR_INVALID_PARAMETER);
330
331     service = _get_local_port (manager, service_id);
332     if (!service) return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
333
334     *name_out = g_strdup (msgport_service_name (service));
335
336     return MESSAGEPORT_ERROR_NONE;
337 }
338
339 messageport_error_e
340 msgport_manager_get_service_is_trusted (MsgPortManager *manager, int service_id, gboolean *is_trusted_out)
341 {
342     MsgPortService *service = NULL;
343     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
344     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
345     g_return_val_if_fail (service_id && is_trusted_out, MESSAGEPORT_ERROR_INVALID_PARAMETER);
346
347     service = _get_local_port (manager, service_id);
348     if (!service) return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
349
350     *is_trusted_out = msgport_service_is_trusted (service);
351
352     return MESSAGEPORT_ERROR_NONE;
353 }
354
355 messageport_error_e
356 msgport_manager_send_message (MsgPortManager *manager, const gchar *remote_app_id, const gchar *remote_port, gboolean is_trusted, GVariant *data)
357 {
358     guint service_id = 0;
359     GError *error = NULL;
360     messageport_error_e err;
361
362     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
363     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
364     g_return_val_if_fail (remote_app_id && remote_port, MESSAGEPORT_ERROR_INVALID_PARAMETER);
365
366     err = msgport_manager_check_remote_service (manager, remote_app_id, remote_port, is_trusted, &service_id);
367     if (service_id == 0) return err;
368
369     msgport_dbus_glue_manager_call_send_message_sync (manager->proxy, service_id, data, NULL, &error);
370
371     if (error) {
372         err = msgport_daemon_error_to_error (error);
373         WARN ("Failed to send message to (%s:%s) : %s", remote_app_id, remote_port, error->message);
374         g_error_free (error);
375         return err;
376     }
377
378     return MESSAGEPORT_ERROR_NONE;
379 }
380
381 messageport_error_e
382 msgport_manager_send_bidirectional_message (MsgPortManager *manager, int local_port_id, const gchar *remote_app_id, const gchar *remote_port, gboolean is_trusted, GVariant *data)
383 {
384     MsgPortService *service = NULL;
385     guint remote_service_id = 0;
386     messageport_error_e res = 0;
387
388     g_return_val_if_fail (manager && MSGPORT_IS_MANAGER (manager), MESSAGEPORT_ERROR_IO_ERROR);
389     g_return_val_if_fail (manager->proxy, MESSAGEPORT_ERROR_IO_ERROR);
390     g_return_val_if_fail (local_port_id > 0 && remote_app_id && remote_port, MESSAGEPORT_ERROR_INVALID_PARAMETER);
391
392     service = _get_local_port (manager, local_port_id);
393     if (!service) {
394         WARN ("No local service found for service id '%d'", local_port_id);
395         return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
396     }
397
398     if ((res = msgport_manager_check_remote_service (manager, remote_app_id, remote_port, is_trusted, &remote_service_id) != MESSAGEPORT_ERROR_NONE)) {
399         WARN ("No remote %sport informatuon for %s:%s, error : %d", is_trusted ? "trusted " : "", remote_app_id, remote_port, res);
400         return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
401     }
402
403     DBG ("Sending message from local service '%p' to remote sercie id '%d'", service, remote_service_id);
404     return msgport_service_send_message (service, remote_service_id, data);
405 }
406