Use rand_r() instead of rand()
[platform/core/connectivity/net-config.git] / src / ethernet.c
1 /*
2  * Network Configuration - EAPoL Service Module
3  *
4  * Copyright (c) 2020 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 "ethernet.h"
26 #include "netdbus.h"
27 #include "util.h"
28 #include "log.h"
29 #include "wifi-power.h"
30 #include "netsupplicant.h"
31
32 #define EAPOL_STORAGEDIR        "/var/lib/connman/"
33 #define ETH_IFNAME              "eth0"
34
35 #define CONNMAN_CONFIG_FIELD_EAP_METHOD         "EAP"
36 #define CONNMAN_CONFIG_FIELD_IDENTITY           "Identity"
37 #define CONNMAN_CONFIG_FIELD_PASSPHRASE         "Passphrase"
38 #define CONNMAN_CONFIG_FIELD_ANONYMOUS_IDENTITY "AnonymousIdentity"
39 #define CONNMAN_CONFIG_FIELD_CA_CERT_FILE       "CACertFile"
40 #define CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE   "ClientCertFile"
41 #define CONNMAN_CONFIG_FIELD_PVT_KEY_FILE       "PrivateKeyFile"
42 #define CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE "PrivateKeyPassphrase"
43 #define CONNMAN_CONFIG_FIELD_PAC_FILE           "PacFile"
44 #define CONNMAN_CONFIG_FIELD_PHASE2             "Phase2"
45 #define CONNMAN_CONFIG_FIELD_PHASE1             "Phase1"
46
47 static Ethernet *ethernet_object = NULL;
48 static gboolean g_eap_enabled = FALSE;
49 netconfig_eapol_s eapol;
50
51 Ethernet *get_ethernet_object(void)
52 {
53         return ethernet_object;
54 }
55
56 static gboolean __netconfig_set_eap_config_file(GVariant *fields)
57 {
58         GVariantIter *iter;
59         gchar *field, *value;
60         gchar *filename = NULL;
61         FILE *fp = NULL;
62         int err = 0;
63
64         /* initialize eap settings */
65         memset(&eapol, 0, sizeof(netconfig_eapol_s));
66         eapol.phase1 = -1;
67
68         /* create eapol conf file */
69         filename = g_strdup_printf("%s/%s-eapol.conf", EAPOL_STORAGEDIR, ETH_IFNAME);
70         if (!filename) {
71                 ERR("Failed to allocate memory.");
72                 err = -ENOMEM;
73                 goto out;
74         }
75
76         fp = fopen(filename, "w");
77         if (!fp) {
78                 ERR("Failed to open %s", filename);
79                 err = -EIO;
80                 goto out;
81         }
82
83         /* update eapol conf file */
84         fprintf (fp, "network={\n");
85         fprintf (fp, "key_mgmt=WPA-EAP\n");
86
87         g_variant_get(fields, "a{ss}", &iter);
88         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
89                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_EAP_METHOD) == 0) {
90                         if (value != NULL) {
91                                 fprintf (fp, "eap=%s\n", value);
92                                 eapol.eap_type = g_strdup(value);
93                         }
94                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0) {
95                         if (value != NULL) {
96                                 fprintf (fp, "identity=\"%s\"\n", value);
97                                 eapol.identity = g_strdup(value);
98                         }
99                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_ANONYMOUS_IDENTITY) == 0) {
100                         if (value != NULL) {
101                                 fprintf (fp, "anonymous_identity=\"%s\"\n", value);
102                                 eapol.anonymous_identity = g_strdup(value);
103                         }
104                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0) {
105                         if (value != NULL)
106                                 fprintf (fp, "password=\"%s\"\n", value);
107                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CA_CERT_FILE) == 0) {
108                         if (value != NULL) {
109                                 fprintf (fp, "ca_cert=\"%s\"\n", value);
110                                 eapol.ca_cert_file = g_strdup(value);
111                         }
112                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE) == 0) {
113                         if (value != NULL) {
114                                 fprintf (fp, "client_cert=\"%s\"\n", value);
115                                 eapol.client_cert_file = g_strdup(value);
116                         }
117                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_FILE) == 0) {
118                         if (value != NULL) {
119                                 fprintf (fp, "private_key=\"%s\"\n", value);
120                                 eapol.private_key_file = g_strdup(value);
121                         }
122                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE) == 0) {
123                         if (value != NULL) {
124                                 fprintf (fp, "private_key_passwd=\"%s\"\n", value);
125                                 eapol.private_key_password = g_strdup(value);
126                         }
127                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PAC_FILE) == 0) {
128                         if (value != NULL) {
129                                 fprintf (fp, "pac_file=\"%s\"\n", value);
130                                 eapol.pac_file = g_strdup(value);
131                         }
132                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE2) == 0) {
133                         if (value != NULL) {
134                                 char str[50] = {0,};
135                                 sprintf(str, "auth=%s", value);
136                                 fprintf (fp, "phase2=\"%s\"\n", str);
137
138                                 eapol.phase2 = g_strdup(value);
139                         }
140                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE1) == 0) {
141                         if (value != NULL) {
142                                 int peap_version;
143                                 char str[50] = {0,};
144                                 if ((g_strcmp0(value, "VERSION_AUTO") == 0) ||
145                                                 (g_strcmp0(value, "VERSION_0") == 0))
146                                         peap_version = 0;
147                                 else
148                                         peap_version = 1;
149
150                                 sprintf(str, "peapver=%d", peap_version);
151                                 fprintf (fp, "phase1=\"%s\"\n", str);
152                                 eapol.phase1 = peap_version;
153                         }
154                 }
155         }
156
157         fprintf (fp, "}");      /* closing of conf file */
158         fflush(fp);
159         fclose(fp);
160 out:
161         g_free(filename);
162
163         return err;
164 }
165
166 static void __netconfig_cleanup_eapol()
167 {
168         g_free(eapol.eap_type);
169         g_free(eapol.identity);
170         g_free(eapol.anonymous_identity);
171         g_free(eapol.ca_cert_file);
172         g_free(eapol.client_cert_file);
173         g_free(eapol.private_key_file);
174         g_free(eapol.private_key_password);
175         g_free(eapol.pac_file);
176         g_free(eapol.phase2);
177         eapol.phase1 = -1;
178 }
179
180 static int __netconfig_set_eapol_property(const gchar *service, gboolean use_eapol)
181 {
182         GVariant *params = NULL;
183         GVariant *message = NULL;
184         GVariantBuilder *builder;
185
186         const char *prop_eap_on_ethernet = "EapOverEthernet";
187
188         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
189
190         g_variant_builder_add(builder, "{sv}", "UseEapol", g_variant_new_boolean(use_eapol));
191
192         if (use_eapol) {
193                 if (eapol.eap_type)
194                         g_variant_builder_add(builder, "{sv}", "EAP",
195                                         g_variant_new_string(eapol.eap_type));
196                 if (eapol.identity)
197                         g_variant_builder_add(builder, "{sv}", "Identity",
198                                         g_variant_new_string(eapol.identity));
199                 if (eapol.anonymous_identity)
200                         g_variant_builder_add(builder, "{sv}", "AnonymousIdentity",
201                                         g_variant_new_string(eapol.anonymous_identity));
202                 if (eapol.ca_cert_file)
203                         g_variant_builder_add(builder, "{sv}", "CACertFile",
204                                         g_variant_new_string(eapol.ca_cert_file));
205                 if (eapol.client_cert_file)
206                         g_variant_builder_add(builder, "{sv}", "ClientCertFile",
207                                         g_variant_new_string(eapol.client_cert_file));
208                 if (eapol.private_key_file)
209                         g_variant_builder_add(builder, "{sv}", "PrivateKeyFile",
210                                         g_variant_new_string(eapol.private_key_file));
211                 if (eapol.private_key_password)
212                         g_variant_builder_add(builder, "{sv}", "PrivateKeyPassphrase",
213                                         g_variant_new_string(eapol.private_key_password));
214                 if (eapol.phase2)
215                         g_variant_builder_add(builder, "{sv}", "Phase2",
216                                         g_variant_new_string(eapol.phase2));
217
218                 if (eapol.phase1 >= 0)
219                         g_variant_builder_add(builder, "{sv}", "Phase1",
220                                         g_variant_new_int32(eapol.phase1));
221
222                 if (eapol.pac_file)
223                         g_variant_builder_add(builder, "{sv}", "PacFile",
224                                         g_variant_new_string(eapol.pac_file));
225
226                 __netconfig_cleanup_eapol();
227         }
228
229         params = g_variant_new("(sv)", prop_eap_on_ethernet, g_variant_builder_end(builder));
230         g_variant_builder_unref(builder);
231
232         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE, service,
233                         CONNMAN_SERVICE_INTERFACE, "SetProperty", params);
234         if (message == NULL) {
235                 g_variant_unref(message);
236                 return -1;
237         }
238
239         g_variant_unref(message);
240
241         return 0;
242 }
243
244 /*********************
245  * Handler Functions *
246  ********************/
247
248 gboolean handle_enable_eap(Ethernet *object, GDBusMethodInvocation *invocation,
249                            const gchar *service, gboolean enable)
250 {
251         g_return_val_if_fail(object != NULL, TRUE);
252
253         DBG("%s EAPoL", enable ? "enable" : "disable");
254
255         if (netconfig_is_ethernet_profile(service) != TRUE) {
256                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
257                 return TRUE;
258         }
259
260         /* TODO: Execute WPA Supplicant if not running */
261         __execute_supplicant(enable);
262
263         /* TODO: Make below variable interface specific and set
264         connMan profile associated with this interface as EAP enabled.
265         */
266         g_eap_enabled = enable;
267
268         if (enable == false) {
269                 int err = __netconfig_set_eapol_property(service, false);
270                 if (err < 0) {
271                         ERR("Failed to set eapol property.");
272                         netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
273                         return TRUE;
274                 }
275         }
276
277         ethernet_complete_enable_eap(object, invocation);
278         return TRUE;
279 }
280
281 gboolean handle_set_eap_config(Ethernet *object, GDBusMethodInvocation *invocation,
282                         const gchar *service, GVariant *fields)
283 {
284         g_return_val_if_fail(object != NULL, TRUE);
285
286         DBG("handle_set_eap_config for service [%s]", service);
287
288         if (netconfig_is_ethernet_profile(service) != TRUE) {
289                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
290                 return TRUE;
291         }
292
293         if (g_eap_enabled == FALSE) {
294                 netconfig_error_dbus_method_return(invocation,
295                                                    NETCONFIG_ERROR_INTERNAL,
296                                                    "EapNotEnabled");
297                 return TRUE;
298         }
299
300         /** Create conf file */
301         int err = __netconfig_set_eap_config_file(fields);
302         if (err < 0) {
303                 ERR("Failed to save eapol conf file.");
304                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
305                 return TRUE;
306         }
307
308         err = __netconfig_set_eapol_property(service, true);
309         if (err < 0) {
310                 ERR("Failed to set eapol property.");
311                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
312                 return TRUE;
313         }
314
315         ethernet_complete_set_eap_config(object, invocation);
316         return TRUE;
317 }
318
319 /*****************************
320  * Initializations Functions *
321  ****************************/
322 void ethernet_object_create_and_init(void)
323 {
324         DBG("Create ethernet object.");
325         GDBusInterfaceSkeleton *interface_ethernet = NULL;
326         GDBusConnection *connection = NULL;
327         GDBusObjectManagerServer *server = netdbus_get_ethernet_manager();
328         if (server == NULL)
329                 return;
330
331         connection = netdbus_get_connection();
332         g_dbus_object_manager_server_set_connection(server, connection);
333
334         /* Interface */
335         ethernet_object = ethernet_skeleton_new();
336         interface_ethernet = G_DBUS_INTERFACE_SKELETON(ethernet_object);
337
338         /* EAP over Ethernet Service */
339         g_signal_connect(ethernet_object, "handle-enable-eap",
340                         G_CALLBACK(handle_enable_eap), NULL);
341         g_signal_connect(ethernet_object, "handle-set-eap-config",
342                         G_CALLBACK(handle_set_eap_config), NULL);
343
344         if (!g_dbus_interface_skeleton_export(interface_ethernet, connection,
345                         NETCONFIG_ETHERNET_PATH, NULL)) {
346                 ERR("Export NETCONFIG_ETHERNET_PATH for ethernet failed");
347         }
348
349         return;
350 }
351
352 void ethernet_object_deinit(void)
353 {
354         DBG("Deinit ethernet object.");
355
356         g_object_unref(ethernet_object);
357 }