Use rand_r() instead of rand()
[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         DBG("fd:%d\n", *fds);
60
61         result = vpn_service_init(arg_iface_name, arg_iface_name_len, *fds, &handle_s);
62
63         DBG("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s",
64                         handle_s.fd, handle_s.index, handle_s.name);
65
66         vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name);
67
68         return TRUE;
69 }
70
71 gboolean handle_vpn_deinit(Vpnsvc *object,
72                                                                         GDBusMethodInvocation *invocation,
73                                                                         const gchar *arg_dev_name)
74 {
75         DBG("handle_vpn_deinit");
76
77         int result = VPNSVC_ERROR_NONE;
78
79         DBG("vpn_deinit, %s\n", arg_dev_name);
80
81         result = vpn_service_deinit(arg_dev_name);
82
83         vpnsvc_complete_vpn_deinit(object, invocation, result);
84
85         return TRUE;
86 }
87
88 gboolean handle_vpn_protect(Vpnsvc *object,
89                                                                         GDBusMethodInvocation *invocation,
90                                                                         const gchar *arg_dev_name)
91 {
92         DBG("handle_vpn_protect");
93
94         int result = VPNSVC_ERROR_NONE;
95
96         int socket;
97         GDBusMessage *msg;
98         GUnixFDList *fd_list;
99         int fd_list_length;
100         const int *fds;
101
102         msg = g_dbus_method_invocation_get_message(invocation);
103         fd_list = g_dbus_message_get_unix_fd_list(msg);
104         fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
105         if (fd_list_length <= 0)
106                 DBG("D-Bus Message doesn't contain any fd!");
107
108         socket = *fds;
109         DBG("vpn_protect, %d, %s\n", socket, arg_dev_name);
110
111         result = vpn_service_protect(socket, arg_dev_name);
112
113         vpnsvc_complete_vpn_protect(object, invocation, result);
114
115         return TRUE;
116 }
117
118 gboolean handle_vpn_up(Vpnsvc *object,
119                                                                 GDBusMethodInvocation *invocation,
120                                                                 const gchar *arg_iface_name)
121 {
122         DBG("handle_vpn_up");
123
124         int result = VPNSVC_ERROR_NONE;
125
126         result = vpn_service_up(arg_iface_name);
127
128         vpnsvc_complete_vpn_up(object, invocation, result);
129
130         return TRUE;
131 }
132
133 gboolean handle_vpn_down(Vpnsvc *object,
134                                                                         GDBusMethodInvocation *invocation,
135                                                                         const gchar *arg_iface_name)
136 {
137         DBG("handle_vpn_down");
138
139         int result = VPNSVC_ERROR_NONE;
140
141         result = vpn_service_down(arg_iface_name);
142
143         vpnsvc_complete_vpn_down(object, invocation, result);
144
145         return TRUE;
146 }
147
148 #define MAX_NUM_ROUTE_RULE 255
149
150 gboolean handle_vpn_block_networks(Vpnsvc *object,
151                                                                                         GDBusMethodInvocation *invocation,
152                                                                                         GVariant *arg_nets_vpn,
153                                                                                         guint arg_nr_nets_vpn,
154                                                                                         GVariant *arg_nets_orig,
155                                                                                         guint arg_nr_nets_orig)
156 {
157         DBG("handle_vpn_block_networks");
158
159         int result = VPNSVC_ERROR_NONE;
160         if (arg_nr_nets_vpn > MAX_NUM_ROUTE_RULE) {
161                 ERR("Number of allowing networks over VPN interface is exceeded %d,"
162                                                 " Limit is %d", arg_nr_nets_vpn, MAX_NUM_ROUTE_RULE);
163                 result = VPNSVC_ERROR_INVALID_PARAMETER;
164                 goto method_complete;
165         }
166
167         if (arg_nr_nets_orig > MAX_NUM_ROUTE_RULE) {
168                 ERR("Number of allowing networks over original interface is exceeded"
169                                                 " %d, Limit is %d", arg_nr_nets_orig, MAX_NUM_ROUTE_RULE);
170                 result = VPNSVC_ERROR_INVALID_PARAMETER;
171                 goto method_complete;
172         }
173
174         do {
175                 char *nets_vpn[arg_nr_nets_vpn];
176                 int prefix_vpn[arg_nr_nets_vpn];
177
178                 char *nets_orig[arg_nr_nets_orig];
179                 int prefix_orig[arg_nr_nets_orig];
180
181                 int i = 0;
182                 GVariantIter iter;
183                 gchar* route_dest;
184                 gint route_prefix;
185
186                 DBG("vpn_block_networks");
187
188                 memset(nets_vpn, 0, sizeof(char *) * arg_nr_nets_vpn);
189                 memset(prefix_vpn, 0, sizeof(int) * arg_nr_nets_vpn);
190                 memset(nets_orig, 0, sizeof(char *) * arg_nr_nets_orig);
191                 memset(prefix_orig, 0, sizeof(int) * arg_nr_nets_orig);
192
193                 /* arg_nets_vpn check */
194                 if (arg_nr_nets_vpn > 0) {
195                         if (arg_nets_vpn != NULL) {
196                                 GVariant *dict_nets_vpn = g_variant_get_variant(arg_nets_vpn);
197                                 g_variant_iter_init(&iter, dict_nets_vpn);
198                                 i = 0;
199                                 while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
200                                         if (i >= arg_nr_nets_vpn) {
201                                                 WARN("No more space for allowing network over VPN interface."
202                                                                 " next index %d / space size %d", i, arg_nr_nets_vpn);
203                                                 g_free(route_dest);
204                                                 break;
205                                         }
206                                         int tmp_route_len = strlen(route_dest);
207                                         nets_vpn[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
208                                         if (nets_vpn[i]) {
209                                                 strncpy(nets_vpn[i], route_dest, tmp_route_len);
210                                                 nets_vpn[i][tmp_route_len] = '\0';
211                                                 prefix_vpn[i] = route_prefix;
212                                                 DBG("nets_vpn[%d] = %s \t", i, (nets_vpn[i] == NULL) ? "" : nets_vpn[i]);
213                                                 DBG("prefix_vpn[%d] = %d ", i, prefix_vpn[i]);
214                                         }
215                                         i++;
216                                 }
217                         }
218                 }
219
220                 /* arg_nets_orig check */
221                 if (arg_nr_nets_orig > 0) {
222                         if (arg_nets_orig != NULL) {
223                                 GVariant *dict_nets_orig = g_variant_get_variant(arg_nets_orig);
224                                 g_variant_iter_init(&iter, dict_nets_orig);
225                                 i = 0;
226                                 while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
227                                         if (i >= arg_nr_nets_orig) {
228                                                 WARN("No more space for allowing network over VPN interface."
229                                                                 " next index %d / space size %d", i, arg_nr_nets_orig);
230                                                 g_free(route_dest);
231                                                 break;
232                                         }
233                                         int tmp_route_len = strlen(route_dest);
234                                         nets_orig[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
235                                         if (nets_orig[i]) {
236                                                 strncpy(nets_orig[i], route_dest, tmp_route_len);
237                                                 nets_orig[i][tmp_route_len] = '\0';
238                                                 prefix_orig[i] = route_prefix;
239                                                 DBG("nets_orig[%d] = %s \t", i, (nets_orig[i] == NULL) ? "" : nets_orig[i]);
240                                                 DBG("prefix_orig[%d] = %d ", i, prefix_orig[i]);
241                                         }
242                                         i++;
243                                 }
244                         }
245                 }
246
247                 /* call function */
248                 result = vpn_service_block_networks(nets_vpn, prefix_vpn, arg_nr_nets_vpn, nets_orig, prefix_orig, arg_nr_nets_orig);
249
250                 for (i = 0; i < arg_nr_nets_vpn; ++i) {
251                         g_free(nets_vpn[i]);
252                 }
253
254                 for (i = 0; i < arg_nr_nets_orig; ++i) {
255                         g_free(nets_orig[i]);
256                 }
257         } while(0);
258
259 method_complete:
260         vpnsvc_complete_vpn_block_networks(object, invocation, result);
261
262         return TRUE;
263 }
264
265 gboolean handle_vpn_unblock_networks(Vpnsvc *object,
266                                                                                         GDBusMethodInvocation *invocation)
267 {
268         DBG("handle_vpn_unblock_networks");
269
270         int result = VPNSVC_ERROR_NONE;
271
272         DBG("vpn_unblock_networks");
273
274         result = vpn_service_unblock_networks();
275
276         vpnsvc_complete_vpn_unblock_networks(object, invocation, result);
277
278         return TRUE;
279 }
280
281 gboolean handle_vpn_update_settings(Vpnsvc *object,
282                                                                 GDBusMethodInvocation *invocation,
283                                                                 gint arg_iface_index,
284                                                                 const gchar *arg_local_ip,
285                                                                 const gchar *arg_remote_ip,
286                                                                 guint arg_mtu)
287 {
288         int result = VPNSVC_ERROR_NONE;
289         DBG("handle_vpn_update_settings");
290
291         result = vpn_service_update_settings(arg_iface_index, arg_local_ip, arg_remote_ip, arg_mtu);
292
293         vpnsvc_complete_vpn_update_settings(object, invocation, result);
294
295         return TRUE;
296 }
297
298 gboolean handle_vpn_add_route(Vpnsvc *object,
299                                                                 GDBusMethodInvocation *invocation,
300                                                                 gchar *arg_iface_name,
301                                                                 const gchar *arg_route,
302                                                                 gint arg_prefix)
303 {
304         DBG("handle_vpn_add_route");
305
306         int result = VPNSVC_ERROR_NONE;
307
308         result = vpn_service_add_route(arg_iface_name, arg_route, arg_prefix);
309
310         vpnsvc_complete_vpn_add_route(object, invocation, result);
311
312         return TRUE;
313 }
314
315 gboolean handle_vpn_remove_route(Vpnsvc *object,
316                                                                 GDBusMethodInvocation *invocation,
317                                                                 gchar *arg_iface_name,
318                                                                 const gchar *arg_route,
319                                                                 gint arg_prefix)
320
321 {
322         DBG("handle_vpn_remove_route");
323
324         int result = VPNSVC_ERROR_NONE;
325
326         result = vpn_service_remove_route(arg_iface_name, arg_route, arg_prefix);
327
328         vpnsvc_complete_vpn_remove_route(object, invocation, result);
329
330         return TRUE;
331 }
332
333 gboolean handle_vpn_add_dns_server(Vpnsvc *object,
334                                                                 GDBusMethodInvocation *invocation,
335                                                                 gchar *arg_iface_name,
336                                                                 const gchar *arg_dns_server)
337 {
338         DBG("handle_vpn_add_dns_server");
339
340         int result = VPNSVC_ERROR_NONE;
341
342         result = vpn_service_add_dns_server(arg_iface_name, arg_dns_server);
343
344         vpnsvc_complete_vpn_add_dns_server(object, invocation, result);
345
346         return TRUE;
347 }
348
349 /*****************************
350  * Initializations Functions *
351  ****************************/
352 Vpnsvc *get_vpnsvc_object(void)
353 {
354         return vpnsvc;
355 }
356
357 void vpnsvc_create_and_init(void)
358 {
359         DBG("Create vpn object.");
360         GDBusInterfaceSkeleton *interface_vpn = NULL;
361         GDBusConnection *connection = NULL;
362         GDBusObjectManagerServer *server = netdbus_get_vpn_manager();
363         if (server == NULL)
364                 return;
365
366         connection = netdbus_get_connection();
367         g_dbus_object_manager_server_set_connection(server, connection);
368
369         /* Interface */
370         vpnsvc = vpnsvc_skeleton_new();
371         interface_vpn = G_DBUS_INTERFACE_SKELETON(vpnsvc);
372
373         /* VPN Service */
374         g_signal_connect(vpnsvc, "handle-vpn-init",
375                         G_CALLBACK(handle_vpn_init), NULL);
376         g_signal_connect(vpnsvc, "handle-vpn-deinit",
377                         G_CALLBACK(handle_vpn_deinit), NULL);
378         g_signal_connect(vpnsvc, "handle-vpn-protect",
379                         G_CALLBACK(handle_vpn_protect), NULL);
380         g_signal_connect(vpnsvc, "handle-vpn-up",
381                         G_CALLBACK(handle_vpn_up), NULL);
382         g_signal_connect(vpnsvc, "handle-vpn-down",
383                         G_CALLBACK(handle_vpn_down), NULL);
384         g_signal_connect(vpnsvc, "handle-vpn-block-networks",
385                         G_CALLBACK(handle_vpn_block_networks), NULL);
386         g_signal_connect(vpnsvc, "handle-vpn-unblock-networks",
387                         G_CALLBACK(handle_vpn_unblock_networks), NULL);
388         g_signal_connect(vpnsvc, "handle-vpn-update-settings",
389                         G_CALLBACK(handle_vpn_update_settings), NULL);
390         g_signal_connect(vpnsvc, "handle-vpn-add-route",
391                         G_CALLBACK(handle_vpn_add_route), NULL);
392         g_signal_connect(vpnsvc, "handle-vpn-remove-route",
393                         G_CALLBACK(handle_vpn_remove_route), NULL);
394         g_signal_connect(vpnsvc, "handle-vpn-add-dns-server",
395                         G_CALLBACK(handle_vpn_add_dns_server), NULL);
396
397         if (!g_dbus_interface_skeleton_export(interface_vpn, connection,
398                         NETCONFIG_VPNSVC_PATH, NULL)) {
399                 ERR("Export NETCONFIG_VPNSVC_PATH for vpn failed");
400         }
401
402         return;
403 }
404
405 void vpnsvc_destroy_deinit(void)
406 {
407         DBG("Deinit vpn object.");
408
409         if (vpnsvc)
410                 g_object_unref(vpnsvc);
411 }
412