5cc61061b4c0b2fb35f0ecfc7840ca6c1c9ae3f4
[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 callback_data {
410         void *cb;
411         void *user_data;
412 };
413
414 static void get_connection_unix_user_reply(DBusPendingCall *call,
415                                                 void *user_data)
416 {
417         struct callback_data *data = user_data;
418         connman_dbus_get_connection_unix_user_cb_t cb = data->cb;
419         DBusMessageIter iter;
420         DBusMessage *reply;
421         int err = 0;
422         unsigned int uid;
423
424         reply = dbus_pending_call_steal_reply(call);
425
426         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
427                 DBG("Failed to retrieve UID");
428                 err = -EIO;
429                 goto done;
430         }
431
432         if (dbus_message_has_signature(reply, "u") == FALSE) {
433                 DBG("Message signature is wrong");
434                 err = -EINVAL;
435                 goto done;
436         }
437
438         dbus_message_iter_init(reply, &iter);
439         dbus_message_iter_get_basic(&iter, &uid);
440
441 done:
442         (*cb)(uid, data->user_data, err);
443
444         dbus_message_unref(reply);
445
446         dbus_pending_call_unref(call);
447 }
448
449 int connman_dbus_get_connection_unix_user(DBusConnection *connection,
450                                 const char *bus_name,
451                                 connman_dbus_get_connection_unix_user_cb_t func,
452                                 void *user_data)
453 {
454         struct callback_data *data;
455         DBusPendingCall *call;
456         DBusMessage *msg = NULL;
457         int err;
458
459         data = g_try_new0(struct callback_data, 1);
460         if (data == NULL) {
461                 DBG("Can't allocate data structure");
462                 return -ENOMEM;
463         }
464
465         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
466                                         DBUS_INTERFACE_DBUS,
467                                         "GetConnectionUnixUser");
468         if (msg == NULL) {
469                 DBG("Can't allocate new message");
470                 err = -ENOMEM;
471                 goto err;
472         }
473
474         dbus_message_append_args(msg, DBUS_TYPE_STRING, &bus_name,
475                                         DBUS_TYPE_INVALID);
476
477         if (dbus_connection_send_with_reply(connection, msg,
478                                                 &call, -1) == FALSE) {
479                 DBG("Failed to execute method call");
480                 err = -EINVAL;
481                 goto err;
482         }
483
484         if (call == NULL) {
485                 DBG("D-Bus connection not available");
486                 err = -EINVAL;
487                 goto err;
488         }
489
490         data->cb = func;
491         data->user_data = user_data;
492
493         dbus_pending_call_set_notify(call, get_connection_unix_user_reply,
494                                                         data, g_free);
495
496         dbus_message_unref(msg);
497
498         return 0;
499
500 err:
501         dbus_message_unref(msg);
502         g_free(data);
503
504         return err;
505 }
506
507 static unsigned char *parse_context(DBusMessage *msg)
508 {
509         DBusMessageIter iter, array;
510         unsigned char *ctx, *p;
511         int size = 0;
512
513         dbus_message_iter_init(msg, &iter);
514         dbus_message_iter_recurse(&iter, &array);
515         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
516                 size++;
517
518                 dbus_message_iter_next(&array);
519         }
520
521         if (size == 0)
522                 return NULL;
523
524         ctx = g_try_malloc0(size + 1);
525         if (ctx == NULL)
526                 return NULL;
527
528         p = ctx;
529
530         dbus_message_iter_init(msg, &iter);
531         dbus_message_iter_recurse(&iter, &array);
532         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
533                 dbus_message_iter_get_basic(&array, p);
534
535                 p++;
536                 dbus_message_iter_next(&array);
537         }
538
539         return ctx;
540 }
541
542 static void selinux_get_context_reply(DBusPendingCall *call, void *user_data)
543 {
544         struct callback_data *data = user_data;
545         connman_dbus_get_context_cb_t cb = data->cb;
546         DBusMessage *reply;
547         unsigned char *context = NULL;
548         int err = 0;
549
550         reply = dbus_pending_call_steal_reply(call);
551
552         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
553                 DBG("Failed to retrieve SELinux context");
554                 err = -EIO;
555                 goto done;
556         }
557
558         if (dbus_message_has_signature(reply, "ay") == FALSE) {
559                 DBG("Message signature is wrong");
560                 err = -EINVAL;
561                 goto done;
562         }
563
564         context = parse_context(reply);
565
566 done:
567         (*cb)(context, data->user_data, err);
568
569         g_free(context);
570
571         dbus_message_unref(reply);
572
573         dbus_pending_call_unref(call);
574 }
575
576 int connman_dbus_get_selinux_context(DBusConnection *connection,
577                                 const char *service,
578                                 connman_dbus_get_context_cb_t func,
579                                 void *user_data)
580 {
581         struct callback_data *data;
582         DBusPendingCall *call;
583         DBusMessage *msg = NULL;
584         int err;
585
586         if (func == NULL)
587                 return -EINVAL;
588
589         data = g_try_new0(struct callback_data, 1);
590         if (data == NULL) {
591                 DBG("Can't allocate data structure");
592                 return -ENOMEM;
593         }
594
595         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
596                                         DBUS_INTERFACE_DBUS,
597                                         "GetConnectionSELinuxSecurityContext");
598         if (msg == NULL) {
599                 DBG("Can't allocate new message");
600                 err = -ENOMEM;
601                 goto err;
602         }
603
604         dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
605                                         DBUS_TYPE_INVALID);
606
607         if (dbus_connection_send_with_reply(connection, msg,
608                                                 &call, -1) == FALSE) {
609                 DBG("Failed to execute method call");
610                 err = -EINVAL;
611                 goto err;
612         }
613
614         if (call == NULL) {
615                 DBG("D-Bus connection not available");
616                 err = -EINVAL;
617                 goto err;
618         }
619
620         data->cb = func;
621         data->user_data = user_data;
622
623         dbus_pending_call_set_notify(call, selinux_get_context_reply,
624                                                         data, g_free);
625
626         dbus_message_unref(msg);
627
628         return 0;
629
630 err:
631         dbus_message_unref(msg);
632         g_free(data);
633
634         return err;
635 }
636
637 DBusConnection *connman_dbus_get_connection(void)
638 {
639         if (connection == NULL)
640                 return NULL;
641
642         return dbus_connection_ref(connection);
643 }
644
645 int __connman_dbus_init(DBusConnection *conn)
646 {
647         DBG("");
648
649         connection = conn;
650
651         return 0;
652 }
653
654 void __connman_dbus_cleanup(void)
655 {
656         DBG("");
657
658         connection = NULL;
659 }