Merge "dbus: modify dbus policy configuration" into tizen
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 <errno.h>
27
28 #include <gdbus.h>
29
30 #include <connman/agent.h>
31
32 #include "connman.h"
33
34 static bool connman_state_idle;
35 static dbus_bool_t sessionmode;
36
37 #if defined TIZEN_EXT
38 static void append_wifi_vsies_structs(DBusMessageIter *iter, void *user_data)
39 {
40         __connman_wifi_vsie_list_struct(iter);
41 }
42
43 static DBusMessage *get_wifi_vsies(DBusConnection *conn,
44                                         DBusMessage *msg, void *data)
45 {
46         DBusMessage *reply;
47
48         DBG("ConnMan, get_wifi_vsies API called");
49
50         reply = dbus_message_new_method_return(msg);
51         if (!reply)
52                 return NULL;
53
54         __connman_dbus_append_objpath_dict_array(reply,
55                         append_wifi_vsies_structs, NULL);
56
57         return reply;
58 }
59 #endif
60
61 static DBusMessage *get_properties(DBusConnection *conn,
62                                         DBusMessage *msg, void *data)
63 {
64         DBusMessage *reply;
65         DBusMessageIter array, dict;
66         dbus_bool_t offlinemode;
67         const char *str;
68
69         DBG("conn %p", conn);
70
71         reply = dbus_message_new_method_return(msg);
72         if (!reply)
73                 return NULL;
74
75         dbus_message_iter_init_append(reply, &array);
76
77         connman_dbus_dict_open(&array, &dict);
78
79         str = __connman_notifier_get_state();
80         connman_dbus_dict_append_basic(&dict, "State",
81                                                 DBUS_TYPE_STRING, &str);
82
83         offlinemode = __connman_technology_get_offlinemode();
84         connman_dbus_dict_append_basic(&dict, "OfflineMode",
85                                         DBUS_TYPE_BOOLEAN, &offlinemode);
86
87         connman_dbus_dict_append_basic(&dict, "SessionMode",
88                                         DBUS_TYPE_BOOLEAN,
89                                         &sessionmode);
90
91         connman_dbus_dict_close(&array, &dict);
92
93         return reply;
94 }
95
96 static DBusMessage *set_property(DBusConnection *conn,
97                                         DBusMessage *msg, void *data)
98 {
99         DBusMessageIter iter, value;
100         const char *name;
101         int type;
102
103         DBG("conn %p", conn);
104
105         if (!dbus_message_iter_init(msg, &iter))
106                 return __connman_error_invalid_arguments(msg);
107
108         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
109                 return __connman_error_invalid_arguments(msg);
110
111         dbus_message_iter_get_basic(&iter, &name);
112         dbus_message_iter_next(&iter);
113
114         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
115                 return __connman_error_invalid_arguments(msg);
116
117         dbus_message_iter_recurse(&iter, &value);
118
119         type = dbus_message_iter_get_arg_type(&value);
120
121         if (g_str_equal(name, "OfflineMode")) {
122                 dbus_bool_t offlinemode;
123
124                 if (type != DBUS_TYPE_BOOLEAN)
125                         return __connman_error_invalid_arguments(msg);
126
127                 dbus_message_iter_get_basic(&value, &offlinemode);
128
129                 if (offlinemode) {
130                         uid_t uid;
131                         if (connman_dbus_get_connection_unix_user_sync(conn,
132                                                 dbus_message_get_sender(msg),
133                                                 &uid) < 0) {
134                                 DBG("Can not get unix user id!");
135                                 return __connman_error_permission_denied(msg);
136                         }
137
138                         if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
139                                 DBG("Not allow this user to turn on offlinemode now!");
140                                 return __connman_error_permission_denied(msg);
141                         }
142                 }
143                 __connman_technology_set_offlinemode(offlinemode);
144         } else if (g_str_equal(name, "SessionMode")) {
145
146                 if (type != DBUS_TYPE_BOOLEAN)
147                         return __connman_error_invalid_arguments(msg);
148
149                 dbus_message_iter_get_basic(&value, &sessionmode);
150
151         } else
152                 return __connman_error_invalid_property(msg);
153
154         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
155 }
156
157 static void append_technology_structs(DBusMessageIter *iter, void *user_data)
158 {
159         __connman_technology_list_struct(iter);
160 }
161
162 static DBusMessage *get_technologies(DBusConnection *conn,
163                 DBusMessage *msg, void *data)
164 {
165         DBusMessage *reply;
166
167 #if !defined TIZEN_EXT
168         DBG("");
169 #endif
170
171         reply = dbus_message_new_method_return(msg);
172         if (!reply)
173                 return NULL;
174
175         __connman_dbus_append_objpath_dict_array(reply,
176                         append_technology_structs, NULL);
177
178         return reply;
179 }
180
181 static DBusMessage *remove_provider(DBusConnection *conn,
182                                     DBusMessage *msg, void *data)
183 {
184         const char *path;
185         int err;
186
187         DBG("conn %p", conn);
188
189         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
190                                                         DBUS_TYPE_INVALID);
191
192         err = __connman_provider_remove_by_path(path);
193         if (err < 0)
194                 return __connman_error_failed(msg, -err);
195
196         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
197 }
198
199 static DBusConnection *connection = NULL;
200
201 static void idle_state(bool idle)
202 {
203
204         DBG("idle %d", idle);
205
206         connman_state_idle = idle;
207
208         if (!connman_state_idle)
209                 return;
210 }
211
212 static struct connman_notifier technology_notifier = {
213         .name           = "manager",
214         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
215         .idle_state     = idle_state,
216 };
217
218 static void append_service_structs(DBusMessageIter *iter, void *user_data)
219 {
220         __connman_service_list_struct(iter);
221 }
222
223 static DBusMessage *get_services(DBusConnection *conn,
224                                         DBusMessage *msg, void *data)
225 {
226         DBusMessage *reply;
227
228         reply = dbus_message_new_method_return(msg);
229         if (!reply)
230                 return NULL;
231
232         __connman_dbus_append_objpath_dict_array(reply,
233                         append_service_structs, NULL);
234
235         return reply;
236 }
237
238 static void append_peer_structs(DBusMessageIter *iter, void *user_data)
239 {
240         __connman_peer_list_struct(iter);
241 }
242
243 static DBusMessage *get_peers(DBusConnection *conn,
244                                         DBusMessage *msg, void *data)
245 {
246         DBusMessage *reply;
247
248         reply = dbus_message_new_method_return(msg);
249         if (!reply)
250                 return NULL;
251
252         __connman_dbus_append_objpath_dict_array(reply,
253                                         append_peer_structs, NULL);
254         return reply;
255 }
256
257 static DBusMessage *connect_provider(DBusConnection *conn,
258                                         DBusMessage *msg, void *data)
259 {
260         int err;
261
262         DBG("conn %p", conn);
263
264         err = __connman_provider_create_and_connect(msg);
265         if (err < 0)
266                 return __connman_error_failed(msg, -err);
267
268         return NULL;
269 }
270
271 static DBusMessage *register_agent(DBusConnection *conn,
272                                         DBusMessage *msg, void *data)
273 {
274         const char *sender, *path;
275         int err;
276
277         DBG("conn %p", conn);
278
279         sender = dbus_message_get_sender(msg);
280
281         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
282                                                         DBUS_TYPE_INVALID);
283
284         err = connman_agent_register(sender, path);
285         if (err < 0)
286                 return __connman_error_failed(msg, -err);
287
288         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
289 }
290
291 static DBusMessage *unregister_agent(DBusConnection *conn,
292                                         DBusMessage *msg, void *data)
293 {
294         const char *sender, *path;
295         int err;
296
297         DBG("conn %p", conn);
298
299         sender = dbus_message_get_sender(msg);
300
301         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
302                                                         DBUS_TYPE_INVALID);
303
304         err = connman_agent_unregister(sender, path);
305         if (err < 0)
306                 return __connman_error_failed(msg, -err);
307
308         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
309 }
310
311 static DBusMessage *register_counter(DBusConnection *conn,
312                                         DBusMessage *msg, void *data)
313 {
314         const char *sender, *path;
315         unsigned int accuracy, period;
316         int err;
317
318         DBG("conn %p", conn);
319
320         sender = dbus_message_get_sender(msg);
321
322         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
323                                                 DBUS_TYPE_UINT32, &accuracy,
324                                                 DBUS_TYPE_UINT32, &period,
325                                                         DBUS_TYPE_INVALID);
326
327         /* FIXME: add handling of accuracy parameter */
328
329         err = __connman_counter_register(sender, path, period);
330         if (err < 0)
331                 return __connman_error_failed(msg, -err);
332
333         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
334 }
335
336 static DBusMessage *unregister_counter(DBusConnection *conn,
337                                         DBusMessage *msg, void *data)
338 {
339         const char *sender, *path;
340         int err;
341
342         DBG("conn %p", conn);
343
344         sender = dbus_message_get_sender(msg);
345
346         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
347                                                         DBUS_TYPE_INVALID);
348
349         err = __connman_counter_unregister(sender, path);
350         if (err < 0)
351                 return __connman_error_failed(msg, -err);
352
353         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
354 }
355
356 static DBusMessage *create_session(DBusConnection *conn,
357                                         DBusMessage *msg, void *data)
358 {
359         int err;
360
361         DBG("conn %p", conn);
362
363         err = __connman_session_create(msg);
364         if (err < 0) {
365                 if (err == -EINPROGRESS)
366                         return NULL;
367
368                 return __connman_error_failed(msg, -err);
369         }
370
371         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
372 }
373
374 static DBusMessage *destroy_session(DBusConnection *conn,
375                                         DBusMessage *msg, void *data)
376 {
377         int err;
378
379         DBG("conn %p", conn);
380
381         err = __connman_session_destroy(msg);
382         if (err < 0)
383                 return __connman_error_failed(msg, -err);
384
385         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
386 }
387
388 static DBusMessage *request_private_network(DBusConnection *conn,
389                                         DBusMessage *msg, void *data)
390 {
391         const char *sender;
392         int  err;
393
394         DBG("conn %p", conn);
395
396         sender = dbus_message_get_sender(msg);
397
398         err = __connman_private_network_request(msg, sender);
399         if (err < 0)
400                 return __connman_error_failed(msg, -err);
401
402         return NULL;
403 }
404
405 static DBusMessage *release_private_network(DBusConnection *conn,
406                                         DBusMessage *msg, void *data)
407 {
408         const char *path;
409         int err;
410
411         DBG("conn %p", conn);
412
413         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
414                                                         DBUS_TYPE_INVALID);
415
416         err = __connman_private_network_release(path);
417         if (err < 0)
418                 return __connman_error_failed(msg, -err);
419
420         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
421 }
422
423 static int parse_peers_service_specs(DBusMessageIter *array,
424                         const unsigned char **spec, int *spec_len,
425                         const unsigned char **query, int *query_len,
426                         int *version)
427 {
428         *spec = *query = NULL;
429         *spec_len = *query_len = *version = 0;
430
431         while (dbus_message_iter_get_arg_type(array) ==
432                                                         DBUS_TYPE_DICT_ENTRY) {
433                 DBusMessageIter entry, inter, value;
434                 const char *key;
435
436                 dbus_message_iter_recurse(array, &entry);
437                 dbus_message_iter_get_basic(&entry, &key);
438
439                 dbus_message_iter_next(&entry);
440
441                 dbus_message_iter_recurse(&entry, &inter);
442
443                 if  (!g_strcmp0(key, "BonjourResponse")) {
444                         dbus_message_iter_recurse(&inter, &value);
445                         dbus_message_iter_get_fixed_array(&value,
446                                                         spec, spec_len);
447                 } else if (!g_strcmp0(key, "BonjourQuery")) {
448                         dbus_message_iter_recurse(&inter, &value);
449                         dbus_message_iter_get_fixed_array(&value,
450                                                         query, query_len);
451                 } else if (!g_strcmp0(key, "UpnpService")) {
452                         dbus_message_iter_get_basic(&inter, spec);
453                         *spec_len = strlen((const char *)*spec)+1;
454                 } else if (!g_strcmp0(key, "UpnpVersion")) {
455                         dbus_message_iter_get_basic(&inter, version);
456                 } else if (!g_strcmp0(key, "WiFiDisplayIEs")) {
457                         if (*spec || *query)
458                                 return -EINVAL;
459
460                         dbus_message_iter_recurse(&inter, &value);
461                         dbus_message_iter_get_fixed_array(&value,
462                                                         spec, spec_len);
463                 } else
464                         return -EINVAL;
465
466                 dbus_message_iter_next(array);
467         }
468
469         if ((*query && !*spec && !*version) ||
470                                 (!*spec && !*query) || (!*spec && *version))
471                 return -EINVAL;
472
473         return 0;
474 }
475
476 static DBusMessage *register_peer_service(DBusConnection *conn,
477                                                 DBusMessage *msg, void *data)
478 {
479         const unsigned char *spec, *query;
480         DBusMessageIter iter, array;
481         int spec_len, query_len;
482         dbus_bool_t master;
483         const char *owner;
484         int version;
485         int ret;
486
487         DBG("");
488
489         owner = dbus_message_get_sender(msg);
490
491         dbus_message_iter_init(msg, &iter);
492         dbus_message_iter_recurse(&iter, &array);
493
494         ret = parse_peers_service_specs(&array, &spec, &spec_len,
495                                                 &query, &query_len, &version);
496         if (ret)
497                 goto error;
498
499         dbus_message_iter_next(&iter);
500         dbus_message_iter_get_basic(&iter, &master);
501
502         ret = __connman_peer_service_register(owner, msg, spec, spec_len,
503                                         query, query_len, version,master);
504         if (!ret)
505                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
506         if (ret == -EINPROGRESS)
507                 return NULL;
508 error:
509         return __connman_error_failed(msg, -ret);
510 }
511
512 static DBusMessage *unregister_peer_service(DBusConnection *conn,
513                                                 DBusMessage *msg, void *data)
514 {
515         const unsigned char *spec, *query;
516         DBusMessageIter iter, array;
517         int spec_len, query_len;
518         const char *owner;
519         int version;
520         int ret;
521
522         DBG("");
523
524         owner = dbus_message_get_sender(msg);
525
526         dbus_message_iter_init(msg, &iter);
527         dbus_message_iter_recurse(&iter, &array);
528
529         ret = parse_peers_service_specs(&array, &spec, &spec_len,
530                                                 &query, &query_len, &version);
531         if (ret)
532                 goto error;
533
534         ret = __connman_peer_service_unregister(owner, spec, spec_len,
535                                                 query, query_len, version);
536         if (!ret)
537                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
538 error:
539         return __connman_error_failed(msg, -ret);
540
541 }
542
543 static const GDBusMethodTable manager_methods[] = {
544         { GDBUS_METHOD("GetProperties",
545                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
546                         get_properties) },
547         { GDBUS_ASYNC_METHOD("SetProperty",
548                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
549                         NULL, set_property) },
550         { GDBUS_METHOD("GetTechnologies",
551                         NULL, GDBUS_ARGS({ "technologies", "a(oa{sv})" }),
552                         get_technologies) },
553         { GDBUS_DEPRECATED_METHOD("RemoveProvider",
554                         GDBUS_ARGS({ "provider", "o" }), NULL,
555                         remove_provider) },
556         { GDBUS_METHOD("GetServices",
557                         NULL, GDBUS_ARGS({ "services", "a(oa{sv})" }),
558                         get_services) },
559         { GDBUS_METHOD("GetPeers",
560                         NULL, GDBUS_ARGS({ "peers", "a(oa{sv})" }),
561                         get_peers) },
562         { GDBUS_DEPRECATED_ASYNC_METHOD("ConnectProvider",
563                               GDBUS_ARGS({ "provider", "a{sv}" }),
564                               GDBUS_ARGS({ "path", "o" }),
565                               connect_provider) },
566         { GDBUS_METHOD("RegisterAgent",
567                         GDBUS_ARGS({ "path", "o" }), NULL,
568                         register_agent) },
569         { GDBUS_METHOD("UnregisterAgent",
570                         GDBUS_ARGS({ "path", "o" }), NULL,
571                         unregister_agent) },
572         { GDBUS_METHOD("RegisterCounter",
573                         GDBUS_ARGS({ "path", "o" }, { "accuracy", "u" },
574                                         { "period", "u" }),
575                         NULL, register_counter) },
576         { GDBUS_METHOD("UnregisterCounter",
577                         GDBUS_ARGS({ "path", "o" }), NULL,
578                         unregister_counter) },
579         { GDBUS_ASYNC_METHOD("CreateSession",
580                         GDBUS_ARGS({ "settings", "a{sv}" },
581                                                 { "notifier", "o" }),
582                         GDBUS_ARGS({ "session", "o" }),
583                         create_session) },
584         { GDBUS_METHOD("DestroySession",
585                         GDBUS_ARGS({ "session", "o" }), NULL,
586                         destroy_session) },
587         { GDBUS_ASYNC_METHOD("RequestPrivateNetwork",
588                               NULL, GDBUS_ARGS({ "path", "o" },
589                                                { "settings", "a{sv}" },
590                                                { "socket", "h" }),
591                               request_private_network) },
592         { GDBUS_METHOD("ReleasePrivateNetwork",
593                         GDBUS_ARGS({ "path", "o" }), NULL,
594                         release_private_network) },
595         { GDBUS_ASYNC_METHOD("RegisterPeerService",
596                         GDBUS_ARGS({ "specification", "a{sv}" },
597                                    { "master", "b" }), NULL,
598                         register_peer_service) },
599         { GDBUS_METHOD("UnregisterPeerService",
600                         GDBUS_ARGS({ "specification", "a{sv}" }), NULL,
601                         unregister_peer_service) },
602 #if defined TIZEN_EXT
603         { GDBUS_METHOD("GetVsies",
604                         NULL, GDBUS_ARGS({ "Vsie", "a(oa{sv})" }),
605                         get_wifi_vsies) },
606 #endif
607         { },
608 };
609
610 static const GDBusSignalTable manager_signals[] = {
611         { GDBUS_SIGNAL("PropertyChanged",
612                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
613         { GDBUS_SIGNAL("TechnologyAdded",
614                         GDBUS_ARGS({ "path", "o" },
615                                    { "properties", "a{sv}" })) },
616         { GDBUS_SIGNAL("TechnologyRemoved",
617                         GDBUS_ARGS({ "path", "o" })) },
618         { GDBUS_SIGNAL("ServicesChanged",
619                         GDBUS_ARGS({ "changed", "a(oa{sv})" },
620                                         { "removed", "ao" })) },
621         { GDBUS_SIGNAL("PeersChanged",
622                         GDBUS_ARGS({ "changed", "a(oa{sv})" },
623                                         { "removed", "ao" })) },
624         { },
625 };
626
627 int __connman_manager_init(void)
628 {
629         DBG("");
630
631         connection = connman_dbus_get_connection();
632         if (!connection)
633                 return -1;
634
635         if (connman_notifier_register(&technology_notifier) < 0)
636                 connman_error("Failed to register technology notifier");
637
638         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
639                                         CONNMAN_MANAGER_INTERFACE,
640                                         manager_methods,
641                                         manager_signals, NULL, NULL, NULL);
642
643         connman_state_idle = true;
644
645         return 0;
646 }
647
648 void __connman_manager_cleanup(void)
649 {
650         DBG("");
651
652         if (!connection)
653                 return;
654
655         connman_notifier_unregister(&technology_notifier);
656
657         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
658                                                 CONNMAN_MANAGER_INTERFACE);
659
660         dbus_connection_unref(connection);
661 }