Merge "Add dbus method for getting wifi passphrase" into tizen
[platform/core/connectivity/net-config.git] / src / vpnsvc.c
1 /*
2  * Network Configuration - VPN Service Module
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <gio/gunixfdlist.h>
24
25 #include "vpnsvc.h"
26 #include "vpnsvc-internal.h"
27 #include "netdbus.h"
28 #include "log.h"
29
30 static Vpnsvc *vpnsvc = NULL;
31
32 /*********************
33  * Handler Functions *
34  ********************/
35 gboolean handle_vpn_init(Vpnsvc *object,
36                                                                 GDBusMethodInvocation *invocation,
37                                                                 const gchar *arg_iface_name,
38                                                                 guint arg_iface_name_len)
39 {
40         DBG("handle_vpn_init");
41
42         int result = VPNSVC_ERROR_NONE;
43
44         vpnsvc_tun_s handle_s;
45         GDBusMessage *msg;
46         GUnixFDList *fd_list;
47         int fd_list_length;
48         const int *fds;
49
50         DBG("vpn_init, %s, %u\n", arg_iface_name, arg_iface_name_len);
51
52         msg = g_dbus_method_invocation_get_message(invocation);
53         fd_list = g_dbus_message_get_unix_fd_list(msg);
54         fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
55
56         if (fd_list_length <= 0)
57                 DBG("D-Bus Message doesn't contain any fd!");
58
59         if (!fds) {
60                 DBG("fd:NULL\n");
61                 vpnsvc_complete_vpn_init(object, invocation, VPNSVC_ERROR_IO_ERROR, 0, "");
62                 return TRUE;
63         }
64
65         DBG("fd:%d\n", *fds);
66
67         result = vpn_service_init(arg_iface_name, arg_iface_name_len, *fds, &handle_s);
68
69         DBG("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s",
70                         handle_s.fd, handle_s.index, handle_s.name);
71
72         vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name);
73
74         return TRUE;
75 }
76
77 gboolean handle_vpn_deinit(Vpnsvc *object,
78                                                                         GDBusMethodInvocation *invocation,
79                                                                         const gchar *arg_dev_name)
80 {
81         DBG("handle_vpn_deinit");
82
83         int result = VPNSVC_ERROR_NONE;
84
85         DBG("vpn_deinit, %s\n", arg_dev_name);
86
87         result = vpn_service_deinit(arg_dev_name);
88
89         vpnsvc_complete_vpn_deinit(object, invocation, result);
90
91         return TRUE;
92 }
93
94 gboolean handle_vpn_protect(Vpnsvc *object,
95                                                                         GDBusMethodInvocation *invocation,
96                                                                         const gchar *arg_dev_name)
97 {
98         DBG("handle_vpn_protect");
99
100         int result = VPNSVC_ERROR_NONE;
101
102         int socket;
103         GDBusMessage *msg;
104         GUnixFDList *fd_list;
105         int fd_list_length;
106         const int *fds;
107
108         msg = g_dbus_method_invocation_get_message(invocation);
109         fd_list = g_dbus_message_get_unix_fd_list(msg);
110         fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
111         if (fd_list_length <= 0)
112                 DBG("D-Bus Message doesn't contain any fd!");
113
114         if (!fds) {
115                 DBG("fd:NULL\n");
116                 vpnsvc_complete_vpn_protect(object, invocation, VPNSVC_ERROR_IO_ERROR);
117                 return TRUE;
118         }
119
120         socket = *fds;
121         DBG("vpn_protect, %d, %s\n", socket, arg_dev_name);
122
123         result = vpn_service_protect(socket, arg_dev_name);
124
125         vpnsvc_complete_vpn_protect(object, invocation, result);
126
127         return TRUE;
128 }
129
130 gboolean handle_vpn_up(Vpnsvc *object,
131                                                                 GDBusMethodInvocation *invocation,
132                                                                 const gchar *arg_iface_name)
133 {
134         DBG("handle_vpn_up");
135
136         int result = VPNSVC_ERROR_NONE;
137
138         result = vpn_service_up(arg_iface_name);
139
140         vpnsvc_complete_vpn_up(object, invocation, result);
141
142         return TRUE;
143 }
144
145 gboolean handle_vpn_down(Vpnsvc *object,
146                                                                         GDBusMethodInvocation *invocation,
147                                                                         const gchar *arg_iface_name)
148 {
149         DBG("handle_vpn_down");
150
151         int result = VPNSVC_ERROR_NONE;
152
153         result = vpn_service_down(arg_iface_name);
154
155         vpnsvc_complete_vpn_down(object, invocation, result);
156
157         return TRUE;
158 }
159
160 #define MAX_NUM_ROUTE_RULE 255
161
162 gboolean handle_vpn_block_networks(Vpnsvc *object,
163                                                                                         GDBusMethodInvocation *invocation,
164                                                                                         GVariant *arg_nets_vpn,
165                                                                                         guint arg_nr_nets_vpn,
166                                                                                         GVariant *arg_nets_orig,
167                                                                                         guint arg_nr_nets_orig)
168 {
169         DBG("handle_vpn_block_networks");
170
171         int result = VPNSVC_ERROR_NONE;
172         if (arg_nr_nets_vpn > MAX_NUM_ROUTE_RULE) {
173                 ERR("Number of allowing networks over VPN interface is exceeded %d,"
174                                                 " Limit is %d", arg_nr_nets_vpn, MAX_NUM_ROUTE_RULE);
175                 result = VPNSVC_ERROR_INVALID_PARAMETER;
176                 goto method_complete;
177         }
178
179         if (arg_nr_nets_orig > MAX_NUM_ROUTE_RULE) {
180                 ERR("Number of allowing networks over original interface is exceeded"
181                                                 " %d, Limit is %d", arg_nr_nets_orig, MAX_NUM_ROUTE_RULE);
182                 result = VPNSVC_ERROR_INVALID_PARAMETER;
183                 goto method_complete;
184         }
185
186         do {
187                 char *nets_vpn[arg_nr_nets_vpn];
188                 int prefix_vpn[arg_nr_nets_vpn];
189
190                 char *nets_orig[arg_nr_nets_orig];
191                 int prefix_orig[arg_nr_nets_orig];
192
193                 int i = 0;
194                 GVariantIter iter;
195                 gchar* route_dest;
196                 gint route_prefix;
197
198                 DBG("vpn_block_networks");
199
200                 memset(nets_vpn, 0, sizeof(char *) * arg_nr_nets_vpn);
201                 memset(prefix_vpn, 0, sizeof(int) * arg_nr_nets_vpn);
202                 memset(nets_orig, 0, sizeof(char *) * arg_nr_nets_orig);
203                 memset(prefix_orig, 0, sizeof(int) * arg_nr_nets_orig);
204
205                 /* arg_nets_vpn check */
206                 if (arg_nr_nets_vpn > 0) {
207                         if (arg_nets_vpn != NULL) {
208                                 GVariant *dict_nets_vpn = g_variant_get_variant(arg_nets_vpn);
209                                 g_variant_iter_init(&iter, dict_nets_vpn);
210                                 i = 0;
211                                 while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
212                                         if (i >= arg_nr_nets_vpn) {
213                                                 WARN("No more space for allowing network over VPN interface."
214                                                                 " next index %d / space size %d", i, arg_nr_nets_vpn);
215                                                 g_free(route_dest);
216                                                 break;
217                                         }
218                                         int tmp_route_len = strlen(route_dest);
219                                         nets_vpn[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
220                                         if (nets_vpn[i]) {
221                                                 strncpy(nets_vpn[i], route_dest, tmp_route_len);
222                                                 nets_vpn[i][tmp_route_len] = '\0';
223                                                 prefix_vpn[i] = route_prefix;
224                                                 DBG("nets_vpn[%d] = %s \t", i, (nets_vpn[i] == NULL) ? "" : nets_vpn[i]);
225                                                 DBG("prefix_vpn[%d] = %d ", i, prefix_vpn[i]);
226                                         }
227                                         i++;
228                                 }
229                         }
230                 }
231
232                 /* arg_nets_orig check */
233                 if (arg_nr_nets_orig > 0) {
234                         if (arg_nets_orig != NULL) {
235                                 GVariant *dict_nets_orig = g_variant_get_variant(arg_nets_orig);
236                                 g_variant_iter_init(&iter, dict_nets_orig);
237                                 i = 0;
238                                 while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
239                                         if (i >= arg_nr_nets_orig) {
240                                                 WARN("No more space for allowing network over VPN interface."
241                                                                 " next index %d / space size %d", i, arg_nr_nets_orig);
242                                                 g_free(route_dest);
243                                                 break;
244                                         }
245                                         int tmp_route_len = strlen(route_dest);
246                                         nets_orig[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
247                                         if (nets_orig[i]) {
248                                                 strncpy(nets_orig[i], route_dest, tmp_route_len);
249                                                 nets_orig[i][tmp_route_len] = '\0';
250                                                 prefix_orig[i] = route_prefix;
251                                                 DBG("nets_orig[%d] = %s \t", i, (nets_orig[i] == NULL) ? "" : nets_orig[i]);
252                                                 DBG("prefix_orig[%d] = %d ", i, prefix_orig[i]);
253                                         }
254                                         i++;
255                                 }
256                         }
257                 }
258
259                 /* call function */
260                 result = vpn_service_block_networks(nets_vpn, prefix_vpn, arg_nr_nets_vpn, nets_orig, prefix_orig, arg_nr_nets_orig);
261
262                 for (i = 0; i < arg_nr_nets_vpn; ++i) {
263                         g_free(nets_vpn[i]);
264                 }
265
266                 for (i = 0; i < arg_nr_nets_orig; ++i) {
267                         g_free(nets_orig[i]);
268                 }
269         } while(0);
270
271 method_complete:
272         vpnsvc_complete_vpn_block_networks(object, invocation, result);
273
274         return TRUE;
275 }
276
277 gboolean handle_vpn_unblock_networks(Vpnsvc *object,
278                                                                                         GDBusMethodInvocation *invocation)
279 {
280         DBG("handle_vpn_unblock_networks");
281
282         int result = VPNSVC_ERROR_NONE;
283
284         DBG("vpn_unblock_networks");
285
286         result = vpn_service_unblock_networks();
287
288         vpnsvc_complete_vpn_unblock_networks(object, invocation, result);
289
290         return TRUE;
291 }
292
293 gboolean handle_vpn_update_settings(Vpnsvc *object,
294                                                                 GDBusMethodInvocation *invocation,
295                                                                 gint arg_iface_index,
296                                                                 const gchar *arg_local_ip,
297                                                                 const gchar *arg_remote_ip,
298                                                                 guint arg_mtu)
299 {
300         int result = VPNSVC_ERROR_NONE;
301         DBG("handle_vpn_update_settings");
302
303         result = vpn_service_update_settings(arg_iface_index, arg_local_ip, arg_remote_ip, arg_mtu);
304
305         vpnsvc_complete_vpn_update_settings(object, invocation, result);
306
307         return TRUE;
308 }
309
310 gboolean handle_vpn_add_route(Vpnsvc *object,
311                                                                 GDBusMethodInvocation *invocation,
312                                                                 gchar *arg_iface_name,
313                                                                 const gchar *arg_route,
314                                                                 gint arg_prefix)
315 {
316         DBG("handle_vpn_add_route");
317
318         int result = VPNSVC_ERROR_NONE;
319
320         result = vpn_service_add_route(arg_iface_name, arg_route, arg_prefix);
321
322         vpnsvc_complete_vpn_add_route(object, invocation, result);
323
324         return TRUE;
325 }
326
327 gboolean handle_vpn_remove_route(Vpnsvc *object,
328                                                                 GDBusMethodInvocation *invocation,
329                                                                 gchar *arg_iface_name,
330                                                                 const gchar *arg_route,
331                                                                 gint arg_prefix)
332
333 {
334         DBG("handle_vpn_remove_route");
335
336         int result = VPNSVC_ERROR_NONE;
337
338         result = vpn_service_remove_route(arg_iface_name, arg_route, arg_prefix);
339
340         vpnsvc_complete_vpn_remove_route(object, invocation, result);
341
342         return TRUE;
343 }
344
345 gboolean handle_vpn_add_dns_server(Vpnsvc *object,
346                                                                 GDBusMethodInvocation *invocation,
347                                                                 gchar *arg_iface_name,
348                                                                 const gchar *arg_dns_server)
349 {
350         DBG("handle_vpn_add_dns_server");
351
352         int result = VPNSVC_ERROR_NONE;
353
354         result = vpn_service_add_dns_server(arg_iface_name, arg_dns_server);
355
356         vpnsvc_complete_vpn_add_dns_server(object, invocation, result);
357
358         return TRUE;
359 }
360
361 /*****************************
362  * Initializations Functions *
363  ****************************/
364 Vpnsvc *get_vpnsvc_object(void)
365 {
366         return vpnsvc;
367 }
368
369 void vpnsvc_create_and_init(void)
370 {
371         DBG("Create vpn object.");
372         GDBusInterfaceSkeleton *interface_vpn = NULL;
373         GDBusConnection *connection = NULL;
374         GDBusObjectManagerServer *server = netdbus_get_vpn_manager();
375         if (server == NULL)
376                 return;
377
378         connection = netdbus_get_connection();
379         g_dbus_object_manager_server_set_connection(server, connection);
380
381         /* Interface */
382         vpnsvc = vpnsvc_skeleton_new();
383         interface_vpn = G_DBUS_INTERFACE_SKELETON(vpnsvc);
384
385         /* VPN Service */
386         g_signal_connect(vpnsvc, "handle-vpn-init",
387                         G_CALLBACK(handle_vpn_init), NULL);
388         g_signal_connect(vpnsvc, "handle-vpn-deinit",
389                         G_CALLBACK(handle_vpn_deinit), NULL);
390         g_signal_connect(vpnsvc, "handle-vpn-protect",
391                         G_CALLBACK(handle_vpn_protect), NULL);
392         g_signal_connect(vpnsvc, "handle-vpn-up",
393                         G_CALLBACK(handle_vpn_up), NULL);
394         g_signal_connect(vpnsvc, "handle-vpn-down",
395                         G_CALLBACK(handle_vpn_down), NULL);
396         g_signal_connect(vpnsvc, "handle-vpn-block-networks",
397                         G_CALLBACK(handle_vpn_block_networks), NULL);
398         g_signal_connect(vpnsvc, "handle-vpn-unblock-networks",
399                         G_CALLBACK(handle_vpn_unblock_networks), NULL);
400         g_signal_connect(vpnsvc, "handle-vpn-update-settings",
401                         G_CALLBACK(handle_vpn_update_settings), NULL);
402         g_signal_connect(vpnsvc, "handle-vpn-add-route",
403                         G_CALLBACK(handle_vpn_add_route), NULL);
404         g_signal_connect(vpnsvc, "handle-vpn-remove-route",
405                         G_CALLBACK(handle_vpn_remove_route), NULL);
406         g_signal_connect(vpnsvc, "handle-vpn-add-dns-server",
407                         G_CALLBACK(handle_vpn_add_dns_server), NULL);
408
409         if (!g_dbus_interface_skeleton_export(interface_vpn, connection,
410                         NETCONFIG_VPNSVC_PATH, NULL)) {
411                 ERR("Export NETCONFIG_VPNSVC_PATH for vpn failed");
412         }
413
414         return;
415 }
416
417 void vpnsvc_destroy_deinit(void)
418 {
419         DBG("Deinit vpn object.");
420
421         if (vpnsvc)
422                 g_object_unref(vpnsvc);
423 }
424