Add support to get PMF information
[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 static unsigned char *parse_context(DBusMessage *msg)
528 {
529         DBusMessageIter iter, array;
530         unsigned char *ctx, *p;
531         int size = 0;
532
533         dbus_message_iter_init(msg, &iter);
534         dbus_message_iter_recurse(&iter, &array);
535         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
536                 size++;
537
538                 dbus_message_iter_next(&array);
539         }
540
541         if (size == 0)
542                 return NULL;
543
544         ctx = g_try_malloc0(size + 1);
545         if (!ctx)
546                 return NULL;
547
548         p = ctx;
549
550         dbus_message_iter_init(msg, &iter);
551         dbus_message_iter_recurse(&iter, &array);
552         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
553                 dbus_message_iter_get_basic(&array, p);
554
555                 p++;
556                 dbus_message_iter_next(&array);
557         }
558
559         return ctx;
560 }
561
562 static void selinux_get_context_reply(DBusPendingCall *call, void *user_data)
563 {
564         struct callback_data *data = user_data;
565         connman_dbus_get_context_cb_t cb = data->cb;
566         DBusMessage *reply;
567         unsigned char *context = NULL;
568         int err = 0;
569
570         reply = dbus_pending_call_steal_reply(call);
571
572         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
573                 DBG("Failed to retrieve SELinux context");
574                 err = -EIO;
575                 goto done;
576         }
577
578         if (!dbus_message_has_signature(reply, "ay")) {
579                 DBG("Message signature is wrong");
580                 err = -EINVAL;
581                 goto done;
582         }
583
584         context = parse_context(reply);
585
586 done:
587         (*cb)(context, data->user_data, err);
588
589         g_free(context);
590
591         dbus_message_unref(reply);
592
593         dbus_pending_call_unref(call);
594 }
595
596 int connman_dbus_get_selinux_context(DBusConnection *connection,
597                                 const char *service,
598                                 connman_dbus_get_context_cb_t func,
599                                 void *user_data)
600 {
601         struct callback_data *data;
602         DBusPendingCall *call;
603         DBusMessage *msg = NULL;
604         int err;
605
606         if (!func)
607                 return -EINVAL;
608
609         data = g_try_new0(struct callback_data, 1);
610         if (!data) {
611                 DBG("Can't allocate data structure");
612                 return -ENOMEM;
613         }
614
615         msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
616                                         DBUS_INTERFACE_DBUS,
617                                         "GetConnectionSELinuxSecurityContext");
618         if (!msg) {
619                 DBG("Can't allocate new message");
620                 err = -ENOMEM;
621                 goto err;
622         }
623
624         dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
625                                         DBUS_TYPE_INVALID);
626
627         if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
628                 DBG("Failed to execute method call");
629                 err = -EINVAL;
630                 goto err;
631         }
632
633         if (!call) {
634                 DBG("D-Bus connection not available");
635                 err = -EINVAL;
636                 goto err;
637         }
638
639         data->cb = func;
640         data->user_data = user_data;
641
642         dbus_pending_call_set_notify(call, selinux_get_context_reply,
643                                                         data, g_free);
644
645         dbus_message_unref(msg);
646
647         return 0;
648
649 err:
650         dbus_message_unref(msg);
651         g_free(data);
652
653         return err;
654 }
655
656 void connman_dbus_reply_pending(DBusMessage *pending,
657                                         int error, const char *path)
658 {
659         if (pending) {
660                 if (error > 0) {
661                         DBusMessage *reply;
662
663                         reply = __connman_error_failed(pending, error);
664                         if (reply)
665                                 g_dbus_send_message(connection, reply);
666                 } else {
667                         const char *sender;
668
669                         sender = dbus_message_get_interface(pending);
670                         if (!path)
671                                 path = dbus_message_get_path(pending);
672
673                         DBG("sender %s path %s", sender, path);
674
675                         if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
676                                 g_dbus_send_reply(connection, pending,
677                                         DBUS_TYPE_OBJECT_PATH, &path,
678                                                         DBUS_TYPE_INVALID);
679                         else
680                                 g_dbus_send_reply(connection, pending,
681                                                         DBUS_TYPE_INVALID);
682                 }
683
684                 dbus_message_unref(pending);
685         }
686 }
687
688 DBusConnection *connman_dbus_get_connection(void)
689 {
690         if (!connection)
691                 return NULL;
692
693         return dbus_connection_ref(connection);
694 }
695
696 int __connman_dbus_init(DBusConnection *conn)
697 {
698         DBG("");
699
700         connection = conn;
701
702         return 0;
703 }
704
705 void __connman_dbus_cleanup(void)
706 {
707         DBG("");
708
709         connection = NULL;
710 }