Added support of WPA3-SAE security mode.
[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)
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)
58                 return NULL;
59
60         size = strlen(value);
61
62         str = g_string_new(NULL);
63         if (!str)
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
187                                 DBUS_TYPE_STRING_AS_STRING;
188                 array_sig = DBUS_TYPE_STRING_AS_STRING;
189                 break;
190         case DBUS_TYPE_OBJECT_PATH:
191                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING
192                                 DBUS_TYPE_OBJECT_PATH_AS_STRING;
193                 array_sig = DBUS_TYPE_OBJECT_PATH_AS_STRING;
194                 break;
195         case DBUS_TYPE_DICT_ENTRY:
196                 variant_sig = DBUS_TYPE_ARRAY_AS_STRING
197                                 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
198                                 DBUS_TYPE_ARRAY_AS_STRING
199                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
200                                                 DBUS_TYPE_STRING_AS_STRING
201                                                 DBUS_TYPE_VARIANT_AS_STRING
202                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
203                                 DBUS_STRUCT_END_CHAR_AS_STRING;
204                 array_sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
205                                 DBUS_TYPE_ARRAY_AS_STRING
206                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
207                                                 DBUS_TYPE_STRING_AS_STRING
208                                                 DBUS_TYPE_VARIANT_AS_STRING
209                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
210                                 DBUS_STRUCT_END_CHAR_AS_STRING;
211                 break;
212         default:
213                 return;
214         }
215
216         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
217
218         dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
219                                                         variant_sig, &value);
220
221         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
222                                                         array_sig, &array);
223         if (function)
224                 function(&array, user_data);
225         dbus_message_iter_close_container(&value, &array);
226
227         dbus_message_iter_close_container(iter, &value);
228 }
229
230 static DBusConnection *connection = NULL;
231
232 dbus_bool_t connman_dbus_property_changed_basic(const char *path,
233                                 const char *interface, const char *key,
234                                                         int type, void *val)
235 {
236         DBusMessage *signal;
237         DBusMessageIter iter;
238
239         if (!path)
240                 return FALSE;
241
242         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
243         if (!signal)
244                 return FALSE;
245
246         dbus_message_iter_init_append(signal, &iter);
247         connman_dbus_property_append_basic(&iter, key, type, val);
248
249         g_dbus_send_message(connection, signal);
250
251         return TRUE;
252 }
253
254 dbus_bool_t connman_dbus_property_changed_dict(const char *path,
255                                 const char *interface, const char *key,
256                         connman_dbus_append_cb_t function, void *user_data)
257 {
258         DBusMessage *signal;
259         DBusMessageIter iter;
260
261         if (!path)
262                 return FALSE;
263
264         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
265         if (!signal)
266                 return FALSE;
267
268         dbus_message_iter_init_append(signal, &iter);
269         connman_dbus_property_append_dict(&iter, key, function, user_data);
270
271         g_dbus_send_message(connection, signal);
272
273         return TRUE;
274 }
275
276 dbus_bool_t connman_dbus_property_changed_array(const char *path,
277                         const char *interface, const char *key, int type,
278                         connman_dbus_append_cb_t function, void *user_data)
279 {
280         DBusMessage *signal;
281         DBusMessageIter iter;
282
283         if (!path)
284                 return FALSE;
285
286         signal = dbus_message_new_signal(path, interface, "PropertyChanged");
287         if (!signal)
288                 return FALSE;
289
290         dbus_message_iter_init_append(signal, &iter);
291         connman_dbus_property_append_array(&iter, key, type,
292                                                 function, user_data);
293
294         g_dbus_send_message(connection, signal);
295
296         return TRUE;
297 }
298
299 dbus_bool_t connman_dbus_setting_changed_basic(const char *owner,
300                                 const char *path, const char *key,
301                                 int type, void *val)
302 {
303         DBusMessage *msg;
304         DBusMessageIter array, dict;
305
306         if (!owner || !path)
307                 return FALSE;
308
309         msg = dbus_message_new_method_call(owner, path,
310                                                 CONNMAN_NOTIFICATION_INTERFACE,
311                                                 "Update");
312         if (!msg)
313                 return FALSE;
314
315         dbus_message_iter_init_append(msg, &array);
316         connman_dbus_dict_open(&array, &dict);
317
318         connman_dbus_dict_append_basic(&dict, key, type, val);
319
320         connman_dbus_dict_close(&array, &dict);
321
322         g_dbus_send_message(connection, msg);
323
324         return TRUE;
325 }
326
327 dbus_bool_t connman_dbus_setting_changed_dict(const char *owner,
328                                 const char *path, const char *key,
329                                 connman_dbus_append_cb_t function,
330                                 void *user_data)
331 {
332         DBusMessage *msg;
333         DBusMessageIter array, dict;
334
335         if (!owner || !path)
336                 return FALSE;
337
338         msg = dbus_message_new_method_call(owner, path,
339                                                 CONNMAN_NOTIFICATION_INTERFACE,
340                                                 "Update");
341         if (!msg)
342                 return FALSE;
343
344         dbus_message_iter_init_append(msg, &array);
345         connman_dbus_dict_open(&array, &dict);
346
347         connman_dbus_dict_append_dict(&dict, key, function, user_data);
348
349         connman_dbus_dict_close(&array, &dict);
350
351         g_dbus_send_message(connection, msg);
352
353         return TRUE;
354 }
355
356 dbus_bool_t connman_dbus_setting_changed_array(const char *owner,
357                                 const char *path, const char *key, int type,
358                                 connman_dbus_append_cb_t function,
359                                 void *user_data)
360 {
361         DBusMessage *msg;
362         DBusMessageIter array, dict;
363
364         if (!owner || !path)
365                 return FALSE;
366
367         msg = dbus_message_new_method_call(owner, path,
368                                                 CONNMAN_NOTIFICATION_INTERFACE,
369                                                 "Update");
370         if (!msg)
371                 return FALSE;
372
373         dbus_message_iter_init_append(msg, &array);
374         connman_dbus_dict_open(&array, &dict);
375
376         connman_dbus_dict_append_array(&dict, key, type, function, user_data);
377
378         connman_dbus_dict_close(&array, &dict);
379
380         g_dbus_send_message(connection, msg);
381
382         return TRUE;
383 }
384
385 dbus_bool_t __connman_dbus_append_objpath_dict_array(DBusMessage *msg,
386                 connman_dbus_append_cb_t function, void *user_data)
387 {
388         DBusMessageIter iter, array;
389
390         if (!msg || !function)
391                 return FALSE;
392
393         dbus_message_iter_init_append(msg, &iter);
394         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
395                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
396                         DBUS_TYPE_OBJECT_PATH_AS_STRING
397                         DBUS_TYPE_ARRAY_AS_STRING
398                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
399                                         DBUS_TYPE_STRING_AS_STRING
400                                         DBUS_TYPE_VARIANT_AS_STRING
401                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
402                         DBUS_STRUCT_END_CHAR_AS_STRING, &array);
403
404         function(&array, user_data);
405
406         dbus_message_iter_close_container(&iter, &array);
407
408         return TRUE;
409 }
410
411 dbus_bool_t __connman_dbus_append_objpath_array(DBusMessage *msg,
412                         connman_dbus_append_cb_t function, void *user_data)
413 {
414         DBusMessageIter iter, array;
415
416         if (!msg || !function)
417                 return FALSE;
418
419         dbus_message_iter_init_append(msg, &iter);
420         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
421                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
422
423         function(&array, user_data);
424
425         dbus_message_iter_close_container(&iter, &array);
426
427         return TRUE;
428 }
429
430 struct callback_data {
431         void *cb;
432         void *user_data;
433 };
434
435 static void get_connection_unix_user_reply(DBusPendingCall *call,
436                                                 void *user_data)
437 {
438         struct callback_data *data = user_data;
439         connman_dbus_get_connection_unix_user_cb_t cb = data->cb;
440         DBusMessageIter iter;
441         DBusMessage *reply;
442         int err = 0;
443         unsigned int uid = 0;
444
445         reply = dbus_pending_call_steal_reply(call);
446
447         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
448                 DBG("Failed to retrieve UID");
449                 err = -EIO;
450                 goto done;
451         }
452
453         if (!dbus_message_has_signature(reply, "u")) {
454                 DBG("Message signature is wrong");
455                 err = -EINVAL;
456                 goto done;
457         }
458
459         dbus_message_iter_init(reply, &iter);
460         dbus_message_iter_get_basic(&iter, &uid);
461
462 done:
463         (*cb)(uid, data->user_data, err);
464
465         dbus_message_unref(reply);
466
467         dbus_pending_call_unref(call);
468 }
469
470 int connman_dbus_get_connection_unix_user(DBusConnection *connection,
471                                 const char *bus_name,
472                                 connman_dbus_get_connection_unix_user_cb_t func,
473                                 void *user_data)
474 {
475         struct callback_data *data;
476         DBusPendingCall *call;
477         DBusMessage *msg = NULL;
478         int err;
479
480         data = g_try_new0(struct callback_data, 1);
481         if (!data) {
482                 DBG("Can't allocate data structure");
483                 return -ENOMEM;
484         }
485
486         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
487                                         DBUS_INTERFACE_DBUS,
488                                         "GetConnectionUnixUser");
489         if (!msg) {
490                 DBG("Can't allocate new message");
491                 err = -ENOMEM;
492                 goto err;
493         }
494
495         dbus_message_append_args(msg, DBUS_TYPE_STRING, &bus_name,
496                                         DBUS_TYPE_INVALID);
497
498         if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
499                 DBG("Failed to execute method call");
500                 err = -EINVAL;
501                 goto err;
502         }
503
504         if (!call) {
505                 DBG("D-Bus connection not available");
506                 err = -EINVAL;
507                 goto err;
508         }
509
510         data->cb = func;
511         data->user_data = user_data;
512
513         dbus_pending_call_set_notify(call, get_connection_unix_user_reply,
514                                                         data, g_free);
515
516         dbus_message_unref(msg);
517
518         return 0;
519
520 err:
521         dbus_message_unref(msg);
522         g_free(data);
523
524         return err;
525 }
526
527 int connman_dbus_get_connection_unix_user_sync(DBusConnection *connection,
528                                                 const char *bus_name,
529                                                 unsigned int *user_id)
530 {
531 #if defined TIZEN_EXT
532         *user_id = 0;
533 #else
534         unsigned long uid;
535         DBusError err;
536
537         dbus_error_init(&err);
538
539         uid = dbus_bus_get_unix_user(connection, bus_name, &err);
540
541         if (uid == (unsigned long)-1) {
542                 DBG("Can not get unix user ID!");
543                 if (dbus_error_is_set(&err)) {
544                         DBG("%s", err.message);
545                         dbus_error_free(&err);
546                 }
547                 return -1;
548         }
549
550         *user_id = (unsigned int)uid;
551 #endif
552
553         return 0;
554 }
555
556 static unsigned char *parse_context(DBusMessage *msg)
557 {
558         DBusMessageIter iter, array;
559         unsigned char *ctx, *p;
560         int size = 0;
561
562         dbus_message_iter_init(msg, &iter);
563         dbus_message_iter_recurse(&iter, &array);
564         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
565                 size++;
566
567                 dbus_message_iter_next(&array);
568         }
569
570         if (size == 0)
571                 return NULL;
572
573         ctx = g_try_malloc0(size + 1);
574         if (!ctx)
575                 return NULL;
576
577         p = ctx;
578
579         dbus_message_iter_init(msg, &iter);
580         dbus_message_iter_recurse(&iter, &array);
581         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
582                 dbus_message_iter_get_basic(&array, p);
583
584                 p++;
585                 dbus_message_iter_next(&array);
586         }
587
588         return ctx;
589 }
590
591 static void selinux_get_context_reply(DBusPendingCall *call, void *user_data)
592 {
593         struct callback_data *data = user_data;
594         connman_dbus_get_context_cb_t cb = data->cb;
595         DBusMessage *reply;
596         unsigned char *context = NULL;
597         int err = 0;
598
599         reply = dbus_pending_call_steal_reply(call);
600
601         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
602                 DBG("Failed to retrieve SELinux context");
603                 err = -EIO;
604                 goto done;
605         }
606
607         if (!dbus_message_has_signature(reply, "ay")) {
608                 DBG("Message signature is wrong");
609                 err = -EINVAL;
610                 goto done;
611         }
612
613         context = parse_context(reply);
614
615 done:
616         (*cb)(context, data->user_data, err);
617
618         g_free(context);
619
620         dbus_message_unref(reply);
621
622         dbus_pending_call_unref(call);
623 }
624
625 int connman_dbus_get_selinux_context(DBusConnection *connection,
626                                 const char *service,
627                                 connman_dbus_get_context_cb_t func,
628                                 void *user_data)
629 {
630         struct callback_data *data;
631         DBusPendingCall *call;
632         DBusMessage *msg = NULL;
633         int err;
634
635         if (!func)
636                 return -EINVAL;
637
638         data = g_try_new0(struct callback_data, 1);
639         if (!data) {
640                 DBG("Can't allocate data structure");
641                 return -ENOMEM;
642         }
643
644         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
645                                         DBUS_INTERFACE_DBUS,
646                                         "GetConnectionSELinuxSecurityContext");
647         if (!msg) {
648                 DBG("Can't allocate new message");
649                 err = -ENOMEM;
650                 goto err;
651         }
652
653         dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
654                                         DBUS_TYPE_INVALID);
655
656         if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
657                 DBG("Failed to execute method call");
658                 err = -EINVAL;
659                 goto err;
660         }
661
662         if (!call) {
663                 DBG("D-Bus connection not available");
664                 err = -EINVAL;
665                 goto err;
666         }
667
668         data->cb = func;
669         data->user_data = user_data;
670
671         dbus_pending_call_set_notify(call, selinux_get_context_reply,
672                                                         data, g_free);
673
674         dbus_message_unref(msg);
675
676         return 0;
677
678 err:
679         dbus_message_unref(msg);
680         g_free(data);
681
682         return err;
683 }
684
685 void connman_dbus_reply_pending(DBusMessage *pending,
686                                         int error, const char *path)
687 {
688         if (pending) {
689                 if (error > 0) {
690                         DBusMessage *reply;
691
692                         reply = __connman_error_failed(pending, error);
693                         if (reply)
694                                 g_dbus_send_message(connection, reply);
695                 } else {
696                         const char *sender;
697
698                         sender = dbus_message_get_interface(pending);
699                         if (!path)
700                                 path = dbus_message_get_path(pending);
701
702                         DBG("sender %s path %s", sender, path);
703
704                         if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
705                                 g_dbus_send_reply(connection, pending,
706                                         DBUS_TYPE_OBJECT_PATH, &path,
707                                                         DBUS_TYPE_INVALID);
708                         else
709                                 g_dbus_send_reply(connection, pending,
710                                                         DBUS_TYPE_INVALID);
711                 }
712
713                 dbus_message_unref(pending);
714         }
715 }
716
717 DBusConnection *connman_dbus_get_connection(void)
718 {
719         if (!connection)
720                 return NULL;
721
722         return dbus_connection_ref(connection);
723 }
724
725 int __connman_dbus_init(DBusConnection *conn)
726 {
727         DBG("");
728
729         connection = conn;
730
731         return 0;
732 }
733
734 void __connman_dbus_cleanup(void)
735 {
736         DBG("");
737
738         connection = NULL;
739 }