service: Disconnect the connecting service when needed
[platform/upstream/connman.git] / src / dbus.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <errno.h>
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 dbus_bool_t connman_dbus_validate_ident(const char *ident)
33 {
34         unsigned int i;
35
36         if (ident == NULL)
37                 return FALSE;
38
39         for (i = 0; i < strlen(ident); i++) {
40                 if (ident[i] >= '0' && ident[i] <= '9')
41                         continue;
42                 if (ident[i] >= 'a' && ident[i] <= 'z')
43                         continue;
44                 if (ident[i] >= 'A' && ident[i] <= 'Z')
45                         continue;
46                 return FALSE;
47         }
48
49         return TRUE;
50 }
51
52 char *connman_dbus_encode_string(const char *value)
53 {
54         GString *str;
55         unsigned int i, size;
56
57         if (value == NULL)
58                 return NULL;
59
60         size = strlen(value);
61
62         str = g_string_new(NULL);
63         if (str == NULL)
64                 return NULL;
65
66         for (i = 0; i < size; i++) {
67                 const char tmp = value[i];
68                 if ((tmp < '0' || tmp > '9') && (tmp < 'A' || tmp > 'Z') &&
69                                                 (tmp < 'a' || tmp > 'z'))
70                         g_string_append_printf(str, "_%02x", tmp);
71                 else
72                         str = g_string_append_c(str, tmp);
73         }
74
75         return g_string_free(str, FALSE);
76 }
77
78 void connman_dbus_property_append_basic(DBusMessageIter *iter,
79                                         const char *key, int type, void *val)
80 {
81         DBusMessageIter value;
82         const char *signature;
83
84         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
85
86         switch (type) {
87         case DBUS_TYPE_BOOLEAN:
88                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
89                 break;
90         case DBUS_TYPE_STRING:
91                 signature = DBUS_TYPE_STRING_AS_STRING;
92                 break;
93         case DBUS_TYPE_BYTE:
94                 signature = DBUS_TYPE_BYTE_AS_STRING;
95                 break;
96         case DBUS_TYPE_UINT16:
97                 signature = DBUS_TYPE_UINT16_AS_STRING;
98                 break;
99         case DBUS_TYPE_INT16:
100                 signature = DBUS_TYPE_INT16_AS_STRING;
101                 break;
102         case DBUS_TYPE_UINT32:
103                 signature = DBUS_TYPE_UINT32_AS_STRING;
104                 break;
105         case DBUS_TYPE_INT32:
106                 signature = DBUS_TYPE_INT32_AS_STRING;
107                 break;
108         case DBUS_TYPE_UINT64:
109                 signature = DBUS_TYPE_UINT64_AS_STRING;
110                 break;
111         case DBUS_TYPE_INT64:
112                 signature = DBUS_TYPE_INT64_AS_STRING;
113                 break;
114         case DBUS_TYPE_OBJECT_PATH:
115                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
116                 break;
117         default:
118                 signature = DBUS_TYPE_VARIANT_AS_STRING;
119                 break;
120         }
121
122         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
123                                                         signature, &value);
124         dbus_message_iter_append_basic(&value, type, val);
125         dbus_message_iter_close_container(iter, &value);
126 }
127
128 void connman_dbus_property_append_dict(DBusMessageIter *iter, const char *key,
129                         connman_dbus_append_cb_t function, void *user_data)
130 {
131         DBusMessageIter value, dict;
132
133         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
134
135         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
136                         DBUS_TYPE_ARRAY_AS_STRING
137                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
138                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
139                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &value);
140
141         connman_dbus_dict_open(&value, &dict);
142         if (function)
143                 function(&dict, user_data);
144         connman_dbus_dict_close(&value, &dict);
145
146         dbus_message_iter_close_container(iter, &value);
147 }
148
149 void connman_dbus_property_append_fixed_array(DBusMessageIter *iter,
150                                 const char *key, int type, void *val, int len)
151 {
152         DBusMessageIter value, array;
153         const char *variant_sig, *array_sig;
154
155         switch (type) {
156         case DBUS_TYPE_BYTE:
157                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
158                 array_sig = DBUS_TYPE_BYTE_AS_STRING;
159                 break;
160         default:
161                 return;
162         }
163
164         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
165
166         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
167                                                         variant_sig, &value);
168
169         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
170                                                         array_sig, &array);
171         dbus_message_iter_append_fixed_array(&array, type, val, len);
172         dbus_message_iter_close_container(&value, &array);
173
174         dbus_message_iter_close_container(iter, &value);
175 }
176
177 void connman_dbus_property_append_array(DBusMessageIter *iter,
178                                                 const char *key, int type,
179                         connman_dbus_append_cb_t function, void *user_data)
180 {
181         DBusMessageIter value, array;
182         const char *variant_sig, *array_sig;
183
184         switch (type) {
185         case DBUS_TYPE_STRING:
186                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
187                 array_sig = DBUS_TYPE_STRING_AS_STRING;
188                 break;
189         case DBUS_TYPE_OBJECT_PATH:
190                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING;
191                 array_sig = DBUS_TYPE_OBJECT_PATH_AS_STRING;
192                 break;
193         case DBUS_TYPE_DICT_ENTRY:
194                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING
195                                 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
196                                 DBUS_TYPE_ARRAY_AS_STRING
197                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
198                                                 DBUS_TYPE_STRING_AS_STRING
199                                                 DBUS_TYPE_VARIANT_AS_STRING
200                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
201                                 DBUS_STRUCT_END_CHAR_AS_STRING;
202                 array_sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
203                                 DBUS_TYPE_ARRAY_AS_STRING
204                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
205                                                 DBUS_TYPE_STRING_AS_STRING
206                                                 DBUS_TYPE_VARIANT_AS_STRING
207                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
208                                 DBUS_STRUCT_END_CHAR_AS_STRING;
209                 break;
210         default:
211                 return;
212         }
213
214         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
215
216         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
217                                                         variant_sig, &value);
218
219         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
220                                                         array_sig, &array);
221         if (function)
222                 function(&array, user_data);
223         dbus_message_iter_close_container(&value, &array);
224
225         dbus_message_iter_close_container(iter, &value);
226 }
227
228 static DBusConnection *connection = NULL;
229
230 dbus_bool_t connman_dbus_property_changed_basic(const char *path,
231                                 const char *interface, const char *key,
232                                                         int type, void *val)
233 {
234         DBusMessage *signal;
235         DBusMessageIter iter;
236
237         if (path == NULL)
238                 return FALSE;
239
240         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
241         if (signal == NULL)
242                 return FALSE;
243
244         dbus_message_iter_init_append(signal, &iter);
245         connman_dbus_property_append_basic(&iter, key, type, val);
246
247         g_dbus_send_message(connection, signal);
248
249         return TRUE;
250 }
251
252 dbus_bool_t connman_dbus_property_changed_dict(const char *path,
253                                 const char *interface, const char *key,
254                         connman_dbus_append_cb_t function, void *user_data)
255 {
256         DBusMessage *signal;
257         DBusMessageIter iter;
258
259         if (path == NULL)
260                 return FALSE;
261
262         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
263         if (signal == NULL)
264                 return FALSE;
265
266         dbus_message_iter_init_append(signal, &iter);
267         connman_dbus_property_append_dict(&iter, key, function, user_data);
268
269         g_dbus_send_message(connection, signal);
270
271         return TRUE;
272 }
273
274 dbus_bool_t connman_dbus_property_changed_array(const char *path,
275                         const char *interface, const char *key, int type,
276                         connman_dbus_append_cb_t function, void *user_data)
277 {
278         DBusMessage *signal;
279         DBusMessageIter iter;
280
281         if (path == NULL)
282                 return FALSE;
283
284         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
285         if (signal == NULL)
286                 return FALSE;
287
288         dbus_message_iter_init_append(signal, &iter);
289         connman_dbus_property_append_array(&iter, key, type,
290                                                 function, user_data);
291
292         g_dbus_send_message(connection, signal);
293
294         return TRUE;
295 }
296
297 dbus_bool_t connman_dbus_setting_changed_basic(const char *owner,
298                                 const char *path, const char *key,
299                                 int type, void *val)
300 {
301         DBusMessage *msg;
302         DBusMessageIter array, dict;
303
304         if (owner == NULL || path == NULL)
305                 return FALSE;
306
307         msg = dbus_message_new_method_call(owner, path,
308                                                 CONNMAN_NOTIFICATION_INTERFACE,
309                                                 "Update");
310         if (msg == NULL)
311                 return FALSE;
312
313         dbus_message_iter_init_append(msg, &array);
314         connman_dbus_dict_open(&array, &dict);
315
316         connman_dbus_dict_append_basic(&dict, key, type, val);
317
318         connman_dbus_dict_close(&array, &dict);
319
320         g_dbus_send_message(connection, msg);
321
322         return TRUE;
323 }
324
325 dbus_bool_t connman_dbus_setting_changed_dict(const char *owner,
326                                 const char *path, const char *key,
327                                 connman_dbus_append_cb_t function,
328                                 void *user_data)
329 {
330         DBusMessage *msg;
331         DBusMessageIter array, dict;
332
333         if (owner == NULL || path == NULL)
334                 return FALSE;
335
336         msg = dbus_message_new_method_call(owner, path,
337                                                 CONNMAN_NOTIFICATION_INTERFACE,
338                                                 "Update");
339         if (msg == NULL)
340                 return FALSE;
341
342         dbus_message_iter_init_append(msg, &array);
343         connman_dbus_dict_open(&array, &dict);
344
345         connman_dbus_dict_append_dict(&dict, key, function, user_data);
346
347         connman_dbus_dict_close(&array, &dict);
348
349         g_dbus_send_message(connection, msg);
350
351         return TRUE;
352 }
353
354 dbus_bool_t connman_dbus_setting_changed_array(const char *owner,
355                                 const char *path, const char *key, int type,
356                                 connman_dbus_append_cb_t function,
357                                 void *user_data)
358 {
359         DBusMessage *msg;
360         DBusMessageIter array, dict;
361
362         if (owner == NULL || path == NULL)
363                 return FALSE;
364
365         msg = dbus_message_new_method_call(owner, path,
366                                                 CONNMAN_NOTIFICATION_INTERFACE,
367                                                 "Update");
368         if (msg == NULL)
369                 return FALSE;
370
371         dbus_message_iter_init_append(msg, &array);
372         connman_dbus_dict_open(&array, &dict);
373
374         connman_dbus_dict_append_array(&dict, key, type, function, user_data);
375
376         connman_dbus_dict_close(&array, &dict);
377
378         g_dbus_send_message(connection, msg);
379
380         return TRUE;
381 }
382
383 dbus_bool_t __connman_dbus_append_objpath_dict_array(DBusMessage *msg,
384                 connman_dbus_append_cb_t function, void *user_data)
385 {
386         DBusMessageIter iter, array;
387
388         if (msg == NULL || function == NULL)
389                 return FALSE;
390
391         dbus_message_iter_init_append(msg, &iter);
392         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
393                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
394                         DBUS_TYPE_OBJECT_PATH_AS_STRING
395                         DBUS_TYPE_ARRAY_AS_STRING
396                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
397                                         DBUS_TYPE_STRING_AS_STRING
398                                         DBUS_TYPE_VARIANT_AS_STRING
399                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
400                         DBUS_STRUCT_END_CHAR_AS_STRING, &array);
401
402         function(&array, user_data);
403
404         dbus_message_iter_close_container(&iter, &array);
405
406         return TRUE;
407 }
408
409 struct selinux_data {
410         connman_dbus_get_context_cb_t func;
411         void *user_data;
412 };
413
414 static unsigned char *parse_context(DBusMessage *msg)
415 {
416         DBusMessageIter iter, array;
417         unsigned char *ctx, *p;
418         int size = 0;
419
420         dbus_message_iter_init(msg, &iter);
421         dbus_message_iter_recurse(&iter, &array);
422         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
423                 size++;
424
425                 dbus_message_iter_next(&array);
426         }
427
428         if (size == 0)
429                 return NULL;
430
431         ctx = g_try_malloc0(size + 1);
432         if (ctx == NULL)
433                 return NULL;
434
435         p = ctx;
436
437         dbus_message_iter_init(msg, &iter);
438         dbus_message_iter_recurse(&iter, &array);
439         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
440                 dbus_message_iter_get_basic(&array, p);
441
442                 p++;
443                 dbus_message_iter_next(&array);
444         }
445
446         return ctx;
447 }
448
449 static void selinux_get_context_reply(DBusPendingCall *call, void *user_data)
450 {
451         struct selinux_data *data = user_data;
452         DBusMessage *reply;
453         unsigned char *context = NULL;
454         int err = 0;
455
456         reply = dbus_pending_call_steal_reply(call);
457
458         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
459                 DBG("Failed to retrieve SELinux context");
460                 err = -EIO;
461                 goto done;
462         }
463
464         if (dbus_message_has_signature(reply, "ay") == FALSE) {
465                 DBG("Message signature is wrong");
466                 err = -EINVAL;
467                 goto done;
468         }
469
470         context = parse_context(reply);
471
472 done:
473         (*data->func)(context, data->user_data, err);
474
475         g_free(context);
476
477         dbus_message_unref(reply);
478
479         dbus_pending_call_unref(call);
480 }
481
482 int connman_dbus_get_selinux_context(DBusConnection *connection,
483                                 const char *service,
484                                 connman_dbus_get_context_cb_t func,
485                                 void *user_data)
486 {
487         struct selinux_data *data;
488         DBusPendingCall *call;
489         DBusMessage *msg = NULL;
490         int err;
491
492         if (func == NULL)
493                 return -EINVAL;
494
495         data = g_try_new0(struct selinux_data, 1);
496         if (data == NULL) {
497                 DBG("Can't allocate data structure");
498                 return -ENOMEM;
499         }
500
501         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
502                                         DBUS_INTERFACE_DBUS,
503                                         "GetConnectionSELinuxSecurityContext");
504         if (msg == NULL) {
505                 DBG("Can't allocate new message");
506                 err = -ENOMEM;
507                 goto err;
508         }
509
510         dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
511                                         DBUS_TYPE_INVALID);
512
513         if (dbus_connection_send_with_reply(connection, msg,
514                                                 &call, -1) == FALSE) {
515                 DBG("Failed to execute method call");
516                 err = -EINVAL;
517                 goto err;
518         }
519
520         if (call == NULL) {
521                 DBG("D-Bus connection not available");
522                 err = -EINVAL;
523                 goto err;
524         }
525
526         data->func = func;
527         data->user_data = user_data;
528
529         dbus_pending_call_set_notify(call, selinux_get_context_reply,
530                                                         data, g_free);
531
532         dbus_message_unref(msg);
533
534         return 0;
535
536 err:
537         dbus_message_unref(msg);
538         g_free(data);
539
540         return err;
541 }
542
543 DBusConnection *connman_dbus_get_connection(void)
544 {
545         if (connection == NULL)
546                 return NULL;
547
548         return dbus_connection_ref(connection);
549 }
550
551 int __connman_dbus_init(DBusConnection *conn)
552 {
553         DBG("");
554
555         connection = conn;
556
557         return 0;
558 }
559
560 void __connman_dbus_cleanup(void)
561 {
562         DBG("");
563
564         connection = NULL;
565 }