enable certificate validation code
[profile/ivi/message-port.git] / daemon / dbus-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
26 #include "dbus-manager.h"
27 #include "common/dbus-manager-glue.h"
28 #include "common/dbus-service-glue.h"
29 #include "common/dbus-error.h"
30 #include "common/log.h"
31 #include "dbus-service.h"
32 #include "dbus-server.h"
33 #include "manager.h"
34 #include "utils.h"
35
36 #include <aul/aul.h>
37 #include <pkgmgr-info.h>
38
39 G_DEFINE_TYPE (MsgPortDbusManager, msgport_dbus_manager, G_TYPE_OBJECT)
40
41 #define MSGPORT_DBUS_MANAGER_GET_PRIV(obj) \
42     G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSGPORT_TYPE_DBUS_MANAGER, MsgPortDbusManagerPrivate)
43
44 struct _MsgPortDbusManagerPrivate {
45     MsgPortDbusGlueManager *dbus_skeleton;
46     GDBusConnection        *connection;
47     MsgPortManager         *manager;
48     MsgPortDbusServer      *server;
49     gchar                  *app_id;
50     gboolean                is_null_cert;
51     GHashTable             *peer_certs;
52 };
53
54
55 static void
56 _dbus_manager_finalize (GObject *self)
57 {
58     //MsgPortDbusManager *manager = MSGPORT_DBUS_MANAGER (self);
59
60     G_OBJECT_CLASS (msgport_dbus_manager_parent_class)->finalize (self);
61 }
62
63 static void
64 _dbus_manager_dispose (GObject *self)
65 {
66     MsgPortDbusManager *dbus_mgr = MSGPORT_DBUS_MANAGER (self);
67
68     DBG ("Unexporting dbus manager %p on connection %p", dbus_mgr, dbus_mgr->priv->connection);
69     if (dbus_mgr->priv->dbus_skeleton) {
70         g_dbus_interface_skeleton_unexport (
71                 G_DBUS_INTERFACE_SKELETON (dbus_mgr->priv->dbus_skeleton));
72         g_clear_object (&dbus_mgr->priv->dbus_skeleton);
73     }
74
75     g_clear_object (&dbus_mgr->priv->connection);
76
77     /* unregister all services owned by this connection */
78     msgport_manager_unregister_services (dbus_mgr->priv->manager, dbus_mgr, NULL);
79
80     g_clear_object (&dbus_mgr->priv->manager);
81
82     if (dbus_mgr->priv->peer_certs) {
83         g_hash_table_unref (dbus_mgr->priv->peer_certs);
84         dbus_mgr->priv->peer_certs = NULL;
85     }
86
87     G_OBJECT_CLASS (msgport_dbus_manager_parent_class)->dispose (self);
88 }
89
90
91 static gboolean
92 _dbus_manager_handle_register_service (
93     MsgPortDbusManager    *dbus_mgr,
94     GDBusMethodInvocation *invocation,
95     const gchar           *port_name,
96     gboolean               is_trusted,
97     gpointer               userdata)
98 {
99     GError *error = NULL;
100     MsgPortDbusService *dbus_service = NULL;
101     msgport_return_val_if_fail (dbus_mgr &&  MSGPORT_IS_DBUS_MANAGER (dbus_mgr), FALSE);
102
103     DBG ("register service request from %p('%s') for port '%s', is_trusted: %d",
104         dbus_mgr, dbus_mgr->priv->app_id, port_name, is_trusted);
105
106     dbus_service = msgport_manager_register_service (
107             dbus_mgr->priv->manager, dbus_mgr, 
108             port_name, is_trusted, &error);
109
110     if (dbus_service) {
111         msgport_dbus_glue_manager_complete_register_service (
112                 dbus_mgr->priv->dbus_skeleton, invocation, 
113                 msgport_dbus_service_get_object_path(dbus_service));
114         return TRUE;
115     }
116
117     if (!error) error = msgport_error_unknown_new ();
118     g_dbus_method_invocation_take_error (invocation, error);
119
120     return TRUE;
121 }
122
123 static gboolean
124 _dbus_manager_handle_check_for_remote_service (
125     MsgPortDbusManager    *dbus_mgr,
126     GDBusMethodInvocation *invocation,
127     const gchar    *remote_app_id,
128     const gchar    *remote_port_name,
129     gboolean        is_trusted,
130     gpointer        userdata)
131 {
132     GError *error = NULL;
133     MsgPortDbusService *dbus_service = NULL;
134     MsgPortDbusManager *remote_dbus_manager = NULL;
135
136     msgport_return_val_if_fail (dbus_mgr && MSGPORT_IS_DBUS_MANAGER (dbus_mgr), FALSE);
137
138     DBG ("check remote service request from %p for '%s' '%s', is_trusted: %d", 
139             dbus_mgr, remote_app_id, remote_port_name, is_trusted);
140
141     remote_dbus_manager = msgport_dbus_server_get_dbus_manager_by_app_id (
142                 dbus_mgr->priv->server, remote_app_id);
143
144     if (remote_dbus_manager) {
145         dbus_service = msgport_manager_get_service (dbus_mgr->priv->manager, 
146                             remote_dbus_manager, remote_port_name, is_trusted, &error);
147         if (dbus_service) {
148             DBG ("Found service id : %d", msgport_dbus_service_get_id (dbus_service));
149             msgport_dbus_glue_manager_complete_check_for_remote_service (
150                 dbus_mgr->priv->dbus_skeleton, invocation, 
151                 msgport_dbus_service_get_id (dbus_service));
152             return TRUE;
153         }
154     }
155
156     if (!error) error = msgport_error_port_not_found (remote_app_id, remote_port_name);
157     g_dbus_method_invocation_take_error (invocation, error);
158
159     return TRUE;
160 }
161
162 static gboolean
163 _dbus_manager_handle_send_message (
164     MsgPortDbusManager    *dbus_mgr,
165     GDBusMethodInvocation *invocation,
166     guint                  service_id,
167     GVariant              *data,
168     gpointer               userdata)
169 {
170     GError *error = NULL;
171     MsgPortDbusService *peer_dbus_service = 0;
172
173     msgport_return_val_if_fail (dbus_mgr && MSGPORT_IS_DBUS_MANAGER (dbus_mgr), FALSE);
174
175     DBG ("send_message from %p('%s') to service_id %d", 
176         dbus_mgr, dbus_mgr->priv->app_id, service_id);
177
178     peer_dbus_service = msgport_manager_get_service_by_id (
179             dbus_mgr->priv->manager, service_id, &error);
180
181     if (peer_dbus_service) {
182         if (msgport_dbus_service_send_message (peer_dbus_service, data, dbus_mgr->priv->app_id, "", FALSE, &error)) {
183             msgport_dbus_glue_manager_complete_send_message (
184                 dbus_mgr->priv->dbus_skeleton, invocation);
185             return TRUE;
186         }
187     }
188
189     if (!error) error = msgport_error_unknown_new ();
190     g_dbus_method_invocation_take_error (invocation, error);
191
192     return TRUE;
193 }
194
195 static void
196 msgport_dbus_manager_class_init (MsgPortDbusManagerClass *klass)
197 {
198     GObjectClass *gklass = G_OBJECT_CLASS(klass);
199
200     g_type_class_add_private (klass, sizeof(MsgPortDbusManagerPrivate));
201
202     gklass->finalize = _dbus_manager_finalize;
203     gklass->dispose = _dbus_manager_dispose;
204 }
205
206 static void
207 msgport_dbus_manager_init (MsgPortDbusManager *self)
208 {
209     MsgPortDbusManagerPrivate *priv = MSGPORT_DBUS_MANAGER_GET_PRIV (self);
210
211     priv->dbus_skeleton = msgport_dbus_glue_manager_skeleton_new ();
212     priv->manager = msgport_manager_new ();
213     priv->is_null_cert = FALSE;
214     priv->peer_certs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
215
216     g_signal_connect_swapped (priv->dbus_skeleton, "handle-register-service",
217                 G_CALLBACK (_dbus_manager_handle_register_service), (gpointer)self);
218     g_signal_connect_swapped (priv->dbus_skeleton, "handle-check-for-remote-service",
219                 G_CALLBACK (_dbus_manager_handle_check_for_remote_service), (gpointer)self);
220     g_signal_connect_swapped (priv->dbus_skeleton, "handle-send-message",
221                 G_CALLBACK (_dbus_manager_handle_send_message), (gpointer)self);
222
223     self->priv = priv;
224 }
225 static gchar *
226 _get_app_id_from_connection (GDBusConnection *connection)
227 {
228     pid_t peer_pid;
229     GError *error = NULL;
230     GCredentials *cred = g_dbus_connection_get_peer_credentials (connection);
231
232     msgport_return_val_if_fail (cred != NULL, NULL);
233 #ifdef ENABLE_DEBUG
234     gchar *str_cred = g_credentials_to_string (cred);
235     DBG ("Client Credentials : %s", str_cred);
236     g_free (str_cred);
237 #endif
238
239     peer_pid = g_credentials_get_unix_pid (cred, &error);
240     if (error) {
241         WARN ("Faild to get peer pid on conneciton %p : %s", connection, error->message);
242         g_error_free (error);
243         return NULL;
244     }
245
246     char app_id[255];
247     aul_return_val res;
248     if ((res = aul_app_get_appid_bypid (peer_pid, app_id, sizeof(app_id))) == AUL_R_OK) {
249         return g_strdup (app_id);
250     }
251     WARN ("Fail to get appid of peer pid '%d', error : %d, considering pid as app_id", peer_pid, res);
252
253     return g_strdup_printf ("%d", peer_pid);
254
255     return NULL;
256 }
257
258 MsgPortDbusManager *
259 msgport_dbus_manager_new (
260     GDBusConnection *connection,
261     MsgPortDbusServer *server,
262     GError **error)
263 {
264     MsgPortDbusManager *dbus_mgr = NULL;
265
266     dbus_mgr = MSGPORT_DBUS_MANAGER (g_object_new (MSGPORT_TYPE_DBUS_MANAGER, NULL));
267     if (!dbus_mgr) {
268         if (error) *error = msgport_error_new (MSGPORT_ERROR_OUT_OF_MEMORY, "Out of memory");
269         return NULL;
270     }
271
272     if (!g_dbus_interface_skeleton_export (
273             G_DBUS_INTERFACE_SKELETON (dbus_mgr->priv->dbus_skeleton),
274             connection,
275             "/",
276             error)) {
277         WARN ("Failed to export dbus object on connection %p : %s",
278                     connection, error ? (*error)->message : "");
279         g_object_unref (dbus_mgr);
280         return NULL;
281     }
282     dbus_mgr->priv->connection = g_object_ref (connection);
283     dbus_mgr->priv->server = server;
284     dbus_mgr->priv->app_id =  _get_app_id_from_connection (connection);
285
286     return dbus_mgr;
287 }
288
289 MsgPortManager *
290 msgport_dbus_manager_get_manager (MsgPortDbusManager *dbus_manager)
291 {
292     msgport_return_val_if_fail (dbus_manager && MSGPORT_IS_DBUS_MANAGER (dbus_manager), NULL);
293
294     return dbus_manager->priv->manager;
295 }
296
297 GDBusConnection *
298 msgport_dbus_manager_get_connection (MsgPortDbusManager *dbus_manager)
299 {
300     msgport_return_val_if_fail (dbus_manager && MSGPORT_IS_DBUS_MANAGER (dbus_manager), NULL);
301
302     return dbus_manager->priv->connection;
303 }
304
305 const gchar *
306 msgport_dbus_manager_get_app_id (MsgPortDbusManager *dbus_manager)
307 {
308     msgport_return_val_if_fail (dbus_manager && MSGPORT_IS_DBUS_MANAGER (dbus_manager), NULL);
309
310     return (const gchar *)dbus_manager->priv->app_id;
311 }
312
313 gboolean
314 msgport_dbus_manager_validate_peer_certificate (MsgPortDbusManager *dbus_manager, const gchar *peer_app_id)
315 {
316     int res ;
317     pkgmgrinfo_cert_compare_result_type_e compare_result;
318     gboolean is_valid_cert = FALSE;
319
320     /* check if the source application has no certificate info */
321     if (dbus_manager->priv->is_null_cert)
322         return TRUE; /* allow all peers to connect */
323
324     /* check if we have cached status */
325     if (g_hash_table_contains (dbus_manager->priv->peer_certs, peer_app_id))
326         return ((gboolean)(glong)g_hash_table_lookup (dbus_manager->priv->peer_certs, peer_app_id));
327
328     if ((res = pkgmgrinfo_pkginfo_compare_app_cert_info (dbus_manager->priv->app_id,
329                     peer_app_id, &compare_result)) != PMINFO_R_OK) {
330         WARN ("Fail to compare certificates of applications('%s', '%s') : error %d", 
331                 dbus_manager->priv->app_id, peer_app_id, res);
332         return FALSE;
333     }
334
335     if (compare_result == PMINFO_CERT_COMPARE_LHS_NO_CERT) {
336         dbus_manager->priv->is_null_cert = TRUE;
337         return TRUE;
338     }
339
340     is_valid_cert = (compare_result == PMINFO_CERT_COMPARE_MATCH) ;
341     g_hash_table_insert (dbus_manager->priv->peer_certs, g_strdup (peer_app_id), (gpointer)is_valid_cert);
342
343     return is_valid_cert;
344 }
345